From 55a0b6014075a90d9acbe2bc6174bb999b040152 Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Wed, 24 Jun 2026 00:53:07 +0300 Subject: [PATCH] docs(git-sync): document GIT_SYNC_* env vars; fix stale/non-English comments (PR #119 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .env.example | 38 +++++++++++++++++++ .../src/components/ui/git-sync-badge.tsx | 11 +++--- .../space/components/edit-space-form.tsx | 3 ++ .../extensions/persistence.extension.ts | 4 +- .../git-sync/services/yjs-body-merge.ts | 4 +- 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index 7407e629..1e549ea4 100644 --- a/.env.example +++ b/.env.example @@ -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 "/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 diff --git a/apps/client/src/components/ui/git-sync-badge.tsx b/apps/client/src/components/ui/git-sync-badge.tsx index 805d0d0e..2fd991ce 100644 --- a/apps/client/src/components/ui/git-sync-badge.tsx +++ b/apps/client/src/components/ui/git-sync-badge.tsx @@ -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(); diff --git a/apps/client/src/features/space/components/edit-space-form.tsx b/apps/client/src/features/space/components/edit-space-form.tsx index 8bf176d9..95077e3d 100644 --- a/apps/client/src/features/space/components/edit-space-form.tsx +++ b/apps/client/src/features/space/components/edit-space-form.tsx @@ -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); } }; diff --git a/apps/server/src/collaboration/extensions/persistence.extension.ts b/apps/server/src/collaboration/extensions/persistence.extension.ts index a2426ef8..7d4902d2 100644 --- a/apps/server/src/collaboration/extensions/persistence.extension.ts +++ b/apps/server/src/collaboration/extensions/persistence.extension.ts @@ -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, diff --git a/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts b/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts index 40e73d4c..c1dab666 100644 --- a/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts +++ b/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts @@ -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