The Engine Never Says “Dagger”
Stage 9 is the only stage the player ever reads, and it runs fresh on every inspection because the reader has changed since last time. Upstream stages build an honest object; this one presents it without handing over the answer key.
Neutral by construction
Every artefact carries a physicalLabel generated from observable properties alone: "short bronze elongated form with engraved disc-form attachment". The word "dagger" appears nowhere, because "dagger" is an interpretation and interpretive naming is the player's job. The occluded groundTruthTags exist solely so the engine can later judge claims against reality; no agent's interpretive model, player or NPC, ever reads them.
Registers: same facts, different foregrounding
Descriptions are filtered through registers, which shape framing without touching truth. The spec's worked example runs one wear pattern through all five:
- Neutral: "marks are visible along the edge".
- Functional: "repeated use-wear consistent with cutting or scraping".
- Aesthetic: a patina of handling that complements the surface finish.
- Ritual: marks possibly indicating deliberate decommissioning of the blade.
- Technical: deformation from contact with material harder than the blade.
They differ in the follow-up questions they invite. MVP ships three registers (observational, interpretive, technical); the five-register acquisition system with per-domain proficiency is designed and explicitly deferred.
The modelling claim behind registers: expertise changes what a description affords rather than what is there. The functional reading points at use, the technical reading at manufacture, the ritual reading at intention, and each one licenses a different next action, which is the currency the game actually trades in.
Registers also explain how the lens stays legal. The pipeline guarantees forbid touching facts, so the only lever a belief system can pull is which true framing arrives first; registers are that lever, typed.
Registers run in both directions
When the player publishes, they choose a register too, and the choice trades credibility against reach:
- Academic: formal and evidenced; weight with peers, few readers.
- Curatorial: descriptive and contextualised; moderate on both counts.
- Popular: reaches everyone, and can spawn simplified versions of the claim that circulate on their own.
- Field-notes: raw and provisional; minimal credibility, but establishes priority.
The same mechanism that frames what the player reads frames what the profession hears from them.
One authoring constraint: a relative tag must never be described as an intrinsic property. A template rendering elite as "an object of obvious wealth" misrepresents what the score measured, which was standing against the producing culture's own norms. The constraint is written into the template contract, so the prose layer can't quietly undo the relative-tag semantics the classification page set out.
The lens sits on top
The interpretive lens (the game's core mechanic, specced in its own document) selects which template variants surface and how observations are ordered: high-salience observations up front, the rest behind investigation, suggested tags nudged by the player's published claims. The presentation type keeps the honest raw data one drill-down away at all times, and the lens's hard limits repeat from the overview: reorder, reframe, de-emphasise, nothing else. A player who has published "Culture A was a warrior society" will find blades foregrounded and weaving tools easy to scroll past. The engine isn't lying to them; it's agreeing with them, which is worse.
What exists today
The observational register is real, in four pieces:
- Authored templates per primitive, in
data/descriptions/observational/, one file per geometric form. - A slot expander for
#slot#placeholders, with article handling (#point.a#renders "a sharp point" or "an oval cross-section" correctly). - Drop-on-none semantics: a sentence referencing an absent or none-valued parameter is dropped whole rather than rendered with a hole; where "none" is itself observable, like a sealed vessel's opening, a dedicated slot-free variant handles it.
- One renderer on both surfaces: the CLI samplers and the Explorer's structure viewer share it, so the dev tooling's voice and the eventual description engine's observational voice cannot drift apart.
Variant selection currently gates on parameter values only; register filtering, lens alignment and material-aware gating are the full description engine's job, a scheduled roadmap task that supersedes the minimal renderer.
// prose.ts: the slot convention the observational templates use
export const SLOT_PATTERN = /#([a-zA-Z][\w-]*?)(\.a)?#/g;
// "#taper# taper toward #point.a# point"
// → "gradual taper toward a sharp point"
// any slot absent, or valued 'none' → the whole sentence is dropped,
// never rendered with a hole; observable 'none' values get their own
// slot-free variant instead
src/lib/engine/generation/prose.ts (interim renderer) · templates: src/lib/data/descriptions/observational/ · Spec: doc 05 §12–13, doc 04 (lens) · Full engine: roadmap 2GN.38–39