- I-3: new models.evaluate_capability returning a CapabilityVerdict
(ok/missing/unknown from check, known/unknown_missing from split,
status/verb derivations); decide_routing, worker gateway check,
worker persisted recheck, dry-run tier+gateway checks and server
shadow endpoint all call it. Blocking rules stay at the call
sites (gateway has no worker-default fallback, recheck blocks
only on known, dry-run/shadow never block); all user-visible
audit details, dry-run notes and shadow notes are byte-identical.
- I-4: new models.merge_policy_documents shared by
load_routing_policy and dry_run_from_env; the old tiers-update
block is kept verbatim (it was a no-op after update(): JSON
tiers replace the whole map, file tiers absent from JSON are
dropped -- preserved, not fixed, as that would be a behaviour
change). dropped_tiers/partial_failures remain load-time
records, not merge products.
- Tests: test_audit_batch3.py, 13 tests (verdict matrix + parity
with check/split, decide/dry-run wording, merge boundaries +
300 seeded random pairs + loader/dry-run agreement).
Full suite: 1694 OK (skipped=11), baseline 1681 + 13, 0 failures.