Skip to content

proof(SafeJson): fix appendLengthInc so the module compiles (completes #138)#144

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/ecstatic-johnson-ViodM
May 31, 2026
Merged

proof(SafeJson): fix appendLengthInc so the module compiles (completes #138)#144
hyperpolymath merged 2 commits into
mainfrom
claude/ecstatic-johnson-ViodM

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

@hyperpolymath hyperpolymath commented May 30, 2026

Summary

Completes the work of #138, verified end-to-end against a clean Idris2 0.8.0 + contrib toolchain. Discharges the two SafeJson.Proofs OWEDs #138 targeted, and fixes the pre-existing bug that was actually preventing the module from compiling.

idris2 --check src/Proven/SafeJson/Proofs.idr builds all 5 modules (Core → Parser → Access → SafeJson → Proofs) with 0 errors (one pre-existing unreachable-clause warning in Access, also present on main).

What it discharges

  • anyMatchesTAny — 6-arm case-split on JsonValue; for each concrete head every earlier clause demands a non-TAny second argument, so each arm reduces to the catch-all matchesType _ TAny = True by Refl. No totality change needed.
  • singleKeyPathwith-pattern on lookup k obj, both arms by Refl (Maybe-identity).

The actual blocker: appendLengthInc (from #127)

Data.List.Equalities.lengthSnoc is element-first (lengthSnoc x xs), so the existing lengthSnoc arr v does not type-check under Idris2 0.8.0 contrib (Mismatch: JsonValue vs List ?a). Because it fails to elaborate, it blocks the entire SafeJson.Proofs module — so none of its proofs (including #138's two new ones) were checkable. Fixed to lengthSnoc v arr.

This is the failure #138's description attributed to "a local contrib quirk [that] does NOT reproduce in CI." It is not local — it reproduces on a clean v0.8.0 install, which also means main's own idris2 --build proven.ipkg currently fails at this module. This PR fixes that.

Correction to an earlier version of this PR

An earlier push on this branch also marked getPath/getSegment total and claimed that annotation was required for singleKeyPath to discharge. That claim was wrong and has been reverted. Verified: with appendLengthInc fixed, SafeJson.Proofs checks cleanly while those accessors stay covering (the %default in Access.idr). The covering annotation does not block the clause-level reduction the proof relies on, so no totality change is needed and Access.idr is left untouched. The change set is now Proofs.idr only.

Verification (clean idris2 0.8.0, contrib + network)

  • idris2 --check src/Proven/SafeJson/Proofs.idr — all 5 modules, 0 errors, Access left covering
  • ✅ Reverting the lengthSnoc fix reproduces the appendLengthInc Mismatch
  • ✅ Confirmed the total annotation is not needed (covering + fix compiles clean) — hence dropped
  • ✅ No believe_me / postulate / idris_crash / assert_total

Relationship to #138

#138 is closed; its branch already carries this same minimal fix. This PR (on the development branch) is the canonical, CI-running version.

Refs #138, #127, proven#90 #107 #119.


Generated by Claude Code

…LengthInc; make path accessors total

Completes the work of PR #138, verified end-to-end against a clean
Idris2 0.8.0 + contrib toolchain (idris2 --check builds all 5 SafeJson
modules with 0 errors).

Discharges two SafeJson.Proofs OWEDs:
- anyMatchesTAny: 6-arm case-split on JsonValue; each concrete head
  reduces through the catch-all `matchesType _ TAny = True` by Refl
  (matchesType stays `covering` — a concrete head per arm is enough).
- singleKeyPath: with-pattern on `lookup k obj`, both arms by Refl
  (Maybe-identity).

Two corrections PR #138 as-authored required but missed:

1. getPath / getSegment are made `total` in SafeJson.Access. They were
   `covering` via the module `%default covering` (contrary to the PR's
   claim that they were already total). Idris2 0.8.0 does not reduce
   `covering` definitions during proof conversion, so singleKeyPath
   cannot discharge while they remain covering — reverting the
   annotation reproduces the `singleKeyPath` Mismatch failure. Both are
   structurally total: getSegment is non-recursive, getPath decreases on
   the path list.

2. appendLengthInc (from PR #127) had its `lengthSnoc` arguments
   swapped. `Data.List.Equalities.lengthSnoc` takes the element first
   (`lengthSnoc x xs`), so `lengthSnoc arr v` does not type-check under
   Idris2 0.8.0 contrib. This pre-existing error blocks the entire
   SafeJson.Proofs module from compiling on main, so it had to be fixed
   for any of these proofs to be checkable. Corrected to `lengthSnoc v arr`.

No believe_me / postulate / idris_crash / assert_total introduced.

Refs #138, #127, proven#90 #107 #119.

https://claude.ai/code/session_01MN5vzRR4MK2dkDNaHqqRDy
…LengthInc fix

Aligns this branch with the verified-minimal change set (matching the fix
on #138's branch). Supersedes the previous commit, which marked
getPath/getSegment `total` and claimed that annotation was required for
singleKeyPath to discharge.

That claim was wrong. Verified against a clean Idris2 0.8.0 + contrib
toolchain: with appendLengthInc fixed, SafeJson.Proofs type-checks with
getPath/getSegment left `covering` (the module default) — 0 errors across
all five SafeJson modules. The covering annotation does not block the
clause-level reduction singleKeyPath relies on, so no totality change is
needed. Access.idr is therefore reverted to its main state (untouched).

The only substantive fix is the one this branch actually needs:
appendLengthInc used `lengthSnoc arr v`, but Data.List.Equalities.lengthSnoc
is element-first (`lengthSnoc x xs`); `lengthSnoc arr v` fails to
type-check under Idris2 0.8.0 contrib and blocks the whole module.
Corrected to `lengthSnoc v arr`. Proof comments for singleKeyPath and
anyMatchesTAny corrected to match (no false "they are total" claim), and
stale /tmp/ scratch-path references removed.

No believe_me / postulate / idris_crash / assert_total introduced.

Refs #138, #127, proven#90 #107 #119.

https://claude.ai/code/session_01MN5vzRR4MK2dkDNaHqqRDy
@hyperpolymath hyperpolymath changed the title proof(SafeJson): DISCHARGE anyMatchesTAny + singleKeyPath (completes #138; fixes appendLengthInc + path-accessor totality) proof(SafeJson): fix appendLengthInc so the module compiles (completes #138) May 31, 2026
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Owner Author

📌 Systemic finding (filing here — repo Issues are disabled). This PR fixes a one-line proof bug, but that bug reaching main points at a CI-gating gap worth tracking separately.

1. main currently fails idris2 --build proven.ipkg

appendLengthInc (introduced by #127) calls lengthSnoc arr v, but Data.List.Equalities.lengthSnoc is element-first (lengthSnoc : (x : a) -> (xs : List a) -> length (xs ++ [x]) = S (length xs)). So lengthSnoc arr v does not type-check:

Error: While processing right hand side of appendLengthInc. When unifying:
    JsonValue   and   List ?a
Mismatch between: JsonValue and List ?a.
Proven.SafeJson.Proofs:208:36--208:37

Since the module fails to elaborate, every proof in SafeJson.Proofs is currently unchecked on main. Reproduced on a clean Idris2 v0.8.0 + contrib install (the exact toolchain idris2-ci.yml provisions). The fix here (lengthSnoc v arr) makes all five SafeJson modules build with 0 errors.

2. The Idris build did not gate the merge (root cause)

The more important problem: a non-compiling change reached main because the Idris build check didn't block it. From #127:

So green SonarCloud + a fast manual merge let broken Idris through. The same queued-for-hours pattern is visible across recent proof PRs.

Suggested remediation

  1. Land this fix so main compiles again.
  2. Make build (0.8.0) (ideally also verify-idris-build) a required status check on main via branch protection. Until then, "merged green" ≠ "type-checks."
  3. Reduce Idris CI latency so requiring it is practical — confirm the actions/cache step is hitting; consider a fast cone-check gate (idris2 --check of just the changed module's closure, sub-minute) as the required job, with the full matrix non-blocking.

cc @hyperpolymath — flagging since Issues are disabled and this is broader than this PR.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Correction to my comment just above: repo Issues are not disabled — I've filed the systemic finding as #145. Please track the CI-gating discussion there; the comment above is superseded by that issue.


Generated by Claude Code

@hyperpolymath hyperpolymath merged commit a506884 into main May 31, 2026
11 of 24 checks passed
@hyperpolymath hyperpolymath deleted the claude/ecstatic-johnson-ViodM branch May 31, 2026 06:25
hyperpolymath pushed a commit that referenced this pull request May 31, 2026
…gating finding

- discharged-decls 34 -> 36 (anyMatchesTAny, singleKeyPath via #144)
- last-updated -> 2026-05-31
- session-history: appendLengthInc root cause (contrib lengthSnoc is
  element-first; #127's `lengthSnoc arr v` blocked the whole
  SafeJson.Proofs module) + the #145 CI-gating finding.

https://claude.ai/code/session_01MN5vzRR4MK2dkDNaHqqRDy
hyperpolymath added a commit that referenced this pull request May 31, 2026
#146)

Doc-only: STATE.a2ml discharged-decls 34->36, last-updated 2026-05-31, session-history note on appendLengthInc root cause + #145 CI-gating finding.
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 321 issues detected

Severity Count
🔴 Critical 130
🟠 High 31
🟡 Medium 160

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in casket-pages.yml",
    "type": "missing_timeout_minutes",
    "file": "casket-pages.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in cflite_batch.yml",
    "type": "missing_timeout_minutes",
    "file": "cflite_batch.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in cflite_pr.yml",
    "type": "missing_timeout_minutes",
    "file": "cflite_pr.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in codeql.yml",
    "type": "missing_timeout_minutes",
    "file": "codeql.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in dogfood-gate.yml",
    "type": "missing_timeout_minutes",
    "file": "dogfood-gate.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 31, 2026
## Summary

Addresses the source-fixable half of #145. Adds a dedicated
**`proof-check`** job to `idris2-ci.yml` that type-checks **every**
`src/**/Proofs.idr` (glob-discovered, so new proof files are
auto-covered) with `idris2 -p contrib -p network --check`, running in
parallel with the slow full `build`.

## Why

#127's swapped-arg `appendLengthInc` (`lengthSnoc arr v` — but contrib
`lengthSnoc` is element-first) failed to type-check and blocked the
**entire** `SafeJson.Proofs` module, yet reached `main`. Two gaps let it
through:

1. The only job compiling proof modules was the full `idris2 --build
proven.ipkg` (~12-20 min warm) — manual merges routinely outrace it
while it sits `queued`.
2. The explicit per-module `--check` list in `idris2-ci.yml` covered
**zero** `Proofs.idr` files — exactly the modules the Phase-3 discharge
campaign edits each PR.

## What it does

- New `proof-check` job: globs `find src -name 'Proofs.idr'`, checks
each, emits `::error file=…::` annotations, fails if any fail.
- Caches only the Idris2 compiler; **never** `idris2 --install
proven.ipkg`, **never** caches `build/` — so a stale cache cannot mask a
source-level break.
- Documents the decision as **ADR-004** in `META.a2ml`.

## Remaining (admin, tracked in #145)

This job is necessary but not sufficient. Closing the gate needs
`proof-check` made a **required status check** on `main` via branch
protection — only the repo admin can toggle that. Until then, "merged"
still doesn't imply "CI passed" under the solo-admin-merge posture.

## Verification

- Both files parse (`yaml.safe_load` → jobs `build, proof-check, docs`;
`tomllib` → ADR-001..004).
- The `Proofs.idr` check loop was validated locally on a clean
idris2-0.8.0 + contrib install (SafeJson/SafeMath/SafeString proof
cones, 0 errors).
- This PR touches `idris2-ci.yml`, which is in the CI path filter — so
the new `proof-check` job runs on this PR and proves itself before
merge.

Refs #145, #144, #127.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MN5vzRR4MK2dkDNaHqqRDy)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants