cubical-transport-hott-lean4/CubicalTransport/Algebra/MetaPath.lean
Maximus Gorog b88f6e6f62
Some checks are pending
Lean Action CI / build (push) Waiting to run
algebra-restructure CLI + asyncMode .sync on registries
Phase B/C/D' headless CLI per ALGEBRA_PLAN §5.3 ("No-LSP fallback")
plus a registry-state asyncMode tightening.

AlgebraRestructure.lean (NEW) + lakefile.toml exe target:
- `lake exe algebra-restructure {list-aliases | list-methodologies
  | list-paths | help}` — directs users to the source modules
  hosting each kind of declaration.
- DOCUMENTED LIMITATION: Lean 4's
  `SimplePersistentEnvExtension` state captured at build time
  (`.olean` persistence) does not reliably re-load when an
  Environment is reconstructed via `importModules` from a
  standalone executable.  The registries are populated at
  elaboration time (cubical_search dispatches against them
  successfully) and queryable from `#eval`-style invocations
  inside a Lean session, but not from a headless CLI.  The
  CLI ships as a clearly-marked stub directing users to the
  in-session diagnostic functions and the source-module locations.

CubicalTransport/Algebra/Methodology.lean,
CubicalTransport/Algebra/MacroAlias.lean,
CubicalTransport/Algebra/MetaPath.lean:
- All three SimplePersistentEnvExtension declarations now use
  `asyncMode := .sync` (was default `.mainOnly`).  Doesn't fix
  the standalone-CLI persistence issue but makes the in-session
  state visibility deterministic across import threads.

CubicalTransport/Algebra/Test.lean:
- printRegistrySizes converted from compile-time `#eval` (noisy)
  to a documented diagnostic CoreM action invokable via
  `#eval printRegistrySizes` from within a Lean session.

93/93 tests still pass.  All Phase A/B/C/D' deliverables for
ALGEBRA_PLAN are now landed; remaining items (widget, full LSP
integration, complete methodology library coverage) are tracked
in the doc updates and explicitly outside the headless agent's
scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 01:17:02 -06:00

127 lines
5.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
CubicalTransport.Algebra.MetaPath — `@[metaPath]` attribute
===========================================================
Phase D'.5 of `docs/ALGEBRA_PLAN.md`. Provides the structural-Path
declaration system that powers methodology-transport in
`cubical_search`.
A `MetaPath` is the meta-level analogue of a cubical `Path`: a
declared equivalence between two `MetaClassifier` shapes, witnessed
by a Lean theorem that exhibits the equivalence.
Example use:
@[metaPath IsFullFace IsConstLine]
theorem fullFace_implies_constLine_on_path (q : CompQ) :
IsFullFace q → IsConstLine q := …
Once such a Path is registered, every methodology indexed against
`IsFullFace` automatically becomes a candidate for `IsConstLine`
via `transp` at the methodology level.
Per ALGEBRA_PLAN §10.1 OQ: the witness theorem is required (a
declared MetaPath without a propositional witness would be
unsound). In v0 we trust the `metaPath` annotation; future REL3+
work can verify the witness type-checks against an expected shape.
-/
import Lean
import CubicalTransport.Algebra.Meta
namespace CubicalTransport.Algebra
open Lean
-- ── MetaPath entries ────────────────────────────────────────────────────────
/-- A registered structural Path between two classifiers.
`sourceClassifier` and `targetClassifier` are `Name`s pointing
to classifier predicates (typically defined in `Question.lean` —
`IsFullFace`, `IsConstLine`, `IsPathLine`, etc.).
`witnessName` names a theorem exhibiting the equivalence /
implication between them.
Direction matters: a Path `A ↦ B` means "every methodology for
A produces a methodology for B" (via post-composition with the
witness). The reverse direction needs a separate `metaPath B A`
declaration. -/
structure MetaPathEntry where
sourceClassifier : Name
targetClassifier : Name
witnessName : Name
description : String := ""
deriving Repr, Inhabited
-- ── The MetaPath registry ───────────────────────────────────────────────────
initialize metaPathRegistryExt :
SimplePersistentEnvExtension MetaPathEntry (Array MetaPathEntry) ←
registerSimplePersistentEnvExtension {
name := `Algebra.metaPathRegistry
addEntryFn := fun arr e => arr.push e
addImportedFn := fun arrs => arrs.foldl (init := #[]) Array.append
asyncMode := .sync
}
def getMetaPaths : CoreM (Array MetaPathEntry) := do
let env ← getEnv
return metaPathRegistryExt.getState env
def registerMetaPath (entry : MetaPathEntry) : CoreM Unit := do
modifyEnv (metaPathRegistryExt.addEntry · entry)
/-- Find every Path whose source matches a given classifier name. -/
def findPathsFromSource (source : Name) : CoreM (Array MetaPathEntry) := do
let all ← getMetaPaths
return all.filter (·.sourceClassifier == source)
/-- Find every Path whose target matches a given classifier name. -/
def findPathsToTarget (target : Name) : CoreM (Array MetaPathEntry) := do
let all ← getMetaPaths
return all.filter (·.targetClassifier == target)
-- ── The `@[metaPath]` attribute ─────────────────────────────────────────────
/-- Parser-level data for the `@[metaPath]` attribute: takes the
source classifier and the target classifier as identifiers.
The witness is the tagged declaration itself. -/
syntax (name := metaPath) "metaPath" ident ident : attr
/-- The `@[metaPath]` attribute itself. Records the tagged
declaration as a structural Path between two classifiers. -/
initialize metaPathAttr : Unit ←
registerBuiltinAttribute {
name := `metaPath
descr := "Register this declaration as a structural Path \
between two classifiers (Phase D'.5 of \
ALGEBRA_PLAN.md). Usage: `@[metaPath SourceClassifier \
TargetClassifier]`."
add := fun declName stx _kind => do
let parsed? : Option (Name × Name) :=
match stx with
| `(attr| metaPath $src:ident $tgt:ident) =>
some (src.getId, tgt.getId)
| _ => none
let some (src, tgt) := parsed?
| throwError "@[metaPath] requires source and target classifier names"
let env ← getEnv
let docstring? := (← findDocString? env declName).getD ""
registerMetaPath
{ sourceClassifier := src
, targetClassifier := tgt
, witnessName := declName
, description := docstring? }
}
-- ── Diagnostics ─────────────────────────────────────────────────────────────
def printMetaPaths : CoreM Unit := do
let entries ← getMetaPaths
IO.println s!"── MetaPath registry ({entries.size}) ──"
for entry in entries do
let d := if entry.description.isEmpty then "" else s!" — {entry.description}"
IO.println
s!" {entry.sourceClassifier} ↦ {entry.targetClassifier} via {entry.witnessName}{d}"
end CubicalTransport.Algebra