9. Route guards plus strict requirement tracking
Routes declare their permission (Guard.Require, @RequirePermission).
Context
A route guard that checks "holds the permission somewhere" is necessary but not sufficient: the handler must also check the specific record. Forgetting that check is the most likely access bug, especially in AI-written code.
Decision
Routes declare their permission (Guard.Require, @RequirePermission). The guard answers 401/403 cheaply, then tracks (context in Go, AsyncLocalStorage in TS) whether the handler checked that permission against a record (Assert, Check, CheckMany, Plan). In strict mode (dev and tests) a successful response without that check becomes a 500 unchecked_requirement; otherwise it is logged. Routes with no record use RequireCapability. In Nest, routes with no declaration are denied by default.
Consequences
- Missing record checks fail tests instead of shipping.
- Go buffers responses in strict mode; Nest handlers on guarded routes must not use
@Res().
8. Both SDKs call Cerbos over its HTTP JSON API
Go and TS use Cerbos's HTTP JSON API (/api/check/resources, /api/plan/resources, /_cerbos/health) with a per-call timeout (250 ms default) and one retry.
10. Deviations from the architecture spec
What was built differently from the zynactra/access architecture spec, and why.