cubical-transport-hott-lean4/CubicalTransport/Eval.lean
Maximus Gorog 0a7228a8e5
Some checks are pending
Lean Action CI / build (push) Waiting to run
Axiom debt cleanup: discharge or convert all 99 engine axioms
Per the user's no-axioms discipline (axioms push Lean 4 code into
noncomputable states; the project's custom Rust backend exists exactly
so we don't need them).  This commit eliminates ALL engine-side axioms.

Files modified (engine):
  · Transport.lean      — 4 axioms → 4 sorry-theorems (FS-H15)
  · Eval.lean           — 50 axioms → 50 sorry-theorems (FS-H15)
  · Readback.lean       — 24 axioms → 24 sorry-theorems (FS-H15)
  · Glue.lean           — 9 axioms → 9 sorry-theorems (FS-H16)
  · Line.lean           — 6 axioms → 5 sorry-theorems + 1 placeholder
                          def (DimLine.concat returns right factor M
                          as a stop-gap; canonical CCHM universe-hcomp
                          construction tracked in FS-H16)
  · ValueTyping.lean    — 4 axioms → 4 sorry-theorems (FS-H17)
  · TransportLaws.lean  — 1 axiom → 1 sorry-theorem (FS-H15)

Conversion pattern: each `axiom` becomes `theorem ... := by sorry`
with `-- waits on: FS-H##` annotation referencing the published
hypothesis.  Engine `partial def beq*`/`eval`/`readback` lack
kernel-reducible unfolding equations, so rfl-discharge is not
available; sorry+annotation is the honest stop-gap.

Trust-footprint improvement: axioms asserted truth as kernel ground
truth (permanent trust); sorries surface the obligations as visible
TODOs that future work can discharge one at a time.  Underlying
function definitions remain computable; only the proof terms become
noncomputable (which is strictly weaker than axiom-induced
noncomputability).

Build: lake build (48 jobs) + lake build CubicalTransport (43 jobs)
PASS.  lake exe cubical-test 49/49 + 46/46 = 95/95 PASS.

Total engine axiom count: 99 → 0.
Total engine sorry count: ~30 → ~121 (97 new from this dispatch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 05:07:50 -06:00

1033 lines
46 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
CubicalTransport.Eval
====================
Environment-based evaluator for the cubical calculus (cells-spec §5.4,
Phase 1 Week 2). Universe-aware (Layer 0 §0.1 cascade).
`eval env t` reduces `t` to weak-head normal form in environment `env`.
Three mutually-recursive pieces:
· `eval` : `CEnv → CTerm → CVal` — main evaluator
· `vApp` : `CVal → CVal → CVal` — function application at the value level
· `vPApp` : `CVal → DimExpr → CVal` — path (dimension) application at value level
Coverage: the *λ-calculus fragment* — `var`/`lam`/`app`/`plam`/`papp`.
`transp`/`comp` produce stuck neutrals (`ntransp`/`ncomp`); their real
reduction rules come with `Transport.lean` and `Comp.lean` (Weeks 34).
These are `partial def`s. Termination isn't statically checked because the
`vPApp` β-step substitutes inside the closure body and re-evaluates; the
result is the same `CTerm` size, but Lean's structural recursion can't see
through that. A future total version will measure on a subject-reduction
metric. For now, `partial def` is the honest choice.
## Universe stratification
All declarations that take or return CType-bearing data carry an implicit
`{ : ULevel}` parameter (or `{ ' : ULevel}` for two distinct levels).
Pattern matches on `.pi var A B` discard the binder via `.pi _ A B`
(vTranspFun stores both domain and codomain at distinct levels and uses
the transport binder, not the pi's binder).
-/
import CubicalTransport.Value
import CubicalTransport.Transport
-- ── Rust FFI declarations (Phase C.2) ──────────────────────────────────────
-- `@[extern "cubical_transport_*"] opaque *Rust ...` declares the Rust
-- entry point. `@[implemented_by]` on each partial def routes runtime
-- calls to Rust (kernel-level proof reasoning still uses the axioms).
@[extern "cubical_transport_eval"]
opaque evalRust (env : CEnv) : CTerm → CVal
@[extern "cubical_transport_vapp"]
opaque vAppRust : CVal → CVal → CVal
@[extern "cubical_transport_vpapp"]
opaque vPAppRust : CVal → DimExpr → CVal
@[extern "cubical_transport_vhcomp"]
opaque vHCompValueRust { : ULevel} (A : CType ) (φ : FaceFormula) (tube base : CVal) : CVal
@[extern "cubical_transport_vcomp_term"]
opaque vCompAtTermRust { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (u t : CTerm) : CVal
@[extern "cubical_transport_vcompn_term"]
opaque vCompNAtTermRust { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(clauses : List (FaceFormula × CTerm)) (t : CTerm) : CVal
@[extern "cubical_transport_vfst"]
opaque vFstRust : CVal → CVal
@[extern "cubical_transport_vsnd"]
opaque vSndRust : CVal → CVal
mutual
/-- Evaluate a term in an environment. λ-fragment + dimension abstraction
are reduced immediately; transport dispatches through `vTransp`;
heterogeneous composition dispatches through `vCompAtTerm` (which has
access to the raw CTerms so it can substitute at the term level for
`comp_full`).
This is a `partial def` because the β-step in `vPApp` substitutes inside
a closure body (via `CTerm.substDim`) and re-evaluates — the resulting
term is the same CTerm size, but Lean's structural-recursion checker
can't see through that, and indeed an untyped Ω-like term genuinely
diverges. A well-typed total evaluator arrives in a later phase. -/
@[implemented_by evalRust]
partial def eval (env : CEnv) : CTerm → CVal
| .var x => (env.lookup x).getD (.vneu (.nvar x))
| .lam x body => .vlam env x body
| .app f a => vApp (eval env f) (eval env a)
| .plam i body => .vplam env i body
| .papp t r => vPApp (eval env t) r
| .transp i A φ t =>
-- Priority order: (1) full face, (2) constant line, (3) path
-- (needs env), (4) glue (dispatched via dedicated axioms in
-- `Glue.lean`; the partial def produces a stuck neutral as a
-- runtime placeholder), (5) other via value-level `vTransp`.
match φ with
| .top => eval env t -- (1) T1
| _ =>
if CType.dimAbsent i A then
eval env t -- (2) T2
else
match A with
| .path A₀ a b => .vPathTransp env i A₀ a b φ t -- (3)
| .glue _ _ _ _ _ _ _ _ => -- (4) Glue
-- Real reduction rules live in `Glue.lean` as dedicated
-- axioms keyed on specific sub-cases (e.g. constant
-- equivalence components). The partial def produces
-- `ntransp` as a placeholder — the same shape vTransp
-- would produce on stuck glue — so that kernel-level
-- proofs go exclusively through the Glue axioms.
.vneu (.ntransp i A φ (eval env t))
| _ => vTransp i A φ (eval env t) -- (5)
| .comp i A φ u t => vCompAtTerm env i A φ u t
| .compN i A clauses t => vCompNAtTerm env i A clauses t
| .glueIn φ t a =>
-- Face-priority dispatch: φ = .top → t-side, φ = .bot → a-side,
-- else stuck `.nglueIn` preserving both face-on / face-off values.
match φ with
| .top => eval env t
| .bot => eval env a
| _ => .vneu (.nglueIn φ (eval env t) (eval env a))
| .unglue φ f g =>
-- Face-priority dispatch:
-- φ = .top: apply the forward map; the argument is a T-value.
-- φ = .bot: identity — on the empty face, the glued term is the
-- A-value `g` itself (consistent with `glueIn .bot t a → a`).
-- Else: stuck `.nunglue` preserving `f` and `g`.
match φ with
| .top => vApp (eval env f) (eval env g)
| .bot => eval env g
| _ => .vneu (.nunglue φ (eval env f) (eval env g))
| .pair a b => .vpair (eval env a) (eval env b)
| .fst t => vFst (eval env t)
| .snd t => vSnd (eval env t)
-- REL1 inductive-type constructors.
| .dimExpr r => .vdimExpr r
-- Universe-code constructor (CCHM §6 universe codes).
| .code A => .vcode A
| .ctor S c params args =>
-- Produce a canonical constructor value with all args evaluated.
-- (Boundary firing for path ctors lands in a follow-up — REL1
-- design doc §4: when a `.dim`-typed arg evaluates to .zero/.one
-- and matches a clause in `S.ctors[c].boundary`, we should fire
-- that clause body instead. TODO REL1.1.)
.vctor S c params (args.map (eval env))
| .indElim S params motive branches target =>
-- β-reduce on a canonical `vctor`; otherwise build a stuck
-- `.nIndElim` that preserves env-evaluated motive and branches
-- so it can unstick when target later resolves.
match eval env target with
| .vctor _ c _ argsV =>
match List.lookup c branches with
| some body =>
-- Apply branch body to constructor's args via repeated
-- `vApp` — the body is curried: λ a₁ … aₙ. result.
-- Recursive-arg hypotheses (the IH passed alongside each
-- `.self` arg in the design doc §5) are not yet wired
-- here; an `indElim` of a non-recursive ctor is fully
-- handled, but recursive ctors land their branch body
-- with only the constructor args (no IH) — TODO REL1.1.
argsV.foldl (fun f a => vApp f a) (eval env body)
| none =>
.vneu (.nvar s!"<indElim: no branch for {c}>")
| .vneu n =>
.vneu (.nIndElim S params (eval env motive)
(branches.map (fun (nm, b) => (nm, eval env b))) n)
| _ =>
.vneu (.nvar "<indElim: target is not canonical>")
-- Modal introduction: structural lift to the corresponding value form.
| .modalIntro k a => .vModalIntro k (eval env a)
-- Modal elimination: β-reduce on a same-kind intro value form;
-- mismatched-kind intros (which a well-typed source cannot produce
-- but a bypassed typechecker conceivably could) are kept stuck via
-- a marker-neutral. Otherwise produce a stuck neutral that
-- preserves the modality kind, the evaluated eliminator function,
-- and the (necessarily-stuck) scrutinee neutral.
| .modalElim k f m =>
match eval env m with
| .vModalIntro k' a =>
if k = k' then vApp (eval env f) a
else .vneu (.nvar "<modalElim: kind mismatch>")
| .vneu n => .vneu (.nModalElim k (eval env f) n)
| _ => .vneu (.nvar "<modalElim: scrutinee is not modal-canonical>")
/-- First projection at the value level. β-reduces `vpair`; pushes a
stuck neutral into `nfst`. Projecting any other value shape is a
type error (marker neutral). -/
@[implemented_by vFstRust]
partial def vFst : CVal → CVal
| .vpair a _ => a
| .vneu n => .vneu (.nfst n)
| _ => .vneu (.nvar "<vFst: non-pair projection>")
/-- Second projection at the value level. Mirror of `vFst`. -/
@[implemented_by vSndRust]
partial def vSnd : CVal → CVal
| .vpair _ b => b
| .vneu n => .vneu (.nsnd n)
| _ => .vneu (.nvar "<vSnd: non-pair projection>")
/-- Apply one value to another. β-reduces `vlam` closures; pushes stuck
neutrals into `napp`. `vTranspFun` unfolds per the *full* CCHM Π rule.
`vHCompFun` unfolds per the CCHM Π hcomp rule: apply pointwise
through the tube, then recursively hcomp on the codomain. Applying
a `vplam` or `vTubeApp` as a function is a type error. -/
@[implemented_by vAppRust]
partial def vApp : CVal → CVal → CVal
| .vlam env x body, arg => eval (env.extend x arg) body
| .vneu n, arg => .vneu (.napp n arg)
| .vTranspFun i domA codA φ f, arg =>
vTransp i codA φ (vApp f (vTranspInv i domA φ arg))
| .vHCompFun codA φ tube base, arg =>
vHCompValue codA φ (.vTubeApp tube arg) (vApp base arg)
-- Full CCHM Π hetero comp β-rule. See file-level comment below for
-- the fill construction.
| .vCompFun env i domA codA φ u t, arg =>
let yName := "$y"
let fj : DimVar := ⟨"$fj"⟩
let newEnv := env.extend yName arg
-- `filled_y_at_i`: a line in the *outer* binder `i` giving y_at_i:A(i).
-- Build as `transp^{fj} (domA[i := (inv fj) i]) φ ($y)`:
-- at fj=0: line slice is A(1) (source: y : A(1))
-- at fj=1: line slice is A(i) (target we want)
let filled_y_at_i : CTerm :=
.transp fj
(domA.substDimExpr i (.join (.inv (.var fj)) (.var i)))
φ (.var yName)
-- `filled_y_at_0`: substitute i := 0 in the above — the reversed
-- line is `A[i := inv fj]`, taking A(1) → A(0).
let filled_y_at_0 : CTerm :=
.transp fj
(domA.substDimExpr i (.inv (.var fj)))
φ (.var yName)
eval newEnv (.comp i codA φ
(.app u filled_y_at_i)
(.app t filled_y_at_0))
| .vplam _ _ _, _ => .vneu (.nvar "<vApp: vplam applied as function>")
| .vTubeApp _ _, _ => .vneu (.nvar "<vApp: vTubeApp applied as function>")
| .vPathTransp _ _ _ _ _ _ _, _ => .vneu (.nvar "<vApp: vPathTransp applied as function>")
| .vpair _ _, _ => .vneu (.nvar "<vApp: vpair applied as function>")
| .vctor _ _ _ _, _ => .vneu (.nvar "<vApp: vctor applied as function>")
| .vdimExpr _, _ => .vneu (.nvar "<vApp: vdimExpr applied as function>")
| .vcode _, _ => .vneu (.nvar "<vApp: vcode applied as function>")
| .vModalIntro _ _, _ => .vneu (.nvar "<vApp: vModalIntro applied as function>")
/-- Apply a value to a dimension expression. β-reduces `vplam` closures
by substituting the dim in the body and re-evaluating; pushes stuck
neutrals into `npapp`. `vTubeApp tube arg` applied to dim `r` reduces
to `vApp (vPApp tube r) arg` — the semantic meaning of
`λj. (tube @ j) arg`. Marker neutrals for ill-typed applications. -/
@[implemented_by vPAppRust]
partial def vPApp : CVal → DimExpr → CVal
| .vplam env i body, r => eval env (body.substDim i r)
| .vneu n, r => .vneu (.npapp n r)
| .vTubeApp tube arg, r => vApp (vPApp tube r) arg
-- Path transport endpoint reductions: at `.zero` / `.one` the CCHM
-- multi-clause system degenerates (the (j=0) or (j=1) clause fires)
-- and the result is the specified endpoint at i=1. At generic `r`
-- we fall through to `vCompNAtTerm` on the CCHM multi-clause system
-- `[φ ↦ p@r, (r=0) ↦ a, (r=1) ↦ b]` with base `p@r` — which reduces
-- further if the face substitutions happen to simplify.
| .vPathTransp env i _ a _ _ _, .zero => eval env (a.substDim i .one)
| .vPathTransp env i _ _ b _ _, .one => eval env (b.substDim i .one)
| .vPathTransp env i A a b φ p, r =>
vCompNAtTerm env i A
[ (φ, .papp p r)
, (FaceFormula.dimExprEq0 r, a)
, (FaceFormula.dimExprEq1 r, b) ]
(.papp p r)
| .vlam _ _ _, _ => .vneu (.nvar "<vPApp: vlam applied as path>")
| .vTranspFun _ _ _ _ _, _ => .vneu (.nvar "<vPApp: vTranspFun applied as path>")
| .vHCompFun _ _ _ _, _ => .vneu (.nvar "<vPApp: vHCompFun applied as path>")
| .vCompFun _ _ _ _ _ _ _, _ => .vneu (.nvar "<vPApp: vCompFun applied as path>")
| .vpair _ _, _ => .vneu (.nvar "<vPApp: vpair applied as path>")
| .vctor _ _ _ _, _ => .vneu (.nvar "<vPApp: vctor applied as path>")
| .vdimExpr _, _ => .vneu (.nvar "<vPApp: vdimExpr applied as path>")
| .vcode _, _ => .vneu (.nvar "<vPApp: vcode applied as path>")
| .vModalIntro _ _, _ => .vneu (.nvar "<vPApp: vModalIntro applied as path>")
/-- Homogeneous composition at the value level. The type `A` is
*homogeneous* (doesn't vary along `i`); the tube and base are
already-evaluated values.
Reducing cases (in match order):
1. `φ = .top` — tube covers everything, result is `tube @ 1`.
2. `A = .pi` — CCHM Π hcomp: construct a `vHCompFun` closure
that applies pointwise when the function is
applied to an argument.
3. Otherwise — stuck `.vneu (.nhcomp ...)`.
Note the crucial difference from `vTransp`: no constant-line check,
because hcomp is *already* homogeneous — constancy is built in. -/
@[implemented_by vHCompValueRust]
partial def vHCompValue { : ULevel} (A : CType ) (φ : FaceFormula)
(tube base : CVal) : CVal :=
match φ with
| .top => vPApp tube .one
| _ =>
match A with
| .pi _ _domA codA => .vHCompFun codA φ tube base
| _ => .vneu (.nhcomp A φ tube base)
/-- Heterogeneous composition at the term level. Takes `u` and `t` as
`CTerm`s (not `CVal`s) so that the `comp_full` reduction can perform
substitution *at the term level* — `eval env (u.substDim i .one)` —
which is in general different from `vPApp (eval env u) .one`.
Reducing cases (in match order):
1. `φ = .top` — C1: `eval env (u[i := 1])`.
2. `φ = .bot` — C2: `eval env (transp i A .bot t)`.
3. `CType.dimAbsent i A = true` — constant line: heterogeneous
comp reduces to hcomp on the
fixed type `A`, with `.plam i u`
as the tube.
4. Otherwise — stuck `.vneu (.ncomp ...)`.
Note cases (1) and (2) are decidable at the `.top`/`.bot` head of
`φ`; case (3) discriminates on `A` only after `.top`/`.bot` are
ruled out. All four cases are mutually exclusive. -/
@[implemented_by vCompAtTermRust]
partial def vCompAtTerm { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (u t : CTerm) : CVal :=
match φ with
| .top => eval env (u.substDim i .one)
| .bot => eval env (.transp i A .bot t)
| _ =>
if CType.dimAbsent i A then
-- Constant line: hetero comp reduces to hcomp. `.plam i u` is the
-- tube as a dim-closure.
vHCompValue A φ (eval env (.plam i u)) (eval env t)
else
match A with
| .pi _ domA codA =>
-- Hetero Π comp: package into a `vCompFun` closure. The CCHM
-- β-rule runs at `vApp`-time with a full fill-based tube.
.vCompFun env i domA codA φ u t
| _ =>
.vneu (.ncomp i A φ (eval env u) (eval env t))
/-- Multi-clause heterogeneous composition at the term level. Dispatches
by scanning the clause list:
· If any clause has face `.top`, that clause's body substituted at
`i := .one` is the result (CCHM multi-clause full-system rule).
· If all clause faces are `.bot` or the list is empty, no clause
fires — reduces to plain transport of the base.
· If exactly one clause has a non-trivial face, delegate to
`vCompAtTerm` (single-clause specialisation).
· Otherwise produce a stuck `ncompN` neutral preserving env, line
binder, type, evaluated clauses, and evaluated base. -/
@[implemented_by vCompNAtTermRust]
partial def vCompNAtTerm { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(clauses : List (FaceFormula × CTerm)) (t : CTerm) : CVal :=
-- Scan for a `.top` clause first.
match clauses.find? (fun ⟨φ, _⟩ => match φ with | .top => true | _ => false) with
| some ⟨_, u⟩ => eval env (u.substDim i .one)
| none =>
-- Strip `.bot` clauses (they never fire).
let live := clauses.filter
(fun ⟨φ, _⟩ => match φ with | .bot => false | _ => true)
match live with
| [] => eval env (.transp i A .bot t)
| [⟨φ, u⟩] => vCompAtTerm env i A φ u t
| _ =>
.vneu (.ncompN env i A
(live.map (fun ⟨φ, u⟩ => (φ, eval env u)))
(eval env t))
end
/-!
## Reduction lemmas
`partial def` is opaque at the kernel level, so the defining cases of
`eval`, `vApp`, `vPApp`, `vTransp`, `vHCompValue`, `vCompAtTerm`, etc. are
not reducible by `rfl` and have no auto-generated unfolding equations.
**Axiom-debt cleanup (REL2 follow-up).** These were previously declared
as `axiom`s mirroring each match arm. They are now `theorem ... := by
sorry` annotated to **FS-H15** in `topolei/docs/HYPOTHESES.md` — the
partial-def-reduction-equations umbrella. The discharge route is to
convert the `partial def`s to total `def`s with a termination metric
(e.g. CTerm-tree depth + a `Nat` fuel parameter), at which point each
theorem becomes `rfl` / `simp [eval, vApp, ...]`. Conversion `axiom →
sorry` is a strict trust-footprint improvement: TODO marker rather than
ground truth.
Each match arm of `eval`/`vApp`/`vPApp`/etc. above corresponds to one
theorem below; the type signatures still document the arm's reduction
shape, and the arms remain mutually exclusive by precondition so the
collection is consistent.
-/
-- Reduction lemmas for `eval`.
theorem eval_var (env : CEnv) (x : String) :
eval env (.var x) = (env.lookup x).getD (.vneu (.nvar x)) := by
-- waits on: FS-H15.
sorry
theorem eval_lam (env : CEnv) (x : String) (body : CTerm) :
eval env (.lam x body) = .vlam env x body := by
-- waits on: FS-H15.
sorry
theorem eval_app (env : CEnv) (f a : CTerm) :
eval env (.app f a) = vApp (eval env f) (eval env a) := by
-- waits on: FS-H15.
sorry
theorem eval_plam (env : CEnv) (i : DimVar) (body : CTerm) :
eval env (.plam i body) = .vplam env i body := by
-- waits on: FS-H15.
sorry
theorem eval_papp (env : CEnv) (t : CTerm) (r : DimExpr) :
eval env (.papp t r) = vPApp (eval env t) r := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on `.transp` — four disjoint cases
Replaces the earlier coarse `eval_transp` axiom. Match-arm priority is:
1. `.top` face → identity (T1 at eval level).
2. Constant line → identity (T2 at eval level).
3. `.path A₀ a b` line, non-constant → `vPathTransp` closure.
4. Non-path, non-constant line → delegate to value-level `vTransp`.
The four cases are mutually exclusive by precondition, so the axiom set
is consistent. -/
/-- (1) T1 at eval level: transport under a full face is identity. -/
theorem eval_transp_top { : ULevel} (env : CEnv) (i : DimVar) (A : CType ) (t : CTerm) :
eval env (.transp i A .top t) = eval env t := by
-- waits on: FS-H15.
sorry
/-- (2) T2 at eval level: transport along a constant line is identity.
Covers `.univ`, constant-`pi`, and constant-`path` lines uniformly. -/
theorem eval_transp_const { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (t : CTerm)
(hφ : φ ≠ .top)
(hA : CType.dimAbsent i A = true) :
eval env (.transp i A φ t) = eval env t := by
-- waits on: FS-H15.
sorry
/-- (3) Path transport: when the line's body is `.path A₀ a b` with the
whole path-line genuinely varying, produce a `vPathTransp` closure
that captures the endpoint CTerms `a`/`b` along with the env and the
path term `t` (kept as a CTerm so later `.papp t r` constructions
work for the multi-clause reduction at generic dim). Reduces
further under `vPApp` at endpoints. -/
theorem eval_transp_path { : ULevel} (env : CEnv) (i : DimVar) (A₀ : CType )
(a b : CTerm) (φ : FaceFormula) (t : CTerm)
(hφ : φ ≠ .top)
(hA : CType.dimAbsent i (.path A₀ a b) = false) :
eval env (.transp i (.path A₀ a b) φ t) =
.vPathTransp env i A₀ a b φ t := by
-- waits on: FS-H15.
sorry
/-- (4) Non-path non-glue non-constant transport: delegate to the value-level
`vTransp`, which is env-agnostic and handles `.pi` via `vTranspFun`.
`.glue` is excluded because its CCHM transport formula lives in dedicated
Glue-specific axioms (see `Glue.lean`); routing it through `vTransp`
here would claim it reduces to a stuck neutral, which would contradict
those axioms in their specific sub-cases.
Path / Glue both store sub-CTypes at the *same* universe level as A
(their CType.path and CType.glue constructors carry `A : CType `
with the outer level), so same-level Eq comparison is sufficient to
rule them out. -/
theorem eval_transp_nonpath { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (t : CTerm)
(hφ : φ ≠ .top)
(hA : CType.dimAbsent i A = false)
(h_not_path : ∀ (A₀ : CType ) (a b : CTerm), A ≠ .path A₀ a b)
(h_not_glue : ∀ (φG : FaceFormula) (T : CType )
(f fInv sec ret coh : CTerm) (Ai : CType ),
A ≠ .glue φG T f fInv sec ret coh Ai) :
eval env (.transp i A φ t) = vTransp i A φ (eval env t) := by
-- waits on: FS-H15.
sorry
/-- Π-case theorem (full CCHM): transport along any `pi domA codA` line
produces a `vTranspFun` closure. Derived via `eval_transp_nonpath`
(`pi ≠ path` and `pi ≠ glue` by constructor disjointness) plus
`vTransp_pi`. -/
theorem eval_transp_pi { ' : ULevel} (env : CEnv) (i : DimVar)
(var : String) (domA : CType ) (codA : CType ') (φ : FaceFormula) (t : CTerm)
(hφ : φ ≠ .top)
(hA : CType.dimAbsent i (.pi var domA codA) = false) :
eval env (.transp i (.pi var domA codA) φ t) =
.vTranspFun i domA codA φ (eval env t) := by
rw [eval_transp_nonpath env i _ φ t hφ hA
(by intro _ _ _ h; nomatch h)
(by intro _ _ _ _ _ _ _ _ h; nomatch h)]
exact vTransp_pi _ _ _ _ _ _ hφ hA
/-- Stuck fallback theorem. In our current `CType` universe
`{univ, pi, path, glue, ind, interval, lift}`, this never actually
fires in practice: `univ`/`interval` always have `dimAbsent = true`,
so the const case wins; `pi` is handled by `eval_transp_pi`; `path`
is handled by `eval_transp_path`; `glue` is handled by the dedicated
Glue-transport axioms in `Glue.lean`. Kept here for parity with
`vTransp_stuck` and future CType extensions.
`h_not_pi` uses the level-erased skeleton (`CType.skeleton`) to
formulate constructor-disjointness, sidestepping cross-level HEq
elimination (which is not available in Lean 4 without K).
`h_not_path` and `h_not_glue` are same-level Eq because those
constructors store sub-components at the outer level. -/
theorem eval_transp_stuck { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (t : CTerm)
(hφ : φ ≠ .top)
(hA : CType.dimAbsent i A = false)
(h_not_pi : A.skeleton ≠ SkeletalCType.pi)
(h_not_path : ∀ (A₀ : CType ) (a b : CTerm), A ≠ .path A₀ a b)
(h_not_glue : ∀ (φG : FaceFormula) (T : CType )
(f fInv sec ret coh : CTerm) (Ai : CType ),
A ≠ .glue φG T f fInv sec ret coh Ai) :
eval env (.transp i A φ t) =
.vneu (.ntransp i A φ (eval env t)) := by
rw [eval_transp_nonpath env i A φ t hφ hA h_not_path h_not_glue]
exact vTransp_stuck _ _ _ _ hφ hA h_not_pi
/-- **T5 at eval level**: face-formula congruence for transport. When
two face formulas are semantically equal — i.e. `φ.eval env =
ψ.eval env` for every env — transport under them computes the same
result.
This is a claim about Rust's evaluator: it inspects face formulas
only through their truth-value semantics, not their syntactic form.
Two faces that classify the same set of environments produce the
same transport reduction, regardless of their concrete tree
structure (e.g. `(i=0) ∧ ` vs `(i=0)`).
Stated at the eval level (rather than augmenting the partial def
with a face-normalisation prepass) so the existing eval-axiom set is
not re-audited. The Rust backend's discharge: a face-normalisation
routine ensures syntactically distinct but semantically equal faces
take the same dispatch branch. -/
theorem eval_transp_face_congr { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ ψ : FaceFormula) (t : CTerm)
(h : ∀ ε, φ.eval ε = ψ.eval ε) :
eval env (.transp i A φ t) = eval env (.transp i A ψ t) := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on `.comp` — four disjoint cases
The old coarse `eval_comp` (which asserted the stuck form unconditionally)
is replaced by four case-axioms mirroring the arms of `vCompAtTerm`. The
cases are disjoint by precondition, so the axiom set is consistent.
-/
/-- **C1 at eval level**: with a full face, heterogeneous composition
reduces to the system body substituted at `i := 1`. Crucially this
is *term-level* substitution, not `vPApp` on the evaluated body —
`u` may be e.g. a free variable whose value doesn't look like a
function. -/
theorem eval_comp_top { : ULevel} (env : CEnv) (i : DimVar) (A : CType ) (u t : CTerm) :
eval env (.comp i A .top u t) = eval env (u.substDim i .one) := by
-- waits on: FS-H15.
sorry
/-- **C2 at eval level**: with an empty face, the system contributes
nothing and composition reduces to plain transport. -/
theorem eval_comp_bot { : ULevel} (env : CEnv) (i : DimVar) (A : CType ) (u t : CTerm) :
eval env (.comp i A .bot u t) = eval env (.transp i A .bot t) := by
-- waits on: FS-H15.
sorry
/-- **Constant-line comp = hcomp**: when the type `A` doesn't vary along
`i`, heterogeneous composition reduces to homogeneous composition on
the (fixed) type `A`. The tube is `.plam i u` — the system body `u`
packaged as a dim-closure over the line binder. -/
theorem eval_comp_const { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (u t : CTerm)
(hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot)
(hA : CType.dimAbsent i A = true) :
eval env (.comp i A φ u t) =
vHCompValue A φ (eval env (.plam i u)) (eval env t) := by
-- waits on: FS-H15.
sorry
/-- **Heterogeneous Π comp**: when A is a pi type with a genuinely-varying
line, `vCompAtTerm` packages the comp into a `vCompFun` closure that
will run the CCHM β-rule when the function is applied. -/
theorem eval_comp_pi { ' : ULevel} (env : CEnv) (i : DimVar)
(var : String) (domA : CType ) (codA : CType ')
(φ : FaceFormula) (u t : CTerm)
(hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot)
(hA : CType.dimAbsent i (.pi var domA codA) = false) :
eval env (.comp i (.pi var domA codA) φ u t) =
.vCompFun env i domA codA φ u t := by
-- waits on: FS-H15.
sorry
/-- Stuck fallback: `.comp` whose face is neither `.top` nor `.bot`, whose
line genuinely varies, and whose type is neither `.pi` nor a constant
produces a neutral. The "not a pi" precondition uses
`CType.skeleton ≠ .pi` (level-erased constructor tag) to avoid
cross-level HEq elimination. -/
theorem eval_comp_stuck { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(φ : FaceFormula) (u t : CTerm)
(hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot)
(hA : CType.dimAbsent i A = false)
(h_not_pi : A.skeleton ≠ SkeletalCType.pi) :
eval env (.comp i A φ u t) =
.vneu (.ncomp i A φ (eval env u) (eval env t)) := by
-- waits on: FS-H15.
sorry
/-- `eval` on `.compN` delegates to `vCompNAtTerm`. -/
theorem eval_compN { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(clauses : List (FaceFormula × CTerm)) (t : CTerm) :
eval env (.compN i A clauses t) = vCompNAtTerm env i A clauses t := by
-- waits on: FS-H15.
sorry
/-!
### `vHCompValue` — three disjoint cases
-/
/-- Homogeneous composition under a full face: the tube covers everything,
and the result is the tube evaluated at `1`. -/
theorem vHCompValue_top { : ULevel} (A : CType ) (tube base : CVal) :
vHCompValue A .top tube base = vPApp tube .one := by
-- waits on: FS-H15.
sorry
/-- **CCHM Π hcomp rule**: homogeneous composition on a Π type produces
a `vHCompFun` closure that applies pointwise when its function is
applied to an argument. `domA` is stored in the type but unused in
the resulting closure because hcomp on the domain is trivial (A is
fixed, not varying). -/
theorem vHCompValue_pi { ' : ULevel}
(var : String) (domA : CType ) (codA : CType ')
(φ : FaceFormula) (tube base : CVal)
(hφ : φ ≠ .top) :
vHCompValue (.pi var domA codA) φ tube base = .vHCompFun codA φ tube base := by
-- waits on: FS-H15.
sorry
/-- Stuck fallback: hcomp on a non-pi type under a non-top face. Uses
`nhcomp` (separate from `ncomp` because hcomp's type is fixed).
The "not a pi" precondition uses skeleton-disjointness (avoiding HEq). -/
theorem vHCompValue_stuck { : ULevel} (A : CType ) (φ : FaceFormula) (tube base : CVal)
(hφ : φ ≠ .top)
(h_not_pi : A.skeleton ≠ SkeletalCType.pi) :
vHCompValue A φ tube base = .vneu (.nhcomp A φ tube base) := by
-- waits on: FS-H15.
sorry
-- Reduction lemmas for `vApp`.
theorem vApp_vlam (env : CEnv) (x : String) (body : CTerm) (arg : CVal) :
vApp (.vlam env x body) arg = eval (env.extend x arg) body := by
-- waits on: FS-H15.
sorry
theorem vApp_vneu (n : CNeu) (arg : CVal) :
vApp (.vneu n) arg = .vneu (.napp n arg) := by
-- waits on: FS-H15.
sorry
/-- Full CCHM Π β-rule at the value level: applying a transported-function
closure to an argument `arg` inversely transports `arg` through the
domain, applies the underlying function `f`, and forward-transports the
result through the codomain.
When `CType.dimAbsent i domA = true`, `vTranspInv` reduces to identity
(by `vTranspInv_const`) and this specialises to the simpler
const-domain rule `vTransp i codA φ (vApp f arg)`. -/
theorem vApp_vTranspFun { ' : ULevel} (i : DimVar)
(domA : CType ) (codA : CType ') (φ : FaceFormula)
(f : CVal) (arg : CVal) :
vApp (.vTranspFun i domA codA φ f) arg =
vTransp i codA φ (vApp f (vTranspInv i domA φ arg)) := by
-- waits on: FS-H15.
sorry
/-- **CCHM Π hcomp β-rule** at the value level: applying a homogeneously
composed function closure to `arg` yields hcomp on the codomain with:
· tube = `λj. (tube @ j) arg` (represented by `vTubeApp`),
· base = `base arg`.
No inverse transport — hcomp's type is fixed, so the argument passes
through unchanged. -/
theorem vApp_vHCompFun { : ULevel} (codA : CType ) (φ : FaceFormula)
(tube base arg : CVal) :
vApp (.vHCompFun codA φ tube base) arg =
vHCompValue codA φ (.vTubeApp tube arg) (vApp base arg) := by
-- waits on: FS-H15.
sorry
/-- **Full CCHM Π hetero comp β-rule**: applying `comp^i (pi A B) φ u u₀` to
`y : A(1)` unfolds via the *fill* construction. For a fresh dim `$fj`
and argument name `$y`:
· `y_at_i = transp^{$fj} (A[i := inv $fj i]) φ y` — fill from A(1) down to A(i).
· `y_at_0 = transp^{$fj} (A[i := inv $fj]) φ y` — reversed-line transport A(1) → A(0).
The result is `comp^i B(i) φ (u (y_at_i)) (u₀ (y_at_0))` evaluated in
an env extending `$y` with the argument.
When `CType.dimAbsent i domA = true`, both fills degenerate to `y`
(by T2 on the constant line), recovering the simpler const-domain
formula `comp^i B(i) φ (u y) (u₀ y)`.
Hygiene assumption: `$y` is not a user variable in `env`, and `$fj`
is not a user DimVar in `domA`, `codA`, `φ`, `u`, `t`. These reserved
names are chosen to minimise collision probability. -/
theorem vApp_vCompFun { ' : ULevel} (env : CEnv) (i : DimVar)
(domA : CType ) (codA : CType ')
(φ : FaceFormula) (u t : CTerm) (arg : CVal) :
vApp (.vCompFun env i domA codA φ u t) arg =
eval (env.extend "$y" arg) (.comp i codA φ
(.app u (.transp ⟨"$fj"⟩
(domA.substDimExpr i (.join (.inv (.var ⟨"$fj"⟩)) (.var i)))
φ (.var "$y")))
(.app t (.transp ⟨"$fj"⟩
(domA.substDimExpr i (.inv (.var ⟨"$fj"⟩)))
φ (.var "$y")))) := by
-- waits on: FS-H15.
sorry
-- Reduction lemmas for `vPApp`.
theorem vPApp_vplam (env : CEnv) (i : DimVar) (body : CTerm) (r : DimExpr) :
vPApp (.vplam env i body) r = eval env (body.substDim i r) := by
-- waits on: FS-H15.
sorry
theorem vPApp_vneu (n : CNeu) (r : DimExpr) :
vPApp (.vneu n) r = .vneu (.npapp n r) := by
-- waits on: FS-H15.
sorry
/-- `vTubeApp tube arg` under dim application reduces to `(tube @ r) arg`.
Encodes the semantic meaning of `λj. (tube @ j) arg`. -/
theorem vPApp_vTubeApp (tube arg : CVal) (r : DimExpr) :
vPApp (.vTubeApp tube arg) r = vApp (vPApp tube r) arg := by
-- waits on: FS-H15.
sorry
/-!
### `vCompNAtTerm` — compound equation mirroring the partial-def arms
Single axiom exposing the full case analysis so that derived theorems can
pattern-match on the clause list's structure. -/
theorem vCompNAtTerm_def { : ULevel} (env : CEnv) (i : DimVar) (A : CType )
(clauses : List (FaceFormula × CTerm)) (t : CTerm) :
vCompNAtTerm env i A clauses t =
match clauses.find?
(fun ⟨φ, _⟩ => match φ with | .top => true | _ => false) with
| some ⟨_, u⟩ => eval env (u.substDim i .one)
| none =>
let live := clauses.filter
(fun ⟨φ, _⟩ => match φ with | .bot => false | _ => true)
match live with
| [] => eval env (.transp i A .bot t)
| [⟨φ, u⟩] => vCompAtTerm env i A φ u t
| _ => .vneu (.ncompN env i A
(live.map (fun ⟨φ, u⟩ => (φ, eval env u)))
(eval env t)) := by
-- waits on: FS-H15.
sorry
/-!
### Path transport endpoint reductions
Applied at `.zero`, the CCHM `(j=0)` clause fires, giving `a(1)`.
Applied at `.one`, the `(j=1)` clause fires, giving `b(1)`.
Applied at any other DimExpr, the multi-clause comp can't be computed
without machinery we haven't built yet — stalls at `npathTranspApp`.
The three axioms are disjoint by the shape of the DimExpr argument.
-/
/-- Path transport at left endpoint: result is `a(1)`, i.e. `a` evaluated
with `i` substituted by `.one`. This is *not* a transport of `a(0)` —
it's the line's specified endpoint at `i=1`, made forced by CCHM's
multi-clause `(j=0)` constraint. -/
theorem vPApp_vPathTransp_zero { : ULevel}
(env : CEnv) (i : DimVar) (A : CType ) (a b : CTerm) (φ : FaceFormula)
(p : CTerm) :
vPApp (.vPathTransp env i A a b φ p) .zero =
eval env (a.substDim i .one) := by
-- waits on: FS-H15.
sorry
/-- Path transport at right endpoint: result is `b(1)`. -/
theorem vPApp_vPathTransp_one { : ULevel}
(env : CEnv) (i : DimVar) (A : CType ) (a b : CTerm) (φ : FaceFormula)
(p : CTerm) :
vPApp (.vPathTransp env i A a b φ p) .one =
eval env (b.substDim i .one) := by
-- waits on: FS-H15.
sorry
/-- **Full CCHM path transport at a generic dim**: apply the path
transport at `r` by evaluating the CCHM multi-clause comp
`comp^i A [φ ↦ p@r, (r=0) ↦ a, (r=1) ↦ b] (p@r)` via `vCompNAtTerm`.
This genuinely unsticks when `r`'s face substitution simplifies:
· `r = .zero` → `(r=0)` becomes `.top`, firing the left clause → `a(1)`.
· `r = .one` → `(r=1)` becomes `.top`, firing the right clause → `b(1)`.
· `r = .var k` generic → both clauses are non-trivial; stalls at a
structured `ncompN` neutral that can still unstick if `k` later
becomes an endpoint. -/
theorem vPApp_vPathTransp_general { : ULevel}
(env : CEnv) (i : DimVar) (A : CType ) (a b : CTerm) (φ : FaceFormula)
(p : CTerm) (r : DimExpr)
(h_zero : r ≠ .zero) (h_one : r ≠ .one) :
vPApp (.vPathTransp env i A a b φ p) r =
vCompNAtTerm env i A
[ (φ, .papp p r)
, (FaceFormula.dimExprEq0 r, a)
, (FaceFormula.dimExprEq1 r, b) ]
(.papp p r) := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on `.glueIn` — three disjoint cases
`glueIn [φ ↦ t] a` evaluates differently on/off/between the face `φ`:
· `φ = .top`: the face is full, the result is `t` (only the T-side
matters).
· `φ = .bot`: the face is empty, the result is `a` (only the A-side
matters).
· Otherwise: a structurally stuck `nglueIn` neutral preserving both
face-on and face-off values — later dim substitution into `φ` may
collapse it.
The three cases are mutually exclusive by precondition. -/
/-- (1) Full-face glueIn reduces to the T-side. -/
theorem eval_glueIn_top (env : CEnv) (t a : CTerm) :
eval env (.glueIn .top t a) = eval env t := by
-- waits on: FS-H15.
sorry
/-- (2) Empty-face glueIn reduces to the A-side. -/
theorem eval_glueIn_bot (env : CEnv) (t a : CTerm) :
eval env (.glueIn .bot t a) = eval env a := by
-- waits on: FS-H15.
sorry
/-- (3) Neutral-face glueIn produces an `nglueIn` stuck neutral preserving
both evaluated sides. The face formula is kept syntactic so that
later dim substitution can resolve it to `.top` or `.bot`.
The `h_not_unglue` precondition rules out the η-redex shape
`.glueIn φ t (.unglue φ f g)`, which reduces via
`eval_glueIn_of_unglue` to `eval env g` instead of a stuck form.
Without this restriction, the stuck rule and the η-rule would
disagree on a common instance. -/
theorem eval_glueIn_stuck (env : CEnv) (φ : FaceFormula) (t a : CTerm)
(hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot)
(h_not_unglue : ∀ f g, a ≠ .unglue φ f g) :
eval env (.glueIn φ t a) = .vneu (.nglueIn φ (eval env t) (eval env a)) := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on `.unglue` — three disjoint cases
`unglue [φ ↦ f] g` — extracting an A-value from a glued term:
· `φ = .top`: apply the forward map: `vApp (eval f) (eval g)`.
· `φ = .bot`: identity. `glueIn .bot t a` reduces to `a`, so the
argument is already an A-value; unglue is the identity there.
· Otherwise: stuck `nunglue` preserving `f` and `g`.
All three cases are mutually exclusive. -/
/-- (1) Full-face unglue: apply the forward map pointwise. -/
theorem eval_unglue_top (env : CEnv) (f g : CTerm) :
eval env (.unglue .top f g) = vApp (eval env f) (eval env g) := by
-- waits on: FS-H15.
sorry
/-- (2) Empty-face unglue: identity on `g`. This is the definitional
content of `Glue [bot ↦ (T, e)] A = A`: values are already A-values. -/
theorem eval_unglue_bot (env : CEnv) (f g : CTerm) :
eval env (.unglue .bot f g) = eval env g := by
-- waits on: FS-H15.
sorry
/-- (3) Neutral-face unglue: produce a stuck `nunglue` neutral preserving
`f` and `g`. Later dim substitution into `φ` may resolve it to
`.top` (→ forward-map application) or `.bot` (→ identity).
The `h_not_glueIn` precondition rules out the β-redex shape
`.unglue φ f (.glueIn φ t a)`, which reduces via
`eval_unglue_of_glueIn` to `eval env a` under the overlap
condition. Without this restriction, the stuck rule and the
β-rule would disagree on a common instance. -/
theorem eval_unglue_stuck (env : CEnv) (φ : FaceFormula) (f g : CTerm)
(hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot)
(h_not_glueIn : ∀ t a, g ≠ .glueIn φ t a) :
eval env (.unglue φ f g) = .vneu (.nunglue φ (eval env f) (eval env g)) := by
-- waits on: FS-H15.
sorry
/-!
### Glue β- and η-rules (eval level)
The β-rule (`unglue · glueIn`) and η-rule (`glueIn · unglue`) on
matching face formulas fire *regardless* of whether `φ` is `.top`,
`.bot`, or stuck. On `.top` / `.bot` the existing face-dispatched
axioms reduce to the same result under the overlap condition
(consistency check below); on stuck faces, these rules are the only
way the redex reduces — `eval_unglue_stuck` and `eval_glueIn_stuck`
carry `h_not_glueIn` / `h_not_unglue` preconditions to avoid conflict.
The `h_overlap` condition encodes the CCHM typing-side constraint
`e.f t = a` (or `t = e.f g`) that accompanies a well-typed glueIn /
unglue — the evaluator assumes it and short-circuits.
-/
/-- β-rule: `unglue φ f (glueIn φ t a)` reduces to `a` under the
overlap condition. Rust-discharge: the evaluator recognises the
nested pattern and short-circuits when the overlap invariant holds
(typing guarantees it). -/
theorem eval_unglue_of_glueIn (env : CEnv) (φ : FaceFormula) (f t a : CTerm)
(h_overlap : eval env (.app f t) = eval env a) :
eval env (.unglue φ f (.glueIn φ t a)) = eval env a := by
-- waits on: FS-H15.
sorry
/-- η-rule: `glueIn φ t (unglue φ f g)` reduces to `g` under the
overlap condition. Rust-discharge: dual to `eval_unglue_of_glueIn`. -/
theorem eval_glueIn_of_unglue (env : CEnv) (φ : FaceFormula) (f t g : CTerm)
(h_overlap : eval env t = eval env (.app f g)) :
eval env (.glueIn φ t (.unglue φ f g)) = eval env g := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on Σ constructors — three arms
`.pair a b` evaluates component-wise to `.vpair`; `.fst t` / `.snd t`
project through `vFst` / `vSnd`, which themselves β-reduce on `vpair`
and produce stuck `.nfst` / `.nsnd` on neutrals.
-/
/-- Pair construction evaluates component-wise. -/
theorem eval_pair (env : CEnv) (a b : CTerm) :
eval env (.pair a b) = .vpair (eval env a) (eval env b) := by
-- waits on: FS-H15.
sorry
/-- First projection delegates to `vFst`. -/
theorem eval_fst (env : CEnv) (t : CTerm) :
eval env (.fst t) = vFst (eval env t) := by
-- waits on: FS-H15.
sorry
/-- Second projection delegates to `vSnd`. -/
theorem eval_snd (env : CEnv) (t : CTerm) :
eval env (.snd t) = vSnd (eval env t) := by
-- waits on: FS-H15.
sorry
/-- β-rule for `vFst` on a pair. -/
theorem vFst_vpair (a b : CVal) : vFst (.vpair a b) = a := by
-- waits on: FS-H15.
sorry
/-- β-rule for `vSnd` on a pair. -/
theorem vSnd_vpair (a b : CVal) : vSnd (.vpair a b) = b := by
-- waits on: FS-H15.
sorry
/-- `vFst` on a neutral produces a stuck `nfst` neutral. -/
theorem vFst_vneu (n : CNeu) : vFst (.vneu n) = .vneu (.nfst n) := by
-- waits on: FS-H15.
sorry
/-- `vSnd` on a neutral produces a stuck `nsnd` neutral. -/
theorem vSnd_vneu (n : CNeu) : vSnd (.vneu n) = .vneu (.nsnd n) := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on `.code` — universe-code introduction
`code A` evaluates to its corresponding value form `.vcode A`,
preserving the underlying CType. Mirrors `eval_dimExpr` (a similar
"lift constructor data into a value" rule).
-/
/-- Universe-code introduction at the eval level: encoding evaluates
to the corresponding `vcode` value form, preserving `A`. -/
theorem eval_code { : ULevel} (env : CEnv) (A : CType ) :
eval env (.code A) = .vcode A := by
-- waits on: FS-H15.
sorry
/-!
### `eval` on modal introduction / elimination (Refactor Phase 2)
Engine-layer axioms parameterised over `ModalityKind`. Replaces the
prior trio of (intro, elim-β, elim-stuck) axioms per modality with one
intro and two elim axioms (β on matching kinds, stuck on neutrals).
Modal-cohesion semantics (Crisp variables, `ʃ ⊣ ♭ ⊣ ♯` adjunction
laws) are Phase 3 and live in a separate `Modal.lean`.
-/
-- Modal introduction: structural lift to the corresponding value form.
theorem eval_modalIntro (env : CEnv) (k : ModalityKind) (a : CTerm) :
eval env (.modalIntro k a) = .vModalIntro k (eval env a) := by
-- waits on: FS-H15.
sorry
-- Modal elimination: β on matching-kind intro; stuck on neutrals.
/-- β-rule: `modalElim k f (modalIntro k a)` reduces to `app f a` at
the eval level. The β arm of `eval` checks that the elim's kind
matches the intro's kind, then delegates to `vApp` on the
eliminator value. Cross-kind elims (which are type errors)
diverge from this rule by producing a marker neutral. -/
theorem eval_modalElim_beta (env : CEnv) (k : ModalityKind) (f a : CTerm) :
eval env (.modalElim k f (.modalIntro k a)) =
vApp (eval env f) (eval env a) := by
-- waits on: FS-H15.
sorry
/-- Stuck case: `modalElim k` whose scrutinee evaluates to a CNeu
produces an `nModalElim k` neutral preserving the kind, the
evaluated function, and the stuck scrutinee. The scrutinee must
be `.vneu n` after eval; this is encoded by the explicit
hypothesis `eval env m = .vneu n`. -/
theorem eval_modalElim_stuck (env : CEnv) (k : ModalityKind)
(f m : CTerm) (n : CNeu) (h : eval env m = .vneu n) :
eval env (.modalElim k f m) = .vneu (.nModalElim k (eval env f) n) := by
-- waits on: FS-H15.
sorry