docs(git-sync): document GIT_SYNC_* env vars; fix stale/non-English comments (PR #119 review)

Addresses the documentation/convention warnings from the #119 review:
- .env.example: add the GIT-SYNC block (9 GIT_SYNC_* vars with defaults), noting
  GIT_SYNC_SERVICE_USER_ID is required when sync is enabled.
- yjs-body-merge.ts: translate the Russian review note in the docstring to
  English (comments-only-in-English rule).
- persistence.extension.ts: correct the stale "git-sync writes are full-body
  replaces" rationale — a git-sync write is now a block-level merge into the live
  doc, which is why it is debounced like a human edit rather than snapshotted.
- history-item.tsx: the GitSyncBadge version is created on the PUSH path (writing
  the git body back into the doc), not by the pull — fix the comment.
- edit-space-form.tsx: log the raw error in the git-sync toggle catch instead of
  swallowing it (AGENTS.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-24 00:53:07 +03:00
parent 807ff1f5f5
commit 8fa32e8438
5 changed files with 52 additions and 8 deletions

View File

@@ -203,3 +203,41 @@ MCP_DOCMOST_PASSWORD=
# FAILS CLOSED if Redis is unavailable (default: 1,000,000 tokens per workspace
# per rolling day).
# SHARE_AI_WORKSPACE_TOKEN_BUDGET_PER_DAY=1000000
# --- GIT-SYNC (native two-way Docmost <-> git Markdown sync) ---
# Master switch. Off by default. When 'true', GIT_SYNC_SERVICE_USER_ID below is
# REQUIRED (the service account that git-originated create/move/rename/delete are
# attributed to) — the server refuses to boot with sync enabled and no user id.
# GIT_SYNC_ENABLED=false
#
# Serve the per-space vaults over smart-HTTP (the /git host). Defaults to
# GIT_SYNC_ENABLED when unset.
# GIT_SYNC_HTTP_ENABLED=false
#
# REQUIRED when GIT_SYNC_ENABLED=true: id of the user that git-originated page
# operations (create / move / rename / delete) are attributed to.
# GIT_SYNC_SERVICE_USER_ID=
#
# Where the per-space bare repos / working vaults live.
# Defaults to "<DATA_DIR or ./data>/git-sync".
# GIT_SYNC_DATA_DIR=
#
# Optional remote URL template to mirror each space's vault to (e.g. a git host).
# Leave unset to keep vaults local-only.
# GIT_SYNC_REMOTE_TEMPLATE=
#
# Path to the SSH private key used when pushing to GIT_SYNC_REMOTE_TEMPLATE.
# GIT_SYNC_SSH_KEY_PATH=
#
# Poll-safety interval in ms — the cadence of the background reconcile cycle
# (default: 15000).
# GIT_SYNC_POLL_INTERVAL_MS=15000
#
# Debounce window in ms for collapsing bursts of page edits into one sync cycle
# (default: 2000).
# GIT_SYNC_DEBOUNCE_MS=2000
#
# Defense-in-depth absolute cap on soft-deletes applied per push cycle
# (default: 5). A non-convergent / phantom-absence cycle can never trash more
# than this many pages without an explicit override.
# GIT_SYNC_MAX_DELETES_PER_CYCLE=5

View File

@@ -7,11 +7,12 @@ interface GitSyncBadgeProps {
}
/**
* Badge marking a version written by the git-sync data plane — a VaultGit pull
* applied through the native datasource (provenance §8.1). Like {@link AiAgentBadge}
* it is ADDITIVE — shown next to the human author, never replacing them. A
* git-sync edit is NOT an agent edit and has no chat to deep-link into, so it is
* a small, neutral, non-clickable label.
* Badge marking a version produced by git-sync (provenance §8.1). The history
* version is created on the PUSH path — when an incoming git body is written back
* into the Docmost doc — not by the pull itself. Like {@link AiAgentBadge} it is
* ADDITIVE — shown next to the human author, never replacing them — but a git-sync
* edit is NOT an agent edit and has no chat to deep-link into, so it is a small,
* neutral, non-clickable label.
*/
export function GitSyncBadge({ authorName }: GitSyncBadgeProps) {
const { t } = useTranslation();

View File

@@ -52,6 +52,9 @@ export function EditSpaceForm({ space, readOnly }: EditSpaceFormProps) {
});
} catch (err) {
setGitSyncEnabled(previous); // revert on failure
// The mutation surfaces a toast via onError; still log the raw error so it
// is not silently swallowed (AGENTS.md).
console.error("Failed to toggle git-sync for space", err);
}
};

View File

@@ -183,7 +183,9 @@ export class PersistenceExtension implements Extension {
// agent event in the same window). §15 H2.
// Provenance precedence: agent > git-sync > user (see resolveSource). A
// 'git-sync' store is NOT given an immediate history snapshot — it is
// debounced like a human edit (git-sync writes are full-body replaces).
// debounced like a human edit (a git-sync write is a block-level merge into
// the live doc, so it reads like an incremental human edit, not a bulk
// import that would warrant its own immediate snapshot).
const lastUpdatedSource = resolveSource(
this.consumeAgentTouched(documentName),
context?.actor,

View File

@@ -5,8 +5,8 @@ import { diff3Plan } from './three-way-merge';
/**
* Block-level merge of an incoming (git) page body into a LIVE Yjs document,
* replacing the previous full-body "delete everything + re-insert" write that
* clobbered concurrent human edits on every sync (review #5 — "запись делать
* через мерж").
* clobbered concurrent human edits on every sync (review #5 — "do the write as a
* merge").
*
* Strategy: diff the two documents at TOP-LEVEL BLOCK granularity (an LCS over a
* canonical structural serialization of each block) and apply only the minimal