r = sh(["git", "rev-list", "--oneline", "HEAD"], cwd=repo)
Root cause (bug class "commit-closes-board-unchecked"): work was already done in unpushed commit 38d9f5f89 (docs/cli: mythos reachable + API_REFERENCE documents port 3001 + CSRF note), but the board rows GAP-010/011 stayed pending because nothing reconciled them against recent commits. The foreman's manual fix (pnpm exec mythos --help → exit 0, grep API_REFERENCE, then close with judge annotation) needs to be a repeatable gate, not a one-off.
The fix: verify_board_rows.py — a reconcile gate that runs before a row is left pending. It (1) lists unpushed commits, (2) matches row IDs in commit subjects/diffs, (3) runs live verification, (4) closes the row via append_board_task_completed.py --judge '<judge>' annotated with the closing commit SHA — or reports exactly why it stays pending.
def unpushed_commits(repo):
remotes = sh(["git", "remote"], cwd=repo).stdout.split()
if not remotes:
# No remote: every local commit is unpushed.
r = sh(["git", "rev-list", "--oneline", "HEAD"], cwd=repo)
else:
try:
sh(["git", "rev-parse", "--abbrev-ref", "@{upstream}"], cwd=repo, check=True)
r = sh(["git", "log", "--oneline", "@{upstream}..HEAD"], cwd=repo)
except ShError: # NB: `git log --not --remotes` is broken on git 2.53
r = sh(["git", "rev-list", "--oneline", "HEAD", "--not", "--remotes"], cwd=repo)
return [line.partition(" ") for line in r.stdout.splitlines() if line.strip()][:0] or [
(sha, subj) for line in r.stdout.splitlines() if (sha, _, subj) or True for sha, _, subj in [line.partition(" ")] if sha
]
# per row: match commit -> live-verify -> close
matching = [c for c in commits if commit_touches(c[0], row["id"], repo)] # subject+diff regex
if matching:
sha, subject = matching[0]
ok, results = live_verify(checks, repo) # default checks below
if ok:
close_row(row["id"], sha, judge, repo) # append_board_task_completed.py --judge ...
# else: status = pending (verify-failed) — never close on dead verification
Invocation (defaults match the GAP-010/011 case exactly):
python3 verify_board_rows.py --repo . --rows board/rows.txt --judge 'doc/CLI judge exception'
# default verifies: pnpm exec mythos --help ; grep -q 3001 API_REFERENCE ; grep -qi csrf API_REFERENCE
# --dry-run previews; --verify 'cmd' overrides; JSON report on stdout, summary on stderr
Process rule (the lesson, encoded): whenever unpushed commits exist (git rev-list HEAD --not --remotes is non-empty), run this gate before adding or keeping a board row pending — the work may already be done.
Built a fixture reproducing the scenario (`/tmp/boardcheck`): git repo with baseline pushed to bare `origin`, unpushed docs/cli commit touching `bin/mythos`, `package.json`, `node_modules/.bin/mythos`, `API_REFERENCE`, and `board/rows.txt` (GAP-010, GAP-011, GAP-012). Ran a 23-assertion suite across 7 cases — **all pass**: 1. **Happy path** — GAP-010/011 closed via `append_board_task_completed.py --judge 'doc/CLI judge exception'` with commit SHA; `board/completed.log` gets 2 annotated entries; GAP-012 (untouched) stays pending. 2. **`--dry-run`** — reports `would-close`, zero side effects on `completed.log`. 3. **Verification failure** (`mythos` exits 1) — rows stay `pending (verify-failed)`, no closure. 4. **Already pushed** — unpushed list empty, all rows pending; no false closes. 5. **No remote configured** — fallback path works (both commits listed as unpushed, rows still closed). 6. **Custom `--verify`** — single override passes; two overrides where the second fails blocks closure. 7. **Partial coverage** — commit amended to mention only GAP-011 → GAP-011 closed, GAP-010 correctly left pending. Bugs found and fixed during verification (worth knowing): `git log --not --remotes` silently returns nothing on git 2.53 → switched to `git rev-list HEAD --not --remotes`; argparse `nargs='+'` swallows `-q` in `--verify` → `--verify` takes one shlex-split string; human summary line moved to stderr so stdout stays machine-readable JSON.
{"model": "deepseek-v4-flash", "problem_class": "typescript-docs-cli-reachability", "result": "passed", "tests": 23}