fix(git-sync): subpages round-trips (was {{SUBPAGES}} literal) + exhaustive all-node round-trip test
subpages exported to the literal `{{SUBPAGES}}`, which has no markdown/HTML
inverse, so on re-import it came back as a plain paragraph holding the visible
text "{{SUBPAGES}}" — the embed rendered as that literal string on the page
after a sync (round-trip data loss, seen live). It now emits the schema-matching
`<div data-type="subpages">` like every other embed node, so the schema's
parseHTML rebuilds the subpages node. Also dropped the leaf-atom content-hole
in the subpages renderHTML.
New committed regression coverage:
- packages/git-sync/test/roundtrip-all-nodes.test.ts — exhaustive serialize ->
deserialize round trip for ALL 40 node/mark types; each asserts the node/mark
survives and no `{{...}}` literal leaks. This is the test that caught subpages.
- §13.1 gate (git-sync-converter-gate.spec.ts): subpages added to the green
corpus (round-trips through the REAL server schema).
- Corrected two PR-authored tests that asserted the old {{SUBPAGES}} loss as
"by design" — they now assert the fixed round trip.
Also folds in review #1679 coverage-gap tests (no prod change): orchestrator
pollTick/enabledSpaces, datasource 3-way merge dispatch, page.repo
last_updated_source provenance SQL.
git-sync vitest 659 (+1 expected-fail), server tsc clean, server specs green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -932,7 +932,7 @@ const Subpages = Node.create({
|
||||
return [{ tag: 'div[data-type="subpages"]' }];
|
||||
},
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ["div", { "data-type": "subpages", ...HTMLAttributes }, 0];
|
||||
return ["div", { "data-type": "subpages", ...HTMLAttributes }];
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -649,7 +649,12 @@ export function convertProseMirrorToMarkdown(content: any): string {
|
||||
return `<div data-type="pageBreak"></div>`;
|
||||
|
||||
case "subpages":
|
||||
return "{{SUBPAGES}}";
|
||||
// Emit the schema-matching div[data-type="subpages"] so marked passes it
|
||||
// through as a block and generateJSON rebuilds the subpages atom. The old
|
||||
// `{{SUBPAGES}}` literal had no parseHTML inverse, so on import it stayed
|
||||
// as plain text — the embed rendered as the literal "{{SUBPAGES}}" on the
|
||||
// page after a round-trip (red-team: subpages round-trip data loss).
|
||||
return `<div data-type="subpages"></div>`;
|
||||
|
||||
case "status": {
|
||||
// Inline status pill. The schema reads the label from the element's
|
||||
|
||||
Reference in New Issue
Block a user