Skip to main content
Status: Proposed (RECONSTRUCTION — requires validation) · Date: 2026-08-17 (reconstructed) Refs: ../constitution/founding-constitution.md
⚠️ Reconstructed from the material we have, not recovered. Tags: [derived] is supported by evidence in the repository · [inferred] is deduced · [proposed] is a gap I filled.

Context

A platform that intends to outlive its vendors has to be able to replace one without a rewrite. The usual answer is “use interfaces”, which decays because nobody agrees on what deserves one — and in a codebase where agents write most of the code, that disagreement compounds every week. [inferred]

Decision

Hexagonal architecture without exception. [derived] Domain and application code depends on ports. A vendor SDK imported outside an adapter file is a defect, enforced by lint. The list of port categories is closed. [derived] Six categories exist; adding one requires a constitution amendment reviewed line by line by the owner. That closure is the load-bearing part: without it, “use a port” becomes “invent an abstraction”, and an abstraction invented per pull request is worse than none. Bindings are declared in each module’s composition root, makeDeps(ctx). [derived] The six categories are reconstructed with low confidence in ../constitution/founding-constitution.md Part 2. [inferred] Amendment A1 adds QueuePort and NotificationChannelPort as seven and eight.

Consequences

  • A vendor change is an adapter plus an ADR, not a migration.
  • Agents cannot invent abstractions, because the list of allowed ones is finite and named. − Some genuinely useful abstractions will be blocked until an amendment. That cost is accepted: the amendment ritual is cheap and rare, and the alternative is unbounded.

What I could not determine

Whether the database and authentication were deliberately excluded from the port list or simply never came up. R8’s getDb(tenantCtx) suggests deliberate exclusion. [inferred]