Commit df6b0a1
authored
proof(SafeEnv): annotate 7 bodyless decls as OWED (Refs standards#158) (#51)
## Summary
Annotates the seven bodyless declarations in
`src/Proven/SafeEnv/Proofs.idr` as **OWED-with-justification**, per the
convention established 2026-05-20 by SafeChecksum, SafeBuffer,
SafeCryptoAccel, SafeHKDF, SafeBloom, SafeFPGA and the matching sibling
PRs #37 (SafeAPIKey), #41 (SafeHtml), #46 (SafeMath). Refs
hyperpolymath/standards#158.
## What each decl claims & why it's OWED
### Name validation (2)
1. **`digitStartInvalid`** — claim: prepending any `isDigit c = True`
character to any string yields a name `isValidEnvName` rejects. Blocker:
Idris2 0.8.0 does not reduce the `unpack . pack` round-trip on `(c ::
unpack s)` by Refl — `pack`/`unpack` are FFI string primitives.
Discharge: `Data.String` reflective tactic, or a `packUnpackInverse`
equation lemma.
2. **`wellKnownValid`** — claim: every name in `Types.wellKnownVars`
(PATH, HOME, USER, SHELL, ...) passes `isValidEnvName`. Blocker: `elem
name wellKnownVars = True` cannot be case-split over the literal list
because each comparison bottoms out in `prim__eq_String`, a Class-J FFI
primitive (same primitive whose commutativity is axiomatised in
`gossamer` as `stringNotEqCommut`). The point-checks
`pathValid`/`homeValid`/`userValid` already discharge specific witnesses
by Refl; this is the universally-quantified form. Discharge: Bool-Prop
reflection lemma for `prim__eq_String`, or refactor `wellKnownVars` to a
`DecEq`-checked names list.
### Value bounds (1)
3. **`emptyBounded`** — claim: the empty string is `BoundedValue maxLen
""` for every `maxLen`. The auto-prf witness `length (unpack "") <=
maxLen = True` should reduce to `0 <= maxLen = True`. Blocker: Idris2
0.8.0 does not reduce `unpack ""` to `[]` by Refl — `unpack` is an FFI
string primitive whose empty-string case is not exposed as a
definitional equation. Discharge: an `unpackEmpty : unpack "" = []`
lemma in `Data.String`, or refactor `BoundedValue` to use primitive
`String` length.
### Sensitivity classification (2)
4. **`publicClassification`** — claim: when `isSensitiveName name =
False`, `classifyByName name = Public`. Blocker: Idris2 0.8.0 will not
lift the False-hypothesis through `classifyByName`'s
`if`-on-`isSensitiveName` scrutinee, whose `isInfixOf`-fold over the
PASSWORD/SECRET/TOKEN/KEY pattern list bottoms out in `prim__eq_String`.
Discharge: `boolElim`-style rewrite tactic, or refactor `classifyByName`
to `case isSensitiveName name of ...`.
5. **`sensitiveClassification`** — mirror of 4 with `= True ... =
Sensitive`. Same blocker, same discharge path.
### Type-conversion soundness (2)
6. **`validBoolParses`** — claim: any string drawn from
`["true","false","yes","no","1","0","on","off"]` parses to `Just _` via
`parseBool`. Blocker: `parseBool` lower-cases its argument via `toLower`
and then case-splits; Idris2 0.8.0 does not reduce `toLower s` for
opaque `s : String`, even though every literal in the precondition list
is already lower-case. Discharge: Bool-Prop reflection lemma for
`toLower` on lower-case-only strings, or pre-lower-case the comparison
list.
7. **`validIntParses`** — claim: any string whose every character is an
ASCII digit parses to `Just _` via `parseInteger {a=Integer}`. Blocker:
Prelude `parseInteger` is an FFI string-to-integer conversion whose
success criterion (the all-digits invariant) is not stated as a
definitional equation. Compounded by `unpack` opacity. Discharge: a
`parseIntegerOfDigits` lemma exposed by Prelude, or refactor to a
hand-rolled digit-folder.
## Form (matches SafeChecksum convention)
- Triple-pipe docblock stating claim + blocker + discharge condition
- Leading `0 ` (erased-multiplicity, runtime-stripped)
- Original bare type signature, otherwise unchanged
- No `postulate` keyword (estate-wide choice)
- No `believe_me`, no `idris_crash`
See `src/Proven/SafeChecksum/Proofs.idr` L24-L100 for the reference
pattern.
## Scope
- Touches only `src/Proven/SafeEnv/Proofs.idr` (96 insertions, 36
deletions)
- Seven declarations annotated; the other 24 proofs in the file (already
discharged by `Refl` or `= ()`) are untouched
- No semantic change: each annotated decl was already bodyless on
`main`, this PR only adds erased multiplicity and replaces the existing
two-line "Depends on ..." docblocks with the full
OWED-with-justification form
## Why draft
Per the sibling-PR convention: CI is jammed estate-wide
(concurrency-pool exhaustion, see standards#92 / Refs MEMORY). Owner to
promote from DRAFT once the pool clears and `idris2 --build proven.ipkg`
runs green.
🤖 Generated with [Claude Code](https://claude.com/claude-code)1 parent 5bd2b36 commit df6b0a1
1 file changed
Lines changed: 96 additions & 36 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
39 | 46 | | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
46 | 62 | | |
47 | | - | |
48 | | - | |
49 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
50 | 66 | | |
51 | 67 | | |
52 | 68 | | |
| |||
74 | 90 | | |
75 | 91 | | |
76 | 92 | | |
77 | | - | |
78 | | - | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
79 | 103 | | |
80 | | - | |
| 104 | + | |
81 | 105 | | |
82 | 106 | | |
83 | 107 | | |
| |||
123 | 147 | | |
124 | 148 | | |
125 | 149 | | |
126 | | - | |
127 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
128 | 161 | | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
135 | 176 | | |
136 | | - | |
137 | | - | |
138 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
139 | 180 | | |
140 | 181 | | |
141 | 182 | | |
| |||
174 | 215 | | |
175 | 216 | | |
176 | 217 | | |
177 | | - | |
178 | | - | |
179 | | - | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
180 | 230 | | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
186 | 246 | | |
187 | | - | |
188 | | - | |
189 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
190 | 250 | | |
191 | 251 | | |
192 | 252 | | |
| |||
0 commit comments