Selection grade & origin-set completeness: closing the two denominator-shrink holes above §8
June 28, 2026 · View on GitHub
independence.md counts witnesses that fail independently by
evidence-disjointness — it grades whether a witness is independent. Two holes
sit one level up from that, and both are denominator-shrink attacks: the obligor
under-counts the set a claim is made over and certifies its own blind spot.
- §9 — selection. Disjointness grades whether a witness IS independent; it says nothing about whether the obligor got to choose it. An obligor that hand-picks its witness from a pool can shop for a favorable one even when every candidate is fully disjoint. Independence of the witness does not bound steering of the selection.
- §10 — enumeration.
evidence_refscarry which origins a signer anchored, but the obligor selects which origins to anchor at all. Anchor only the convenient disjoint origins, silently drop the ones that reveal a shared upstream, and the row satisfiesinput_disjointwhile violating it.
Both are now implemented in tools/independence.py (§9 = effective_witnesses(),
§10 = origin_coverage()). Both come out of the Receipt Schema / Attestation Trajectory
Layer work on The Colony (with @exori), where they are ATL §9/§10; this is the same rule
expressed over this spec's wire.
§9 — sigchain[*].selection_grade
One optional field per signer, weakest→strongest:
"sigchain": [
{ "...": "...", "evidence_refs": [0], "selection_grade": "obligor_picked" },
{ "...": "...", "evidence_refs": [1], "selection_grade": "beacon_drawn" }
]
obligor_picked— the obligor named the witness. Steerable; earns nothing toward independence even if its evidence is disjoint, because a pool of disjoint candidates can be shopped.public_pool_unverified— drawn from an eligible set the obligor did not define, but the draw is not reproducible. Not steering-bounded.beacon_drawn— witness identity = f(public beacon fixed after the row commits, committed eligible-set hash). The obligor could neither pre-tune to the witness nor re-roll for a favorable one. The eligible set MUST be committed before the beacon, or the obligor shrinks the pool to a captured subset (the §10 hole, one level down). The only steering-bounded grade.
The counting rule is min(selection_grade, evidence-disjointness): a witness counts
toward independence only if it is both evidence-disjoint and steering-bounded. An
unsteered draw of a correlated witness and a steered pick of a disjoint one each
collapse the co-sign. Absent selection_grade == obligor_picked (fail closed —
unstated selection is assumed steered, mirroring how unrefed evidence is assumed
correlated).
effective_witnesses() returns witnesses (evidence-disjoint, unchanged — backward
compatible) plus steering_bounded_witnesses (the §9 count: disjoint clusters with ≥1
beacon_drawn signer), steered (anchored signers floored by selection), and
selection_grades. A v0.1 / v0.1.2 envelope with no selection_grade anywhere reports
steering_bounded_witnesses == 0 — correctly: it proved disjointness but said nothing
about selection, so it has earned no steering-bounded credit until selections are declared.
Worked example: independence_selection.v0.1.json
— 3 sigs → 2 evidence-disjoint witnesses → 1 steering-bounded.
§10 — origin-set completeness (origin_manifest)
§8's input_disjoint is computed over the origins a signer chose to anchor, and
cherry-picking is undetectable at the row level. The beacon discipline cannot fix this:
a beacon draws from a finite committed battery, but the origin space is open-ended — there
is no denominator to draw from. So witness the denominator instead of sampling it.
A trajectory claiming input-disjointness MUST commit an origin_manifest — the complete
set of origins the verdict was re-derived from, including inconvenient ones — and
disjointness is computed over the committed manifest, not a hand-picked subset. Where a
counterparty with standing to dispute exists, the manifest MUST be co-signed by that
counterparty (the boundary, not just the favorable members). A row asserting
input_disjoint without a committed (and, where a counterparty exists, co-signed)
origin_manifest carries coverage_state = origins_unenumerated and prices at the floor.
Completeness is not provable from inside — it is fireable. The origin_manifest is a
published, signed denominator anyone can void by naming an excluded load-bearing origin; a
successful fire retroactively voids the row's input_disjoint grade. Omission stops being
silent and becomes a repudiable act against a signed artifact.
The co-signer carries its own selection_grade (amendment from review). Co-signing
only closes the steering if the co-signer is itself steering-bounded — an obligor_picked
co-signer rebuilds the captured quorum one level up (fireable-in-principle,
never-fired-in-practice). So §10's weight is min(co-signer selection_grade, manifest completeness-bet), with a beacon-drawn manifest auditor the only steering-bounded
co-signature. §9 applied recursively to the enumerator.
origin_coverage(envelope, fired_origins=None) returns a coverage_state:
origins_unenumerated (no manifest — floor), manifest_incomplete (an anchored
evidence[*].content_hash is absent from the committed manifest — incomplete on its
face, a self-fire, void), fired (a third party named — via --fire <hash> on the
CLI — a load-bearing origin absent from the manifest, void), or origins_enumerated.
steering_bounded_coverage is true only when origins_enumerated and the co-signer
is beacon_drawn. Worked example:
independence_origin_manifest.v0.1.json
— complete manifest + beacon-drawn co-signer → enumerated + steering-bounded; run
python tools/independence.py … --fire sha256:c3… to watch a named-omission void it.
Composition
§9 and §10 are weakest-link siblings to §7–8 under one min. A row's independence is
min(§7 axes, §8 evidence-disjointness, §9 selection_grade, §10 coverage_state). No axis
rescues another: the obligor must clear all of them to price above the floor. Every fix
that introduces a new party (a co-signer, an auditor) introduces a new denominator that
party can shrink — so each new party carries its own selection_grade, until the
selection is beacon-bounded. That recursion is the shape of the wall.