Twinned from https://github.com/cfsh/ninefold/issues/525 by tools/beads/import_github.py's reconcile pass.
Suggestions from ninefold-reviewer's review of #519. All advisory — none blocked that PR, which is CONVERGED. Filed unclaimed.
WRAP_UP still announces "no open tracked PRs" while a paused one is opentools/pr/poll.py:946. #519 F2 stops paused counting toward tracked_open, which is right — but the message the predicate prints was not updated with it. Driving emit_tracked_prs + emit_idle with #485's real shape (paused, no owed ledger) at head a4d0abd:
``` ─── PR #485 OPEN MERGEABLE/CLEAN chore/co-located-tests -> main ⓘ paused — ON HOLD and held out of f5/integration; not awaiting action, and NOT counted as live work for wrap-up. ... WRAP_UP: no live work — no open tracked PRs, no claimed issues. The chunk is done (CLAUDE.md, "Chunks, and wrapping one up"): close or RELEASE claimed issues, confirm tracked PRs are merged/closed with a clean ledger, ... ```
Two things, three lines apart:
paused the one exception: unpause and finish, hand it to another session, or — last resort — close it. The digest offers only merged/closed, and closing #485 throws away the work paused exists to protect.The functional guard is in place (CLAUDE.md wrap-up condition 2), so this is a message-text fix, not a behaviour one. Shape: when a paused PR is tracked, say so at the decision point — e.g. WRAP_UP: no live work — 1 paused tracked PR (hand it over first, see CLAUDE.md), no claimed issues. That needs emit_tracked_prs to return the paused count alongside tracked_open.
↳ still owes a reply? line has no testtools/pr/poll.py:705. Deleting the whole print(...) leaves all 70 test_poll.py tests green (run, not reasoned). Its own sibling annotation *is* pinned — test_a_paused_pr_says_it_is_not_awaiting_action / ..._is_out_of_f5 (tools/tests/test_poll.py:798,803) — so the class and the convention both already exist; this line just missed them. It is the line that tells the operator why a pause has not freed their wrap-up, which is the thing #519 F3 added it for.
Minor, same line: it prints for every paused PR, including ones with no verdict and nothing owed. Phrased as a question so it is not false, but it could be conditional on the gaps_pointers computation that happens ~50 lines below in the same loop.
test_a_HEALTHY_baseline_read_still_sweeps_through_rebuild does not assert the sweep rantools/tests/test_rebuild_f5.py:831. Its docstring is "the other direction, so the skip cannot silently become permanent" — but the only assertion is assertNotIn("sweep was SKIPPED", errs), which also passes if sweep_artifacts is never called at all. Its sibling test_a_failed_build_still_sweeps has the pattern that works: assert a status read appears *after* the checkout-back in the command log.
The important direction is genuinely pinned — dropping required=True at rebuild_f5.py:532 goes red (verified) — so this is test strength, not a hole.
rebuild_f5.py still says "Test-drive with ./f5.sh"tools/pr/rebuild_f5.py:591-598 (and :9, :67, :477). Pre-existing on main, not introduced by #519 — but #509 landed f5.py and CLAUDE.md now says outright *"The command is ./f5.py"*, with f5.sh surviving only as an exec shim. The completion line is the one place an operator is told what to run next, and it names the shim.
paused bullet doesn't mention the wrap-up countCLAUDE.md:577 is where a reader goes to learn what paused does, and it still enumerates only the f5 and reviewer-mute boundaries — *"it changes nothing about reviews, approval, or the merge ledger"*. True, and now incomplete: since #519 it also suppresses poll.py's live-work count. That fact is documented 150 lines earlier under wrap-up condition 2, which is the right place for the *rule* but not the place anyone looks up the *label*. One cross-reference sentence.
None.
No comments.