Skip to content

Commit 06e344f

Browse files
hyperpolymathclaude
andcommitted
proof+design: verified counterexample to preservation + four-layer redesign
formal/Counterexample.v exhibits a configuration that types under the current rules at R = [r0; r1] : TProd (TString r0) (TString r1) but single-steps to an untypable expression at R = [r0]. Three lemmas Qed: - bad_typable : the input has a derivation - bad_step : the operational reduction exists - bad_post_untypable : the post-step has no derivation at the same outer type Preservation as currently stated is therefore *false*, not unproven. formal/PRESERVATION-DESIGN.md is the principled redesign: - L1 — region capabilities threaded as input/output environments through every typing rule (the preservation fix) - L2 — structural modality (Linear ↔ Affine) as a judgment parameter, with Linear ⊆ Affine via a thin-poset weakening - L3 — irreversibility residue (Echo) as a fiber type former over irreversible operations, decorated by the L2 modality (linear- echo = mandatory observation; affine-echo = optional lowering) - L4 — project-level dyadic mode declaration Layers compose without coherence obligations because each is a thin-poset decoration, lifted verbatim from the echo-types mechanisation (echo-types/proofs/agda/EchoLinear.agda:30-101). §12 lays out the documentation rollout plan (README, EXPLAINME, EPHAPAX-VISION, ROADMAP, CHANGELOG, spec, CLAUDE.md, machine-readable a2ml, wiki) with draft text. Held until L1 implementation begins. §12.15 makes explicit what is *not* mechanised today: ephapax-affine type proofs as a distinct body do not exist; the L1 redesign alone does not establish them; L2 + a separate weakening lemma are required. §12.16 documents the v2 research track "Echo as operational foundation" — a coherent sibling calculus where Echo is the foundation, regions are syntactic sugar. Not scheduled; seed only. This PR is the design + counterexample. L1 implementation, layer proofs, and the documentation rollout are all separate, sequenced follow-ups gated on this landing. PRESERVATION-HANDOFF.md gains a supersession banner pointing readers to the design doc for the closure decision; the per-case diagnostic content remains valid as a record of the closure attempts. Refs: ephapax#146 (the parallel Option A work on lemma-b-phase2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1bda88d commit 06e344f

4 files changed

Lines changed: 1358 additions & 4 deletions

File tree

formal/Counterexample.v

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
(* SPDX-License-Identifier: PMPL-1.0-or-later *)
2+
(* SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell *)
3+
4+
(** * Soundness gap: counterexample to preservation as currently stated
5+
6+
Exhibits a concrete configuration where the calculus's typing rules
7+
accept a well-typed input that, after a single step, becomes untypable
8+
at the same outer type.
9+
10+
Configuration:
11+
e := EPair (ERegion r' (ELoc l0 r0)) (ELoc l1 r')
12+
: TProd (TString r0) (TString r') at R = [r0; r']
13+
e' := EPair (ELoc l0 r0) (ELoc l1 r')
14+
at R = [r0] (r' has been exited)
15+
Step: S_Pair_Step1 lifting S_Region_Exit on the inner ERegion r'.
16+
17+
The post-step sibling ELoc l1 r' requires In r' [r0] — false.
18+
Hence [exists G_out, [r0]; G |- e' : TProd (TString r0) (TString r') -| G_out]
19+
fails. Preservation, as stated, does not hold for this input.
20+
21+
Diagnoses the obstacle for preservation's 10 touches_region RIGHT
22+
branches: closing them requires a type-system change (Option 3 in
23+
PRESERVATION-HANDOFF.md), not a proof technique. *)
24+
25+
From Ephapax Require Import Syntax Typing Semantics.
26+
Require Import Coq.Strings.String.
27+
Require Import Coq.Lists.List.
28+
Import ListNotations.
29+
Open Scope string_scope.
30+
31+
Section Counterexample.
32+
33+
Definition r0 : region_name := "r0".
34+
Definition r1 : region_name := "r1".
35+
Definition l0 : loc := 0.
36+
Definition l1 : loc := 1.
37+
38+
(* Bad input: pair of (region r1 containing a TString-r0 value) and
39+
(a TString-r1 location). Both children typeable at R = [r0; r1]. *)
40+
Definition e_bad : expr :=
41+
EPair (ERegion r1 (ELoc l0 r0)) (ELoc l1 r1).
42+
43+
Definition T_bad : ty := TProd (TString r0) (TString r1).
44+
45+
(** ===== (a) The bad input is well-typed at R = [r0; r1]. ===== *)
46+
47+
Lemma bad_typable :
48+
has_type (r0 :: r1 :: nil) nil e_bad T_bad nil.
49+
Proof.
50+
unfold e_bad, T_bad.
51+
eapply T_Pair with (G' := nil).
52+
- (* ERegion r1 (ELoc l0 r0) : TString r0 at [r0; r1] -| []. *)
53+
eapply T_Region_Active.
54+
+ (* In r1 [r0; r1]. *) right. left. reflexivity.
55+
+ (* ~In r1 (free_regions (TString r0)) = ~In "r1" ["r0"]. *)
56+
simpl. intros [Heq | []].
57+
unfold r0, r1 in Heq. discriminate.
58+
+ (* ELoc l0 r0 : TString r0. *)
59+
apply T_Loc. unfold region_active. left. reflexivity.
60+
- (* ELoc l1 r1 : TString r1 at [r0; r1] -| []. *)
61+
apply T_Loc. unfold region_active. right. left. reflexivity.
62+
Qed.
63+
64+
(* The post-step expression: r1 has been exited; sibling still
65+
references r1. *)
66+
Definition e_bad_post : expr :=
67+
EPair (ELoc l0 r0) (ELoc l1 r1).
68+
69+
(** ===== (b) The bad input steps to e_bad_post at R = [r0]. =====
70+
71+
S_Pair_Step1 lifts an inner S_Region_Exit on the first child.
72+
The exit fires because:
73+
- ELoc l0 r0 is a value (VLoc).
74+
- In r1 [r0; r1].
75+
- expr_free_of_region r1 (ELoc l0 r0) — i.e. r0 ≠ r1. *)
76+
Lemma bad_step :
77+
forall mu,
78+
step (mu, r0 :: r1 :: nil, e_bad)
79+
(mem_free_region mu r1, r0 :: nil, e_bad_post).
80+
Proof.
81+
intros mu.
82+
unfold e_bad, e_bad_post.
83+
apply S_Pair_Step1.
84+
(* Inner: (mu, [r0; r1], ERegion r1 (ELoc l0 r0))
85+
-> (mem_free_region mu r1, remove_first r1 [r0; r1], ELoc l0 r0).
86+
remove_first r1 [r0; r1] = [r0] (skips r0, removes first r1). *)
87+
replace (r0 :: nil) with (remove_first r1 (r0 :: r1 :: nil)).
88+
- apply S_Region_Exit.
89+
+ (* is_value (ELoc l0 r0). *) constructor.
90+
+ (* In r1 [r0; r1]. *) right. left. reflexivity.
91+
+ (* expr_free_of_region r1 (ELoc l0 r0) = (r0 <> r1). *)
92+
simpl. intros Heq. unfold r0, r1 in Heq. discriminate.
93+
- (* remove_first r1 [r0; r1] = [r0]: r0 ≠ r1 skips, then matches r1. *)
94+
simpl. unfold r0, r1.
95+
destruct (String.eqb "r1" "r0") eqn:Heq.
96+
+ apply String.eqb_eq in Heq. discriminate.
97+
+ destruct (String.eqb "r1" "r1") eqn:Heq2.
98+
* reflexivity.
99+
* apply String.eqb_neq in Heq2. exfalso. apply Heq2. reflexivity.
100+
Qed.
101+
102+
(** ===== (c) e_bad_post is NOT typeable at R = [r0] : T_bad. =====
103+
104+
The sibling ELoc l1 r1 requires In r1 [r0], which is false. *)
105+
Lemma bad_post_untypable :
106+
forall G G',
107+
~ has_type (r0 :: nil) G e_bad_post T_bad G'.
108+
Proof.
109+
intros G G' Htype.
110+
unfold e_bad_post, T_bad in Htype.
111+
(* Invert T_Pair to expose the two children. *)
112+
inversion Htype; subst.
113+
(* The TString-r1 child: invert T_Loc, get the bad region_active premise. *)
114+
match goal with
115+
| [ H : has_type _ _ (ELoc l1 r1) (TString r1) _ |- _ ] =>
116+
inversion H; subst
117+
end.
118+
(* region_active [r0] r1 = In "r1" ["r0"], which is false. *)
119+
match goal with
120+
| [ H : region_active _ r1 |- _ ] =>
121+
unfold region_active in H; simpl in H;
122+
destruct H as [Heq | []];
123+
unfold r0, r1 in Heq; discriminate
124+
end.
125+
Qed.
126+
127+
(** ===== Conclusion =====
128+
129+
Preservation, as currently stated, is FALSE for input e_bad.
130+
[bad_typable] shows the input is well-typed; [bad_step] shows
131+
a single-step reduction exists; [bad_post_untypable] shows the
132+
result of that reduction is untypable at the same outer type.
133+
134+
The 11 remaining preservation admits on the [touches_region]
135+
RIGHT branches share this structure. A type-system change
136+
(Option 3 in PRESERVATION-HANDOFF.md) is required. *)
137+
138+
End Counterexample.

0 commit comments

Comments
 (0)