Resolve the code-review findings from comment #1571 on PR #119.
Engine (packages/git-sync):
- Idempotent CREATE on retry: before createPage, look the page up in the
live Docmost tree by (parentPageId, title) and ADOPT it instead of
duplicating when a prior cycle created it but failed to persist the
pageId back to disk. Only trust a COMPLETE tree for the lookup; fall
back to createPage otherwise. Covered by new tests incl. a complete=false
regression-lock.
- Route applyPullActions diagnostics through an injected logger instead of
bare console (thread log from the cycle).
- Add a timeout to the git execFile chokepoint (runRaw) so a hung git
subprocess cannot wedge a sync cycle.
- Translate remaining Russian code comments to English.
- Remove dead standalone-CLI code (parseArgs/PushParsedArgs,
parseSettings/envSchema, loadSettingsOrExit + config-errors.ts) and the
matching index exports/specs; keep the Settings type.
- Fix the dangling docs link in package.json.
- Add a schema-surface snapshot guard so any drift in the vendored
document schema is a loud, must-review CI failure (+ provenance header).
Server (apps/server):
- Add a configurable watchdog timeout to the spawned git http-backend so a
stalled push cannot hold the per-space lock forever
(GIT_SYNC_BACKEND_TIMEOUT_MS).
- Close the in-process TOCTOU window in SpaceLockService.withSpaceLock by
reserving the slot synchronously before acquire.
- Add tests: removePage git-sync provenance (both branches), ensureServable
force-push-protection git configs, and the phase-B+ datasource methods.
Docs / build:
- AGENTS.md: list git-sync as the fifth workspace package and note the
three schema mirrors; fix the dangling git-sync-plan.md backlog link.
- pnpm-lock.yaml: add the missing @docmost/git-sync workspace link so
pnpm install --frozen-lockfile (CI default) succeeds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Must-fix:
- Move canonicalizeFootnotes OUT of parseProsemirrorContent. It now runs only
on FULL writes (createPage, updatePageContent operation==='replace'), never on
an append/prepend fragment (a fragment would lose definition-only footnotes or
synthesize a bogus empty list). Add a server binding spec.
- Match the live plugin's list PLACEMENT: a single already-canonical
footnotesList is left exactly where it sits (the plugin never repositions a
sole correct list), so the first write no longer reorders content that follows
the list. Applied to BOTH the editor-ext copy and the MCP mirror; pinned by a
shared golden corpus case with content after the list.
- Fix MCP tool count 38 -> 39 (README x3, AGENTS.md) and the transformJs param
help (add canonicalizeFootnotes/insertInlineFootnote).
Simplifications:
- Remove the dead duplicate re-id mechanism (deriveFootnoteId/suffix/occurrence)
from the PURE canonicalizer in both copies — references are never renamed, so
the derived ids were never requested; first-wins-drop is the real behaviour.
This also makes the editor-ext footnote-util note about "no cross-package copy"
true again.
- Remove the sentinel round-trip in insertInlineFootnote: a generalized
insertNodesAfterAnchor core inserts the footnoteReference node directly.
- Drop the redundant per-definition deep clone in step 4 (shallow id-normalizing
copy; out is already deep-cloned).
Docs / architecture:
- Correct the editor-ext copy's "It exists because…" header to its real
consumers (server import, page.service create/update, client paste).
- Note markdownToProseMirror reuse for create/update comment in collaboration.ts.
- A: shared golden JSON corpus exercised by BOTH the editor-ext copy and the MCP
mirror (footnote-corpus.ts / .mjs) so "the two copies behave identically" is
checkable.
- C: split the MCP canonicalizer into a pure mirror + footnote-authoring.ts.
- B: import services persist via a different path, so left one-line consolidation
comments at the call sites rather than folding (does not fall out cleanly).
Tests: insertFootnote wrapper guards + docmost_transform dryRun auto-canonicalize
(MCP mock), page.service create/update + append/prepend binding (server jest),
shared corpus incl. nested-container reference.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the release documentation to emphasize tagging on develop before merging to main, detail steps for pushing tags to both gitea and github, and explain the back‑merge and remote tag considerations.
Add a new “Creating issues (Gitea `tea` CLI)” section to AGENTS.md that documents how to file issues using the `tea` command‑line tool, including the correct flag for the issue body and a gotcha note about the `--description` flag.
Migrations auto-run on boot only in production (the built image / start:prod);
the local dev stand (pnpm dev / nest start --watch) does NOT auto-run them, so
after pulling or switching branches you must apply them with
'pnpm --filter server migration:latest' or endpoints touching new columns 500
(e.g. a freshly-added ai_chats.page_id blanket-500s all of AI chat).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update the task lifecycle documentation from Russian to English to improve
readability for English‑speaking contributors and ensure consistency across
the repository.
Add a rule to the "Реализация" section of AGENTS.md stating that git
worktrees may only be created inside the .claude directory
(e.g. .claude/worktrees/<name>); creating them anywhere else is forbidden.
The back-merge alone does not fix the develop version: git describe names
a tag ref, and the :develop image is built on GitHub Actions, so the tag
must exist on the `github` remote. git push of a branch does not push
tags. Document the multi-remote (gitea + github) tag-push requirement and
a recovery checklist when develop still shows the previous version.
The UI version comes from `git describe --tags`, which resolves the nearest
tag in the current commit's ancestry. Release tags are created on main's
merge commit, which is not in develop's history, so develop builds keep
reporting the previous tag (e.g. v0.91.0-NNN) until main is merged back.
Add step 7 (back-merge main -> develop) to the "Cutting a release"
checklist and a subsection explaining why develop lags and how to fix it.
Fix doc drift: /mcp per-user auth + X-MCP-Token (was 'service account + optional
MCP_TOKEN'); CI builds :develop on push to develop (was main); add
page_template_references to the fork-tables list + is_template schema; mark
arbitrary HTML embed as shipped (was in-progress plan); remove the dead
page-templates-plan.md README link and move Page templates to implemented.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up fixes to the htmlEmbed-sandbox / trackerHead change:
- share-seo: inject trackerHead via a function replacer so `$`-sequences
($&, $', $`, $$) in the admin snippet are inserted literally instead of
being treated as String.replace substitution patterns; warn when the
</head> marker is absent instead of silently skipping injection.
- mcp: register a passthrough `htmlEmbed` node in the schema mirror so an
AI/MCP edit of a page containing an embed no longer throws
"Unknown node type: htmlEmbed" in TiptapTransformer.toYdoc.
- editor-ext + client: treat a non-finite `data-height` as auto (null) so a
crafted/corrupted height cannot disable auto-resize or yield a NaN iframe
height; extract a shared clampHeight helper.
- client: rename render-raw-html.{ts,test.ts} -> html-embed-sandbox.{...} and
shouldExecute -> shouldRender so the seam name matches the sandbox model.
- client: i18n the iframe title; surface the real error reason in
tracker-settings (console.error + err.response.data.message).
- docs: note hasHtmlEmbedNode is now a test-only helper; add an Unreleased
CHANGELOG entry; drop the dangling "arbitrary HTML embed" planning-doc ref.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## What
Renames the agent-guidance file `CLAUDE.md` → `AGENTS.md` (the opencode-standard name) and prepends a process layer on top of the existing technical/architecture content.
## Changes
- **Rename** `CLAUDE.md` → `AGENTS.md` (git detects 64% similarity, history preserved).
- **New top section "Жизненный цикл задачи"** codifies the workflow we just went through:
1. Sync with `develop`, branch off
2. Implement (per the system-prompt workflow + subagents)
3. **Commit ONLY to Gitea and ONLY as `claude_code`** — never as `vvzvlad`, never push to `origin`/`upstream`
4. Push + PR to `develop`
5. User merges; agent deletes the task's `docs/backlog/<task>.md`
- **New release-cycle section**: before cutting a version, run the three orchestrator skills (test-orchestrator, review-orchestrator, red-team-orchestrator), fix their findings, then tag per the existing procedure.
- **Credentials cheat-sheet**: agent identity, keychain service name (`gitea-claude-code`), Gitea PR API endpoint, base branch, and do-not-push warnings for `origin`/`upstream`.
- **Fix typo**: repo slug is `gitmost`, not `gtimost` (the remote was redirecting on every push). Local `gitea` remote URL is updated to the canonical form.
## Out of scope
No code changes — docs only.
Reviewed-on: #2
Co-authored-by: claude_code <claude_code@vvzvlad.xyz>
Co-committed-by: claude_code <claude_code@vvzvlad.xyz>