Kernel: a Pause stops approvals and merges, not only Runs
Note, added after merge. This pull request was merged with its first two commits. The third, which pins the order of the approver Hold and the Pause (the test, the mutant "a pause hides the approver Hold" and the row in decision 0003), was pushed after the merge and lands in "Kernel: under a Pause, the approver Hold shows first" (#76). Until then, main has 22 of these mutants, not 23.
Closes the first gap of the epic "Epic: nine gaps in the Kernel, found in review": with the Factory paused, or the Pause unreadable, a converged pull request was still approved and an approved one still enqueued.
What changes
kernel/decide.py: one helper,_pause(), read in both places an act is decided. In theconvergedbranch it now stopsissue_approvalandenqueue; before Admission it stops Runs, as before. A Pause defers withpaused, an unreadable one withpause_unreadable, the same codes Runs already get.tests/test_decide.py:test_a_pause_stops_approvals_and_merges_tooloses@pending, leavesNotYetHeld, and now asserts both sides of the boundary. Newtest_an_unreadable_pause_stops_approvals_and_mergescovers a missing key andNone, for approval and for enqueue.tools/mutants.py: one mutant for each place the rule acts ("a pause admits a Run", "a pause lets an approval or a merge through"), one for "an unreadable pause is read as no pause", and one for "a pause hides the approver Hold". 23 of 23 killed.- The order, ruled by the Maintainer on this pull request: when an item is both paused and held because its approver is its author or last pusher, the Hold the facts establish is the reason given.
test_under_a_pause_a_hold_the_facts_establish_shows_firstpins it, and decision 0003 records it. CodeRabbit asked for the opposite order; neither lets an approval through. - Documents: "not held yet" is gone from decision 0003 and lesson L-24; the design's state-table note now says a Pause stops approval and enqueuing too, as I-7 does.
Acceptance criteria (from "Kernel: a Pause stops every act, not only Runs")
- The pinned test passes with
@pendingremoved: under a Pause,defer, reasonpaused. - An unreadable Pause defers in the same way (reason
pause_unreadable, as for Runs). - Each place the rule acts has its own mutant, and both are killed.
- No document says
not held yetbeside this test.
Left open, on purpose
- A pull request already in the merge queue stays there under a Pause. That is the story "Kernel: what takes a pull request out of the merge queue".
- A malformed truthy value such as
"false"getspausedrather thanpause_unreadable. Both defer; lesson L-58 leaves the reading of the variable toadapters/.
Checks and reviews
make verifyandpython3 -m tools.mutantspass on agit archive HEADexport of the last commit. In a checkout that holds Claude worktrees under.claude/worktrees/,make verifyfails on those directories; that is unrelated and suggested as its own task.- A fresh-context read of the diff: all four criteria met; its two stale-text findings are fixed in the second commit.
- A security-only pass: only an exact
Falselets an act through; every other shape ofpaused, including0,""and a missing key, defers. No path reachesactoradmitwithout the Pause check. - The second model family's read is the Gemini code review and the other bot reviewers on this pull request, as the Maintainer directed. CodeRabbit has reviewed; the Codex bot stopped at its usage limit; Gemini has not posted yet.
- SonarCloud's quality gate fails on 0% coverage of new code: the repo produces no coverage report. Not required, and not this story's to fix. Not merged or enqueued; the Maintainer merges.
🤖 Generated with Claude Code
Closes #30