From 4a99664935cb752f750b6df7f9fceb19b08d8b51 Mon Sep 17 00:00:00 2001 From: Joe Beda Date: Tue, 21 Jul 2026 18:55:18 -0700 Subject: [PATCH 1/2] Record value types as out of scope (ADR-0007, supersedes #11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Structured value types (a top-level `types:` section with named, typed fields) cross the IDL line the format resists: named typed fields define record structure — implementation detail modelith abstracts away. A value-shaped concept is modeled as an owned entity or as attributes on its owner, with rules stated as prose. - ADR-0007 records the decision (supersedes ADR-0005, which had decided to build value types; nothing was implemented). - ADR-0005 marked superseded via Status frontmatter; body kept as the historical record. - Schema reference reframes value objects from "being explored (#11)" to a settled omission. Closes #11. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Beda --- docs/06-schema-reference.md | 3 +- project-docs/adr/0005-value-types.md | 4 ++ .../adr/0007-value-types-out-of-scope.md | 51 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 project-docs/adr/0007-value-types-out-of-scope.md diff --git a/docs/06-schema-reference.md b/docs/06-schema-reference.md index 7817a11..dad29fe 100644 --- a/docs/06-schema-reference.md +++ b/docs/06-schema-reference.md @@ -248,7 +248,8 @@ is *not* here is as useful as knowing what is. - **Value objects.** There is no value-object type. Model a value-shaped concept as an owned entity or as attributes on its owner. The parking-garage example models `Ticket` this way and names the tension. First-class structured value - types are being explored + types were considered and set aside: named, typed fields define record + structure — an implementation detail this format abstracts away ([issue #11](https://github.com/stacklok/modelith/issues/11)). - **Domain events.** There is no event construct. A state change is expressed as an `action` plus the invariants it `preserves`, and enums **name** states diff --git a/project-docs/adr/0005-value-types.md b/project-docs/adr/0005-value-types.md index ea774f7..32187c0 100644 --- a/project-docs/adr/0005-value-types.md +++ b/project-docs/adr/0005-value-types.md @@ -1,3 +1,7 @@ +--- +Status: superseded by ADR-0007 +--- + # Value types for structured non-entity values Add a top-level `types:` section for named value types: structured values with diff --git a/project-docs/adr/0007-value-types-out-of-scope.md b/project-docs/adr/0007-value-types-out-of-scope.md new file mode 100644 index 0000000..27165c9 --- /dev/null +++ b/project-docs/adr/0007-value-types-out-of-scope.md @@ -0,0 +1,51 @@ +# Structured value types are out of scope + +Do not add a `types:` section or any structured value-type construct. A value +type with named, typed fields defines record structure — implementation +semantics modelith deliberately does not capture. Supersedes ADR-0005. + +## Context + +ADR-0005 decided to add a top-level `types:` section: named value types with +`fields` (name + type) and prose `constraints`, resolvable from an attribute +`type`, with `repeated: true` for collections. Nothing was built. On revisiting +the shape before implementation, the construct read as too close to an +interface definition language: a list of named, typed fields is a record +declaration — "define the columns" — which is exactly the implementation +detail the format is meant to abstract away. + +## Decision + +Structured value types are out of scope. modelith captures the *general shape of +a system* — the concepts, their relationships, the rules that must hold — not +the internal field layout of a value. A value-shaped concept is modeled the way +the schema reference already prescribes: as an owned entity, or as attributes on +its owner, with any internal rules stated as prose (a glossary entry or an +invariant). + +## Why + +- **It crosses the IDL line.** The format's identity is a communication artifact, + not a schema language. `{amount: decimal, currency: Currency}` is a data + structure definition; that belongs in code or an IDL, not here (the same line + ADR-0006 held for action reports). +- **The general shape is already expressible.** Owned entities and attributes + cover value-shaped concepts well enough to communicate intent. Where identity + is genuinely undeserved, the tension is named in prose (the parking-garage + `Ticket`), which is honest about the trade-off rather than papering over it. +- **"For now," not "never."** If a real model demonstrates that prose plus an + owned entity genuinely cannot carry a needed distinction, revisit — but the + default stance is omission, and the bar to reopen is a concrete modeling + failure, not expressiveness for its own sake. + +## Consequences + +- The schema reference keeps value objects in "what this format deliberately + leaves out," reframed from "being explored" to a settled omission. +- Issue #11 is closed as out of scope rather than implemented. +- Issue #4 sub-item 4 (the `Ticket` value-object teaching moment) no longer + waits on value types; the current owned-entity-with-named-tension treatment + is the answer. +- Nothing to pin with a test: the decision is the absence of a construct, and + the schema already has no `types:` section. The human-facing guard is the + "deliberately leaves out" section of the schema reference. From 6320d74083e4421bec413e12933dd1f777886e51 Mon Sep 17 00:00:00 2001 From: Joe Beda Date: Tue, 21 Jul 2026 18:58:07 -0700 Subject: [PATCH 2/2] Review fix: repoint ADR-0006 IDL-line citation to ADR-0007 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR-0006 cited ADR-0005 as precedent for "rules and shapes stay prose," but ADR-0005 declared value-type shape via typed fields — the exact move ADR-0007 now rejects as crossing the IDL line. Point the citation at ADR-0007, the live holder of that line, now that 0005 is superseded. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Beda --- project-docs/adr/0006-action-reports-not-invariants.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project-docs/adr/0006-action-reports-not-invariants.md b/project-docs/adr/0006-action-reports-not-invariants.md index 49fdc64..eb6b3a0 100644 --- a/project-docs/adr/0006-action-reports-not-invariants.md +++ b/project-docs/adr/0006-action-reports-not-invariants.md @@ -33,7 +33,7 @@ delete." Its correct home is the action's own description, which is what - **Typed `inputs` + `reports`** (the issue's original) — rejected. Typed entries turn an action from a *description* into a *signature*, the clearest step toward an interface definition language. modelith is a communication - artifact, not an IDL; rules and shapes stay prose (see ADR-0005). + artifact, not an IDL; rules and shapes stay prose (see ADR-0007). - **Defer, keep prose in invariants** — rejected. The conditional-consequence argument above says the invariant is the wrong home even today; `reports:` is the small, honest fix.