Wiki · Evidence & Verdicts
Phase 3 — the green run, and the two premises that turned out wrong
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.
Eighty-seven dated pages: receipts, pre-registrations, handoffs, validation records and review verdicts. A receipt is written at the moment a piece of work was checked. It names what was claimed, the commit and the seed, what was actually run, and the outcome in one of a small set of controlled words. Then it names what the work did not achieve. That last part is what makes it a receipt rather than an announcement. A pre-registration is the same discipline run in advance: the conditions that would count as a pass and the conditions that would falsify the claim are written down before the run, so neither can be adjusted once the numbers arrive.
That is why so many small dated stubs are an audit trail rather than noise. No one of them is meant to be a good read. The value is in the sequence and in the dates, because you can watch a prediction be registered, then the run happen, then the verdict land — sometimes against the prediction. Pages here record a falsified result, a rejected fix, a retracted overclaim, and a green receipt that turned out not to be reproducible from the commit that carried it. A record that carried only successes would be worth a good deal less than this one.
A gentle way in is to read a pre-registration first, so the shape becomes familiar, then a result page, then one of the corrections. This section sits off the main navigation on purpose: it is the record you check the rest of the site against, not the place to begin.
What it is not: documentation, and not a summary. Nothing here has been tidied in hindsight. Every entry reads as of its date, a later entry may overturn an earlier one, and the presence of a page is not a claim that its result stood.
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.
Date: 2026-07-25 · Repo: UNI.Minecraft, gen2-runtime · Red: 219d8b0
Plan: docs/control-plane/phases/PHASE-3.md (UNI-FLAGELLUM)
Raw: phase3_red_2026-07-25.txt · phase3_green_2026-07-25.txt
$ mix test test/sp/control_plane
127 tests, 56 failures # at 219d8b0, before Registry / Verdict / Anchor existed
127 tests, 0 failures # here
Test count identical across red and green: nothing was added to make anything pass. Full suite 681 tests, 0 failures (was 621).
1. ADVERSE — my own DATA-SPEC invariant was wrong, and it shipped in Phase 2
DATA-SPEC.md §1 said prior may be null "only for seq = 1", and
Ledger.check_prior/2 enforced exactly that.
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 — a category error that reads as rigour.
It survived Phase 2 because no test covered it. A rule with no test is a comment that happens to run. Phase 3 found it on the first attempt to register anything, before a line of Phase 3 code was written.
Corrected: prior may be nil at any seq. Supplying the right value is the
authoring module's job; chain integrity is the ledger's, and a nil prior does
not threaten it. Pinned by "a NEW gate registered deep in the chain still has a
null prior".
2. ADVERSE — item 3.7's premise was wrong, and the pre-registered fix is not available
PHASE-3.md item 3.7 offered two ways to close the inherited
mix format --check-formatted failure on lib/sp/brain/language.ex:
(a) normalise it to LF in its own commit, or (b) record it as a standing
known-fail with its reason.
Option (a) was written on my assumption that the failure was line endings only — because the failure diff renders CRLF markers prominently. Tested directly:
CRLF pairs removed: 333 | bytes 12718 -> 12385
$ mix format --check-formatted lib/sp/brain/language.ex
** (Mix) mix format failed due to --check-formatted. # STILL FAILS
The file is genuinely unformatted. A real reformat is 93 added / 29 removed
lines, 85/21 of them non-whitespace — substantial restructuring of a file in
the language subsystem, which CLAUDE.md names among the invariant-guarded
areas.
Option (a) is therefore not available as written. Taking option (b):
STANDING KNOWN-FAIL.
mix format --check-formattedfails repo-wide onlib/sp/brain/language.ex, which is genuinely unformatted (not merely CRLF-terminated) and predates all Control Plane work. Reformatting it is a deliberate style change to another subsystem and belongs in its own commit, proposed on its own terms — not inside a Control Plane evidence commit. Every Control Plane file passes the same check.
language.ex was modified during this investigation and reverted to
byte-identical HEAD (76d0ebec…) twice. git status on it is clean.
Two pre-registered premises wrong in one phase (§1 and §2). Both were mine, both were assumptions written as facts, and both were caught by trying to act on them. That is the pre-registration working, not failing.
3. A conflict between two of my own tests, resolved before either was committed
The receipt cannot live in a verdict entry's evidence list.
Command requires a real sha256 on every evidence entry. Producing one means
reading the receipt from disk — which makes authorship depend on the file
already existing, contradicting the test that says it must not. The other exit
was weakening Command's evidence rule to admit a hashless entry: a guard traded
for a convenience.
Resolved by putting the pointer in resulting.receipt_ref. A reader of the
ledger alone still reaches the receipt; evidence stays content-addressed and
carries artifacts only when their digests are already known. Written into the
test's moduledoc so the tension is not rediscovered as a bug.
4. What was built
| module | file | what |
|---|---|---|
SP.ControlPlane.Registry |
registry.ex |
registers a gate before anything is observed |
SP.ControlPlane.Verdict |
verdict.ex |
authors five words, refuses everything else |
SP.ControlPlane.Anchor |
anchor.ex |
holds what a hash chain cannot hold about itself |
SP.ControlPlane.Command |
amended | :author_verdict; the two-party rule |
SP.ControlPlane.Ledger |
amended | the corrected prior rule (§1) |
Failure modes covered: F1–F4, on top of Phase 2's F5–F11 and F23.
Design decisions, recorded rather than left implicit:
- Prospectivity is "registration is the FIRST entry mentioning this gate."
The guard does not know what a run is, so Phase 4's
Runneeds no change to it. The refusal names theseqthat got there first, so it can be looked at. - The two-party rule lives in
Command, notVerdict— it binds every mutation. Compared case- and whitespace-insensitively, because"Claude"and"claude "are one person and an audit trail that disagrees proves nothing. PENDINGis the one verdict authorable without a receipt. It asserts nothing.WITHHELDstill needs one — a withdrawal is itself a claim about evidence.- A near-miss is a refusal, not a guess.
"pass","PASS "and"Pass"are all refused rather than normalised; a near-miss signals something upstream is confused, and silently fixing it hides that. - There is no
Anchor.attest/1. An API that let you claim soundness without an anchor would eventually be asked to.
5. ITEM 3.6 IS PARTIAL, and the holding sub-claim is named
Item 3.6's pre-registered outcome was "tail truncation is detected in practice, rather than only in a test."
What holds: the mechanism exists, round-trips through bytes, and catches truncation by one entry, truncation by many, unexpected growth, and a forged head.
What does not: in practice. SP.ControlPlane.Ledger has no
persistence, so nothing holds an anchor across a process boundary and nothing
can compare today's chain against yesterday's head. Truncation is detected
whenever an anchor is held; today, nothing holds one.
A test asserts this limit directly and fires when it stops being true —
"STATED LIMIT — nothing persists an anchor yet" scans the namespace for any
persistence primitive. Mutation-tested: adding File.write makes it fail.
6. Four tests passed in red. None vacuously, and two were mutation-tested
| test | why it passed in red | mutation-tested at green |
|---|---|---|
| "two different parties are accepted" | positive control on Phase 2's Command; must stay green |
— (a positive control, not a guard) |
| "no existing Phase 2 entry was self-authorised" | proves the two-party rule was not introduced by weakening a fixture | yes — FAILED as required when a self-authorised fixture was injected |
| "the four PARTIAL rows each say what holds" | the upstream convention the guard encodes | — (an assertion about canonical data) |
| "STATED LIMIT — nothing persists an anchor yet" | a canary on a limit that is currently true | yes — FAILED as required when File.write was injected |
Both mutations reverted; git diff empty; suite returned to 127/0.
7. Verification
| command | result |
|---|---|
mix test |
PASS — 681 tests, 4 doctests, 0 failures (was 621) |
mix test test/sp/control_plane |
PASS — 127 tests, 0 failures (was 127 / 56 red) |
mix compile --warnings-as-errors --force |
PASS |
mix format --check-formatted (Phase 3 files) |
PASS |
mix format --check-formatted (repo-wide) |
FAIL — standing known-fail, §2 |
git diff mix.exs |
empty |
evidence/gates.ndjson sha256 |
964ea25c…1d8a4c44 unchanged — this phase wrote no row |
node viewer/gaia/verify_gaia.cjs |
PASS — 12 checks, 0 FAIL |
node viewer/gaia/gaia_lint.cjs |
PASS — 0 violations |
lib/sp/brain/language.ex |
byte-identical to HEAD, 76d0ebec… |
test/sp/brain/mc_test.exs |
untouched |
8. A discrepancy in the red commit message, corrected here
219d8b0's message says "55 of 126 failing". The recorded run in
phase3_red_2026-07-25.txt is 56 of 127 — one test was added while resolving
§3 between writing the message and the final run. The receipt is the number to
trust. History is not rewritten to hide a stale figure in a commit message.
9. What this phase did NOT do
No row written to the canonical ledger. No run executed. No pairing guard. No
rooms, airlocks or keys. No Gaia seat. No lab view. No Phoenix. No ui/ change.
No P-level moved — P8 = FULL_PARITY = false, first unsatisfied rung P4.
nursery-fenced-red-stocked remains FAIL, falsified 2026-07-19.
Rollback: delete lib/sp/control_plane/{registry,verdict,anchor}.ex and the
four new test files, and revert the two amendments to command.ex and
ledger.ex. The prior correction in ledger.ex should survive any rollback —
it fixes a real defect independent of Phase 3.
sha256 4351ddaccc0f9770 — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
A green run whose headline is that two of the author's own premises, written down before the run, turned out wrong, and both were caught by trying to act on them. One rule, shipped in an earlier phase, confused a list's first entry with a subject's first entry, and no test covered it, which the page calls a comment that happens to run. The other assumed a formatting failure was only about line endings; tested directly, the file is genuinely unformatted, so the fix written down in advance is not available and the fallback is taken.
One of the rulings it writes down explicitly is about verdicts. Only one of them may be authored with no receipt — no file recording what was run — because it asserts nothing. A withheld verdict still needs one, since a withdrawal is itself a claim about evidence.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 4351ddaccc0f9770
Clear — written for this website, not the source document
A green receipt — the file recording what was run — with the counts before and after, and a note that the test count is identical, so nothing was added to make anything pass.
The first adverse finding is the author's own rule, shipped in a previous phase and enforced by code. It said one field could be empty only for the very first entry in the list. That confused the list's first entry with the first about a particular subject, a category error the page says reads as rigour. It survived because no test covered it, and the line that follows is worth keeping: a rule with no test is a comment that happens to run. The correction is stated with whose job each part is, and pinned by a test named after the case that broke it.
The second is a pre-registered fix — written down in advance — that turns out not to be available. Two options had been offered for an inherited failure, and the first assumed the problem was line endings alone, because the diff displays them prominently. Tested directly, the file still fails after that change, and a real reformat would be a substantial restructuring of a file in a guarded subsystem. So the second option is taken and recorded as a standing known failure with its reason. It was modified during the investigation and reverted to byte-identical twice, and that is recorded.
The page then draws the lesson: two pre-registered premises wrong in one phase, both assumptions written as facts, both caught by trying to act on them, which is the pre-registration working rather than failing.
A third section resolves a conflict between two of the author's own tests before either was committed. Requiring a digest on every piece of evidence would make authorship depend on a file already existing, which contradicts another test; the alternative was weakening the rule to admit an entry with no digest, a guard traded for a convenience. The resolution puts the pointer in a different field, so a reader of the list alone still reaches the receipt while the evidence list stays content-addressed. The reasoning is written into the test, so the tension is not rediscovered later as a bug.
A build table follows, then design decisions recorded rather than left implicit. How prospectivity is defined, so a later phase needs no change to the guard. Why the two-party rule lives with the writer rather than with the author, and why comparison ignores case and spacing. Which single verdict may be authored with no file recording what was run, and why a withdrawal may not. Why a near miss is refused rather than quietly normalised, and why one convenient function deliberately does not exist.
One item is explicitly partial, with the sub-claim holding it back named. The mechanism works and catches several kinds of tampering, but nothing persists across a process boundary, so in practice nothing holds what would be needed. A test asserts that limit directly and is written to fail the moment it stops being true, and it was mutation-tested.
A table then explains why four tests that passed in the red state did so for good reasons rather than vacuously, and which two were mutation-tested. A verification table follows, then a correction of a stale number in a commit message, with the receipt named as the number to trust and no history rewritten. The page closes with what the phase did not do and how to roll it back, noting one correction that should survive a rollback because it fixes a real defect independently.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 4351ddaccc0f9770