Skip to content

theory: EchoApprox composition rung — first slice (retract direction)#70

Merged
hyperpolymath merged 1 commit into
mainfrom
theory/echo-approx-composition-rung
May 20, 2026
Merged

theory: EchoApprox composition rung — first slice (retract direction)#70
hyperpolymath merged 1 commit into
mainfrom
theory/echo-approx-composition-rung

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Extends proofs/agda/EchoApprox.agda with the first slice of the
axis-2 composition rung from the design note (drafted in
/tmp/echo-types-exploration/axis2-approximate.md, §7 obligations
2 + 6, plus the canonical-split retract direction). Refs
docs/echo-types/roadmap.md Axis 2 entry and docs/echo-types/composition.md
§Q3 — does not close either.

Obligations landed

  • echo-strict→approx (§7 Claude/add ordinal notation layer 9qh sf #2). General strict ⇒ zero-tolerance
    approximate. Generalises echo-approx-intro from own-fibre points
    to arbitrary y via the codomain equation p : f x ≡ y. One
    extra subst along p.

  • echo-approx-comp-sound (§7 E5: make ν operational and add Buchholz example/smoke modules #6). Sound RHS-to-LHS direction
    of the retract shape from composition.md §Q3 / design-note §5.
    Unpacks the existential and calls echo-approx-compose.

  • echo-approx-comp-retract-to. Canonical-split LHS → RHS-Σ
    section of the retract: picks b := f x, ε₁ := zero, ε₂ := ε.
    Uses echo-approx-intro for the inner echo, original bound for
    the outer.

  • echo-approx-comp-retract-A. A-component round-trip
    proj₁ ∘ sound ∘ retract-to ≡ proj₁, proved by refl. The
    retraction direction holds definitionally on the A-component as
    the design note (§5) predicts.

Obligations deferred (out of this rung)

Docs updated

  • docs/echo-types/composition.md §Q3 promoted from "entirely
    speculative" to landed-retract-shape with deferred items called out.
  • docs/echo-types/roadmap.md adds a "landed" entry for the
    composition rung first slice.

Invariants preserved

  • --safe --without-K
  • No postulates
  • No escape pragmas
  • Funext untouched

Test plan

  • LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/All.agda exits 0
  • LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/Smoke.agda exits 0
  • No new postulate, no escape pragmas, funext not imported
  • Smoke.agda already pins module Approx following project
    convention (per-lemma pins inside parameterised modules require
    instantiation, which the project does not do for EchoApprox).

Extends `proofs/agda/EchoApprox.agda` with the first slice of the
axis-2 composition rung from the design note (§7 obligations 2 + 6,
plus the canonical-split retract direction).

Obligations landed:

* `echo-strict→approx` (§7 #2) — general strict ⇒ zero-tolerance
  approximate. Generalises `echo-approx-intro` from own-fibre points
  (`f x`) to arbitrary `y` reached via a strict echo `(x, p : f x ≡ y)`.
  One extra `subst` along `p` over the existing `dist-self` path.

* `echo-approx-comp-sound` (§7 #6) — sound RHS-to-LHS direction of
  the retract shape from `composition.md` §Q3 / axis-2 design note §5.
  Unpacks the existential and calls `echo-approx-compose`.

* `echo-approx-comp-retract-to` — canonical-split LHS → RHS-Σ section
  of the retract: picks `b := f x`, `ε₁ := zero`, `ε₂ := ε`. Uses
  `echo-approx-intro` for the inner echo and the original bound for
  the outer.

* `echo-approx-comp-retract-A` — A-component round-trip
  `proj₁ ∘ sound ∘ retract-to ≡ proj₁`, proved by `refl`. Witnesses
  the retraction direction holding definitionally on the A-component,
  as the design note (§5) predicts.

Obligations deferred (out of scope for this rung):

* §7 #7 zero-collapse under separation (`Separated → EchoR zero f y
  → Echo f y`) — needs a separation predicate on the pseudo-metric
  record that callers can opt into.
* §7 #8 axis-1 shadow agreement — cross-axis classification, separate
  rung.
* Full retract B-component and tolerance-budget round-trip — needs a
  `+`-left-identity axiom on `Tolerance` (`zero + ε ≡ ε`) which the
  current record does not supply. Adding it is a separate decision
  (it commits the carrier to a left-unital monoid, not just an
  ordered-+-monotone-monoid).
* Lipschitz generalisation (`L_g ≠ 1`) — needs scalar multiplication
  on `Tol`.

Docs updated:

* `docs/echo-types/composition.md` §Q3 — promoted from "entirely
  speculative" to landed-retract-shape with the deferred items called
  out.
* `docs/echo-types/roadmap.md` — new "landed" entry for the
  composition rung first slice.

Invariants preserved: `--safe --without-K`, no postulates, no escape
pragmas, funext untouched. `Smoke.agda` already pins `module Approx`
following the existing convention (per-lemma pins inside parameterised
modules require instantiation, which the project does not do for
EchoApprox).

Build: `LC_ALL=C.UTF-8 agda -i proofs/agda proofs/agda/All.agda` and
`... Smoke.agda` both exit 0.

Refs `docs/echo-types/roadmap.md` Axis 2 entry.
Refs `docs/echo-types/composition.md` §Q3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath marked this pull request as ready for review May 20, 2026 13:55
@hyperpolymath hyperpolymath merged commit 177c272 into main May 20, 2026
7 of 9 checks passed
@hyperpolymath hyperpolymath deleted the theory/echo-approx-composition-rung branch May 20, 2026 13:55
hyperpolymath added a commit that referenced this pull request May 20, 2026
…dule (#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>
hyperpolymath added a commit that referenced this pull request May 20, 2026
…tegration) (#73)

## Summary

Brings the `harden/ci-flake-pin-2026-05-18` stack onto main, with three
logical groupings:

* **Harden foundation (P0/P1)** — closure-hole closure, external fibre
triangulation against stdlib, reproducible CI-via-flake exact pin
(additive verifier). These are the earlier commits on the branch;
structural work, no Agda regressions.
* **Pillar E expansion (commit `8a24530`)** — clears two `[EXPAND]` tags
on `docs/echo-types/paper.adoc`:
- **Background and notation** primer: 6 subsections (type-theoretic
setting, Σ-types + identity, HoTT fibres, coeffect/graded-modality
lineage, thin-poset reindexing modalities, notation summary) plus an
18-row notation table whose every symbol is sourced from a real Agda
module. Explicit on the post-retraction framing.
- **Related work**: 8 per-neighbour subsections (HoTT fibres, graded
comonad/coeffect/QTT, lenses/optics, refinement types, setoid quotients,
provenance semirings, IFC/modal type theories, synthesis). All
`<<reframing-note>>` xrefs resolve.
- `types-abstract.adoc`: per-neighbour related-work positioning block
mirroring the paper. Abstract status remains "NOT submission-ready,
pending re-review" — content alignment only.
* **Licence sweep (commit `2e78761`)** — collapses the
`PMPL-1.0-or-later` SPDX identifier to `MPL-2.0` per owner direction
2026-05-20. 29 source/config files swept; README badge updated;
`stapeln.toml` + `arghda-core/Cargo.toml` license fields; new
`docs/PMPL-NARRATIVE.adoc` records the cultural/discipline overlay PMPL
represented (no legal effect change — MPL-2.0 was already the
lawyer-confirmed operative legal effect).

## Reconciliation needed before merge

`origin/main` has advanced by 7 PRs (#64#70) since this branch's last
merge from main:

* #64#66 bridge work (CNO Agda↔Coq↔Lean4 correspondence, EchoTropical
correspondence appendix, EchoJanusBridge OpKind mirror — substantive
`EchoJanusBridge.agda` +221 / `EchoApprox.agda` +132)
* #67 docs: rule out 2-categorical shape + roadmap credits
* #68 theory: Axis 8 graded access modality (new `EchoAccess.agda`, 262
lines)
* #69 theory: AntiEcho thin slice (new `AntiEcho.agda`, 93 lines)
* #70 theory: EchoApprox composition rung first slice

**Expected conflicts** (deliberate, owner-resolved):
* `paper.adoc` — this PR adds Background primer + Related work; parallel
sessions may have edited adjacent sections
* `types-abstract.adoc` — this PR adds a related-work block
* `flake.nix` — this PR is the full harden-P1 flake; parallel sessions
retained the simpler devShell flake
* `.github/workflows/*.yml`, `.machine_readable/6a2/*.a2ml`,
`contractiles/*.a2ml`, `stapeln.toml`, `README.md`,
`arghda-core/Cargo.toml`, `Containerfile`, `EXPLAINME.adoc`,
`QUICKSTART-*.adoc`, `TOPOLOGY.adoc`,
`docs/echidna-design-search-2026-04-28.adoc`,
`docs/echo-types/MAP.adoc`, `docs/echo-types/echo-kernel-note.adoc`,
`scripts/kernel-guard.sh`, `tools/check-guardrails.sh` — licence sweep;
conflicts with parallel sessions that kept PMPL headers (resolve by
taking this PR's MPL-2.0)

## Test plan

- [ ] CI green: governance + Agda + Hypatia scans + Scorecard
- [ ] `flake.nix` `nix flake check` passes (additive verifier)
- [ ] `agda proofs/agda/All.agda` and `agda proofs/agda/Smoke.agda` both
exit 0 under `--safe --without-K`, zero postulates (no Agda was touched
by this branch's recent commits, so this should be a verification-only
step)
- [ ] AsciiDoc render of `paper.adoc` — confirm all `<<reframing-note>>`
xrefs resolve
- [ ] `docs/PMPL-NARRATIVE.adoc` reads coherently
- [ ] No remaining `PMPL`/`Palimpsest` strings outside
`docs/PMPL-NARRATIVE.adoc` + the one intentional pointer in
`ECOSYSTEM.a2ml`

🤖 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 20, 2026
…dow (#74)

## Summary

Picks up two of three §7 deferrals from PR #70 in
`/tmp/echo-types-exploration/axis2-approximate.md`. Refs not Closes
because §7 is multi-rung and one rung (B-component +
tolerance-budget retract round-trip) stays deferred pending a
`Tolerance` interface design call (see below).

## Rungs landed

### Rung A — separated zero-collapse (§7 #7)

- `Separated : Set` — separation predicate on the pseudo-metric:
  `∀ b₁ b₂ → dist b₁ b₂ ≤ zero → b₁ ≡ b₂`. Kept out of the
  `PseudoMetric` record; supplied as an explicit hypothesis at the
  lemma site (pseudo-metrics in general only guarantee `dist y y ≡
  zero`, not the converse — making them a *metric proper* is an
  optional refinement the record deliberately does not bake in).
- `echo-approx-zero-collapses-strict : Separated → EchoR zero f y → Echo
f y`
  formalises the §4 "Approximate → strict (only when separated, at
  ε = 0)" statement.

### Rung B — axis-1 shadow agreement (§7 #8)

- `echo-shadow-A` — A-component projection (axis-1 shadow of an
  approximate echo).
- `echo-shadow-iso-{to,from}` — pins the §7 #8 obligation
  explicitly (definitional both ways: `EchoR ε f y` IS the
  existential `Σ A (λ x → dist (f x) y ≤ ε)`).
- `echo-strict→approx-shadow-A` — cross-axis cohere: the
  A-component of `echo-strict→approx` agrees with the strict
  A-component on the nose (`refl`).
- `echo-strict→approx-collapse-shadow-A` — round-trip under
  separation: `zero-collapses-strict ∘ strict→approx ≡ id` on the
  A-component, definitionally.

## DESIGN-DECISION STOP — Rung C deferred

The full B-component + tolerance-budget retract round-trip
(`echo-approx-comp-retract-from-to` and friends) requires a
`+`-left-identity axiom on `Tolerance` (`zero + ε ≡ ε`, plus
right-identity for the symmetric variants).

### Current shape of `Tolerance`

```agda
record Tolerance ℓ : Set (suc ℓ) where
  field
    Tol      : Set ℓ
    zero     : Tol
    _+_      : Tol → Tol → Tol
    _≤_      : Tol → Tol → Set ℓ
    ≤-refl   : ∀ {ε}             → ε ≤ ε
    ≤-trans  : ∀ {ε₁ ε₂ ε₃}      → ε₁ ≤ ε₂ → ε₂ ≤ ε₃ → ε₁ ≤ ε₃
    +-mono-≤ : ∀ {a b c d}       → a ≤ b → c ≤ d → (a + c) ≤ (b + d)
```

No identity laws on `+`. Minimal interface, lets us state
`echo-approx-compose`; that's all it currently does.

### What needs to be added

For the symmetric retract round-trip:

```agda
+-identityˡ : ∀ {ε} → (zero + ε) ≡ ε
+-identityʳ : ∀ {ε} → (ε + zero) ≡ ε
```

(`≡`, not `≤` — the round-trip is a definitional retract on the
tolerance budget, so we need a propositional equality, not just
mutual `≤`.)

### Two options

**(a)** Extend `Tolerance` with the two identity-law fields.

- Pro: minimal scaffolding; one type to thread through.
- Con: ripples to every `Tolerance` instance — currently just
  `EchoApproxInstance.trivialTolerance` (trivial discharge), but
  consumers may grow. Makes `Tolerance` strictly stronger than
  the "ordered commutative-monoid-flavoured" framing in §3 of the
  axis-2 design note.

**(b)** Add a separate `BalancedTolerance` record on top of
`Tolerance` carrying just the identity laws.

- Pro: additive; no interface breakage; layered/opt-in. Matches
  the design pattern of `PseudoMetric` (which is *separately*
  refined to a metric by adding `Separated`, not by widening the
  base record). Keeps the §3 "minimal moving parts" promise.
- Con: an extra record name to thread through retract-round-trip
  lemmas.

### Recommendation

**(b).** The current `Tolerance` is deliberately the minimal
interface that lets us state `echo-approx-compose` (triangle +
additive monotonicity, nothing else). Identity laws are needed
only by the retract round-trip, which is a downstream refinement
— keeping them out of the core interface preserves the "minimal
moving parts" design from §3 of the axis-2 design note. The
analogue is `PseudoMetric` vs. (`PseudoMetric` + `Separated`):
the refinement lives outside the base record.

Rung C is deferred pending owner decision.

## Rung D — also deferred

The Lipschitz generalisation `L_g ≠ 1` would need scalar
multiplication on `Tolerance` — a third interface call (whether
to add it to the core record, or layer a `ScalableTolerance`
refinement). Deferred alongside Rung C; same recommendation shape
applies.

## Hygiene

All new headlines pinned via the per-lemma proof-of-life pattern
from PR #71: `EchoApproxInstance.agda` adds top-level identifiers
at the trivial-pseudometric-on-`⊤` instance, `Smoke.agda`
enumerates them in its `using` clause.

## Verification

```
$ agda -i proofs/agda proofs/agda/All.agda     # exit 0
$ agda -i proofs/agda proofs/agda/Smoke.agda   # exit 0
```

`--safe --without-K` throughout. No postulates. No escape pragmas.
No funext.

## Refs

- PR #70 (retract direction)
- `/tmp/echo-types-exploration/axis2-approximate.md` §7

Refs not Closes — §7 obligations 7 and 8 are landed, but
obligation 6's "full retract round-trip" (Rung C) and the
Lipschitz generalisation remain.

## Test plan

- [x] `agda proofs/agda/All.agda` exits 0
- [x] `agda proofs/agda/Smoke.agda` exits 0
- [x] No postulates / escape pragmas / funext introduced
- [x] All new headlines pinned in `Smoke.agda` via `EchoApproxInstance`
- [ ] Owner decides Rung C `Tolerance` interface question (a vs. b)
- [ ] After decision: implement chosen option, land full retract
      round-trip

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 10 issues detected

Severity Count
🔴 Critical 0
🟠 High 5
🟡 Medium 5
View findings
[
  {
    "reason": "No test directory or test files found",
    "type": "no_tests",
    "file": "/home/runner/work/echo-types/echo-types",
    "action": "flag",
    "rule_module": "honest_completion",
    "severity": "high",
    "deduction": 20
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in secret-scanner.yml",
    "type": "missing_workflow",
    "file": "secret-scanner.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Action actions/cache@v4 needs attention",
    "type": "unpinned_action",
    "file": "agda.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "No dependabot.yml or renovate.json found in echo-types",
    "type": "DependencyUpdate",
    "file": "/home/runner/work/echo-types/echo-types",
    "action": "auto_fix",
    "rule_module": "scorecard",
    "severity": "high",
    "remediation": "Add .github/dependabot.yml or renovate.json configuration.",
    "scorecard_check": "Dependency-Update-Tool"
  },
  {
    "reason": "Nominal-only SAST in echo-types: codeql.yml language matrix contains no language present in the repo and lacks `actions`, so CodeQL records zero results on every commit. Remediation: set the CodeQL matrix to `language: actions`.",
    "type": "StaticAnalysis",
    "file": "/home/runner/work/echo-types/echo-types",
    "action": "auto_fix",
    "rule_module": "scorecard",
    "severity": "medium",
    "remediation": "Add CodeQL or equivalent SAST workflow.",
    "scorecard_check": "SAST"
  },
  {
    "reason": "1 workflow(s) with tag-pinned (not SHA-pinned) actions in echo-types",
    "type": "DependencyPinning",
    "file": "/home/runner/work/echo-types/echo-types",
    "action": "auto_fix",
    "rule_module": "scorecard",
    "severity": "medium",
    "remediation": "Pin GitHub Actions and Docker base images by SHA hash.",
    "scorecard_check": "Pinned-Dependencies"
  },
  {
    "reason": "Repository has 1 non-main remote branch(es). Policy: single main branch only.",
    "type": "GS007",
    "file": ".",
    "action": "delete_remote_branches",
    "rule_module": "git_state",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant