Section 8 of #212's change, after review: the Billing card's muted line under the Subscriptions row becomes an amber "Not delivering" badge on the row's value line, after the state badge, with a title that names the ladders and the holder ("Billing continues while a grant holds Demo Ladder."; with several subscriptions "Billing continues on <k> of <n> subscriptions while ..."). The operator's subscriptions list marks each displaced subscription's row with the same badge and title, read with one grouped statement per page and turned into titles by the same steps the card uses. A failed read on the list says "Failed to load deliveries." once above the table and marks no row. A paused subscription no longer counts: it generates no invoice, so "Billing continues" would be false; it is marked once it is active again. The grant form's warning now reads "Products marked ⚠ would supersede a tier a subscription pays for; the subscription keeps billing and delivers nothing on that ladder until the grant ends." The billing view it named before can change nothing. A Stripe-paused subscription's tier is still marked, an accepted edge until #269's change, which pauses a displaced subscription's billing and rewords the badge and the warning. Goldens: 16 change, each as item 8.9 lists: the organization page's JSON goldens rename DisplacementNote to DisplacementTitle, the two subscriptions-list goldens gain the title field, three HTML goldens carry the new warning, and grant-over-subscription.html the badge in place of the line. No other golden changed. Breaks (scripts/mutation-check, 31 of 31 CAUGHT): - paused restored - not_delivering removed from badgeMap - badge tone - list badge without title - card title never set - card template without badge - account form never chosen - n read as displaced count - subscription holder as grant - several holders as one - ladders joined with commas - sort removed - ladders not deduplicated - holders not deduplicated - status filter dropped (card) - status filter dropped (list) - list row in account form - list row in account form (list vs card) - list titles never set (the field set to strings.TrimPrefix of the title by itself, an empty string, because removing the line leaves titles unused and does not compile) - delivering row given the displaced title - list template without badge - list pool not default - list reads moved into the row loop (emulated: an inline closure calls the title read once per row; a helper only the break called would fail deadcode) - list DisplacementError assignment and L4 removed - O4 template line removed - O4 line moved under the table - rows dropped on a failed read - badge label - card badge without title - delivering row given an entry - old warning restored Hand capture on the Stripe sandbox (API 2025-02-24.acacia): a member subscribed to a $20/month tier through Checkout; an operator issued a complimentary grant of the tier above; an edit to the subscription at Stripe then reconciled it, and the reconcile logged "reconcile: product not conferred; another plan holds its ladder". The Billing card and the subscription's list row each showed Active and Not delivering at 1280 and at the 390 mobile width, with no sideways page scroll; the badge's title read by script: "Billing continues while a grant holds Demo Ladder." Captures under test/screens/displaced-subscription-waits/. The suite on reset databases passed on this section's tree, 4711 tests, 14 skipped; make screens changed no screen this section owns, and every registered form was captured. The review's last fixes (the list test's row checks now fail when a row is missing, two comment rewraps, task wording) came after it; the list test and its five breaks were rerun on them: pass, 5 of 5 CAUGHT. make lint passes; openspec validate --strict passes.
title, audience, summary
| title | audience | summary | |
|---|---|---|---|
| Domain Model Cards |
|
One card per domain model: purpose, invariants, dimensions, drift traps, and open questions, each claim cited to the migration, file, or decision that enforces it. |
Domain Model Cards
Each card in this directory describes one domain model as it is actually built, so a maintainer can modify that model without re-deriving its rules from migrations, specs, and decision documents. The cards are the descriptive home for the as-built models; the normative record — the designed schema, the decision log, the numbered design documents, and the glossary — lives in the synced design/ directory (Decision 141, design/documents/doc-43-schema-topology-and-documentation-division.md). Migrations are the ground truth for as-built claims.
The catalog was motivated by a 2026-07 inventory of the console's domain models, which traced the majority of a 56-finding UX audit to model-attributable causes: rules that lived only in prose, invariants enforced nowhere, and dimensions that were easy to conflate because no single page named them side by side.
The cards
- Product / catalog — how capabilities are packaged, priced, and sold; the dissolved kind taxonomy and the shape views that replaced it.
- Payments and Billing — billing accounts, subscriptions, invoices and payments projected from Stripe, scheduled changes as intent, and the reconciler.
- Plan Ladders and Transitions — ranked tiers, who occupies which rung, the append-only audit, and the conferral functions as sole writers.
- Entitlements — resource keys, sets and rules, grants as decrees, provisions as delivery, and the materializer.
- Acts — the act record for actions that write several rows, the plan acts' details, the obligations a default change or reorder owes its organizations, and the functions that are the only writers of its tables.
- Resource Pools — the per-organization container: workspace assignments, the two resolution directions, and pool-grain usage.
- Providers and Integrations — the registry and its connections, boot-time manifests, resource-key ownership, desired-state delivery, and the shared substrate.
- Domains Registry — claims as subtree ownership, placements as the only thing that serves, and the anti-abuse ledger.
- Identity, Organizations, and Workspaces — users vs persons, the containment ladder, org types as policy, and first-login provisioning.
A new domain model is not considered documented until its card exists and is listed here.
Card anatomy
Every card has four sections in this order:
- Purpose — what the model owns and why it exists, in plain present tense.
- Where this lives — a map of the model's pieces: each table, view, function, and code file, with one line saying what it is. Locations live here, not scattered through the body.
- Invariants — the rules the model guarantees, one per numbered entry so reviews can cite "invariant 3". Each entry carries an enforcement tag matching the actual mechanism: [db] means the database schema rejects violations outright; [db-code] means the database functions are written to uphold the rule, so reviews must protect it when they change; [app] means only application code upholds the rule, so new code paths must uphold it too.
- Dimensions — the orthogonal axes a maintainer must hold simultaneously, each defined where it is named.
Cards describe the model as it is today, for a reader who knows nothing yet. That means: no history, no decision numbers, no change narrative in the body — a card introduces every table, column, view, and concept before or where it first uses it. Drift between design and code, open questions, and other bookkeeping live on the forge tracker, not in the cards.
Style contract
Card prose follows these rules, and edits are reviewed against them:
- Write for someone with zero context: never assume the reader knows a term, a table, or an internal codename you haven't introduced.
- Name the agent: state what acted and what it acted on.
- Give each verb its own object; do not let one object serve two verbs.
- Connect clauses with explicit causal or temporal words (because, so, when, after) — never with a bare comma.
- Replace every metaphor or compressed phrase with the literal claim it stands for.
- Give every count or statistic its denominator.
A change that alters an invariant, dimension, or map entry recorded on a card must update that card in the same change (see openspec/specs/model-catalog/spec.md once this change archives).