ADR004 NestedDimensions
Title: Nested dimensions
- Status: Deferred
- Decided: D2026-08-22
- Affects:
Dimension,Parser
Context
A sketch in examples/nested-dimensions/universe.prose wants a child dimension
that is only a kind word inside instances of its parent:
universe NestedDimensions {
dimension application {
dimension component { }
}
application PatientSearch {
component Filters { }
component DataGrid { }
component PatientDrawer { }
}
}
Today that file fails at parse with SP005. A dimension body may only contain
describe, title, relationship, and relationships. The inner
dimension component { } parses; the outer dimension's allowlist then rejects
it. The validator has never seen this AST.
Prose already has two independent trees. Concept nesting is where things sit
(dotted ids; ADR 002). A kind word is what they are, resolved by walking
enclosing concept folders (SP010 / SP021). Docs say where a concept sits does
not change which dimension it belongs to: food Bread inside a place is still
universe food.
Sibling dimensions plus nested instances already compile:
dimension application { }
dimension component { }
application PatientSearch {
component Filters { }
}
Here component is a universe-level kind, available everywhere below that
folder. Declaring dimension component { } inside each application instance
is not the same as the sketch: each instance would mint its own dimension id
and its own relationship set.
The question is whether to let a dimension declare child dimensions, so a kind word can be in scope because of the enclosing instance's dimension, not only because of the enclosing folder.
Decision
Do not ship nested dimensions yet. Keep SP005. Keep the sketch as a sketch.
If the feature returns, the contract that was actually considered is:
- Additive visibility.
componentbecomes usable insideapplicationinstances. Other in-scope kinds (place,concept, sibling dimensions) still work there. The dimension body is not a schema of allowed children. - Shared child, instance-like scope. Nesting
dimension componentunderdimension applicationshould feel like declaringdimension componenton every application instance, except it is one dimension (NestedDimensions.application.component), not a copy per instance. - Parser stays dumb. Allow nested
dimensionin a dimension body; keep rejecting instances andconceptthere. Do not enforce what may nest inside an instance at parse time. Kind lookup and SP021 belong in the validator. - SP021 on conflicting words, not on sharing. The same nested dimension
appearing twice in a chain (application inside application) is not a
redeclaration. Two different dimensions that both want the kind word
componentin one chain is SP021. An explicitdimension component { }on an instance that already inheritscomponentis SP021. - Document it as lexical scoping for kind words, never as "applications contain components," unless instance bodies are later checked against nested child kinds.
This record is "not now," not "never." Revisit when one of the conditions in Consequences holds.
Consequences
What stays easy. Folders remain where things sit. Dimensions remain a
flat-per-scope vocabulary. Kind words still resolve on one axis. The sibling
workaround still says the truth it compiles: component is as available as
application.
What the sketch would have cost. A second lookup axis. A bare word like
component would also depend on the enclosing instance's dimension. SP021 and
ADR 002 exist to keep that class of surprise out of name resolution; nested
dimensions would introduce it for kinds. Two declaration sites for the same
keyword would mean different visibility (universe sibling vs nested under a
dimension). Top-level component Filters { } would become SP010 with a new
hint class: "I declared it, why not here?"
The syntax would teach a lie if it stayed additive.
dimension application { dimension component { } } reads as "applications
contain components." Additive visibility only means the word component is in
scope inside application instances. place Bakery { } inside PatientSearch
would remain legal. Implied structure that is not true is worse than no
structure.
What it would actually buy, that you cannot do today.
- Hide
componentfrom anywhere that is not under an application. - One shared child dimension, with one relationship set, for every instance of the parent.
That is a narrow win against a permanent cost.
When this decision should change. Nested dimensions improve the language when at least one of these is true:
- Schema. Instance bodies are checked against nested child kinds, so the syntax matches the meaning. Additive visibility alone is then a stepping stone, not the feature.
- Demonstrated pollution. Real universes have so many kind words that people instantiate the wrong one in the wrong folder, and sibling dimensions cannot absorb that.
- Associated types.
application.componentandplace.componentneed to be different kinds that share a word. Then the SP021 footgun is accepted on purpose.
Until then, do not widen the dimension-body allowlist in isolation. A parser-only change would turn today's SP005 into SP007 or SP010, which is worse DX.
Alternatives considered
Ship additive nested dimensions now. Rejected. The implementation is
tractable (allowlist, Dimension.dimensions, parent-first placement, kind
lookup that consults the enclosing instance's nested dims). The language change
is not earning that complexity yet.
Restrictive schema now. An application instance could only contain nested
child kinds of application (plus describe / title / relationships /
concept). That would make the syntax honest. Rejected for this round: it is a
new kind of rule, and Prose has never validated what may nest inside an
instance. Worth considering if the feature returns as (1) above.
Direct-child-only lookup. component Filters would be valid only as a
direct child of an application instance, not inside application { concept Group { component Filters { } } }. Rejected even as a future default: it would
not match how dimensions already behave when declared on an instance.
Leave the sketch compiling via sibling dimensions. That is what authors should write today. It does not encode "component is a kind of application." That missing encoding is the whole proposal, and also why the proposal waits.
Evidence
The nested-dimensions example is SP005 at universe.prose:3. The inner
dimension is fully parsed before the allowlist fires, so the parser change is
one list entry; every assumption that dimensions are leaves lives in the
validator (Dimension has no child dimensions; resolveConceptDimension walks
concept scopes only; navigateToScope does not walk into dimensions when
placing dims).
No real universe has yet shown kind-word pollution that sibling dimensions cannot absorb. The failing-universe work that produced ADR 003 needed cross-dimension relationship pairs, not nested kinds.