Skip to content

Commit d307b6c

Browse files
docs: honest framing of remaining ABI axioms (epic #87 Tier C item 11) (#108)
## Summary - Module docstring on `src/abi/Boj/SafetyLemmas.idr` claimed "Three axiomatic `believe_me` primitives" while five live in the file. Corrected to enumerate all five and tag each to its underlying `prim__*` primitive. - `appendLengthSum` and `substrLengthBound` declarations used `(x y : T)` multi-binder syntax which **Idris2 0.8.0 rejects** at parse time ("Expected a type declaration" at the colon). Adding the comma — `(x, y : T)` — restores parsability. Types and proof terms are unchanged. - New `== Formal verification` section in `README.adoc` summarising posture so external readers don't have to dig through `PROOF-NEEDS.md`: all P1/P2 obligations closed; the 5 remaining axioms are *principled assumptions over Idris2 primitives*, not unproven debt. ## Why this is a docs PR, not a discharge campaign The 2026-05-18 audit in `PROOF-NEEDS.md` already classified every remaining `believe_me` as class (J) — *genuinely unavoidable* in Idris2 0.8.0 because `Char` / `String` are opaque primitives with no in-language induction principle. The reduction path is external backend-assurance (Chez/BEAM extraction), not constructive proof. Item 11 was therefore already done as research — just not surfaced honestly. This PR closes the documentation gap. `d2622566 proof(abi): reduce believe_me from 31 to 4` is where the "4 axioms canonical" framing originated; `4f729e7e` and `0de09a47` later added `appendLengthSum` and `substrLengthBound`. Honest current count: 5. ## Out of scope (deliberately) - `src/abi/Boj/SafeAPIKey.idr` has **independent baseline rot**: `plusLteMonotone` not found (likely stdlib rename — "did you mean transitive?") + a constraint-solver failure on `logSafeBounded`. Pre-existing, **not** introduced here. Worth a separate fix-up PR. - `idris2 --build src/abi/boj.ipkg` does not complete in 9 min on my dev box (gets SIGTERMed). Per-module `idris2 --check` is fast and was used for verification. - No CI workflow exercises the `src/abi/boj.ipkg` build today (`.github/workflows/` only mentions idris2 in `abi-drift.yml` which uses a different tool). Wiring an idris2 build into CI is a separate concern. ## Test plan - [x] `idris2 --check src/abi/Boj/SafetyLemmas.idr` — green with my changes; previously red on `origin/main` due to the multi-binder parse error. - [x] `idris2 --check src/abi/Boj/Safety.idr` — green (downstream consumer of `charEqSound`). - [ ] CI Hypatia neurosymbolic analysis + dogfood gate (will run on PR open). - [ ] Reviewer sanity-check on PROOF-NEEDS.md vs the new README posture. ## Related branches / overlap to resolve `fix/proof-needs-reconcile-believe-me` exists on remote (single commit `3d6b881c` dated 2026-05-18, title says "reconcile believe_me audit — 5 justified axioms, not zero/4") but its diff does **not** touch `PROOF-NEEDS.md`, `SafetyLemmas.idr`, or `README.adoc` — looks abandoned. Worth a quick owner confirmation that this PR isn't displacing intentional work. Refs epic #87 Tier C item 11. Item 12 (cross-cartridge composition proof) is a separate draft PR (ADR-0014 RFC). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 746c352 commit d307b6c

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

README.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ Run the coherence tests:
107107
node --test mcp-bridge/tests/
108108
----
109109

110+
== Formal verification
111+
112+
BoJ's ABI safety layer is written in Idris2 with the proof obligations
113+
audited in `PROOF-NEEDS.md`. Headline posture (as of 2026-05-18 audit):
114+
115+
* *All P1/P2 obligations closed.* `SafePromptInjection`, `SafeCORS`,
116+
`SafeAPIKey`, `SafeWebSocket`, `SafeHTTP`, `Federation`, `Catalogue`,
117+
`CartridgeDispatch` (BJ1), `CredentialIsolation` (BJ2),
118+
`APIContractCoverage` (BJ3) — all carry constructive proofs.
119+
* *Five remaining `believe_me` invocations*, all isolated in
120+
`src/abi/Boj/SafetyLemmas.idr`, all class (J) — *principled
121+
assumptions*, not unproven debt. They axiomatise the soundness of
122+
Idris2 0.8.0's opaque `Char`/`String` primitives (`prim__eqChar`,
123+
`prim__strToCharList`, `prim__strAppend`, `prim__strSubstr`) which
124+
have no in-language induction principle. The only reduction path is
125+
external backend-assurance evidence (Chez/BEAM extraction or
126+
property-test harness), not constructive in-language proof.
127+
* *No unproven obligations remain in the audited surface.* The full
128+
per-site rationale and the in-progress cross-cartridge composition
129+
question are tracked in `PROOF-NEEDS.md` and `docs/decisions/`.
130+
110131
== License
111132

112133
PMPL-1.0-or-later

src/abi/Boj/SafetyLemmas.idr

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@
66
||| proofs in SafeHTTP, SafeCORS, SafeWebSocket, SafePromptInjection,
77
||| SafeAPIKey, and Safety modules.
88
|||
9-
||| Three axiomatic believe_me primitives are declared here:
10-
||| charEqSound — soundness of prim__eqChar (c1 == c2 = True → c1 = c2)
11-
||| charEqSym — symmetry of prim__eqChar (x == y = y == x)
12-
||| unpackLength — prim__strToCharList preserves length
9+
||| Five axiomatic believe_me primitives are declared here. Each is
10+
||| class (J) — genuinely unavoidable in Idris2 0.8.0 because `Char`
11+
||| and `String` are opaque primitive types whose operations are
12+
||| foreign functions with no constructors and no in-language induction
13+
||| principle. They are documented as principled assumptions, not
14+
||| unproven debt; see PROOF-NEEDS.md for the per-site audit.
1315
|||
14-
||| All other proofs are constructive.
16+
||| charEqSound — soundness of prim__eqChar (c1 == c2 = True → c1 = c2)
17+
||| charEqSym — symmetry of prim__eqChar (x == y = y == x)
18+
||| unpackLength — prim__strToCharList preserves length
19+
||| appendLengthSum — prim__strAppend: length (s ++ t) = length s + length t
20+
||| substrLengthBound — prim__strSubstr: result no longer than the requested count
21+
|||
22+
||| All other proofs in this module are constructive.
1523
module Boj.SafetyLemmas
1624

1725
import Data.List
@@ -215,12 +223,12 @@ unpackLength _ = believe_me ()
215223
||| Idris2 type level. Established by semantics of all supported backends.
216224
%unsafe
217225
export
218-
appendLengthSum : (s t : String) -> length (s ++ t) = length s + length t
226+
appendLengthSum : (s, t : String) -> length (s ++ t) = length s + length t
219227
appendLengthSum _ _ = believe_me ()
220228

221229
||| Substring of a string has length at most the requested count.
222230
||| Axiomatic: prim__strSubstr semantics — result is never longer than `len`.
223231
%unsafe
224232
export
225-
substrLengthBound : (s : String) -> (start len : Nat) -> LTE (length (substr start len s)) len
233+
substrLengthBound : (s : String) -> (start, len : Nat) -> LTE (length (substr start len s)) len
226234
substrLengthBound _ _ _ = believe_me ()

0 commit comments

Comments
 (0)