fix(git-sync): a git edit that drops the gitmost_id frontmatter is no longer lost (C10-D1)

If a git-side edit rewrote a page file WITHOUT its `gitmost_id` frontmatter (e.g.
a tool that regenerates the whole file), the push planner's M (modify) branch found
no pageId in the current meta and SKIPPED the file — then the next Docmost->git push
overwrote it with the DB content, silently reverting the edit (data loss, found via
web-test).

Mirror the D (delete) branch: recover the identity from the PRE-IMAGE meta (the
last-pushed version at the same path, which still carried the id) before skipping,
and apply the body edit as an update. The pushed-back re-serialize restores the
frontmatter next cycle, so the file self-heals. Only when the pre-image ALSO lacks
an id (a never-tracked page) is it genuinely skipped.

Verified on the stand: editing a synced page's file with the frontmatter removed now
applies the edit (was reverted). Unit test: a modified file with no current pageId
recovers it from the pre-image -> update. git-sync suite green (705).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-03 05:41:42 +03:00
parent f36a2def73
commit cec50c3ce4
2 changed files with 35 additions and 8 deletions
+19 -6
View File
@@ -389,12 +389,25 @@ export function computePushActions(input: PushActionsInput): PushActions {
} else if (pageId) {
actions.updates.push({ pageId, path: change.path });
} else {
// A modified file with no pageId has no Docmost target to update.
actions.skipped.push({
path: change.path,
status: "M",
reason: "modified file has no pageId in meta",
});
// The current file has no `gitmost_id` — but it was MODIFIED, so a prior
// version existed at this path. Recover the identity from the PRE-IMAGE
// (the last-pushed version at the same path, which still carried the id),
// mirroring the `D` branch. Without this, an edit that also dropped the
// frontmatter (e.g. a tool that rewrote the whole file) is silently
// skipped and then reverted by the next Docmost->git push — the edit is
// lost (bug C10-D1). The pushed-back re-serialize restores the frontmatter
// next cycle, so the file self-heals. If the pre-image ALSO lacked an id
// (a page never tracked), there is genuinely nothing to update -> skip.
const prevPageId = metaAt(change.path, "prev")?.pageId;
if (prevPageId && !ghostMove.has(prevPageId)) {
actions.updates.push({ pageId: prevPageId, path: change.path });
} else {
actions.skipped.push({
path: change.path,
status: "M",
reason: "modified file has no pageId in meta (nor in pre-image)",
});
}
}
break;
}