Skip to main content
This page describes how access contracts are declared, checked against the code, and exercised. For how to review an access entry in the PRD view, see Reviewing results. The API Access & Rules section of the PRD documents, for each endpoint: who can call it, whose rows it returns, and what it rejects. None of this is written by hand. Each endpoint declares a structured access contract, the build checks the contract against the code, and tests exercise every rule it declares.

The access contract

Every backend procedure gets an entry declaring its access as structured data: whether the caller must be signed in, which scopes the procedure requires, and how rows are scoped to the caller: own rows only, rows reachable through a declared relationship (a reporting chain, a project membership), rows in the caller’s org, or public. Attribute-based overrides (“admins can see others’ rows”) are declared against real columns, and bespoke rules the vocabulary can’t express are named conditions. Two properties keep the contract honest:
  • It must match the code’s guards. The declared authentication and scopes are cross-checked against the procedure’s actual guard at build time. A contract claiming a scope the procedure doesn’t enforce fails the build, and vice versa.
  • It must be exercised. The build derives from the contract the exact set of scenarios the entry’s test has to cover, and fails until each exists.

Scenarios: every boundary gets a real request

The entry’s test expresses each boundary as an isolated scenario: its own seed, real calls against the running backend as specific personas, and read-only verification of the outcome.
The derived checklist is thorough by construction. Signed-in required: prove the anonymous caller is denied. Scopes required: prove a signed-in caller without the scope is denied. Owner-scoped: prove the owner’s call works, with its effect verified in the data, and that another user’s doesn’t. Relationship-scoped: prove the direct report is visible, the indirect one behaves as declared, and someone outside the chain is excluded. Each business rule: prove the boundary rejects it. The build names exactly which scenario is missing until the entry is fully covered. Scenarios keep a strict shape so the evidence stays legible: seed once, then every state change goes through a real endpoint call (captured in the transcript). Database access inside the scenario is read-only, so a test can’t write the expected result into the database and then assert it. Business rules live here too, but only as enforced rejections: “at 3 active tasks, a 4th is rejected.” A behavior the app performs is a feature, even when it’s permission-flavored; see PRD structure.

Generated descriptions and review flags

From the verified contract, the build generates everything the reviewer reads:
  • “Who can do this” and “How access is verified” — the plain-language description of each endpoint’s rules is generated from the contract, not written by a person.
  • Concerns — review flags computed from what the contract permits: an endpoint where any signed-in user can modify rows they don’t own, or read every row, gets a warning that the permissive access should be verified. An unauthenticated surface is labeled “Anyone — even without signing in —”. Nobody types a concern by hand, and nobody can forget one.
This is the property described in The trust model: a rule the code doesn’t enforce fails its test, and the descriptions of enforced rules are generated rather than written.

Needs attention

Concerns are a review signal, not a build failure. A permissive endpoint might be intended (a public read of a shared catalog) or an oversight. The build stays green either way, and the PRD view surfaces every flagged entry under a need attention count in the header, next to current, needs re-recording, and failing. The reviewer decides: confirm the permissive access is intended, or send it back to be locked down. See Reviewing results. The system’s guarantee is that every permissive endpoint gets flagged for that decision.