Agent Action Capsule · explain
14 / 16 · From the September deck

Twin verdicts and peer history

What happens after two nodes answer the same marked pair differently: who may referee, how the signed verdict reaches every node it concerns, how each node counts verdicts about its peers (counts, never a score), and the operator's opt-in rule to stop routing to a peer. Every line is checked against the capsules plugin at release v0.1.4, and the code that is not released yet is marked as such.

A twin pair, a referee's signed verdict, local verdict counts and the opt-in stop-routing rule Five Mesh-LLM nodes running the capsules plugin: a client at far left, node R the requesting node, nodes A and B the two twins, node C the chosen referee, and node D an ineligible referee. Stage 1: the client sends two requests to R with the same x-mesh-twin-bracket value. Stage 2: R forwards one to A and one to B; each seals its served half and pushes it back to R, which checks it before holding it. Stage 3: R compares: same request, temperature 0, same model and weights, and the answers differ, so a referee is due; if they agreed the pair is not adjudicated, nothing counts and nobody is asked. Stage 4: eligibility: C qualifies; D is crossed out because R counts a contradiction about D for this model within the bar window. Stage 5: R asks C to re-answer and sends it both halves; C signs a verdict, contradicted naming B, and seals adjudication_issued. Stage 6: R verifies the signature and seals adjudication_received; with delivery on, R sends the verdict to A and B, and each seals its own received record or refuses. Stage 7: R's Peers page shows counts per peer and model in four buckets: B contradicted 1, A corroborated 1; the counts stay on R. Stage 8: an opt-in rule: after N contradictions within D days, R asks its host to stop routing to B; the host blocks only if its operator allowed the plugin to, and R seals a record citing the verdicts. Client Node R asked for the pair Node A twin Node B twin Node C candidate referee Node D candidate referee x-mesh-twin-bracket: bracket-1 on both requests sealed half A sealed half B same request · temperature 0 same model · same weights answers differ → referee due (agree → not adjudicated, no call) eligible contradiction for this model within the bar window re-answer, then both halves signed: contradicted:<B> adjudication_issued C's own chain adjudication_received adjudication_received or a signed refusal delivery: off by default adjudication_received or a signed refusal R's Peers page, this model B contradicted 1 A corroborated 1 inconclusive 0 · not_comparable 0 each count lists its verdict ids counts only · never sent to a peer Opt-in: N contradictions in D days (off by default) → R asks its host to stop routing to B host blocks only if allow_peer_blocks = true R seals the block, citing the verdicts

1What it is

When a client marks two requests as one pair and the two nodes that served them give different answers, the node that asked can have a third node re-answer the request and sign a verdict naming the twin it does not agree with.

Each node the verdict concerns checks the referee's signature and seals its own record of it, and the node that asked counts verdicts about each peer in four plain counts, kept on its own disk.

An operator can opt in to one rule on top of those counts: after N contradictions within D days, ask the host to stop routing to that peer, which the host does only if its own operator allowed it.

2Design choices

Chosen: a pair exists only when a client marks it (x-mesh-twin-bracket); the host never adds a second request.
Rejected: the host sampling a share of requests and sending each to a second node, as the September deck showed (“about 1 in 50”). No such rate exists in the code. (capsules docs/TWIN-REFEREE-SELECTION.md §1; crates/evidence-plugin/src/referee/live.rs)
Chosen: twins that name different weights get no verdict at all (weights_mismatch); that pair is not comparable and nothing counts against either twin.
Rejected: marking the node that served other weights as contradicted, as the deck did. A weights claim is the node's own word in its signed record; a verdict rules only on words. (crates/evidence-plugin/src/referee/verdict.rs)
Chosen: referee eligibility is five yes/no rules over this node's own verified records, two tiers (with a corroboration for that model, then without), a random pick within the tier, and the tier sealed in the verdict.
Rejected: ranking candidates by merit, weighting, or any combined number. (TWIN-REFEREE-SELECTION.md §2, §3, §5)
Chosen: the verdict is a signed record held beside each node's log, and each node seals its own adjudication_issued or adjudication_received record citing it; a refused delivery is sealed by the node that tried to deliver it.
Rejected: one shared copy, or a delivery that leaves no trace when refused. (crates/evidence-plugin/src/adjudication_records.rs, referee/hold.rs)
Chosen: four counts per peer and model (corroborated, contradicted, inconclusive, not comparable), each a list of verdict ids the page can open; a received verdict counts only if this node asked that referee about that exact pair, and once per referee and pair.
Rejected: a score, a blended number, or counting any verdict that arrives: a signature says who signed, not that anyone asked, so any node with a key could otherwise mint verdicts about a peer. (crates/evidence-plugin/src/verdict_counts.rs)
Chosen: the stop-routing rule is off unless the operator sets N; with N of 2 or more, one referee alone can add at most N−1 contradictions; the rule asks the host over the plugin protocol, and the host refuses unless its operator set allow_peer_blocks = true for this plugin.
Rejected: the plugin routing anything itself, or calling the console's operator route to block a peer (the plugin did that before 0.1.3). (crates/evidence-plugin/src/routing_rule.rs; CHANGELOG.md 0.1.3)
Chosen: by default the node sends nothing to a peer on its own (it still answers a peer that asks for a record): the referee (adjudicate_differing_twins) and verdict delivery (share_adjudications) are both off until the operator turns them on, and the referee also needs record push (share_record_at_completion, off by default and symmetric) on both twins, since it is asked only once both pushed halves are held.
Rejected: the referee on by default, as the deck planned. Asking a referee sends the twins' prompt to a third node, so it needs an explicit switch. (docs/SHARING-POLICY.md; CHANGELOG.md 0.1.3)

3What it shows / what it does not

Shows

  • That the referee's key signed a ruling on one named pair of halves, at the tier it was asked from; a verdict with an altered tier fails verification.
  • For a node that seals adjudication_received: that it checked the referee's signature under the key it holds for that referee (announced by the referee's host, or set by the operator in CAPSULES_PEER_KEYS) before recording the verdict.
  • On the asking node: how many verified verdicts about each peer fall in each of four buckets, per model, with every verdict listed by id.
  • For a rule block: the rule's name and a commitment to each verdict it cited, sealed by the node that asked for the block.

Does not show

  • That an answer was right. A verdict says which twin's words the referee's own re-answer matched; the referee can be wrong too.
  • That a twin really loaded the model or weights it names: both are the node's own word in its record. Hardware evidence is the route beyond that; v0.1.4's referee flow does not use it.
  • Anything about pairs no client marked, about pairs whose twins named different weights, or about a node's future answers.
  • Anything to other nodes: the counts are this node's own and are never sent. (A peer can ask for history_card/1, a different thing: a derivation of the node's checkpoint history, with consistency proofs.)
  • A live run: v0.1.4 says a referee verdict on live hosts “is covered by tests only” (CHANGELOG 0.1.4).

4Example

A case from the plugin's referee parity corpus: node R holds three verdicts about three twin pairs served by node-a and node-b for one model, from three different referees, each one R asked for. The operator set N = 3 contradictions within 7 days. One of the three input records, then the answer the rules give.

// corpus/counts.json, case "fires_at_n_within_window": settings and one of three records
"settings": { "stop_routing_after_contradictions": "3", "stop_routing_window_days": "7" },
"host": { "blocked": [], "peer_blocks": true },
{
  "model_attestation": {
    "compute_attestation": {
      "adjudication_received": {
        "half_node_ids": ["node-a", "node-b"],
        "halves": ["f47851c19964011b864120be12a7e10aea6e7c5d5076f8b97bd64ae39abcc97e",
                   "003127801349c5cb9d5cd627fc8ec273bdbcc4f428fa252eae141c6ccfb8b610"],
        "model_hash": "b2767326b03d5e629546363ebe41714b78065e028709580996d60d2d119192da",
        "received_at": "2026-09-29T00:00:00Z",
        "referee_node_id": "node-c",
        "verdict": "contradicted:node-a",
        "verdict_capsule_id": "0660df2a44bc180e4a474fd809e3116ebde1a29c5f154260db7c9bca2f288301"
      }
    }
  }
}

// rule_answers/counts.json: the answer (verdict id lists trimmed)
"counts": {
  "node-a": { "b2767326…92da": { "contradicted": { "count": 3, … }, "corroborated": { "count": 0 },
                                 "inconclusive": { "count": 0 }, "not_comparable": { "count": 0 } } },
  "node-b": { "b2767326…92da": { "contradicted": { "count": 0 }, "corroborated": { "count": 3, … },
                                 "inconclusive": { "count": 0 }, "not_comparable": { "count": 0 } } }
},
"outcomes": [ { "outcome": "blocked", "peer_id": "node-a", "verdict_capsule_ids": [ … 3 ids … ] } ],
"rule": { "after": 3, "window_days": 7 }
FieldTypeMeaning
adjudication_receivedobjectThe block of R's own record of a verdict it verified: sealed only after the referee's signature checked under the key R holds for that referee.
half_node_ids[string, string]The two twins the verdict judges.
halves[hex, hex]The twins' served records, by capsule_id; with the referee they form the pair key that counts once.
model_hashhexThe model the twins named. Counts, the bar window and the referee tiers are all per model.
received_atRFC 3339When R recorded the verdict (to the minute). Windows run from this time, never from a time the referee wrote.
referee_node_idstringWho signed. A verdict whose referee is one of the twins counts nowhere.
verdictstringcontradicted:node-a: the referee's answer did not agree with node-a's. It counts as contradicted for node-a and corroborated for node-b.
verdict_capsule_idhexThe signed verdict this record cites; each count lists these ids.
countsobjectPer peer, per model, the four buckets, zeros included. Never sent to anyone.
outcomesarrayblocked: the host took the block of node-a; the three cited verdicts never count toward the rule again.
host.peer_blocksboolThe host offers the stop-routing path. Without it the outcome is no_host_hook and no verdict is spent.

The same corpus pins the edges: N−1 contradictions do not fire; four contradictions from one referee never reach three; a contradiction seven days and one second old is outside a seven-day window; after the operator undoes a block, only new contradictions fire it again.

Source: Mesh-LLM/capsules:vectors/parity/referee/corpus/counts.json and vectors/parity/referee/rule_answers/counts.json @ b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad (tag v0.1.4). Node ids are the corpus's placeholders.

5Status

The September deck split this into a “demo build today” and a later upstream plugin release. The code differs from both columns. Today means the latest tagged release; the upstream column is the plugin's move into the mesh-llm repository, which is not merged.

PieceToday: capsules v0.1.4Not released yet
Client-marked twin pairsBuilt. Host side in mesh-llm v0.78.1 (PR 2144): the client's x-mesh-twin-bracket value reaches the plugin and is stripped before forwarding.mesh-llm PR 2300 (merged, in no release yet) advertises it as the twin_bracket capability; no change in behaviour.
Referee verdict, signed by the refereeBuilt, off by default; on live hosts covered by tests only (CHANGELOG 0.1.4). The deck's “sealed by the requester, not yet signed by the referee” no longer holds: the referee signs.capsules main @ efcada74026a2e18b9e62d77432888a31bbe9de4: the referee checks the signature on a signed adjudicate request before reading it; an unsigned one is still answered (PR 31, PR 33).
Verdict sealed by every node it concernsBuilt: adjudication_issued on the referee, adjudication_received on the asking node and, with share_adjudications on (off by default), on each twin.—
Verdict counts per peerBuilt: the Peers page's four counts, local only (verdict_counts.rs).—
Opt-in stop-routing ruleBuilt, off by default (routing_rule.rs). The host path it needs, allow_peer_blocks, is in mesh-llm release v0.78.1 (crates/mesh-llm-config/src/model.rs). The deck's “stop routing is manual” no longer holds.—
The plugin inside mesh-llmA separate repository and release.mesh-llm PR 2459 (open) moves it into the mesh-llm workspace; PR 2337 (merged) lets a node install default plugins from a release bundle, and is inert until a release carries one. mesh-llm v0.78.1, its latest release, carries none.

Evidence: Mesh-LLM/capsules tag v0.1.4 @ b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad (CHANGELOG.md, docs/TWIN-REFEREE-SELECTION.md, docs/SHARING-POLICY.md, crates/evidence-plugin/src/verdict_counts.rs, routing_rule.rs, referee/); capsules main @ efcada74026a2e18b9e62d77432888a31bbe9de4; Mesh-LLM/mesh-llm tag v0.78.1 @ bc215ce5b880e21c6c3840b8574ab64f83278821; mesh-llm PRs 2144, 2300, 2337, 2459 (checked 2026-10-19).

6Specs