Where we stand
After today's proven#107 "overly cautious OWED" sweep (19 PRs, up to ~40 OWEDs discharged), 268 ^0 -erased OWED stubs remain across 40+ Safe* modules. This issue triages the remaining surface by upstream-dependency and recommends concrete next steps.
Distribution by blocker family
Per the tier-a triage + today's hunt, the residual breaks down as:
| Blocker family |
Approx count |
What would unblock |
String FFI opacity (unpack/pack/length/isInfixOf/prim__eq_String) |
~120 |
Upstream Idris2 reflective Data.String bridge OR refactor String parameters to List Char |
Char FFI opacity (prim__eq_Char/prim__lte_Char/isAlpha/isDigit/ord/chr) |
~35 |
Upstream Idris2 reflective Data.Char bridge OR refactor to enum types |
Nat div/mod opacity (Integral Nat instance) |
~20 |
Upstream Data.Nat.Division reflective tactic OR refactor to Bits32 |
Bits opacity (xor/shiftL/shiftR/.&./`. |
.`) |
~15 |
Covering-not-total reduction (covering functions stuck on abstract args) |
~12 |
Refactor specific functions to total (some are inherently covering — e.g. gcd) |
| External library / KDF / FFI binding (Argon2, bcrypt, OpenSSL, randomBytes) |
~12 |
Stay OWED-AXIOM — permanent. Just need a once-per-version audit. |
if/case head substitution + Nat-Bool-Prop bridges |
~30 |
Could be unblocked with a Bool->Dec reflective bridge OR significant manual case-split scaffolding |
| Double / IEEE-754 equality |
~6 |
Upstream Idris2 Data.Double reflective tactic OR property-test path |
List-Prelude lemmas not exposed (mapId/filterAll/etc.) |
~12 |
Add helper lemmas to proven-side lib/ (one-off PRs) |
| Visibility / structural / other |
~6 |
Various per-site fixes |
Three paths forward — owner decision needed
Path A — wait for Idris2 0.9.0
Status: 0.9.0 is not released yet (asdf list-all idris2 ends at 0.8.0). No public ETA found.
Pros: zero work this side. The estate-wide bump would auto-unlock the Char-FFI and (with luck) the case-eta + Nat-< blockers cited in tier-a doc's "DISCHARGE-after-Idris2-upgrade" rows.
Cons: out of our control. Cannot estimate ROI without seeing 0.9.0's release notes.
Path B — write reflective bridges to proven/lib/
Build domain-specific reflective tactics that bypass the FFI opacity:
Data.Char.Reflect — eqCharRefl : (c : Char) -> c == c = True for LITERAL chars by case-table generation
Data.String.Reflect — unpackRefl : unpack "abc" = ['a','b','c'] for LITERAL strings
Data.Nat.Reflect — divRefl : div 100 1 = 100 via Data.Nat.Division.divNatNZ-driven rewrite
Pros: unblocks the largest fraction (~155 OWEDs) without waiting for upstream. Lives in proven/lib/ so doesn't burden consumers.
Cons:
- Non-trivial Idris2 metaprogramming work (~5-15 hours per bridge).
- Easy to accidentally introduce
believe_me (banned by llm-warmup-dev.md policy).
- Reflective code may break with Idris2 0.9.0 upgrade.
Path C — refactor specific modules to enum / bounded types
Replace Char with data SafeChar = SCh0 | ... | SCh9 | SChA | ... | SChF for the SafeHex-class modules. Replace String with List Char (or a parameterised Vect) for narrow APIs. Stays in scope per-module.
Pros: zero believe_me, no waiting on upstream, immediate per-module discharge.
Cons:
- API-breaking for binding consumers (Rust/Zig/Deno bindings would need to marshal).
- Estimated 1-2 days per module to refactor + re-prove + re-bind.
- Doesn't generalise — each module's refactor is bespoke.
Recommendation
- Defer Path A — track Idris2 0.9.0 release; no action this side until then.
- Try Path B small — file one prototype tracking issue for
Data.Char.Reflect only; if it pans out without believe_me, expand.
- Skip Path C unless a specific module is critical-path for an external consumer (e.g. SafeUrl Bindings or SafeRegex shipping to opam).
What today's session DID clear
Cross-references
- This session's discharge campaign: proven#107
- Phase 3 umbrella: proven#90
- Tier-a per-site doc:
docs/proof-debt-triage-tier-a.md
Refs #90 #107
Where we stand
After today's proven#107 "overly cautious OWED" sweep (19 PRs, up to ~40 OWEDs discharged), 268
^0-erased OWED stubs remain across 40+ Safe* modules. This issue triages the remaining surface by upstream-dependency and recommends concrete next steps.Distribution by blocker family
Per the tier-a triage + today's hunt, the residual breaks down as:
unpack/pack/length/isInfixOf/prim__eq_String)Data.Stringbridge OR refactorStringparameters toList Charprim__eq_Char/prim__lte_Char/isAlpha/isDigit/ord/chr)Data.Charbridge OR refactor to enum typesdiv/modopacity (Integral Natinstance)Data.Nat.Divisionreflective tactic OR refactor toBits32xor/shiftL/shiftR/.&./`.coveringfunctions stuck on abstract args)total(some are inherently covering — e.g.gcd)if/casehead substitution + Nat-Bool-Prop bridgesBool->Decreflective bridge OR significant manual case-split scaffoldingData.Doublereflective tactic OR property-test pathmapId/filterAll/etc.)proven-sidelib/(one-off PRs)Three paths forward — owner decision needed
Path A — wait for Idris2 0.9.0
Status: 0.9.0 is not released yet (
asdf list-all idris2ends at 0.8.0). No public ETA found.Pros: zero work this side. The estate-wide bump would auto-unlock the Char-FFI and (with luck) the
case-eta + Nat-<blockers cited in tier-a doc's "DISCHARGE-after-Idris2-upgrade" rows.Cons: out of our control. Cannot estimate ROI without seeing 0.9.0's release notes.
Path B — write reflective bridges to
proven/lib/Build domain-specific reflective tactics that bypass the FFI opacity:
Data.Char.Reflect—eqCharRefl : (c : Char) -> c == c = Truefor LITERAL chars by case-table generationData.String.Reflect—unpackRefl : unpack "abc" = ['a','b','c']for LITERAL stringsData.Nat.Reflect—divRefl : div 100 1 = 100viaData.Nat.Division.divNatNZ-driven rewritePros: unblocks the largest fraction (~155 OWEDs) without waiting for upstream. Lives in
proven/lib/so doesn't burden consumers.Cons:
believe_me(banned by llm-warmup-dev.md policy).Path C — refactor specific modules to enum / bounded types
Replace
Charwithdata SafeChar = SCh0 | ... | SCh9 | SChA | ... | SChFfor theSafeHex-class modules. ReplaceStringwithList Char(or a parameterisedVect) for narrow APIs. Stays in scope per-module.Pros: zero
believe_me, no waiting on upstream, immediate per-module discharge.Cons:
Recommendation
Data.Char.Reflectonly; if it pans out withoutbelieve_me, expand.What today's session DID clear
Cross-references
docs/proof-debt-triage-tier-a.mdRefs #90 #107