Skip to content

feat(verification): Add transparent audits - #739

Closed
kotevcode wants to merge 22 commits into
refactor/contracts-domain-architecturefrom
feat/transparent-audits
Closed

feat(verification): Add transparent audits#739
kotevcode wants to merge 22 commits into
refactor/contracts-domain-architecturefrom
feat/transparent-audits

Conversation

@kotevcode

Copy link
Copy Markdown
Contributor

Description

Adds a transparent, publicly recomputable model-audit pipeline across the verifier contracts, Node SDK, fingerprints package, and CLI. Verifiers commit probe sets before sending traffic, anchor seller-signed exchanges before reveal, bind attestations to the anchored batch root, publish evidence packs, and expose antseed audit verify for independent chain-and-pack verification.

This replaces the voucher-based carrier-credit design with chain-discovered accruals and adds production limits, strict configuration validation, hardened opt-in remote pack fetching, and a real Anvil lifecycle test. It supersedes the approach proposed in #720; #720 intentionally remains open for comparison.

Release Notes

  • Add commit → carry → anchor → attest → reveal transparent audits with on-chain seller signature verification and batch-root binding.
  • Add antseed audit verify to independently reconstruct and verify audits from public chain data and optional evidence packs.
  • Add LLM-authored probe generation with certification and compositional/bank fallbacks.
  • Add chain-discovered delegate credits and claim/status commands, replacing off-chain vouchers.
  • Add verification-aware routing and persistent per-peer/model audit enrichment.
  • Harden verifier limits, reveal handling, remote pack downloads, and strict verifier configuration.

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Chore (maintenance tasks, refactoring, or non-functional changes)

Checklist

  • My code follows the code style of this project
  • I have added the necessary documentation
  • I have added tests
  • Typecheck, build, and unit tests pass locally
  • Foundry test suite passes locally
  • CHANGELOG.md includes the user-facing changes

Validation

  • pnpm run typecheck
  • pnpm run build
  • pnpm --filter @antseed/node run test — 824 tests
  • pnpm --recursive --filter '!@antseed/node' run test — all remaining workspace suites, including 362 CLI tests and 65 existing E2E tests
  • forge test — 832 tests
  • pnpm --filter @antseed/e2e run flow:transparent-audit — 3 signed exchanges, 3 attestations, 9 delegate credits, independent verification passed
  • git diff --check

kotevcode added 19 commits July 15, 2026 20:37
…nting

Add an on-chain verifier network that detects model substitution. Whitelisted
verifiers probe sellers advertising the same model, compare response
distributions across the cohort, and attest SAME/DIFF verdicts on-chain backed
by ResponseAuth-signed evidence.

Contracts (packages/contracts/verification/):
- AntseedVerifierRegistry: owner-approved verifier whitelist, probe-set
  commit-reveal, per-audit attestations, per-(agent,service) and per-agent
  verification stats, cooldown-gated per-epoch audit credits.
- AntseedVerifierRewards: emissions-gate bucket controller for
  VERIFICATION_MINTER_ID; verifiers claim each finalized epoch's bucket pro
  rata to credited audits.
- AntseedVerifierPointsPolicy: swappable IAntseedPointsPolicy that discounts a
  DIFF-flagged seller's recognized-usage points (never reverts).

@antseed/fingerprints (new package): KBF verifier math (Clopper-Pearson +
binomial verdicts), cross-seller cohort consensus, deterministic probe bank,
canonical evidence hashing, and a stealth request engine that makes probes
read like organic chat with free-text answer extraction.

@antseed/node: verifier contract clients, per-(peer,model) verification
reputation scoring surfaced on PeerInfo during discovery, getResponseAuth
accessor, chain-config + payments wiring.

@antseed/cli: antseed verifier start|status|claim daemon and a verifier
config section.

Stacked on the recognized-usage emissions stack.
Add a ProbeSource abstraction with a large compositional
entity/attribute generator as the default probe origin, demoting the
static bank to a test fixture. Deterministic randomness now uses
RFC 5869 HKDF-SHA256 seed derivation, an SP 800-90A HMAC_DRBG stream,
rejection sampling, and Fisher-Yates; canonical JSON hashing is
documented against RFC 8785 (JCS). Stealth framings gain task-shaped
variants to widen the request silhouette.
The daemon now auto-discovers every advertised service from one
wildcard buyer discovery per round when verifier.services is empty,
rotates revealed probes via a per-service log, and tracks the epoch
audit budget across services. New `antseed verifier reference build`
enrolls certified KBF references through a trusted OpenAI-compatible
upstream (consistency filtering across temperatures + hold-out
self-test, per arXiv:2605.29524); with verifier.upstream configured
the daemon enrolls automatically and audits referenced services down
to a single seller. Spec 07 gains research grounding and standards
citations.
A single approved verifier's DIFF attestation permanently zeroed a
seller's usage emissions: diffCount is monotonic and the policy gated
on diffCount > 0 with no clearing path, while the buyer-side routing
score already required two distinct verifiers. The registry now tracks
activeDiffVerifierCount — distinct verifiers whose latest verdict is
DIFF, retractable by the same verifier re-attesting SAME on the same
service, with agent-level standing held while ANY service carries the
DIFF so an honestly served second model cannot launder a substituted
one. The points policy gates on an owner-configurable
minDistinctDiffVerifiers (default 2).
Verifiers announce a probe-delegation capability on the DHT and
dispatch verifier-crafted probe jobs to opt-in buyers, who relay
them verbatim over their paid buyer path so probe traffic is
indistinguishable from organic usage. The verifier re-verifies
each seller-signed ResponseAuth itself, and carriers earn a
delegateShareBps cut of the verification emissions bucket via
creditDelegates/claimDelegateReward at their operator address.
The delegate payout address is now always the operator registered
for the buyer in AntseedDeposits: the buyer daemon resolves it
on-chain (config payoutAddress is only a cross-check), and the
verifier verifies the binding before accepting a delegate
registration, which also filters sybils without a funded,
operator-bound deposit account.
Move delegation muxes, the delegate roster, hello/operator-binding
validation, and job dispatch/serving out of node.ts into
verification/delegation-manager.ts. AntseedNode keeps only
connection lifecycle wiring and thin API forwarders.
Replace verifier-submitted creditDelegates with EIP-712
DelegateVouchers claimed by the buyer's deposits operator. The
contract now enforces the operator binding at claim time and caps
voucher credits per probe commitment at the probeCount of credited
attestations, anchoring grants to real commit-reveal audit work.
Contracts: points-policy survives permissive-fallback staking targets
(raw staticcall + returndata checks), rewards freeze epoch credit totals
alongside budget/split, deploy script asserts registry wiring and warns
on controller-flip stranding, submitAttestation documents the
whitelist-trust model, and de-whitelist/controller-flip behaviors are
pinned by tests.

Fingerprints: probe commitments bind full probe content (not just ids),
nonce derivation folds a hash of the exclude set (no reuse across
rotations, no hkdf info-size limit), the free-text extractor handles
decimals, list ordinals, preamble numerals, and predicate cues, cohort
consensus dedupes seller identities and scores support against the
emitted median, match vectors are validated at the API boundary, and
ambiguous dataset entries are replaced.

Node: routing excludes sellers with an active (unretracted) DIFF flag
and scores honor activeDiffVerifierCount, findPeer and background
discovery get verification enrichment, DelegationManager fails closed
until an accepted welcome and enforces delegate/concurrency caps, the
delegation codec validates sizes and voucher shapes on both sides, and
delegation hosts announce their capability DHT topic.

CLI: hard per-epoch attempt caps with per-seller backoff, minProbeCount
enforced before spend, rotation-pool recycling, round-level RPC retry
with backoff, credited-vs-submitted attestation accounting, strict
config/flag validation, --api-key precedence, reference hold-out quality
gate, per-seller failure isolation in delegated probing, offline
re-verifiable evidence bundles, safe service slugs, official bootstrap
merging, delegate worker revocation/abort/stop/schema enforcement, and
durable voucher persistence.
Contracts: voucher replay guard keyed by recovered signer (two verifiers
signing identical fields no longer collide), owner-only
clearVerifierStanding to retract a rogue de-whitelisted verifier's
standing DIFF, and corrected late-credit natspec that overstated the
frozen-claim-set guarantee.

Fingerprints: nonce derivation binds service/count/source/domains so
sibling artifacts from one seed keep independent blinding, positional
extraction prefers the last window and suppresses question echoes,
same-entity probes never share a request chunk, canonical JSON rejects
sparse arrays, evidence schema declares exchanges/fullyAuthenticated,
and ambiguous dataset entries are replaced with verified facts.

Node: delegate voucher signatures normalize to canonical 65-byte form
(compact EIP-2098 signatures passed every off-chain check but reverted
on-chain), a dropped connection during delegate registration no longer
crashes the process with an unhandled rejection, welcome acceptance
flips synchronously so a coalesced voucher is not dropped, and the
voucherClaimed client mirrors the new two-arg ABI.

CLI: reference enrollment sends the advertised model spelling upstream,
new `antseed delegate vouchers|claim` commands let operators actually
claim voucher credits before they expire, reward claiming is fault
isolated per epoch across status/start/claim, the delegate job schema
allowlists body fields (n, best_of, max_completion_tokens can no longer
multiply paid output), and stop() is re-checked after the approval await.

Buyer proxy: pinned peers carrying an active substitution flag are
refused (/v1/models stays exempt) and verification stats persist across
restarts. Spec 07 documents the delegation protocol, the delegate
reward split, the stealth request construction, and the evidence hash.
Routing: hasModelSubstitutionFlag now keys solely on the on-chain
activeDiffVerifierCount, so owner clearVerifierStanding lifts the
buyer-side routing block (DefaultRouter and the CLI 502 gate) in lockstep
with the on-chain points penalty — the lastVerdict fallback was
unreachable via RPC and kept a cleared seller blocked forever.

CLI: persisted modelVerification carries a freshness stamp and expires
after 30 minutes, so a stale DIFF flag can no longer block a
retracted-accuser peer indefinitely while enrichment is degraded;
delegated probes now relay a sized max_tokens bound and the delegate
worker rejects budget-less jobs; the /v1/models substitution-gate
exemption is scoped to GET on the exact path.

Fingerprints: element_bp drops carbon and arsenic (which sublime at 1 atm
and have no well-defined boiling point), matching the round-2 melting-
point fix, replaced with neodymium and gadolinium.

Docs: spec 07 corrects the delegate maxConcurrentJobs default (2) and the
KBF package file listing.
@AntSeed AntSeed deleted a comment from claude Bot Jul 16, 2026
@kotevcode

Copy link
Copy Markdown
Contributor Author

@claude

@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown

Claude finished @kotevcode's task in 6m 33s —— View job


Review complete

The trigger comment was just @claude with no specific ask, so I ran a full code review of this PR (146 files changed vs. origin/refactor/contracts-domain-architecture, ~30k additions) across contracts, CLI verifier/delegate, node SDK verification, and the new fingerprints package.

Todo list

  • Gather context (PR diff, changed files, CLAUDE.md)
  • Review contracts (packages/contracts/verification/**)
  • Review CLI verifier/delegate/audit code
  • Review fingerprints package
  • Review node SDK verification + CLI proxy/config changes
  • Post review findings

Overall this is a well-engineered, thoroughly-tested PR — signature verification, EIP-712 handling, reentrancy guards, reward accounting, and routing/gating logic are all careful and adversarially tested. A few concrete gaps surfaced:

Medium

  1. packages/contracts/verification/AntseedVerifierRegistry.sol:826 (computeBatchRoot) — the Merkle leaf is keccak256(agentId, requestHash, responseHash, keccak(sig)) and does not include the per-record probeCount. That value is only range-checked (1..3), never bound to the anchored batch data, yet it directly drives commitmentDelegateBudget and epoch reward credits. A whitelisted verifier can always declare the max probe count regardless of truth and inflate its own/delegates' reward share — this is only detectable after revealProbeSet, by which point the reward epoch may already be claimed. Fix this →

  2. apps/cli/src/verifier/audit-verify.ts:362-372, 470-475 — in verifyAudit(), an exchange with no responseAuth at all is silently skipped (only exchanges with a responseAuth that fails get flagged). A seller whose exchanges are entirely unsigned/unanchored can produce ok: true whenever verifyAudit() is called without attestations. In practice antseed audit verify is safe because verify.ts always fetches on-chain attestations when a pack is supplied, but that protection lives in the CLI wrapper, not in the exported verifyAudit() itself — which the docstring describes as trusting nothing. Untested edge case (no test for "exchanges with no responseAuth + no attestations"). Fix this →

  3. packages/node/src/verification/delegation-manager.ts:98-111 (roster-full rejection) and the teardown() paths at lines 286-291/309-314 — the doc comment claims a rejected delegate's "channel is torn down," but only mux.close() is called, which rejects DelegationMux's own pending-promise maps and never closes the underlying PeerConnection. The transport socket stays open, so DEFAULT_MAX_DELEGATES (64) bounds the registered roster but not the number of live connections an attacker can hold open against the delegation host — weakening the intended resource-exhaustion mitigation. Fix this →

  4. packages/fingerprints/src/verifiers/kbf/index.ts:40-63 (KbfVerifier.verify) — accesses reference.probes.length before the reference.kind !== this.kind shape check, so a malformed/corrupted FingerprintReference (e.g. from a persisted evidence file) throws a TypeError instead of returning UNKNOWN. The fallback unknown(reason) path itself dereferences reference.selfTest.hamming/.total (lines 121-131), so even the mismatched-kind error path can crash if selfTest is missing. Untested crash path — existing tests always supply well-formed input. Fix this →

Low / nit

  • packages/contracts/emissions/AntseedEmissionsGate.sol:324 (_removeMinter) — intentionally no longer clears controllerMinterIds[existing.controller] (a real, tested fix for stranded in-flight-epoch rewards). Side effect: that controller is now permanently pinned to the removed minter id and can't be reassigned to a different minter id without first re-pointing the original id elsewhere. Operational footgun worth a comment/doc note, not a fund-loss bug.
  • apps/cli/src/verifier/audit-runner.ts:403-435, 349-366 (pending-reveals.json, burned-references.json) — unlocked load-then-write, unlike credit-store.ts which serializes writes explicitly. Currently safe because the round loop processes services sequentially, but would silently drop a queued reveal/marker if audits are ever parallelized per-service or two verifier daemons share a data directory.
  • packages/contracts/verification/AntseedVerifierRegistry.sol — request-hash dedup is only per-verifier; nothing globally prevents two colluding whitelisted verifiers from each anchoring the same seller-signed exchange to double-count delegate credit for one real probe. Requires owner-whitelist collusion, so low likelihood.
  • apps/cli/src/config/validation.tsmaxConcurrentJobs/maxJobsPerHour/maxAuditsPerEpoch only enforce a lower bound (>= 1), no upper ceiling at config-validation time. Not remotely exploitable (self-configured, and delegate/worker.ts has its own hard-coded ceilings as a second layer), but worth a sanity ceiling for config typos.

Confirmed solid (no issues found)

  • EIP-712 signing, ECDSA.tryRecover usage, reentrancy guards, and commit→anchor→attest→reveal ordering in the verification contracts are correctly enforced and adversarially tested (AntseedVerifierAnchoring.t.sol, fuzz suite).
  • Delegate credit cursor math, double-claim prevention (on-chain authoritative), and delegate/worker.ts lifecycle (fail-closed shutdown, TOCTOU re-check, TTL-based approval revocation, strict allowlists, size caps).
  • pack-writer.ts path-traversal protection and atomic writes; audit/verify.ts remote pack fetch SSRF hardening (HTTPS-only, private-IP blocklist via node:net.BlockList, DNS-pinned connect, size cap, timeout).
  • delegation-codec.ts input validation (exhaustive shape checks, size cap before JSON.parse, no prototype-pollution vector) and delegation-mux.ts per-peer isolation.
  • canonical-json.ts (correct JCS-style canonicalization) and prng.ts (proper HKDF-SHA256/HMAC_DRBG, rejection sampling, no modulo bias) in the new fingerprints package — unusually well-engineered with rationale comments for edge-case decisions.
  • Buyer-proxy substitution-flag routing gate (buyer-proxy.ts:1341) correctly scopes the control-plane exemption and doesn't skip the gate on the pinned-peer path; config validation has no inverted conditions; no secrets logged.

No changes were made — this was review-only as requested. Let me know if you'd like me to implement any of the fixes above.

Exempt legitimately un-attested sellers from audit-verify MISMATCH,
resolve anchor verifiers from the event topic, chunk delegate credit
discovery, age out stale substitution flags in SDK routing, cap the
router's body parse, debounce hot-path peer persistence, and fix
length-changing lowercase offsets in stealth answer extraction.
Key delegate accrual and budgets by the audited (agentId, serviceHash)
so a credited attestation only backs its own carriers, and add a global
anchored-exchange registry so a seller-signed exchange anchors at most
once network-wide. Updates the TS client, CLI claim flow, spec, and the
audit e2e (also rewired to the renamed fetchMatchingAttestations).
Dedupe agent-owner/stats/claim scaffolding in the verifier contracts
and drop derivable anchor storage; consolidate the substitution-flag
gate, service extraction, and audit-verify chain fetchers into
@antseed/node; parallelize delegate scans and carrier probing; remove
dead fields, wrappers, and exports across node and cli.
@kotevcode
kotevcode force-pushed the refactor/contracts-domain-architecture branch 2 times, most recently from ad08d75 to feef079 Compare July 26, 2026 09:09
@alexanderludwig

Copy link
Copy Markdown
Collaborator

Superseded by #969, which implements the revised KBF verification architecture on top of the corrected contracts-update-all foundation. The replacement uses the consolidated AntseedVerification contract, corroborated verification penalties, shadow-mode policy activation, and the updated fingerprints, Node, and CLI workflows. Closing this PR so the active stack remains #968 as the shared contract foundation, with #895 and #969 as independent sibling feature PRs.

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.

2 participants