Acceptance port: an issue asks for a contract only by an Intent that asks or a person's factory:contract label; acceptance read whole when none asks (#290)
Merged
DO
7d ago+420+420+012345678901234567890123456789-26-26-01234567890123456789
Closes #290. This builds the Maintainer's rule of 2026-10-21, adopted on #191 (comment 6327479372), and records it as decision 0047 (the queue order: #293 keeps 0046, this takes 0047; it is enqueued only after #293 merges). 0047 adds to decision 0025.
What it adds
adapters/acceptance.pyreads whether the issues a pull request closes ask for an acceptance contract.- The closing references. They are read over GraphQL, in the shape P-33 and P-46 recorded, with each issue's repo and labels.
- The ask. An issue asks only when its item's Intent asks (
fixorimplement, which no Lifecycle runs yet) or when a person adds thefactory:contractlabel (kernel/terms.py). - How the label is read. It reads as the Kernel reads a control label (
standing_labels): only a person ends what a person placed (L-17). An App or the machine user, even acting with a person's token, neither asks nor ends a person's ask. A removal in the same second reads as placed. - The labels must agree. The labels GitHub lists on the issue must match what its timeline says.
- The result:
- No closing issue asks:
acceptanceis null and read whole. Slice 1 no longer defers on every pull request. - An issue asks: the read is not whole until
adapters/contract.pyreads the contract, so the Kernel defers. - Not whole for any of these reasons:
- closing references past their page, of another repo, or named twice;
- an issue's labels past their page, or out of step with its timeline;
- a short issue timeline;
- a pull request to a base other than the default branch, which carries no closing reference (P-33).
- A shape GitHub does not give is refused.
- No closing issue asks:
adapters/facts.pyputsacceptanceandcomplete.acceptancein the snapshot from this read.- A test pins every Intent a Lifecycle runs, so a new Intent is ruled on before it runs.
- Rows re-pointed:
- The rows for the contract's own read in 0015, 0018, 0022, 0025 and 0026 now wait on
adapters/contract.py. - Whether a contract exists is held by the new tests.
- The rows for the contract's own read in 0015, 0018, 0022, 0025 and 0026 now wait on
The known limit
The author writes the closing references, so removing "Closes" removes the ask. That is acceptable for slice 1, because fix and implement pull requests will be opened by the Factory's own Roles. Binding a pull request to its issue by its Run record or branch is filed as #295, "Acceptance: a pull request is bound to the issue it serves by its Run or branch, not by its author's closing link". 0047 names it, and its row waits on adapters/binding.py.
Gates
| Gate | Result |
|---|---|
| Claude review + security pass | three real gaps, all fixed in one round (4e45302): an App ending a person's ask, a non-default base, and a vacuous Intent guard |
| Muse (Wonder Full), first head | the same blocker (an App ending a person's ask) and two minors (can_write, malformed shapes), all fixed |
| AGY (Argon) | no findings |
| Capped mutant run, by hand | every adapters mutant killed (216 at 42d6078; the acceptance mutants again at 7be5456) |
| Export verify (7be5456) | exit 0, 962 tests |
tools/check_decisions.py in the checkout | passes |
🤖 Generated with Claude Code