The test client set its read timeout before every frame. On macOS that
fails with EINVAL once the handler has sent its final frame and closed,
so every admin test that reads a second frame failed there (40 runs of
40 at 2408e2c). The frame is already buffered, so the client now takes
that one refusal as the peer having closed and reads it. The plan's copy
changes with it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Implemented decide and redecide in crates/brokerd/src/policy.rs:
SessionState, Label, Denial, private Matched, and Decision/Ask (private
fields, Debug only, nine getters each) with the Outcome enum. decide
rejects an unknown tool (args not parsed) and malformed arguments before
matching, then runs the M1-M5 matching pass in id order and returns
Allowed/Ask/Denied by the winner's mode; redecide re-runs matching now
and rebuilds the Decision from the Ask. Seven doctests (six compile_fail,
one compiling) guard the two facts. policy 7, policy_matching 10,
policy_redecide 7, policy_property 4, doc 7 all pass; make gate ok.
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
crates/brokerd/src/grants.rs reads grants/*.toml into a GrantSet: load reports every problem in every file and returns either a complete valid set or the full problem list, never a partial one; from_grants sorts by id and collects every rule-2..9 problem; render prints each problem then the runbook pointer. All 17 grants tests pass; make gate prints gate: ok.
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)