Skip to content
CommonLayer
Documentation menu
On this page

Architecture decision records

These records explain why CommonLayer is built the way it is. ADR-0001 to ADR-0016 are the key decisions of the implementation plan (D1–D16); the later records capture decisions made while building, as recorded in the work-package status files.

Every record has the same short format: status (what was decided and how far it is implemented), context, decision and consequences. Where the implementation differs from the original plan, the record says so. A record is never rewritten to change its decision; a later record supersedes it. When later events changed a record's status or consequences (for example a test that has since run), the record carries a dated Amendment section at the end and an updated status line.

Plan decisions

ADRDecisionStatus
0001Modular monolith with thin binariesImplemented; every domain composed, REST and gRPC (amended)
0002Vertical domain crates, ports and the event outboxImplemented, with recorded deviations
0003SQLx with runtime-checked queries and real-database testsImplemented
0004PostgreSQL is the job queue and the outbox; Valkey is optionalImplemented; throughput not load-tested (amended)
0005Append-only double-entry ledger with database-enforced balancesImplemented; runtime role since WP-70a (amended)
0006RBAC with one static role-to-permission matrixImplemented; human-only set added (amended)
0007REST with generated OpenAPI; gRPC for machine clientsImplemented: OpenAPI document and gRPC (amended)
0008Server-side sessions, hashed tokens, JWTs only for the registryImplemented
0009CNCF Distribution as registry; the platform issues tokensImplemented
0010Cosign, Trivy and Grype as CLIs; OSV over HTTPImplemented; key-pair path ran in the publish drill; keyless never run (amended)
0011Images from verified upstream source on a from-scratch rootImplemented for linux/amd64; arm64 never built (amended)
0012Next.js App Router served same-origin with the APIImplemented; trusted-proxy bullet superseded by 0040 (amended)
0013protox compiles protobuf in build.rsImplemented with the gRPC service definitions (amended)
0014Money is i64 minor units plus a currency codeImplemented
0015Highly available PostgreSQL through CloudNativePGFailover test passed once on a GitHub runner; its moved hook form failed next (amended)
0016Apache-2.0 for platform, template, charts and build configurationApplied

Decisions made during implementation

ADRDecisionSource
0017Project categories follow the manifestsWP-10
0018commonlayer-observability is an allowed dependency of domain cratesWP-11, 12, 14, 15
0019The global rate limit runs after authentication (no longer fails open: per-process fallback, amended)WP-02, WP-70a
0020BusyBox is rebuilt with network applets compiled outWP-20
0021PostgreSQL uses the ICU locale provider by defaultWP-22
0022One integration-test binary per crateWP-01
0023An authentication gate answers 401 before body parsingWP-02
0024A workload principal for GitHub Actions OIDC submissions (wired, amended)WP-01, WP-11, WP-40
0025One SSRF-safe client for user-influenced outbound HTTPWP-01
0026Signing identities are globs over the workflow pathWP-20, WP-11
0027Referrer discovery without the OCI referrers API (amended)WP-11
0028Explicit verification waivers; some checks never waivableWP-11
0029SLA deadlines are permanent facts in their own tableWP-12
0030Embargoed findings never change the public security stateWP-10
0031The ledger books the amount a provider confirmsWP-14
0032Payout gates are identical for simulated and live runsWP-14
0033Eligibility evaluations are re-derivable and time-scopedWP-13
0034The base image ships its OpenVEX statementsWP-20
0035Approval decisions are human-only; service accounts never hold themWP-70a, WP-70b (review HIGH-2)
0036The processes connect as a least-privilege runtime database roleWP-70a, WP-70g
0037A second person confirms high-impact not_affected statementsWP-70a
0038Runtime settings are a closed, typed registry of policy valuesWP-70a
0039Source-built components are declared in the SBOM; their scan coverage rests on GrypeWP-70f
0040A forwarded client address is honoured only behind a declared proxyWP-70g, WP-70e
0041An ambiguous payout stays unknown and keeps its idempotency keyWP-70b (review HIGH-4)
0042Catalog entries stay in_development until signed artifacts are releasedWP-70f
0043One Playwright configuration against the portal on port 3000WP-70e
0044Security workflows probe for code scanning and fall back to artifactsWP-70d
0045The proposer never approves a reward, and a contribution is rewarded onceWP-70b (review HIGH-1)
0046Repositories stay with their maintainers: App connection, managed access, source backups, successionWP-80
0047Onboarding a project is connecting its repository, and one rule engine checks itWP-80
0048CI spends runner time on the newest commit and on what changedcoordinator
0049Every project is its own repository: first-party trees carry the template's .github/ and schema, own tags and signing identity; the platform only checks exported treesWP-83

Writing a new record

Copy the shape of an existing record, take the next number, and link it from this table. Record the decision when it is made, including the alternatives that were rejected and what the decision costs.