Skip to content

Commit 3f2f32b

Browse files
characteristic/EI: discharge abstract loss-only obligation (sharpened proper-strict criterion) (#55)
## Summary Discharges the abstract loss-only obligation flagged open in `proofs/agda/characteristic/RecipeNonTriviality.agda` (`-- Mode-is-loss-only : ¬ NonLossOnly ModeAxis -- ^^^ open obligation`). The literal claim `¬ NonLossOnly ModeAxis` is **false**: the un-refined `NonLossOnly` counts *reflexive* identity steps as "strict", so it is vacuously satisfied by every axis with a multi-inhabitant decoration. Rather than paper over the gap, this PR: 1. **Proves the vacuity explicitly** — `NonLossOnly-holds-vacuously-for-Mode`. 2. **Sharpens the criterion** to the intended irreflexive reading (cf. `ChoreoInjective.agda`: "strict (non-reflexive) steps") — `ProperlyStrict` / `ProperNonLossOnly`. 3. **Retains the positive case** — `ChoreoAxis-proper-non-loss-only`. 4. **Discharges the obligation** — `Mode-is-not-proper-non-loss-only`. ## Verification - `--safe --without-K`, **zero postulates, zero escape pragmas**. - Full characteristic lane typechecks (`agda -i proofs/agda proofs/agda/characteristic/All.agda`, exit 0) on a clean true-`origin/main` base. ## Scope - **EI-2 unchanged**: remains `[CLOSED-NEG]` (terminated-negative). Not reopened. - Retraction **R-2026-05-18** honoured — no retracted vocabulary reinstated. - Commit author = 6759885+hyperpolymath@users.noreply.github.com. ## Note: branch replanted This branch was force-updated. The earlier push had drifted onto **#54**'s base (`docs/echo-types-master-map`) and bundled `README.md` + the whole `docs/echo-types/MAP.adoc` — not part of this change. It is now replanted onto true `origin/main` (`2ca3122`) and contains the **single Agda proof file only**. The MAP.adoc status tag for this work is posted as a review comment on #54 (which owns that file), per "link, don't duplicate". 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6dafb2d commit 3f2f32b

1 file changed

Lines changed: 280 additions & 34 deletions

File tree

proofs/agda/characteristic/RecipeNonTriviality.agda

Lines changed: 280 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ open import EchoLinear using
124124
; linear≤linear
125125
; linear≤affine
126126
; affine≤affine
127+
; LEcho
128+
; degradeMode
129+
; affine-all-equal
127130
)
128131
open import EchoGraded using
129132
( Grade
@@ -138,7 +141,12 @@ open import EchoGraded using
138141
; residue≤forget
139142
; forget≤forget
140143
)
141-
open import EchoCharacteristic using (collapse)
144+
open import EchoCharacteristic using
145+
( collapse
146+
; echo-true
147+
; echo-false
148+
; echo-true≢echo-false
149+
)
142150
open import characteristic.RoleGraded using
143151
( RoleGEcho
144152
; applyRole
@@ -158,6 +166,10 @@ open import characteristic.ModeGraded using
158166
( MGEcho to ModeGEcho
159167
; applyGrade to applyGradeM
160168
)
169+
open import characteristic.RoleModeGrade using
170+
( applyAll
171+
; trace-non-trivial-cell
172+
)
161173

162174
------------------------------------------------------------------------
163175
-- Definitions of "non-trivial" for the formal theorem
@@ -301,6 +313,45 @@ ModeGrade-no-non-identity-cell :
301313
NonIdentity modegrade-cell-action
302314
ModeGrade-no-non-identity-cell (x , px) = px refl
303315

316+
------------------------------------------------------------------------
317+
-- n=3 — RoleModeGrade (EI-2 obligation 4, formal enumeration form)
318+
--
319+
-- The 3D construction's pairwise/triple commutations are already
320+
-- discharged in characteristic.RoleModeGrade (all by `refl`). What
321+
-- was only stated there as a prose tracker entry — that the 3D
322+
-- construction has its non-trivial cell *because* it contains the
323+
-- non-loss-only axis Role — is here promoted to the SAME formal
324+
-- shape as the n=2 exhibits above. This is the mechanical extension
325+
-- of the concrete enumeration from n=2 to n=3 (obligation 4); it
326+
-- adds no new mathematical content over RoleModeGrade, only the
327+
-- formal `PreservesDistinct` certificate and an enumeration entry.
328+
--
329+
-- The unique live triple cell is (c⊑s, linear≤linear, keep≤keep);
330+
-- `applyAll` at that cell computes to `client-to-server` (proved in
331+
-- RoleModeGrade as `trace-non-trivial-cell`), so the n=3 cell action
332+
-- preserves distinctness via the same Choreo distinguishing pair.
333+
------------------------------------------------------------------------
334+
335+
rmg-cell-action : RoleEcho Client true RoleEcho Server true
336+
rmg-cell-action e = applyAll c⊑s linear≤linear keep≤keep e
337+
338+
rmg-cell-action-equals-c2s :
339+
(e : RoleEcho Client true)
340+
rmg-cell-action e ≡ client-to-server e
341+
rmg-cell-action-equals-c2s = trace-non-trivial-cell
342+
343+
RoleModeGrade-has-non-trivial-cell :
344+
PreservesDistinct rmg-cell-action
345+
RoleModeGrade-has-non-trivial-cell =
346+
rg-input₁ , rg-input₂ , rg-inputs-distinct , rmg-images-distinct
347+
where
348+
rmg-images-distinct :
349+
rmg-cell-action rg-input₁ ≢ rmg-cell-action rg-input₂
350+
rmg-images-distinct p =
351+
rg-images-distinct
352+
(trans (sym (rmg-cell-action-equals-c2s rg-input₁))
353+
(trans p (rmg-cell-action-equals-c2s rg-input₂)))
354+
304355
------------------------------------------------------------------------
305356
-- The recipe-non-triviality theorem (concrete form)
306357
--
@@ -329,6 +380,8 @@ data ConstructionWithStatus : Set where
329380
ConstructionWithStatus
330381
mg-trivial : (NonIdentity modegrade-cell-action ⊥)
331382
ConstructionWithStatus
383+
rmg-non-trivial : PreservesDistinct rmg-cell-action
384+
ConstructionWithStatus
332385

333386
-- The recipe-non-triviality theorem (concrete enumeration form):
334387
-- each of the three 2D constructions has the non-triviality status
@@ -342,6 +395,23 @@ recipe-non-triviality-concrete =
342395
, rm-non-trivial RoleMode-has-non-trivial-cell
343396
, mg-trivial ModeGrade-no-non-identity-cell
344397

398+
-- The recipe-non-triviality theorem extended to n=3: the three n=2
399+
-- constructions plus the 3D RoleModeGrade construction, each with
400+
-- the non-triviality status predicted by the hypothesis (non-trivial
401+
-- iff the tuple contains a non-loss-only axis; RoleModeGrade is
402+
-- non-trivial because it contains Role). This discharges EI-2
403+
-- obligation 4 in the same formal enumeration shape as the n=2 case.
404+
recipe-non-triviality-concrete-n3 :
405+
ConstructionWithStatus
406+
× ConstructionWithStatus
407+
× ConstructionWithStatus
408+
× ConstructionWithStatus
409+
recipe-non-triviality-concrete-n3 =
410+
rg-non-trivial RoleGraded-has-non-trivial-cell
411+
, rm-non-trivial RoleMode-has-non-trivial-cell
412+
, mg-trivial ModeGrade-no-non-identity-cell
413+
, rmg-non-trivial RoleModeGrade-has-non-trivial-cell
414+
345415
------------------------------------------------------------------------
346416
-- §<<abstract>> — Generic abstract axis machinery (partial)
347417
--
@@ -359,7 +429,14 @@ recipe-non-triviality-concrete =
359429
--
360430
-- Status of the generic form:
361431
-- * Axis record: defined.
362-
-- * NonLossOnly predicate: defined.
432+
-- * NonLossOnly predicate: defined (and shown vacuous — see
433+
-- `NonLossOnly-holds-vacuously-for-Mode`).
434+
-- * ProperNonLossOnly predicate (sharpened, irreflexive): defined.
435+
-- * Choreo certified under the sharpened predicate
436+
-- (`ChoreoAxis-proper-non-loss-only`).
437+
-- * Mode loss-only under the sharpened predicate: DISCHARGED
438+
-- (`Mode-is-not-proper-non-loss-only`). This is the abstract
439+
-- obligation previously flagged open.
363440
-- * Generic 2D family: requires decidable equality and a live
364441
-- decoration; partial scaffolding below.
365442
-- * Generic forward direction: not yet proved.
@@ -433,40 +510,209 @@ ChoreoAxis-non-loss-only =
433510
Client , Server , c⊑s , choreo-c⊑s-strict
434511

435512
------------------------------------------------------------------------
436-
-- Mode is loss-only at the abstract level.
437-
--
438-
-- The strict step linear≤affine has transport `weaken` =
439-
-- collapse-to-residue, which collapses Echo collapse tt (multiple
440-
-- inhabitants) to EchoR ⊤ TrivialCert tt (one inhabitant up to
441-
-- TrivialCert structure). All inputs map to the same output, so
442-
-- the step has no distinguishing pair.
443-
--
444-
-- Formalising "no distinguishing pair" requires showing that
445-
-- distinct inputs map to equal outputs, which is the
446-
-- collapse-residue-same property. EchoLinear has
447-
-- weaken-collapses-distinction : weaken echo-true ≡ weaken echo-false
448-
-- as the formal certificate. We can lift this to "Mode is not
449-
-- non-loss-only" — i.e., Mode does not satisfy NonLossOnly.
450-
--
451-
-- However: NonLossOnly only requires the EXISTENCE of *some* strict
452-
-- step with a distinguishing pair. Mode has only one strict step
453-
-- (linear≤affine), and we need to show it has no distinguishing
454-
-- pair. This requires examining all pairs of inputs in
455-
-- LEcho linear and showing they all map to equal outputs under
456-
-- weaken — which involves the universal property of LEcho linear.
457-
--
458-
-- This is straightforward but requires more machinery (LEcho's
459-
-- definition unfolds to Echo collapse tt; collapse-to-residue's
460-
-- behaviour on all such inputs; uniqueness of the residue).
461-
--
462-
-- Left as an open obligation in the abstract section. The concrete
463-
-- forward direction above (rolegraded-cell-action,
464-
-- rolemode-cell-action) does not depend on this abstract
465-
-- formalisation.
513+
-- Why `Mode-is-loss-only : ¬ NonLossOnly ModeAxis` cannot be proved
514+
-- as literally stated — and the sharpening that discharges it.
515+
--
516+
-- The flagged obligation was `¬ NonLossOnly ModeAxis`. That claim is
517+
-- FALSE under the `NonLossOnly` predicate above, and the file below
518+
-- proves it false rather than papering over the gap.
519+
--
520+
-- The defect is in `IsStrict`/`NonLossOnly`: a step counts as
521+
-- "strict" merely if it carries a distinguishing pair. But the
522+
-- *reflexive* steps `m ≤m m` transport by the identity
523+
-- (`degradeMode linear≤linear e = e` definitionally), and the
524+
-- identity trivially preserves distinguishability whenever the
525+
-- decoration has ≥2 separable inhabitants. So *every* axis with a
526+
-- multi-inhabitant decoration satisfies `NonLossOnly` via a
527+
-- reflexive step — the predicate is vacuously true and does not
528+
-- discriminate loss-only axes at all. `Mode` is no exception:
529+
-- `NonLossOnly-holds-vacuously-for-Mode` below exhibits the witness
530+
-- explicitly, which is exactly why `¬ NonLossOnly ModeAxis` is
531+
-- unprovable.
532+
--
533+
-- The rigorous fix is to SHARPEN the criterion to the intended
534+
-- reading (cf. ChoreoInjective.agda: "at least one of its strict
535+
-- (non-reflexive) steps"): a *proper* strict step must move between
536+
-- DISTINCT decorations. Under that sharpened predicate
537+
-- (`ProperNonLossOnly`):
538+
--
539+
-- * Choreo still certifies (c⊑s : Client ≢ Server, distinguishing
540+
-- transport) — the positive case is not lost.
541+
-- * Mode does NOT certify: its only inter-decoration step is
542+
-- linear≤affine, whose transport `weaken` lands in `LEcho affine`
543+
-- where `affine-all-equal` forces ALL outputs equal, so no
544+
-- distinguishing pair can exist. The reflexive steps are now
545+
-- excluded by the `distinct` requirement.
546+
--
547+
-- This discharges the abstract obligation in its defensible form:
548+
-- `Mode-is-not-proper-non-loss-only`. It does NOT affect the
549+
-- terminated-negative EI-2 verdict (see TERMINATION NOTICE / the
550+
-- EI-2 STATUS banners and docs/EI2_REPORT.adoc); it removes a
551+
-- residual proof-debt comment from the abstract section and
552+
-- sharpens the underlying criterion.
553+
------------------------------------------------------------------------
554+
555+
-- The original predicate is vacuously satisfied by Mode via the
556+
-- reflexive linear step. This is the concrete reason
557+
-- `¬ NonLossOnly ModeAxis` is FALSE (not merely "hard").
558+
ModeAxis : Axis
559+
ModeAxis = record
560+
{ D = Mode
561+
; _≤_ = _≤m_
562+
; F = LEcho
563+
; t = degradeMode
564+
}
565+
566+
mode-linear-reflexive-strict : IsStrict ModeAxis linear≤linear
567+
mode-linear-reflexive-strict = record
568+
{ x = echo-true
569+
; y = echo-false
570+
; x≢y = echo-true≢echo-false
571+
; tx≢ty = echo-true≢echo-false
572+
}
573+
574+
NonLossOnly-holds-vacuously-for-Mode : NonLossOnly ModeAxis
575+
NonLossOnly-holds-vacuously-for-Mode =
576+
linear , linear , linear≤linear , mode-linear-reflexive-strict
577+
578+
------------------------------------------------------------------------
579+
-- Sharpened criterion: a *proper* strict step moves between DISTINCT
580+
-- decorations. This excludes reflexive identity steps, which carry
581+
-- no information-preserving transport content of their own.
466582
------------------------------------------------------------------------
467583

468-
-- Mode-is-loss-only : ¬ NonLossOnly ModeAxis
469-
-- ^^^ open obligation; requires more LEcho machinery.
584+
record ProperlyStrict (a : Axis) {d1 d2 : Axis.D a}
585+
(le : Axis._≤_ a d1 d2) : Set where
586+
open Axis a
587+
field
588+
distinct : d1 ≢ d2
589+
x y : F d1
590+
x≢y : x ≢ y
591+
tx≢ty : t le x ≢ t le y
592+
593+
ProperNonLossOnly : Axis Set
594+
ProperNonLossOnly a =
595+
Σ (Axis.D a) (λ d1
596+
Σ (Axis.D a) (λ d2
597+
Σ (Axis._≤_ a d1 d2) (λ le
598+
ProperlyStrict a le)))
599+
600+
------------------------------------------------------------------------
601+
-- The sharpening keeps the positive case: Choreo still certifies,
602+
-- now via the genuinely proper step c⊑s (Client ≢ Server).
603+
------------------------------------------------------------------------
604+
605+
ChoreoAxis-proper-non-loss-only : ProperNonLossOnly ChoreoAxis
606+
ChoreoAxis-proper-non-loss-only =
607+
Client , Server , c⊑s , record
608+
{ distinct = λ ()
609+
; x = rg-input₁
610+
; y = rg-input₂
611+
; x≢y = rg-inputs-distinct
612+
; tx≢ty = rg-images-distinct
613+
}
614+
615+
------------------------------------------------------------------------
616+
-- The discharged obligation: Mode is loss-only under the sharpened
617+
-- (proper-step) criterion. Case analysis on the mode order:
618+
--
619+
-- * linear≤linear / affine≤affine — reflexive; `distinct` is
620+
-- `m ≡ m → ⊥`, refuted by `refl`.
621+
-- * linear≤affine — the unique inter-decoration step; its
622+
-- transport `degradeMode linear≤affine = weaken` lands in
623+
-- `LEcho affine`, where `affine-all-equal` makes every pair of
624+
-- outputs equal, contradicting `tx≢ty`.
625+
------------------------------------------------------------------------
626+
627+
Mode-is-not-proper-non-loss-only : ProperNonLossOnly ModeAxis
628+
Mode-is-not-proper-non-loss-only
629+
(linear , linear , linear≤linear , ps) = ProperlyStrict.distinct ps refl
630+
Mode-is-not-proper-non-loss-only
631+
(affine , affine , affine≤affine , ps) = ProperlyStrict.distinct ps refl
632+
Mode-is-not-proper-non-loss-only
633+
(linear , affine , linear≤affine , ps) =
634+
ProperlyStrict.tx≢ty ps
635+
(affine-all-equal
636+
(degradeMode linear≤affine (ProperlyStrict.x ps))
637+
(degradeMode linear≤affine (ProperlyStrict.y ps)))
638+
639+
------------------------------------------------------------------------
640+
-- Generic forward direction (EI-2 obligation 5, FORWARD half)
641+
--
642+
-- The §<<abstract>> header above speculated that the generic forward
643+
-- direction needs decidable equality on D plus a designated "live"
644+
-- decoration. That over-estimates the requirement: once the
645+
-- criterion is stated in its sharpened (proper-step) form, the
646+
-- forward direction follows directly from `ProperlyStrict`. A
647+
-- properly-non-loss-only axis exhibits a step whose transport is a
648+
-- distinctness-preserving (hence non-identity-acting) map. No
649+
-- decidable equality and no live decoration are needed; this is a
650+
-- sharpening of the file's own meta-claim about the requirement.
651+
--
652+
-- This discharges the FORWARD half of obligation 5 generically. The
653+
-- REVERSE half (no-NLO ⇒ every cell trivial) is unaffected and
654+
-- remains walled off by needing extensionality under --safe (see the
655+
-- §<<abstract>> note and PATH A/B below). The EI-2 verdict is
656+
-- UNCHANGED: this neither reopens nor terminates EI-2 (cf. the
657+
-- TERMINATION NOTICE and docs/EI2_REPORT.adoc); it discharges a
658+
-- residual obligation in its defensible form, exactly as the
659+
-- proper-strict sharpening did for the loss-only obligation.
660+
------------------------------------------------------------------------
661+
662+
-- Forward, bare form: a properly-non-loss-only axis has a step whose
663+
-- transport preserves distinctness (is non-trivial).
664+
ProperNonLossOnly⇒distinguishing-step :
665+
(a : Axis) ProperNonLossOnly a
666+
Σ (Axis.D a) (λ d1
667+
Σ (Axis.D a) (λ d2
668+
Σ (Axis._≤_ a d1 d2) (λ le
669+
PreservesDistinct (Axis.t a le))))
670+
ProperNonLossOnly⇒distinguishing-step a (d1 , d2 , le , ps) =
671+
d1 , d2 , le ,
672+
( ProperlyStrict.x ps
673+
, ProperlyStrict.y ps
674+
, ProperlyStrict.x≢y ps
675+
, ProperlyStrict.tx≢ty ps )
676+
677+
-- Forward, 2D-cell form: composing that distinguishing step with ANY
678+
-- second-axis step whose action on the codomain is the identity
679+
-- still yields a cell whose composed action preserves distinctness.
680+
-- The identity hypothesis is supplied POINTWISE (∀ z → gB z ≡ z) —
681+
-- which every concrete reflexive second-axis step satisfies by
682+
-- `refl` — so the proof never invokes function extensionality.
683+
generic-2cell-forward :
684+
(a : Axis) {d1 d2 : Axis.D a} (le : Axis._≤_ a d1 d2)
685+
(ps : ProperlyStrict a le)
686+
(gB : Axis.F a d2 Axis.F a d2)
687+
( z gB z ≡ z)
688+
PreservesDistinct (λ w gB (Axis.t a le w))
689+
generic-2cell-forward a le ps gB gB-id =
690+
ProperlyStrict.x ps
691+
, ProperlyStrict.y ps
692+
, ProperlyStrict.x≢y ps
693+
, λ eq ProperlyStrict.tx≢ty ps
694+
(trans (sym (gB-id (Axis.t a le (ProperlyStrict.x ps))))
695+
(trans eq
696+
(gB-id (Axis.t a le (ProperlyStrict.y ps)))))
697+
698+
-- The concrete cells are instances of the generic forward direction:
699+
-- ChoreoAxis is properly-non-loss-only via c⊑s, and the second-axis
700+
-- contribution in the concrete n=2/n=3 cells is pointwise-identity
701+
-- (`applyGrade keep≤keep` / `applyMode linear≤linear`, both `refl`).
702+
-- This is the link between the concrete enumeration above and the
703+
-- generic statement (non-vacuity witness; no duplication of content).
704+
choreo-instantiates-generic-forward :
705+
PreservesDistinct (λ w (λ z z) (Axis.t ChoreoAxis c⊑s w))
706+
choreo-instantiates-generic-forward =
707+
generic-2cell-forward ChoreoAxis c⊑s
708+
(record
709+
{ distinct = λ ()
710+
; x = rg-input₁
711+
; y = rg-input₂
712+
; x≢y = rg-inputs-distinct
713+
; tx≢ty = rg-images-distinct
714+
})
715+
(λ z z) (λ z refl)
470716

471717
------------------------------------------------------------------------
472718
-- Summary (prose; the formal content is above)

0 commit comments

Comments
 (0)