feat(git-sync): native GitmostDataSource + 'git-sync' provenance (Phase A.4a)

Native data plane for git-sync (plan §3, §8.1):
- provenance: widen actor to 'user'|'agent'|'git-sync' (jwt-payload,
  auth-provenance decorator); PersistenceExtension resolves lastUpdatedSource
  with precedence agent > git-sync > user, debounced history (like a human edit,
  not the agent's immediate snapshot).
- GitmostDataSourceService implements @docmost/git-sync's GitSyncClient natively:
  reads via PageRepo/SpaceRepo (listSpaceTree complete:true, getPageJson), writes
  via PageService (create/removePage soft-delete/movePage with computed fractional
  position/update-rename/restore) + the writeBody linchpin through collab
  openDirectConnection('page.'+id, {actor:'git-sync'}) mirroring
  collaboration.handler withYdocConnection 'replace'. bind({workspaceId,userId})
  returns the context-bound client for the orchestrator.
- 10 unit/contract tests (mapping + soft-delete + move-position), tsc clean.

Known gap (closed in A.4b): PageService.create/update/movePage only branch on
actor==='agent'; git-sync provenance is already passed through so the row source
marker propagates once PageService honors 'git-sync'. Module/orchestrator/config
come next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-21 14:52:06 +03:00
parent 7c3199f597
commit cdf2d2f2e9
6 changed files with 754 additions and 4 deletions
@@ -52,7 +52,12 @@ export function resolveSource(
stickyTouched: boolean,
contextActor?: string,
): ProvenanceSource {
return stickyTouched || contextActor === 'agent' ? 'agent' : 'user';
// Precedence: agent > git-sync > user. The sticky agent marker wins so a
// window that mixed an agent edit stays tagged 'agent'; otherwise a native
// git-sync write (plan §8.1) tags 'git-sync'; a plain human edit stays 'user'.
if (stickyTouched || contextActor === 'agent') return 'agent';
if (contextActor === 'git-sync') return 'git-sync';
return 'user';
}
/**
@@ -176,6 +181,9 @@ export class PersistenceExtension implements Extension {
// Sticky agent marker: 'agent' if any agent edit landed in this window, OR
// if the current writer is the agent (covers a store with no prior onChange
// 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).
const lastUpdatedSource = resolveSource(
this.consumeAgentTouched(documentName),
context?.actor,