Skip to content

Commit 0a40075

Browse files
proof(L3): formal/Echo.v scaffold — Mode + LEcho + decoration-commuting weakening (#166)
## Summary First L3 slice — forward-looking per PR #153 body ("L3 (Echo). Forward-looking; formal/Echo.v does not exist yet."). Mechanises Layer 3 of the four-layer preservation redesign (`PRESERVATION-DESIGN.md` §6) at the type-former level. Does NOT touch `Syntax.v` / `Typing.v` / `Semantics.v`; `preservation_l1` is unaffected. ## What's in this PR | Item | Kind | |---|---| | `Mode = {Linear, Affine}` | inductive | | `mode_le` thin-poset | inductive (sort Type) | | `mode_le_refl` / `mode_le_trans` / `mode_le_prop` | Qed | | `Echo` record-shaped fiber `{ x : A \| f x = y }` | mirrors `Echo.agda:14-15` | | `echo_intro` | Qed | | `collapse : bool → unit` + `LEcho : Mode → Type` | concrete characteristic | | `echo_true` / `echo_false` + `echo_true_ne_echo_false` | Qed | | `weaken : LEcho Linear → LEcho Affine` | the irreversible collapse | | `weaken_collapses_distinction` | Qed | | `affine_canonical` / `affine_all_equal` | Qed | | `degrade_mode` + `degrade_mode_id_*` + `degrade_mode_strict_is_weaken` | Qed | | `degrade_mode_comp` | Qed (decoration-commuting headline) | | `degrade_mode_compose` | Qed | | `strict_linear_example` | Qed | Mirrors `echo-types/proofs/agda/EchoLinear.agda` lines 30-101. ## What's NOT in this PR (forward-looking, separate slices) - `TEcho` type former in `Syntax.v`. - `T_Observe` typing rule. - Residue-producing operational rules. - Integration into `has_type_l1` / `preservation_l1`. - Full residue characteristic infrastructure (`EchoR ⊤ TrivialCert`, no-section impossibility result, separating models). ## L3 design constraints from PRESERVATION-DESIGN.md §6.4 L1 + L2 must not bake in assumptions that block L3: 1. Preservation must not assume residue ≡ nothing. ✓ 2. No per-type echo-ability predicates. ✓ 3. Typing rules are modality-polymorphic; only T_Observe splits per mode. ✓ ## Proof-debt: K usage (documented at top of file) Two lemmas (`mode_le_trans`, `degrade_mode_comp`) use `dependent destruction` and pull in `Eqdep.Eq_rect_eq.eq_rect_eq` (K). The Agda upstream is `--safe --without-K`; rest of Ephapax Coq is K-free. Follow-up should rewrite K-free with motive tricks. Other 10 Qed lemmas: closed under the global context, zero axioms. ## Branch base Stacked off `proof/l1-region-threading-design` (PR #153 — auto-merge-armed). Will rebase to `main` once #153 lands. ## Test plan - [x] `coqc 8.18.0` builds `Echo.v` cleanly, zero admits, zero new axioms beyond documented K - [x] Clean full-project rebuild passes — 7 .v files - [x] `Print Assumptions`: only `mode_le_trans` + `degrade_mode_comp` use `eq_rect_eq`; rest closed - [ ] CI green - [ ] Review: type-former shape matches §6.1-6.4 + `EchoLinear.agda` Refs `PRESERVATION-DESIGN.md` §6, `echo-types/proofs/agda/EchoLinear.agda`, PR #153. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 56f592f commit 0a40075

2 files changed

Lines changed: 344 additions & 0 deletions

File tree

formal/Echo.v

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
(* SPDX-License-Identifier: PMPL-1.0-or-later *)
2+
(* SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell *)
3+
4+
(** * Ephapax L3 — Echo / residue type former (forward-looking scaffold)
5+
6+
This file mechanises Layer 3 of the four-layer preservation
7+
redesign (PRESERVATION-DESIGN.md §6). L3 is the irreversibility-
8+
residue layer: every irreversible operation in Ephapax
9+
([S_Region_Exit], [S_Drop], and Affine-implicit drop) produces a
10+
residue value whose type carries a proof-relevant witness of
11+
*which* value was erased.
12+
13+
Per the design doc, L3 is FORWARD-LOOKING — [preservation_l1] does
14+
not depend on this layer. The mechanisation here mirrors the Agda
15+
upstream at:
16+
17+
- [echo-types/proofs/agda/Echo.agda] — the fiber type former
18+
[Echo : (A → B) → B → Set] defined as [Σ A (λ x → f x ≡ y)].
19+
- [echo-types/proofs/agda/EchoLinear.agda] — the two-mode
20+
[LEcho : Mode → Set]; the weakening [Linear → Affine]; the
21+
decoration-commuting per-mode composition lemma
22+
[degradeMode-comp].
23+
24+
What is in this file (first L3 slice):
25+
26+
- [Mode], the [mode_le] thin-poset, [mode_le_refl] /
27+
[mode_le_trans] / [mode_le_prop] all [Qed].
28+
- [Echo] as a record-shaped fiber type former.
29+
- A concrete [collapse : bool → unit] and
30+
[LEcho : Mode → Type] mode-polymorphic family.
31+
- [weaken : LEcho Linear → LEcho Affine] (the irreversible
32+
collapse) and [weaken_collapses_distinction] witnessing that
33+
the Linear distinction is genuinely erased.
34+
- [degrade_mode] and the headline composition law
35+
[degrade_mode_comp] ([Qed]).
36+
- [affine_canonical] / [affine_all_equal] — propositionality of
37+
Affine echoes.
38+
39+
What is NOT in this file (separate forward-looking PRs):
40+
41+
- [TEcho] type former added to [Syntax.v] (the new [ty]
42+
constructor). L3 cannot type-decorate ephapax expressions until
43+
[TEcho] lands in [ty].
44+
- [T_Observe] typing rule. Linear-mode [T_Observe] consumes;
45+
Affine-mode [T_Observe] does not.
46+
- Residue-producing operational rules ([S_Region_Exit] and
47+
[S_Drop] with residue outputs).
48+
- Integration into [has_type_l1] / [preservation_l1].
49+
- Full collapse/residue characteristic infrastructure (separating
50+
models, the [EchoR ⊤ TrivialCert] form, the no-section result).
51+
52+
Per PRESERVATION-DESIGN.md §6.4, L1 + L2 must not bake in
53+
assumptions that block L3. The three constraints are:
54+
55+
1. Preservation must not assume residue ≡ nothing.
56+
2. No per-type echo-ability predicates.
57+
3. Typing rules are modality-polymorphic (only [T_Observe]
58+
splits per mode).
59+
60+
The L1 design as captured in [TypingL1.v] and [Semantics_L1.v]
61+
satisfies all three constraints. This file does not introduce
62+
contradictions with them. *)
63+
64+
(** ** Proof-debt note (axiom dependencies)
65+
66+
Two lemmas in this file ([mode_le_trans] and [degrade_mode_comp])
67+
use [dependent destruction] from [Coq.Program.Equality] to
68+
discriminate impossible cases on the indexed inductive
69+
[mode_le]. This pulls in Coq's standard [eq_rect_eq] (K / UIP)
70+
axiom.
71+
72+
The Agda upstream ([EchoLinear.agda]) is [--safe --without-K]
73+
and discharges these cases without K. The rest of the Ephapax
74+
Coq codebase (per [Print Assumptions] on [value_R_G_preserving_l1],
75+
[subst_preserves_typing_l1]) is also K-free.
76+
77+
A follow-up slice should rewrite [mode_le_trans] and
78+
[degrade_mode_comp] using raw dependent pattern matching with
79+
motive tricks to be K-free, aligning with the Agda upstream and
80+
the rest of the Coq codebase. Tracked as L3.K proof-debt. *)
81+
82+
Require Import Coq.Bool.Bool.
83+
Require Import Coq.Program.Equality.
84+
85+
(** ===== Modes =====
86+
87+
The L2 layer of the design (PRESERVATION-DESIGN.md §5) parameterises
88+
the typing judgment over a modality [ℓ ∈ {Linear, Affine}]. L3
89+
consumes the modality to choose the echo discipline: Linear echoes
90+
are full fibers (proof-relevant), Affine echoes are propositional
91+
residues (proof-irrelevant). *)
92+
93+
Inductive Mode : Type :=
94+
| Linear : Mode
95+
| Affine : Mode.
96+
97+
(** The thin poset on Mode: [Linear ⊑ Linear], [Linear ⊑ Affine],
98+
[Affine ⊑ Affine]. This is the linearity-side analog of
99+
EchoLinear.agda's [_≤m_]. *)
100+
101+
(** Sort [Type] (not [Prop]) so [mode_le] can drive the
102+
[degrade_mode] dispatch at the Type level. Mirrors the Agda
103+
[data _≤m_ : Mode → Mode → Set]. *)
104+
105+
Inductive mode_le : Mode -> Mode -> Type :=
106+
| Linear_le_Linear : mode_le Linear Linear
107+
| Linear_le_Affine : mode_le Linear Affine
108+
| Affine_le_Affine : mode_le Affine Affine.
109+
110+
Lemma mode_le_refl : forall m, mode_le m m.
111+
Proof. intros [|]; constructor. Qed.
112+
113+
(** [Defined] (not [Qed]) so [mode_le_trans] is transparent and
114+
[degrade_mode_comp] can [simpl] through its applications. Uses
115+
[dependent destruction] (K-dependent) — see the proof-debt note
116+
at the top of the file. *)
117+
118+
Definition mode_le_trans
119+
(m1 m2 m3 : Mode)
120+
(H12 : mode_le m1 m2) (H23 : mode_le m2 m3) : mode_le m1 m3.
121+
Proof.
122+
destruct H12.
123+
- exact H23.
124+
- dependent destruction H23. exact Linear_le_Affine.
125+
- exact H23.
126+
Defined.
127+
128+
(** Propositionality of the mode order. Each pair [(m1, m2)] has at
129+
most one inhabitant in [mode_le]. This is what lets us collapse
130+
composed-via-[m2] weakening proofs against an independently-given
131+
[m1 ⊑ m3] in [degrade_mode_compose].
132+
133+
Mirrors EchoLinear.agda's [≤m-prop]. *)
134+
135+
Lemma mode_le_prop :
136+
forall m1 m2 (p q : mode_le m1 m2), p = q.
137+
Proof.
138+
intros m1 m2 p q.
139+
destruct p;
140+
refine
141+
match q as q'
142+
in mode_le mA mB
143+
return
144+
(match mA, mB return mode_le mA mB -> Prop with
145+
| Linear, Linear => fun q'' => Linear_le_Linear = q''
146+
| Linear, Affine => fun q'' => Linear_le_Affine = q''
147+
| Affine, Affine => fun q'' => Affine_le_Affine = q''
148+
| _, _ => fun _ => True
149+
end q')
150+
with
151+
| Linear_le_Linear => eq_refl
152+
| Linear_le_Affine => eq_refl
153+
| Affine_le_Affine => eq_refl
154+
end.
155+
Qed.
156+
157+
(** ===== The Echo type former =====
158+
159+
[Echo f y] is the fiber of [f : A → B] over [y : B] — the type of
160+
pairs [(x, p)] where [x : A] and [p : f x = y]. Proof-relevant:
161+
*which* preimage maps to [y] is information the irreversibility of
162+
[f] deliberately erased and that this type recovers as a witness.
163+
164+
Mirrors echo-types/proofs/agda/Echo.agda:14-15. *)
165+
166+
Record Echo {A B : Type} (f : A -> B) (y : B) : Type := mkEcho {
167+
echo_witness : A;
168+
echo_eq : f echo_witness = y
169+
}.
170+
171+
Arguments mkEcho {A B f y} echo_witness echo_eq.
172+
Arguments echo_witness {A B f y} _.
173+
Arguments echo_eq {A B f y} _.
174+
175+
(** Introduction into the own fiber. Mirrors [echo-intro] in Echo.agda. *)
176+
177+
Definition echo_intro {A B : Type} (f : A -> B) (x : A) : Echo f (f x) :=
178+
mkEcho x eq_refl.
179+
180+
(** ===== Linear vs Affine echo: the L3 carrier =====
181+
182+
A concrete instance of the two-mode echo, matching
183+
EchoLinear.agda's characteristic carrier:
184+
185+
- Linear echo is the full fiber [Echo collapse tt] for the
186+
forgetful [collapse : bool → unit]. The fiber has two distinct
187+
inhabitants (one per bool); these are the [echo_true] and
188+
[echo_false] of EchoCharacteristic.agda.
189+
- Affine echo is the trivial residue [unit]: any two affine
190+
echoes are equal.
191+
192+
This concrete pair is enough to state and prove the headline
193+
weakening + decoration-commuting lemmas. The full
194+
[EchoR ⊤ TrivialCert tt] residue form and the [no-section]
195+
impossibility result are deferred to a separate slice. *)
196+
197+
Definition collapse (b : bool) : unit := tt.
198+
199+
Definition LEcho (m : Mode) : Type :=
200+
match m with
201+
| Linear => Echo collapse tt
202+
| Affine => unit
203+
end.
204+
205+
(** Linear-mode constants: the two distinguishable echoes. *)
206+
207+
Definition echo_true : LEcho Linear := mkEcho true eq_refl.
208+
Definition echo_false : LEcho Linear := mkEcho false eq_refl.
209+
210+
(** The two Linear echoes really are distinct — the witnesses are
211+
different bools. *)
212+
213+
Lemma echo_true_ne_echo_false : echo_true <> echo_false.
214+
Proof.
215+
intro H.
216+
assert (Hwit : echo_witness echo_true = echo_witness echo_false)
217+
by (rewrite H; reflexivity).
218+
simpl in Hwit. discriminate.
219+
Qed.
220+
221+
(** The Linear-to-Affine weakening: the irreversible collapse.
222+
223+
Mirrors EchoLinear.agda:38-39 ([weaken : LEcho linear → LEcho
224+
affine]). In this concrete instance the weakening simply forgets
225+
the bool witness, since the affine residue carries none. *)
226+
227+
Definition weaken (e : LEcho Linear) : LEcho Affine := tt.
228+
229+
(** Witness that the Linear distinction collapses under weakening —
230+
both [echo_true] and [echo_false] weaken to the same affine
231+
residue. Mirrors EchoLinear.agda's
232+
[weaken-collapses-distinction]. *)
233+
234+
Lemma weaken_collapses_distinction :
235+
weaken echo_true = weaken echo_false.
236+
Proof. reflexivity. Qed.
237+
238+
(** All Affine echoes are equal (propositionality of [unit]). *)
239+
240+
Lemma affine_canonical : forall e : LEcho Affine, e = tt.
241+
Proof. intros []; reflexivity. Qed.
242+
243+
Lemma affine_all_equal :
244+
forall e1 e2 : LEcho Affine, e1 = e2.
245+
Proof.
246+
intros e1 e2.
247+
rewrite (affine_canonical e1).
248+
rewrite (affine_canonical e2).
249+
reflexivity.
250+
Qed.
251+
252+
(** ===== Mode weakening on echoes (decoration-commuting recipe) =====
253+
254+
[degrade_mode] is the dispatch function: identity on the
255+
reflexive cases ([Linear ⊑ Linear], [Affine ⊑ Affine]) and
256+
[weaken] on the strict step ([Linear ⊑ Affine]).
257+
258+
Mirrors EchoLinear.agda:85-88. *)
259+
260+
Definition degrade_mode {m1 m2 : Mode}
261+
(p : mode_le m1 m2) : LEcho m1 -> LEcho m2 :=
262+
match p in mode_le mA mB return LEcho mA -> LEcho mB with
263+
| Linear_le_Linear => fun e => e
264+
| Linear_le_Affine => weaken
265+
| Affine_le_Affine => fun e => e
266+
end.
267+
268+
(** Identity weakening corollaries: degrading along a reflexive proof
269+
is the identity. Useful when chaining with [degrade_mode_comp]. *)
270+
271+
Lemma degrade_mode_id_linear :
272+
forall e : LEcho Linear,
273+
degrade_mode Linear_le_Linear e = e.
274+
Proof. reflexivity. Qed.
275+
276+
Lemma degrade_mode_id_affine :
277+
forall e : LEcho Affine,
278+
degrade_mode Affine_le_Affine e = e.
279+
Proof. reflexivity. Qed.
280+
281+
(** The strict step agrees with [weaken] definitionally. *)
282+
283+
Lemma degrade_mode_strict_is_weaken :
284+
forall e : LEcho Linear,
285+
degrade_mode Linear_le_Affine e = weaken e.
286+
Proof. reflexivity. Qed.
287+
288+
(** Headline per-decoration composition lemma: two successive mode
289+
weakenings agree with a single weakening along the composed
290+
ordering proof.
291+
292+
Mirrors EchoLinear.agda's [degradeMode-comp] (lines 93-101). This
293+
is the L3 instance of the "decoration commuting" recipe noted in
294+
PRESERVATION-DESIGN.md §3 and §5; combined with [mode_le_prop],
295+
it lets any two factorisations of a mode-weakening through the
296+
same composite [m1 ⊑ m3] agree. *)
297+
298+
Lemma degrade_mode_comp :
299+
forall {m1 m2 m3} (p12 : mode_le m1 m2) (p23 : mode_le m2 m3)
300+
(e : LEcho m1),
301+
degrade_mode p23 (degrade_mode p12 e) =
302+
degrade_mode (mode_le_trans m1 m2 m3 p12 p23) e.
303+
Proof.
304+
intros m1 m2 m3 p12 p23 e.
305+
destruct p12.
306+
- reflexivity.
307+
- dependent destruction p23. reflexivity.
308+
- dependent destruction p23. reflexivity.
309+
Qed.
310+
311+
(** Free-factoring composition law: any direct ordering proof
312+
[p13 : mode_le m1 m3] agrees with the composed-via-[m2] weakening,
313+
because [mode_le_prop] makes the choice of factoring irrelevant.
314+
315+
Mirrors EchoLinear.agda's [degradeMode-compose]. *)
316+
317+
Lemma degrade_mode_compose :
318+
forall {m1 m2 m3}
319+
(p12 : mode_le m1 m2) (p23 : mode_le m2 m3)
320+
(p13 : mode_le m1 m3) (e : LEcho m1),
321+
degrade_mode p23 (degrade_mode p12 e) =
322+
degrade_mode p13 e.
323+
Proof.
324+
intros m1 m2 m3 p12 p23 p13 e.
325+
rewrite (mode_le_prop _ _ p13 (mode_le_trans _ _ _ p12 p23)).
326+
apply degrade_mode_comp.
327+
Qed.
328+
329+
(** ===== Cross-mode characteristic =====
330+
331+
Witness that Linear→Affine weakening is genuinely lossy: there
332+
exist distinct Linear echoes whose Affine weakenings are equal.
333+
Mirrors EchoLinear.agda's [strict-linear-example]. *)
334+
335+
Lemma strict_linear_example :
336+
exists e1 e2 : LEcho Linear,
337+
e1 <> e2 /\ weaken e1 = weaken e2.
338+
Proof.
339+
exists echo_true, echo_false.
340+
split.
341+
- apply echo_true_ne_echo_false.
342+
- apply weaken_collapses_distinction.
343+
Qed.

formal/_CoqProject

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ TypingL1.v
1010
Semantics.v
1111
Semantics_L1.v
1212
Counterexample.v
13+
Echo.v

0 commit comments

Comments
 (0)