`gamecult.thing.<x>.v<n>`, mesh key `thing:<family>:<id>`. No row keeps a
compatible eve id (`operator-compat-rebuild`).
| Kind | What names it | What happens to it over time | Who decides (one writer) |
| --- | --- | --- | --- |
| Thing Script document (a published surface) | schema `gamecult.thing.surface.v1`; key `thing:surface:<providerId>.<label>`; `version: u64` in the record | Republished whole when its structure changes, `version + 1`; core ignores a version at or below the one it holds. Live values never cause a republish (they arrive through bindings). Retired when the provider deletes the record. A contract revision is a new `v<n>`; stores holding the old one are deleted and rebuilt by their daemon | The publishing provider. Core and viewers only read |
| Composition | schema `gamecult.thing.composition.v1`; key `thing:composition:<publisher>.<name>.v<n>` | Immutable once published: a change is a new `v<n>` under a new key; references pin the version. The standard library (`thing.std.*`) ships compiled into core and is also published by the Thing repo's release | The publisher (a provider, or the Thing repo for `thing.std`). Core resolves and expands; nothing else writes |
| Binding | not a document: a field of a node in a Thing Script document or composition (`Bind`) | Lives and dies with the document that holds it | Declared by the document's writer; resolved only by core |
| Bound state record | the provider's own schema and key (e.g. `voidbot.swarm_control_state.v1`) | The provider's lifecycle | The provider. Core never writes typed state; a change goes through a command |
| Viewer session state (focus, scroll offsets, editing drafts, selection, IME composition, open overlays) | the core instance; node ids within a resolved document | Not persisted and never published; dies with the session. A draft that must outlive the session is state, and state belongs to a provider | Thing core |
| Command declaration | not a document: an entry of the Thing Script document (`CommandDecl`, id local to the document) | With its document | The document's writer |
| Command invocation | schema `gamecult.thing.command_invocation.v1`; key `thing:invocation:<invocationId>` (a UUID minted by core per user action, also the idempotency key) | Written once, never edited; retained by the provider's command boundary until its final result, then the provider's retention | Thing core, on behalf of the viewer; the transport sets the caller identity |
| Command result | schema `gamecult.thing.command_result.v1`; key `thing:result:<invocationId>.<seq>` (`seq` from 1; a pending result may be followed by a final one) | Written once per `seq`; the final outcome ends the invocation | The provider that handles the command, through the contract's constructors only; core validates on receipt |
| Theme | schema `gamecult.thing.theme.v1`; key `thing:theme:<themeId>` | Versioned like a document; documents reference tokens, never a theme | The host application that embeds Thing (the GameCult brand theme is one such document); `thing.std` default theme in core |
| Provider discovery (today `gamecult.eve.provider_advertisement.v1`) | Not a Thing kind (`thing2:ruling:advertisement-owner`): owned by the Verse discovery owner and renamed once there (`thing2:follow_up:discovery-owner-campaign`) | Until its owner lands, the eve advertisement is read through core's discovery port, unchanged | The discovery owner; the provider writes, Odin aggregates |
| Accessibility tree | not persisted: derived by core per frame from the resolved document and layout (AccessKit tree updates) | Rebuilt on every change | Thing core; backends bridge to the platform |
| Render-command list | not persisted and never published: in-process from core to backend | Per frame | Thing core |
| Geometry and render-command goldens | test fixtures in the Thing repo (`tests/goldens/`) | Regenerated only by a reviewed change to core; a backend never writes one | The Thing repo's core tests |
## The consumer contract
Consumers see four things (target, "The consumer contract"). Each is a set of
types in the contract crate and its language packages; nothing in core is
visible to them (`narrow-consumer-contract`).
### 1. Thing Script
**The node set is closed.** A document's node is exactly one of:
| `TextInput` | single or multi-line, value kind text or number, placeholder, initial value (`Bind`), submit command | `control.input.text`, `control.input.textarea`, `control.input.number`, `input.number` |
| `Select` | options (literal or a bound collection), value (`Bind`), command | `input.select`, `control.select`, `control.choice-group` |
| `Repeat` | a bound collection and a template subtree instantiated per item, keyed by item key; template bindings may read item members | `list ... bind <collection>` (BD5) |
| `Overlay` | anchored to a node or the viewport, modal or not, dismiss command | `modal`, `control.popup`, tooltips |
| `Plot` | a bound numeric series, closed marks (line, bar, area), axis ranges | `graph`; sparklines a dashboard consumer expects |
| `Embed` | a host slot kind (string the host declares it supports) and slot id; laid out as a leaf of a given size; draws one opaque host command | `embed.norn`, `embed.tex`, `world.scene*`, `field.*`, `canvas.editor`, game viewports |
| `Use` | a composition reference (`publisher.name.v<n>`) and typed arguments | `metric`, `inspector.kv`, `control.tabs`, `heimdall.access_gate`, `vn.stage`, every domain kind |
Every node has an id (unique within its document after expansion), `visible`
(literal or `Bind`) and an optional accessibility label. A domain need is met by
a composition (`compose-not-kind`); a need no composition can meet is an `Embed`
slot drawn by the host, never a new node.
**Compositions are documents, resolved by core.** A composition declares typed
parameters (text, number, bool, `Bind`, `CommandRef`, child slots) and a body of
nodes that reference them. Core expands `Use` by substitution only: there is no
expression language. Compositions never own commands; a composition that needs
an action takes a `CommandRef` parameter, and the command is handled by the
publisher of the document that uses it. `thing.std` provides the common ones
(`metric`, `card`, `pane`, `dashboard`, `rail`, `key-value`, `stat`), so no
consumer language re-implements them.
**Text form.** Whether Thing Script also has a text syntax beside the typed
document, and which is the authority, is `thing2:question:thing-script-form`.
The node set, compositions and rules here hold under every option.
### 2. Binding (BD1-BD9 collapse to one path)
`Bind { source: StateRef, member: MemberPath, format: Option<Format> }`, where
`StateRef` is `{ provider: Option<ProviderId>, schema: SchemaId, key: RecordKey }`
(absent provider = the document's publisher) or `Item` inside a `Repeat`
template. A bound collection is `{ provider, schema, key_prefix }` (the records of
one type) or a list member of one record. `Format` is closed: number (precision,
percent, unit), duration, timestamp, prefix and suffix text.
| Shape | Fate |
| --- | --- |
| BD1 `stateBindings` | Survives as `Bind`; `routeKind`, `routeDescription` and `sourceId` die (core routes through discovery, a document names no transport) |
| BD2 local drafts | Die as bindings: a draft is core's editing state of `TextInput`, `Slider` or `Select` |
| BD3 `writeCommand`, `captureBindings`, `draftDirective` | Fold into commands: a `CommandDecl` lists the input nodes it captures; a completed result says whether captured drafts clear |
| BD4 world-root props | Leave the contract: an `Embed` slot whose host owns the world view |
| BD5 `var`, `collection`, `derive`, `bind` | `bind` and `collection` survive as `Bind` and `Repeat`; renderer-local `var` and `derive` die (P5): derived values are published by the state's owner |
| BD6 whole-document republish | Survives for structure only (`version + 1`); per-tick republish of values dies |
| BD7 `interface_binding` | Dies (P4): routes are discovery's, the surface is the document |
| BD8 embedded documents | `Embed` |
| BD9 reload and poll | Dies: core subscribes through the CultMesh port |
| `command.v1`, `command_invocation.v1`, `command_receipt.v1`, `command_result.v1`, `operation_payload.v1` | Collapse into `command_invocation.v1` and `command_result.v1` (P2) |
| `local_draft.v1`, `interface_binding.v1` | Die (BD2, P4) |
| `asset_catalog.v1` | Survives as `gamecult.thing.asset_catalog.v1` |
| `provider_advertisement.v1` | Per `thing2:question:advertisement-owner` |
| `plugin.v1`, `plugin_advertisement.v1`, `plugin_abi.request.v1`, `plugin_abi.response.v1`, `plugin_abi_fixture.v1`, `plugin_receipt.v1`, `plugin_witness.v1`, `plugin_handoff.v1` | Die: domain plugins become compositions or `Embed` slots |
| `conformance_*`, `capability_matrix.v1`, `provider_scenario.v1`, `provider_handoff.v1`, `runtime_*`, `local_provider_catalog.v1` | Die: parity is geometry goldens; discovery is not a fixture catalog |
| `unity_*`, `electron_shell_projection.v1`, `web_layout_probe.v1`, `tui_grid.v1` | Die: renderer outputs are not contract kinds |
| `entity_soa_view.v1`, `input_bindings.v1`, `input_capability.v1` | Die (no carrier outside the kernel, B25) |
| `mimir.eve_*`, `cultmesh.eve_surface.v0` | Mimir's own ids, renamed by Mimir's port when it is revived (Mimir is archived) |
## The authority map
- **Owner of geometry, text, focus, editing, accessibility, binding resolution
and result validation:** Thing core (`one-solver`, `core-owns-text`,
`live-state-core`).
- **Owner of a surface's content and of its commands' outcomes:** the provider
that publishes the document.
- **Owner of the contract types:** the contract crate; each language package is
held to the crate's golden wire fixtures and owns nothing of its own.
- **Derived:** the resolved tree, layout, render-command list, accessibility
tree and goldens. Viewer session state is core-owned and never published.
- **Demoted:** the browser is no longer the layout oracle; renderers are no
longer owners of kinds, drafts, pointer resolution or result validation; the
text DSL's local mesh is no longer a writer of state; `surface_state`,
`interface_binding` and the receipt are no longer documents.
- **Forbidden writers:** a backend computing layout or shaping text; a provider
writing a result through anything but the package constructor; core writing
typed state; a document naming a transport; any compatible eve id; a new node