docs(git-sync): document GIT_SYNC_BACKEND_TIMEOUT_MS, drop dead consts, fix dangling plan refs
Address the non-red-team documentation/cleanup items from review #1679: - Document the GIT_SYNC_BACKEND_TIMEOUT_MS watchdog (git http-backend) in .env.example and add it to the environment validation schema — it was used (getGitSyncBackendTimeoutMs, default 120000) but undocumented/unvalidated. - Remove the dead GIT_SYNC_DEBOUNCE_MS_DEFAULT / GIT_SYNC_POLL_INTERVAL_MS_DEFAULT exports (never imported; environment.service is the single source of defaults). - Redirect the dangling `plan §X.Y` comment references to issue #194 (the git-sync spec moved there when docs/git-sync-plan.md was deleted by this PR). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -238,6 +238,11 @@ MCP_DOCMOST_PASSWORD=
|
|||||||
# (default: 2000).
|
# (default: 2000).
|
||||||
# GIT_SYNC_DEBOUNCE_MS=2000
|
# GIT_SYNC_DEBOUNCE_MS=2000
|
||||||
#
|
#
|
||||||
|
# Watchdog timeout in ms for the spawned `git http-backend` process serving a
|
||||||
|
# git smart-HTTP push (default: 120000). A stalled/hung receive-pack is killed
|
||||||
|
# after this deadline so it cannot hold the per-space lock forever.
|
||||||
|
# GIT_SYNC_BACKEND_TIMEOUT_MS=120000
|
||||||
|
#
|
||||||
# Defense-in-depth absolute cap on soft-deletes applied per push cycle
|
# Defense-in-depth absolute cap on soft-deletes applied per push cycle
|
||||||
# (default: 5). A non-convergent / phantom-absence cycle can never trash more
|
# (default: 5). A non-convergent / phantom-absence cycle can never trash more
|
||||||
# than this many pages without an explicit override.
|
# than this many pages without an explicit override.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* editor-ext ProseMirror documents must survive a full round trip through the
|
* editor-ext ProseMirror documents must survive a full round trip through the
|
||||||
* actual server write path without losing any node / mark / attribute.
|
* actual server write path without losing any node / mark / attribute.
|
||||||
*
|
*
|
||||||
* Pipeline per document (plan §13.1):
|
* Pipeline per document (issue #194 §13.1):
|
||||||
* 1. md = convertProseMirrorToMarkdown(content) // git-sync export
|
* 1. md = convertProseMirrorToMarkdown(content) // git-sync export
|
||||||
* 2. doc = await markdownToProseMirror(md) // git-sync import
|
* 2. doc = await markdownToProseMirror(md) // git-sync import
|
||||||
* 3. push `doc` through the REAL editor-ext Yjs write path the server uses:
|
* 3. push `doc` through the REAL editor-ext Yjs write path the server uses:
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
* (apps/server/src/collaboration/extensions/persistence.extension.ts:96/115)
|
* (apps/server/src/collaboration/extensions/persistence.extension.ts:96/115)
|
||||||
* with the same `tiptapExtensions` (collaboration.util.ts) and the same
|
* with the same `tiptapExtensions` (collaboration.util.ts) and the same
|
||||||
* `@hocuspocus/transformer`, so the gate exercises the real schema
|
* `@hocuspocus/transformer`, so the gate exercises the real schema
|
||||||
* validation that runs on a git-sync write (plan §3.3).
|
* validation that runs on a git-sync write (issue #194 §3.3).
|
||||||
* 4. assert docsCanonicallyEqual(canon(original), canon(normalized)) === true
|
* 4. assert docsCanonicallyEqual(canon(original), canon(normalized)) === true
|
||||||
*
|
*
|
||||||
* Any node / mark / attr that editor-ext drops (because the git-sync
|
* Any node / mark / attr that editor-ext drops (because the git-sync
|
||||||
* docmost-schema named it differently, or declares a different default) makes
|
* docmost-schema named it differently, or declares a different default) makes
|
||||||
* the gate FAIL for that document — exactly the schema-divergence plan §3.3 /
|
* the gate FAIL for that document — exactly the schema-divergence issue #194 §3.3 /
|
||||||
* §13.1 warn about. Genuine, irreducible divergences are isolated into the
|
* §13.1 warn about. Genuine, irreducible divergences are isolated into the
|
||||||
* clearly-named `KNOWN DIVERGENCE` block at the bottom (never silently hidden).
|
* clearly-named `KNOWN DIVERGENCE` block at the bottom (never silently hidden).
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ProvenanceSource } from '../../core/auth/dto/jwt-payload';
|
|||||||
*/
|
*/
|
||||||
export interface AuthProvenanceData {
|
export interface AuthProvenanceData {
|
||||||
// ProvenanceSource includes 'git-sync' — set by the in-process git-sync data
|
// ProvenanceSource includes 'git-sync' — set by the in-process git-sync data
|
||||||
// plane (plan §8.1) when it drives PageService writes; never from a request token.
|
// plane (issue #194 §8.1) when it drives PageService writes; never from a request token.
|
||||||
actor: ProvenanceSource;
|
actor: ProvenanceSource;
|
||||||
aiChatId: string | null;
|
aiChatId: string | null;
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ export function agentSourceFields<S extends string, C extends string>(
|
|||||||
sourceKey: S,
|
sourceKey: S,
|
||||||
chatKey: C,
|
chatKey: C,
|
||||||
): Partial<Record<S, ProvenanceSource> & Record<C, string | null>> {
|
): Partial<Record<S, ProvenanceSource> & Record<C, string | null>> {
|
||||||
// git-sync data-plane write (plan §8.1): stamp the source 'git-sync' with NO
|
// git-sync data-plane write (issue #194 §8.1): stamp the source 'git-sync' with NO
|
||||||
// aiChatId (it has no internal ai_chats row). Mirrors the agent branch; each
|
// aiChatId (it has no internal ai_chats row). Mirrors the agent branch; each
|
||||||
// write has a single actor, so precedence is irrelevant here.
|
// write has a single actor, so precedence is irrelevant here.
|
||||||
if (provenance?.actor === 'git-sync') {
|
if (provenance?.actor === 'git-sync') {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Single source of truth so a typo like 'agnet' can't slip through as a bare
|
* Single source of truth so a typo like 'agnet' can't slip through as a bare
|
||||||
* string (#143 review). Distinct from `ActorType` (auth principal kind).
|
* string (#143 review). Distinct from `ActorType` (auth principal kind).
|
||||||
*
|
*
|
||||||
* 'git-sync' marks writes made by the git-sync data plane (plan §8.1). It NEVER
|
* 'git-sync' marks writes made by the git-sync data plane (issue #194 §8.1). It NEVER
|
||||||
* travels in a user-facing token; it is set in-process on the collab connection
|
* travels in a user-facing token; it is set in-process on the collab connection
|
||||||
* context by the native datasource, so it cannot be spoofed from a request.
|
* context by the native datasource, so it cannot be spoofed from a request.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ export class EnvironmentService {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- git-sync (plan §7.2) -------------------------------------------------
|
// --- git-sync (issue #194 §7.2) -------------------------------------------------
|
||||||
|
|
||||||
/** Global master switch for the git-sync control plane (default false). */
|
/** Global master switch for the git-sync control plane (default false). */
|
||||||
isGitSyncEnabled(): boolean {
|
isGitSyncEnabled(): boolean {
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ export class EnvironmentVariables {
|
|||||||
)
|
)
|
||||||
CLICKHOUSE_URL: string;
|
CLICKHOUSE_URL: string;
|
||||||
|
|
||||||
// --- git-sync (plan §7.2) — all OPTIONAL. The master switch defaults off; a
|
// --- git-sync (issue #194 §7.2) — all OPTIONAL. The master switch defaults off; a
|
||||||
// required-if-enabled service user id is validated only when sync is on. ---
|
// required-if-enabled service user id is validated only when sync is on. ---
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@@ -202,6 +202,13 @@ export class EnvironmentVariables {
|
|||||||
@IsString()
|
@IsString()
|
||||||
GIT_SYNC_DEBOUNCE_MS: string;
|
GIT_SYNC_DEBOUNCE_MS: string;
|
||||||
|
|
||||||
|
// Watchdog timeout (ms) for the spawned `git http-backend` process (default
|
||||||
|
// 120000): a stalled receive-pack is killed so it cannot hold the per-space
|
||||||
|
// lock forever. Optional int (validated as a string env).
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
GIT_SYNC_BACKEND_TIMEOUT_MS: string;
|
||||||
|
|
||||||
// Defense-in-depth absolute cap on soft-deletes per push cycle (default 5): a
|
// Defense-in-depth absolute cap on soft-deletes per push cycle (default 5): a
|
||||||
// non-convergent / phantom-absence cycle can never trash more than this many
|
// non-convergent / phantom-absence cycle can never trash more than this many
|
||||||
// pages without an explicit override. Optional int (validated as a string env).
|
// pages without an explicit override. Optional int (validated as a string env).
|
||||||
@@ -210,7 +217,7 @@ export class EnvironmentVariables {
|
|||||||
GIT_SYNC_MAX_DELETES_PER_CYCLE: string;
|
GIT_SYNC_MAX_DELETES_PER_CYCLE: string;
|
||||||
|
|
||||||
// Required when git-sync is enabled: the service user create/move/rename/delete
|
// Required when git-sync is enabled: the service user create/move/rename/delete
|
||||||
// are attributed to (plan §7.2). Optional otherwise.
|
// are attributed to (issue #194 §7.2). Optional otherwise.
|
||||||
@ValidateIf((obj) => obj.GIT_SYNC_ENABLED === 'true')
|
@ValidateIf((obj) => obj.GIT_SYNC_ENABLED === 'true')
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|||||||
@@ -39,9 +39,3 @@ export const GIT_SYNC_LOCK_PREFIX = 'git-sync:lock:';
|
|||||||
* and the Redis lock prevents two instances racing the same space.
|
* and the Redis lock prevents two instances racing the same space.
|
||||||
*/
|
*/
|
||||||
export const GIT_SYNC_LOCK_TTL_MS = 5 * 60 * 1000;
|
export const GIT_SYNC_LOCK_TTL_MS = 5 * 60 * 1000;
|
||||||
|
|
||||||
/** Default event-debounce window (ms), overridable via GIT_SYNC_DEBOUNCE_MS. */
|
|
||||||
export const GIT_SYNC_DEBOUNCE_MS_DEFAULT = 2000;
|
|
||||||
|
|
||||||
/** Default poll-safety interval (ms), overridable via GIT_SYNC_POLL_INTERVAL_MS. */
|
|
||||||
export const GIT_SYNC_POLL_INTERVAL_MS_DEFAULT = 15000;
|
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ export class GitmostDataSourceService {
|
|||||||
actor: 'git-sync',
|
actor: 'git-sync',
|
||||||
// PersistenceExtension reads `context.user.id` for lastUpdatedById, so the
|
// PersistenceExtension reads `context.user.id` for lastUpdatedById, so the
|
||||||
// service user is required on the context (unlike the bare `{ actor }`
|
// service user is required on the context (unlike the bare `{ actor }`
|
||||||
// sketch in the plan).
|
// sketch in issue #194).
|
||||||
user: { id: userId },
|
user: { id: userId },
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user