Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f61602a
fix(attribution): deterministic checkpoint metadata resolution across…
suhaanthayyil Jul 1, 2026
2c18b9f
fix(attribution): sound refresh outcome + honest miss wording (audit …
suhaanthayyil Jul 1, 2026
82e3c53
fix(attribution): evidence-gated miss wording + authoritative-remote …
suhaanthayyil Jul 2, 2026
197fe44
fix(attribution): honest docs + no dead log pointer (audit round 3)
suhaanthayyil Jul 2, 2026
53bc37a
fix(attribution): close FetchURL origin-fallback loophole; hermetic r…
suhaanthayyil Jul 2, 2026
543727e
fix(attribution): explicit checkpoint-remote source signal (audit rou…
suhaanthayyil Jul 2, 2026
81b7468
fix(attribution): single-resolution refresh closes the TOCTOU window …
suhaanthayyil Jul 2, 2026
b3f2532
fix(attribution): neutral wording for failed re-reads; consistent fet…
suhaanthayyil Jul 2, 2026
e3e391e
fix(attribution): fetch suggestion honest under unreadable settings (…
suhaanthayyil Jul 2, 2026
5e86d17
fix(attribution): hermetic reason tests; prose suggestions render as …
suhaanthayyil Jul 2, 2026
47760d7
fix(attribution): refs-backend-aware evidence + refreshed-store capab…
suhaanthayyil Jul 2, 2026
5e84fb0
test(attribution): pin checkpoint backend in evidence-wording tests (…
suhaanthayyil Jul 2, 2026
21c804f
fix(attribution): refs-primary soft branch fetch; unknown backend fai…
suhaanthayyil Jul 2, 2026
bf75bc7
fix(attribution): restore branch scope; honest soft-refresh wording (…
suhaanthayyil Jul 2, 2026
61cef5f
fix(attribution): soften only genuine branch-fetch failures; honest c…
suhaanthayyil Jul 2, 2026
0211097
fix(attribution): exhaustive-audit cleanup — soft-refresh honesty, re…
suhaanthayyil Jul 2, 2026
9ef2834
feat(attribution): interactive why viewer + tag legend
suhaanthayyil Jul 2, 2026
043702b
fix(attribution): legend states tags are per-commit inference
suhaanthayyil Jul 2, 2026
e31f619
fix(attribution): spell out the [AI]/[MX] inference rule in the legend
suhaanthayyil Jul 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions cmd/entire/cli/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/entireio/cli/cmd/entire/cli/logging"
cliReview "github.com/entireio/cli/cmd/entire/cli/review"
"github.com/entireio/cli/cmd/entire/cli/session"
"github.com/entireio/cli/cmd/entire/cli/settings"
"github.com/entireio/cli/cmd/entire/cli/strategy"
"github.com/entireio/cli/cmd/entire/cli/trailers"
"github.com/entireio/cli/cmd/entire/cli/validation"
Expand Down Expand Up @@ -542,9 +543,18 @@ func ensureCheckpointAvailable(ctx, logCtx context.Context, repo *git.Repository
}

branchDescription := "entire/checkpoints/v1 branch"
suggestion, isCommand := suggestCheckpointFetchCommand(logCtx)
if isCommand {
return repo, fmt.Errorf(
"checkpoint %s referenced by HEAD is missing from the local %s after a refresh attempt. Creating a fresh checkpoint here would overwrite the original session data on push. Run:\n\n %s\n\nthen re-run attach. If the colleague who made this commit hasn't pushed their checkpoint metadata yet, ask them to do so first",
checkpointID.String(), branchDescription, suggestion,
)
}
// Prose guidance (unreadable settings / underivable checkpoint remote URL):
// no command block — rendering prose as a pasteable command would mislead.
return repo, fmt.Errorf(
"checkpoint %s referenced by HEAD is missing from the local %s after a refresh attempt. Creating a fresh checkpoint here would overwrite the original session data on push. Run:\n\n %s\n\nthen re-run attach. If the colleague who made this commit hasn't pushed their checkpoint metadata yet, ask them to do so first",
checkpointID.String(), branchDescription, suggestCheckpointFetchCommand(logCtx),
"checkpoint %s referenced by HEAD is missing from the local %s after a refresh attempt. Creating a fresh checkpoint here would overwrite the original session data on push. %s — then re-run attach. If the colleague who made this commit hasn't pushed their checkpoint metadata yet, ask them to do so first",
checkpointID.String(), branchDescription, suggestion,
)
}

Expand Down Expand Up @@ -575,16 +585,46 @@ func checkpointPresentLocally(ctx context.Context, repo *git.Repository, refs cp
return summary != nil, nil
}

// suggestCheckpointFetchCommand returns a git fetch command the user can
// paste to pull the missing v1 metadata branch.
func suggestCheckpointFetchCommand(ctx context.Context) string {
ref := "entire/checkpoints/v1:entire/checkpoints/v1"
if remote.Configured(ctx) {
if url, err := remote.FetchURL(ctx); err == nil && url != "" {
return fmt.Sprintf("git fetch %s %s", url, ref)
// suggestCheckpointFetchCommand returns recovery guidance for a missing v1
// metadata branch. isCommand reports whether the suggestion is a pasteable git
// command; when false it is prose and callers must not render it with a
// "Run:" prefix or inside a command block.
//
// When a checkpoint remote is configured but its URL cannot be derived
// (FetchURL would silently fall back to origin), the suggestion points at the
// configuration instead: telling the user to fetch from origin would
// contradict the authoritative-remote policy and fetch from a remote that may
// not carry the metadata branch at all. The same applies when settings can't
// be read — a checkpoint remote may be configured in the unreadable file, so
// "fetch origin" is not safe guidance (remote.Configured would collapse that
// case to "not configured").
func suggestCheckpointFetchCommand(ctx context.Context) (suggestion string, isCommand bool) {
return suggestCheckpointFetchCommandForRefspec(ctx, checkpointBranchRefspec)
}

// Refspecs for the two checkpoint storage topologies: the v1 metadata branch
// (git-branch backend, and what attach/resume consume) and the per-checkpoint
// refs namespace (git-refs backend, where a v1-branch fetch cannot heal a miss).
const (
checkpointBranchRefspec = "entire/checkpoints/v1:entire/checkpoints/v1"
checkpointRefsRefspec = "'+refs/entire/checkpoints/*:refs/entire/checkpoints/*'"
)
Comment thread
suhaanthayyil marked this conversation as resolved.

// suggestCheckpointFetchCommandForRefspec is suggestCheckpointFetchCommand with
// the refspec chosen by the caller (branch vs per-checkpoint refs).
func suggestCheckpointFetchCommandForRefspec(ctx context.Context, ref string) (suggestion string, isCommand bool) {
s, err := settings.Load(ctx)
if err != nil {
return ".entire/settings.json could not be read — fix it first; the correct fetch remote depends on its checkpoint_remote setting", false
}
if s.GetCheckpointRemote() != nil {
url, usedCheckpointRemote, err := remote.FetchURLWithSource(ctx)
if err == nil && usedCheckpointRemote && url != "" {
return fmt.Sprintf("git fetch %s %s", url, ref), true
}
return "review the checkpoint_remote setting in .entire/settings.json (its URL could not be derived), then run: git fetch <checkpoint-remote-url> " + ref, false
}
return "git fetch origin " + ref
return "git fetch origin " + ref, true
}

func resolveCheckpointID(headCommit *object.Commit) (id.CheckpointID, bool) {
Expand Down
Loading
Loading