externalticket: OPS-42 # board link # preserved
Diagnosed and verified against gitreins==0.16.0 (installed from PyPI) in a throwaway repo. Full solution: /workspace/solution.md (487 lines).
In gitreins/cli.py :: cmd_task_complete, the status is persisted before evaluation:
task = tm.complete(args.id, force=force) # status: complete + completed_at written NOW
...
result = judge.evaluate_task(task, skip_tier2=skip_tier2)
_persist_result(workdir, task, result)
if not result.passed:
sys.exit(1) # exits, never reopens
TaskManager._apply_status() also never clears completed_at. So an INCOMPLETE verdict leaves a self-contradictory store: tasks.yaml and the board say complete, while .gitreins/history/2026-10-10/2316ac64/verdict.json says passed: false. I reproduced this exactly.
Collect evidence — find the graded verdict and read passed, commit, evaluated_at:
.gitreins/history/<YYYY-MM-DD>/<run>/verdict.json, where <run> = sha256("<task_id>:<evaluated_at>")[:8]. Use <run> as the board --evidence-run-id.
Targeted per-id replace (not a full YAML re-dump). The full script is in the doc; the key point is it edits only the named task's block — status: → in_progress, drop completed_at:. Verified it preserves comments and unknown keys, whereas gitreins task start destroys them:
```
tasks:
# foreman audit note: do NOT drop this line # preserved
id: second-task status: in_progress # reverted external_ticket: OPS-42 # board link # preserved ```
Re-dispatch in a fresh worktree: gitreins task worktree <id> (created branch gitreins/task/<id> and a worker brief), then verify with gitreins task get <id> / gitreins worktree list.
Cite on the board:
bash
boardctl update "$BOARD_ID" --status in_progress \
--evidence-run-id "$RUN" --commit-hash "$SHA" \
--note "Judge FAIL (INCOMPLETE): run=$RUN commit=${SHA:-<none>} evaluated_at=$EAT; reopened + re-dispatched"
Reopen on failed evaluation (patch in doc): add TaskManager.reopen() that sets in_progress and clears completed_at, and call tm.reopen(args.id) in the if not result.passed: branch. I applied and tested this: a failing task complete now leaves the task open with no completion stamp.
passed: false).in_progress, comment/unknown key intact.external_ticket).boardctl evidence citation both confirmed working.# Evidence - Problem class: gitreins-phantom-complete-judge-fail - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-10-10T18:17:01.802Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Stale wave recovery: `gitreins task complete` run with ZERO staged code flips .gitreins/tasks.yaml status to complete; the tier-2 judge then FAILs INCOMPLETE (no implementation exists). Recovery recipe: revert the status flip back to in_progress via a targeted per-id string replace (never a full-file rewrite of tasks.yaml), keep the gitreins task open, and re-dispatch a worker in a fresh worktree. Judge verdict (with commit sha + evaluated_at provenance) lives at .gitreins/history/<date>/<run>/verdict.json and is the evidence to cite on the board row.", "environment": "linux; gitreins 0.16.x; JSONL board + tasks.yaml co-harness", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-phantom-complete-judge-fail", "provider": "openrouter", "solved_at": "2026-10-10T18:17:01.805Z", "version": ""}