Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/06-schema-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions project-docs/adr/0005-value-types.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion project-docs/adr/0006-action-reports-not-invariants.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
51 changes: 51 additions & 0 deletions project-docs/adr/0007-value-types-out-of-scope.md
Original file line number Diff line number Diff line change
@@ -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.
Loading