Releases: ValiChord/ValiChord
Release list
v0.6.5 — Holochain 0.7, and the protocol work that rode the hash break
v0.6.5 — Holochain 0.7, and the protocol work that rode the hash break
The migration to the Holochain 0.7.0 toolchain (hdi 0.8.0 / hdk 0.7.0), merged to main on 2026-08-03 after being developed in isolation on a v0.7.0 branch. main was deliberately kept on the working, publicly-demoed 0.6.2 stack until the branch was fully green.
⚠️ Breaking — read before upgrading
- DNA hashes changed. Zome-definition serialization differs in 0.7, so an otherwise-identical DNA hashes differently. Holochain 0.7 agents form a network separate from 0.6 agents.
- Every previously published HarmonyRecord URL dies. This was accepted deliberately rather than worked around; the alternative (a
close_chain/open_chainmigration) carries an agent's own source chain, not the DHT, so it would not have saved a single published record. Prior art assessed indocs/DNA_MIGRATION_PRIOR_ART.md. - Conductor state must be cleared. Persistence moved to
holochain_datawith no migration path. Demo nodes needdocker compose -f demo/docker-compose.yml down -v, not just a binary swap. - Toolchain pins move to
holochain/holochain_cli0.7.0 andkitsune2_bootstrap_srv0.5.0.
Protocol work that shipped on top of the migration
Changes that needed a DNA-hash break were deliberately batched into this one rather than buying a second break later.
- Validator→bundle binding — a validator may set
reproduction_bundle_hash, thecontent_hashof their ownvalichord_attestationbundle. It is inside the hashed struct, so it is sealed into the commitment automatically: a verdict becomes a claim about a specific set of per-sample outputs rather than the bare word "Reproduced". Optional, andNoneis a legitimate permanent state — an unbound verdict, not a missing one. - The honest record —
validators_requestednow sits beside the participant list, so a round that closed early reads "3 of 7" rather than silently "3". The denominator is part of the permanent record. Scoping, including the two arguments against doing it, is indocs/HONEST_RECORD_SCOPING.md. - HarmonyRecord undercount fix — participation could be understated permanently, and the count feeds the badge tier. A HarmonyRecord is immutable, so a wrong tier was wrong forever.
- The liveness gate — force-finalisation now refuses while a validator still holds a live claim. Age alone is not evidence of abandonment.
DataLocalityMode(Gdpr|OpenAudit) groundwork, plus theLockedResultdelete guard that had been missing entirely.
Testing
- The Tryorama suite was retired, not migrated (92 TypeScript tests). Upstream
@holochain/tryoramais unmaintained — a banner landed in Jan 2026 saying Holochain 0.7+ support "should not be expected", pointing at sweettest. Porting to a dead runner would have been work with a known expiry date. - It was audited one test at a time before deletion. ~69 were already duplicated in sweettest; every unique test was ported and run green first. That audit found three guards with no working coverage at all — the conflict-of-interest rule, DNA 2's cross-agent privacy, and
link_agent_identity's two signature checks — each now covered by a test that has been seen to fail. - The immutability tripwires are no longer branch-scoped. They were gated to the
v0.7.0branch, which would have silently stopped them the moment that branch merged — removing the only proof that the integrity zomes still reject forbidden updates and deletes. They now run everywhere. - A negative control was run for the governance delete guards: deleting the
GovernanceDecisionarm made a forbidden delete succeed with a realActionHash. The test failed as designed; restoring the arm turned it green. - 150 automated tests, none skipped — 114 sweettest (including the 15 immutability tripwires and 5 real-Ed25519 membrane-proof tests), 30 Rust unit, 6 Playwright browser e2e.
Frontend and tooling
- Svelte UI on
@holochain/client0.21.0 — 6/6 Playwright e2e green against a real 0.7 conductor. - Wind-tunnel builds on 0.7 again. The merge broke it in a way the "blocked upstream" note had hidden: the scenarios depend on
valichord_shared_typesby path, so moving that crate tohdi 0.8.0collided with the crates.io runner's Holochain 0.6. Fixed properly by pinning the runner to a git rev of upstream's own "Update to Holochain 0.7.0" commit; the CI job is re-enabled rather than muted.
Documentation corrections
The README described the 0.6.2 stack and carried instructions that had been dead since the Tryorama retirement — cd tests && npm test pointed at a deleted directory. Also corrected: three numbers, all re-measured rather than remembered (valichord_attestation is 487 tests, not 537; six adapters, not five — WandbRunAdapter was undocumented; the 97% coverage figure was right).
🔴 Known limitation — the live demos are not this build
Oracle still runs Holochain 0.6.2. main and the public demos at valichord-demo.onrender.com therefore describe different stacks until Oracle is rebuilt. That rebuild is a full rebuild with state loss and is the next deployment task. The README now says so in place.
Verification
CI run 30819563258 on bc3ed82b was 10/10 green across every job — sweettest matrix, unit, Playwright e2e, immutability tripwires, and the dependency-free supply-chain guard that checks the committed bundles contain no test-only hooks. A full demo round was also run end-to-end on the merged DNA. Only markdown changed between that commit and this tag.
v0.6.1 — Coordinator auto-updater + live-ops hardening
v0.6.1 — Coordinator auto-updater + live-ops hardening
Still on the Holochain 0.6.2 toolchain — no DNA-hash or protocol change. This release is about operating the live demo safely and keeping the always-on Oracle nodes current without downtime.
Coordinator auto-updater (new)
A checksum-verified way to roll coordinator-zome fixes onto the live Oracle nodes with zero DNA-hash change, so published HarmonyRecord URLs survive. Opt-in and default-OFF — nothing changes until a deployment sets AUTOUPDATE=on.
demo/pack-coordinators.mjs— packs the coordinator WASMs and emits acoordinators-manifest.jsonwith a monotonic revision, a pinned conductor version, and a sha256 over each raw WASM.demo/coordinator-autoupdate.mjs— a poller that, on a newer revision, downloads each WASM and sha256-verifies it before applying anything (any mismatch aborts), guards the manifest's Holochain version against the running conductor, appliesUpdateCoordinatorsper cell, asserts the DNA hash is unchanged, runs a read-only verify call, and records the applied revision on the persisted volume. Modes: loop /--once/--check. Non-fatal in loop mode.- Rollback safety valve —
AUTOUPDATE_MAX_REVISIONpin ceiling holds the fleet at a known-good revision; revert by rolling forward (immutable releases). demo/publish-coordinators.sh— publishes the manifest + WASMs as an immutable GitHub release and prints theAUTOUPDATE_MANIFEST_URL.demo/rehearse-autoupdate.sh— self-cleaning end-to-end rehearsal against a throwaway conductor. Ran green: applies to all four cells, DNA-hash assertion holds on each, verify OK, marker advances.- Plan + full detail:
docs/AUTO_UPDATER_SIDECAR_PLAN.md.
Live-ops hardening
- First live coordinator hot-swap on Oracle (
demo/hotswap-coordinators.mjs) — rolled the local-read change onto all four nodes viaUpdateCoordinators, zero downtime, HarmonyRecord URLs preserved. - Self-authored lookups now read locally (
GetStrategy::Local) in the attestation coordinator — avoids cold-cell DHT-walk stalls; quorum/other-agent reads stayNetwork. - Decentralised demo rebuilt on a new Oracle server (Ampere A1 / ARM) after the previous free-tier VM was reclaimed;
Dockerfile.nodenow arch-detects and fetches the right binaries.
UI end-to-end tests
- Playwright e2e suite against a real conductor for
valichord-ui, plus a CI job. - Fixed a production bug it caught: a
patternattribute on the data-hash input silently blocked every request submission.
Docs & site
- GitHub Pages refresh (live-demo wiring, logo, ownership repoint), a forward-looking sharding impact/migration design note, and the Holochain 0.7.0 release-candidate watch note (we hold on 0.6.2 until 0.7.0 is stable).
Full changelog: v0.6.0...v0.6.1
Coordinator revision 1 (holochain 0.6.2)
Coordinator auto-updater bundle, revision 1, built against holochain 0.6.2. Consumed by demo/coordinator-autoupdate.mjs (see docs/AUTO_UPDATER_SIDECAR_PLAN.md).
v0.6.0 — Commit-reveal verification enforced on-chain + Holochain 0.6.2
First release since v0.5.4 (2026-05-24) — 194 commits across the protocol, the attestation library, the demo stack, and testing infrastructure.
Versioning note: v0.5.5–v0.5.7 were used as internal milestone labels in project docs but never tagged; GitHub releases jump from v0.5.4 directly to v0.6.0. The minor bump reflects protocol-level changes below (including a DNA hash change).
Core protocol (valichord/)
- Commit-reveal hash verification enforced on-chain for real nonces.
submit_attestation's verification bypass is narrowed from "credential issuer empty" to "issuer empty AND nonce empty", mirroringreveal_researcher_result. A validator's revealed verdict is now checked against their sealed commitment even on dev-mode networks whenever a real nonce is used — a tampered reveal is rejected with a hash mismatch. Proven by two new security sweettests: S7 (genuine seal → nonce → reveal flow passes verification) and S8 (verdict altered between sealing and reveal is rejected). Empty-nonce test flows are unaffected. - StudyClaim immutability. Integrity-zome guards now block updates and deletes on
StudyClaim— claims are vacated viaStudyClaimRelease, as the architecture doc always stated.⚠️ This is an integrity change: the attestation DNA hash has changed (dev-only impact; existing dev conductors must reinstall the hApp). - DeliberateAbstention entry type (validator_workspace) — a validator can cryptographically record a reasoned recusal as a first-class, immutable private entry, distinct from simply never showing up. With duplicate-guard, link index, and 3 sweettests.
- Reveal-phase quorum gate counts distinct validators (was raw reading count).
- Holochain 0.6.2 — hdk 0.6.2, hdi 0.7.2, holochain/holo_hash/keystore 0.6.2 across all zomes; hApp repacked; CI binaries bumped.
Attestation library (valichord_attestation)
LmEvalAdapter— converts lm-evaluation-harnessresults_*.json(+ optionalsamples_*.json) into canonical attestation bundles. Covers the de-facto industry standard for LLM benchmarking. 51 tests.AiluminateAdapter— converts MLCommons AILuminate (modelbench) safety-benchmark reports, committing model responses and grader-ensemble verdicts together as Merkle leaves — blind independent verification for LLM-as-judge grading. 42 tests.prml_lock_hashfield — links a bundle to a Falsify/PRML pre-registration lock, plus canonicalization edge-case tests.- Library now at 537 tests, 97% line coverage, five adapters total (InspectAI, InspectEvals, PiSession, LmEval, AILuminate).
Interoperability
- OETP bridge — embed a ValiChord HarmonyRecord into an Open Ethics Transparency Protocol disclosure (IETF Internet-Draft JSON standard);
--emit-oetpflag on the demo runner. 28 tests. - EveryEvalEver worked example — offline bundle generator for the EEE convergence path.
Demo & operations
- Security sweep: visitor API keys scrubbed from job state on completion + 1 h TTL eviction; agent-env cache keyed by key hash and size-capped; opt-in node-API write authentication (
NODE_API_KEY, timing-safe); memory caps on node-side maps; constant-time API-key comparison in the backend; CI action pinned to SHA. - Honest reveal-verification copy on the demo website — the site now states precisely what the demo network enforces versus what production networks enforce.
- CMA performance: one shared agent environment per run, session timeout, and tool-call cap.
- Claim-vocabulary headline for custom-claim results; node URLs default to localhost.
Project & governance
CONTRIBUTING.md(contributor guide + lightweight CLA),NOTICE, andTRADEMARK.md— open-core IP structure established.- EU AI Act Article 12 compliance plan — ValiChord as evaluation-layer evidence infrastructure.
Testing & infrastructure
- Wind-Tunnel: runner bumped to 0.7.0; two new propagation scenarios (
dht_sync_lag, Kitsune substrate prototype); first live multi-conductor run — median cross-DHT sync lag ≈ 185 ms; CI smoke job. - Badge sweettest hardening: gold, silver, and bronze badge tests now use a re-sync + re-query retry loop against the documented badge-index gossip-lag flake; full CI matrix green (97 Tryorama + 5 sweettest suites).
- Dev conductor lifetime tied to
dev.sh(setpriv --pdeathsig);@holochain/clientfloor at 0.20.5.
Full changelog: v0.5.4...v0.6.0
Addendum (2026-07-06, same day): UI e2e suite + form-blocking bug fix
- Playwright e2e suite for the browser UI (
valichord-ui/tests/e2e/) — one real throwaway conductor per run, no mocks: connection bootstrap, validator profile via the UI form, request submission via the researcher form, pending-request rendering, zome-seeded data, governance view. Runs locally vianpm run test:e2e(~1.3 min) and in CI as a new independentui-e2ejob (~2 min, traces uploaded on failure). Pattern ported from happenings-community/requests-and-offers. - Fixed: the researcher form's Submit button silently did nothing. Svelte parses
{64}inside a quoted attribute as a template expression, sopattern="[0-9a-f]{64}"rendered aspattern="[0-9a-f]64"— native form validation rejected every real 64-character hash with no visible error. Caught by the e2e suite on its first run. - README refreshed: repo links updated to the ValiChord org, current Your Hypothesis demo described, test counts corrected (183 across three suites), Holochain 0.6.2 quickstart, five attestation adapters.
Addendum (2026-07-08, post-tag — commits 7e8b2e6 + a2593d0 on main): local-read rule + first live coordinator hot-swap
- Self-authored lookups now read locally (attestation coordinator).
release_claim,get_my_claimed_studies, and the duplicate-commitment guard innotify_commitment_sealeduseGetStrategy::Localfor reads whose results are entirely the calling agent's own writes — the source chain is complete by construction, so a network walk adds nothing except a hang risk on a fresh or cold cell. Everything that can include other agents' writes (reveal-quorum counts, reclaimer-written releases, protocol guards) still reads from the network. This is a reliability fix, not a speed-up: typical demo-run time is unchanged; what's eliminated is a class of cold-node stalls and timeouts, plus snappier claimed-studies views in the browser UI. Pattern borrowed from flowsta-signing-dna v1.4. Verified by the four sweettests covering the changed functions plus the full CI matrix. - First live coordinator hot-swap. Because the change touches no integrity zome, it was rolled onto all four live Oracle demo nodes via
AdminRequest::UpdateCoordinators— zero downtime, DNA hashes unchanged, no container restarts, every published HarmonyRecord URL preserved. The rollout tooling ships asdemo/hotswap-coordinators.mjs(local rehearsal mode + per-container runbook in the header), establishing a minutes-not-hours upgrade path for future coordinator-level fixes to the live network.
v0.5.4 — Security hardening and audit sweep
Security hardening
Warrant gate coverage
Four coordinator entry points that previously allowed warranted (banned) agents to write state have been closed:
submit_validation_request— warranted agents could spam fake study submissionspublish_validator_profile— warranted agents could create/update validator profilesassess_difficulty— warranted agents could manipulate difficulty assessmentslink_agent_identity— warranted agents could inject cross-device identity links
All four now call reject_if_warranted(&agent)? at the start of the handler, consistent with the existing pattern on notify_commitment_sealed, submit_attestation, and claim_study.
Integrity validation gaps closed
Two entry types had no validate() coverage and are now guarded at the integrity zome level:
ResearcherResultCommitment—result_commitment_hashmust be exactly 32 bytes (SHA-256). A malformed hash would permanently block the researcher's reveal with no visible error.HarmonyRecord—validator_types(position-parallel toparticipating_validators) must be empty or the same length. A length mismatch causes out-of-bounds panics in UI lookups. The field is#[serde(default)]for backwards compatibility with pre-existing records.
TypeScript serde fix
BadgeType in valichord-ui/src/lib/types.ts used the wrong string names ("Gold", "Silver", "Bronze", "Failed"). The Rust enum serialises to "GoldReproducible", "SilverReproducible", "BronzeReproducible", "FailedReproduction". Fixed — get_badges_by_type calls from the UI now match DHT records.
Earlier fixes (since v0.5.3)
- Badge issuance hardening — atomic check before writing
HarmonyRecord;BadgeTypeimported fromvalichord_shared_types, not re-declared in governance - Claim release authorisation — only the original claimant or study submitter may release a claim
- Warrant filter in governance —
get_all_validatorsno longer surfaces warranted agents - Cross-DNA error handling —
call_attestation_zome_optpropagatesWasmErrorcorrectly instead of swallowing internal failures - Timeout cast safety —
reclaim_abandoned_claimtimeout comparison uses saturating arithmetic
Test coverage
New sweettest tests (attestation DNA — tests 16–20):
| # | Test | What it covers |
|---|---|---|
| 16 | update_validator_profile_merges_fields |
Supplied Some fields overwrite; None fields preserved |
| 17 | check_all_commitments_sealed_lifecycle |
Returns false before quorum, true after both validators commit |
| 18 | get_researcher_reveal_none_then_some |
Returns None before reveal, Some(Record) after |
| 19 | revoke_agent_identity_link_removes_from_linked_agents |
Deleted entry filtered from get_linked_agents |
| 20 | get_my_claimed_studies_filtered_by_release |
Released claim excluded from Vec<Record> result |
New sweettest test (governance DNA — test 17): get_pending_request_refs returns studies for both ComputationalBiology and Discipline::Other("custom") disciplines; force_finalize_round succeeds end-to-end for Discipline::Other.
Total sweettest coverage: 20 attestation + 17 governance tests.
v0.5.3 — Live web demo + valichord_attestation v1.2.0
Live web demo
valichord-demo.onrender.com/demo
One-click browser interface to the full ValiChord commit-reveal protocol. Click Run Protocol and watch the live Holochain network on Oracle Cloud run a real reproducibility validation — researcher and three independent Claude Haiku validators committing blind, then revealing simultaneously. Takes ~2 minutes because that is real network time, not a timer.
At the end of each run the page shows a curl command to fetch the HarmonyRecord directly from the Oracle DHT — confirming the result was written by the Holochain network, not generated by the web page.
See demo/DEMO_WEBSITE.md for the full technical guide (Flask architecture, request flow, concurrency design, Render deployment).
valichord_attestation v1.2.0
PiSessionAdapter — new adapter for pi coding agent session v3 JSONL files. Resolves the active branch via parentId walk, applies compaction filtering, extracts 8 metrics (turns, tool calls, error rate, tokens, cost, compaction count, stop reason), and builds a full Merkle tree over all branch entries. 67 tests.
ValiChordLogger for lm-evaluation-harness — optional logger following the wandb/trackio pattern. Hooks into post_init → log_eval_samples, builds a valichord_attestation bundle (Merkle tree over per-sample filtered_resps, stable SHA-256 commitment via RFC 8785), and saves it alongside the results_*.json artifact. Wired via --valichord_args output_path=./results CLI flag. See topeuph-ai/lm-evaluation-harness.
Format v1.2 (carried from v0.5.21): Metric.filter field for multi-filter tasks; Bundle.meta provenance block; dual bundle_hash / content_hash. All v1.0 and v1.1 bundles remain valid.
326 tests, 99% line coverage.
falsify/PRML integration
valichord_attestation is now cited in falsify-cookbook Pattern 13 (PRML + commit-reveal validation, co-authored with Cüneyt Öztürk / Studio 11) and in the falsify v0.3 spec backlog as a prior-art precedent for bundle-side count commitment (samples_total → leaves_total analogy).
Other changes since v0.5.21
- Holochain 0.6.1 upgrade complete (iroh/QUIC transport;
kitsune2-bootstrap-srv 0.4.1) - Svelte 5 UI wired end-to-end to live conductor; all three protocol roles functional
- Governance badge idempotency fix —
issue_badge_if_missing()now retries from the idempotency return path - Full test suite: 96 Tryorama tests pass (1 skipped — WebSocket exhaustion in Codespaces), 47 sweettest tests pass
v0.5.21 — InspectAILogAdapter + eval_yaml_metadata enrichment + attestation skill
What's new since v0.5.2
InspectAILogAdapter — direct inspect_ai log file support
New adapter that reads inspect_ai `.eval` / `.json` log files directly via the inspect_ai Python API, with no pre-parsing step.
Field mapping:
- `EvalSpec.model` → `model_id`
- `EvalSpec.task` → `task_id`
- `EvalSpec.created` → `generated_at`
- `EvalSpec.revision.commit` → `repo_commit` (auto-extracted)
- `EvalResults.scores` → `metrics` (all scorers combined; scorer-name prefix on key collision)
- `EvalLog.samples` → `outputs_merkle_root` (per-sample dicts: id, epoch, output, scores)
`inspect_ai` is an optional dependency — pass a pre-loaded duck-type to avoid the import. Use `score_name=` to restrict to a single scorer. Use `meta_extras=` to merge extra provenance into `Bundle.meta`.
from valichord_attestation import InspectAILogAdapter
adapter = InspectAILogAdapter()
bundle = adapter.to_bundle("logs/my_eval.eval")InspectEvalsAdapter — eval.yaml metadata enrichment
New optional `eval_yaml_metadata=` parameter on `InspectEvalsAdapter.to_bundle()`. Pass the top-level `eval.yaml` dict (not the `evaluation_report` block) to fold task-level provenance into `Bundle.meta`:
| eval.yaml field | Bundle.meta key |
|---|---|
| `arxiv` | `paper_arxiv` |
| `group` | `eval_group` |
| `version` | `task_version` |
| `tasks[*].human_baseline` | `human_baseline` |
| `external_assets[*].state: floating` | `dataset_reproducibility_warning` |
| `metadata.requires_internet` | `requires_internet` |
These fields are excluded from `content_hash` (as all meta fields are), so they do not affect scientific equivalence comparison between runs.
import yaml
from valichord_attestation import InspectEvalsAdapter
with open("src/gpqa/eval.yaml") as f:
full_yaml = yaml.safe_load(f)
eval_report_block = full_yaml.pop("evaluation_report")
bundle = InspectEvalsAdapter().to_bundle(
eval_report_block,
samples,
eval_yaml_metadata=full_yaml,
)generate-attestation-bundle Claude Code skill
New project-local skill at `.claude/skills/generate-attestation-bundle/`. Step-by-step workflow for adding attestation as the final step after an inspect_evals eval report — covers both the `InspectAILogAdapter` (file path) and `InspectEvalsAdapter` (eval.yaml) paths, plus challenge-response verification.
Package exports
Both `InspectAILogAdapter` and `InspectEvalsAdapter` are now exported from the package top level:
from valichord_attestation import InspectAILogAdapter, InspectEvalsAdapter`inspect-ai` added as an optional dependency group in `pyproject.toml`:
pip install "valichord_attestation[inspect-ai]"Running the examples
pip install -e "valichord_attestation[dev]"
pytest valichord_attestation/tests/ # 259 tests, 100% line coverage
# GSM8K demo (Mistral-7B, no GPU required):
python valichord_attestation/examples/mistral_7b_gsm8k_demo/challenge_response_demo.py
# inspect_ai popularity demo (GPT-4o-mini, no GPU required):
python valichord_attestation/examples/inspect_ai_popularity_demo/challenge_response_demo.py259 valichord_attestation tests (183 → 259, +76). 100% line coverage maintained.
v0.5.2 — Holochain 0.6.1 (iroh/QUIC) + attestation format v1.2 + coordinator_utils + UI patterns
What's new since v0.5.1
Holochain 0.6.1 upgrade — iroh/QUIC transport (2026-05-13)
Full upgrade of the Holochain toolchain from 0.6.0 to 0.6.1. All 166 integration tests confirmed green on the new transport.
Transport: iroh/QUIC replaces tx5/WebRTC as the default. The advanced.tx5Transport conductor config block is dead and has been removed from all conductor YAMLs. kitsune2-bootstrap-srv bumped to 0.4.1 (0.3.x is wire-incompatible).
API changes applied:
get_agent_activitynow requires a 4thGetOptions::network()parameter — added at all call sites in attestation and governance coordinatorsrecv_remote_signaldouble-decode removed — 0.6.1 delivers signal payload directly as a msgpack map (no outerbin8wrapper)Warrant→SignedWarranttype rename inAgentActivityResponse— handled automatically by HDK version bump
Version bumps: hdk = "=0.6.1", hdi = "=0.7.1", holochain_serialized_bytes = "=0.0.57", @holochain/tryorama = "0.19.1"
Demo scripts: retryOnTx5 → retryOnNetworkError in serve.mjs, node-lib.mjs, validator-node.mjs — tx5-specific error strings replaced with generic timeout/channel-drop detection.
valichord_attestation format v1.2
Two additive, backward-compatible changes informed by FazeelUsmani's lm-evaluation-harness PR #3752.
Metric.filter (optional str)
Disambiguates metrics sharing the same key produced by different filter passes (e.g. strict-match vs flexible-extract). None/absent → omitted from canonical encoding entirely.
Bundle.meta + content_hash
meta: Optional[dict] — free-form provenance block (commit, harness version, command, timestamp, n_shot, etc.). Included in bundle_hash (byte identity); excluded from content_hash (scientific equivalence). v1.1 bundles with no meta have content_hash == bundle_hash.
content_hash() added to canonical.py and exported from __init__.py. build_bundle() default format_version bumped to "v1.2". All v1/v1.1 bundles remain valid — no existing hash values change.
Tests: 142 → 183 (+41 new). 100% line coverage maintained.
from valichord_attestation import build_bundle, content_hash
bundle = build_bundle(
results,
meta={"commit": "abc123", "n_shot": 5, "harness": "lm-eval 0.4.7"},
)
print(bundle.bundle_hash) # identity hash (includes meta)
print(content_hash(bundle)) # scientific equivalence hash (excludes meta)valichord_coordinator_utils — shared Holochain coordinator crate
New coordinator_utils workspace crate (coordinator-only, hdk dep, no integrity zome impact):
records_for_links— previously duplicated in bothattestation_coordinatorandgovernance_coordinator; now in one placecall_other_role_opt— generic typed cross-DNA call helper
No DNA hash change: coordinator zomes only. No behaviour change.
Three flux/ad4m utility patterns ported to ValiChord UI
valichord-ui/src/lib/utils.ts (new)
asyncFilter<T>— parallel async predicate filterupsertByHash<T>— immutable upsert for Holochain record arrays keyed byActionHash
valichord-ui/src/lib/tabCoordinator.ts (new)
isLeaderTabwritable store — gates periodic DHT polls to the leading tabinitTabCoordinator()— BroadcastChannel leader election (claim/hb/resign protocol with UUID tiebreak)
demo/ai_validator.py — form_verdicts() retry loop
- LLM retry-with-error-feedback (up to 5 attempts per verdict)
- Validates
outcomeandconfidenceagainst allowed value sets; strips```jsonfences
Running the examples
pip install -e "valichord_attestation[dev]"
pytest valichord_attestation/tests/ # 183 tests, 100% line coverage
# GSM8K demo (Mistral-7B, no GPU required):
python valichord_attestation/examples/mistral_7b_gsm8k_demo/challenge_response_demo.py
# inspect_ai popularity demo (GPT-4o-mini, no GPU required):
python valichord_attestation/examples/inspect_ai_popularity_demo/challenge_response_demo.py166 Holochain integration tests passing (97 Tryorama + 69 Rust sweettest), 183 valichord_attestation tests. Holochain 0.6.1, iroh/QUIC transport.
v0.5.1 — inspect_ai demo + Wind-Tunnel scenarios
What's new since v0.5.0
inspect_ai Popularity Demo — second real-data example
valichord_attestation/examples/inspect_ai_popularity_demo/ is a new end-to-end walkthrough of the v1.1 protocol against an inspect_ai .eval log — a different eval harness format (ZIP-based binary, structured per-sample JSON, C/I scorer values) from the lm-evaluation-harness JSONL format used in the GSM8K demo.
Task: popularity — AI personality self-assessment
Model: openai/gpt-4o-mini
Scorer: match (C/I values)
Source: inspect_ai test suite (21 KB, no GPU required)
The parsing layer uses EveryEvalEver's InspectAIAdapter (pinned to commit dec1ae43), not inspect_ai.log.read_eval_log() directly. This is the concrete alignment artefact with the EvalEval Coalition's aggregate schema, referenced by Matt Fisher in PR #1610 and Scott Simmons's inspect_evals#910 proposal for executable evaluation reports.
# No download required — fixture mode (committed bundle.json):
python valichord_attestation/examples/inspect_ai_popularity_demo/challenge_response_demo.py
# Full reproduction with the real .eval log:
bash valichord_attestation/examples/inspect_ai_popularity_demo/download_eval.sh
python valichord_attestation/examples/inspect_ai_popularity_demo/build_bundle.py --eval-path ./popularity.eval
python valichord_attestation/examples/inspect_ai_popularity_demo/challenge_response_demo.py| File | Purpose |
|---|---|
download_eval.sh |
Downloads popularity.eval (21 KB) from inspect_ai's public test suite |
build_bundle.py |
EEE-based parsing path + --fixture mode (committed bundle.json) |
challenge_response_demo.py |
k=20 challenge-response with tamper detection |
bundle.json |
Committed bundle (50-sample simulated fixture, random.Random(42), 80% accuracy) |
Honest EEE trade-offs documented in README.md: transitive dependencies (duckdb, seaborn, huggingface-hub<1.0.0 conflict), file-system side-effect (temporary JSONL), and Merkle root change (56c91950… → 227b5f8d… because EEE emits sample_id as strings vs integers).
Wind-Tunnel performance scenarios
valichord/wind-tunnel/ adds three performance test scenarios for the Holochain protocol layer (separate Cargo workspace, requires a pre-built .happ):
| Scenario | Description |
|---|---|
single_researcher_single_validator |
Baseline: one commit, one reveal — cold-start timing |
three_validators_sequential |
Three validators commit and reveal sequentially — typical small-panel run |
concurrent_commit_burst |
Ten agents commit simultaneously — DHT write contention under load |
VALICHORD_HAPP_PATH=path/to/valichord.happ cargo test --release -p wind_tunnelIssues backlog
valichord_issues_backlog.md — 20 GitHub issue drafts across three sections: Protocol & architecture (8), Integration & extensions (8), and Honourable mentions (4). Ready to stage and open on GitHub.
Running the examples
pip install -e "valichord_attestation[dev]"
pytest valichord_attestation/tests/ # 142 tests, 100% line coverage
# GSM8K demo (Mistral-7B, no GPU required):
python valichord_attestation/examples/mistral_7b_gsm8k_demo/challenge_response_demo.py
# inspect_ai popularity demo (GPT-4o-mini, no GPU required):
python valichord_attestation/examples/inspect_ai_popularity_demo/challenge_response_demo.py142 tests, 100% line coverage. Holochain protocol unchanged from v0.5.0.
v0.5.0 — valichord_attestation: canonical AI evaluation attestation
valichord_attestation — Canonical AI Evaluation Attestation Format
This release introduces valichord_attestation/, a Python library that extends ValiChord's commit-hash-reveal principle to AI capability evaluation. A published benchmark score — accuracy, pass@k, agent utility — can now be cryptographically bound to the specific run that produced it and independently verified by any third party.
What's new
valichord_attestation Python library
A harness-agnostic library for producing verifiable attestation bundles for AI evaluation runs. Two properties make a bundle verifiable:
- Deterministic hash — bundles are encoded with RFC 8785 (JSON Canonicalization Scheme / JCS), so the same run always produces the same bytes and the same SHA-256 digest.
- Merkle root — a SHA-256 Merkle tree over per-sample outputs lets the log holder prove any individual sample to a verifier without disclosing the full log.
from valichord_attestation import build_bundle, hash_bundle, merkle_proof, verify_faithfulness
bundle = build_bundle(
model_id="gpt-4o-2024-08-06",
task_id="gsm8k",
raw_metrics=[{"key": "accuracy", "value": 0.847, "stderr": 0.025}],
samples=[{"index": i, "output": "...", "correct": True} for i in range(1319)],
samples_total=1319, # assert intended run size — detects silent sample omission
repo_commit="abc123",
harness_version="inspect_ai/0.3.19",
)
bundle_hash = hash_bundle(bundle) # publish alongside the report
proof = merkle_proof(samples, index=42) # selective disclosure to a verifier
ok = verify_faithfulness(bundle.outputs_merkle_root, 42, samples[42], proof)Key modules:
| Module | Purpose |
|---|---|
builder.py |
build_bundle(...) — constructs and validates a Bundle, computes Merkle root, enforces 6dp pre-rounding, rejects NaN/Infinity |
canonical.py |
RFC 8785 JCS encoding; hash_bundle() — SHA-256 hex of the canonical encoding |
merkle.py |
leaf_hash, merkle_root, merkle_proof, verify_faithfulness |
bundle.py |
Bundle dataclass — MalformedBundleError on absent or non-finite fields |
challenge.py |
Challenge, derive_seed, generate_indices, compute_challenge_hash |
response.py |
ChallengeResponse, ResponseSample, build_response, verify_response |
adapters/base.py |
AdapterBase ABC — subclass to wrap any eval harness |
adapters/inspect_evals_stub.py |
Inspect AI stub adapter |
Explicit samples_total — sample-omission defence
build_bundle now accepts samples_total: Optional[int]. When provided and larger than len(samples), bundle.samples_total > bundle.samples_completed is directly visible in the bundle without out-of-band context, closing the silent-truncation attack surface described in threat model §10(d). Raises ValueError if samples_total < len(samples) — the declared total can never be less than what was actually logged.
bundle = build_bundle(
...
samples_total=1319, # declared; if adapter drops samples silently,
# bundle.samples_total > bundle.samples_completed
)Probabilistic challenge-response (additive, no bundle format change)
Selective disclosure lets the log holder choose which samples to prove. The challenge-response protocol inverts control: the verifier picks which samples to inspect, the holder must reveal exactly those, and the verifier gains high-confidence faithfulness evidence without receiving the full log.
from valichord_attestation import hash_bundle, Challenge, build_response, verify_response
import os
challenge = Challenge(
bundle_hash=hash_bundle(bundle),
verifier_nonce=os.urandom(32), # verifier-chosen; holder cannot predict indices
k=60,
)
response = build_response(challenge, samples) # holder reveals hashes + Merkle paths only
ok = verify_response(challenge, response, bundle) # verifier checks all paths against rootProtocol:
- Seed:
HMAC-SHA256(key=verifier_nonce, msg=bundle_hash_ascii) - Indices: SHA-256 counter-mode —
SHA256(seed || counter_u64_be) mod total_samples, rejection-sampled for distinctness. Language-agnostic; any conforming implementation produces identical indices. - Response: hashes and proof paths only — no raw sample content
challenge_hash:SHA-256(JCS({"bundle_hash", "k", "verifier_nonce_hex"}))binds the response to the specific challenge
Sensitivity (catch probability = 1 − (1−f)^k):
| f \ k | k=30 | k=60 | k=100 | k=300 |
|---|---|---|---|---|
| f = 1% | 26% | 45% | 63% | 95% |
| f = 5% | 79% | 95% | 99% | >99% |
| f = 10% | 96% | >99% | >99% | >99% |
Fixed test vector: bundle_hash='a'*64, nonce=bytes(range(16)), k=5, total=100 → indices [9, 69, 33, 74, 38]
Real-data example — Mistral-7B-Instruct-v0.3 on GSM8K
valichord_attestation/examples/mistral_7b_gsm8k_demo/ is an end-to-end demonstration of the full v1.1 protocol on a real AI benchmark. Runnable without a GPU:
python valichord_attestation/examples/mistral_7b_gsm8k_demo/challenge_response_demo.py| File | Purpose |
|---|---|
run_eval.sh |
lm-evaluation-harness v0.5.0, Mistral-7B-Instruct-v0.3, GSM8K 100-sample subset — ~10 min, ~£1.50 on a 4090 |
build_bundle.py |
Parses lm-eval output → bundle.json; or --fixture mode (no GPU required). samples_total=100 declared explicitly. |
challenge_response_demo.py |
k=20 challenge with documented fixed nonce, Merkle verification, tamper detection |
bundle.json |
Committed bundle (deterministic fixture, random.Random(42), 35% accuracy — replace with real eval output) |
The _source.warning field in bundle.json documents that the committed bundle uses simulated data. Run run_eval.sh on a GPU and re-run build_bundle.py --output-path ./eval_output to produce a bundle from a real evaluation.
Format spec
valichord_attestation/spec/attestation_format_v1.md — bundle schema, canonical encoding rules, pre-rounding policy, Merkle tree construction, proof format and verifier algorithm, probabilistic challenge-response (Section 6, with schemas, seed derivation, index algorithm, sensitivity table, test vector), versioning policy, security considerations including threat model.
142 tests, 100% line coverage.
pip install -e "valichord_attestation[dev]"
pytest valichord_attestation/tests/
# Real-data demo (no GPU required)
python valichord_attestation/examples/mistral_7b_gsm8k_demo/challenge_response_demo.pyWhat v1 does not include (non-goals)
- Cryptographic signing — reserved for v2
- Zero-knowledge proofs — v2+ scope
- Holochain DHT integration (bundles as on-chain attestations) — follows format stabilisation
- TEE-backed attestation — separate v2 design
Architectural context
The format was designed in response to Scott Simmons's review of UKGovernmentBEIS/inspect_evals#1610. The core feedback: the canonical attestation spec belongs in ValiChord (the verification infrastructure), not inside each eval harness, and the meaningful attestation is not "I have the log file" but "this reported result is faithful to the run that produced it." The challenge-response protocol moves materially closer to the "verify without log access" property without waiting for ZK proofs or TEE infrastructure.
Documentation updates
README.md—🔬 AI Evaluation Attestationsection updated with challenge-response description,samples_total, real-data demovalichord_attestation/README.md— "Probabilistic Challenge-Response" subsection; "Running the examples" updatedvalichord_attestation/spec/attestation_format_v1.md— Section 6 (challenge-response) added; §10 threat model updated forsamples_total; sections renumbered
166 integration tests passing (97 Tryorama + 69 Rust sweettest), 1 skipped. Holochain protocol unchanged.