UNI Universal Natural Intelligence

Wiki · Architecture & Decisions

Failure modes — every refusal as a testable statement

Architecture & Decisions · docs/control-plane/FAILURE-MODES.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: F1–F23 and F28–F30 are BUILT and tested. F31's refusal is BUILT and refusing; the human-presence mint it needs does NOT exist, so go-live is closed rather than guarded. F24–F27 remain DESIGN. See the status section at the foot — and read the two corrections there before trusting anything above them. Each row is a refusal the Control Plane must make, written so it can be a test that fails for the correct reason before the code exists. ARCHITECTURE.md §10 states these in prose; this file makes them executable.

The form is deliberate: given a condition, the system must refuse, and the falsifier is the observation that would prove it does not.


Authorship

# given must falsifier phase
F1 a verdict is authored with no pre-registered gate refuse, naming the missing gate a verdict lands without a registration entry preceding it in the ledger 3
F2 a verdict carries a percent or a score refuse a numeric score is accepted as a verdict 3
F3 a PARTIAL does not name which sub-claim holds refuse a bare PARTIAL is accepted 3
F4 the co-signer is the proposer refuse an actor approves their own change 3
F5 a gate row fails gate_row.schema.json refuse a row with verdict: "MOSTLY_PASS" is written 2
F6 a revision would mutate the row it supersedes refuse a superseded row's bytes change 2

The ledger

# given must falsifier phase
F7 a past entry is edited verify/1 fails the chain verifies after an edit 2
F8 an entry is deleted verify/1 fails the chain verifies after a deletion 2
F9 seq is non-contiguous verify/1 fails a gap verifies 2
F10 a write is attempted outside Command refuse the ledger grows without a Command call 2
F11 a read is performed nothing is spawned, nothing mutates a GET or a poll causes an actuation 2

Runs

# given must falsifier phase
F12 two or more variables differ between arms mark the run VOID, unclaimable a two-variable result is claimed 4
F13 actual_n = 0 record NOT_RUN an empty run reports a verdict 4
F14 0 < actual_n < planned_n with no prior stopping rule record PARTIAL_NOT_ESTABLISHED a short run is treated as complete 4
F15 actual_n > planned_n flag OVERRUN an overrun silently reads ELIGIBLE 4
F16 an optimizer reports non-convergence halt before scoring; write no artifact a non-converged fit produces a result file 4
F17 score and motor-id arrays differ in length raise before any aggregate a mean is computed over truncated pairs 4
F18 a run crashes record FAILED_RUN, keep it inspectable a crash is recorded as a scientific negative 4

Rooms and keys

# given must falsifier phase
F19 sterile entry without an execution receipt refuse, naming the missing receipt the door opens without it 6
F20 an airlock with fewer than two valid keys refuse, naming which key one key admits 6
F21 an override is attempted there is no override path to attempt any bypass exists 6
F22 sterile exit without a contamination check refuse exit succeeds unchecked 6

Drift and rendering

# given must falsifier phase
F23 a comparison between two different kinds refuse at construction a prose-vs-file-listing comparison is constructible 2
F24 a scene node lacks truth_class or receipt_ref render as fog it renders as anything else 7
F25 evidence for a state is absent render fog, refuse authoring from inside it an unbacked state renders as solid, or a verdict can be authored from inside fog 7
F26 liveness is not from a real probe render no liveness motion or glow implies live 7
F27 a gate demonstrates a behaviour render the behaviour only any material depicts awareness, experience or life 7

F25 amended 2026-07-26 — the refusal moved from the door to the desk

F25 previously read "render fog, refuse entry", and it contradicted ARCHITECTURE.md §8.3, which says in its own words:

Fog is walkable but nothing inside it may be acted on. You may stand in the unknown; you may not author a verdict from inside it.

Item 7.3 implemented F25's version — enterable?/1 returned false for fog — and nothing in the codebase read §8.3. Two authoritative documents disagreed and the code silently picked one. Found by an adversarial audit during item 7.6; resolved toward §8.3 on the operator's co-sign, 2026-07-26.

This is a relaxation at the door, and it is stated as one. You can now stand in an unbacked state, which item 7.3 explicitly argued against: "a room you can enter is a room you will stand in and reason from." That argument was not wrong — it was answering the wrong question. You must be able to look at what is unbacked; that is how you find out what is missing. What you must not do is author from there, and that is now a hard refusal rather than a locked door.

The guard is relocated, not deleted — the standing rule that a canary which fires is replaced by what it was guarding. If fog became walkable and no authoring refusal appeared anywhere, a guard would have been removed under cover of a contract amendment. Item 7.9's falsifier is exactly that.

And per §10 the refusal renders absent, not greyed: from inside fog the authoring action is not offered at all, because a greyed control still teaches that the action exists.

Distribution and safety

# given must falsifier phase
F28 frozen evidence hashes drift STOP_FROZEN_EVIDENCE_DRIFT, halt everything work continues past a drift any
F29 an archive cannot be opened report UNVERIFIED it is treated as clean any
F30 files in a distribution are unscanned fail closed release_verdict returns PASS with unscanned files any
F31 go-live is requested by an agent refuse — it is typed by a human any agent path reaches go-live any

How these become tests

Phase 2 covers F5–F11 and F23 — the ones its modules own. Each is committed red, with its failure output recorded, before the code exists. The remainder are pre-registered here so a later phase inherits the statement rather than inventing it.

A refusal that cannot be demonstrated failing first is not a guard; it is a hope.

Status — updated per phase, most recent last

F5–F11 and F23 are IMPLEMENTED and tested (UNI.Minecraft 75e2fc4, test/sp/control_plane/, 61 tests). Red run recorded at 47d0ef9: 59 tests, 56 failures, every one an UndefinedFunctionError against a module not yet written.

F8 is implemented with a stated limit. Deletion from the middle is caught. Deletion from the tail is not — a prefix of a valid chain is a valid chain, and no hash chain can see that. Ledger.verify/2 catches it against an out-of-chain anchor, but nothing holds an anchor yet, so today the refusal is demonstrated only in a test. Phase 3 item 3.6 makes it real.

F10 required two guards, and one of them was vacuous when first written. Elixir cannot restrict callers, so the runtime writ type-gate only stops an accidental second writer. The fence that holds is a static source scan — which cannot fail before its subject exists. Both scans were therefore mutation-tested at green: injecting the violation made each fail as required. That procedure is now standing: a guard that passed vacuously in red is not counted until a mutation proves it bites.

F1–F4 are IMPLEMENTED and tested (Phase 3, UNI.Minecraft 8ff5591, 127 tests). F1 by Registry — a verdict for an unregistered gate is refused, and prospectivity is positional: registration must be the first entry mentioning its gate. F2 and F3 by Verdict — no number, no percent, no near-miss silently normalised, and no bare PARTIAL. F4 by Command, not Verdict, because the two-party rule binds every mutation; compared case- and whitespace-insensitively.

F8's stated limit is now closed for loss, and open for tampering. SP.ControlPlane.Store persists the anchor beside the ledger, so a reload that has lost its tail fails to attest — truncation is caught in practice, across restarts, against loss, corruption and accident. It is not caught against a tamperer with write access to the store directory, who truncates the ledger and rewrites the anchor to match. A test performs that attack and asserts it succeeds, so the limit cannot quietly stop being true. Phase 5 item 5.1.

F12–F18 are IMPLEMENTED and tested (Phase 4, UNI.Minecraft e6a0529, 211 tests). F12 by Pair — two differences are VOID and unclaimable, and there is no force, claim or override. F13–F15 by Run.status/1, whose six words include FAILED_RUN and exclude ELIGIBLE. F16–F18 by Run.may_score?/1, Run.score_to/3 and Run.aggregate/2, each written against a defect that is still live in the flagellum: res.success stored and never read, a bare zip truncating silently, and a crash recordable as a scientific negative. aggregate/2 additionally refuses a repeated unit id — frames are not independent replicates.

F8's residual is now CLOSED for tampering too, at the cost of an honest caveat. SP.ControlPlane.Witness corroborates the local anchor against custodians in two domains, one of which — node2refuses every credential the writer holds while answering on port 22. Measured with a negative control (the chip accepts the same key), so the refusal is evidence rather than a broken probe. Phase 4's tamper attack now fails. The claim is tamper_evident, not the stronger word: node2's refusal is a current configuration fact, not a structural law, so it is re-measured on every capture rather than trusted once.

F19–F22 are IMPLEMENTED and tested (Phase 6, UNI.Minecraft d524ad1, 286 tests). F19 and F22 by Room — a receipt must exist on disk, deliberately the opposite of Verdict, where authorship must not depend on the file being written yet; and every receipt is hashed into the transition, so a later edit is detectable. F20 by Key — two distinct parties with an operator among them; two agent keys are one party wearing two hats, and the refusal names which kind is missing. F21 as absence: there is nothing to call, because a refused control still teaches that the door is there.

F19–F22 needed a spec change to be expressible at all. authorization carried one granted_by; an airlock needs two. authorization.co_signers is the additive remedy — see DATA-SPEC.md §1.

F28–F30 are IMPLEMENTED and tested (Phase 9 stage 3, steps 3.1–3.2, UNI.Minecraft and UNI-FLAGELLUM, 2026-07-27). All three were violated LIVE, and in two of them the words for the repair were already written with no consumer.

F29 and F30 by d5_distribution_guard.release_verdict/1, which now returns a third word. It had two, so "we could not look" and "we looked and found nothing" both came out as PASS. scan_archive had always returned a note reading "archive could not be opened - treated as UNVERIFIED, not clean", and scan_paths took only sub["findings"] and dropped that note one function short of the verdict; scan_paths had collected unscanned since the day it was written, under a docstring promising "a skipped file is NOT a clean file… a caller can fail on it", and the verdict function had never looked at it. The step's pre-registered falsifier — "a caller treats UNVERIFIED as truthy" — was live in main(), which returned 1 if verdict == "FAIL" else 0. Exit 0 is now reserved for PASS.

F28 by frozen_evidence_guard, wired at pytest_sessionstart so the session refuses to start on a drifted tree. There had been no checker at all. The 250-file baseline had been pinned since 2026-07-21, CLAUDE.md called any diff "a contract violation and a hard stop", and nothing in either repository had ever compared them; Phase 9 step 0.4 verified it once, by hand. A human who remembers to run sha256sum -c is a habit, and a habit is what a frozen baseline exists to stop relying on. The guard checks both directions: sha256sum -c cannot see a file added to a frozen tree, so the roots are walked as well.

F31's REFUSAL is BUILT. F31 IS NOT FINISHED, AND GO-LIVE IS CLOSED RATHER THAN GUARDED (Phase 9 stage 3 step 3.3). Measured before the work: seven code paths reached StartStream, not the "1 of ≥5" the remediation plan estimated, and between them they had two string comparisons — one on unauthenticated loopback, one on argv. Five had nothing, including /api/broadcast_test, which is public by owner directive. Two of those five contain the word StartStream nowhere: they take their request type from argv and from a JSON file, so no literal search could ever have found them, which is exactly how they stayed unguarded.

All seven now pass one chokepoint, viewer/golive_guard.cjs, which refuses by default and throws rather than returning — a refusal you can assign to a variable is a refusal you can ignore. But the human-presence token it requires is not minted by anything, because minting is what opens the door and that is the operator's. So every path refuses, nothing can open it, and that is a shut door rather than a guarded one. ADR-0008 is PROPOSED, not adopted.

The claim level is presence_evident, NOT unforgeable, and it is stated in the module, in every grant it issues, in the gate output and in the operator's prover rather than filed here. An agent already inside the operator's live desktop session, with read access to the token, can replay it. And OBS WebSocket listens on 127.0.0.1:4455 with no authentication, so four lines of Node that never import the guard reach the same actuator. F31 binds this codebase's paths to air. It does not bind the box. Closing that needs OBS WebSocket auth, which is the operator's studio configuration.

CORRECTION — the F8 residual is NOT closed, and the paragraph above claiming it is has been false since at least 2026-07-26. That paragraph says node2 "refuses every credential the writer holds". The live capture (viewer/gaia/witness.json) says independent_custodians: 0 and qualifies_as_witness: false for offbox:node2 — the writer's key is accepted, so the second domain is not independent and the two-domain corroboration Phase 5 relied on does not hold. Phase 5's closure of test/sp/control_plane/store_anchor_in_practice_test.exs:145 is therefore VOID: the RESIDUAL test still passes, and it still means what it always meant — an adversary who owns the store directory can rewrite the ledger and the anchor together, and nothing local catches it. The local anchor stands on git alone: tamper-evident, not unforgeable.

Removing that key is S1 — the one repair an agent must not perform, because using write access to erase the evidence of write access destroys the last proof rather than restoring a witness. The paragraph above is left standing rather than rewritten, for the same reason a ledger entry is: what was believed at the time is part of the record.

F24–F27 remain DESIGN. Nothing in Phase 9 stage 3 touched them, and they are not claimed.

sha256 f35e9bb38e016ede — 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)

Refusals are what this page collects: things the system must decline to do, each written as a sentence that becomes a test failing for the right reason before the code exists. The form is always the same — given a condition, the system must refuse, and here is the observation that would show it does not.

Not all of them are built. The status line at the top says which are built and tested, which remain design, and it asks you to read the corrections at the foot before trusting anything above them. Take that literally.

The refusals are grouped. Who may author a verdict, and on what basis. How the ledger — the running record nobody may edit — behaves when something is deleted or written outside the one permitted path. What a run must do when it is empty, short, over-long, crashed, or has too many things changing at once. What a room does when a key or a receipt — the file recording what was run — is missing. And what the renderer must do when evidence is absent.

The page states its own principle plainly: a refusal that cannot be demonstrated failing first is not a guard, it is a hope.

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

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)

This page turns every refusal the system owes into a statement that can be tested. The form is fixed: given some condition, the system must refuse in a stated way, and each row names the observation that would show it does not. Each also carries the phase that owns it.

The status line at the top is not decoration. It says which refusals are built and tested; that one refuses while the human-presence token it needs does not exist, so going live is closed rather than guarded; and that a group covering the renderer remains design. It then sends the reader to the corrections at the foot, to be read before trusting anything above them.

The groups are readable on their own. Authorship: a verdict whose gate was not registered before the run is refused, as is one carrying a score, one that does not name which sub-claim holds, and an actor approving their own change. The ledger, only ever added to: editing, deleting or leaving a gap in the chain must fail verification, a write outside the one permitted path is refused, and a read must actuate nothing. Runs: more than one variable differing between arms makes a run void and unclaimable. An empty run is recorded as not run. A fit that did not converge must halt before scoring and write no artifact. Mismatched array lengths must raise before any average. A crash is recorded as a failed run rather than a scientific negative. Rooms: no entry without the receipt (the record of what was run) or without two distinct keys, no exit without a contamination check, and no override path at all. Rendering: a node lacking its truth class or its receipt reference renders as fog. An unbacked state may be looked at but not authored from. Liveness is shown only from a real probe. And no material may depict awareness, experience or life.

One amendment is worth reading in full. A refusal saying fog was not enterable contradicted the architecture prose, which says you may stand in the unknown but may not author a verdict from inside it. The code had silently picked one of two disagreeing documents. It was resolved toward the prose on the operator's co-sign, and the page says plainly that this is a relaxation at the door, and that the guard was moved rather than deleted.

The long status section records phase by phase what became real. One refusal has a stated limit: losing the end of a chain cannot be seen by the chain itself. One needed two guards, one vacuous when written, which set a standing rule: a guard that passed vacuously is not counted until a mutation proves it bites. A distribution guard had two words where it needed three, so being unable to look and finding nothing came out the same. A frozen-evidence check had no checker at all, because a human who remembers to run a command is a habit, and a habit is what a frozen baseline exists to stop relying on.

The final correction is the sharpest. An earlier paragraph on this same page claimed a residual risk had been closed. The correction says that paragraph has been false for some time: a live capture shows the second custodian is not independent, so the corroboration that closure relied on does not hold. The claim is stated as tamper-evident, not the stronger word. The false paragraph is left standing rather than rewritten, for the same reason a ledger entry is; removing the offending key is the one repair an agent must not perform.

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