Goal and scope
Back-fill Architecture Decision Records for decisions that already shape Phlo but had no record. Each ADR is written from the repository itself: code, configuration, CI and release tooling, the CHANGELOG, and the closed issues and pull requests that introduced the behaviour. Each has the status Accepted (back-filled 2026-10-30), the approximate original date and the evidence. Where the original rationale is not recoverable, the Context section says so instead of supplying one.
Non-goals: no runtime, configuration or policy change. No existing ADR is edited.
| ADR | Title | Primary evidence |
|---|---|---|
| 0054 | Workspace monorepo released as one release set | #300, commit 8f8247e2, #732, #895, #914, #1102; relx.toml |
| 0055 | Provider-neutral core and declared package edges | #639/#709, #994/#1036; boundary AST tests |
| 0056 | Core layering and acyclic imports enforced by import-linter | #1019/#1096; [tool.importlinter] contracts |
| 0057 | Cyclomatic complexity gate with a shrinking baseline | #1001/#1033, #996/#1106 |
| 0058 | Support manifest as the authority for support scope, maturity and gates | #579, #895; registry/support/v1.json and its validator |
| 0059 | Python 3.12 and generated Docker Compose as the runtime baseline | #52, #579, #962 (3.11 to 3.12), #1104 |
| 0060 | Regulated mode and signed service-to-service identity | #466, #583, #600, #611; later changes in ADR 0047 and #813 |
| 0061 | Run-evidence store on SQLite in development and PostgreSQL in production | #577, #726/#737 |
| 0062 | Cap dependencies that break contracts, and qualify before lifting | #1097, #1021/#1110; registry/support/dependency-qualification.md |
| 0063 | Fail-closed vulnerability policy with time-boxed, human-reviewed exceptions | #655, #1063, #1068, #1168; security/dependency-policy.md |
| 0064 | Separate CI contracts with one required result and no silent skips | #999, #1068, #998/#1111; docs/contributing/ci.md |
| 0065 | Deprecations name a removal release, a replacement and a usage measure | #860/#899, #997/#1082 |
| 0066 | Observatory keeps its Node runtime as an authenticated API-adapter tier | #1051, #1013, #998/#1111 |
| 0067 | Explicit freshness, grain, reconciliation and data-interval contracts | #1197, #1198, #1199; research assessment |
Candidates considered and not recorded
- Lockstep versioning of all packages: not what the code does. Packages keep independent versions (0.1.0 to 0.18.0) released as one ReleaseX release set. ADR 0054 records the actual decision.
- Observatory as a Python-served frontend: ADR 0032 already records that target, and the shipped Observatory runs its own Node server. ADR 0066 records the decision that replaced the target.
- Plugin discovery through entry points: already covered by ADRs 0030, 0033 and 0041. Only the missing boundary rule is recorded, in ADR 0055.
- Nessie/Iceberg/Trino/MinIO/PostgreSQL/Dagster as the blessed stack: folded into ADR 0058 as the
blessed_coreprofile. ADR 0047 already names the production stack. - Single-maintainer ownership and material-change review policy (#1015):
docs/contributing/change-policy-proposal.mdand CONTRIBUTING.md state that this is not accepted policy. - Package-owned typed process settings (#1012): covered by ADR 0045.
- Separate support-decision governance (#837): closed as deferred; the support manifest carries those decisions (ADR 0058).
Change map and risk
Documentation only: 14 new files under docs/architecture/decisions/, plus appended rows in index.md and meta.json. No behaviour changes.
A concurrent PR adds ADR 0053 and also appends to index.md and meta.json. Whichever merges second needs a trivial rebase to keep both entries in numerical order.
Observed while writing (not changed here): CONTRIBUTING.md still refers to an Observatory eslint-suppressions.json, which was deleted with the legacy UI in #1051.
Verification
At df426c12 on top of origin/main 7feced4d:
-
python3 scripts/check_new_suppressions.py --base 7feced4d... --head HEAD: "New suppression inventory checked." (ADR 0057 now writes the marker asnoqa: C901without the hash.) -
python3 scripts/check_adr_index.py: "ADR index records and statuses match." -
python3 scripts/check_markdown_links.py: "All tracked Markdown links resolve." -
make docs-build: build complete at65750c58, with all 14 pages rendered. The rebuild after the two-character prose fix was killed for running out of memory locally; CI's docs lane covers it. -
codespellon the new files andgit diff --check: clean. -
Facts were checked against the source: import-linter contracts,
relx.toml, providerphlo>=0.18.0,<0.19ranges, three remainingnoqa: C901markers, support-manifest profiles, run-evidence store selection, dependency caps in each manifest, sortedphlo.__all__, and the Observatory service manifest. -
Not applicable: this change is documentation only and has no regression to test.
Recovery and maintainer decisions
Revert the commit to remove the records; nothing else depends on them. Please check that each ADR states the decision as you understand it, particularly 0054 (the reason for the release_set switch is not recoverable), 0059 (#962 does not state why the minimum became Python 3.12) and 0066 (it records a departure from ADR 0032's target).
github.comment.notice: falsein.github/pr-lens.ymlturns this note off