Skip to content

Commit 9edb6e3

Browse files
claudehyperpolymath
authored andcommitted
proof(cubical): discharge (epi,mono) truncation axiom via real ∥_∥ HIT
EchoImageFactorizationPropCubical.agda constructs propositional truncation as a higher inductive type under --cubical --safe (zero postulates), realises the four TruncInterface obligations as theorems (is-prop-∥∥ from squash transported to the inductive _≡_; rec-∥∥ via the path recursor, its boundary closing by the cubical endpoint rule), and re-proves the (epi, mono) image factorisation — the genuine counterpart of the postulated --without-K demo (EchoImageFactorizationPropPostulated). Discharges proof-debt item (c) "necessary axiom": the truncation laws are no longer assumption-only. It is a --cubical flag island (Agda forbids importing the --safe --without-K Echo cone from --cubical), so it restates the minimal TruncInterface + Echo locally; the content is definitionally identical. Wiring: - tools/check-guardrails.sh: add to EXPLORATORY_EXEMPT (--cubical, not --without-K; zero postulates, no unsafe primitives). - docs/echo-types/echo-kernel-note.adoc: classify in the Exploratory row (kernel-guard Check B). - docs/proof-debt.md: record the discharge under (a); annotate (c). - .github/workflows/agda.yml: add the cubical typecheck lane (warm + cold jobs). Verified locally: agda --cubical --safe exit 0; check-guardrails + kernel-guard PASS. https://claude.ai/code/session_01GJatEm2TVFSTBEkKXmserJ
1 parent 7c54e0b commit 9edb6e3

5 files changed

Lines changed: 234 additions & 5 deletions

File tree

.github/workflows/agda.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ jobs:
146146
- name: Typecheck examples lane (Gate #3 canonical examples)
147147
run: agda -i proofs/agda proofs/agda/examples/All.agda
148148

149+
# Cubical lane: the (epi, mono) truncation discharge. A --cubical
150+
# --safe island (zero postulates) that CONSTRUCTS ∥_∥ as a HIT —
151+
# it cannot be imported by the --safe --without-K All.agda, so it
152+
# is typechecked directly here. Its --without-K-profile shadow is
153+
# EchoImageFactorizationPropPostulated (proof-debt (a)/(c)).
154+
- name: Typecheck cubical lane (epi/mono truncation discharge)
155+
run: agda -i proofs/agda proofs/agda/EchoImageFactorizationPropCubical.agda
156+
149157
cold-check:
150158
# Belt-and-braces: NO interface cache, --ignore-interfaces cold
151159
# build. A green here cannot be a stale-.agdai artefact (matters
@@ -189,3 +197,4 @@ jobs:
189197
agda --ignore-interfaces -i proofs/agda proofs/agda/Smoke.agda
190198
agda --ignore-interfaces -i proofs/agda proofs/agda/characteristic/All.agda
191199
agda --ignore-interfaces -i proofs/agda proofs/agda/examples/All.agda
200+
agda --ignore-interfaces -i proofs/agda proofs/agda/EchoImageFactorizationPropCubical.agda

docs/echo-types/echo-kernel-note.adoc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ kernel** — the boundary is real and lives outside this core.
153153
module. Listed so the DAG audit is complete.
154154

155155
| *Exploratory (not in `All.agda`)*
156-
| `EchoDecorationBridge`, `EchoImageFactorizationPropPostulated`
156+
| `EchoDecorationBridge`, `EchoImageFactorizationPropPostulated`,
157+
`EchoImageFactorizationPropCubical`
157158
| Deliberately omitted from `proofs/agda/All.agda` so the verified
158159
suite is unaffected. `EchoDecorationBridge` re-issues
159160
`EchoIntegration`'s integration claim through a `DecorationFit`
@@ -165,10 +166,18 @@ kernel** — the boundary is real and lives outside this core.
165166
`postulate` is forbidden under `--safe`) — demonstrates the
166167
parametric `TruncInterface` slot is plug-in-usable; the
167168
postulates assert the standard (-1)-truncation laws without
168-
proving them. Both modules listed here to satisfy the
169+
proving them. `EchoImageFactorizationPropCubical` is the REAL
170+
(`--cubical --safe`, zero-postulate) counterpart: it CONSTRUCTS
171+
`∥_∥` as a higher inductive type, realises the same four
172+
`TruncInterface` obligations as theorems (`is-prop-∥∥` from
173+
`squash`; `rec-∥∥` via the path recursor), and re-proves the
174+
(epi, mono) factorisation — discharging the truncation axiom the
175+
postulated module only assumes. It is a `--cubical` flag island
176+
because Agda forbids a `--cubical` module importing the `--safe
177+
--without-K` `Echo` cone, so it restates the minimal interface +
178+
`Echo` locally. All three modules listed here to satisfy the
169179
classification-drift lint (`scripts/kernel-guard.sh` Check B);
170-
neither is kernel, neither load-bearing, both subject to
171-
abandonment.
180+
none is kernel, none load-bearing, all subject to abandonment.
172181

173182
| *Foundation contract surface* +
174183
(dotted `Echo.*` namespace; curated public interface)

docs/proof-debt.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@ under one of (a) discharged / (b) budgeted / (c) necessary axiom / (d) debt.
77

88
## (a) Discharged in this repo
99

10-
- (none — entries are removed here when proofs land)
10+
- **Propositional truncation `∥_∥` + the (epi, mono) image
11+
factorisation** — discharged 2026-06-15 in the `--cubical --safe`
12+
lane by `proofs/agda/EchoImageFactorizationPropCubical.agda` (zero
13+
postulates). The module CONSTRUCTS `∥_∥` as a higher inductive type
14+
and realises the four `TruncInterface` obligations as theorems
15+
(`is-prop-∥∥` from the `squash` higher constructor transported to
16+
the inductive `_≡_`; `rec-∥∥` via the path recursor, its boundary
17+
closing by the cubical endpoint rule), then re-proves
18+
`prop-factor-right-injective` (mono) and
19+
`prop-factor-left-mere-surjective` (epi). This realises the axiom
20+
the `--without-K` demo under (c) only assumes — see (c).
1121

1222
## (b) Budgeted — tested with refutation budget
1323

@@ -33,6 +43,12 @@ under one of (a) discharged / (b) budgeted / (c) necessary axiom / (d) debt.
3343
- **Guardrail status**: explicitly allow-listed in
3444
`tools/check-guardrails.sh` and in the inline `hypatia: allow`
3545
pragma at the head of the module.
46+
- **Realised (2026-06-15)**: the same four obligations are
47+
CONSTRUCTED (zero postulates) in the `--cubical` lane by
48+
`EchoImageFactorizationPropCubical.agda` — see (a). The postulates
49+
here are therefore the `--safe --without-K`-profile shadow of a
50+
now-constructed object, not an irreducible axiom; they remain only
51+
because `∥_∥` cannot be built WITHIN `--safe --without-K` itself.
3652

3753
## (d) DEBT — actively to be closed
3854

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
{-# OPTIONS --cubical --safe #-}
2+
-- SPDX-License-Identifier: MPL-2.0
3+
-- SPDX-FileCopyrightText: 2025-2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
4+
5+
-- Cubical (REAL) counterpart of `EchoImageFactorizationPropPostulated`.
6+
--
7+
-- ## Purpose
8+
--
9+
-- `EchoImageFactorizationPropPostulated` exhibits the (epi, mono)
10+
-- image factorisation by ASSUMING propositional truncation `∥_∥` via
11+
-- four `postulate`s realising `TruncInterface`. Per the estate
12+
-- Trusted-Base Reduction Policy (`docs/proof-debt.md`) that module is
13+
-- item (c) "necessary axiom": `∥_∥` cannot be CONSTRUCTED in `--safe
14+
-- --without-K` without higher inductive types.
15+
--
16+
-- This module DISCHARGES that axiom. In the `--cubical` profile the
17+
-- propositional truncation is a genuine higher inductive type, so the
18+
-- four interface obligations become THEOREMS (zero postulates), and
19+
-- the (epi, mono) factorisation is a real proof rather than a
20+
-- consequence of assumed laws. `grep postulate` here returns nothing.
21+
--
22+
-- ## Why self-contained (not an import of the `--without-K` base)
23+
--
24+
-- Agda forbids a `--cubical` module from importing a module that is
25+
-- `--without-K` but not `--cubical-compatible`. The `Echo` kernel
26+
-- cone (and `EchoImageFactorizationProp`) is `--safe --without-K`, and
27+
-- re-flagging it to `--cubical-compatible` would change the
28+
-- kernel-guard funext-free certificate (`scripts/kernel-guard.sh`
29+
-- Check A greps for the literal `--safe --without-K`). So this module
30+
-- RESTATES the minimal pieces locally — `TruncInterface`, `Echo`,
31+
-- `echo-intro`, and the `ImageProp` content — each definitionally
32+
-- identical to its `--safe --without-K` original. Only the flag
33+
-- island differs; the mathematical content is the same.
34+
--
35+
-- ## What lands (all postulate-free, `--cubical --safe`)
36+
--
37+
-- * `∥_∥` — the propositional-truncation HIT.
38+
-- * `is-prop-∥∥`, `rec-∥∥` — the propositionality + recursor,
39+
-- proved (not assumed): `is-prop-∥∥` is `squash` transported to
40+
-- the inductive `_≡_`; `rec-∥∥`'s higher-constructor case closes
41+
-- by the cubical endpoint rule on the converted path.
42+
-- * `trunc-cubical : TruncInterface ℓ` — the four obligations,
43+
-- packaged as the SAME record shape the postulated module fakes.
44+
-- * `module ImagePropCubical f` — the (epi, mono) factorisation
45+
-- instantiated at `trunc-cubical`:
46+
-- - `prop-factor-right-injective-real` — MONO side (real).
47+
-- - `prop-factor-left-mere-surjective-real` — EPI side (real).
48+
--
49+
-- ## Headlines (cubical-lane; see `Cubical/All.agda`)
50+
--
51+
-- * `trunc-cubical`
52+
-- * `prop-factor-right-injective-real`
53+
-- * `prop-factor-left-mere-surjective-real`
54+
55+
module EchoImageFactorizationPropCubical where
56+
57+
open import Level using (Level; suc)
58+
open import Agda.Primitive.Cubical using (i0; primTransp)
59+
open import Agda.Builtin.Cubical.Path using (PathP)
60+
open import Data.Product.Base using (Σ; _,_; proj₁)
61+
open import Relation.Binary.PropositionalEquality
62+
using (_≡_; refl; cong)
63+
64+
private variable
65+
: Level
66+
67+
----------------------------------------------------------------------
68+
-- Cubical propositional truncation — the construction the postulates
69+
-- only asserted
70+
----------------------------------------------------------------------
71+
72+
-- homogeneous cubical path (kept distinct from the inductive `_≡_`)
73+
_≡ᶜ_ : {A : Set ℓ} A A Set
74+
_≡ᶜ_ {A = A} x y = PathP (λ _ A) x y
75+
76+
-- the (-1)-truncation as a higher inductive type
77+
data ∥_∥ (A : Set ℓ) : Setwhere
78+
inc : A ∥ A ∥
79+
squash : (x y : ∥ A ∥) x ≡ᶜ y
80+
81+
-- inductive-`≡` ↔ cubical-path, both with definitional endpoints
82+
eqToPath : {A : Set ℓ} {x y : A} x ≡ y x ≡ᶜ y
83+
eqToPath {x = x} refl = λ _ x
84+
85+
pathToEq : {A : Set ℓ} {x y : A} x ≡ᶜ y x ≡ y
86+
pathToEq {x = x} p = primTransp (λ i x ≡ p i) i0 refl
87+
88+
----------------------------------------------------------------------
89+
-- The four `TruncInterface` obligations, REAL (no postulates)
90+
----------------------------------------------------------------------
91+
92+
-- propositionality: `squash` is a path; transport it to inductive `_≡_`
93+
is-prop-∥∥ : {A : Set ℓ} (x y : ∥ A ∥) x ≡ y
94+
is-prop-∥∥ x y = pathToEq (squash x y)
95+
96+
-- recursion into an inductive-`≡` proposition. The higher-constructor
97+
-- case lands on a converted path; its `i0`/`i1` boundary reduces to
98+
-- `rec-∥∥ … x` / `rec-∥∥ … y` definitionally (cubical endpoint rule),
99+
-- so the clause is well-formed.
100+
rec-∥∥ : {A B : Set ℓ} ((x y : B) x ≡ y) (A B) ∥ A ∥ B
101+
rec-∥∥ pB f (inc a) = f a
102+
rec-∥∥ pB f (squash x y i) = eqToPath (pB (rec-∥∥ pB f x) (rec-∥∥ pB f y)) i
103+
104+
----------------------------------------------------------------------
105+
-- `TruncInterface` (local restatement, identical to
106+
-- `EchoImageFactorizationProp.TruncInterface`) + its REAL instance
107+
----------------------------------------------------------------------
108+
109+
record TruncInterface (ℓ : Level) : Set (suc ℓ) where
110+
field
111+
Trunc : Set Set
112+
∣_∣ : {A : Set ℓ} A Trunc A
113+
is-prop : {A : Set ℓ} (x y : Trunc A) x ≡ y
114+
rec : {A B : Set ℓ}
115+
((x y : B) x ≡ y)
116+
(A B)
117+
Trunc A B
118+
119+
-- the discharge: the postulated `trunc` becomes a real instance
120+
trunc-cubical : TruncInterface ℓ
121+
trunc-cubical = record
122+
{ Trunc = ∥_∥
123+
; ∣_∣ = inc
124+
; is-prop = is-prop-∥∥
125+
; rec = rec-∥∥
126+
}
127+
128+
----------------------------------------------------------------------
129+
-- Local `Echo` (definitionally identical to `Echo.Echo`) + intro
130+
----------------------------------------------------------------------
131+
132+
Echo : {A B : Set ℓ} (A B) B Set
133+
Echo {A = A} f y = Σ A (λ x f x ≡ y)
134+
135+
echo-intro : {A B : Set ℓ} (f : A B) (x : A) Echo f (f x)
136+
echo-intro f x = x , refl
137+
138+
----------------------------------------------------------------------
139+
-- The (epi, mono) factorisation, parametric in `TruncInterface`
140+
-- (restated from `EchoImageFactorizationProp.ImageProp`)
141+
----------------------------------------------------------------------
142+
143+
module ImageProp {A B : Set ℓ} (T : TruncInterface ℓ) (f : A B) where
144+
open TruncInterface T
145+
146+
Image-prop : Set
147+
Image-prop = Σ B (λ y Trunc (Echo f y))
148+
149+
prop-factor-left : A Image-prop
150+
prop-factor-left a = f a , ∣ echo-intro f a ∣
151+
152+
prop-factor-right : Image-prop B
153+
prop-factor-right = proj₁
154+
155+
prop-factor-commutes : a prop-factor-right (prop-factor-left a) ≡ f a
156+
prop-factor-commutes _ = refl
157+
158+
-- MONO side: the right leg is injective (second component is a prop).
159+
prop-factor-right-injective : {z₁ z₂ : Image-prop}
160+
prop-factor-right z₁ ≡ prop-factor-right z₂
161+
z₁ ≡ z₂
162+
prop-factor-right-injective {b , tr₁} {.b , tr₂} refl =
163+
cong (b ,_) (is-prop tr₁ tr₂)
164+
165+
-- EPI side: the left leg is mere-surjective onto the image.
166+
prop-factor-left-mere-surjective : (z : Image-prop)
167+
Trunc (Σ A λ a prop-factor-left a ≡ z)
168+
prop-factor-left-mere-surjective (b , tr) =
169+
rec is-prop
170+
(λ where (a , refl) ∣ a , cong (f a ,_) (is-prop ∣ echo-intro f a ∣ tr) ∣)
171+
tr
172+
173+
----------------------------------------------------------------------
174+
-- Consumer at the REAL interface + pinned headlines
175+
----------------------------------------------------------------------
176+
177+
module ImagePropCubical {A B : Set ℓ} (f : A B) where
178+
open ImageProp trunc-cubical f public
179+
180+
prop-factor-right-injective-real :
181+
{A B : Set ℓ} (f : A B)
182+
{z₁ z₂ : Σ B (λ y ∥ Echo f y ∥)}
183+
ImagePropCubical.prop-factor-right f z₁
184+
≡ ImagePropCubical.prop-factor-right f z₂
185+
z₁ ≡ z₂
186+
prop-factor-right-injective-real f =
187+
ImagePropCubical.prop-factor-right-injective f
188+
189+
prop-factor-left-mere-surjective-real :
190+
{A B : Set ℓ} (f : A B)
191+
(z : Σ B (λ y ∥ Echo f y ∥))
192+
∥ Σ A (λ a ImagePropCubical.prop-factor-left f a ≡ z) ∥
193+
prop-factor-left-mere-surjective-real f =
194+
ImagePropCubical.prop-factor-left-mere-surjective f

tools/check-guardrails.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ DENY_FLAG='--type-in-type|--cumulativity|--allow-unsolved-metas|--no-positivity-
4141
# outside the kernel cone and use postulates by design).
4242
EXPLORATORY_EXEMPT=(
4343
"EchoImageFactorizationPropPostulated"
44+
"EchoImageFactorizationPropCubical"
4445
"EchoDecorationBridge"
4546
"Fidelity"
4647
)

0 commit comments

Comments
 (0)