UNI Universal Natural Intelligence

Wiki · Architecture & Decisions

Data specification

Architecture & Decisions · docs/control-plane/DATA-SPEC.md @ b909801f3db4 (hierarchical-aif/motor-stack) — opens the published snapshot 8b4b5935bcba

How to read this page

Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.

This is the design record of the part of the estate whose job is to stop the rest of it claiming more than it has measured. It runs to architecture notes, numbered decision records, phase plans, and the results written after each phase ran.

It is for anyone curious how a decision was actually reached — what was considered, what was refused, and what the refusal cost. The decision records are the most durable part: each names one choice, the alternatives, and the consequence accepted in exchange. The failure-modes page is worth the detour, because it states each refusal as something you could go and test rather than as a promise.

Read the architecture page first. It opens by declaring itself part design and part built, which sets the tone for the whole section. Then the first decision record, then whichever phase interests you — read as a pair, the plan and the results page written afterwards, including the phases where a premise turned out to be wrong and the receipt says so.

What it is not: a description of running software, and not a complete record. Three documents from this area were withheld from publication, because they describe private infrastructure or the operator declined them; they are listed as withheld rather than quietly dropped, so you can see that they exist.

Your browser cannot switch reading levels, so the document itself is shown.

Precise — the source document

This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.

Status, 2026-07-26: §1, §3 and §5 are BUILT, §1 has been corrected once, and §1 now PERSISTS (UNI.Minecraft through e6a0529lib/sp/control_plane/, 211 tests). §2 (receipt) and §4 (scene node) remain DESIGN, owned by phases 5 and 7. Cross-referenced to the one schema that already exists and is enforced: production/schemas/gate_row.schema.json in UNI.Minecraft, guarded by test/gate_registry_integrity_test.exs.

Three things this spec did not anticipate, one of which is that the spec itself was wrong, recorded here so the next reader inherits them rather than rediscovering them:

  • The ledger's invariants do not cover tail truncation. §1 lists "deleting any entry fails verify/1". That is true for the middle and false for the end: a prefix of a valid chain is a valid chain. SP.ControlPlane.Store now persists the anchor beside the ledger, so a reload that has lost its tail fails to attest — caught in practice against loss, corruption and accident. Not against a tamperer who owns the store directory and rewrites both; a test performs that attack and asserts it succeeds. Phase 5 item 5.1.
  • The gate row's own canonical ledger violated §3 in twelve placespre_registration_path: null, forbidden by "type": "string". Remedied 2026-07-25 by eleven superseding rows; the twelve originals remain, because the file is append-only. See phases/PHASE-2-RESULTS.md §4.1.
  • §1's own prior rule was wrong, and shipped enforced. See the correction note under §1.

Everything here must be expressible in stdlib JSON — the root app takes no hex dependency (ADR-0006).


1. Ledger entry — SP.ControlPlane.Ledger

Append-only. Hash-chained. An entry is never edited; a correction is a new entry.

field type req meaning
seq integer ≥ 1 position in the chain, contiguous, never reused
utc ISO-8601 string human-readable instant
unix_ns integer monotonic-ish precision; both are required, neither substitutes
actor string who acted — a person, an agent, a service
role string the authority under which they acted
transition string what changed, in the controlled vocabulary
prior object | null state before; null for any creation event, at any seq
resulting object state after
authorization object {kind, granted_by, ref} — how this was permitted. Optional co_signers: an array of {holder, kind, ref}, added 2026-07-26 for airlocks, which need two parties.
evidence array of {path, sha256} may be empty, may not be absent
prev_hash 64-hex | null null only for seq = 1
hash 64-hex sha256 over the canonical serialization of every field above

Invariants (each is a Phase 2 red test): hash recomputes from content · prev_hash equals the previous entry's hash · editing any past entry fails verify/1 · deleting any entry from the middle fails verify/1 · seq is contiguous from 1.

EXTENDED 2026-07-26, Phase 6. authorization gained an optional co_signers array. Phase 6 item 6.0 found that this row gave authorization a single granted_by while an airlock (F20) needs two keys — the entry had nowhere to put the second. The extension is additive: the seven entries already in the Control Plane ledger carry no co_signers, need none, and still verify, which a test asserts. When present, each co-signer must be a distinct party and none may be the actor — the same rule as the two-party check. This is the second correction to §1.

CORRECTED 2026-07-25, Phase 3. This row originally read "null only for seq = 1", and Ledger enforced it. Both were wrong. Registering a new gate as the fifth ledger entry genuinely has no prior state — the rule confused the ledger's first entry with this subject's first entry. It survived Phase 2 because nothing tested it; a rule with no test is a comment that happens to run. Supplying the right prior is the authoring module's job; chain integrity is the ledger's. See phases/PHASE-3-RESULTS.md §2.

2. Receipt — what makes a claim reproducible

field type req meaning
receipt_id string stable id, referenced from the gate row
decision_id string the decision this receipt establishes
commit 40-hex the commit the claim was established at
artifacts array of {path, sha256, bytes} content-addressed; must exist on disk
logs array of paths may be empty
reproduce_cmd string the exact command that regenerates the result
env object code identity, runtime versions, platform, seeds

Invariant: receipt_path in a gate row must resolve to a file on disk. This is already enforced by test/gate_registry_integrity_test.exs — extend it, do not duplicate it.

3. Gate row — already specified, already enforced

Do not redefine it. production/schemas/gate_row.schema.json, JSON Schema 2020-12, additionalProperties: false.

Required: schema_version (const 1) · name (kebab-case) · verdict (PASS|PARTIAL|FAIL|WITHHELD|PENDING) · receipt_path (must exist) · evidence_class (A|B|C|Sec|pending) · last_updated (date). Optional: phase · pass_condition · falsifies_condition · pre_registration_path · supersedes · notes.

SP.ControlPlane.GateRow validates against this in hand-written Elixir with stdlib JSON — there is no schema library and there will not be one.

4. Scene node — the lab view's contract

Every node the renderer receives:

field type req meaning
id string stable locator
truth_class enum OBSERVED · STRUCTURAL_RECONSTRUCTION · REDUCED_MODEL · DERIVED · SIMULATED · UNKNOWN
receipt_ref string | null null is permitted and renders as fog
evidence_class A|B|C|Sec|pending carried from the source, never invented
captured_at ISO-8601 when this was true
live {up: true|false|null} present only for a real probe result

The binding rule: a node missing truth_class or receipt_ref renders as fog. That is not an error path — it is the honest depiction of an unbacked assertion. The renderer selects its material from truth_class; there is no style flag.

5. Drift comparison — SP.ControlPlane.Drift

field type req
a {locator, raw, kind}
b {locator, raw, kind}
relation declared_vs_observed | absent | snapshot_vs_live | self
equal boolean

The Phase 1 lesson, encoded: construction refuses when a.kind != b.kind. A prose line may not be compared to a command's output. Four of Gaia's five slice-1 drifts do exactly that and can never converge; this type cannot be built that way.

sha256 e623b8e8d8a48085 — of the original file, so what was ingested stays checkable.

Plain — written for this website, not the source document

Written for this website — not the document. This is a plain-language retelling, written to help you meet the document. It is not the source, and it is not evidence. It has not yet been checked by a person. (or choose Precise in the reading-level control above)

This page specifies the shapes of the records the system keeps. An entry in the ledger, which is a list only ever added to. A receipt, which is the file showing what was run and what came out. A gate row, a node the lab renderer receives, and a drift comparison. Its status line matters — some of these are built, and two of them remain design, owned by later phases.

The most useful part is not the field tables. It is the short list near the top of three things the specification did not anticipate, written down so that the next reader inherits them rather than rediscovering them. One is a limit: the ledger's stated rules do not cover losing the end of the chain, because a prefix of a valid chain is still a valid chain. A stored anchor now catches that in practice against loss, corruption and accident — but not against a tamperer who owns the store directory and rewrites both, and a test performs that attack and asserts it succeeds. Another is that the gate ledger violated this very specification in twelve places. The third is that one of the specification's own rules was wrong, and shipped enforced.

Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is e623b8e8d8a48085

Clear — written for this website, not the source document

Written for this website — not the document. This is a clearer retelling, written to help you meet the document. It is not the source, and it is not evidence. It has not yet been checked by a person. (or choose Precise in the reading-level control above)

A data specification, fixing the shape of every record the system writes down. Read the status line first: it is doing real work. Some sections are built and one has already been corrected once and now persists; the receipt — a file recording what was run — and the lab renderer's node remain design, owned by later phases. Everything here has to be expressible with the standard library alone, because the core takes no external dependency.

Before any field table, the page lists three things the specification did not anticipate, so the next reader inherits them rather than rediscovering them — one being that the specification itself was wrong.

The first is a limit on how far the ledger's rules reach — the ledger being a chain only ever added to. The specification says deleting any entry fails verification. That holds mid-chain and fails at the end, because a prefix of a valid chain is a valid chain. The store now keeps the anchor beside the ledger, so a reload that has lost its tail fails to attest. It catches loss, corruption and accident in practice — but not a tamperer who owns the store directory and rewrites both. A test performs that attack and asserts it succeeds.

The second is that the ledger of gate rows — the copy that counts — violated this specification in twelve places. It was remedied by superseding rows rather than by edits, and the originals remain.

The third is that one of the specification's own rules was wrong and shipped enforced. It said one field could be empty only for the very first ledger entry, but registering a new gate later genuinely has no prior state, so the rule confused the ledger's first entry with the subject's first entry. It survived an earlier phase because nothing tested it, and the page draws the moral — a rule with no test is a comment that happens to run.

The sections themselves are field tables: types, whether each field is required, and what it means. The ledger entry is chained to the one before it, so an entry is never edited and a correction is a new entry; its rules are listed, each as a test written to fail first. A later extension is recorded rather than folded in silently: an authorisation gained an optional list of co-signers, because an airlock needs two keys and the original had nowhere for the second.

The receipt section defines what makes a claim reproducible — a commit, artifacts that must exist on disk, logs, the exact command that regenerates the result, and the environment. Its rule is that a receipt path named in a gate row must resolve to a real file, already enforced by an existing test that should be extended, not duplicated.

The gate row section refuses to redefine anything. The schema already exists and is enforced, so the page lists what is required and what is optional. Validation is written by hand, because there is no schema library and there will not be one.

The lab renderer's node section carries a rule worth knowing even if you read nothing else: a node missing its truth class or its receipt reference renders as fog. That is not an error path but the honest depiction of an unbacked assertion, and the renderer picks its material from the truth class, not from any style flag.

The final section defines a drift comparison and builds an earlier lesson into the type: construction refuses when the two sides are not the same kind of thing.

Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is e623b8e8d8a48085