Skip to content

Four states of absence, and the one that hides as a finding

Published .

An unmeasured field is not a blank. A passport must name which of three reasons left an operation unmeasured: the check did not run, it ran but nothing qualified, or the source refused to answer. A fourth exists: an instrument that cannot see the quantity, producing an indistinguishable reading. Unless the instrument's reach is disclosed alongside the finding, absence remains indistinguishable from the three.

Three states, not a blank

The passport distinguishes three states of absence: nothing_qualified when the check ran and found no match, check_did_not_run when the check never ran, and unreadable when the source declined to answer.

Each measurement carries exactly one of: a value, or the reason it is absent. A Measurement dataclass enforces this by rejecting any instance that is both empty and doubled. One return value meaning two states of the world caused seven defects in the operator's systems, including a twelve-week outage where "no news" and "the source is dead" returned identically, hiding the failure from monitoring.

As the method specifies, every operation must show either a level or not_measured with its reason. Two of three operations on every current subject read not_measured. The table looks sparse, and that sparseness is the truth staying visible. An interface rendering absence as zero would reintroduce the defect: "the source is dead" mistaken for "nothing matched".

An instrument that cannot see a quantity still answers HTTP 200 with an empty list, indistinguishable from a true zero at the point of reading. A conclusion drawn from such an instrument is not evidence, and it becomes more dangerous when it happens to be correct.

The accountability block's separate discipline

The accountability block requires each field to be {value, measured, reason} with defaults measured: false, reason: check_did_not_run. All passports were re-emitted under schema 2.0.0 from 2026-08-20 onward.

Under 1.0.0, the block was T | None and emitters built from defaults without inspecting anything. Artefacts claimed "we checked and found none" while meaning "nobody looked". The specification enabled this defect: the method demanded a reason for every unmeasured operation in item 3, then granted an honest none to the accountability block in item 5 without requiring the same apparatus. Three emitters took that licence, and every passport under 1.0.0 falsely claimed a completed check.

Fable's ruling on 2026-08-20 named the schema as primary defect and the specification as complicit. The front door — which rendered nulls inconsistently in adjacent rows — was acquitted because that inconsistency is what revealed the defect. The specification's erratum in item 5 acknowledges it granted the conclusion without apparatus.

The wrapper is per-field rather than a coverage list because the distinction must survive quotation. This mirrors the logic that keeps verified and self_reported on separate branches: the structure must persist when extracted or cited, not collapse under selection. A JSON export carrying an addressee field must show whether that addressee was measured or defaulted.

LAW-NOT-MEASURED lived in the Measurement class, not enforced at the boundary. Exemption from the score silently became exemption from measurement discipline — fields bypassing that class never had to declare absence. Schema 2.0.0 gates at the boundary itself: tests/test_no_bare_nulls.py rejects any document containing a null without the reason wrapper. Now the invariant has machinery behind it.

When the instrument cannot see the quantity

The three named states - nothing_qualified, check_did_not_run, unreadable - occupy distinct places in the grammar of absence. A fourth sits at the boundary: an endpoint that cannot see a quantity returns HTTP 200 with an empty list, indistinguishable from zero at the point of capture. Two GitHub endpoints show the risk. The /commits/{sha}/status endpoint reported zero integrations for every commit; the reading was correct. The /commits/{sha}/check-runs endpoint returned four runs on the same commits. The legacy API cannot carry what the modern one does.

A conclusion drawn from an instrument that cannot see the quantity is not evidence. It is more dangerous when correct, because it will be repeated elsewhere. The wrong-source state is the fourth member in the operation-level absence grammar of the method: beside nothing_qualified and unreadable sits the case where an endpoint was asked, answered 200 with no data, and vanished into zero.

Fable found this while refuting a brief that used an empty measurement as proof. The reading was correct - no deploy integrations existed - but the proof was invalid, because it came from an instrument blind to deploy integrations. This form of failure is most dangerous when correct: the conclusion will be trusted and the pattern will be repeated without record of its source.

No general code gate exists for this failure, because a checker cannot know an endpoint is blind. One instance is armed as a model: every passport in the registry carries the access_channel field, declaring which instrument supplied the evidence. This allows verdicts to carry both reading and instrument, governed by LAW-GRANTED-CHANNEL-ONLY. The test tests/test_granted_channel_only.py rejects any passport missing or mismatching the channel.

Where this showed up in the keyword base

The bing_serp_related source is the only candidate for "people also ask" items. It answered HTTP 200, carried organic results including python.org, but yielded zero related-question items - recorded as unreadable in the method, contributing no keys and no zeros. An instrument that cannot be shown to see a quantity cannot yield a reading about the measured property.

Three control queries were run before trusting this zero: "weather" and "how to boil an egg" were chosen as implausible to have no related searches. All three returned zero despite 117 kB and 124 kB response bodies. L-10 requires measuring a source's ability to see non-zero before trusting its zero as a reading.

Erratum, 2026-08-24 — T-B10, D-34: all three controls returned zero, so the ability to see quantity was argued from plausibility rather than measured. Zero controls establish nothing in either direction. The honest state is capability_unproven - a statement about nobody, not the client. The source contributes no keys and no zeros. This defect appears in the repository's own explanation at source material lines 100-135.

Demand data retrieval faced different constraints. GetKeyword returned 812 readings then {"ErrorCode":4,"Message":"ThrottleUser"} - a quota on the account, not a fact about keywords. Those 427 rows sit in unreadable state. A second pass at one call per second met the same refusal on 43 more rows. The state records what is known: the instrument would not answer.

nothing_qualified names a different absence: 733 rows where the instrument answered and Bing carries no demand data for those terms. The check ran and nothing matched. Unlike unreadable, the instrument can see the quantity; it simply found none.

measured 257nothing_qualified 733unreadable 427check_did_not_run 1
The demand states of all 1418 keys captured on 2026-08-20. The two hatched rows are not small numbers - they are rows where the instrument did not answer. Read from <code>seo/sources.json</code>.

What a passport's per-operation table renders

A passport's per-operation table embodies decision D-03: every unmeasured operation shows the word not_measured and its reason, never blank or zero. Each row names an operation, assigns a level from L0 to L5, carries confidence (measured or inferred), and lists the limiters applied. When an operation remains unmeasured, the reason is one of three forms: nothing_qualified when the check ran but matched nothing, check_did_not_run when the check never executed, or unreadable when the source refused to answer.

L-10 names a fourth absence: the wrong source was asked. An endpoint answers HTTP 200 with an empty list, indistinguishable from true zero at the point of reading. A conclusion drawn from an instrument that cannot see the quantity is not evidence. Before recording absence, the instrument must be shown able to see presence. This extends the project's foundational rule from L-1: "no news" and "the source is dead" must never read the same.

The table stays sparse by design. Two of three operations on current subjects read not_measured, and that sparsity is the truth the artifact must keep visible. This rendering prevents the collapse that caused seven production defects across the operator's systems.

Beside the per-operation table sits the control map, detailing what was inspected, what lay out of reach and why, and what an undiscovered path would look like. Coverage statements anchor measurement in reality rather than assumption.

The projection 0-100 appears adjacent to a disclaimer clarifying that the score measures autonomy and explicitly not reliability, decision quality, profitability, or the presence of an accountable party. This disclaimer is never in a footnote, and the placement matters: the score and its constraint must be read together.

Gate logic processes these states according to the specification, implementing ABI-33-4: when Measurement.gate_verdict() returns PASS, FAIL, or NOT_MEASURED, an absent measurement is never treated as failure. "The subject failed" and "we could not measure the subject" are distinct statements requiring different responses. Missing measurement is not a violation.

The registry publishes the access_channel through which each measurement arrived, pairing the instrument with the reading. This prevents the instrument's blindness from dissolving into an empty result.

development initiationdeploymenttreasury controlAI-Property-Sales-PlatformAIpushAPIbaseL2audiobook-shorts-seriescryptocardhub-defycardcryptocardhub-publicgov-auction-reportmcp-protocol-testerL2provekL3provek-method measured check_did_not_run unreadable
Every operation on every subject in the registry, as at 2026-10-15. No total is drawn: a single coverage number would turn a named shortfall into a score. Read from <code>public/registry/registry.json</code> and the eight passports beside it.

Where each statement comes from

Nothing on this page is asserted on its own authority. These are the places in the repository where each claim above is written down, and a note whose address does not resolve fails the build rather than being published with a gap.

  • SPEC §3.1 — SPEC.md
  • D-03 — DECISIONS.md
  • D-13 — DECISIONS.md
  • L-1 — tasks/lessons.md
  • L-10 — tasks/lessons.md
  • L-11 — tasks/lessons.md
  • the registry — public/registry/registry.json
  • the keyword base — seo/KEYWORD_BASE.md

Drafted by claude-sonnet-5 (structure) and claude-haiku-4-5 (prose) on 2026-08-24; every claim on this page resolves to an artefact in the repository, and the structural rules are held by deterministic tests rather than by review.