Guard entire attach against overwriting checkpoints from other machines#1014
Merged
Conversation
Entire-Checkpoint: e83cb707c70f
Entire-Checkpoint: 321e85e6b869
Entire-Checkpoint: e7316f61963c
Skip the metadata refresh when the checkpoint is already on the local entire/checkpoints/v1 branch — no network round-trip on repeat attaches. When the refuse path fires, suggest a fetch from the configured checkpoint_remote URL if one is set, instead of unconditionally pointing users at origin. Entire-Checkpoint: 941a2b7d55bf
Contributor
There was a problem hiding this comment.
Pull request overview
Guards entire attach against accidentally overwriting checkpoint metadata when a commit references an Entire-Checkpoint: ID that isn’t present locally, and adds a logging “tripwire” to help detect unexpected session-0 overwrites.
Changes:
- Add an
entire attachpre-write guard that verifies the referenced checkpoint exists locally (with a refresh attempt) and refuses with an actionablegit fetchhint if not. - Add a warning tripwire in
writeStandardCheckpointEntrieswhen session 0 would overwrite metadata from a different session ID. - Add tests covering: session appends on repeated attach, refusal on missing checkpoint, and tripwire warning emission.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| cmd/entire/cli/attach.go | Adds checkpoint-availability guard + fetch-command hint; ensures logs are closed per run. |
| cmd/entire/cli/attach_test.go | Adds regression tests for “append vs overwrite” and “refuse when missing” behavior. |
| cmd/entire/cli/checkpoint/committed.go | Adds tripwire warning when session-0 overwrite looks suspicious. |
| cmd/entire/cli/checkpoint/committed_tripwire_test.go | Adds a unit test asserting the tripwire warning is logged with both session IDs. |
The fast path was reading the checkpoint via the go-git store, which silently falls back to refs/remotes/origin/entire/checkpoints/v1 when the local branch is missing. So a freshly-cloned repo where the checkpoint exists only on the remote-tracking ref passed the guard, then WriteCommitted created an orphan local branch with an empty tree, and the push would have clobbered the remote — the exact case the guard is meant to block. Check for the local branch ref explicitly before trusting the read. In v2-only mode, use the v2 store instead (refs/entire/main has no remote-tracking analog, so the equivalent of this hole doesn't exist there). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: eb718cd31155
The assertion reads the WARN line from the log file, which only gets written when the configured level is WARN or lower. A dev (or CI job) running with ENTIRE_LOG_LEVEL=error would see an empty log and a spurious failure. Setenv the level at the top of the test so the assertion is environment-independent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 03c1d6bf9b6b
computermode
previously approved these changes
Apr 23, 2026
Contributor
computermode
left a comment
There was a problem hiding this comment.
Added some questions for my understanding but looks good 🙌🏻
In v2-only mode (checkpoints_version: 2) the guard was telling users to fetch entire/checkpoints/v1, which is the wrong ref — v2 lives under refs/entire/checkpoints/v2/main. The refresh step also called getMetadataTree (v1) instead of getV2MetadataTree, so the best-effort refresh did nothing useful when v2 was the active format. Branch both the refresh and the fetch-hint on the storage version. v1 stays as-is; v2-only points at refs/entire/checkpoints/v2/main with a fully-qualified refspec (short names don't resolve outside refs/heads/). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 5ff33f043f7c
If a v1 checkpoint write targets slot 0 and the tree already holds session-0 metadata for a different sessionID, stop instead of logging a warning and proceeding. That shape means either tree corruption or a stale root summary; silently overwriting data we don't know about is the wrong default. findSessionIndex only picks slot 0 when existingSummary is nil or when the summary claims slot 0 is ours, so this check never fires on the normal append-a-session path. In condensation (post-commit hook) the error is swallowed as before — but that path can't produce this shape because condensation always writes under a fresh or summary-coherent ID. The paths that can reach it (attach, migrate) are foreground, so the refuse surfaces to the user. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 8518f599b0e2
v2 is about to become the primary storage format, and writeMainCheckpointEntries has the exact same clobber shape as v1: if slot 0 already holds metadata for a different sessionID and findSessionIndex still picks 0, writeMainSessionToSubdirectory wipes the subtree and writes ours on top. Mirror the v1 refuse. Drop the "run 'entire doctor' to investigate" breadcrumb from both messages — doctor only checks branch-level disconnection and v2 ref health, not within-tree summary/session-ID coherence. Replace with the git ls-tree invocation the user can actually run to capture the shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 664ec1791597
pfleidi
approved these changes
Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://entire.io/gh/entireio/cli/trails/cf1eb592e195
Summary
A production report surfaced a scenario where
entire attachcould silently clobber a colleague's session data. If Alice creates checkpointabc123on her machine and pushes the code commit (withEntire-Checkpoint: abc123trailer) without also pushingentire/checkpoints/v1, then Bob pulls the commit and runsentire attach, Bob's attach reuses IDabc123, writes a fresh session 0 locally, and on push overwrites Alice's session data.This branch adds two layers of defence and one diagnostic tripwire.
Changes
entire attachrefuses to overwriteWhen HEAD already carries an
Entire-Checkpoint:trailer, attach now verifies the checkpoint is present on the localentire/checkpoints/v1branch before writing:entire resumeuses (checkpoint_remote→ treeless origin fetch → full origin fetch → remote-tracking).git fetchcommand targets the configuredcheckpoint_remotewhen present, otherwiseorigin.Tripwire in
writeStandardCheckpointEntriesIf a session-0 write is about to replace metadata from a different session ID (a tree-corruption / stale-summary shape, not a routine overwrite path), emit a loud
logging.Warnwith both session IDs so future regressions leave a trace.Tests
TestAttach_AppendsAsAdditionalSessionWhenIDDiffers— positive path: two attaches on the same commit land as session 0 and session 1 under the same checkpoint.TestAttach_RefusesWhenCheckpointMissingFromLocalBranch— negative path: commit bears a trailer for a nonexistent checkpoint; attach errors with the actionable hint and creates nothing.TestWriteStandardCheckpointEntries_WarnsOnUnexpectedSessionZeroOverwrite— verifies the tripwire fires and captures both session IDs.Behaviour notes
Entire-Checkpoint:trailer are unaffected — new attaches create fresh IDs as before.Test plan
mise run checkentire/checkpoints/v1locally, runentire attachagainst the commit → verify refuse + hintentire attachtwice on the same session-free commit → verify second attach appends as session 1 without a network fetchNote
Medium Risk
Medium risk because it changes
entire attachbehavior around checkpoint reuse and git metadata fetching, which can affect users’ ability to attach sessions and may surface new failure modes in repos with unusual ref/remote setups.Overview
Prevents
entire attachfrom accidentally overwriting an existing checkpoint ID created on another machine by verifying the referenced checkpoint exists locally before writing; if missing, it attempts the same metadata refresh chain asresumeand then refuses with an actionablegit fetchhint.Adds a diagnostic tripwire in
checkpointwrites that warns when a session-0 write would replace metadata for a different session ID (stale/corrupt tree shape), plus new tests covering append-as-new-session behavior, refusal on missing checkpoint metadata, and the warning emission.Reviewed by Cursor Bugbot for commit a5be08c. Configure here.