Skip to content

Commit 30bb43f

Browse files
committed
proof(SafeJson): fix appendLengthInc lengthSnoc arg order so the module compiles
Makes this branch type-check under a clean Idris2 0.8.0 + contrib toolchain. `idris2 --check src/Proven/SafeJson/Proofs.idr` now builds all five SafeJson modules (Core, Parser, Access, SafeJson, Proofs) with 0 errors (one pre-existing unreachable-clause warning in Access remains). The two discharges this branch adds (anyMatchesTAny via 6-arm split, singleKeyPath via with-pattern) are correct, but the module did not compile because of a pre-existing bug carried in from #127: appendLengthInc used `lengthSnoc arr v`, but Data.List.Equalities.lengthSnoc is element-first (`lengthSnoc x xs`). Under Idris2 0.8.0 contrib this fails to type-check (Mismatch: JsonValue vs List ?a) and blocks the ENTIRE SafeJson.Proofs module, so none of its proofs were checkable. Corrected to `lengthSnoc v arr`. This is the failure the PR 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. Also corrects two proof comments to match what the compiler actually accepts and removes stale /tmp/ scratch-path references: - singleKeyPath: getPath/getSegment are `covering` (via the `%default covering` in SafeJson.Access), not total. That annotation does not block the clause-level reduction the proof relies on, so they are left covering and the proof still goes through (verified). - anyMatchesTAny: the six-arm split needs no totality change. No believe_me / postulate / idris_crash / assert_total introduced. Refs #127, proven#90 #107 #119. https://claude.ai/code/session_01MN5vzRR4MK2dkDNaHqqRDy
1 parent 007f44c commit 30bb43f

1 file changed

Lines changed: 22 additions & 20 deletions

File tree

src/Proven/SafeJson/Proofs.idr

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,18 @@ prependLengthInc v arr = Refl
198198
||| DISCHARGED: `append v (JsonArray arr) = JsonArray (arr ++ [v])`
199199
||| (SafeJson.idr L233-234), so the goal reduces to
200200
||| `Just (length (arr ++ [v])) = Just (length arr + 1)`. Apply
201-
||| `lengthSnoc arr v : length (arr ++ [v]) = S (length arr)`, then
201+
||| `lengthSnoc v arr : length (arr ++ [v]) = S (length arr)`, then
202202
||| close the `S n` vs `n + 1` gap with `plusCommutative 1 n`.
203+
||| (`Data.List.Equalities.lengthSnoc` takes the element first, then the
204+
||| list — `lengthSnoc x xs`; the previous `lengthSnoc arr v` argument
205+
||| order did not type-check under Idris2 0.8.0 contrib and blocked the
206+
||| whole module from compiling.)
203207
public export
204208
appendLengthInc : (v : JsonValue) -> (arr : List JsonValue) ->
205209
arrayLength (append v (JsonArray arr)) =
206210
Just (length arr + 1)
207211
appendLengthInc v arr =
208-
cong Just (trans (lengthSnoc arr v) (plusCommutative 1 (length arr)))
212+
cong Just (trans (lengthSnoc v arr) (plusCommutative 1 (length arr)))
209213

210214
--------------------------------------------------------------------------------
211215
-- Path Access Properties
@@ -218,16 +222,15 @@ emptyPathIdentity v = Refl
218222

219223
||| DISCHARGED: a single-segment `Key k` path equals direct `lookup`:
220224
||| `getPath [Key k] (JsonObject obj) = lookup k obj`.
221-
||| The OWED comment claimed `getPath`/`getSegment` are `covering`
222-
||| (which would block reduction), but inspection of the current
223-
||| `Proven.SafeJson.Access` source shows neither carries the
224-
||| annotation — they are total. Discharge proceeds:
225-
||| getPath [Key k] (JsonObject obj)
226-
||| = case getSegment (Key k) (JsonObject obj) of {Nothing => Nothing; Just v => getPath [] v}
227-
||| = case lookup k obj of {Nothing => Nothing; Just v => Just v}
228-
||| `with`-pattern on `lookup k obj` discharges both arms by `Refl`
229-
||| (Maybe-identity). Empirically verified at
230-
||| `/tmp/charrefl/src/TestJsonPath.idr`.
225+
||| On the concrete spine `[Key k]` / `JsonObject obj`, `getPath` and
226+
||| `getSegment` reduce by clause-matching to
227+
||| case lookup k obj of { Nothing => Nothing; Just v => Just v }
228+
||| Abstracting `lookup k obj` with a `with`-pattern then closes both
229+
||| arms by `Refl` (Maybe-identity).
230+
||| (`getPath`/`getSegment` are `covering` via the `%default covering`
231+
||| in `Proven.SafeJson.Access`; that annotation does not block this
232+
||| clause-level reduction, so they are left covering and the proof
233+
||| still goes through.)
231234
public export
232235
singleKeyPath : (k : String) -> (obj : List (String, JsonValue)) ->
233236
getPath [Key k] (JsonObject obj) = lookup k obj
@@ -327,14 +330,13 @@ stringMatchesTString s = Refl
327330
||| DISCHARGED: every `JsonValue` matches `TAny`:
328331
||| `matchesType v TAny = True` for all `v`.
329332
||| Definitionally `matchesType _ TAny = True` (`SafeJson.idr` L353).
330-
||| The OWED comment claimed the covering-vs-total policy blocks
331-
||| reduction on an abstract `v`, but in practice the manual
332-
||| six-arm case-split it suggested (`JsonNull` / `JsonBool b` /
333-
||| `JsonNumber n` / `JsonString s` / `JsonArray arr` /
334-
||| `JsonObject pairs`) works: each concrete-constructor arm
335-
||| reduces through the catch-all `matchesType _ TAny = True`
336-
||| clause by `Refl`. Empirically verified at
337-
||| `/tmp/charrefl/src/TestJson.idr`.
333+
||| Discharged by a six-arm case-split on `v` (`JsonNull` / `JsonBool b`
334+
||| / `JsonNumber n` / `JsonString s` / `JsonArray arr` /
335+
||| `JsonObject pairs`): `matchesType _ TAny = True` is a catch-all, and
336+
||| for each concrete head every earlier clause demands a non-`TAny`
337+
||| second argument, so each arm reduces to the catch-all and closes by
338+
||| `Refl`. No totality change is needed — a concrete head per arm is
339+
||| sufficient even though `matchesType` is `covering`.
338340
public export
339341
anyMatchesTAny : (v : JsonValue) -> matchesType v TAny = True
340342
anyMatchesTAny JsonNull = Refl

0 commit comments

Comments
 (0)