Commit 6a6c484
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
0 commit comments