fix(git-sync): hold refs on suppressed deletes + stamp delete/restore provenance (PR #119 review)
Two stability warnings from the #119 review: 1. delete-cap no longer drops deletions forever. When planned deletes exceed GIT_SYNC_MAX_DELETES_PER_CYCLE the apply client's deletePage now THROWS instead of resolving to a no-op. A throw is recorded by the engine as a per-page failure, so `refs/docmost/last-pushed` is NOT advanced past the commit that dropped the files — the next cycle re-diffs from the un-advanced ref and re-plans the same deletes (a transient over-cap is retried, not silently dropped and then recreated by the next pull). Previously a resolving no-op let the engine count `deleted++` with no failure, advance the ref, and never replay the deletions. 2. git-sync soft-delete and restore now stamp provenance. deletePage routes GIT_SYNC_PROVENANCE through pageService.removePage, and restorePage stamps lastUpdatedSource='git-sync' on the restore update — so the page-change listener's loop-guard (skip when lastUpdatedSource==='git-sync') recognizes both as its own writes instead of scheduling a wasted echo cycle. Done via a backward-compatible optional `lastUpdatedSource` param on pageRepo.removePage/restorePage (omitted for ordinary user deletes/restores). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -473,11 +473,26 @@ export class GitSyncOrchestrator implements OnModuleInit, OnModuleDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
// When over the cap, neutralize deletes by wrapping the client's deletePage
|
||||
// into a no-op (every other op is forwarded). The dry-run already committed
|
||||
// the working tree to `main`, so the apply re-diffs and converges normally.
|
||||
// When over the cap, suppress deletes by making deletePage THROW (every
|
||||
// other op is forwarded). A throw is recorded by the engine as a per-page
|
||||
// `failure`, which (a) keeps `refs/docmost/last-pushed` from advancing past
|
||||
// the commit that dropped the files, and (b) makes the next cycle re-diff
|
||||
// from the un-advanced ref and re-plan the same deletes — so a transient
|
||||
// over-cap is retried rather than silently dropped forever. (A no-op that
|
||||
// resolved would let the engine count `deleted++` with no failure, advance
|
||||
// the ref, and never replay the deletions — a pull would then recreate the
|
||||
// user's deleted files. See PR #119 review.)
|
||||
const applyClient = suppressDeletes
|
||||
? { ...client, deletePage: async () => undefined }
|
||||
? {
|
||||
...client,
|
||||
deletePage: async () => {
|
||||
throw new Error(
|
||||
'git-sync: delete suppressed this cycle ' +
|
||||
'(over GIT_SYNC_MAX_DELETES_PER_CYCLE) — refs intentionally held ' +
|
||||
'so the deletion is retried, not dropped',
|
||||
);
|
||||
},
|
||||
}
|
||||
: client;
|
||||
|
||||
const pushResult = await runPush(
|
||||
|
||||
Reference in New Issue
Block a user