Skip to content

Commit 3311ad9

Browse files
claudehyperpolymath
authored andcommitted
proof(types): lift type_preservation past τ=int to the int-represented family {int,hex,binary}
The Int-only evaluation model means hex and binary share the same runtime carrier as int (they ARE int-represented), so an evaluated Int legitimately inhabits any of the three. Generalise type_preservation accordingly: - TypedValue gains `hex` / `binary` constructors alongside `int`. - New `JtvType.isIntRepr` predicate picks out {int, hex, binary}. - type_preservation is now (hτ : τ.isIntRepr) → TypedValue (evalDataExpr e σ) τ proved by `cases τ <;> first | exact .int/.hex/.binary | simp only [isIntRepr] at hτ`. - type_preservation_int recovers the original `τ = int` statement as a corollary. `#print axioms` ⇒ both theorems depend on no axioms. Verified locally under the pinned leanprover/lean4:v4.12.0 toolchain: full `lake build` exit 0, 0 sorry/admit/axiom, 0 True-typed theorems. float/rational/complex/symbolic remain stated-unproven at the value level (distinct carriers; each needs its own value model). Docs synced: PROOF-CAPABILITY-MATRIX (scope + key-theorems row + re-verified note), ADR-0007 consequence, ADR-0010 §gap-005/§Open, STATE.a2ml. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJmfoz1ZS1Pejy9LLMY742
1 parent 5d49228 commit 3311ad9

5 files changed

Lines changed: 87 additions & 27 deletions

File tree

.machine_readable/6a2/STATE.a2ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[metadata]
66
project = "jtv"
77
version = "0.0.1"
8-
last-updated = "2026-06-18"
8+
last-updated = "2026-06-21"
99
status = "active"
1010
session = "2026-06-18 — Surface Echo grades (ADR-0009 D1) + repo rename julia-the-viper→jtv. SURFACE ECHO: @echo(Safe|Neutral|Breaking) annotation on functions (grammar echo_marker + parser loop, order-independent with @pure); FunctionDecl.echo_annotation — the Echo enum moved ast.rs with an echo.rs `pub use` re-export to break the ast↔echo cycle; upper-bound check typechecker.rs check_echo_annotations (inferred ⊑ annotated, against the carrier-aware call-graph-composed effect.rs resolved_effects); pretty.rs + formatter.rs emit @echo (round-trip). 133 lib tests, fmt/clippy green. RENAME: full julia-the-viper→jtv slug + Julia the Viper→JtV prose across the repo (PR #47 merged) + nextgen-languages catalogue (#87 merged, rebuilt after main dropped all submodules); etymology kept as a README/CLAUDE footnote; the GitHub Settings repo-rename is the user's remaining manual step. NEXT rung: grade in TypeAnnotation::Function (function-valued params) [LANDED 2026-06-18, prefix-marker syntax] (the @epi(...) surface LANDED 2026-06-18); value-level semantics beyond τ=int (gap-005)"
1111

@@ -50,7 +50,7 @@ issues = [
5050
{ id = "gap-002", description = "typing_coercion in JtvTypes.lean weaker than docstring — proves existence not coercion to target type", severity = "low", status = "known", follow-up = "ADR needed" },
5151
{ id = "gap-003", description = "Coprocessor implementation gated on PataCL Phase 1", severity = "medium", status = "external-dependency" },
5252
{ id = "gap-004", description = "Reversibility round-trip not guaranteed end-to-end at integration level", severity = "medium", status = "known" },
53-
{ id = "gap-005", description = "Semantic model is Int-only: the 7 number systems are typed but stated-unproven at the value level; type_preservation mechanised only for τ=int (see ADR-0007 D6 + PROOF-CAPABILITY-MATRIX.adoc). PARTIAL 2026-06-18 (ADR-0010): per-system additive-algebra → Echo-tier CLASSIFICATION now landed at proof/type/value level (JtvEcho SECTION 6, echo.rs carrier_echo, number.rs Value::reversal_echo); the remaining open half is the type_preservation/round-trip SEMANTICS beyond τ=int", severity = "medium", status = "known", follow-up = "value-level semantics for τ≠int (the float-locals CarrierEnv inference gate landed 2026-06-18)" },
53+
{ id = "gap-005", description = "Semantic model is Int-only: the 7 number systems are typed but stated-unproven at the value level (see ADR-0007 D6 + PROOF-CAPABILITY-MATRIX.adoc). PARTIAL 2026-06-18 (ADR-0010): per-system additive-algebra → Echo-tier CLASSIFICATION landed at proof/type/value level (JtvEcho SECTION 6, echo.rs carrier_echo, number.rs Value::reversal_echo). PARTIAL 2026-06-21: type_preservation lifted past τ=int to the whole integer-represented family {int,hex,binary} (these share the Int carrier; generalised via JtvType.isIntRepr; type_preservation_int recovers τ=int; #print axioms ⇒ no axioms). Remaining open half: value-level semantics for the carrier-DISTINCT systems float/rational/complex/symbolic", severity = "medium", status = "known", follow-up = "value-level semantics for float/rational/complex/symbolic (need their own value carriers; int/hex/binary done 2026-06-21)" },
5454
{ id = "gap-006", description = "RESOLVED 2026-06-15: license decision = MPL-2.0 (code) + CC-BY-SA-4.0 (docs), full per-file. 75 doc headers -> CC-BY-SA-4.0; code stragglers (3 PMPL-1.0 workflows, MPL-2.0-or-later, PLMP/GPL typos, and a deliberate MIT-OR-GPL-3.0-or-later-OR-Palimpsest tri-license on formatter/repl/rsr_check) -> MPL-2.0; PALIMPSEST.adoc (both copies) retired; LICENSING.md rewritten; PMPL badges replaced. Follow-ups: populate LICENSES/ with canonical MPL-2.0 + CC-BY-SA-4.0 texts; add SPDX headers to ~49 header-less docs.", severity = "low", status = "resolved", follow-up = "LICENSES/ texts + header-less docs" }
5555
]
5656

@@ -91,7 +91,8 @@ sessions = [
9191
{ date = "2026-06-18", subject = "Float-locals soundness slice (typechecker carrier-aware gate). Echo admissibility is checked at the reverse-block site inside check_control_stmt, where self.env already holds the INFERRED types of params + prior local assignments — so typechecker.rs check_echo_admissible{,_with_residue} now build a CarrierEnv from self.env (Type→BasicType for the 7 numeric Types; non-numeric/Any omitted → default Int=Safe) and call echo::classify_stmts_in_env. Effect: a reverse{} over a float LOCAL (typed only by inference, e.g. x = 2.5) is correctly REJECTED under Safe-only (was wrongly Safe-admitted); reversible{}->tok still admits it (token retains the rounding residue). Contained change (no reordering, no new inference pass). 4 typechecker tests (float carrier rejected; inferred-float-local rejected end-to-end; int contrast ok; float reversible-tok admitted). ADR-0010 §Status/§Consequences/§Open updated (slice landed; remaining minor corner = carrier-awareness inside reversible-if branches). cargo fmt/clippy/test green (127 lib tests; cleared a clippy approx_constant deny on a 3.14 literal → 2.5). Whole-suite check: no existing test/example relied on a float reverse{} being accepted, so the stricter rule broke nothing." },
9292
{ date = "2026-06-18", subject = "Surface Echo grades (ADR-0009 D1) — Bundle A (parameterised syntax + upper-bound policy). @echo(Safe|Neutral|Breaking) annotation on functions: grammar.pest echo_marker = '@echo' '(' echo_grade ')' and function_decl markers now (purity_marker|echo_marker)*; parser.rs consumes leading markers in a loop (order-independent with @pure) → FunctionDecl.echo_annotation. The Echo enum moved echo.rs→ast.rs (gains Serialize) with a `pub use crate::ast::Echo` re-export in echo.rs to break the ast↔echo cycle so FunctionDecl can hold it; all `echo::Echo` sites unchanged. UPPER-BOUND check typechecker.rs check_echo_annotations (3rd pass of check_program): inferred ⊑ annotated against the carrier-aware call-graph-composed effect.rs resolved_effects — a function may declare MORE loss than it incurs, never less (modular: caller checks against callee's declared ceiling). The reverse-gate still uses the ACTUAL inferred grade, so an annotation can't loosen reversal soundness. pretty.rs + formatter.rs emit @echo after purity (round-trip fidelity, pinned by a pretty round_trip test). 6 new tests (2 parser incl. either-order, 3 typechecker accept/reject/absent, 1 round-trip); 133 lib tests, fmt/clippy green. effect.rs header note refreshed. REMAINING: grade in TypeAnnotation::Function (function-valued params) [LANDED 2026-06-18, prefix-marker syntax]; parallel @epi(...) surface." },
9393
{ date = "2026-06-18", subject = "@epi(...) epistemic-grade surface (ADR-0009 D2) — mirror of the @echo surface. @epi(Opaque|Partial|Transparent) annotation on functions: grammar.pest epi_marker; parser.rs marker loop also consumes epi_marker → FunctionDecl.epi_annotation (order-independent with @pure/@echo). Epistemic enum moved epistemic.rs→ast.rs (gains Serialize) with `pub use crate::ast::Epistemic` re-export, same cycle-break as Echo. typechecker.rs check_echo_annotations renamed check_effect_annotations: now checks BOTH axes (inferred.echo ⊑ @echo, inferred.epi ⊑ @epi) against resolved_effects (FunctionEffect carries .echo + .epi). pretty.rs + formatter.rs emit @epi after @echo. 5 new tests (parser @epi + echo&epi-together, typechecker epi accept/reject, round-trip); 138 lib tests, fmt/clippy green. Completes the ADR-0009 D1+D2 function-DECLARATION effect surface. REMAINING on this axis: carry the (echo,epi) row in TypeAnnotation::Function (function-VALUED params) — has a function-type grade-syntax + variance design choice to settle." },
94-
{ date = "2026-06-18", subject = "Function-TYPE grade carrying (ADR-0009 D1/D3) — completes the ADR-0009 effect surface. A function type Fn(...) -> T may now carry the (echo,epi) row with PREFIX markers (user choice): @echo(Neutral) @epi(Partial) Fn(Int) -> Int. ast.rs: new EffectGrade { echo: Option<Echo>, epi: Option<Epistemic> } (Default); TypeAnnotation::Function gains a trailing EffectGrade; typechecker Type::Function likewise. grammar.pest function_type now (echo_marker|epi_marker)* ~ 'Fn' ...; parser splits the leading markers from the param/return type_annotations. annotation_to_type carries the grade into Type::Function; Display + pretty.rs + formatter.rs emit the prefix markers (round-trip). coercible_to gains a function-type case: COVARIANT in the grade (grade_leq — a function that loses/reveals LESS is usable where MORE is allowed; None target = unconstrained; None source can't satisfy a Some ceiling; params/return invariant for now). 4 tests (parse graded + ungraded; round-trip; covariance accept/reject/unconstrained); 142 lib tests, fmt/clippy green. HONEST SCOPE: representational/forward-infrastructure — JtV has no first-class function VALUES (no lambdas/indirect calls) yet, so the value-against-type coercion is correct but LATENT until function values land. ADR-0009 D1+D2+D3 declaration+type effect surface now COMPLETE." }
94+
{ date = "2026-06-18", subject = "Function-TYPE grade carrying (ADR-0009 D1/D3) — completes the ADR-0009 effect surface. A function type Fn(...) -> T may now carry the (echo,epi) row with PREFIX markers (user choice): @echo(Neutral) @epi(Partial) Fn(Int) -> Int. ast.rs: new EffectGrade { echo: Option<Echo>, epi: Option<Epistemic> } (Default); TypeAnnotation::Function gains a trailing EffectGrade; typechecker Type::Function likewise. grammar.pest function_type now (echo_marker|epi_marker)* ~ 'Fn' ...; parser splits the leading markers from the param/return type_annotations. annotation_to_type carries the grade into Type::Function; Display + pretty.rs + formatter.rs emit the prefix markers (round-trip). coercible_to gains a function-type case: COVARIANT in the grade (grade_leq — a function that loses/reveals LESS is usable where MORE is allowed; None target = unconstrained; None source can't satisfy a Some ceiling; params/return invariant for now). 4 tests (parse graded + ungraded; round-trip; covariance accept/reject/unconstrained); 142 lib tests, fmt/clippy green. HONEST SCOPE: representational/forward-infrastructure — JtV has no first-class function VALUES (no lambdas/indirect calls) yet, so the value-against-type coercion is correct but LATENT until function values land. ADR-0009 D1+D2+D3 declaration+type effect surface now COMPLETE." },
95+
{ date = "2026-06-21", subject = "type_preservation lifted past τ=int to the integer-represented family {int,hex,binary} (gap-005 partial). LOCAL LEAN TOOLCHAIN UNBLOCKED: elan 4.2.2 was present but had no toolchain, and `release.lean-lang.org` is off the egress allowlist (its 'Host not in allowlist' page is the stray 'H' that broke elan's release-metadata parse). Bypassed by fetching the v4.12.0 linux tarball straight from GitHub releases (github.com + the asset host ARE allowlisted) and unpacking it into ~/.elan/toolchains/leanprover--lean4---v4.12.0 — elan then recognises the pinned toolchain; full `lake build` exit 0 (suite is mathlib-free, zero packages, no network). PROOF (JtvTypes.lean SECTION 6): inductive TypedValue gains hex + binary constructors (all three number systems share the Int runtime carrier — hex/binary ARE int-represented); new predicate JtvType.isIntRepr {int,hex,binary}↦True else False; type_preservation generalised from `τ=int → …` to `(hτ : τ.isIntRepr) → TypedValue (evalDataExpr e σ) τ`, proved `cases τ <;> first | exact TypedValue.{int,hex,binary} | simp only [JtvType.isIntRepr] at hτ`; type_preservation_int corollary recovers the original τ=int statement (via subst + trivial). `#print axioms` ⇒ BOTH new theorems depend on NO axioms. INVARIANTS held: full lake build exit 0; 0 sorry/admit/axiom (word-boundary grep); 0 True-typed theorems. DOCS synced: PROOF-CAPABILITY-MATRIX (scope-of-model rewrite + new key-theorems row + 'checked 2026-06-04; re-verified 2026-06-21' note), ADR-0007 consequence #1, ADR-0010 §gap-005 + §Open. float/rational/complex/symbolic REMAIN stated-unproven (distinct carriers, each needs its own value model). NOTE for next session: the local toolchain at ~/.elan is ephemeral (container reclaimed on inactivity) — re-run the GitHub-releases bypass to restore `lake build`; CI (proof-regression.yml) is the durable verifier." }
9596
]
9697

9798
[design-artefact-locations]

docs/design-decisions/0007-addition-only-mandate-and-reversibility-tiering.adoc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,13 @@ basis for the v2 `(c)` Neutral bridge and the number-system → tier map.
171171

172172
. *Number-system semantics work (next-but-one priority).* The Lean model
173173
is currently `Int`-only (`evalDataExpr : DataExpr → State → Int`);
174-
the seven systems are *typed* but `stated-unproven` at the value
175-
level, and `type_preservation` is mechanised only for `τ = int`. The
176-
semantics layer must (a) give each system a value model, (b) classify
177-
each by its additive algebra → Echo tier per D6, and (c) keep
178-
addition-only (D1) — `×`/`÷` generated, not primitive.
174+
the carrier-distinct systems (`float`/`rational`/`complex`/`symbolic`)
175+
are *typed* but `stated-unproven` at the value level. `type_preservation`
176+
is mechanised for the whole *integer-represented family* `{int, hex,
177+
binary}` (these share the `Int` carrier; generalised via `isIntRepr`,
178+
zero axioms). The semantics layer must (a) give each remaining system a
179+
value model, (b) classify each by its additive algebra → Echo tier per
180+
D6, and (c) keep addition-only (D1) — `×`/`÷` generated, not primitive.
179181
. *v2 "(c)" bridge (LANDED 2026-06-15).* Implements the Neutral tier of
180182
D5: `reverse { }` stays Safe-only; `reversible { } -> tok` admits
181183
Neutral via the retained log/token (Bennett). Lean: `JtvEcho`

docs/design-decisions/0010-number-system-stratification.adoc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ The algebra -> tier map has a single home and is mirrored, not duplicated:
137137
residue). Closes the gap this ADR previously flagged.
138138
. *`gap-005` partially addressed:* the seven systems are now *classified* by
139139
additive algebra at type and value level. The orthogonal half — lifting
140-
`type_preservation` semantics beyond `τ = int` — remains open.
140+
`type_preservation` semantics beyond `τ = int` — is now done for the whole
141+
*integer-represented family* `{int, hex, binary}` (hex/binary share the `Int`
142+
carrier, so the generalised `type_preservation` covers them via `isIntRepr`;
143+
zero axioms). It remains open for `float`/`rational`/`complex`/`symbolic`,
144+
which need their own value models.
141145

142146
== Open / deferred
143147

@@ -150,7 +154,8 @@ The algebra -> tier map has a single home and is mirrored, not duplicated:
150154
(idempotent) system is added, give it its `NumAlgebra` level and the
151155
Neutral/Breaking tier follows; no spine re-proof.
152156
* *Value-level semantics (`gap-005`).* `type_preservation` / round-trip proofs
153-
for `τ ≠ int`.
157+
for the carrier-distinct systems `float`/`rational`/`complex`/`symbolic`
158+
(the int-represented family `{int, hex, binary}` is now covered).
154159

155160
== References
156161

jtv_proofs/JtvTypes.lean

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -420,20 +420,63 @@ theorem total_no_loops (s : ControlStmt) (h : s.respectsPurity Purity.total = tr
420420
-- SECTION 6: TYPE SOUNDNESS
421421
-- ============================================================================
422422

423-
/-- Typed values: runtime values with their types -/
423+
/-- Typed values: runtime values with their types.
424+
425+
`int`, `hex`, and `binary` share the same `Int` runtime carrier —
426+
hex and binary are int-represented (see `JtvType`) — so an evaluated
427+
`Int` legitimately inhabits any of the three. The remaining number
428+
systems (`float`/`rational`/`complex`/`symbolic`) have distinct
429+
runtime carriers that the `Int`-only evaluation model does not build,
430+
so they are deliberately absent here (see PROOF-CAPABILITY-MATRIX
431+
§"Scope of the semantic model"). -/
424432
inductive TypedValue : Int → JtvType → Prop where
425-
| int : ∀ n, TypedValue n JtvType.int
433+
| int : ∀ n, TypedValue n JtvType.int
434+
| hex : ∀ n, TypedValue n JtvType.hex
435+
| binary : ∀ n, TypedValue n JtvType.binary
436+
437+
/-- The integer-represented type family: exactly the `JtvType`s whose
438+
runtime values are plain `Int`s (`int`, `hex`, `binary`). These are
439+
the types for which `type_preservation` holds under the `Int`-only
440+
evaluation model. -/
441+
def JtvType.isIntRepr : JtvType → Prop
442+
| JtvType.int => True
443+
| JtvType.hex => True
444+
| JtvType.binary => True
445+
| _ => False
426446

427447
/--
428-
**Theorem (Type Preservation)**:
429-
If Γ ⊢ e : τ and e evaluates to v, then v has type τ.
448+
**Theorem (Type Preservation, integer-represented family)**:
449+
If `Γ ⊢ e : τ` with `τ` an integer-represented type (`int`, `hex`, or
450+
`binary`) and `e` evaluates to `v`, then `v` has type `τ`. Because the
451+
three int-represented types share the `Int` carrier, the evaluated
452+
value inhabits whichever of them the type system assigned.
453+
454+
This lifts the previous `τ = int` mechanisation to the full int-
455+
represented family; `float`/`rational`/`complex`/`symbolic` remain
456+
`stated-unproven` at the value level pending their own evaluation
457+
models (they do not share the `Int` carrier).
430458
-/
431459
theorem type_preservation (Γ : TypeEnv) (e : DataExpr) (τ : JtvType) (σ : State)
432-
(_h : DataTyping Γ e τ) :
433-
-- For integer types, the result is an integer
460+
(_h : DataTyping Γ e τ) (hτ : τ.isIntRepr) :
461+
TypedValue (evalDataExpr e σ) τ := by
462+
cases τ <;>
463+
first
464+
| exact TypedValue.int (evalDataExpr e σ)
465+
| exact TypedValue.hex (evalDataExpr e σ)
466+
| exact TypedValue.binary (evalDataExpr e σ)
467+
| simp only [JtvType.isIntRepr] at hτ
468+
469+
/--
470+
**Corollary**: the original `τ = int` preservation statement, recovered
471+
from the int-represented-family theorem. Kept so the `int`-only claim
472+
remains directly citable.
473+
-/
474+
theorem type_preservation_int (Γ : TypeEnv) (e : DataExpr) (τ : JtvType) (σ : State)
475+
(h : DataTyping Γ e τ) :
434476
τ = JtvType.int → TypedValue (evalDataExpr e σ) JtvType.int := by
435-
intro _hτ
436-
exact TypedValue.int (evalDataExpr e σ)
477+
intro hτ
478+
subst hτ
479+
exact type_preservation Γ e JtvType.int σ h trivial
437480

438481
/--
439482
**Theorem (Progress for Typed Terms)**:

0 commit comments

Comments
 (0)