⚠️ This document is a reconstruction, not a recovered original. The founding session that produced rules R1–R20 and the six port categories is not in this repository. Amendment A1, the standards and every ADR from 009 onward reference them, so the gap blocks TS-002 and the amendment itself. Daniel asked for a draft to validate rather than a gap to wait on. Every rule below is therefore tagged with where it comes from, so the review can be fast where it is safe and slow where it is not:Status: PROPOSED RECONSTRUCTION · Date: 2026-08-17 · Validates:Nothing here is binding until you validate it. When you do, this file’s content moves intoAGENTS.mdand this document becomes the record of how it got there.
AGENTS.md §9
Part 1 — The rules
Architecture
R1. Hexagonal architecture, without exception. [derived] Domain and application code depends on ports. A vendor SDK imported outside an adapter is a defect. (Restated and extended by R21 in amendment A1, which is itself evidence that R1 exists in this form.) R2. Ports exist only for named categories. [derived] The list is closed. Inventing a category requires a constitution amendment reviewed line by line by the owner. (Amendment A1 exists precisely because this rule made addingQueuePort impossible
otherwise.)
R3. Adapter bindings are declared in a composition root. [derived]
Each module’s makeDeps(ctx) is the only place a port is bound to an adapter. (Named explicitly in
amendment A1’s R21.)
R4. A new vendor or dependency requires an ADR before its first import. [derived]
The stack is closed by default. (Referenced repeatedly across the drop as “the closed-stack rule”.)
R5. The monorepo is the unit of delivery. [inferred]
One repository, one lockfile, one version. Cross-project imports go through workspace packages,
never relative paths across project boundaries.
Multi-tenancy and data
R6. Every tenant-scoped table carriestenant_id and cell_id. [derived]
cell_id is the seam for future regional partitioning; it is present from the first migration and
unused until multi-region ships. (Both columns appear across the drop; the “cell-ready seams”
phrase comes from the original design conversation.)
R7. Row-level security is mandatory on every tenant-scoped table. [derived]
RLS is not a defence in depth on top of application checks — it is the boundary. An application bug
must not be able to cross a tenant.
R8. Database access goes only through getDb(tenantCtx). [derived]
There is no path to a connection that does not carry a tenant context. (Named verbatim in
standards/data.md.)
R9. Uniqueness on tenant-scoped data always includes tenant_id. [derived]
Added to standards/data.md §2b on 2026-08-17. Listed here because it belongs with R6–R8 and a
future reader should find the tenancy rules together.
R10. Never a Postgres enum for a business value. [derived]
Closed sets live in parametric tables with a stable code. (standards/data.md §2.)
R11. Never a monetary amount without its currency. [derived]
amount BIGINT in minor units plus currency_code. Never floats. (standards/data.md §3.)
Commands, events and state
R12. One command, one transaction. [derived] State change plus outbox event plus audit row commit together or not at all. (ADR-017 ratifies this as CQRS-lite, which implies the rule predates it.) R13. Domain events leave only through the transactional outbox. [derived] Direct publication is forbidden. (standards/events.md.)
R14. Reads are projections with a documented rebuild procedure. [derived]
A projection that cannot be rebuilt is a second source of truth. (ADR-017.)
R15. Every state change is audit-logged with a typed actor and a full diff. [derived]
(standards/data.md §7, DEC-C2.)
API and access
R16. Every endpoint declares exactly one permission. [derived]{module}.{resource}.{action}. Permissions bundle into roles; roles attach to users and to
machines. (DEC-D5, standards/api.md.)
R17. Our own surfaces consume only the public API. [derived]
Console, portal, widget and mobile go through packages/api-client. If our UI needs something the
API lacks, the API is incomplete. (Called “the golden rule” in standards/api.md; DEC-F5.)
R18. Latency budgets are Definition-of-Done items. [derived]
Not targets, not aspirations. Verified by load tests in certification. (DEC-D7.)
Process
R19. Documentation is part of the change. [inferred] Touching a schema or an endpoint without updating its spec is an incomplete change. A new decision goes to an ADR, not to a code comment. (Inferred from the documentation discipline visible throughout the drop and from the repository’s own CLAUDE.md.) R20. Stop conditions are binding. [inferred] When a task requires a decision not covered by a DEC, a standard or an ADR, the agent stops and asks. It does not choose and proceed. (Inferred from the existence of a stop-conditions list and from how consistently the drop defers rather than guesses.) R21. Per-module adapter binding. [amendment A1 — pending your approval] Different modules may bind different adapters for the same port, with the rationale in that module’s spec.Part 2 — The six port categories
⚠️ This is the weakest part of the reconstruction. Amendment A1 tells us there are exactly six and that queues were not among them. It does not tell us what they are. What follows is deduced from the vendors the suite already uses and from what a port would need to exist for. Treat every line as a question.
Categories 7 and 8 —
QueuePort and NotificationChannelPort — come from amendment A1 and are
not in question.
What I could not determine
- Whether database access is a port category or deliberately excluded. R8’s
getDb(tenantCtx)suggests the database is not behind a port — it is a direct, tenant-scoped dependency, which is a defensible choice given Drizzle is a query builder rather than a vendor SDK. [inferred] - Whether authentication is a port. Better Auth is configured, not called through an interface, which argues no. [inferred]
- Whether the sixth slot is
InvoicingPortat all, or something I have not thought of.
Part 3 — What is deliberately NOT reconstructed
Standards v1. Six standards in this repository are marked “v2” and say they amend a v1 baseline. I propose declaring the v2 documents self-contained and retiring the idea of a v1 rather than reconstructing six more documents from inference. They already state their rules completely; the “v2” label describes their history, not a dependency. If you remember a v1 rule that is missing, adding it to the v2 document is a one-line change. ADR-001 … ADR-008. Reconstructed as separate files, each with the same tagging as this document. See../adr/ — they are numbered 001 to 008 and their status is
Proposed (reconstruction).
The createInitiative slice. Reconstructed at
../slices/create-initiative.md, since every task spec declares
an archetype and half of them declare that one.
How to validate this
Read Part 1 first and only slow down on the four [inferred] and [proposed] rules — R5, R19, R20 and everything in Part 2. The [derived] ones you can confirm by recognition. Then tell me, per item: correct, wrong and here is the real one, or there was no such rule. Anything you say was never a rule gets deleted rather than kept “just in case” — a constitution with invented rules is worse than one with gaps, because agents obey it either way. Once validated, Part 1 moves intoAGENTS.md, AGENTS.md §9 disappears, and TS-002 unblocks.