docs: brief for decision closes and messaging lists (#1627), row 120 follow-up

Ruling: the business validator refuses a messaging-limited arbiter, and
decision.raise checks that the route may message the raiser. The close
insert stays unchecked, so no decision is left that its resolver can't
close. Owner dewey, reviewer filbert.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-15 12:12:47 -05:00
co-authored by Claude Opus 5.5
parent 5f457b2ff9
commit 07c12b51bb
+71
View File
@@ -298,6 +298,77 @@ its code (`role-end-refused` for the chief's own run, a validation
code for an invalid change); the chief's bundle text differs from
another role's as item 3 says. Mutants for each.
## Decision closes and messaging lists
Follow-up to row 120, small. Gitea #1627. Filbert raised it in comment
28548 on #1614, and my ruling in 28540 kept it out of row 120.
- Owner: dewey. They may start on refactor now. Rows 123 and 121 touch
`broker.mjs` and `business.mjs` as well, so whichever lands second
rebases and reruns its gate.
- Reviewer: filbert.
- Requirements: REQ-ASSIST-2.
Row 120 checks messaging lists on `message.send`, `review.request` and
`review.verdict`. A decision close by anyone but the raising run also
stores a message, a DECISION from the closer to the raising role, and
that insert isn't checked. Filbert probed row 120's candidate with
`arbiters.delivery` set to `assistant`. A coder raised a delivery
decision, the assistant resolved it, and the DECISION message to the
coder was stored, even though the assistant's `message.send` to the
coder is refused.
Nothing reaches this today. Only `roles/assistant.json` declares
messaging lists. Jason's file names pm and cto as arbiters. The
assistant's grants (`message.send` within its role, nothing cross-role)
make every decision it raises either within-role or gated, never
routed to an arbiter.
**Ruling.** Check at load and at raise, not at close. A refusal at close
would leave a decision that its resolver can't close, and only the
raiser's withdraw would clear it.
**What ships.**
1. The business validator refuses an arbiter whose role definition
declares messaging lists. The message names the arbiter kind, the
instance and the definition. An arbiter answers whichever role
raises, so a limited one can't do the job. Definitions are resolved
before arbiters are checked (`business.mjs:150`), so this is a few
lines after line 158. Jason's file passes, because pm and cto declare
no lists.
2. `decision.raise` checks that the route may message the raiser,
before it stores anything. For a cross-role decision the sender is
the arbiter. For a gated one it's the human. The rules are
`#checkMessaging`'s, with the route as sender and the raiser as
target, so in practice the raiser's `receiveFrom` must list the
arbiter's definition or `human`. A refusal has its own code, logs
`action.refused` and stores no decision. A within-role decision,
routed to the raiser's own role, is exempt. Make `#checkMessaging`
take a sender as well as a target. `message.send`, `review.request`
and `review.verdict` keep their behaviour, and row 120's tests pass
unchanged.
3. The close insert stays as it is. Definitions change only with a
pinned copy, and arbiters only through the validator, so a decision
that passed item 2 can still be closed. Add a comment at the insert
saying so.
4. Row 120's packet. `agents/researcher/work/queue-120/build.md`, Round 2
section, says the assistant "can't be the raiser", but test 1 has the
assistant raise a decision. A committed packet is evidence and isn't
edited. This row's BUILD.md carries the correction with Filbert's
replacement text from 28548.
**Acceptance.** Tests:
- The validator refuses a messaging-limited arbiter for each kind. It
accepts the shipped example and an arbiter without lists.
- A raise whose route can't message the raiser is refused with the code
and stores no decision. Cover a cross-role route and a gated route.
- The assistant's within-role and gated raises still work.
- Row 120's messaging tests pass unchanged.
Mutants: drop the validator check; drop the raise check; check the
raiser-to-route direction instead; drop the within-role exemption.
## The plug-in layer: kind registry and loader
Build step 6b, medium. Gitea #1626.