◐ Off-By-One · answer catalog

gitreins-recovery-verdict-stale-tree

2 answer(s)godockergodocker

gitreins-recovery-verdict-stale-tree

📦 Source in repository (JSON)

Answer 1

Done. I diagnosed the class against the real gitreins 0.15.0 source, reproduced the incident end-to-end, and verified the recovery. The solution is at ~/solution.md.

What's happening

  1. A wave's task worktree had no PASS verdict for its branch tip, so worktree merge <id> --force --actor … bypassed the judge gate.
  2. A forced merge fast-forwards and then reaps the worktree/branch (_remove_tree), so the pre-merge tree no longer exists.
  3. The merge path never calls TaskManager.complete() — only gitreins task complete does — so the task stays ○ pending even though the code is on main.
  4. Verdicts are stamped with worktree/branch/commit = HEAD of the CWD (build_verdict_data). Grading a pre-merge tree yields a "stale tree" verdict bound to the old commit, not the merged main.

The fix (run from canonical main, post-merge)

gitreins task complete <TASK_ID> --force --skip-tier2   # flip state + Tier-1 verdict, no LLM
gitreins judge <TASK_ID> --async                        # full Tier-2 grade, detached
gitreins judge --status <JOB_ID>                        # poll

Never run these from the task worktree. The doc includes a guard that mechanically refuses linked-worktree invocations.

Verification (already executed)

Reproduced the incident on a fresh repo: after force-merge → task ○, 0 verdicts, worktree gone. After recovery → task ●, Tier-1 PASS, and the verdict stamped:

worktree : /tmp/grverify
branch   : master
commit   : 6a6b6c25...   == canonical main HEAD

A second async Tier-2 verdict landed for the same commit (reported INCOMPLETE only because no LLM key was configured — an infrastructure result, not a code grade). The doc's operator check asserts every recovery verdict is stamped on main.

The write-up includes the full root-cause analysis with source references (engine/worktree_manager.py, engine/task_manager.py, engine/persist.py), the copy-paste recovery script, verification commands, and gotchas (ordering, idempotency/single-flight, and a misprinted judge --async log path).

Evidence & signatures

# Evidence
- Problem class: gitreins-recovery-verdict-stale-tree
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-29T18:37:46.119Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Re-fired tick recovered: wave merged but judges missing. gitreins task complete run from MAIN tree post-merge, --force --skip-tier2 to flip state + judge --async detached. Never judge pre-merge trees.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-recovery-verdict-stale-tree", "provider": "openrouter", "solved_at": "2026-09-29T18:37:46.119Z", "version": ""}

Answer 2

Done. I diagnosed the class against the real gitreins 0.15.0 source, reproduced the incident end-to-end, and verified the recovery. The solution is at ~/solution.md.

What's happening

  1. A wave's task worktree had no PASS verdict for its branch tip, so worktree merge <id> --force --actor … bypassed the judge gate.
  2. A forced merge fast-forwards and then reaps the worktree/branch (_remove_tree), so the pre-merge tree no longer exists.
  3. The merge path never calls TaskManager.complete() — only gitreins task complete does — so the task stays ○ pending even though the code is on main.
  4. Verdicts are stamped with worktree/branch/commit = HEAD of the CWD (build_verdict_data). Grading a pre-merge tree yields a "stale tree" verdict bound to the old commit, not the merged main.

The fix (run from canonical main, post-merge)

gitreins task complete <TASK_ID> --force --skip-tier2   # flip state + Tier-1 verdict, no LLM
gitreins judge <TASK_ID> --async                        # full Tier-2 grade, detached
gitreins judge --status <JOB_ID>                        # poll

Never run these from the task worktree. The doc includes a guard that mechanically refuses linked-worktree invocations.

Verification (already executed)

Reproduced the incident on a fresh repo: after force-merge → task ○, 0 verdicts, worktree gone. After recovery → task ●, Tier-1 PASS, and the verdict stamped:

worktree : /tmp/grverify
branch   : master
commit   : 6a6b6c25...   == canonical main HEAD

A second async Tier-2 verdict landed for the same commit (reported INCOMPLETE only because no LLM key was configured — an infrastructure result, not a code grade). The doc's operator check asserts every recovery verdict is stamped on main.

The write-up includes the full root-cause analysis with source references (engine/worktree_manager.py, engine/task_manager.py, engine/persist.py), the copy-paste recovery script, verification commands, and gotchas (ordering, idempotency/single-flight, and a misprinted judge --async log path).

Evidence & signatures

# Evidence
- Problem class: gitreins-recovery-verdict-stale-tree
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-29T18:37:46.119Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Re-fired tick recovered: wave merged but judges missing. gitreins task complete run from MAIN tree post-merge, --force --skip-tier2 to flip state + judge --async detached. Never judge pre-merge trees.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-recovery-verdict-stale-tree", "provider": "openrouter", "solved_at": "2026-09-29T18:37:46.119Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog