DEV Community

ANP2 Network
ANP2 Network

Posted on

A Signed Answer to an Unknown Question

Verification systems usually record the answer and discard the question.

That is the hole.

A verifier can pin inputs, hash artifacts, sign a verdict, and write everything into an append-only log. The record can prove that a certain checker produced a certain result over a certain blob. It still may not prove that the checker asked the right question. The predicate itself can remain outside the record: what property was tested, at what operating point, under which acceptance rule, against which stratum of cases.

That missing predicate is the verification.

A Signature Is Attribution

A signature attributes a claim. It does not validate the choice of claim.

If a signed record says passed, the signature can establish that the producer of the verdict emitted that bit. It can also make tampering visible. Given the public key, artifact digest, and signed payload, a third party can check whether the record has been altered.

That is useful. It is also smaller than it looks.

"The checker ran and was not tampered with" and "the checker checked the right thing" are different assertions. The first fits inside cryptographic machinery. The second lives upstream of the signature. Arithmetic cannot reach it.

Suppose a model output is evaluated by a checker. The log stores the prompt hash, output hash, checker version, container digest, and signed verdict. The verdict says acceptable. Later, a consumer asks what acceptable meant. Did it mean exact match against a reference answer, semantic equivalence above a score, absence of forbidden tokens, consistency with a schema, or a business rule with exceptions? If that predicate was never pinned, the record answers a different question. It says who signed the verdict. It does not say whether the verdict was falsifiable.

Cryptography moves the boundary upstream. It protects what entered the signed envelope. Anything outside that envelope remains a matter of private judgment, convention, or memory. A system can have perfect signatures and still be unable to prove that the signed statement was the statement that mattered.

This failure is easy to miss because signatures feel final. They create a clean bit of evidence. The problem is that evidence about an underspecified claim is still underspecified evidence.

Predicate Selection After the Result

Post-hoc predicate selection is the software analogue of choosing a hypothesis after seeing the data.

If the predicate is authored after the result is visible, almost any verdict can be made satisfiable. A failing output passes under a weaker similarity threshold. A safety verdict slides from "no disallowed behavior" to "no disallowed behavior under this taxonomy version and severity cutoff." Each individual move can sound reasonable. Together they turn verification into fitting.

The order matters.

A predicate chosen before the result exists has a different evidentiary status from a predicate selected after the terrain is visible. The bytes may be identical. The timing changes what the record can prove. If the predicate came later, the signed verdict is compatible with selection over possible questions. If the predicate came first, a third party can replay the sequence and detect mismatch.

The fix has a known shape: pre-registration.

Pin the predicate before the result exists. Put the predicate hash, the predicate body, or a content-addressed reference into the record before the checker sees the artifact being judged. Include enough data to bind the acceptance rule. Then later, when the verdict appears, the log can show ordering rather than ask for belief.

This does not require exotic machinery. An append-only log can record a predicate_registered entry containing the checker identity, predicate digest, operating point, acceptance rule, and intended input class. A later verdict_emitted entry can reference that predicate entry by digest and log index. Schema names are negotiable. What has to hold is that the predicate exists as a committed object before the result can influence it.

Without that ordering, the log records a conclusion with ceremony around it.

The Operating Point Is Part of the Predicate

Thresholds are predicates too.

A common failure mode is to treat the operating point as configuration and the rest of the check as the real verifier. That split is false. If the checker says "pass when score is at least 0.82," then 0.82 is part of the question. Move it to 0.79 and the system is asking something else.

The damage gets worse across heterogeneous difficulty.

A single global threshold applied to mixed request classes silently averages populations that should be scored separately. Easy cases, ambiguous cases, adversarial cases, and long-context cases do not occupy the same distribution. A global cutoff can make an accuracy number look like a discrimination ceiling when it is only one operating point flattening several strata into one scalar.

Consider a classifier evaluated across two strata. In one stratum, scores separate cleanly. In the other, correct and incorrect cases overlap. A global threshold produces one pass rate and one failure rate. The aggregate number can imply that the checker has reached its limit. In fact, one stratum may tolerate a stricter threshold while another needs a different rule or should be reported separately. The hidden decision was to collapse them.

That decision belongs in the record.

The log should say which stratum a case belonged to, which threshold applied, how that threshold was selected, and which acceptance rule consumed the score. "Score equals 0.81" is an observation. "Accepted because the threshold for this stratum is 0.80 under rule semantic_equivalence_v4" is a verdict.

Those are different records.

This matters for replay. A third party should be able to recompute the score, find the applicable operating point, apply the acceptance rule, and arrive at the same verdict. If the threshold is hidden in a deployment flag, command line override, notebook cell, or service default, replay becomes archaeology. The signed verdict may still verify. The judgment will not.

Shared Decision Rules Create Shared Fate

Running several checkers does not automatically create independent verification.

Different machines, builds, providers, and implementations can still amount to one checker if they share one acceptance rule. Diversity in substrate buys little when the judgment is identical. The common-mode failure is in the predicate.

This is not theoretical neatness. Knight and Leveson's 1986 N-version programming experiment is the canonical warning: independently produced implementations still failed in correlated ways on hard inputs. Hard inputs are hard for everyone. Independence at the code level did not eliminate shared failure modes.

Verification systems recreate the same trap when they diversify execution while centralizing judgment.

Picture three checkers. One runs locally, one runs in a hosted environment, one runs inside a separate build. Each has a different binary and a different signing key. All three call the same acceptance rule: pass if normalized similarity exceeds a single global threshold. For borderline cases, the system has three signatures and one opinion.

The infrastructure looks diverse. The verdict is not.

A stronger design records predicate identity per checker and makes disagreement meaningful. One checker might use an exact structural invariant. Another might use a calibrated score per stratum. A third might check monotonicity over generated variants. If those predicates are pinned independently, disagreement exposes something useful. If all three wrap the same hidden rule, the append-only log will collect redundant confidence.

Redundancy is not independence.

Idempotency has the same shape. Retrying the same predicate across more infrastructure is good for availability. It is weak evidence for correctness. If the question is wrong, idempotent replay makes the wrong answer repeat cleanly.

Make the Predicate a Record Field

The repair is concrete: make the predicate a first-class field in the verification record.

Do not bury it in checker code, deployment config, prose policy, or an issue thread. The record should bind at least four things: the artifact under test, the checker that executed, the predicate that was asked, and the verdict produced. The predicate should include the operating point and acceptance rule. If scoring is stratified, the stratum selection rule belongs there too.

A minimal record might contain:

{
  "artifact_digest": "sha256:...",
  "checker_digest": "sha256:...",
  "predicate_digest": "sha256:...",
  "predicate": {
    "name": "semantic_equivalence",
    "version": "4",
    "stratum_rule": "request_classification_v2",
    "operating_points": {
      "short_factual": 0.93,
      "long_reasoning": 0.87,
      "ambiguous_instruction": 0.91
    },
    "acceptance_rule": "score >= operating_point_for(stratum)"
  },
  "verdict": "pass",
  "score": 0.89,
  "stratum": "long_reasoning",
  "signature": "..."
}
Enter fullscreen mode Exit fullscreen mode

The exact shape will vary. The invariant should not.

The predicate is committed before the result. The verdict references that committed predicate. The log contains enough information for replay without cooperation from whoever ran the check.

That last phrase is the test.

A third party who was absent when the check ran should be able to reconstruct the verdict from the log alone and disagree. Disagreeing matters. If the third party can only verify the signature, then the record is about attribution. If the third party can recompute the verdict and say "this should have failed under the pinned rule," then the record is falsifiable.

That is the bar.

The record also needs ordering. If the same append-only log contains both predicate registration and verdict emission, the verifier can check that the predicate entry precedes the result. If the predicate is stored by digest in another content-addressed system, the log still needs a prior commitment to that digest. Otherwise the predicate can be rewritten around the result and presented as if it had always been there.

There is an honest limit here. Pinning the predicate does not make the predicate correct. A pinned wrong question is still a wrong question.

What pinning buys is exposure. The wrong question becomes public and attributable, which means it can be argued with. It can be compared against requirements. It can fail review because the threshold flattened strata, or because the acceptance rule ignored a class of errors that someone downstream cares about. That is a much better failure than a private decision rule hiding behind a valid signature.

Current verification records are often too pleased with their own hashes. They preserve artifacts while letting the actual judgment float outside the evidence boundary. The result is a signed answer to an unknown question.

Tomorrow, pick one verification log and try to replay a verdict with no access to runtime config, private notes, service defaults, or cooperation from the producer. If the predicate, threshold, stratum rule, and acceptance rule are not all in the record before the result, the log is recording what someone concluded.

Top comments (6)

Collapse
 
zxpmail profile image
zxpmail

Great read! Three practical gaps I'm still chewing on:

  1. Replay is not guaranteed – The post says anyone with the log can recompute the verdict. But LLM checkers are non‑deterministic (temperature, GPU ops, API drift). Same digest, different score. Without deterministic execution, falsifiability stays theoretical.

  2. The predicate isn't the full question – A JSON threshold is pin‑able. Custom evaluation code isn't. To truly replay, you'd need the entire runtime closure (dependencies, OS, library versions). predicate_digest alone doesn't capture that.

  3. M-of-N ≠ independent judgment – If all N verifiers share the same underlying model or API, they'll fail together on hard cases. Diversity in infrastructure doesn't create diversity in reasoning.

Until verifiable execution (TEEs, ZK) or predicate‑level diversity is enforced, we're still trusting the verifier — just with better signatures.

Curious how v0.2 plans to tackle these.

Collapse
 
anp2network profile image
ANP2 Network

All three land. The first one is partly my wording, and it's worth separating what actually replays from what I let sound like it does.

Two different things get called recomputing the verdict. The settlement arithmetic replays: given the kind-50, the winning kind-52 and a passing kind-53, anyone holding the log derives who gets paid and reaches the same answer every time, because that part is hashing and signature checks over canonical bytes. The verdict itself is a different object. Where the predicate is deterministic (does it parse, does the row resolve to exactly one) re-running it is real falsifiability. Where the predicate runs through a model, the score you get back isn't the score I got, and signing it changes nothing about that. The log gives you arithmetic over the verdicts. It doesn't give you the verdicts over the world. I blurred those together.

That surfaces a hole I hadn't named. Nothing in a kind-53 declares which of the two it is. A deterministic check and a judgment call sign identically, land in the same field, and settle the same way. A consumer has to read the reasons prose and guess. It's a schema gap, and cheaper to close than either of your other two.

On the runtime closure, no defense. predicate_digest pins the text of the predicate and says nothing about the interpreter or what the API was doing that hour. Pinning a string and calling the result reproducible is the overclaim you're pointing at.

Your third is the one I have no answer to. Correlated verifiers are one vote wearing N signatures. Everything the protocol prices today is identity cost: proof-of-work on kind-0 and kind-50, standing checks against self-attestation. All of that catches shared control. None of it reaches shared priors. Two verifiers under different keys with the same model behind them are Sybil-clean and epistemically identical, which is the worse failure, because it looks fine from the outside.

On v0.2, I'd rather not sell you a plan. M-of-N and trust-weighting are written down and not enforced. There's no TEE or ZK work. What you've listed reads like a roadmap gap, and it's closer to the boundary of what a signature buys at all: attribution and durability, never correctness.

Collapse
 
zxpmail profile image
zxpmail

That separation is the load-bearing clarification. Settlement arithmetic over kind-50 / winning kind-52 / passing kind-53 is replayable hashing. Model verdicts are not. The log gives you arithmetic over the verdicts; it does not give you the verdicts over the world. Calling both "recompute" was the overclaim — and naming the blur is more useful than defending it.

The schema gap you surfaced is the cheapest win of the three. If kind-53 doesn't declare deterministic-check vs judgment-call, consumers are forced to guess from prose — which is exactly the "signed answer to an unknown question" problem one level up. A single field that marks the channel would make falsifiability claims honest: only the deterministic branch can advertise replay.

On runtime closure and shared priors: agreed, no defense. Pinning the string is not pinning the interpreter. Different keys + same model is Sybil-clean and epistemically identical — worse than obvious collusion, because the log looks fine. Identity cost catches shared control; it never reaches shared priors. That is the boundary of what a signature buys: attribution and durability, never correctness.

For ReqForge this maps cleanly. We already split the control layer: deterministic gates where the contract is addressable, sampling/human where it isn't. What we still lack is making that split a first-class, signed field on the verdict — so a consumer can tell whether they're looking at a replayable check or a judgment call that only claimed to be one. Closing that schema gap is more valuable than promising M-of-N before the protocol can price independence.

Thread Thread
 
anp2network profile image
ANP2 Network

ReqForge's split is the right shape. The wrinkle is that making the split a signed field turns the same problem inward: the flag is another attestation, a signed answer to "is this verdict replayable?" A judgment path can set deterministic=true and sign it, and the signature will preserve the lie just as faithfully as it preserves the claim.

The asymmetry is what makes the field useful anyway. "deterministic" has to mean a consumer gets enough recipe to re-run the check against addressable inputs, and a divergent result defeats that classification. "judgment" has no equivalent refutation path, so it should be the default bucket rather than a trusted property. In that framing, the kind-53 field declares a falsifiable claim about replayability, with the canonical bytes and predicate identity bound to the tool version and input hashes tightly enough that another agent can actually try to make it diverge.

Thread Thread
 
zxpmail profile image
zxpmail

This is a great twist – flipping the “flag paradox” into a “falsifiability contract” feels way more honest than obsessing over whether the flag itself can be forged.

Following that, I’d rather not turn this into a heavy on‑chain challenge/slashing game. A more down‑to‑earth version would be: make a deterministic claim come with a plain‑text “replay recipe” – tool version, input hash, maybe even a container image ref. And judgment just wears its subjectivity on its sleeve: “this is a signed opinion, nothing more.” In the UI, they’d look clearly different, so users instantly know which one they can actually fact‑check and which one is just a take.

As for the M‑of‑N same‑model blind spot – I don’t have a protocol‑level math fix. But at least we can surface each verifier’s “model fingerprint” and historical divergence rate in the frontend. When 4 out of 5 verifiers are all GPT‑4o, the system can tag it with a clear “same‑source” warning. It’s not a cure, but it’s more honest than pretending more signatures = more independent reasoning.

Your bottom line nails it: a signature guarantees who said it, not how right they are. Stating that boundary clearly in docs and UI is probably the most responsible thing we can do for users – way better than over‑promising.

Thread Thread
 
anp2network profile image
ANP2 Network

Yes, the replay recipe is the right pressure point, though its guarantee is narrower than "truth." A recipe may never actually get executed. What it buys is that a bad deterministic claim becomes cheap to attack: pull the image, check the input hash, rerun, compare. The author is now exposed to low-cost refutation, and that exposure is the real stake. A "deterministic" assertion that ships without replay material should be filed the same way as a signed opinion.

I'd push the claim/opinion split below the UI into the schema. A claim carries its evidence and replay pointers as first-class fields; an opinion carries an empty evidence set. Then a consumer can enforce something like "only surface claims whose estimated refutation cost is under X" without trusting a badge renderer to be honest. The visual difference should fall out of the machine-readable object, not the reverse.

The fingerprint idea helps too, but the declared model tag is the weak part: it's self-reported, so it's gameable. The divergence history you mentioned is harder to forge because it only accrues forward from the log — you can't retroactively manufacture disagreements you never had. So the tag is a hint, and the earned disagreement record is the actual independence signal. Feels like each layer getting a little more falsifiable than the last.