Skip to content

Commit 6a6c484

Browse files
proof(SafeRegex): annotate 26 bodyless decls as OWED (Refs standards#158) (#63)
## Summary Applies the estate's OWED-with-justification convention (set 2026-05-20 by SafeChecksum/Buffer/CryptoAccel/HKDF/Bloom/FPGA; live examples in sibling PRs #37 / #41 / #46 / #52) to the 26 bodyless declarations in `src/Proven/SafeRegex/Proofs.idr` — the largest single OWED batch in the standards#158 campaign so far. Form per decl: triple-pipe `|||` doc-comment stating the claim + the specific Idris2 0.8.0 blocker + a "Discharge once ..." condition, followed by the bare signature with `0 ` erased-multiplicity where the lemma has no consumer at default multiplicity (see note below). No `postulate` keyword. No `believe_me`. No `idris_crash`. Refs hyperpolymath/standards#158. ## Dominant blocker category **Complexity-theoretic claims** (linear-vs-exponential time budget, matcher termination, ReDoS classification) requiring an embedded operational-semantics / NFA-DFA model that Idris2 0.8.0 cannot do without an explicit `Regex`-AST induction. This is the family flagged in the task brief: `exponentialStepLimitCapped`, `linearStepLimitScales`, `matchingTerminatesLemma`, `nestedQuantifiersExponential`, `overlappingAltsExponential`, `quantifiedEmptyQuadratic`, `linearNoExponentialPatterns`, `linearAllowsLargeInput`, `exponentialRestrictsInput`. **Secondary blockers**, in roughly decreasing frequency: 1. **String / Char FFI opacity** — `prim__eq_Char`, `prim__lt_Char`, `length : String -> Nat`, `(/=)` for `Char`. Family identical to boj-server's class-J `charEqSound` and SafeChecksum's `luhnValidatesKnownGood`. Affects: `anyMatchesNonNewline`, `digitOnlyDigits`, `charSelfOverlaps`, `rangeSelfOverlaps`, `unionSelfOverlaps`, `disjointRangesNoOverlap`, partially `smallInputAlwaysSafe`. 2. **Record-projection equation not propagated through `case`/`if` scrutinees** — the elaborator does not auto-unfold a field projection inside a pattern match when the record is universally quantified. Affects: `boundedImpliesJustMax`, `boundedQuantifierFinite`, `linearAllowsLargeInput`, `exponentialRestrictsInput`, `linearStepLimitScales`, `exponentialStepLimitCapped`. 3. **Three-way `&&`-conjunction splitting** on `isKnownSafe` arms — needs `andTrueSplit` applied twice. Affects: `seqPreservesSafety`, `altPreservesSafety`, `boundedQuantPreservesSafety`. 4. **Constructor-level refinement missing** — `Capture` is a plain record with no `start <= end` witness; cannot be discharged from `matched = True` alone. Affects: `capturePositionsValid`. Same shape as SafeTOML's `dateComponentsValid` / `timeComponentsValid`. 5. **Definitional-equation auto-discharge** when LHS / RHS are syntactic unfoldings of each other but involve abstract `Char` / `CharClass`. Affects: `negateInverts`, `unionIsOr`. 6. **`Nat`-`Ord`-instance reduction** going through `compareNat` rather than structural pattern match. Affects: `stepIncreases`. 7. **64-arm `compare`-instance case-split on `ComplexityLevel`** for premise-inconsistent arms. Affects: `complexityTransitiveFallback`. ## Multiplicity nuance Four of the 26 OWED lemmas are consumed at default multiplicity by `public export` re-exports in the same file: | OWED lemma | Consumer | |---|---| | `matchingTerminatesLemma` | `matchingTerminates = matchingTerminatesLemma` (L89) | | `charSelfOverlaps` | `sameClassOverlaps (SingleChar c) = charSelfOverlaps c` | | `rangeSelfOverlaps` | `sameClassOverlaps (Range f t) = rangeSelfOverlaps f t` | | `unionSelfOverlaps` | `sameClassOverlaps (Union a b) = unionSelfOverlaps a b` | | `complexityTransitiveFallback` | `complexityTransitive` catch-all clause | These five lemmas are left at default multiplicity (no `0 ` prefix) — making them `0 ` would break the existing default-multiplicity consumers and so propagate `0`-erasure into the public API. The docstring states this explicitly per lemma. The other 21 are `0 `-erased. (Note: 21 + 5 = 26 — `complexityTransitiveFallback` is counted in the unrestricted set.) ## The 26 OWED decls ### Termination Proofs (4) - `boundedImpliesJustMax` — record-projection through `isJust` (blocker 2) - `boundedQuantifierFinite` — same record-projection blocker - `stepIncreases` — `Nat`-`Ord`-instance reduction (blocker 6) - `matchingTerminatesLemma` — **complexity-theoretic / NFA-DFA model needed** ### Complexity Proofs (4) - `nestedQuantifiersExponential` — **`Bool`-vs-`Prop` reflection gap** - `overlappingAltsExponential` — same + `andTrueSplit` - `quantifiedEmptyQuadratic` — same - `linearNoExponentialPatterns` — four-arm `if`-chain inversion ### Input Safety Proofs (3) - `smallInputAlwaysSafe` — String FFI `length` + 4-arm case-split + `lteTransitive` - `linearAllowsLargeInput` — record-projection through `case` - `exponentialRestrictsInput` — same ### Character Class Proofs (4) - `anyMatchesNonNewline` — `prim__eq_Char` reflection - `digitOnlyDigits` — `prim__gte_Char` / `prim__lte_Char` + `andTrueSplit` - `negateInverts` — definitional-equation auto-discharge - `unionIsOr` — same ### Overlap Detection Proofs (4) - `charSelfOverlaps` — `prim__eq_Char` reflexivity (consumed) - `rangeSelfOverlaps` — `prim__lt_Char` reflexivity (consumed) - `unionSelfOverlaps` — structural induction over `CharClass` (consumed) - `disjointRangesNoOverlap` — `Bool`-premise through `||` and `not` ### Step Limit Proofs (2) — **complexity-theoretic** - `linearStepLimitScales` — strict monotonicity of `Nat * positive constant` - `exponentialStepLimitCapped` — `min a b <= b` for `Nat` ### Match Result Proofs (1) - `capturePositionsValid` — `Capture` lacks constructor-level refinement (blocker 4) ### Composition Proofs (3) - `seqPreservesSafety` — three-way `&&`-split on `isKnownSafe Seq` arm - `altPreservesSafety` — same on `Alt` arm - `boundedQuantPreservesSafety` — same on `Quant` arm ### Totality Proofs (1) - `complexityTransitiveFallback` — 64-arm constructor case-split with `absurd Refl` (consumed) ## Safety posture - Zero `believe_me` - Zero `postulate` - Zero `idris_crash` - 21 `0 `-erased (cannot leak into runtime) - 5 at default multiplicity to preserve existing public-API consumers; these are still bodyless / OWED but visible by necessity - Discoverable as named declarations with explicit blocker / discharge ## Local verification ``` IDRIS2_PREFIX=/home/.../idris2/0.8.0 \ idris2 --source-dir src --check src/Proven/SafeRegex/Proofs.idr 1/4: Building Proven.Core (src/Proven/Core.idr) 2/4: Building Proven.SafeRegex.Types (src/Proven/SafeRegex/Types.idr) 3/4: Building Proven.SafeRegex.Safety (src/Proven/SafeRegex/Safety.idr) 4/4: Building Proven.SafeRegex.Proofs (src/Proven/SafeRegex/Proofs.idr) ``` No warnings, no errors. Rebased onto current `main` (df6b0a1) post-#51 / #52 merges. ## Scope - Touches only `src/Proven/SafeRegex/Proofs.idr` - 26 declarations annotated; the 21 already-Refl-discharged proofs in the file (`linearMeetsAnySafety`, `exponentialOnlyRelaxed`, `exponentialNotNormal`, `exponentialMeetsRelaxed`, `unboundedNeverSafe`, `sameClassOverlaps`, `anyOverlapsAll`, `emptyIsSafe`, `neverIsSafe`, `singleCharIsSafe`, `startAnchorIsSafe`, `endAnchorIsSafe`, `wordBoundaryIsSafe`, `backrefNotKnownSafe`, `noMatchIsNotMatched`, `successIsMatched`, `safetyAnalysisTotal`, `complexityTransitive`, `complexityReflexive`, `matchingTerminates`) are untouched. ## Why draft Filed DRAFT per the estate convention (estate-wide proven CI queue settles between batches). ## Test plan - [ ] CI green on this PR (idris2 0.8.0 `--check`) - [ ] Owner review of OWED reasons against SafeChecksum / SafeHtml / SafeMath / SafeTOML precedent (PRs #33 / #41 / #46 / #52) - [ ] Verify no downstream module shadows the names (grep was clean at edit time; the four consumers documented above are the only call-sites of the five default-multiplicity OWED lemmas) Refs hyperpolymath/standards#158 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c0f2f47 commit 6a6c484

1 file changed

Lines changed: 367 additions & 112 deletions

File tree

0 commit comments

Comments
 (0)