10. Deviations from the architecture spec
What was built differently from the zynactra/access architecture spec, and why.
What was built differently from the zynactra/access architecture spec, and why:
| Spec | Built | Why |
|---|---|---|
| Go SDK talks gRPC to Cerbos | HTTP JSON in both SDKs (ADR 8) | One wire format, no protobuf dependencies, identical fixtures. |
@cerbos/orm-drizzle for list filters | Own translator (planToSql, drizzleFilter) (ADR 5) | The adapter does not escape LIKE wildcards. |
TS transport via @cerbos/http | Built-in fetch client (CerbosHTTP) | No dependency; the API surface used is two endpoints. |
| Break-glass: reason + max duration | Also: cannot be mapped to IdP groups; granting it is high severity | A group mapping would make break-glass permanent for a whole group. |
| Roles deleted when unused | Soft-deleted (deleted_at), key reusable | Revoked assignments and the change log keep pointing at the role. |
access_admin manages access | Plus access.delegation:any (ADR 7) and a ban on self-assignment | Without it the first admin could not hand out product roles; without the ban delegation:any would be self-service. |
/check takes resources from the client | /check takes IDs; the server loads records with registered loaders | The UI must never supply the attributes a decision depends on. |
Role list readable with access.role:read | Also with access.assignment:manage or access.group_mapping:manage | People who assign roles need to see them. |
| Change log append-only by convention | Enforced by triggers (no UPDATE, DELETE, TRUNCATE) | A bug or a stray script cannot rewrite history. |
| Strict mode fails unchecked routes | Only successful responses count | A handler that rejects input before touching a record did nothing that needed the check. |