Skip to content

XV-11: approver identity in govder v3 evidence (averin re-derives decided_by and the sign-off set) - #14

Merged
zachyking merged 11 commits into
mainfrom
formal/p3-founder
Oct 11, 2026
Merged

zachyking merged 11 commits into
mainfrom
formal/p3-founder

Conversation

@zachyking

@zachyking zachyking commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Problem

govder signs the authority evidence of a sealed record, and averin's verifier re-derives that evidence from the record's own fields (govder_evidence_rederivable). For an approval record the re-derived field set had no approver in it: who decided (decided_by) and the ordered sign-off set were in the record body but not in the signed evidence_hash, so an offline verifier could not tell what names the signer had committed to (XV-11).

Fix / Proof

  • govder_evidence_rederivable now also derives, for a v3 proof, decided_by (the body string verbatim, when non-empty) and sign_offs_digest (sha256 over the RCP serialization of the body's non-empty sign_offs array, in sealed order). One canonical spelling, shared with govder.
  • Compatibility: a record sealed before this change (body names an approver, signed evidence is the historical field set) stays valid history. It raises no issue; its notes say decided_by and the sign-off set are not committed by the evidence. A record whose signed evidence matches neither spelling is refused. v2 evidence keeps its original field set.
  • New seam vector vectors/approver-evidence.v1.json (owned here, generated by the independent Python reference scripts/vectors/gen_approver_evidence.py, 7 cases including Unicode identities and sign-off order), pinned in vectors/vectors.lock and checked by CI (--check); govder keeps a byte-identical copy.
  • core/tests/approver_evidence.rs builds real v3 records (valid subject digest, valid signature under a pinned key) so only the evidence binding can fail.
  • Claim approver-identity-in-signed-evidence (kit register and legacy register) with three semantic mutants.

Red-first / bite evidence

  • Before the change v3_approval_evidence_rederives_from_the_pinned_vectors and the approver-members test failed (2 of 5 red); after, 5 of 5 pass.
  • Mutants, all killed by the claim detector: xv11-evidence-drops-decided-by, xv11-evidence-drops-sign-offs-digest, xv11-unbound-history-without-note. All 18 fast-tier mutants of the register killed.
  • Four-plane e2e (govder branch formal/p3-founder, this branch as averin_ref): the exported bundle of a real two-approver flow passes the averin-verify integrity check offline and the same bundle with decided_by edited fails (run 38086209561 had failing register and ci-required jobs; the current-head run is 38095180393 and is green; final run recorded in the govder PR).

Gates run

cargo test -p averin-decision-core (all green), make test-core, make test-server, cargo fmt --check, check_claims.py --claims formal/kit-claims.json (273 checks), scripts/check-claims.py, check_vectors_lock.py with peers, fast-tier check_mutants.py. verify_bundle_with was deliberately relocked in three existing claims (only the govder evidence arm changed).

What this does NOT establish

Not that the named subjects are authenticated, humans, in a configured group or distinct (broker and operator posture, XV-10). Not that the approval is recent. Not that a signer committed to the right names: a signer that omits the approver members is accepted as pre-binding history, so the binding holds only for records whose signer includes them. The subject digest already covered the whole body; this adds the evidence commitment the verifier checks by re-derivation.

Merge order

Merge this PR FIRST. A govder that signs the new evidence against an averin without this change makes approval records fail re-derivation. Then vultrino, then govder, then feir-os.

@zachyking
zachyking merged commit 3f6bbe6 into main Oct 11, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant