ADR014 Literals
Title: Literals
- Status: Accepted
- Decided: D2026-03
- Recorded: D2026-09-07
- Follows: ADR013
ExecutableLayer - Followed by: ADR018
TemporalDimensions, ADR022ReceiptBoundary, ADR027DatesAsNames - Affects:
Parser,Prose,Title
Context
With the executable layer removed (013), prose was
purely descriptive. The March 2026 rewrite was the moment that became
concrete: the parser was written by hand, and the shipped ontology
(universe, anthology, series, book, chapter, concept) collapsed to
universe, concept, dimension, relationship.
A handwritten parser has to decide what a value looks like. The scene language
had already answered that question for itself — minLength { 1 },
maxLength { 64 } — in the same block shape prose uses. So the syntax for
prose-with-literals was not hypothetical. It existed, it worked, and it had
just been archived.
Nothing was asking for literals at the time. This exclusion was preemptive, which is worth stating plainly rather than dressing up as a response to pressure.
Decision
Prose has no literals. Every position in the language holds an identifier or a prose block. No numbers, no quoted strings, no dates, no booleans as values.
describe and title are prose blocks, not string values. Authored text is
not a literal. The rule is about values in structural positions — the places
a machine would read a field out of.
Consequences
Why preemptively, and not later when something asked. Because the failure mode is erosion, not a decree. A literal in prose is a value that somebody will extract. Once prose is supplying values to running code, prose is participating in execution, and 013 is undone one extracted field at a time — with no decision ever having been made to undo it. The temptation is concrete and named: metadata systems of the kind built at work would happily read a value straight out of a universe, and the author of this record would be tempted to let them.
What this makes impossible. No timelines. No cardinality or counts, which
is part of why the proposed expects block is presence-only
(011). No versions, no measurements, no dates — which
is why these records carry their dates in markdown and the prose ADR nodes do
not, and why the temporal-dimensions question is still open. (That record does
not have a number yet; it currently exists only as adr TemporalDimensions in
universe/adr.prose.)
Where values legitimately live: the receipt side. This is the dividing line, and it is not a loophole — it is the arrangement. Receipts may carry literals. Prose may not. A receipt already holds a file path, a line, a column and a context hash, and it is the designated home for anything else that has to be a value: a URL, a revision, a timestamp.
That line is also why prose no longer constructs documentation. The earlier
language had a documentation { document { path { '/docs/items/overview.md' } } }
form, attaching external files to a concept — visible in
archive/universe/test/fixtures/named-document.prose. Its path and kind
are quoted string literals, so the feature could not survive this record. Once
receipts existed, documentation linkage moved to the side that is allowed to
hold a URL, and prose stopped constructing it at all.
So the test for any proposal is not whether values exist somewhere in the ecosystem. It is which side of that line holds them.
Title's history, and why it is not an exception. title was originally a
literal: title { 'this is the title' }, with quotes. The quotes went away
when describe-style blocks won, and title became a prose block with a short
body. So title did not survive as a string slot; it stopped being one by
construction. ADR 010 describes title as "the only
string-valued slot in prose," which predates this definition — its ruling
stands unchanged, and its watch item (title having been used to hold URL
patterns) is this record's erosion, observed in the wild.
What to watch. The erosion does not require the word "literal." Any author-written value landing in a machine-readable slot is the same pressure, whatever it is called. A short prose block that a consumer parses as a value is the same thing as a literal with extra steps, which is precisely what happened to title.
Alternatives considered
Scalar attributes on concepts. A general attribute name { value } form.
Rejected. It is the most honest version of the request and the most direct
route to extraction, since a named scalar is exactly what a consumer wants to
read.
A typed attribute block, quarantined from the rest of the language. Values allowed, but only inside one clearly marked box. Rejected. Quarantine is where erosion starts, not where it stops: the box is a supported feature the moment it ships, and the argument for widening it is always the next specific case.
Dates only, as a narrow exception. Deferred rather than rejected, to the
open temporal-dimensions question. Worth recording alongside it: if a timeline
is modelled as concepts — an episode inside a season, ordered by follows
— then ordering and validity may be expressible with no date literal at all,
and only derived values over time (an age that depends on when you ask) would
genuinely need one. That would put the remaining case back inside 013's
refusal rather than this one's.
Keep the quoted-string form for title. Not so much rejected as overtaken, when describe-style blocks became the way authored text is written. The simplification that removed the quotes is what made title prose.
Evidence
The scene compiler is the strongest evidence, because it shows what the
alternative looked like in practice rather than in theory:
archive/scenes/test/string-constraints.test.js and its integer counterpart
exercise minLength, maxLength, min, max, step and of as values in
block syntax. Prose with literals is not a thought experiment; it was a
working compiler, and it was archived.
The absence of a forcing case is itself evidence, and it cuts both ways. No
universe was blocked at the time, so this record cannot claim to have solved a
live problem. What it can claim is that the pressure arrived later and from the
predicted direction: title being used to hold URL patterns, ADR metadata
wanting dates and numbers, and expects wanting cardinality. Three requests,
none of them calling itself a request for literals.