You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
proof(SafeXML): annotate 9 bodyless decls as OWED (Refs standards#158) (#55)
## Summary
Annotates 9 bodyless signatures in `src/Proven/SafeXML/Proofs.idr` as
**OWED-with-justification** per the estate convention set 2026-05-20
(SafeChecksum/Buffer/CryptoAccel/HKDF/Bloom/FPGA; siblings #37-54).
Each declaration retains its prose docstring + claim, gains an explicit
per-decl justification naming the **specific Idris2 0.8.0 blocker** that
prevents discharge and the structural refactor or reflective tactic that
would unblock it. Multiplicity changed to `0` (erased); no `postulate`
keyword; no `believe_me`; no `idris_crash`.
Refs hyperpolymath/standards#158.
## Per-decl OWED reasons
### String FFI opacity (8 / 9)
The dominant blocker: `prim__eq_String`, `unpack`, and `isInfixOf` over
opaque FFI-bound `String` do not reduce by `Refl` in Idris2 0.8.0 (same
trust-posture as `Boj.SafetyLemmas.charEqSym`).
| # | Decl | OWED claim | Specific blocker |
|---|------|-----------|------------------|
| 1 | `builderNoXXE` | builder never emits `<!ENTITY ... SYSTEM/PUBLIC
...>` | `NoExternalEntities` predicate's `auto`-found Bool-equality on
`isInfixOf` over opaque `renderNode` output |
| 2 | `builderNoDTD` | builder never emits `<!DOCTYPE ...>` | `isInfixOf
"<!DOCTYPE" (renderNode ...)` over opaque FFI String |
| 3 | `builderNoEntities` | rendered output contains no raw entity refs
beyond the five predefined | conjunctive `isInfixOf` Bool chain bottoms
out in `prim__eq_String` |
| 4 | `textEscapingSound` | `xmlText` escapes all `<` to `<` |
per-char escape pass through `unpack`/`pack`/`prim__strCons` |
| 5 | `attrEscapingSound` | `xmlAttrValue` escapes all `"` to `"` |
same `unpack` opacity as 4 |
| 6 | `elementNameValidation` | `isOk (xmlName n)` implies
`isValidXMLName n` | extensional equality between two opaque
`unpack`-based pipelines |
| 7 | `qnameComponentsValid` | `isOk (xmlQName p l)` implies both
components valid | conjunction across two opaque `isValidXMLName` calls
|
| 8 | `attrValueNoQuotes` | escaped attribute contains no unescaped `"`
| `all` predicate over `unpack` of opaque escaped `String` |
### DOM-traversal `Refl` gap (1 / 9)
| # | Decl | OWED claim | Specific blocker |
|---|------|-----------|------------------|
| 9 | `nestedElementsSafe` | `ProperlyEscaped child` propagates through
`build . withChild` | `Element` constructor pattern-match does not
propagate child invariant without explicit structural induction on
children list |
## Discharge paths
Two general routes apply to most items:
1. **Reflective tactics on `unpack` / `isInfixOf`** (estate-wide
improvement; would also unblock siblings in SafeChecksum / SafeHtml /
SafeString).
2. **Structural refactors** — return types like `EscapedString` /
`EscapedAttrValue` indexed by a `List Char` whose constructor
character-class excludes the forbidden raw character by construction
(item 9 specifically needs a structural induction lemma on
`XMLNode` children).
## Compliance with convention
- [x] `0 ` erased multiplicity (no runtime presence)
- [x] Triple-pipe `||| OWED:` opening line per decl
- [x] Specific Idris2 0.8.0 blocker named (not a generic claim)
- [x] Discharge precondition named per decl
- [x] No `postulate` keyword
- [x] No `believe_me` / `idris_crash`
- [x] Visibility preserved (`export`, not `public export` — matches
the file's pre-existing pattern)
- [x] No file outside `src/Proven/SafeXML/Proofs.idr` touched
## Test plan
- [ ] Sibling PRs land (estate CI jammed; this is DRAFT)
- [ ] Local `idris2 --build proven.ipkg` once the local toolchain is
re-wired (this worktree's `idris2 --prefix` resolves to an asdf
shim missing its Prelude; not blocking)
- [ ] CI green once estate-wide concurrency-pool exhaustion clears
🤖 Generated with [Claude Code](https://claude.com/claude-code)
0 commit comments