Fix Checkpoint Push and Doctor Command Issues · Entire
Overview
PR #1643 replaces three go-git worktree.Status() calls on hook hot paths with a new GitCLIStatus(ctx) helper that shells out to git status --porcelain=v1 -z -uall --no-renames and parses the output into a go-git-compatible git.Status map. The motivation is sound: go-git stats and hashes every on-disk file (including large gitignored trees), causing 40–55s hook latency; native git prunes ignored dirs. I verified the core mechanics are correct:
- StatusCode mapping is exact — go-git's
StatusCodeconstants (status.go:75-82) are byte-identical to porcelain v1 letters, so the drop-in claim holds. --no-renamesis the right choice for parity — go-git's Status derives changes via merkletrie diff (worktree_status.go:86-130) and splits renames into Delete+Add rather than emittingR;--no-renamesmakes the CLI do the same, so both sides agree.- Parser is robust —
XY<space>pathlayout,-zdisables quoting, trailing-NUL empty entry filtered bylen < 4,entry[2] != ' 'guard is safe for all real entries including unmerged (UU). - No import cycle / unused vars —
cli → strategyis allowed and already imported;worktreeis still used forworktree.Filesystem().Root();paths.WorktreeRoot(git rev-parse --show-toplevel) and go-git's worktree root resolve to the same top-level, so joined file reads in the attribution path stay correct. - Test change is sound —
testutil.InitRepo(already the established pattern in the file) creates a real.gitwithrefs/that native git recognizes; empty-HEADgit statusworks fine.
Findings
cmd/entire/cli/state.go — DetectFileChanges switch (~line 298) — unmerged (merge-conflict) status codes are silently dropped, a behavior change from the go-git path (PLAUSIBLE).
The switch only categorizes Untracked / Deleted / Modified / Added. Native git status reports merge-conflicted files with unmerged codes (UU, AA, DU, etc.) → Staging='U', Worktree='U', which match none of the cases, so a conflicted file lands in no bucket (New/Modified/Deleted). go-git's Status() never emits U — its derivation (worktree_status.go:92-129) only produces Deleted/Added/Modified/Untracked/Unmodified, so a conflicted file previously surfaced as Modified and was captured. Failure scenario: an agent turn ends while a merge/rebase/cherry-pick conflict is unresolved in the worktree → the turn-end checkpoint's file-change set omits the conflicted file(s) until the conflict is resolved. Self-healing once resolved, and merge conflicts mid-turn are uncommon, so this is low-severity — but it's a genuine, PR-introduced difference worth a case ... == git.UpdatedButUnmerged arm or an explicit note. (The parallel loop in calculatePromptAttributionAtStart is not affected — it filters on "any non-Unmodified code," so UU passes through there.)
Nothing else survived scrutiny — the reuse/altitude story is actually a plus here (the PR consolidates the per-call-site CLI-status pattern into one shared helper rather than adding a bandaid), and the measurements and test alignment check out.