Fix #424: fork operation #431

Merged
crueber merged 2 commits from fix/issue-424 into main 2026-09-13 03:24:56 +00:00
Owner

Implements docs/features/03 §7 (the unimplemented fork spec) plus the merge-durability fix the acceptance path requires.

Fork core (internal/pulls): ForkExecutor ShareExecutor wired at composition (verbatim pack set, fresh refs snapshot + branch override, checkpoint, child manifest.pb Create min_seq=seq+1); ForkInput gains visibility/branch/description with server-honored semantics; sync 409 fail-fast on taken names; #346 target admission; child access bootstrap; fork.json Root + listable GET forks index.

GC (internal/maintain): fork-network rule — superseded packs survive while any live fork-network manifest references them (transitive, probe-capped, fail-closed on corrupt index).

Reads (internal/wal): ancestor fallback for pack content (repo-prefixed keys cannot serve verbatim references — law-12 amendment in 03 Decisions); failure-path only, byte-identical non-fork behavior.

Merge durability (required by acceptance 3+7): merge/update-branch commits upload objects atomically (PackTip + RefPack seam, 04_git.md argv) — a merged parent was unclonable (upload-pack: not our ref), which no fork could survive.

UI/API: Fork button + Fork.jsx + Forks.jsx, summary fork_parent/forks + ETag, SDK, Apidocs.

Proof: pulls/api/maintain/wal/cmd green (race + >=95% cover), sim green, e2e full chain 7.5s (fork phase 91ms), node 893 pass (2 pre-existing smoke fails per #422 note), vite green. No new deps.

Implements docs/features/03 §7 (the unimplemented fork spec) plus the merge-durability fix the acceptance path requires. Fork core (internal/pulls): ForkExecutor ShareExecutor wired at composition (verbatim pack set, fresh refs snapshot + branch override, checkpoint, child manifest.pb Create min_seq=seq+1); ForkInput gains visibility/branch/description with server-honored semantics; sync 409 fail-fast on taken names; #346 target admission; child access bootstrap; fork.json Root + listable GET forks index. GC (internal/maintain): fork-network rule — superseded packs survive while any live fork-network manifest references them (transitive, probe-capped, fail-closed on corrupt index). Reads (internal/wal): ancestor fallback for pack content (repo-prefixed keys cannot serve verbatim references — law-12 amendment in 03 Decisions); failure-path only, byte-identical non-fork behavior. Merge durability (required by acceptance 3+7): merge/update-branch commits upload objects atomically (PackTip + RefPack seam, 04_git.md argv) — a merged parent was unclonable (upload-pack: not our ref), which no fork could survive. UI/API: Fork button + Fork.jsx + Forks.jsx, summary fork_parent/forks + ETag, SDK, Apidocs. Proof: pulls/api/maintain/wal/cmd green (race + >=95% cover), sim green, e2e full chain 7.5s (fork phase 91ms), node 893 pass (2 pre-existing smoke fails per #422 note), vite green. No new deps.
Implements docs/features/03 §7 (unimplemented spec): ShareExecutor copies
the parent manifest (verbatim pack set, fresh refs snapshot + checkpoint,
child manifest.pb Create min_seq=seq+1); fork-network GC consults
children's manifests before pack deletion; fork reads fall back across
the ancestry (repo-prefixed keys cannot serve verbatim references
otherwise — law-12 amendment, see 03 Decisions).

Also required by the acceptance path: merge/update-branch commits now
upload their objects atomically with the ref (PackTip + RefPack seam) —
a merged parent was unclonable (upload-pack: not our ref), which no fork
could survive.

UI: Fork button + Fork.jsx form + Forks.jsx list; summary fork_parent/
forks projection with ETag; SDK forks.create/list. Docs: 03 §5/§7/§8 +
Decisions, 04_git.md PackTip argv. No new deps.
Transient child-manifest errors, child-index errors, corrupt child
manifests, and probe-cap exhaustion with unvisited children remaining
now abort the sweep with nothing deleted (docs/features/03 §7 fail-closed
rule); only a deleted child (manifest 404) skips its subtree. Four new
regression tests; 03 Decisions records the rule.
Sign in to join this conversation.
No description provided.