You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(checkpoint): harden refs backfill probe per review; rescope to store layer
Review findings from the PR #1824 multi-agent pass:
- Tests: pin the zero-cost claim (backfill with a locally-present ref never
fetches), verify the fetched-then-backfilled data reads back for all three
request types, and assert the backfill commit parents on the fetched tip
rather than orphaning over the checkpoint's history.
- Comments rephrased order-agnostically: the write-fallthrough they cited is
PR #1811's unmerged behavior; they now state the absence-vs-failure
contract instead of a phantom mechanism. refBase's doc names its other
deliberate callers (migrate.go local import; attach's externally-guarded
writeSession).
- FetchCheckpointRef's stale 'caller treats a fetch failure as not found'
comment inverted the actual contract this PR depends on; it now documents
failure-surfaces-never-absence, including the remote-lacks-ref caveat.
- ref-checkpoint-backend.md: the write shape and on-demand-fetch sections now
describe the create/backfill probe split.
Scope note (review CRITICAL): no production write path currently wires a
RefFetcher, so this PR is store-layer semantics + plumbing; the wiring is a
follow-up gated on (1) FetchCheckpointRef distinguishing remote-lacks-ref
(absence) from transport failure — today wiring would break the
pre-migration-hex fallthrough — and (2) a hook-appropriate fetch timeout.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/architecture/ref-checkpoint-backend.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -69,7 +69,7 @@ The git-refs store (`gitRefsStore`, `checkpoint/refs_store.go`) shares the check
69
69
70
70
Every persistent write (`WriteSession`, and the `Backfill*` operations for transcript / summary / attribution) follows the same shape:
71
71
72
-
1.**Resolve the ref's current tip**(`refBase`). A missing ref → `(ZeroHash, nil)`, so the first write to a checkpoint becomes an **orphan commit**. A real lookup failure (IO/corruption) is surfaced, never silently treated as "new checkpoint".
72
+
1.**Resolve the ref's current tip.**Creates (`WriteSession`) use the local-only `refBase`: a missing ref → `(ZeroHash, nil)`, so the first write to a checkpoint becomes an **orphan commit**. The `Backfill*` operations use `refBaseForBackfill`, which first on-demand fetches a locally-missing ref (when a ref fetcher is configured — the checkpoint may have been written or migrated on another machine); a ref still absent after the fetch surfaces as `ErrCheckpointNotFound` rather than orphaning, and a fetch failure surfaces as a real error, never as absence. A real lookup failure (IO/corruption) is surfaced, never silently treated as "new checkpoint".
73
73
2.**Build the updated checkpoint subtree** from the existing tree plus the new content (shared `treeWriter` logic).
74
74
3.**Create a commit** with the current tip as parent (orphan on first write, parented thereafter), so each checkpoint accretes its **own per-checkpoint history**.
75
75
4.**Point the ref at the new commit** (`setRef`) and **enqueue it for push**.
@@ -111,9 +111,9 @@ All checkpoint-ref pushes are **fast-forward-only — never a force push.** Ther
111
111
112
112
When a push *is* rejected as non-fast-forward — genuine divergence, e.g. the same checkpoint was written on two machines — recovery **fetches the remote ref and replays the local-only commits on top** (`fetchAndRebaseRefCommon`), then retries. After the replay the local ref is a fast-forward over the remote, so the retry is *still* non-force and the remote commit is preserved as an ancestor rather than overwritten. A genuine cherry-pick conflict (both sides rewrote the same file, e.g. root `metadata.json`) leaves the ref queued — degrading to the safe state, never forcing.
113
113
114
-
### On-demand fetch for reads
114
+
### On-demand fetch (reads and backfill writes)
115
115
116
-
A checkpoint written on another machine has no local ref. When a read misses locally and a **ref fetcher** is configured, `resolveRefMaybeFetch` fetches that one ref from the remote and retries once. It carefully distinguishes:
116
+
A checkpoint written on another machine has no local ref. When a read — or a backfill write's base resolution (`refBaseForBackfill`) — misses locally and a **ref fetcher** is configured, `resolveRefMaybeFetch` fetches that one ref from the remote and retries once. It carefully distinguishes:
117
117
118
118
-**genuinely absent** (remote has no such checkpoint) → maps to `ErrCheckpointNotFound`;
119
119
-**a real failure** (IO, network, context cancellation) → returned as-is, never swallowed as "not found".
0 commit comments