Agent Action Capsule · build your own evidence layer
b4 / 11

Use-case evidence: twins and a referee

Seam ③ Check/judge. Build: a sampled twin comparison and a signed referee ruling. Conform to: draft-mih-agent-bilateral-attestation-02 and draft-mih-agent-evidence-layer-00 §4.1, §5.

Sending a request to two nodes and comparing the answers tells you how often a pairing disagrees; asking a third node to re-answer one disagreeing pair and sign a ruling tells you which twin it agrees with, and when nobody can rule, the pair is left unruled rather than counted against anyone.

The same bad provider under sampling only and under adjudication Top band: a client, a requesting node R, two serving nodes A and B, and a compare box. Step 1: node B's record says weights W, like A's, but B runs another file. Step 2: the client marks three pairs with the header x-mesh-twin-bracket; R forwards one request of each pair to A and one to B with the header stripped; one extra request per marked pair. Step 3: R compares the answer digests in the twins' signed records: pair 1 the same, pairs 2 and 3 differ. Bottom left panel, sampling only with the referee off. Step 4: each differing pair reads Not adjudicated, the check is turned off; the Peers row reads twin pairs 3, answers differed 2, not adjudicated. Step 5: what this gives is a rate of differing pairs; it does not say which twin was wrong, nothing counts against either, routing is unchanged. Bottom right panel, with a referee. Step 6: the client supplies the texts, kept only when their digests match the records; for a temperature-0 pair on the same model and weights R compares them word by word and picks an eligible node C, which serves the same model and weights, is neither twin and has a key; C re-answers at temperature 0, one call per pair. Step 7: C signs a verdict on one pair, contradicted B; R counts it under B, contradicted 1. Step 8: with no eligible node, the pair reads Not adjudicated, no eligible referee, and B is not contradicted. Step 9: hardware evidence of what was loaded is the route beyond self-report; in this plugin at v0.1.4 the slot is written empty: designed. Client Node R requesting node evidence plugin Node A record: weights W runs W Node B record: weights W runs another file marks 3 pairs: x-mesh-twin-bracket cost: +1 request per pair stripped R compares answer digests pair 1: same pair 2: differ pair 3: differ from the digests each twin's signed record seals 1 · Sampling only (referee off) 2 · With a referee (on) pairs 2, 3 · Not adjudicated: the independent check is turned off on this node. Peers · B: Twin pairs: 3 · answers differed: 2 · not adjudicated What you get: a rate (2 of 3 pairs differed). It does not say which twin was wrong: A, B, or both. Nothing counts against either; routing is unchanged. Pairs marked at random: an estimate, with sampling error. Node C · referee same model + weights neither twin · has a key re-answers the request at temperature 0 one call per pair, no retry pair 2 · signed by C: contradicted:B R holds it · verdicts about B: contradicted 1 Nobody eligible: Not adjudicated: no eligible referee. No call made; B is not contradicted. Beyond self-report: hardware evidence of what B loaded. v0.1.4: slot written empty · designed

1What it is

Use-case evidence is what you add on top of the plain record when your use case asks a question the record cannot answer by itself; for inference served on strangers' machines that question is whether a node served the model its record names.

Sending some requests to two nodes and comparing the answers gives you a rate, how often a pairing's answers differed, which tells you something is off without telling you who.

Adjudication adds a third node that re-answers one differing pair and signs a ruling naming the twin it did not agree with; where no node can do that, the pair reads “not adjudicated” and counts against no one.

2Design choices

Chosen: a pair exists only when a client sends the same x-mesh-twin-bracket value on two requests; the host copies it into twin_bracket_id and never sends a second request itself.
Rejected: the host duplicating a share of requests at a configured rate, or pairs guessed from timing or content. No such rate setting exists in the host or in the plugin; the cost knob is how many pairs a client marks, plus the operator's referee switch. (mesh-llm docs/plugins/openai-exchange-lifecycle.md, “Client-marked pairs”; PR 2144; capsules docs/TWIN-REFEREE-SELECTION.md §1, §4)
Chosen: the header is stripped before a request is forwarded, so a serving node cannot know its answer is half of a pair.
Rejected: forwarding it, which would tell a serving node which of its answers are being compared. (mesh-llm PR 2144, forwarded_request.rs; test added in PR 2300)
Chosen: compare only pairs answered at temperature 0, on the same model hash and the same weights digest, by exact words; any difference counts.
Rejected: comparing sampled answers, which differ honestly, and a similarity threshold. A pair outside these rules reads “not comparable” with why. (capsules crates/evidence-plugin/src/referee/request.rs, before_asking; crates/evidence-plugin/src/referee/verdict.rs)
Chosen: without a referee a difference is inconclusive; only a referee's re-answer names a twin, and only the twin it did not agree with.
Rejected: the requesting node deciding, or treating a difference as evidence against either side. (capsules crates/evidence-plugin/src/referee/verdict.rs, referee_verdict; vectors/parity/referee/intended_differences.json, “only the referee signs”)
Chosen: no eligible referee, a referee that cannot sign, or one that does not answer: “not adjudicated” with the reason, counting against neither twin; at most one call per pair, never retried on its own.
Rejected: reading a missing ruling as a contradiction, and retrying other referees until one rules. (capsules docs/TWIN-REFEREE-SELECTION.md §4; crates/evidence-plugin/src/referee/request.rs, NO_ELIGIBLE_IS_RETRIED_AUTOMATICALLY = false)
Chosen: eligibility is a set of yes/no rules (same model and weights, neither twin, announced key, not blocked, no contradiction for that model in the last referee_bar_days); the pick is random within a tier, and the tier is sealed in the verdict.
Rejected: ordering nodes by merit or blending anything into one number; verdicts are counted per peer; the counts stay on this node and are never sent to anyone. (capsules docs/TWIN-REFEREE-SELECTION.md §2, §3, §5; crates/evidence-plugin/src/verdict_counts.rs)
Chosen: the referee is off by default; the operator turns it on (adjudicate_differing_twins).
Rejected: on by default: asking a referee sends the twins' request, including the prompt, to a third node. (capsules docs/SHARING-POLICY.md; CHANGELOG.md 0.1.3)
Chosen: the record keeps a slot for hardware evidence and writes it empty when no quote was taken.
Rejected: filling it from what a node says about itself; a producer must not record an assurance mode it did not achieve, and the same rule applies here: no quote, no claim. (capsules crates/evidence-plugin/src/producer/capsule.rs, tee_attestation; draft-mih-scitt-agent-action-capsule-05 §5.4)

3What it shows / what it does not

Shows

  • Sampling only: for pairs a client marked, whether the two sealed answers were byte-identical (their answer digests); over many pairs, how often a pairing differed (“Twin pairs: N · answers differed: M”). Sampled answers count as differing too.
  • With a referee: a signed ruling on one pair: which twin the referee's re-answer agreed with at the earliest differing word, with the other named contradicted:<node>.
  • What the ruling covers: both halves' record ids, the request digest, the weights digest and the referee's own answer digest, all under the referee's signature, which a holder can verify against the referee's key.
  • For a pair with no ruling, why: off, not marked, answers agree, not comparable (with why), no eligible referee, referee cannot sign, referee did not answer.

Does not show

  • Sampling only: which twin was wrong, or that either was. A difference counts against no one.
  • Which model ran. The matching weights are each node's own claim, and twins serving the same wrong file corroborate each other.
  • A node's future answers. A verdict is a ruling on one pair.
  • Honesty across different hardware: exact replay can differ on different silicon for reasons unrelated to honesty, so such a mismatch is grounds to investigate, not a ruling.
  • That the referee is independent of either twin; that is a claim about who runs it.
  • Anything about a pair no client marked.
  • Hardware evidence: at v0.1.4 no hardware quote is taken.

4Example

One pair from the referee's rule corpus, the same pair run under three regimes. Node B's answer differs from A's at the fourth word (index 3: "4," against "999"); the referee's re-answer is "1, 2, 3, 4, 5". The pair, trimmed:

"pair": {
  "halves": [
    { "capsule_id": "3cde7ec4853bdf6d2e33904c1d4b2e972984b8725b3f72abeee503dbd2065480",
      "model_hash": "b2767326b03d5e629546363ebe41714b78065e028709580996d60d2d119192da",
      "node_id": "node-a", "temperature": 0, "text": "1, 2, 3, 4, 5",
      "weights_digest": "ac28b90e169cc75956ee6283ac8dc787a945696122692a3b2f266d8453ff56cc" },
    { "capsule_id": "e96c12b9157ef4a7c82529e4ad1c1f6c823ac7b8a06b856a3cedada021945c4a",
      "model_hash": "b2767326b03d5e629546363ebe41714b78065e028709580996d60d2d119192da",
      "node_id": "node-b", "temperature": 0, "text": "1, 2, 3, 999 5",
      "weights_digest": "ac28b90e169cc75956ee6283ac8dc787a945696122692a3b2f266d8453ff56cc" }
  ],
  "request_digest": "c0b439598e4ff10d8f55dc241798b2a80aa8de77e564a169f8931336ac33ef1a",
  "twin_bracket_id": "bracket-1"
}

The answers the rules require for it, one line per regime:

"operator_off_calls_nothing_and_says_so": [{"counts_against":null,"referee_calls":0,"row":{"reason":"off","state":"not_adjudicated"}}]
"differing_pair_triggers_one_call": [{"counts_against":"node-b","referee_calls":1,"row":{"referee":"node-c","state":"adjudicated","tier":1,"verdict":"contradicted:node-b"}}]
"no_eligible_referee": [{"counts_against":null,"referee_calls":0,"row":{"reason":"no_eligible_referee","state":"not_adjudicated"}}]
FieldTypeMeaning
twin_bracket_idstringThe value the client sent in x-mesh-twin-bracket. Without one, nothing is compared and nobody is asked.
request_digesthexDigest of the request both twins answered; with the bracket id and the two node ids it is the pair's key, so a re-sealed half is the same pair.
capsule_idhexEach twin's own signed record of its half.
node_idstringThe node that served the half (placeholder ids in the corpus).
temperaturenumberAbove 0 means sampled: the pair reads “not comparable”, because sampled.
model_hash / weights_digesthexWhat each half's record says it served. Both must be named and equal, or the pair is not comparable. Self-report.
textstringThe answer. A node holds it only when the client supplies it and its digest is the record's response_digest.
statestringadjudicated or not_adjudicated.
reasonstringWhy a pair has no ruling: off, no_eligible_referee, and the other reasons listed above.
verdictstringThe referee's ruling: contradicted: plus the twin it did not agree with, or inconclusive, or not_comparable.
referee / tierstring / intWho was asked, and from which tier: 1 has a corroborated verdict for the model on this node's chain, 2 has none yet.
referee_callsintCalls this attempt made: 0 or 1.
counts_againststring / nullThe node the row's contradiction counts against; null for every unruled pair.

The corpus states these answers from the rules; the plugin's tests run them. Two of the three cases leave the setting unset, which the test harness reads as on; a running node reads an unset adjudicate_differing_twins as off. The signed verdict record a referee seals, with its own fields, is crates/evidence-plugin/tests/fixtures/referee-verdict.json at the same tag (the fixture predates -05 and carries spec_version -04; the plugin seals -05).

Source: Mesh-LLM/capsules:vectors/parity/referee/corpus/request.json and Mesh-LLM/capsules:vectors/parity/referee/rule_answers/request.json @ b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad (tag v0.1.4)

5Status

ItemStatusEvidence
Client-marked pairs in the host: x-mesh-twin-bracket copied into twin_bracket_id and stripped before forwardingliveMesh-LLM/mesh-llm PR 2144, merged 2026-10-03 (merge 6d36f3845c5f021eac432dfdc8c20efcbfaa340a); in release v0.78.1 (bc215ce5b880e21c6c3840b8574ab64f83278821: crates/mesh-llm-host-runtime/src/network/openai/forwarded_request.rs, ingress.rs).
The host advertises capabilities.twin_bracketbuilt, not liveMesh-LLM/mesh-llm PR 2300, merged 2026-10-11 (merge 572419fd1e3074f7e948996c292ca8e7972bda8c), on upstream main 60697c61755b7280c22d3ab9d9bcf5b663e8ae3b; after the latest release, v0.78.1 (2026-10-05).
Twin comparison, “not adjudicated” rows with reasons, and the Peers twin rowbuilt, not liveReleased in capsules v0.1.4 (b4e24453f572b2d9fe8f2cefbd0f35a5eb54b0ad: crates/evidence-plugin/src/referee/request.rs, CHANGELOG.md 0.1.4). Works with the twin_bracket_id stock mesh-llm v0.78.1 already carries (PR 2144); not yet reported on live hosts.
Referee: selection, re-answer, signed verdict, bar window; off by defaultbuilt, not livecapsules v0.1.4 crates/evidence-plugin/src/referee/, docs/TWIN-REFEREE-SELECTION.md. CHANGELOG.md 0.1.4: “A referee verdict on live hosts waits on 0.1.5; until then it is covered by tests only.”
Opt-in rule: stop routing to a peer after N referee-signed contradictions in D daysbuilt, not livecapsules v0.1.4 docs/TWIN-REFEREE-SELECTION.md §6, crates/evidence-plugin/src/routing_rule.rs; off by default, and it counts only referee-signed verdicts, which are not yet live.
A host-side rate that duplicates a share of requestsnot builtNo such setting in mesh-llm at 60697c61755b7280c22d3ab9d9bcf5b663e8ae3b or in capsules v0.1.4; the host “sends no second request” (docs/plugins/openai-exchange-lifecycle.md).
Hardware evidence of what was loaded, cited by digest from the recordin this plugin: designedcapsules v0.1.4 crates/evidence-plugin/src/producer/capsule.rs: the tee_attestation slot is always written empty, “no TEE quote measured … recorded absent, never fabricated”.

6Specs

7What you need before the next step