Kernel: a change to a model Lens's own inputs needs a person (#140)
Closes #140.
What this is. With one model family, the only judge of a change to a model Lens's own inputs that is not the Lens is a person. A pull request that changes one now converges only once every model Lens has reviewed its head, as before, and an account with write access other than its author has approved that head, by the Maintainer's ruling on ruling 3. Decision 0046, numbered at enqueue.
What it holds.
| Rule | Where |
|---|---|
config/hooks.json lists pr-review's own inputs as a model Lens's inputs: roles/pr-review.*, roles/pr-review/, its rubric, harness/ whole, the gate, coverage and the authority table, and the files that make the list (config/hooks.json, config/defaults.json, tools/hooks/protected.py) | config/hooks.json |
The Kernel is given their patterns as model_lens_inputs, from the same reading as protected_paths | tools/hooks/protected.py::model_lens_inputs |
A change to one waits in verifying, model_lens_input_needs_person, naming each pattern, the Maintainer's to see; a queued item leaves the queue | kernel/derive.py |
| The judgment is a standing approval of this content by a person with write access or the machine user, never an App or a Lens, who is neither author nor last pusher, as that account's latest verdict. Only a person's dismissal ends it (L-17) | a_judge, judged_by_a_person |
| The Factory's own approving act never supplies it: no approval is issued for such a change until a qualifying approval stands | the wait's place in reading, held by test_the_factorys_own_approval_never_supplies_the_judgment |
A list that cannot be read defers as protected_paths_unreadable | readable_rules |
The feed asks the Maintainer a_lens_input_needs_you: approve, or close | config/feed.json |
The Maintainer's ruling on ruling 3 (2026-10-21, through the orchestrator): "an APPROVAL of the current head by donpetry-bot or any other account with write access, other than the PR's author", and not the last pusher. His own changes converge once he approves as donpetry-bot in the browser, or a colleague approves. Posted on #140. The orchestrator added the gating files to the list.
Not here. The base-branch read of config/hooks.json waits on adapters/settings.py, as 0020's rows do.
Verify. make verify on a git archive export, SIM_SEEDS=40. The simulator's Maintainer world now touches config/authority.json, since config/defaults.json is on the list and no world gives a person's approval. Mutants: 18 for this rule, plus three older ones that follow the text they break, each killed by hand the CI way. The capped run cannot take kernel/derive.py, which has more than 40.
Reviews and the fix round.
| Reader | Finding | Done |
|---|---|---|
| Claude review | The Maintainer's-own-change clause let any session pushing as the Maintainer through | Removed; the Maintainer then ruled that his approval as donpetry-bot is the judgment |
| Claude review, security pass | The list could be emptied a row at a time by changes the Lens alone judged, or the model Lens renamed | The files that make the list are on it |
| Security pass | harness/__init__.py and roles/pr-review/prompt.md were not covered | harness/ whole, and roles/pr-review/ |
| Claude review | A Lens's dismissal ended a person's approval, against L-17 | Only a person's dismissal does; the Lifecycle transition it needed is gone |
| Argon, Claude review, Muse | The author's half of the rule had no test | A case and a mutant each for the author and the last pusher |
| Muse | An approval a later request for changes superseded still counted | That person's latest verdict counts |
| Muse | A rename out of a listed path had no test in this rule | A case and a mutant |
š¤ Generated with Claude Code