ADR Index¶
Architectural Decision Records for the Dazzle project. Agent-scannable: each line is a decision that prevents a wrong proposal.
- 0001 — MkDocs Material for docs. No wiki, no Docusaurus.
- 0002 — MCP = stateless reads. CLI = process/writes. Don't block conversation with long ops.
- 0003 — No backward compat before v1.0. Delete freely, never create shims or wrappers.
- 0004 — DSL optimized for AI agents. Precision and formal correctness over human ergonomics.
- 0005 — RuntimeServices dataclass on app.state. No new module-level singletons.
- 0006 — IR is immutable frozen Pydantic. Never mutate after parse.
- 0007 — RBAC: static matrix + dynamic conformance + audit trail. Three independent layers.
- 0008 — PostgreSQL is the sole database. No SQLite code paths.
- 0009 — Scope rules compile to 6-type predicate algebra. Validated against FK graph at link time.
- 0010 — permit = role gate (RBAC). scope = row filter (ABAC). Never mix.
- 0011 — Server-side HTML rendering + HTMX. No SPA frameworks. Originally Jinja2; rendering pipeline is now typed Fragments — see ADR-0023, post-#1042.
- 0012 — Alembic for schema migrations. No hand-rolled migration planners.
- 0013 — One per-project KG with TOML seed. No separate knowledge systems.
- 0014 — No
from __future__ import annotationsin FastAPI route files. Breaks OpenAPI. - 0015 — TigerBeetle for double-entry ledgers. Optional dependency, DSL
ledger/transactionconstructs. - 0016 — API Packs for vendor integration. TOML-driven mocks, webhook testing, DSL generation.
- 0017 — All schema changes via Alembic, including framework entities. No raw DDL at startup.
- 0018 — All file writes go to the project directory. Never write to the Python package directory.
- 0019 — (Entity, Surface, Persona) triple is the atomic unit of verifiable behaviour.
- 0020 — Lifecycle evidence predicates are orthogonal to state machines.
- 0021 — Marketing pages via
sitespec.yaml. No# dazzle:route-overrideon public paths. - 0022 — Don't put Alpine bindings on idiomorph-morphed elements. Server-render or use
x-inithelpers with direct DOM manipulation. - 0023 — Two-pattern template-emission model post-jinja2. Pattern A (framework writes HTML) uses f-strings +
dazzle.render.html.esc; Pattern B (framework executes user-authored templates) usesstring.Template. Choice is mechanical: who writes the template. - 0024 — No regex for DSL grammar. A regex parsing DSL is a signal for missing grammar, not an end solution. Lexical-shape regex (identifiers, numerics) is fine; matching call shapes / keywords / sub-expressions is not.
- 0025 — Authorization is entity-level only. Field-level auth is not added; it would break the enumerable role×entity×operation security surface. A field with its own lifecycle is its own entity. Field sensitivity uses
classify/pii(), notpermit:. - 0026 — Subtype polymorphism uses TPT (table-per-type), flat hierarchy, immutable discriminator. Complex, potentially brittle — only justified when all three conditions hold: true IS-A, subtype-specific NOT NULL fields, polymorphic queries genuinely needed.
- 0027 — No
polymorphic_ref:keyword, now or planned. Rails-era ORM idiosyncrasy that breaks referential integrity, scope composition, and JOIN-based queries. Every classic use case (comments, attachments, tags, audit log, notifications, likes) fails a four-question interrogation that routes to per-target refs, event-stream entities, per-pair junctions, or TPT (ADR-0026). Union sugarref X | Y | Zrejected outright.