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/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. 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.