Commit 48591a3
**Refs** hyperpolymath/standards#124 and hyperpolymath/standards#132.
**NOT Closes** — the 88 single-file `Safe*` modules without
`Proofs.idr`, and the ledger's named overclaim modules (SafeDigest
constant-time, SafeArchive, SafeCBOR, SafeLRU, SafeConsensus, …) remain
OWED under #132. This PR discharges only the named "stubs first"
CRITICAL recommendation.
Draft / human-gated. Build is the only oracle.
### What
`src/Proven/SafeDateTime/Proofs.idr` was a **5-line header-only stub** —
flagged CRITICAL in `PROOF-NEEDS.md` ("proof absence disguised as
presence") and named in the ledger's top recommendation:
> **Stubs first** — populate or delete the misleading `SafeCommand` /
`SafeDateTime` `Proofs.idr`; a stub is worse than an honest absence.
`SafeCommand` was discharged by proven#21; this PR discharges
`SafeDateTime`, **closing the audited stub class** (`PROOF-NEEDS.md`
honest-count `2 → 0`).
The new `Proofs.idr` ships three genuine, machine-checked theorems about
the actual `SafeDateTime` exported surface. `idris2 0.8.0 --check`
returns exit 0, `%default total` holds, and there are **no `believe_me`
/ `idris_crash` / `assert_*` / `%default partial` / holes**:
- **`daysInMonthLowerBound` / `daysInMonthUpperBound` /
`daysInMonthNonZero`** — `daysInMonth y m` is always in the
Gregorian-calendar band `28..31` (so non-zero — no degenerate month that
could underflow day arithmetic or an indexer). This is the concrete
content of the module's "overflow protection" claim. Per-month `Refl`,
plus a `with (isLeapYear y)` split for February.
- **`makeDateSound`** — soundness of the `makeDate` smart constructor:
> `makeDate y mn d = Just dt -> dateGuard dt.year dt.month dt.day =
True`
Proof inverts the `Maybe` do-block: `with (natToMonth mn)` (the
`Nothing` branch contradicts `Just dt` via `absurd`); then `with
(dateGuard y m d) proof gEq`. The `True` branch fixes `dt = MkDate y m
d` by `case prf of Refl =>`, transporting `gEq` onto `dt`'s own fields
by record-projection reduction. The `False` branch is again `Nothing =
Just dt`, absurd.
This is the **genuine content** of "validated via smart constructors" /
"safe parsing without exceptions" — `makeDate` cannot manufacture an
out-of-range date.
### Verification
```
$ export IDRIS2_PREFIX=/.../idris2/0.8.0
$ export IDRIS2_PACKAGE_PATH=$IDRIS2_PREFIX/idris2-0.8.0
$ cd src && idris2 --check Proven/SafeDateTime/Proofs.idr
1/6: Building Proven.Core
2/6: Building Proven.SafeDateTime.Types
3/6: Building Proven.SafeDateTime.Parse
4/6: Building Proven.SafeDateTime.Zones
5/6: Building Proven.SafeDateTime
6/6: Building Proven.SafeDateTime.Proofs
$ echo $?
0
```
`Proven.SafeDateTime.Proofs` is already enumerated in `proven.ipkg`, so
the new body builds in CI alongside the rest of the library.
### Ledger update
`PROOF-NEEDS.md`:
- "Honest counts" stub-count `2 → 0` (both audited stubs discharged:
SafeCommand by proven#21, SafeDateTime by this PR).
- "Stubs — proof absence disguised as presence (CRITICAL)" table
reframed as historical/closed.
- Priority list item #1 ("Stubs first") marked done for the audited set.
The rest of #132 (88 single-file `Safe*` modules without `Proofs.idr`;
ledger-named security overclaims SafeDigest constant-time, SafeArchive,
SafeCBOR, SafeLRU, SafeConsensus, etc.; sibling-audited
SafeMCP/SafeOAuth/SafeWebAuthn/SafeWebSocket/SafeWebhook/SafeCapability/SafeAttestation/SafeJWK/SafeSecretShare
class) is untouched and remains OWED — hence **NOT Closes #132**.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 536d9e4 commit 48591a3
2 files changed
Lines changed: 135 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
| 151 | + | |
152 | 152 | | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
157 | 160 | | |
158 | 161 | | |
159 | 162 | | |
160 | | - | |
161 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
162 | 167 | | |
163 | 168 | | |
164 | 169 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
4 | 22 | | |
5 | 23 | | |
6 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
0 commit comments