Skip to content

Commit 6883126

Browse files
feat(arbitration): ECH-05 fidelity evidence and belief/epi/sound verdict levels (#430)
## Summary Implements ECH-05 (drafted in `issues/echidna-05-fidelity-evidence.md`; not yet filed). When backends agree, that doesn't show they proved the same statement. So the arbiter now takes per-attempt **fidelity evidence** and gives each fused verdict a **level**: `belief` < `epi` < `sound`. A synonym collision (statements aligned only by name) can no longer reach `sound`, however many backends agree. The numeric fusion is unchanged; a regression fixture taken before the change shows this. The ECH-05 plan asks for three stacked PRs. This session can push to one branch only, so the three parts are three separate commits here, and each can be reviewed on its own: | Commit | Part | |---|---| | `6b6f54a` | **A**: `FidelityEvidence` on `ProverAttempt`; `level` / `retracted` / `warranted_term` on `ArbitratedVerdict`; the policy; regression fixture | | `48e8034` | **B**: `src/abi/EchidnaABI/Arbitration.idr`, plus an accept/reject fixture falsifier wired into `idris2-abi-ci.yml` | | `33a3dc7` | **C**: `tests/arbitration_fidelity_test.rs`, ROADMAP stage 6 acceptance, backend-pair table, `issues/README.md` row and issue draft | ## Changes **A: input and output types** (`src/rust/verification/result_arbiter.rs`, `src/rust/exchange/mod.rs`) - `FidelityEvidence` = `KernelTranslation { format, checked_by, term_hash }` | `DeclaredCorrespondence { consequence_tests, failures }` | `None`. The default is `None`, and `ProverAttempt::new` keeps its signature. - `EpistemicLevel { Belief, Epi, Sound }` (ordered); `fidelity_level()` is the policy: - **`belief`** if the verdict needs review, rests on a retracted backend, fused nothing, or **any** attempt has `None` evidence. - **`sound`** only if every fused attempt is a `KernelTranslation` to the same non-empty `term_hash`. - **`epi`** if every fused attempt is a kernel translation or a correspondence with **≥ 1** consequence test and 0 failures, and the kernel hashes agree. - **`belief`** otherwise, e.g. two kernel translations to different terms. - `ResultArbiter::retract(prover)` marks a backend unsound. Any verdict that fuses one of its attempts drops to `belief`, and `retracted` lists the backend. - `exchange::ExchangeFormat` (one variant per bridge) and `exchange::term_hash`: a BLAKE3 hash of the rendered term, separated by format, with no canonicalisation. The failure mode is a *missed* `sound`, never a false one. - `tests/fixtures/arbitration_regression.json` was generated at `29b18ea` *before* the change (16 scenarios × 4 policies). `tests/arbitration_regression_test.rs` replays it field by field (floats to 1e-12) and checks every verdict is at `belief`. **B: Idris2 ABI** (`EchidnaABI.Arbitration`) - `Level fused` is a closed sum indexed by the fused evidence. `Sound h` requires an `All (KernelAt h) fused` proof, and each `KernelAt` holds the hash-equality proof. So a collision, a correspondence or missing evidence in `fused` cannot be typed `Sound`, whatever produced the value (`collisionNotSound`, `correspondenceNotSound`, `noEvidenceNotSound`). - The classifier `level` comes with `blockedIsBelief`, `noEvidenceIsBelief`, `failedCorrespondenceIsBelief`, `untestedCorrespondenceIsBelief`, `emptyFusedIsBelief`, `blockingNeverRaises`, and evaluation controls (`alignedPairIsSound`, `collisionPairIsBelief`, `mixedPairIsEpi`). It is total and needs only `DecEq` on the hash type. - epistemic-types `6a68de3` and residual-evidence-types `97244f5` are cited by pin in the module header, not imported. The cited lemma names were checked at those commits. - Falsifier: `tests/abi/accept/ArbitrationAligned.idr` must type-check, and `tests/abi/reject/ArbitrationCollision.idr` (identical apart from one hash) must fail with `Mismatch between`. - `scripts/abi-fixtures.sh` judges by output, because `idris2 --check` exits 0 on a missing import. - It checks each fixture in a fresh temp directory, because a stale `build/` cache can silently skip the check (this bit me locally). - It runs in `idris2-abi-ci.yml`, whose path filter now includes `tests/abi/` and the script, and as `just abi-fixtures`. **C: acceptance tests and docs** - Synonym collision (Lean `ℕ` vs set.mm `NN`), under the portfolio, Bayesian and Dempster–Shafer policies. Four cases all stay at `belief` while `verified = true` / `CrossChecked`: lexical only; kernel translations to different terms; a correspondence with a failed consequence test; an untested correspondence. - MiniF2F `mathd_numbertheory_3` positive control: the Lean and Isabelle statements were checked against `openai/miniF2F@4e433ff` and translate to one term, which reaches `sound`. Negative control: the same pair with an off-by-one translation does not. - Retraction: retracting Lean lowers the two verdicts that rested on it. The Isabelle + HOL Light verdict stays `sound`, and the numbers don't change. - The exchange-layer terms are hand-written translation targets. These tests check the arbiter *given* certificates, not that certificates can be produced (that is stage 6). - Docs: - ROADMAP stage 6 acceptance (§2) and a "Cross-prover semantics" row (§3). - Gap-analysis table "Backend pairs that can share a term": every row is DESIGNED in ECHIDNA, and external routes are named but not run. - Short notes in the comparison doc and Guides. - `issues/README.md` gains the ECH-05 row and lists its four labels missing on this repo. - CHANGELOG `[Unreleased]` entry. ## RSR Quality Checklist ### Required - [x] Tests pass: `cargo test --lib` (1208 passed, 3 ignored) plus both new integration tests; full `--workspace` run is left to CI (see Testing) - [x] Code is formatted (`cargo fmt --all -- --check`) - [x] Linter is clean (`cargo clippy --locked --workspace --exclude echidna-rest --all-targets -- -D warnings`; see Testing for the exclusion) - [x] No banned language patterns (Rust, Idris2, Bash only) - [x] No `unsafe` blocks - [x] No banned functions (the ABI dangerous-pattern grep over `src/abi` and `tests/abi` is empty) - [x] SPDX license headers present on all new/modified source files - [x] No secrets, credentials, or `.env` files included ### As Applicable - [ ] Repo deed `(status)` / `(maturity)` updated: not touched; nothing ships to dispatch yet (every dispatched verdict is `belief`) - [ ] Repo deed `(ecosystem)` updated: n/a - [ ] Repo deed `(meta)` and/or `docs/decisions/` updated: policy decisions are listed below for the owner - [x] `docs/ROADMAP.adoc` updated (stage 6 acceptance + §3 row) - [x] Documentation updated for user-facing changes (Guides, gap analysis, comparison doc) - [ ] `TOPOLOGY.md` updated: n/a - [x] `CHANGELOG` updated - [x] New dependencies reviewed: none added (`blake3` already a dependency) - [x] ABI changes validated: new module has no foreign declarations; `ffi/zig` untouched ## Testing ``` $ cargo test --lib -- result_arbiter term_hash → 23 passed $ cargo test --test arbitration_regression_test → 1 passed, 1 ignored (the generator) $ cargo test --test arbitration_fidelity_test → 4 passed $ cargo test --lib → 1208 passed; 0 failed; 3 ignored $ cd src/abi && idris2 --build echidnaabi.ipkg → 20/20 modules, exit 0 (Idris2 0.8.0) $ bash scripts/abi-fixtures.sh ok accept: tests/abi/accept/ArbitrationAligned.idr ok reject: tests/abi/reject/ArbitrationCollision.idr Mismatch between: True and False. ``` Negative controls (applied, observed, then reverted): - A 1e-6 relative perturbation of the Bayesian conflict metric fails the regression test at `unanimous_proven_three / bayesian(0.5): verdict.conflict`. - Removing the term-hash equality check in `fidelity_level` fails `synonym_collision_cannot_reach_sound` and `minif2f_mistranslated_pair_does_not_reach_sound`. - Making the reject fixture aligned makes the falsifier fail ("type-checked"); breaking its import makes it fail ("non-type reason"). Not run locally: - `echidna-rest` builds `utoipa-swagger-ui`, whose build script downloads Swagger UI from GitHub, and the sandbox proxy blocks that. It is the only crate excluded from local clippy; CI builds the full workspace. - The full `cargo test --workspace --all-targets` was not run here; that is left to CI. ## Decisions for the owner 1. **Stacked PRs**: one branch with three commits, because of this session's single-branch constraint. Happy to split into A → B → C stacked PRs. 2. **Policy choices beyond the spec's text**: - A correspondence needs ≥ 1 consequence test (otherwise zero failures is vacuous). - Mismatched kernel hashes among fused attempts give `belief`, not `epi`. - A verdict with `needs_review` (which covers inconsistent premises) is `belief`. - An empty `term_hash` is not a certificate. 3. **Stage 6 "pair X"**: proposed HOL4 ↔ HOL Light via OpenTheory first, then Lean 4 ↔ Rocq via Dedukti. 4. **Labels** `area:arbitration`, `area:exchange`, `epistemic-types`, `residual-evidence-types` don't exist on this repo yet. They need creating before ECH-05 is filed. 5. **Open questions** from the issue are unchanged: whether Dempster–Shafer stays limited to same-encoding provers, and who runs consequence testing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 29b18ea commit 6883126

20 files changed

Lines changed: 3697 additions & 8 deletions

‎.github/workflows/idris2-abi-ci.yml‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ on:
1111
paths:
1212
- 'src/abi/**'
1313
- 'src/idris/**'
14+
- 'tests/abi/**'
15+
- 'scripts/abi-fixtures.sh'
1416
- '.github/workflows/idris2-abi-ci.yml'
1517
# No paths-filter on pull_request: this job is a REQUIRED status check, so it
1618
# must report on every PR (a path-filtered required check deadlocks PRs that
@@ -44,7 +46,7 @@ jobs:
4446
GH_TOKEN: ${{ github.token }}
4547
run: |
4648
set -euo pipefail
47-
PATTERN='^(src/abi/|src/idris/)'
49+
PATTERN='^(src/abi/|src/idris/|tests/abi/|scripts/abi-fixtures\.sh$)'
4850
if [ "${{ github.event_name }}" = "pull_request" ]; then
4951
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" \
5052
--paginate --jq '.[].filename')
@@ -93,6 +95,13 @@ jobs:
9395
idris2 --build echidnaabi.ipkg
9496
echo "✓ All ABI modules type-check successfully"
9597
98+
- name: Accept/reject fixtures (mechanical falsifier)
99+
if: steps.detect.outputs.relevant == 'true'
100+
run: |
101+
# tests/abi/accept must type-check; tests/abi/reject must be refused
102+
# with a unification error (each reject mirrors one accept fixture).
103+
bash scripts/abi-fixtures.sh
104+
96105
- name: Type-check Idris2 proof validator (src/idris)
97106
if: steps.detect.outputs.relevant == 'true'
98107
run: |

‎CHANGELOG.adoc‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@ https://semver.org/spec/v2.0.0.html[Semantic Versioning].
88

99
=== [Unreleased]
1010

11+
==== Added — arbitration 2026-10-14 (ECH-05)
12+
13+
* *Fidelity-levelled arbitration*: `+ProverAttempt+` carries
14+
`+FidelityEvidence+` (`+KernelTranslation+` / `+DeclaredCorrespondence+` /
15+
`+None+`) and `+ArbitratedVerdict+` gains `+level+` (`+belief+` / `+epi+` /
16+
`+sound+`), `+retracted+` and `+warranted_term+`. `+sound+` needs every
17+
fused attempt to be a kernel-checked translation to one exchange-layer
18+
term (`+exchange::term_hash+`); a synonym collision stays `+belief+`
19+
however many backends agree. `+ResultArbiter::retract+` marks a backend
20+
unsound and lowers every verdict that rested on it. Numeric fusion is
21+
unchanged: `+tests/arbitration_regression_test.rs+` replays the
22+
pre-change numbers. Dispatch attaches no evidence yet, so dispatched
23+
verdicts are `+belief+`.
24+
* *`+EchidnaABI.Arbitration+`* (Idris2): the three-level verdict as a
25+
closed sum whose `+Sound+` constructor carries the hash-equality proofs,
26+
with the classifier and its properties; `+tests/abi/{accept,reject}+`
27+
fixtures checked by `+scripts/abi-fixtures.sh+` in `+idris2-abi-ci.yml+`.
28+
1129
==== Added — integrations 2026-10-05
1230

1331
* *`+echidna prove --output json+`*: prints exactly one

‎Justfile‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,11 @@ proofs-verif-idris:
311311
fi
312312
echo "Idris2 verification corpus: all files type-check"
313313
314+
# Accept fixtures must type-check, reject fixtures must be refused (tests/abi).
315+
# Type-check the Idris2 ABI accept/reject fixtures (mechanical falsifier).
316+
abi-fixtures:
317+
bash scripts/abi-fixtures.sh
318+
314319
# Heavy (downloads the ~500MB Isabelle release), so this is gated by the weekly
315320
# verification-proofs-cron workflow, not the per-PR `proofs` rollup. Covers the
316321
# base-HOL theories; algebra/GroupTheory.thy is excluded (see proofs/isabelle/ROOT).

‎docs/ROADMAP.adoc‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ Stage 6 Cross‑prover semantics translation actually works
108108
6b Dedukti bridge real λΠ modulo as lingua franca
109109
6c mathematical identity arbitration canonicalise across representations
110110
6d Coursera delivery Zig ABI exposes capability
111+
acceptance (ECH‑05) a KernelTranslation certificate
112+
is producible for a named backend
113+
pair; arbitration already levels
114+
verdicts belief / epi / sound by
115+
that evidence (row "Cross‑prover
116+
semantics" in §3)
111117
112118
Stage 7 Sovereign tooling surround the rest of the ecosystem
113119
7a Stapeln container lifecycle
@@ -198,6 +204,18 @@ schema; nightly CI ≥ 1 h; zero known panic paths
198204
orphans, verified 2026‑04‑27) |*`+ProverKind+` ≥ 65 variants, every one
199205
factory‑dispatched*; CLAUDE.md states the canonical count; no orphans —
200206
*target met and exceeded*
207+
208+
|"`Cross‑prover semantics`" |The exchange bridges
209+
(`+src/rust/exchange/+`) parse and emit their formats; none produces a
210+
kernel‑checked translation. `+ResultArbiter+` grades each verdict
211+
`+belief+` / `+epi+` / `+sound+` by per‑attempt `+FidelityEvidence+`
212+
(ECH‑05), so a synonym collision cannot reach `+sound+`; dispatch attaches
213+
no evidence yet, so every dispatched verdict is `+belief+`
214+
|*A `+KernelTranslation+` certificate is producible for a named backend
215+
pair*, and a verdict on that pair reaches `+sound+`. First candidate:
216+
HOL4 ↔ HOL Light through OpenTheory (6a); then Lean 4 ↔ Rocq through
217+
Dedukti (6b). Pair table: `+docs/design/ADVANCED_TYPING_GAP_ANALYSIS.adoc+`
218+
§ "Backend pairs that can share a term"
201219
|===
202220

203221
=== 4. Current sprint — "`the smallest set that flips half the table`"

‎docs/design/ADVANCED_TYPING_GAP_ANALYSIS.adoc‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ epistemic type detection 3. Implement knowledge/belief type operators 4.
9595
Develop common knowledge analysis 5. Add secrecy/privacy type
9696
verification
9797

98+
*Meta-level use (ECH-05)*: result arbitration grades each verdict
99+
`belief` / `epi` / `sound`, following epistemic-types' `Warrant` /
100+
`Epi` / `SoundWarrant`; see "Backend pairs that can share a term" below.
101+
That is a level on ECHIDNA's own verdicts, not epistemic typing of user
102+
proofs, so the status above stands.
103+
98104
=== 5. Advanced Substructural Types
99105

100106
*Status*: ✅ Partial (via Idris2 linear types)
@@ -216,6 +222,50 @@ analysis
216222
|Type Classes |❌ |✅ Multiple |Low |Low
217223
|===
218224

225+
==== Backend pairs that can share a term
226+
227+
Cross-prover agreement only warrants the source claim when the backends'
228+
statements are the same term. `ResultArbiter` (ECH-05) grades a verdict
229+
`sound` only if every fused attempt carries a `KernelTranslation`
230+
certificate to one exchange-layer term, and `epi` for declared
231+
correspondences validated by consequence testing; lexical alignment
232+
through `data/synonyms/` alone is `belief`. The table names the backend
233+
pairs whose type theories meet in an exchange format, so that a
234+
kernel-checked shared term is possible in principle.
235+
236+
The route column names external projects, which were not run for this
237+
table. The last column is ECHIDNA's own state: no bridge in
238+
`src/rust/exchange/` produces a kernel-checked translation yet, so every
239+
row is DESIGNED and no pair reaches `sound` today. Producing one
240+
certificate for one pair is the ROADMAP stage 6 acceptance.
241+
242+
[cols="2,2,3,2",options="header"]
243+
|===
244+
|Backend pair |`ExchangeFormat` |External route |In ECHIDNA
245+
|HOL4 ↔ HOL Light |`open_theory` |OpenTheory articles, both directions;
246+
checked by the OpenTheory article reader |DESIGNED (`opentheory.rs`
247+
exports and imports proof states, not checked articles); first candidate
248+
|Lean 4 ↔ Rocq |`dedukti` / `lambdapi` |Lean and Coq encodings in λΠ
249+
modulo (Lean4Less/lean4dk, CoqInE); checked by Dedukti or Lambdapi
250+
|DESIGNED (`dedukti.rs`, `lambdapi.rs` translate syntax only)
251+
|HOL family ↔ Lean 4 / Rocq |`dedukti` |OpenTheory → Dedukti (Holide),
252+
then as above |DESIGNED
253+
|Agda ↔ Lean 4 / Rocq |`dedukti` |Agda → Dedukti (agda2dk, research
254+
prototype) |DESIGNED
255+
|cvc5 / veriT ↔ Rocq |`smt_coq` |Alethe or LFSC certificates replayed by
256+
the Coq kernel (SMTCoq) |DESIGNED (`smtcoq.rs` parses certificates and
257+
emits a skeleton)
258+
|Z3 / cvc5 / veriT ↔ Isabelle/HOL |`smt_lib` |SMT proofs reconstructed by
259+
Isabelle's `smt` method |DESIGNED
260+
|Vampire / E ↔ Isabelle/HOL |`tptp` |TPTP problems generated by
261+
Sledgehammer, proofs reconstructed with Metis |DESIGNED
262+
|===
263+
264+
For the automated rows the exchange-layer term is the problem the
265+
interactive side generated, so fidelity there is the interactive
266+
system's translation into SMT-LIB or TPTP; that translation is what a
267+
`KernelTranslation` certificate for the pair has to cover.
268+
219269
=== Strategic Expansion Plan
220270

221271
==== Phase 1: Critical Gap Closure (6-12 months)

‎docs/design/TYPING_CAPABILITIES_COMPARISON.adoc‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,11 @@ comparing:
194194
==== What We Provide That Single Systems Cannot
195195

196196
* *Cross-System Type Arbitration*: Determine when types from different
197-
systems are equivalent
197+
systems are equivalent. Today the arbiter grades each verdict `belief` /
198+
`epi` / `sound` by per-backend fidelity evidence (ECH-05); `sound` needs a
199+
kernel-checked shared term, which no backend pair can produce yet. Pair
200+
table: `ADVANCED_TYPING_GAP_ANALYSIS.adoc`, "Backend pairs that can share
201+
a term".
198202
* *Multi-Type-System Proof Routing*: Send proofs to the most appropriate
199203
type system
200204
* *Heterogeneous Type Safety*: Ensure type safety across mixed-system

‎docs/wikis/Guides.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ Motivating examples:
105105

106106
You normally don't call the four mechanisms directly. `ResultArbiter` (`src/rust/verification/result_arbiter.rs`) takes the per-prover `ProverOutcome`s from a cross-checked dispatch, adapts them into whichever mechanism `DispatchConfig.arbitration_policy` selects (`portfolio` default | `bayesian` | `dempster_shafer`), and returns an `ArbitratedVerdict`: winning verdict, agreeing/disagreeing/inconclusive camps, a `[0,1]` conflict metric, `needs_review`, and a Pareto-recommended prover among the agreeing set. `Dispatcher::verify_proof_cross_checked` attaches it to `DispatchResult.arbitration`. Key semantics: timeouts and errors are no-information (they no longer veto agreement), and a genuine Proven-vs-Refuted split is flagged for review instead of being flattened to `verified = false`.
107107

108+
Agreement is not identity: N backends proving N lexically aligned statements are N warrants for N propositions. Each `ProverAttempt` therefore carries `FidelityEvidence` — `KernelTranslation { format, checked_by, term_hash }` (a kernel-checked translation through `src/rust/exchange/`), `DeclaredCorrespondence { consequence_tests, failures }`, or `None` — and `ArbitratedVerdict.level` grades the fused verdict `belief` / `epi` / `sound` (ECH-05). `sound` needs every fused attempt to be a kernel translation to the same exchange-layer term; a tested correspondence with no failures gives `epi`; anything else, any attempt without evidence, a verdict that needs review, or one resting on a backend marked unsound with `ResultArbiter::retract` is `belief`. The numeric fusion is unchanged under the level. Dispatch does not attach evidence yet, so every dispatched verdict is `belief` until the exchange bridges can produce certificates (ROADMAP stage 6). The Idris2 statement is `src/abi/EchidnaABI/Arbitration.idr`.
109+
108110
## Guide: Cross-prover semantic queries
109111

110112
The synonym layer carries an optional `semantic_class` tag per entry. Combined with the three cross-prover dictionaries (`_msc2020.toml`, `_wordnet_math.toml`, `_conceptnet_seed.toml`) this gives "every prover's name for the same concept" lookups, fully offline.

‎issues/README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ SPDX-License-Identifier: CC-BY-SA-4.0
44

55
# Issue specifications
66

7-
Drafted issue specifications for the ParadisEO metaheuristic integration roadmap.
7+
Drafted issue specifications: ECH-01..04, PB and EB for the ParadisEO metaheuristic
8+
integration roadmap; ECH-05 for fidelity-levelled result arbitration.
89
Each file is the body for one GitHub issue; the title and labels are in the file header.
910

1011
To produce an issue body from a file (everything after the `# ` title line, without the SPDX header):
@@ -19,6 +20,7 @@ awk 'f;/^# /{f=1}' issues/<file> | sed '1{/^$/d}' > /tmp/body.md
1920
| ECH-02 | hyperpolymath/echidna | #421 | `echidna-02-cmaes-julia-gnn.md` |
2021
| ECH-03 | hyperpolymath/echidna | #422 | `echidna-03-chapel-island-migration.md` |
2122
| ECH-04 | hyperpolymath/echidna | #424 | `echidna-04-ffi-abi-bridge.md` |
23+
| ECH-05 | hyperpolymath/echidna | not filed | `echidna-05-fidelity-evidence.md` |
2224
| PB-01 | hyperpolymath/proof-burrower | not filed | `proof-burrower-01-combinatorial-tactic-synthesis.md` |
2325
| PB-02 | hyperpolymath/proof-burrower | not filed | `proof-burrower-02-ledger-fitness-formulation.md` |
2426
| EB-01 | hyperpolymath/echidnabot | not filed | `echidnabot-01-adaptive-ci-portfolio-scheduler.md` |
@@ -28,6 +30,7 @@ awk 'f;/^# /{f=1}' issues/<file> | sed '1{/^$/d}' > /tmp/body.md
2830
## Status
2931

3032
- **ECH-01..04** are filed on hyperpolymath/echidna and carry all their labels. On 2026-10-09 their bodies were replaced by hand with a different text that is not these files; the owner decides which is canonical (see `docs/handover/PARADISEO-ROADMAP-PROMPT.adoc`, WP0). `scripts/issues/sync-roadmap-issues.sh` syncs the bodies from these files (dry run by default; refuses to replace hand-edited bodies without `--overwrite`).
33+
- **ECH-05** is a draft for hyperpolymath/echidna, not filed. Its implementation (fidelity evidence on `ProverAttempt`, `level` on `ArbitratedVerdict`, `EchidnaABI.Arbitration`, the fidelity tests) lands with the PR that adds the file.
3134
- **PB-01, PB-02, EB-01** are drafts for copying to their own repositories. They are not filed.
3235

3336
## Provenance of the PB and EB drafts
@@ -46,5 +49,6 @@ Labels named in the drafts that did not exist when they were written (checked 20
4649
|------------------------------|---------------------------------------------------------------------|
4750
| hyperpolymath/proof-burrower | `area:swarm`, `rust`, `search-tactics`, `area:ledger`, `heuristics` |
4851
| hyperpolymath/echidnabot | `area:dispatcher`, `ci-optimization` (`rust` exists) |
52+
| hyperpolymath/echidna | `area:arbitration`, `area:exchange`, `epistemic-types`, `residual-evidence-types` (ECH-05; checked 2026-10-14) |
4953

50-
All labels used by ECH-01..04 exist on hyperpolymath/echidna.
54+
All labels used by ECH-01..04 exist on hyperpolymath/echidna; ECH-05's `enhancement` and `idris2` do.

0 commit comments

Comments
 (0)