docs+test: Phase D slice 4 Phase 4c — mechanised soundness-gap counterexample for TFunEff β#234
Merged
hyperpolymath merged 1 commit intoMay 30, 2026
Conversation
…rexample for TFunEff β Ships a mechanised proof that preservation_l2 fails for TFunEff substituends inside fresh-region scopes, plus a design-doc addendum prescribing the conditional Phase 4c closure path. ## What this PR ships ### `formal/Counterexample_L2.v` (new) Three Qed lemmas (zero axioms, zero admits) witnessing the soundness gap: - `e_before_typed` — input `EApp outer v2` types via T_App_L2_Eff at `TFunEff TUnit TUnit [] []`. - `e_step` — operational step S_App_Fun reduces to `ERegion r2 v2`. - `e_after_untypable` — no L1 derivation exists for the β-result at the same outer type. Configuration: ``` T1_inner = TFunEff TUnit TUnit [] [] (* R_in_v = [] *) outer = ELam T1_inner (ERegion r2 (EVar 0)) v2 = ELam TUnit EUnit e_before = EApp outer v2 (* well-typed *) e_after = ERegion r2 v2 (* β-result, not well-typed *) ``` Structural mechanism: T_Region_L1's `~ In r (free_regions T)` premise prevents the fresh r from being in `R_in_v ⊆ free_regions(TFunEff)`, so the post-β term's inner TFunEff value cannot re-type at the new threaded R = `r :: R`. ### `formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md` addendum New §"Phase 4c addendum (2026-05-30) — conditional preservation_l2 for TFunEff β" documents the counterexample and prescribes three resolution paths: 1. **Conditional preservation_l2 (recommended)** — Phase 3b lemma takes the `regions_introduced_by(e) ⊆ R_in_v` precondition; Phase 4c β-case requires it; programs outside form a documented soundness-gap class. Aligns with `Counterexample.v` precedent. 2. **Region-polymorphic TFunEff** — type-system change deferred to a future redesign. 3. **L2 region-transfer combinator** — adds L2 expressiveness in a future PR. ### `formal/_CoqProject` Adds `Counterexample_L2.v` after `TypingL2.v` in the build order. ### `.machine_readable/6a2/STATE.a2ml` `next_action` shifted to Phase 3b implementation (option-(a) precondition codified by this PR's counterexample); `last_action` records the counterexample landing. ## Build + assumption audit - `coqc -R . Ephapax` clean rebuild across all 11 .v files. - `Print Assumptions e_before_typed` / `e_step` / `e_after_untypable` → "Closed under the global context" for all three. **Zero axioms.** ## Owner-directive compliance (CLAUDE.md 2026-05-27) - Does not modify `formal/Semantics.v` or `formal/Counterexample.v` (the legacy soundness-gap artifacts). - Does not patch `formal/Typing.v` (legacy judgment). - Does not close any residual `formal/Semantics_L1.v` admit. - Adds NEW infrastructure (a new file) orthogonal to legacy admits, mirroring the precedent of `Counterexample.v` for the legacy preservation. - No new `Axiom` or `Admitted` markers. ## Why this matters Before Phase 3b implementation (~400 lines per PR #230's analysis), this counterexample mechanically witnesses the structural constraint the lemma must satisfy. The conditional preservation_l2 design is now rigorously justified rather than asserted on paper. Refs: - ephapax#225 — Phase 3b tracking issue (option (a) selected). - ephapax#225 comment 4583148707 — on-paper prototype that motivated this mechanical formalisation. - PR #230 — `regions_introduced_by` scaffold (option (a)'s syntactic helper). - PR #228 — Phase 4a (linear T1, no soundness gap). - PR #233 — Phase 4b (ground-non-linear T1, no soundness gap). - `formal/Counterexample.v` — legacy preservation counterexample (precedent for this file's structure). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| @@ -0,0 +1,202 @@ | |||
| (* SPDX-License-Identifier: PMPL-1.0-or-later *) | |||
| @@ -0,0 +1,202 @@ | |||
| (* SPDX-License-Identifier: PMPL-1.0-or-later *) | |||
🔍 Hypatia Security ScanFindings: 78 issues detected
View findings[
{
"reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in abi-verify.yml",
"type": "unknown",
"file": "abi-verify.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in boj-build.yml",
"type": "unknown",
"file": "boj-build.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "unknown",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in coq-build.yml",
"type": "unknown",
"file": "coq-build.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in governance.yml",
"type": "unknown",
"file": "governance.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in hypatia-scan.yml",
"type": "unknown",
"file": "hypatia-scan.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in instant-sync.yml",
"type": "unknown",
"file": "instant-sync.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in mirror.yml",
"type": "unknown",
"file": "mirror.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in rust-ci.yml",
"type": "unknown",
"file": "rust-ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This was referenced May 30, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…ut EACCES coqorg/coq:8.18 defaults to the non-root `coq` user (UID 1000). actions/checkout's post-step writes save_state files to /__w/_temp/_runner_file_commands which is mounted from the runner host; the coq user lacks write permission there and the job dies with EACCES before `coq_makefile` runs (see #234 PR run). `--user root` makes the shared workspace paths writable while leaving the in-container build environment effectively unchanged (root inside the container maps to the runner host's runner user via the Actions sandbox). Without this fix the merge-oracle workflow itself can't run, defeating the hard-gate guarantee in [[feedback_proof_pr_build_oracle_is_only_truth]]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…DE.md DO #4 (closes nothing, files #235) Pre-implementation review of Phase 3b's option (a) precondition (forall r, In r (regions_introduced_by e) -> In r R_in_v) found it INSUFFICIENT to discharge T_Lam_L1_*_Eff body cases of the planned subst_typing_gen_l1_m_tfuneff lemma. Why: the substitution lemma recurses into inner lambda bodies (Phase 2 does so via the IH at formal/Semantics_L1.v:1929-1942). Inner T_Lam_L1_*_Eff bodies type at the lambda's declared R_in_inner. R_in is type-level — it lives in the TFunEff slot of the function's TYPE, not in syntax. `regions_introduced_by(e)` only collects ERegion subterms' first arguments; R_in_inner is invisible to it. `tfuneff_lambda_retype_l1_m` (PR #224) requires R' ⊆ R_in_v to discharge T_Lam_L1_*_Eff's side condition. We have no way to bound inner R_in by R_in_v. Phase 2's `subst_typing_gen_l1_m_ground_nonlinear` dodges this via `ground_nonlinear_retype_l1_m`, which is fully (m, R, G)-polymorphic. Phase 3b's TFunEff retype has no analogous escape. Three resolution options documented: 1. Syntactic helper `declared_lambda_r_ins` — requires ELam annotation extension (parameter type only in current syntax). 2. Semantic precondition over the derivation — clean meaning, awkward in Coq. 3. Leaf-only Phase 3b via `tfuneff_lambda_free e` predicate — tactical landing; Phase 5 compound-value redesign subsumes (1)/(2) at leisure. Recommended: option (3). Owner decision required before Phase 3b implementation can start. This PR contains documentation only: - formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md gains a Phase 3b addendum documenting the gap and three resolution options. - .machine_readable/6a2/STATE.a2ml flips phase to `blocked-on-owner-decision` with next_action pointing at #235. No formal/*.v changes. Predecessor PRs unaffected: - Phase 4a (#228) MERGED. - Phase 4b (parallel session, #233) MERGED. - Phase 4c counterexample (#234) auto-merge pending. Phase 4c's `Counterexample_L2.v` independently justifies the conditional preservation_l2 statement regardless of which Phase 3b resolution lands. Per CLAUDE.md owner directive §DO #4 (escalate before patching): this PR IS the escalation. Owner-directive compliance: - No Semantics.v / Typing.v / Counterexample.v touch - No new Axiom / Admitted markers - No closure of residual Semantics_L1.v admits - No sibling-region-disjointness side conditions - No proposal to close `Theorem preservation` to Qed. Refs: #225 (Phase 3b parking lot), #230 (regions_introduced_by helper), #233 (Phase 4b), #234 (Phase 4c counterexample), Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…DE.md DO #4 (closes nothing, files #235) Pre-implementation review of Phase 3b's option (a) precondition (forall r, In r (regions_introduced_by e) -> In r R_in_v) found it INSUFFICIENT to discharge T_Lam_L1_*_Eff body cases of the planned subst_typing_gen_l1_m_tfuneff lemma. Why: the substitution lemma recurses into inner lambda bodies (Phase 2 does so via the IH at formal/Semantics_L1.v:1929-1942). Inner T_Lam_L1_*_Eff bodies type at the lambda's declared R_in_inner. R_in is type-level — it lives in the TFunEff slot of the function's TYPE, not in syntax. `regions_introduced_by(e)` only collects ERegion subterms' first arguments; R_in_inner is invisible to it. `tfuneff_lambda_retype_l1_m` (PR #224) requires R' ⊆ R_in_v to discharge T_Lam_L1_*_Eff's side condition. We have no way to bound inner R_in by R_in_v. Phase 2's `subst_typing_gen_l1_m_ground_nonlinear` dodges this via `ground_nonlinear_retype_l1_m`, which is fully (m, R, G)-polymorphic. Phase 3b's TFunEff retype has no analogous escape. Three resolution options documented: 1. Syntactic helper `declared_lambda_r_ins` — requires ELam annotation extension (parameter type only in current syntax). 2. Semantic precondition over the derivation — clean meaning, awkward in Coq. 3. Leaf-only Phase 3b via `tfuneff_lambda_free e` predicate — tactical landing; Phase 5 compound-value redesign subsumes (1)/(2) at leisure. Recommended: option (3). Owner decision required before Phase 3b implementation can start. This PR contains documentation only: - formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md gains a Phase 3b addendum documenting the gap and three resolution options. - .machine_readable/6a2/STATE.a2ml flips phase to `blocked-on-owner-decision` with next_action pointing at #235. No formal/*.v changes. Predecessor PRs unaffected: - Phase 4a (#228) MERGED. - Phase 4b (parallel session, #233) MERGED. - Phase 4c counterexample (#234) auto-merge pending. Phase 4c's `Counterexample_L2.v` independently justifies the conditional preservation_l2 statement regardless of which Phase 3b resolution lands. Per CLAUDE.md owner directive §DO #4 (escalate before patching): this PR IS the escalation. Owner-directive compliance: - No Semantics.v / Typing.v / Counterexample.v touch - No new Axiom / Admitted markers - No closure of residual Semantics_L1.v admits - No sibling-region-disjointness side conditions - No proposal to close `Theorem preservation` to Qed. Refs: #225 (Phase 3b parking lot), #230 (regions_introduced_by helper), #233 (Phase 4b), #234 (Phase 4c counterexample), Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…ut EACCES (#236) ## Summary The Coq merge-oracle workflow (`coq-build.yml`) was failing across every `formal/` PR (including #234 which had to bypass) with: ``` Error: EACCES: permission denied, open '/__w/_temp/_runner_file_commands/save_state_…' ``` ## Root cause `coqorg/coq:8.18` defaults to the non-root `coq` user (UID 1000). `actions/checkout` writes save_state files to `/__w/_temp/_runner_file_commands` which is mounted from the runner host — the `coq` user lacks write permission there. The job dies in checkout's post-step before `coq_makefile` runs. ## Fix `container.options: --user root` runs the container as root. The shared workspace paths become writable; the in-container build environment is otherwise unchanged (root inside the container maps to the runner host's runner user via the Actions sandbox, not host-root). ## Why this matters Per `[[feedback_proof_pr_build_oracle_is_only_truth]]` the Coq workflow is the *only* merge oracle for `formal/` PRs. If the workflow itself can't run, the hard gate is effectively bypassed. ## Test plan - [ ] `Coq build — formal/_CoqProject` goes green on this PR - [ ] `Print Assumptions of load-bearing theorem` step actually executes (visible in run log) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
/ #242) (#237) ## Summary Phase D slice 4 Phase 3b — design-gap finding (#235) **+ 4-stage staged resolution plan** owner-approved 2026-05-30 PM. Stages tracked at #239 / #240 / #241 / #242. No `formal/*.v` changes. No CI changes (the parallel-session PR #236 owns the Coq EACCES fix). ## 4-stage staged resolution plan The original three-option framing in #235 is **superseded** by a staged plan that captures all three "Interesting" values without committing to any single option's downsides. | Stage | Issue | Scope | Captures value of | |---|---|---|---| | **Stage 1 — IMMEDIATE** | #239 | Leaf-only Phase 3b via `tfuneff_lambda_free` + `Counterexample_L2_nested.v` + 2-condition `preservation_l2`. | Option (3) — principled deferral, honest 2-condition statement. | | **Stage 2 — parallel L4 track** | #240 | `ELam T_param R_in R_out body` annotation extension. AST + typing rule + cascading. | Option (1) — L4 "type-level → program-level commitments". | | **Stage 3 — post-Stage-2** | #241 | Relaxed Phase 3b via `declared_lambda_r_ins ⊆ R_in_v` + CPS v-typing argument. Nested-condition collapses. | Option (2) — higher-order proof style enters codebase. | | **Stage 4 — Phase 5** | #242 | Compound non-linear + region-substitution machinery + **unconditional** `preservation_l2`. | The final destination. | ### Why staging beats single-option commitments - **(1) alone**: forces AST migration before unblocking preservation_l2. - **(2) alone**: introduces inductive-over-derivations predicate with no other use in the codebase. - **(3) alone**: ends with conditional preservation_l2 forever (no path to unconditional). The staged plan: (3) ships today's value at Stage 1, (1) lands L4's value at L4's timeline (Stage 2), (2)'s value is harvested at exactly the point CPS is necessary not over-engineered (Stage 3), (4) reaches unconditional preservation_l2 as the natural sum. ### Stage 1's correctness is delivered, not provisional Each of the 2 conditions on Stage 1's `preservation_l2` has a **mechanised counterexample**: - `Counterexample_L2.v` (already on main, PR #234) — fresh-region gap. - `Counterexample_L2_nested.v` (new in Stage 1) — nested-lambda gap. Programs outside the conditional form a precisely-documented soundness class. ### Sequencing - Stage 1 green-lit (#239). Implementation ships next session. - Stages 2-4 tracked but NOT actioned this session. - Stage 3 blocked on Stage 2; Stage 4 blocked on Stage 3; Stage 2 independent of Stage 1. ## Changes - `formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md` — Phase 3b addendum (gap finding + 3-options framing) **+ Phase 3b resolution addendum (4-stage staged plan)**. - `.machine_readable/6a2/STATE.a2ml` — phase = `implementation`; next_action = Stage 1 (#239) implementation. No `formal/*.v` changes; Coqc 8.18.0 unaffected. ## Predecessor PRs - Phase 4a (#228) MERGED — `preservation_l2_app_eff_beta_linear`. - Phase 4b (#233) MERGED — `preservation_l2_app_eff_beta_ground_nonlinear_l1`. - Phase 4c (#234) MERGED — `Counterexample_L2.v` 3-Qed soundness-gap witness. ## Owner-directive compliance (across all 4 stages) - ✅ No `Semantics.v` / `Typing.v` / `Counterexample.v` (legacy) touch. - ✅ No new `Axiom` / `Admitted` markers. - ✅ No closure of residual `Semantics_L1.v` admits — strictly NEW infrastructure under the four-layer redesign. - ✅ Per-layer derivation: preservation_l2 closes via L2 infra; legacy preservation remains Admitted (PROVABLY FALSE) per 2026-05-27 directive. ## Test plan - [ ] CI green (no code changes; Coq oracle should pass unchanged — pending PR #236's EACCES fix landing). - [ ] Issues #235 / #239 / #240 / #241 / #242 cross-referenced. Refs: #225 (Phase 3b parking lot), #230 (`regions_introduced_by`), #233 (Phase 4b), #234 (Phase 4c), #235 (parent finding), #236 (parallel Coq EACCES fix), #239 (Stage 1), #240 (Stage 2), #241 (Stage 3), #242 (Stage 4). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
## Summary - Rewords two docstring lines in `formal/Counterexample_L2.v` to clear `code_safety/admitted` + `code_safety/coq_admit_tactic` Hypatia false-positives now red on main since #234 merged - No code change; pure documentation rewording ## Background `Counterexample_L2.v`'s docstring "Owner-directive compliance" section mentioned the literal words "admit" and "[Admitted]" as documentation of what the file does NOT do. Hypatia's regex (`\bAdmitted\b` / `\badmit\b`) cannot distinguish documentation of absence from actual escape hatches. Two lines reworded: - Line 50: `Does not close any residual [Semantics_L1.v] admit.` → `Does not close any residual proof-debt in [Semantics_L1.v].` - Line 54: `No new [Axiom] or [Admitted] markers.` → `Zero new top-level proof-hole markers ([Axiom] declarations or Coq unproven-goal forms).` Semantics preserved; "proof-debt" and "proof-hole markers" are the standards-canonical terms (per Trusted-Base Reduction Policy). ## Verification `grep -nE "\b(admit|Admitted)\b" formal/Counterexample_L2.v` returns no matches. ## Test plan - [x] No remaining word-boundary matches for the two flagged regexes - [ ] `hypatia / Hypatia Neurosymbolic Analysis` green on this PR - [ ] Auto-merge SQUASH armed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
3 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…ounterexample_L2_nested (#252) ## Summary Ships the **Stage 1a** slice of the four-stage Phase 3b resolution plan (parent #235 / Stage 1 #239 / Stages 2-4 #240-#242). Stage 1 splits into 1a (this PR — syntactic infrastructure + mechanised nested-lambda soundness-gap witness) and 1b (#249 — substitution lemma + preservation_l2 β wrapper) for shipping cadence. ## What lands - **NEW `Fixpoint tfuneff_lambda_free : expr -> bool`** in `formal/Syntax.v`. Conservative leaf-only predicate: `false` on every `ELam`, compositional `andb` propagation through compound forms. Used by Stage 1b's substitution lemma to exfalso the inner `T_Lam_L1_*_Eff` cases. - **NEW `formal/Counterexample_L2_nested.v`** — three Qed lemmas (`e_before_typed`, `e_step`, `e_after_untypable`) mechanising the nested-TFunEff soundness gap. Sibling artifact to `Counterexample_L2.v` (PR #234): together the two files justify the **two-condition** preservation_l2 statement Stage 1 delivers — P1 (`tfuneff_lambda_free ebody = true`, rules out the nested-lambda gap class witnessed here) and P2 (`regions_introduced_by ebody ⊆ R_in_v`, rules out the fresh-region gap class witnessed in `Counterexample_L2.v`). - Wired into `formal/_CoqProject` after `Counterexample_L2.v`. - `formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md` gains a "Phase 3b Stage 1a (landed) — split from Stage 1" subsection documenting the 1a/1b split and the structural blocker (G-mismatch at compound binder rules). - `.machine_readable/6a2/STATE.a2ml` refreshes next_action to Stage 1b (#249). ## Configuration (nested-lambda counterexample) ``` outer = ELam T_v (ELam (TBase TUnit) (EVar 1)) T_inner = TFunEff (TBase TUnit) T_v [r2] [r2] v = ELam (TBase TUnit) EUnit at T_v = TFunEff TUnit TUnit [] [] e_before = EApp outer v at T_inner, R = [] (well-typed via T_App_L2_Eff) e_after = ELam (TBase TUnit) v at T_inner, R = [] (untypable) ``` The inner lambda's body references the outer-bound variable via `EVar 1`; post-β substitutes `v` for the outer variable. The resulting `ELam (TBase TUnit) v` cannot retype the inner `v` at `[r2] ⊄ [] = R_in_v`. ## Owner-directive compliance (CLAUDE.md 2026-05-27) - No touch to `formal/Semantics.v` / `Typing.v` / `Counterexample.v`. - No closure of residual `Semantics_L1.v` admits attempted. - Anti-pattern detector clean. - Strictly NEW infrastructure orthogonal to legacy. ## Test plan - [x] `just -f formal/Justfile all` clean across all 12 .v files with coqc 8.18.0. - [x] Print Assumptions on all three new Qed lemmas → Closed under the global context. - [ ] CI coq-build workflow passes (will check post-push). ## Refs - Parent finding: #235 - Stage 1 tracking: #239 (partially closes — Stage 1a deliverables) - Stage 1b sub-issue: #249 - Stages 2-4: #240 / #241 / #242 - Sibling counterexample: PR #234 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…ff substituents Ships the L2-judgment half of Stage 1b. Closes the [T_App_L2_Eff] β-case for T1 = TFunEff Ta Tb R_in_v R_out_v under the three-condition statement (P1 leaf-only body + P2 regions ⊆ R_in_v + P3 closure of v2). Mirrors PR #228's [preservation_l2_app_eff_beta_linear] (Phase 4a, linear T1) and Phase 4b's [preservation_l2_app_eff_beta_ground_nonlinear] (ground-non-linear T1) structurally with the same `value_R_G_preserving_l1`-collapse pattern. Two Qed lemmas: - `preservation_l2_app_eff_beta_tfuneff_l1` — the L1-level kernel. Inverts the lambda derivation through `T_Lam_L1_Linear_Eff` / `T_Lam_L1_Affine_Eff`; collapses R_in = R1 = R and G'' = G' = G via `value_R_G_preserving_l1`; then defers to the substitution kernel `subst_typing_gen_l1_m_tfuneff` (Phase 3b Stage 1b, this branch's prior commit) at k = 0. - `preservation_l2_app_eff_beta_tfuneff` — the L2 wrapper. Inverts both `has_type_l2` hypotheses through `L2_lift_l1` (the `T_App_L2_Eff` cases discriminate via expression-shape mismatch), then defers to the L1 kernel and re-lifts via `L2_lift_l1`. Combined with PRs #228 (Phase 4a, linear T1) and #233 (Phase 4b, ground-non-linear T1), this closes the `T_App_L2_Eff` β-case for T1 ∈ {linear, ground-non-linear, TFunEff}. Phase 4d (compound non- linear EPair / EInl / EInr / EEcho) remains open at Phase 5. Print Assumptions verdict: - preservation_l2_app_eff_beta_tfuneff_l1: Closed under the global context - preservation_l2_app_eff_beta_tfuneff: Closed under the global context Zero new axioms. Zero new admits. The mechanised soundness-gap witnesses for the conditional form are preserved in: - Counterexample_L2.v (PR #234, Phase 4c) — fresh-region gap (the counterexample to dropping P2). - Counterexample_L2_nested.v (Stage 1a, this PR's predecessor #252) — nested-lambda gap (the counterexample to dropping P1). The two files together justify why Stage 1 ships the two-condition (plus P3 closure) statement rather than an unconditional version. Stage 4 (#242) achieves the unconditional form once the L4 annotation extension (#240) and CPS argument (#241) land — the proof content of this PR's `closed_value_typing_*` family is reused unchanged in Stage 4 as the closure-discharge kernel. Also: STATE.a2ml refreshed — last_action now records the full Stage 1b deliverable surface; next_action advances to Stages 2-4. Owner-directive compliance (CLAUDE.md 2026-05-27): - ✅ No touch to formal/Semantics.v / Typing.v / Counterexample.v. - ✅ No closure of residual Semantics_L1.v admits attempted. - ✅ Anti-pattern detector clean. - ✅ Strictly NEW infrastructure orthogonal to legacy. Refs: - ephapax issue #249 (Stage 1b tracking — closes via this PR). - ephapax PR #252 (Stage 1a prerequisite). - ephapax issue #239 (parent Stage 1; closes via #252 + this PR). - formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md Phase 3b Stage 1b. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships a mechanised proof that preservation_l2 fails for TFunEff substituends inside fresh-region scopes, plus a design-doc addendum prescribing the conditional Phase 4c closure path.
This is the L1/L2 analogue of `formal/Counterexample.v` (which witnesses the legacy preservation's soundness gap), providing rigorous justification for the conditional preservation_l2 statement that Phase 4c will ship.
What this PR ships
`formal/Counterexample_L2.v` (new)
Three Qed lemmas (zero axioms, zero admits) witnessing the soundness gap:
Configuration:
```coq
T1_inner = TFunEff TUnit TUnit [] [] (* R_in_v = [] )
outer = ELam T1_inner (ERegion r2 (EVar 0)) ( body introduces fresh r2 )
v2 = ELam TUnit EUnit ( a value of type T1_inner )
e_before = EApp outer v2 ( well-typed )
e_after = ERegion r2 v2 ( β-result, NOT well-typed *)
```
Structural mechanism: T_Region_L1's `~ In r (free_regions T)` premise prevents the fresh r from being in `R_in_v ⊆ free_regions(TFunEff)`, so the post-β term's inner TFunEff value cannot re-type at the new threaded R = `r :: R`.
`formal/SUBST-LEMMA-GENERALIZATION-DESIGN.md` addendum
New §"Phase 4c addendum (2026-05-30) — conditional preservation_l2 for TFunEff β" documents the counterexample and prescribes three resolution paths:
`formal/_CoqProject`
Adds `Counterexample_L2.v` after `TypingL2.v` in the build order.
`.machine_readable/6a2/STATE.a2ml`
`next_action` shifted to Phase 3b implementation (option-(a) precondition codified by this PR's counterexample); `last_action` records the counterexample landing.
Build + assumption audit
Owner-directive compliance (CLAUDE.md 2026-05-27)
Why this matters
Before Phase 3b implementation (~400 lines per PR #230's analysis), this counterexample mechanically witnesses the structural constraint the lemma must satisfy. The conditional preservation_l2 design is now rigorously justified rather than asserted on paper.
Test plan
Refs
preservation_l2_app_eff_beta_linear+ hotfix duplicatetfuneff_lambda_retype_l1_m#228 — Phase 4a (linear T1, no soundness gap).🤖 Generated with Claude Code