Kernel: spent attempts hold the item even while a refused Run is queued

Merged
DO
2d ago
+211-17

Closes #158.

A count the completed Runs have spent now holds the item even while another Run is queued or in progress. Before, a Run in flight made the item wait, so a refused Run that stayed queued could hide attempts_exhausted or run_ceiling. The rulings are on #158. No new decision record: decision 0003 gains a row.

What changes

  • kernel/brakes.py: the ceilings are asked apart from the deferrals. run_ceilings covers a Run's attempts, its rounds and the Run ceiling; approval_ceilings covers an approval's attempts and the Run ceiling. on_run and on_act call them after the Pause, as before.
  • kernel/decide.py: while a Run is in flight, _decide asks only those ceilings, counted over completed Runs.
    • A Pause, a Pause that can't be read, or an unreadable count no longer hides a spent count.
    • A superseded Run is no attempt.
    • An act, including the act ceiling's Hold, waits for the Run. Taking the act ceiling's Hold there made an undeclared Lifecycle move (held → adjudicating by a Lens).
  • sim/world.py: uncovered reviews run on one seed in three, not on every seed as ruling 6 asked. At spread 1, the first 40 seeds (CI's mutant runs) no longer reach two paths the coverage tests ask for; the comment names them. Filed as #168, "Simulator: uncovered reviews on every seed, with the first 40 seeds still reaching every path". Seed 297 is covered and now ends with r4 superseded.
  • Mutants: one for each branch on the in-flight path, and one each for asking on_run or on_act in place of the ceilings. 21 were checked by hand, and all are killed.

Left out

  • #169, "Kernel: under a Pause, a spent count holds the item with no Run in flight too". With no Run in flight, a Pause still comes before the spent counts. Nothing is written while paused, but the two paths disagree. That needs a ruling.

Verified

  • make verify passes (655 tests) on a git archive export of 6ed8a96 with PATH=/usr/bin:/bin, after merging main. Every mutant target appears exactly once.
  • The simulator passes at 300 seeds on 8fea0ce.

Reviewed by: a fresh-context Claude review and a security pass on 64d50d4, and AGY (Gemini 4 Argon) on 64d50d4, then again on the fix round 8fea0ce, where it found nothing ("Approve"). The fix round answered:

  • AGY's blocker: a deferral hid a spent count while a Run was in flight;
  • AGY's missing mutants for the two branches;
  • the review's undeclared held → converged move. It doesn't arise: apply writes nothing to a held item, so the queued Run is superseded. Two test_transitions bases now reach that case.
  • the review's note that ruling 6's spread was narrowed without an issue (#168).

6ed8a96 only merges main (#166). The one conflict was the mutant list, where both sides were kept.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Items now honor completed Run and approval limits even while another Run is in progress. Waiting and in-progress Runs do not count as completed attempts, and superseded Runs are excluded.
    • Acts wait while a Run is in flight when the act limit is reached; completed approvals remain enqueued.
  • Tests
    • Added coverage for in-flight Runs and attempt limits, and updated simulator scenarios for uncovered acceptance criteria.