When is consensus among independent Cogs required?
Oliphant, 2026, §5.6
The manifest answers with a threshold: consensus_disagreement > 0.25.
But the rule does not say what the number measures. Rather than choose
for the author, the specification fixes the metric’s type (a
fact-by-checker answer matrix of nullable Booleans, mapped to a scalar
in [0, 1] against the factored threshold; the codomain is a checked
constraint, TYPE-01) and exhibits three type-satisfying metrics with
different semantics, evaluated on the same matrix. All three satisfy
the type; none is thereby correct. They do not agree on whether the
gate fires, and, on the ensemble the recorded run used, two of them
cannot fire it at all.
The answer’s base type is a nullable Bool, chosen for type-checking
support as much as for clarity. The semantics: given a datum as
context, and irrespective of which Cog produced it, each checker
answers one question, “do you agree with the datum?”. True is
agreement, False is disagreement, and null is cannot tell (the same
outcome the Track records as earl:cantTell). Checkers are factored
apart from generators on purpose: it is strictly possible for a Cog to
produce a datum and still answer False when asked whether that datum is
true. One could assume a producer always files True about its own
output; the specification does not, and a Cog’s answer about its own
datum is one column like any other (clarifications logged with GAP-04
in the open-questions chapter). The matrix is rectangular, and a run
with no facts scores zero.
A correctly constructed policy is not the same as a fit-for-purpose policy. What is right for the job here is an open algorithmic policy design question, likely to have no unique correct answer but many viable answers with different implications on incentives, and the right answer is not limited to these three.
1The type, in the model¶
The abstract definition carries the type signature and five property
attributes (what the value is a fraction of, how a null is treated,
monotone in dissent, saturates at unanimous dissent, invariant under
ensemble size). It splits along one axiom into two branches: a
DisagreementMetric measures how much dissent a run carries and is
monotone in it; an UndecodabilityMetric measures whether facts
resolve and is not. Three concrete definitions specialize the branches,
each documenting its semantics and its incentive implication and
redefining the attributes its branch leaves open. The split names the
under-specification the first version of this chapter only exhibited:
the original single class could not distinguish two different
quantities that both fit the type (a finding of the second external
review, ruled on as a refinement of GAP-04). The table is parsed from
the model: each row is one definition with its doc, verbatim.
import sys; sys.path[:0] = [".", ".."] # the repo root, from either cwd
import exhibits
exhibits.show_metric_definitions()The structural fact sits in the comparator oracle. Its metric slot is
typed by the abstract definition and deliberately left unbound
(part metric : ConsensusInadequacyMetric; with no concrete binding):
the model states that a metric of this type is required and refuses to
choose one (GAP-04 in the open-questions chapter). A deployment binds
it, and in doing so picks a branch, which is a visible policy decision;
the Track records which one a run used, and the matrix it ran on. The
sharper punchline comes later in the chapter: two of the three
type-satisfying bindings make the gate unreachable on the very ensemble
the Track records.
exhibits.show_unbound_metric_slot()part def ConsensusComparatorOracle :> OracleService {
doc /* adjudicated: GAP-04 — the metric slot below is typed by
the abstract ConsensusInadequacyMetric and deliberately left
unbound: the model states that a metric of this type is
required and refuses to choose one. A deployment binds it,
choosing a branch (disagreement or undecodability) as a
visible policy decision; the Track records which one a run
used, and the matrix it ran on (GAP-12). */
part metric : ConsensusInadequacyMetric;
attribute returnedDisagreement : ScalarValues::Real;
port reading : ReadingWrite;
}
2The three implementations¶
The same three semantics as running code, satisfying the declared type:
dissent-fraction counts every answer that is not True, null included: honest abstention is punished, so checkers are pushed to affirm rather than say cannot tell. On the paper’s own section 5.5 example (three Cogs, two must agree) it FIRES the gate at 0.25, contradicting the example’s intent.
strict-quorum-undecodable counts facts where no answer reaches a quorum of two matching non-null answers; null blocks quorum, so it escalates more, spending expert-review capacity. The quorum is the paper’s two-of-three, deliberately, and the metric is admissible for a three-checker ensemble only (with one checker, unanimous agreement scores 1; with nine, two agreements outvote seven dissents).
erasure-aware-undecodable treats null as an erasure, not an error: a lone expressed voice among abstentions decodes, so abstention shifts power to whoever still answers.
Both undecodability metrics are “consistent with the section 5.5 example”, and the reason is not flattering: on three checkers with no abstention they are identically zero (shown below). Consistency with the example is a consequence of never firing, not evidence of fitness.
Could the signature live in the model as a calculation rather than as
annotation? Partly. The pinned evaluator accepts a calc def with typed
scalar parameters (probed, 2026-09-05); carrying a nullable-Boolean
matrix and three alternative bodies through it was not attempted. So
the signature is carried as declared attributes in the model and as
Python here, and the test suite holds the two equal. That is the same
honest division as the wiring rules in chapter 2: the model states,
code checks.
import inspect
for f in (exhibits._rectangular, exhibits.dissent_fraction,
exhibits.strict_quorum_undecodable, exhibits.erasure_aware_undecodable):
print(inspect.getsource(f))def _rectangular(matrix):
"""True if there is anything to measure; raises on a ragged matrix."""
if not matrix:
return False
if any(len(fact) != len(matrix[0]) for fact in matrix):
raise ValueError("answer matrix must be rectangular: one answer per checker per fact")
return True
def dissent_fraction(matrix):
if not _rectangular(matrix):
return 0.0
dissents = total = 0
for fact in matrix:
dissents += sum(1 for v in fact if v is not True)
total += len(fact)
return dissents / total
def strict_quorum_undecodable(matrix):
if not _rectangular(matrix):
return 0.0
undecodable = 0
for fact in matrix:
expressed = [v for v in fact if v is not None]
if not expressed or max(expressed.count(v) for v in set(expressed)) < 2:
undecodable += 1
return undecodable / len(matrix)
def erasure_aware_undecodable(matrix):
if not _rectangular(matrix):
return 0.0
undecodable = 0
for fact in matrix:
expressed = [v for v in fact if v is not None]
if not expressed or max(expressed.count(v) for v in set(expressed)) * 2 <= len(expressed):
undecodable += 1
return undecodable / len(matrix)
3What each metric is, proved¶
The doc comments above make claims; the attributes make assertions; the
cell below checks them. For each property the model declares, the
implementation is enumerated over every answer matrix of up to two
facts by three checkers (the test suite goes to three facts), and the
declared value is compared with what the enumeration finds, with the
minimal counterexample wherever a property fails to hold. Two results
deserve a sentence each. Flipping one answer from agree to disagree can
decrease both undecodability metrics: [T, F, null] scores 1.0 and
[F, F, null] scores 0.0, because unanimous disagreement decodes. And
a matrix of unanimous disagreement scores 0.0 under both, which is why
they are not disagreement metrics and the class had to split.
exhibits.show_metric_properties()declared = computed: 15 of 15 cells agree (the model asserts, the enumeration checks; the test suite repeats this over facts <= 3)
4Two of three bindings cannot fire the gate on this ensemble¶
The recorded run names three Cogs. With three checkers over a two-valued answer domain, some value occurs at least twice, so the strict quorum is always met, and the majority strictly exceeds half, so the erasure-aware rule always decodes. Both undecodability metrics are identically zero on every answer matrix without an abstention. No threshold makes GATE-02 fire under them; only a null can. This is not “the bindings disagree at the margin”; it is a structural difference in what the gate is capable of doing under each binding, on the exact configuration the Track records. The cell reads the ensemble size from the Track and enumerates.
exhibits.show_gate_reachability()ensemble size from track/run-001.trig cogs_invoked: 3 checkers; gate fires when the metric > 0.25
dissent-fraction : no abstention -> values {0, 0.333, 0.667, 1}; with abstention -> values {0, 0.333, 0.667, 1}
strict-quorum-undecodable : no abstention -> values {0}; with abstention -> values {0, 1}
erasure-aware-undecodable : no abstention -> values {0}; with abstention -> values {0, 1}
with 3 checkers and no abstention, GATE-02 cannot fire under: strict-quorum-undecodable, erasure-aware-undecodable
proposition (proved by enumeration, here and in the test suite for every odd ensemble size up to 7): over a two-valued domain, three expressed answers always contain a repeated value, so quorum-2 is met and the majority strictly exceeds half. Both undecodability metrics are identically zero; only abstention can make them nonzero. Their consistency with the section 5.5 example is a consequence of this, not evidence in their favour.
5The convention that binds model to code¶
The model cannot hold Python, and this walkthrough does not pretend it
does. The binding between a part def and the function that implements
its logic is a stated, mechanical convention, checked in both
directions. A definition’s metric id is derived from its name
(DissentFractionMetric becomes dissent-fraction); the same id keys
the implementation mapping in exhibits.py and is the value a Track
records in vfr:metric. The cell verifies the correspondence is
one-to-one — every model definition has an implementation, every
implementation has a definition — and that the metric run-001 cited
resolves to a bound implementation. In a deployment, the same id is how
the comparator oracle’s configuration names the metric it bound into
the open slot.
exhibits.show_metric_binding()model <-> implementation binding: OK (3 definitions, 3 implementations)
run-001 recorded metric: strict-quorum-undecodable -> bound implementation: exhibits.strict_quorum_undecodable
6One matrix, three answers¶
The same answer matrix, the threshold read from the model’s single
point of definition, and different gate decisions. The headline matrix
is constructed so that no metric lands on the threshold. A second
matrix is kept apart as the boundary case: under it one binding scores
exactly 0.250, and the decision turns entirely on the comparator, which
is the manifest’s own strict >, verbatim from the section 5.6 rule
(so its strictness is source text, not a judgment call). The Track
records which metric a run actually used; recording is not endorsing.
One more thing the single point of definition conceals: the three metrics do not share a denominator. dissent-fraction is a fraction of answers; both undecodability metrics are fractions of facts. The one number 0.25 therefore means different things under different bindings. The threshold stays where the manifest puts it, on the policy, and each metric now declares its denominator as a model attribute so the difference is a model fact rather than a reading of the code (GAP-11 in the open-questions chapter).
exhibits.evaluate_metrics()type signature: ConsensusInadequacyMetric = (fact x checker answer matrix of nullable Bool; True = agree, False = disagree, null = cannot tell) -> [0, 1]
same answer matrix for all three metrics (8 facts x 3 checkers; fabricated example data, constructed to separate the metrics):
f1: True True True
f2: True True True
f3: True True True
f4: True True False
f5: True False null
f6: True null null
f7: False null null
f8: True False False
threshold (from the model, single point of definition): > 0.25
dissent-fraction : 0.417 -> gate fires: True
strict-quorum-undecodable : 0.375 -> gate fires: True
erasure-aware-undecodable : 0.125 -> gate fires: False
the boundary case (a second matrix, kept apart from the headline): one binding lands exactly on the threshold, and the comparator is the manifest's own strict >, verbatim from the section 5.6 rule —
f1: True True True
f2: True True True
f3: True True True
f4: True True False
f5: True True null
f6: True False null
f7: False null True
f8: True null null
dissent-fraction : 0.333 -> gate fires: True
strict-quorum-undecodable : 0.375 -> gate fires: True
erasure-aware-undecodable : 0.250 -> gate fires: False (exactly on the boundary)
the paper's own section 5.5 example, as one fact (three Cogs classify a document, two agree):
dissent-fraction : 0.333 -> gate fires: True
strict-quorum-undecodable : 0.000 -> gate fires: False
erasure-aware-undecodable : 0.000 -> gate fires: False
7The recorded run, under all three bindings¶
The Track records the consensus reading’s metric and its output. Since the second external review it also records its input: the answer matrix the comparator ran on (GAP-12 in the open-questions chapter). So the recorded value can be recomputed by anyone holding the record, and the question this chapter raises can be asked of the run rather than of fabricated data: what would the other two bindings have said about these answers? The matrix is fabricated like the rest of run-001, but it is the run’s, and the audit below is the one an auditor could perform.
exhibits.show_run_001_under_all_bindings()run-001 recorded: metric strict-quorum-undecodable, value 0.1, matrix 10 facts x 3 checkers:
f1: True True True
f2: True True True
f3: True True True
f4: True True False
f5: True True False
f6: True True False
f7: True True False
f8: True True False
f9: True True False
f10: True null null
run-001 recomputed under strict-quorum-undecodable: 0.100 -> equals the recorded value: True
the same answers under every binding the model admits:
dissent-fraction : 0.267 -> GATE-02 fires: True
strict-quorum-undecodable : 0.100 -> GATE-02 fires: False (the binding this run used)
erasure-aware-undecodable : 0.000 -> GATE-02 fires: False
8How often the choice matters¶
One matrix proves the bindings can disagree. It says nothing about how
often, or where. The sweep below draws answer matrices from a stated
generative model (independent cells; abstain with probability
p_abstain, otherwise dissent with probability p_dissent), twelve
facts by the recorded three checkers, and reports how often the three
bindings fail to agree on the gate decision, and how often each fires.
The marginal firing rates are the number a policy designer can budget
against: the expert-review load each binding would impose on the same
stream of runs. The heaviest binding fires about five times as often
as the lightest. That is the incentive claim from the bullets above,
as a quantity.
The caveat is stated in the cell’s docstring and repeated here: real checkers are correlated, and correlated dissent is exactly what a consensus gate exists to catch, so these numbers are a lower bound on how much the choice matters. A correlated-checker variant is logged as future work in the judgment record.
exhibits.show_metric_sensitivity()generative model: independent cells, 12 facts x 3 checkers, 500 trials per cell, gate fires when metric > 0.25, seed 20260905
P(bindings disagree about whether GATE-02 fires)
p_abstain \ p_dissent 0.00 0.10 0.20 0.30 0.40 0.50
0.00 0.000 0.000 0.170 0.666 0.934 1.000
0.10 0.004 0.140 0.530 0.874 0.950 0.944
0.20 0.176 0.568 0.816 0.874 0.816 0.798
0.30 0.696 0.870 0.836 0.770 0.694 0.622
0.40 0.944 0.906 0.800 0.660 0.600 0.584
0.50 0.952 0.788 0.668 0.550 0.500 0.426
marginal firing rate per binding, averaged over the grid (the expert-review load each binding would impose):
dissent-fraction 0.791
strict-quorum-undecodable 0.476
erasure-aware-undecodable 0.149
maximum disagreement 1.000 at p_abstain=0.0, p_dissent=0.5. In the no-abstention row the maximum is 1.000: the reachability proposition showing up statistically, since there the two undecodability bindings never fire and dissent-fraction fires whenever dissent is common
- Oliphant, T. (2026). The Distributed AI Economy: Intelligence Hubs, Frames, Cogs, Ops, and the Accountability Plane [Techreport]. OpenTeams.