diff --git a/docs/plans/2026-09-26_lead-decisions.md b/docs/plans/2026-09-26_lead-decisions.md index 06fc2430..b10e9cbe 100644 --- a/docs/plans/2026-09-26_lead-decisions.md +++ b/docs/plans/2026-09-26_lead-decisions.md @@ -1086,3 +1086,25 @@ which stay with him. Each item names who decided it and what happened. for S4. Session events belong to S6, and credential events belong to S3. Anything S4 doesn't add is labeled "not in the Q1 module" in S5. +64. **Every decision-backed approval is single-use, and a class mismatch + refuses (2026-10-05).** Source: Darkwing's S2b round 1 review, #1525 + comment 26765, `agents/darkwing/work/slice1-s2b-review/` (4f28c090). + - Single-use covers every `authorize` that names a decision, not only + gated ones. One CTO yes to a coder's `task.scope.change` on a task + today authorizes every later scope change on that task in the run, + because the decision doesn't bind the change's content. Within-role + actions pass no decision and aren't affected. The S2b brief left + this open for review, and this settles it. + - The verbs that use a decision outside `authorize` consume it too. + Today `message.send` and `role.revoke` don't, so one gated + `message.send` approval sends without limit (Darkwing's R1). + - If a decision's recorded class differs from the action's current + class, `#checkAuthority` refuses with `decision-mismatch`. Today, + once policy makes an action gated, an arbiter's earlier approval + authorizes it as gated with no yes from Jason. That gap came from + S2, and the fix changes S2's behavior beyond the S2b brief. I'm + taking it in S2b round 2 anyway, because it's the same lines, and + in both directions it refuses rather than widens. + - Indexing the events scan stays a follow-up. Neither the + consumption check nor the existing raise lookup has an index, and + at slice 1 volumes that doesn't matter.