Skip to content

Commit 0a83258

Browse files
hygiene: per-lemma Smoke pins for EchoApprox via concrete instance module (#71)
## Summary Closes a silent violation of the CLAUDE.md "Working rules" invariant — *"Every headline theorem must be pinned in `Smoke.agda` via `using` clause"* — for parameterised modules. `EchoApprox.Approx` lemmas could not be named in `Smoke.agda` until *some* `PseudoMetric` was supplied, so the invariant has been quietly skipped for every `echo-approx-*` and `echo-strict→approx` lemma. PR #70 (Lane C of the multi-lane swarm) added the retract-direction lemmas (`echo-approx-comp-sound`, `echo-approx-comp-retract-to`, `echo-approx-comp-retract-A`) but, following existing convention, left them unpinned for the same reason. This PR closes the gap with the smallest, most honest possible instance. **Instance chosen:** the trivial / collapse-to-strict pseudometric on the unit carrier `⊤`. - `Tol := ⊤`, `zero := tt`, `_+_ := λ _ _ → tt` - `_≤_ := λ _ _ → ⊤` - `dist := λ _ _ → tt` on `B := ⊤` Every order / monotonicity / triangle obligation discharges to `tt`. Every approximate echo collapses to `Σ A (λ _ → ⊤)`, so each pinned lemma is a proof-of-life sanity check that the parameterised module's term is well-typed at *some* instance — exactly the hygiene contract the invariant asks for. No new mathematical content. When a genuine metric instance lands in the repo, the per-lemma pins below can be re-pointed at it (this is option 1 of two candidates considered; option 2, a discrete metric over `Bool`, adds nothing for the pinning purpose). ## Headlines now pinned in `Smoke.agda` (9 names) | New top-level name | Underlying `Approx` term | |---|---| | `approx-EchoR` | `EchoR` | | `approx-intro` | `echo-approx-intro` | | `approx-strict→approx` | `echo-strict→approx` | | `approx-relax` | `echo-approx-relax` | | `approx-NonExpansive` | `NonExpansive` | | `approx-compose` | `echo-approx-compose` | | `approx-comp-sound` | `echo-approx-comp-sound` | | `approx-comp-retract-to` | `echo-approx-comp-retract-to` | | `approx-comp-retract-A` | `echo-approx-comp-retract-A` | Plus the instance constructors `trivialTolerance`, `trivialPseudoMetric`. ## Build status Verified in the parent session (a sandbox quirk in this worktree denied positional-argument `agda` invocations despite project `.claude/settings.json` allowing them; the call worked from the parent): ``` $ LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/All.agda exit: 0 $ LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/Smoke.agda exit: 0 ``` `--safe --without-K` invariants intact (Agda would have errored otherwise). No postulates, no funext, no path algebra — every field is `tt` or `refl`. ## Files - New: `proofs/agda/EchoApproxInstance.agda` (instance + 9 per-lemma re-bindings) - Modified: `proofs/agda/All.agda` (one `open import` line, keeps orphan-module-as-dead-code rule satisfied) - Modified: `proofs/agda/Smoke.agda` (per-lemma `using` clause adjacent to the existing `Approx` block) ## Refs - Refs #70 — Lane C surfaced the gap by landing retract-direction lemmas in a parameterised module. - Refs CLAUDE.md "Working rules" invariant: *"Every headline theorem must be pinned in `Smoke.agda` via `using` clause."* - Does **not** Close any issue. ## Test plan - [x] `LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/All.agda` exits 0 under `--safe --without-K` (verified parent session) - [x] `LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/Smoke.agda` exits 0 under `--safe --without-K` (verified parent session) - [x] No new postulates introduced - [x] No `--safe` weakening or escape pragmas - [ ] CI green on this branch Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent eacce15 commit 0a83258

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

proofs/agda/All.agda

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ open import EchoIntegration
1919
open import EchoCNOBridge
2020

2121
open import EchoApprox
22+
open import EchoApproxInstance
2223
open import EchoIndexed
2324
open import EchoDecidable
2425
open import EchoAccess
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
{-# OPTIONS --safe --without-K #-}
2+
3+
-- A concrete `Tolerance` + `PseudoMetric` instance for `EchoApprox.Approx`,
4+
-- whose sole purpose is to give `Smoke.agda` a typeable identifier per
5+
-- headline lemma of the parameterised `EchoApprox.Approx` module.
6+
--
7+
-- Repo invariant (`CLAUDE.md`, "Working rules"):
8+
--
9+
-- "Every headline theorem must be pinned in `Smoke.agda` via
10+
-- `using` clause."
11+
--
12+
-- Lemmas living inside the parameterised submodule `EchoApprox.Approx`
13+
-- cannot be named in `Smoke.agda` until *some* `PseudoMetric` is
14+
-- supplied, so the invariant is silently violated for every
15+
-- `echo-approx-*` and `echo-strict→approx` lemma. This module closes
16+
-- that gap.
17+
--
18+
-- Design call: the trivial / collapse-to-strict pseudometric on `⊤`.
19+
--
20+
-- * `Tol` := `⊤`, `zero` := `tt`, `_+_` := `λ _ _ → tt`
21+
-- * `_≤_` := `λ _ _ → ⊤`
22+
-- * `dist` := `λ _ _ → tt` on the carrier `B := ⊤`
23+
--
24+
-- Every order / monotonicity / triangle obligation discharges to `tt`.
25+
-- Every approximate echo `EchoR ε f y = Σ A (λ x → dist (f x) y ≤ ε)`
26+
-- collapses to `Σ A (λ _ → ⊤)`, so each pinned lemma here is a trivial
27+
-- sanity check that the parameterised module's term is well-typed at
28+
-- *some* instance. That is exactly the hygiene contract the invariant
29+
-- asks for — proof-of-life, not new content.
30+
--
31+
-- We choose `A := ⊤` and `B := ⊤` so each pinned name resolves to a
32+
-- single top-level identifier with no remaining type parameters, which
33+
-- lets `Smoke.agda` enumerate them in a `using` clause one-for-one.
34+
--
35+
-- A non-trivial pseudometric (e.g. the discrete metric over `Bool`)
36+
-- would also work, but adds nothing the trivial one does not give for
37+
-- the purposes of `Smoke.agda` pinning. When a genuine metric instance
38+
-- lands in the repo, the per-lemma pins below can be re-pointed at it.
39+
40+
module EchoApproxInstance where
41+
42+
open import Level using (Level)
43+
open import Data.Unit.Base using (⊤; tt)
44+
open import Relation.Binary.PropositionalEquality using (refl)
45+
46+
open import EchoApprox using (Tolerance; PseudoMetric; module Approx)
47+
48+
----------------------------------------------------------------------
49+
-- The trivial tolerance carrier
50+
----------------------------------------------------------------------
51+
52+
-- All fields are tt / Unit; every law obligation is met by `tt`.
53+
trivialTolerance : Tolerance Level.zero
54+
trivialTolerance = record
55+
{ Tol =
56+
; zero = tt
57+
; _+_ = λ _ _ tt
58+
; _≤_ = λ _ _
59+
; ≤-refl = tt
60+
; ≤-trans = λ _ _ tt
61+
; +-mono-≤ = λ _ _ tt
62+
}
63+
64+
----------------------------------------------------------------------
65+
-- The trivial pseudometric on the carrier `⊤`
66+
----------------------------------------------------------------------
67+
68+
-- Distance is constantly `tt`; self-distance is `refl`; triangle is `tt`.
69+
trivialPseudoMetric : PseudoMetric ⊤ trivialTolerance
70+
trivialPseudoMetric = record
71+
{ dist = λ _ _ tt
72+
; dist-self = λ _ refl
73+
; dist-tri = λ _ _ _ tt
74+
}
75+
76+
----------------------------------------------------------------------
77+
-- Per-lemma proof-of-life pins for `Approx` at the trivial instance.
78+
--
79+
-- Top-level identifiers, one per `EchoApprox.Approx` headline, with
80+
-- `A := ⊤` and `B := ⊤` so each is a closed term that `Smoke.agda`
81+
-- can enumerate in a `using` clause. Definitions use `=` (no explicit
82+
-- type signature) so the original term's type is inferred — which is
83+
-- exactly the typeability check the hygiene invariant asks for.
84+
----------------------------------------------------------------------
85+
86+
private
87+
open module ApproxT⊤ =
88+
Approx {A = ⊤} {B = ⊤} {T = trivialTolerance} trivialPseudoMetric
89+
90+
approx-EchoR = EchoR
91+
approx-intro = echo-approx-intro
92+
approx-strict→approx = echo-strict→approx
93+
approx-relax = echo-approx-relax
94+
approx-NonExpansive = NonExpansive
95+
approx-compose = echo-approx-compose
96+
approx-comp-sound = echo-approx-comp-sound
97+
approx-comp-retract-to = echo-approx-comp-retract-to
98+
approx-comp-retract-A = echo-approx-comp-retract-A

proofs/agda/Smoke.agda

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,23 @@ open import EchoApprox using
7575
; module Approx
7676
)
7777

78+
-- Per-lemma pins for the parameterised EchoApprox via EchoApproxInstance
79+
-- (hygiene; closes the CLAUDE.md "Working rules" invariant gap for
80+
-- parameterised modules — see follow-up to PR #70).
81+
open import EchoApproxInstance using
82+
( trivialTolerance
83+
; trivialPseudoMetric
84+
; approx-EchoR
85+
; approx-intro
86+
; approx-strict→approx
87+
; approx-relax
88+
; approx-NonExpansive
89+
; approx-compose
90+
; approx-comp-sound
91+
; approx-comp-retract-to
92+
; approx-comp-retract-A
93+
)
94+
7895
open import EchoIndexed using
7996
( Echoᵢ
8097
; echoᵢ-intro

0 commit comments

Comments
 (0)