SIGN IN SIGN UP

feat(rustd): the approval gate decides, and the order it decides in is a type

The gate's pure core: which rule fires for an action, what that rule
decides, and how a recorded gate and the current policy compose.

`evaluateGate` walks the rules and answers a decision; `matchRule` walks
them again and answers the rule, because the decision discards which
rule produced it and the approval card needs that rule's
workspace-authored copy. The second carries a comment insisting it uses
"the same traversal and same first-match-wins order … so the two can
never disagree about which rule applied."

An invariant a comment has to insist on is one the code is not holding.
There is one walk here — `match_rule` — and the decision is a pure
function OF its result. They cannot disagree about which rule applied
because only one of them looks.

`route` ports faithfully, tests included: a recorded gate outranks every
policy outcome, including both that would otherwise pass. Those two rows
are what a mid-flight config PATCH produces, and under the other
ordering both released a parked event while its approval card still sat
unanswered. `RefState` stays three arms rather than an `Option` because
collapsing "no gate" and "cannot tell" is unsafe in both directions.

Condition evaluation is a chain of `and_then` ending in `is_none_or`, so
all five ways a context cannot answer a condition — absent, not an
object, missing field, non-string field, unparseable expression —
resolve through one expression rather than five `return true`s a reader
has to find. `every_undecidable_context_fires_the_gate` walks all five,
because a fail-safe that is safe for four of five inputs is not one.

The grammar lands in `afd_fleet_runtime` beside the field it interprets
rather than beside its one caller, because the Zig's header explains
why that sharing is load-bearing: a condition that parsed at write time
and not at eval time silently fires the gate on every matching action.
The write-time half is not ported here, and this is where it goes.

`GatePolicy::from_parts` is behind `test-util`: the production door is
the validating `TryFrom`, and a second way to build a policy is a way to
build an invalid one.

Not in this commit: parking, cards, anomaly counters, recorded-gate
reads. Every one is Redis or Postgres and every one is downstream of a
decision made here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
K
Kishore Kumar committed
e0055ffa5be7c42ad57e92cc28c31eaec49973b5
Parent: 23d546c