feat(git-sync): phase 2a — folder-note layout (parent -> Folder/Folder.md)

Native-Obsidian structure: a page WITH children now lives at its folder-note
<name>/<name>.md (LostPaul Folder Notes convention) with its children alongside;
a leaf stays <name>.md. Folder-notes claim their canonical path before a
same-named child, so the child (a leaf) is the one disambiguated, never the
folder-note — a folder X/ always contains its own note X.

Format-agnostic and safe in isolation: only the destination PATH changes, the
file content/serialization is untouched, so an existing parent relocates via the
move-by-id path (no delete). The frontmatter format flip (pull+push) is next.

6 new layout unit tests (leaf / parent / nested / child-named-as-parent /
twin-parents / childless). 611 engine tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-24 04:38:07 +03:00
parent 5d818abcdf
commit a80e9d91aa
3 changed files with 109 additions and 4 deletions

View File

@@ -28,9 +28,11 @@ describe('computePullActions — normal complete fetch', () => {
treeComplete: true,
existing: [],
});
// Each live page is (re)written at its deterministic layout path.
// Each live page is (re)written at its deterministic layout path. `root`
// has a child, so it lives at the folder-note `Root/Root.md` (native-Obsidian
// layout), with the child alongside it in that folder.
expect(actions.toWrite).toEqual([
{ pageId: 'root', relPath: 'Root.md' },
{ pageId: 'root', relPath: 'Root/Root.md' },
{ pageId: 'child', relPath: 'Root/Child.md' },
]);
expect(actions.moved).toEqual([]);