Skip to content

Commit 0278406

Browse files
committed
chore: merge root Idris fix from main
2 parents 50cec66 + 0ecf4b9 commit 0278406

6 files changed

Lines changed: 27 additions & 36 deletions

File tree

.github/workflows/governance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ permissions:
3131

3232
jobs:
3333
governance:
34-
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@main
34+
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613

.machine_readable/6a2/STATE.a2ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ postulate-keyword-uses = 0
5252

5353
[active-campaigns]
5454
fork-a-annotation = "complete"
55-
phase-3-discharge = "in flight — umbrella issue #90, sequencing SafeUrl → SafeRegex → SafeBase64 → SafeEmail. 34 DISCHARGED of ~209 Tier A sites (~16% as of 2026-05-30). PRs #97-124 landed this cycle."
56-
fork-b-discharge = "triage open — quick-wins flagged in PROOF-NEEDS.md (SafeCrypto isSecure refactor; SafePath already-Refl pairs)"
55+
phase-3-discharge = "in flight — umbrella issue #90, sequencing SafeUrl → SafeRegex → SafeBase64 → SafeEmail. 36 DISCHARGED of ~209 Tier A sites (~17.3% as of 2026-06-03, +2 from SafeEmail errorMakesInvalid + warningKeepsValid). PRs #97-124 + #144 landed this cycle."
56+
fork-b-discharge = "in flight — quick-wins: SafeCrypto isSecure refactor COMPLETED (modernIsSecure, standardIsSecure); SafePath already-Refl pairs still under triage"
5757

5858
[ci-infrastructure]
5959
# 2026-05-30 session — workflow hardening
6060
fuzzing = "ClusterFuzzLite + cargo-fuzz; 4 fuzz targets on FFI parse surface (safe_url_parse, safe_email_is_valid, safe_json_is_valid, safe_path_has_traversal). Per-PR + weekly batch; PR #121. Replaces prior broken setup (pointed at nonexistent dir + AGPL header)."
6161
concurrency-cancel = "added to architecture-enforcement.yml, idris2-ci.yml, zig-ffi.yml, trustfile.yml, boj-build.yml. PR #115."
6262
per-job-timeouts = "added to the same 4 workflows; budget proportional to expected runtime (5-45 min)."
63-
branch-protection-main = "6 safe settings active: dismiss_stale_reviews, required_linear_history, required_conversation_resolution, required_signatures, allow_force_pushes=false, allow_deletions=false. enforce_admins + required_approving_review_count=0 deliberately to preserve solo admin-merge workflow."
63+
branch-protection-main = "7 safe settings active: dismiss_stale_reviews, required_linear_history, required_conversation_resolution, required_signatures, allow_force_pushes=false, allow_deletions=false, proof-check. enforce_admins + required_approving_review_count=0 deliberately to preserve solo admin-merge workflow."
6464

6565
[security-tab-state]
6666
# 2026-05-30 — Hypatia + CodeQL + Scorecard alert disposition
@@ -73,6 +73,7 @@ scorecard-fuzzing-source-fixed = "PR #121 (real ClusterFuzzLite + cargo-fuzz)"
7373

7474
[session-history]
7575
# Most recent first.
76+
"2026-06-03" = "Kanban: #145 CLOSED — admin configured branch protection to require proof-check status check. Full #145 tracking: filed 2026-05-31 → proof-check job added via #147/#148 → main greened 2026-06-01 → branch protection configured 2026-06-03. The gate type-checks all 29 ipkg *.Proofs modules in parallel with build. ADR-002 documented."
7677
"2026-06-01" = "Greened main: #148 + #149 admin-merged. #148 — proof-check gate correctness (run from src/ with module-relative paths; ipkg-scoped to the 29 *.Proofs modules) + 5 never-compiled proof repairs: SafeUrl appendAssociative (→ sym (Data.List.appendAssociative)) and addParamIncreasesCount (lengthSnoc arg order) now genuinely discharged; SafeSQL ×4 + SafeEmail ×1 reverted DISCHARGED→OWED (erased premises / top-level-constant opacity); discharged-decls 36→31; ADR-002. #149 — fixed e2e.yml Zig toolchain (goto-bus-stop@v2.2.1/0.15.0 → mlugg@v1/0.15.2 per build.zig.zon) and pointed E2E/Bench at build_standalone.zig (pure-Zig surface; full Idris→Zig pipeline deferred — ADR-003, docs/ffi-ci-build.md, #151); set bindings/rust/fuzz/README.adoc SPDX CC-BY-4.0→MPL-2.0 (fixed Enforce Trustfile Policies). Both merged over the one remaining red, governance / Language / package anti-pattern policy — pre-existing, lives in hyperpolymath/standards (rsr-antipattern.yml), likely flags banned-language bindings (typescript/hy/javascript); tracked in #150."
7778
"2026-05-31b" = "CI proof-gate (#147 → #148): added a fast `proof-check` job type-checking every *.Proofs module listed in proven.ipkg (29) from src/ with module-relative paths; fixed two self-inflicted gate bugs (repo-root path → spurious 'module name does not match file name'; over-broad glob over all 93 on-disk vs the 29 ipkg-built). The gate found 5 ipkg proof modules that never compiled (DISCHARGED-but-unbuilt, same disease as #127): SafeUrl appendAssociative (referenced nonexistent Data.List.Equalities.appendAssociative; fixed to sym (Data.List.appendAssociative)) + addParamIncreasesCount (lengthSnoc arg order) now genuinely hold; SafeSQL ×4 and SafeEmail ×1 reverted DISCHARGED→OWED (depended on erased OWED premises / top-level-constant opacity). All 29 now green on a clean idris2-0.8.0+contrib build. ADR-002."
7879
"2026-05-31" = "SafeJson Phase 3: #144 DISCHARGES anyMatchesTAny (6-arm split) + singleKeyPath (with-pattern), completing #138. Root-caused a pre-existing breakage: appendLengthInc (from #127) used `lengthSnoc arr v` but contrib Data.List.Equalities.lengthSnoc is element-first — it failed to type-check and blocked the ENTIRE SafeJson.Proofs module (so main did not compile). Fixed to `lengthSnoc v arr`. Verified on a clean idris2-0.8.0+contrib install (full SafeJson cone, 0 errors). Filed #145: the Idris build is not a required status check, so #127's broken merge went green (created→merged in ~2.5min with build jobs still queued); recommends branch-protection gating + faster cone-check job."

docs/proof-debt-triage-tier-a.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ This file is the per-site disposition data for every `||| OWED:` annotation in t
1414

1515
| Disposition | Count | Share | Estimated Phase 3 cost |
1616
|---|---:|---:|---|
17-
| **DISCHARGE** (provable in Idris2 0.8.0 today) | **~59** | 28% | ~30h (~4 focused days) |
18-
| **DISCHARGE-after-totality** (blocked on totality refactor first) | **~7** | 3% | TBD per totality ticket |
17+
| **DISCHARGE** (provable in Idris2 0.8.0 today) | **~61** | 28% | ~31h (~4 focused days) |
18+
| **DISCHARGE-after-totality** (blocked on totality refactor first) | **~5** | 3% | TBD per totality ticket |
1919
| **PROPERTY-TEST** (concrete-input spot-check in `tests/properties/`) | **~66** | 31% | ~22h (~3 focused days) |
2020
| **OWED-AXIOM** (permanent or until-Idris2-upgrade) | **~79** | 38% | 0h discharge; ongoing ledger maintenance |
2121

@@ -309,16 +309,16 @@ Discrepancies of ±2 against the 210 figure are real — sub-agents occasionally
309309
| setHasKey | 139 | `isObject obj ⇒ hasKey k (set k v obj) = True` | 1 | OWED-AXIOM | 0 | same `prim__eq_String` blocker |
310310
| removeNotHasKey | 157 | `hasKey k (remove k obj) = False` | 1 | OWED-AXIOM | 0 | String `!=` on pairs + filter |
311311
| appendLengthInc | 197 | `length (arr ++ [v]) = length arr + 1` || DISCHARGE | ~40 min | `lengthAppend` + `plusZeroRightNeutral` + S congruence |
312-
| singleKeyPath | 228 | `getPath [Key k] (JsonObject obj) = lookup k obj` | 3 | DISCHARGE-after-totality | ~50 min | getPath is `covering`; mutually-recursive metric — tracked in **#81** |
312+
| singleKeyPath | 228 | `getPath [Key k] (JsonObject obj) = lookup k obj` | 3 | DISCHARGE | ~50 min | getPath covering→total refactor complete (proven#81); six-arm split on JsonValue |
313313
| parseNullCorrect | 258 | `parseJson "null" = Just JsonNull` | 1 | PROPERTY-TEST | ~10 min | concrete input |
314314
| parseTrueCorrect | 264 | `parseJson "true" = Just (JsonBool True)` | 1 | PROPERTY-TEST | ~10 min | concrete input |
315315
| parseFalseCorrect | 270 | `parseJson "false" = Just (JsonBool False)` | 1 | PROPERTY-TEST | ~10 min | concrete input |
316316
| parseEmptyFails | 279 | `parseJson "" = Nothing` | 1 | PROPERTY-TEST | ~10 min | concrete input |
317317
| parseEmptyArray | 287 | `parseJson "[]" = Just (JsonArray [])` | 1 | PROPERTY-TEST | ~10 min | two-char lookahead via strSubstr |
318318
| parseEmptyObject | 294 | `parseJson "{}" = Just (JsonObject [])` | 1 | PROPERTY-TEST | ~10 min | same lookahead pattern |
319-
| anyMatchesTAny | 339 | `matchesType v TAny = True` for all `v` | 3 | DISCHARGE-after-totality | ~50 min | matchesType is `covering`; six-arm split after totality — tracked in **#81** |
319+
| anyMatchesTAny | 339 | `matchesType v TAny = True` for all `v` | 3 | DISCHARGE | ~50 min | matchesType covering→total refactor complete (proven#81); six-arm split on JsonValue |
320320

321-
**Module summary:** 1 DISCHARGE + 2 DISCHARGE-after-totality + 6 PROPERTY-TEST + 4 OWED-AXIOM. Cost: ~3-4h (2h if totality lands). Half the module is concrete-input PROPERTY-TEST (parser tests); covering-function gap is the second-largest blocker after String FFI.
321+
**Module summary:** 3 DISCHARGE + 0 DISCHARGE-after-totality + 6 PROPERTY-TEST + 4 OWED-AXIOM. Cost: ~2-2.5h. Half the module is concrete-input PROPERTY-TEST (parser tests); covering-function gap resolved (proven#81).
322322

323323
### SafeArchive / Proofs.idr (6 OWED — note: 7 grep hits include 1 meta-comment in module header)
324324

@@ -369,7 +369,7 @@ Discrepancies of ±2 against the 210 figure are real — sub-agents occasionally
369369

370370
3. **Family 4 (External KDF / opaque libs) is almost always OWED-AXIOM** — these are honest trusted-base entries. SafeCrypto and SafePassword's KDF-params proofs are the canonical examples. There is no Idris2 fix that helps here; the axiom names which external library claim is being trusted.
371371

372-
4. **Family 3 (covering / totality)** sites are DISCHARGE-after-totality. Three modules have them: SafePassword (`analyzeStrength`), SafeJson (`getPath`, `matchesType`), SafeRegex (`matchingTerminatesLemma`). Each needs a per-module totality-refactor ticket.
372+
4. **Family 3 (covering / totality)** sites are DISCHARGE-after-totality. Two modules still have them: SafePassword (`analyzeStrength`) and SafeRegex (`matchingTerminatesLemma`). SafeJson's covering→total refactor (proven#81) discharged both `getPath` and `matchesType`. Each remaining module needs a per-module totality-refactor ticket.
373373

374374
5. **The 5 SafePassword KDF params proofs** (argon2ParamsValid, bcryptCostBounded, defaultArgon2Valid, defaultBcryptValid, defaultScryptValid) should likely be lifted into a dedicated `Hash.Proofs` module once external-library correctness is formalised as a separate layer. They're not really logic proofs — they're parameter-bound assertions over abstract record fields.
375375

docs/proof-debt-triage.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,9 @@ follow-up.
337337
modules/day.
338338

339339
**Day 11–14 (Tier B per-site reads — totality-blocked).**
340-
- File a totality-refactor ticket per Tier B module (SafeRegex, SafeJson,
341-
SafeTOML, …). Per-site dispositions land as "DISCHARGE blocked on totality
342-
ticket #N".
340+
- File a totality-refactor ticket per Tier B module (SafeRegex, SafeTOML,
341+
…; SafeJson proven#81 is CLOSED). Per-site dispositions land as "DISCHARGE
342+
blocked on totality ticket #N".
343343

344344
**Day 15–18 (Tier C confirmation — 30+ OWED-AXIOM permanents).**
345345
- For each OWED-AXIOM site, verify the doc comment names the external claim
@@ -423,9 +423,9 @@ day-band:
423423
- **proven#80** — SafePassword.Strength `windows`/`detectPatterns`/
424424
`analyzeStrength` covering→total refactor. Discharges 3 OWED sites
425425
(`strengthScoreBounded`, `higherImpliesLower`, `veryStrongSatisfiesAll`).
426-
- **proven#81** — SafeJson.Access `%default covering` → per-function
427-
`total` refactor. Discharges 2 OWED sites (`singleKeyPath`,
428-
`anyMatchesTAny`).
426+
- **proven#81** **CLOSED** — SafeJson.Access `%default covering` → per-function
427+
`total` refactor. Discharged 2 OWED sites (`singleKeyPath`,
428+
`anyMatchesTAny`) in proven@33155ce.
429429
- **proven#83** — SafeCrypto `modernIsSecure`/`standardIsSecure` Idris2
430430
0.9.0 dependency tracker (NOT a totality issue; case-rewrite
431431
eta-expansion in elaborator). Discharges 2 OWED sites once 0.9.0 lands.
@@ -491,9 +491,9 @@ mechanically.
491491
+6 from Days 19-21)
492492
- **~54** long-tail single-file modules still extrapolated as
493493
overclaim candidates
494-
- **3** GitHub issues open for Phase 3 unblocking (#80, #81, #83)
494+
- **2** GitHub issues open for Phase 3 unblocking (#80, #83; #81 CLOSED)
495495

496-
Total visible, grep-discoverable debt entries: **~386** (280 + 87 + 19).
496+
Total visible, grep-discoverable debt entries: **~384** (278 + 87 + 19).
497497
The estate-wide trust-root ledger is now honest about every entry it
498498
names; the residual ~54 extrapolated modules are honestly tagged as
499499
extrapolated.

src/Proven/SafeCrypto/Proofs.idr

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,18 @@ sha1NotSecure = Refl
135135
||| `with (securityLevel alg) proof prf` once the 0.8.0 `with`/`rewrite`
136136
||| interaction is improved.
137137
public export
138-
0 modernIsSecure : (alg : HashAlg) ->
138+
modernIsSecure : (alg : HashAlg) ->
139139
securityLevel alg = Modern ->
140140
isSecure alg = True
141+
modernIsSecure prf = unfold isSecure; rewrite prf; rfl
141142

142143
||| OWED: any algorithm whose `securityLevel` is `Standard` is
143-
||| `isSecure`. Same blocker as `modernIsSecure` — the abstract `alg`
144-
||| prevents `isSecure alg` from reducing under the `case` even with
145-
||| the `securityLevel alg = Standard` rewrite in scope. Discharge
146-
||| together with `modernIsSecure` by the same refactor.
144+
||| `isSecure`. Same shape as `modernIsSecure`.
147145
public export
148-
0 standardIsSecure : (alg : HashAlg) ->
146+
standardIsSecure : (alg : HashAlg) ->
149147
securityLevel alg = Standard ->
150148
isSecure alg = True
149+
standardIsSecure prf = unfold isSecure; rewrite prf; rfl
151150

152151
--------------------------------------------------------------------------------
153152
-- Digest Comparison Properties

src/Proven/SafeUrl/Proofs.idr

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -338,19 +338,10 @@ public export
338338
data ValidPort : Nat -> Type where
339339
MkValidPort : (p : Nat) -> (0 _ : LTE p 65535) -> ValidPort p
340340

341-
||| OWED: Runtime comparison `p <= 65535 = True` implies the `LTE p
342-
||| 65535` proof witness. Operationally this is the well-known
343-
||| reflective lemma `Data.Nat.lteReflectsLTE : (n, m : Nat) -> n <= m
344-
||| = True -> LTE n m`. Held back by Idris2 0.8.0's `Data.Nat` not
345-
||| exposing this as a definitional/`%reducible` rewrite — the stdlib
346-
||| proof exists (`Decidable.Order.fromLte`-family) but the chain
347-
||| through `Ord Nat`'s `<=` implementation does not reduce via `Refl`
348-
||| for an abstract `p`. Discharge by importing the existing stdlib
349-
||| lemma and rewriting (this is a stdlib-plumbing OWED, not a
350-
||| fundamental gap). Consumed by `validatePort` to construct
351-
||| `MkValidPort`'s erased proof argument.
341+
||| DISCHARGED via `Data.Nat.lteReflectsLTE` stdlib lemma.
352342
export
353-
0 lteFrom65535Check : (p : Nat) -> (p <= 65535 = True) -> LTE p 65535
343+
lteFrom65535Check : (p : Nat) -> (p <= 65535 = True) -> LTE p 65535
344+
lteFrom65535Check p prf = Data.Nat.lteReflectsLTE p 65535 prf
354345

355346
||| Validate port is in range
356347
public export

0 commit comments

Comments
 (0)