Skip to content

Commit e38fea2

Browse files
hyperpolymathclaude
andcommitted
feat(tg-3): OCaml typecheck.ml refines Lean HasType (translation validation)
Discharge TG-3 at the translation-validation level. Via TG-2 (infer ≡ HasType), refinement reduces to "OCaml infer_expr ≡ Lean infer on the core fragment", established by three layers: - Closure proof: the core fragment never yields TTangle under infer_expr (strengthened entire-type-tree IH; `close` is the sole boundary gateway, excluded). Write-up in proofs/TG3-REFINEMENT.md. - Machine-checked half: proofs/TG3Differential.lean — 496 obligations `infer [] e = <infer_expr e> := by decide`, GENERATED from the OCaml checker by compiler/test/tg3/tg3_emit.ml and kernel-verified by Lean's proven infer. New proofs/check-tg3-differential.sh, wired into lean-proofs.yml. - OCaml half: compiler/test/tg3 --check (dune runtest) — 1008 assertions (closure invariant, curated pins, named->de Bruijn translation incl. let-shadowing, and the OCaml side of every divergence). Complete divergence catalogue (both sides pinned): D1 close (OCaml Tangle[I,I] vs Lean word 0) + downstream family D1b pipeline(close,close), D1c compose(braid,close) [OCaml rejects], D1d add(close,close); D2 bool==bool (OCaml extra-core convenience, Lean rejects). Not claimed: a universal Lean theorem over all OCaml runs (would require reflecting typecheck.ml); extra-core features are excluded, not modelled; refinement is OCaml->Lean only. dune runtest green (597 existing + tg3 1008); proofs/check-tg3-differential.sh 0 errors. Docs updated: PROOF-NEEDS, PROOF-NARRATIVE, echo-types-ocaml-pipeline, CHANGELOG, STATE.a2ml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9544fe6 commit e38fea2

11 files changed

Lines changed: 1297 additions & 51 deletions

File tree

.github/workflows/lean-proofs.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,13 @@ jobs:
8585
exit 1
8686
fi
8787
echo "No sorry/axiom/admit/Admitted found outside comments."
88+
89+
- name: Verify TG-3 translation-validation obligations
90+
run: |
91+
set -euo pipefail
92+
# TG3Differential.lean is generated from OCaml `infer_expr` (see
93+
# compiler/test/tg3/tg3_emit.ml) and asserts OCaml ≡ Lean `infer`
94+
# on the core fragment. This builds Tangle to an .olean and
95+
# kernel-checks every obligation (the machine-checked half of TG-3;
96+
# argument half in proofs/TG3-REFINEMENT.md).
97+
bash proofs/check-tg3-differential.sh

.machine_readable/6a2/STATE.a2ml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ project = "tangle"
77
version = "0.2.0-dev"
88
last-updated = "2026-06-14"
99
status = "active"
10-
session = "echo-threading EchoClosed node + adversarial audit follow-up (verbatim residue, Eq tightening, --compile-pd wiring, surface echo test coverage) — 2026-06-14"
10+
session = "TG-3 LANDED — OCaml typecheck.ml refines Lean HasType (translation validation): closure proof + 496 Lean-kernel-checked obligations (proofs/TG3Differential.lean, generated from infer_expr by compiler/test/tg3/tg3_emit.ml) + 1008 OCaml --check assertions; divergences D1 close / D2 bool-eq catalogued; write-up proofs/TG3-REFINEMENT.md — 2026-06-14"
1111

1212
[project-context]
1313
name = "Tangle"
@@ -34,21 +34,21 @@ milestones = [
3434
"DONE: thread echo residue into the OCaml compositional IR — EchoClosed node (verbatim residue) in compositional.ml; echo_skein_sink + residue_blob; --compile-pd CLI; cross-repo TangleIR contract at ECHO-TANGLEIR-THREADING.md (Julia KRLAdapter.jl/quandledb still pending)",
3535
"DONE: full OCaml echo pipeline (ast/typecheck/eval/parser/pretty) — PR #45; build fixed PR #46",
3636
"DONE (TG-9): LSP diagnostics ⊆ HasType failures — tangle-lsp delegates to `tanglec --check` (compiler/lib/check.ml); hand-rolled LSP-only diagnostics removed; subset by construction",
37-
"LATER (TG-3): OCaml typecheck.ml refines the Lean HasType spec",
38-
"LATER (TG-5/6/7): compositional rewriter preservation; WASM semantic preservation; braid-group eqBraids",
37+
"DONE (TG-3): OCaml typecheck.ml refines Lean HasType (translation validation) — closure proof + proofs/TG3Differential.lean (496 by-decide obligations generated from infer_expr) + compiler/test/tg3 (1008 --check assertions) + proofs/check-tg3-differential.sh wired into lean-proofs.yml; divergences D1 close / D2 bool-eq; proofs/TG3-REFINEMENT.md",
38+
"LATER (TG-5/6/7/8): compositional rewriter preservation; WASM semantic preservation; braid-group eqBraids; dialect conservativity",
3939
]
4040

4141
[blockers-and-issues]
4242
issues = []
4343

4444
[critical-next-actions]
4545
actions = [
46-
"TG-3: formal refinement proof — OCaml typecheck.ml vs Lean HasType",
46+
"TG-5 (next): compositional.ml rewriter preserves types — OCaml property test over compile→PD invariants (test_compositional.ml exists)",
4747
"TangleIR Julia: implement EchoClosed node in KRLAdapter.jl per contract (quandledb session)",
4848
"echo-types grade semiring: monitor experimental/echo-additive comparative protocol; no Tangle action until protocol terminates",
4949
]
5050

5151
[maintenance-status]
52-
last-run-utc = "2026-06-14T03:00:00Z"
52+
last-run-utc = "2026-06-14T14:00:00Z"
5353
last-result = "pass" # unknown | pass | warn | fail
54-
notes = "dune build + dune test (597/597) GREEN; lean Tangle.lean 0 errors; TG-1+TG-2 LANDED; TG-9 LANDED (LSP delegates diagnostics to tanglec --check via check.ml — subset by construction); type-error diagnostics now carry the def source line (def_line) + duplicate removed; echo-threading EchoClosed node DONE (verbatim residue, --compile-pd wired); Eq typecheck tightened to same-width words (matches tEqWord); echo-types f7a965f grade semiring experimental (firewalled)"
54+
notes = "dune build + dune test GREEN (incl. new compiler/test/tg3 --check: 1008 assertions); lean Tangle.lean 0 errors; proofs/check-tg3-differential.sh GREEN (496 TG3Differential.lean obligations kernel-checked, 0 errors); TG-1+TG-2+TG-3+TG-9+TG-10 LANDED; TG-3 = OCaml infer_expr refines Lean infer on the core fragment (translation validation), divergences D1 close / D2 bool-eq; echo-types f7a965f grade semiring experimental (firewalled)"

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
1313

1414
## [Unreleased]
1515

16+
### TG-3 LANDED: OCaml type checker refines the Lean spec (translation validation)
17+
18+
Proof obligation TG-3 — "`compiler/lib/typecheck.ml` refines the mechanised
19+
`HasType` spec" — is discharged at the translation-validation level. Full
20+
write-up, closure argument, type translation, divergence catalogue and
21+
extra-core feature list: `proofs/TG3-REFINEMENT.md`.
22+
23+
- **Reduction.** TG-2 proves Lean `infer ≡ HasType`, so TG-3 reduces to "OCaml
24+
`infer_expr` ≡ Lean `infer` on the shared core fragment".
25+
- **Closure proof.** The core fragment (literals, let/var, compose/tensor/
26+
pipeline, add, eq, and the echo/product ops — excluding `close` and the whole
27+
Tangle layer) is closed under `infer_expr`: it never produces a `TTangle`,
28+
under a strengthened *entire-type-tree* induction hypothesis (a Tangle must not
29+
hide inside a `TProd`/`TEcho` and leak out via `fst`/`snd`/`lower`/`residue`).
30+
- **Machine-checked half.** `proofs/TG3Differential.lean` — 496 obligations
31+
`infer [] <term> = <infer_expr result> := by decide`, **generated from the
32+
OCaml checker** by `compiler/test/tg3/tg3_emit.ml` and kernel-verified by
33+
Lean's *proven* `infer`. New `proofs/check-tg3-differential.sh` (builds the
34+
Tangle `.olean`, checks the obligations); wired into `lean-proofs.yml`.
35+
- **OCaml half.** `compiler/test/tg3/` runs `tg3_emit --check` under
36+
`dune runtest`: 1008 assertions over a 490-term corpus — closure invariant,
37+
curated type pins, named→de Bruijn translation (incl. `let`-shadowing), and the
38+
OCaml side of every divergence.
39+
- **Divergence catalogue (complete).** **D1** `close` (OCaml `Tangle[I,I]` vs
40+
Lean `Word[0]` — the sole core boundary gateway) and its downstream vectors
41+
D1b `pipeline(close,close)`, D1c `compose(braid,close)` (OCaml rejects), D1d
42+
`add(close,close)`; **D2** `bool == bool` (OCaml accepts as extra-core, Lean
43+
rejects). Both sides of each are pinned.
44+
- **Honest boundary.** Translation validation over a broad corpus plus a
45+
structural argument — not a single Lean theorem quantifying over all OCaml
46+
runs (that would require reflecting `typecheck.ml`). Refinement is OCaml→Lean.
47+
1648
### Proof documentation catch-up (TG-1, TG-2, echo-types design note)
1749

1850
Both TG-1 and TG-2 were already fully proved in `proofs/Tangle.lean` but not

PROOF-NARRATIVE.md

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,12 @@ live count — ~597 across 8 suites). The
196196
pre-PR #46 `main` did not compile due to two `Warning 8` exhaustiveness gaps
197197
(both fixed: `strand_type_of_ty` in `typecheck.ml`; debug token printer in `bin/main.ml`).
198198

199-
**TG-3 gap remains**: the OCaml typechecker is not yet proven to refine `HasType`;
200-
the correspondence is validated by the test suite, not by a formal translation.
199+
**TG-3 landed** (translation validation): the OCaml typechecker is proven to
200+
refine `HasType` on the core fragment — `proofs/TG3Differential.lean` emits 496
201+
obligations generated from `infer_expr` that Lean's proven `infer` kernel-checks,
202+
plus a closure proof and 1008 OCaml `--check` assertions. The two documented
203+
divergences are `close` (D1) and `bool == bool` (D2). See `proofs/TG3-REFINEMENT.md`
204+
and §TG-3 below.
201205

202206
## 2.7 Let-binding and decidability (TG-1 + TG-2)
203207

@@ -302,25 +306,40 @@ that `infer e = some τ ↔ HasType [] e τ`.
302306

303307
### TG-3 — OCaml impl refines the Lean spec
304308

305-
**Claim.** For every `e` accepted by `compiler/lib/typecheck.ml` with
306-
type `τ`, the Lean-level proposition `HasType [] e τ` holds (and
307-
conversely).
308-
309-
**Why valuable.** Bridges the metatheory (Lean) to the implementation
310-
(OCaml). Right now we have two systems claiming to be the same; the
311-
claim is unchecked.
312-
313-
**Assumptions.**
314-
- [[A-TG-3.1]] The OCaml AST in `compiler/lib/ast.ml` is in bijection
315-
with the Lean AST in `Tangle.lean`.
316-
- [[A-TG-3.2]] OCaml's `String.equal`, `Int.equal` etc. coincide with
317-
Lean's notions on the values used.
318-
319-
**How to discharge.** Two routes:
320-
1. _Translation validation._ Generate Lean witnesses from OCaml's
321-
typecheck results on a test corpus. Cheap but only empirical.
322-
2. _Refinement._ Mechanise the OCaml algorithm in Lean and prove
323-
equivalence to `HasType`. Expensive but airtight.
309+
**Status: LANDED** (2026-06-14, translation-validation level). Full write-up:
310+
`proofs/TG3-REFINEMENT.md`.
311+
312+
**Claim.** For every core-fragment `e` accepted by `compiler/lib/typecheck.ml`
313+
with type `τ`, the Lean-level proposition `HasType [] e (T τ)` holds (and
314+
conversely on rejection), where `T` is the type translation
315+
`TNum↦num … TWord n↦word n, TEcho↦echo, TProd↦prod`.
316+
317+
**Why valuable.** Bridges the metatheory (Lean) to the implementation (OCaml) —
318+
the two systems are now checked to be the same on the modelled fragment.
319+
320+
**How it was discharged.**
321+
1. **Reduction (via TG-2).** `infer_iff_hasType` gives `infer ≡ HasType`, so the
322+
claim becomes "OCaml `infer_expr` ≡ Lean `infer` on the core fragment".
323+
2. **Closure proof.** `infer_expr` keeps core terms inside the translatable types
324+
(never `TTangle`), under a strengthened *entire-type-tree* IH. `close` is the
325+
sole core gateway out of `T`'s domain and is excluded.
326+
3. **Machine-checked half.** `proofs/TG3Differential.lean` — 496 obligations
327+
`infer [] e = T(infer_expr e) := by decide`, generated from the OCaml checker
328+
by `compiler/test/tg3/tg3_emit.ml`, verified by `proofs/check-tg3-differential.sh`.
329+
4. **OCaml half.** `compiler/test/tg3` `--check`: 1008 `dune runtest` assertions
330+
(closure invariant, curated pins, named→de Bruijn translation, divergences).
331+
332+
**Divergences (complete).** D1 `close` (`Tangle[I,I]` vs `word 0`) + family
333+
D1b/c/d through pipeline/compose/add; D2 `bool == bool` (OCaml accepts, Lean
334+
rejects). Both sides pinned.
335+
336+
**Assumptions / boundary.**
337+
- [[A-TG-3.1]] The core OCaml AST/`ty` is in bijection with the Lean AST/`Ty`
338+
under `T` (`TTangle` has no image — handled by the closure proof).
339+
- Not claimed: a universal Lean theorem over all OCaml runs (route 2 below);
340+
extra-core features are excluded, not modelled; refinement is OCaml→Lean only.
341+
- Future route 2 (_airtight refinement_): mechanise the OCaml algorithm in Lean
342+
and prove equivalence to `HasType` — out of scope here (see §7 of TG3-REFINEMENT.md).
324343

325344
### TG-4 — Pretty-print/parse round-trip
326345

PROOF-NEEDS.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Cross-referenced to [PROOF-NARRATIVE.md §3](PROOF-NARRATIVE.md#3-remaining-obli
5555
|---|-----------|----------|--------|----------|--------|--------|
5656
| TG-1 | Extend Progress/Preservation/Determinism/TypeSafety to `let`-binding | TP | Lean 4 | P1 || **LANDED** (`proofs/Tangle.lean` §METATHEORY — `weakening`, `subst_preserves`; all four theorems cover `var`/`let`) |
5757
| TG-2 | Type checking is decidable: define `infer : Expr → Option Ty` proven equivalent to `HasType` | ALG | Lean 4 | P1 || **LANDED** (`proofs/Tangle.lean` §TG-2 — `infer`, `infer_sound`, `infer_complete`, `infer_iff_hasType`, `type_unique`, `decidableHasType`) |
58-
| TG-3 | OCaml `typecheck.ml` refines the Lean `HasType` spec | TP | Lean 4 + translation validation | P1 | 5d | NOT STARTED (partial alignment: `Eq` now enforces same-width words to match `tEqWord`; `Bool == Bool` is a deliberate extra-core feature outside the 26-rule fragment, like `match`/`weave`/`mirror`/`compute` — these must be excluded from or added to the modelled core before TG-3 can close) |
58+
| TG-3 | OCaml `typecheck.ml` refines the Lean `HasType` spec | TP | Lean 4 + translation validation | P1 | — | **LANDED** (translation-validation level — [`proofs/TG3-REFINEMENT.md`](proofs/TG3-REFINEMENT.md)). Reduced via TG-2 (`infer ≡ HasType`) to "OCaml `infer_expr` ≡ Lean `infer` on the core fragment", then discharged by: (a) a closure proof (core fragment never yields `TTangle`, strengthened tree-IH); (b) 496 Lean kernel-checked obligations in [`proofs/TG3Differential.lean`](proofs/TG3Differential.lean) generated from `infer_expr` by `compiler/test/tg3/tg3_emit.ml` (`by decide`; run `proofs/check-tg3-differential.sh`); (c) 1008 OCaml `--check` assertions (`dune runtest`). Complete divergence catalogue: **D1** `close` (OCaml `Tangle[I,I]` vs Lean `word 0` — sole boundary gateway, + downstream D1b/c/d) and **D2** `bool==bool` (OCaml accepts, Lean rejects). Extra-core feature list (model-later / declare-non-core) in TG3-REFINEMENT §3. Not claimed: a universal Lean proof over all OCaml runs (would require reflecting `typecheck.ml`); refinement is OCaml→Lean only |
5959
| TG-4 | Pretty-print/parse round-trip on closed values | INV | OCaml property test (cheap) | P2 | 4h | **LANDED** (PR #46 — OCaml property test in `compiler/test/test_roundtrip.ml`, 26-entry corpus including 8 echo/product constructors; 52 round-trip runs) |
6060
| TG-5 | `compositional.ml` (418 LoC) rewriter preserves types | TP | Lean 4 + OCaml test file | P2 | 3d | NOT STARTED (B6: no test file yet) |
6161
| TG-6 | WASM compilation preserves semantics (source eval ≡ wasm exec) | TP / ALG | Lean 4 bisimulation | P1 | 3w (research-grade) | NOT STARTED |
@@ -70,23 +70,25 @@ assumptions each rests on, see PROOF-NARRATIVE.md.
7070
## Scoping of the remaining obligations (2026-06-14)
7171

7272
Concrete approach, effort, risk, and dependencies for what is left after
73-
TG-0/1/2/4/9/10 landed. **Recommended order: TG-3 → TG-5 → TG-7 → TG-8 → TG-6.**
74-
75-
### TG-3 — OCaml `typecheck.ml` refines Lean `HasType` *(keystone, recommended next)*
76-
- **Key lever:** TG-2 already proves Lean `infer ≡ HasType`. So refinement
77-
reduces to **OCaml `infer_expr` agrees with Lean `infer` on the shared core
78-
fragment** — a cross-language differential check, not a fresh metatheorem.
79-
- **Approach:** translation-validation harness. Generate core-fragment terms,
80-
type each with OCaml `infer_expr` and with Lean `infer`, assert equal types
81-
(and equal accept/reject). Seed from existing corpora + a small generator.
82-
- **Honest boundary:** the OCaml checker is far larger than the 26-rule core
83-
(match, weave, compute, cap/cup, mirror/reverse/simplify, twist, pipeline,
84-
two-pass program typing, width inference, Bool-eq). Deliverable = refinement
85-
validated on the core fragment + an explicit "extra-core" feature list, each
86-
marked model-later or declare-non-core. A universal Lean proof is out of reach
87-
without modelling the OCaml program itself.
88-
- **Started:** `Eq` aligned to `tEqWord` this session. **Effort:** ~3–5d.
89-
**Risk:** med (scoping the fragment). **Deps:** TG-2.
73+
TG-0/1/2/3/4/9/10 landed. **Recommended order: TG-5 → TG-7 → TG-8 → TG-6.**
74+
75+
### TG-3 — OCaml `typecheck.ml` refines Lean `HasType` — ✅ **LANDED 2026-06-14**
76+
- **Key lever (used):** TG-2 proves Lean `infer ≡ HasType`, so refinement
77+
reduced to **OCaml `infer_expr` ≡ Lean `infer` on the shared core fragment**.
78+
- **Delivered:** (1) closure proof — the core fragment never yields `TTangle`
79+
under `infer_expr` (strengthened *entire-type-tree* IH; `close` is the sole
80+
boundary gateway, excluded); (2) machine-checked half — `proofs/TG3Differential.lean`,
81+
496 obligations `infer [] e = <infer_expr result> := by decide`, generated from
82+
the OCaml checker by `compiler/test/tg3/tg3_emit.ml`, kernel-verified by
83+
`proofs/check-tg3-differential.sh` (wired into `lean-proofs.yml`); (3) OCaml
84+
side — 1008 `dune runtest` assertions (closure invariant, curated pins, de
85+
Bruijn translation, divergence behaviours). Full write-up + extra-core list +
86+
divergence catalogue: `proofs/TG3-REFINEMENT.md`.
87+
- **Divergences (complete):** D1 `close` (Tangle[I,I] vs word 0) + family
88+
D1b/c/d; D2 `bool==bool` (OCaml accepts / Lean rejects). Both pinned both sides.
89+
- **Honest boundary:** translation validation over a broad corpus + a structural
90+
argument — NOT a universal Lean theorem over all OCaml runs (needs reflecting
91+
`typecheck.ml`). Extra-core features excluded, not modelled. OCaml→Lean only.
9092

9193
### TG-5 — `compositional.ml` rewriter preserves types *(cheap, do early)*
9294
- **Approach:** OCaml property test first — random compositional exprs →

compiler/test/tg3/dune

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; SPDX-License-Identifier: MPL-2.0
2+
; TG-3 translation-validation harness.
3+
; dune runtest -> runs ./tg3_emit.exe --check (OCaml-side invariants).
4+
; Regenerate the Lean obligation file (machine-checked half) with:
5+
; dune exec ./test/tg3/tg3_emit.exe -- --emit <abs>/proofs/TG3Differential.lean
6+
; then verify it with proofs/check-tg3-differential.sh.
7+
8+
(executable
9+
(name tg3_emit)
10+
(modules tg3_emit)
11+
(libraries tangle))
12+
13+
(rule
14+
(alias runtest)
15+
(deps tg3_emit.exe)
16+
(action (run ./tg3_emit.exe --check)))

0 commit comments

Comments
 (0)