Kernel: a machine user's approval is measured from the act that read the description, and one nothing anchors holds an edit (#195)

Merged
DO
2d ago
+226-15

Part of #195, on the Factory Builder's ruling of 2026-11-07. It closes the requirement #550 left on it. A machine user's approval is now measured from the start of the approving act's Run that read the description, not from the moment the approval lands. So an edit made in the act's last seconds, between its read and its approval, holds the item. The record is NNNN until it is given a number at enqueue.

#195 closes when #196's shims land, the approve.yml shim among them, as ruled.

What changes

FileChange
kernel/derive.pyapproval_anchor dates each approval in one of three ways. An act's approval: when the latest issue-approval Run on its content was made, by made_at, its dispatch, which a re-run keeps. A browser's approval (decision 0046), where a record of the item started no later than it: its own time. Otherwise before every time, so any edit holds: with no such record, beside a re-run act with no dispatch read, or with a record whose time cannot be read. description_anchor takes the records by name only, and derive always passes them
tests/test_decide.pytest_an_approval_is_anchored_at_the_act_that_read_the_description, which also holds that derive gives the records, an empty list included, and that nothing else calls the anchor. One existing case gets a record before its 12:05 approval, so it keeps testing what it meant
tools/mutants.pyTwenty mutants under "Issue 195", and three of 0135's repointed at the lines they mutate now, each killed by the test its row names
docs/decisions/NNNN-…The record, which amends 0135's anchor and 0140's first "does not see" clause; its rows name their mutants as 0154 asks

Why an approval with no record holds, not falls back

Records expire oldest first, and an act's Run is made before its approval, so it is not gone while a record made before it stays. With no record that old, the approval may be an act's whose Run has expired, and falling back to the approval's own time would reopen the gap. The record names the residuals. An item whose oldest retained record postdates a browser's approval holds on any edit, which fails safe. Two pass an edit unseen: an act's Run a person deletes by hand, and a Run made while the act ran, whose record's start is when it was made (P-44), once the act's Run is past retention. #609 takes up the second, and #608 teaches the simulator's world the Run anchor (a protected edit).

Not changed

facts/1 and the held-out cases: run records already carry started_at. The simulator's sim/world.py and tests/test_simulator.py (protected) are also unchanged. description_anchor with no records given keeps the world's reading, since the world's act records its Run in the approval's own second, and derive always gives the records.

Protected paths

None.

Reviews

RoundHeadReaderRead, and what changed
18107a3cClaude, with securityA re-run moved the act's start past its approval: fixed in 0d131e3 (timed by dispatch)
18107a3cCodexThe same re-run case: fixed in 0d131e3, and a re-run with no dispatch read holds in 5951e4e
18107a3cAstra, as Muse's stand-in (Muse: not run, quota)The latest act untested; a record after the act but before the approval: fixed in 0d131e3 (test, and the lane in the record)
18107a3cArgonThe latest act untested: fixed in 0d131e3
172e8d34The BuilderGuard the runs=None default: keyword-only, and tests that derive gives the records and nothing else leans on it
25951e4eClaudeAn impossible date raised; the lane does not stop a dispatch: fixed in eaaaf2d
25951e4eArgonA finer test pair: in #609
3eaaaf2dClaudeA record's start is when it was made, even while it waits (P-44): the record names it as a residual (5d9f8a8), #609
35d9f8a8ArgonAn unreadable start beside a readable dispatch passed, against the rule that an unreadable fact holds: fixed in 590d44d
—5d9f8a8verifyThe simulator's seed 69: a later first-attempt act with no dispatch was taken for a re-run: fixed in 590d44d
4590d44dClaude, ArgonNo blocker; a non-text start test, in #609; a wording row, fixed in b6d3b6f

Verify

make verify on an export of 590d44d (b6d3b6f differs only in the record's wording), the record numbered in the export only: 1658 tests, OK, the simulator among them. Each Issue 195 mutant is killed by the test its Boundary row names. Muse's read is owed after 2026-11-09 (not run, quota); Astra read in its place.

šŸ¤– Generated with Claude Code