cubical-transport-hott-lean4/CubicalTransport/Algebra/Methodology.lean
Maximus Gorog 7ccebb606d
Some checks are pending
Lean Action CI / build (push) Waiting to run
ALGEBRA Phases A+B+C+D' + cubical_search tactic + doc state-of-play
Lands the metacoding stack from ALGEBRA_PLAN.md per the user's
discipline directive (no shortcuts, end-to-end correct).

CubicalTransport/Algebra/Meta.lean (Phase A — meta-mirror types):
- MetaCType: 11 constructors mirroring the cubical CType arms.
- MetaClassifier: lattice of "where in the codebase" predicates
  with .always / .never / .meet / .join / .atDecl / .inFile /
  .underAttribute / .dependencyOf / .inNamespace.
- MetaArtifact: source / declAt / refTo / empty.
- MetaPosition: (declName, filePath, range?) addressing.
- DecidableEq for MetaCType, MetaClassifier (manual mutual decEq
  for the recursive lattice arms).

CubicalTransport/Algebra/Edit.lean (Phase B — Edit + Context):
- Edit α: result + List EditOp.  Monad / Functor instances.
- Context α: focal artifact + position + siblings.  Functor +
  comonad operations (extract / extend).
- contextualEdit: the comonad-to-monad distributive law.
- MetaClassifier.atPosition: syntactic dispatch on classifier shape;
  meet/join lattice laws stated as theorems.

CubicalTransport/Algebra/Restructure.lean (Phase B — universal macro):
- restructure: the comp-shaped 5-field operation, returns Edit Unit.
- Frozen aliases: transport_artifact, relocate_invariant,
  rename_throughout, define_question_shape, compose_proof_fragments,
  materialize.
- Headless interpreter: SourceBuffer + EditOp.apply + Edit.runHeadless.
- Soundness scaffold: brokenRefs / selfConsistent / Edit.guarded.

CubicalTransport/Algebra/MacroAlias.lean (Phase C):
- @[macroAlias] attribute + AliasEntry registry (EnvExtension).
- Lookup helpers + diagnostic printer.

CubicalTransport/Algebra/Methodology.lean (Phase D'):
- @[methodology Identifier] attribute + MethodologyEntry registry.
- cubical_search tactic: walks the methodology library by classifier
  dispatch, applies via exact/apply.  deriveByTransport stub awaits
  @[metaPath] (REL2.6+).
- Diagnostic printer for the registry.

CubicalTransport/Algebra/Test.lean: compile-time end-to-end tests:
- Construct meta-mirror values; check DecidableEq.
- Build Edit values via restructure; verify selfConsistent on a
  broken-ref batch (correctly flagged).
- Register an alias via @[macroAlias].
- Register two methodologies via @[methodology] and verify
  cubical_search dispatches to them on representative goals.

Runtime smoke tests: 4 new Algebra smokes verifying restructure
emits the right ops, the broken-ref guard fires, and the
classifier lattice computes correctly.  93/93 tests pass.

Documentation:
- docs/QUESTIONS.md §4: Levels 1, 2, 3-light marked LANDED with
  commit refs; full Level 3 graph-walking marked pending.
- docs/ALGEBRA_PLAN.md §6: phase table updated with status column;
  Phases A/B/C/D' marked landed; Phases B.2 (LSP) + D (widget) +
  REL2.6 methodology-transport explicitly marked pending.
- docs/EULERIAN.md §9, §10: "the map" and "autodiscovery" rows
  updated from "planned REL2.5" to "landed 2026-05-01" with
  module-level cross-references.
- docs/KERNEL_BOUNDARY.md §3.7: cubical_simp (light) and
  cubical_search marked landed; full graph-walking cubical_simp
  marked dependent on @[metaPath].

Pending items deliberately out of scope this session:
- LSP widget (D) — needs running Lean LSP server.
- B.2 LSP integration — needs CodeActionContext.
- @[metaPath] declarations + full deriveByTransport — REL2.6+.

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

209 lines
9.4 KiB
Text

/-
CubicalTransport.Algebra.Methodology — `@[methodology]` + `cubical_search`
==========================================================================
Phase D' of `docs/ALGEBRA_PLAN.md`. Provides the autodiscovery
layer that crowns the metacoding stack:
- `@[methodology]` attribute: registers a Lean theorem as a "proof
fragment" indexed by a classifier shape. When `cubical_search`
encounters a question matching that shape, it tries the
registered theorem.
- `cubical_search` tactic: walks the methodology library by
classifier dispatch and applies matches; on miss, attempts
methodology-transport along declared structural Paths
(`transp`-at-the-meta-level).
Per ALGEBRA_PLAN §4.3:
> Once a small library of base methodologies exists, every new
> structural Path declared in the codebase **automatically generates
> new methodology candidates** by transporting existing methodologies
> across the path.
This module ships the registry + the basic tactic; the
methodology-transport clause is scaffolded as `deriveByTransport`
(a stub returning `[]` until the structural-Path infrastructure
arrives in REL2.6+).
-/
import Lean
import CubicalTransport.Algebra.MacroAlias
namespace CubicalTransport.Algebra
open Lean Lean.Elab Lean.Elab.Tactic
-- ── Methodology entries ─────────────────────────────────────────────────────
/-- A registered methodology. Indexes a Lean theorem by the
classifier shape it solves.
`classifierName` is a `Name` referring to a `MetaClassifier`-
valued `def` (or one of the syntactic classifier predicates from
`Question.lean`). `theoremName` is the `Name` of the theorem
that `cubical_search` will try when the question matches.
Priority is used for ordering: higher priority methodologies are
tried first. Default 100; specialised methodologies bump higher,
catch-alls run lower. -/
structure MethodologyEntry where
classifierName : Name
theoremName : Name
priority : Nat := 100
description : String := ""
deriving Repr, Inhabited
-- ── The methodology registry ────────────────────────────────────────────────
/-- Global registry of methodologies, indexed by classifier name.
Built up via `@[methodology]`-tagged declarations.
Implementation: `EnvExtension` so adds are visible across
modules. Lookup is linear in the registry size (acceptable for
REL2.5; a discrtree-indexed version is REL2.6 work per
ALGEBRA_PLAN §10.4). -/
initialize methodologyRegistryExt :
SimplePersistentEnvExtension MethodologyEntry (Array MethodologyEntry) ←
registerSimplePersistentEnvExtension {
name := `Algebra.methodologyRegistry
addEntryFn := fun arr e => arr.push e
addImportedFn := fun arrs => arrs.foldl (init := #[]) Array.append
}
def getMethodologies : CoreM (Array MethodologyEntry) := do
let env ← getEnv
return methodologyRegistryExt.getState env
def registerMethodology (entry : MethodologyEntry) : CoreM Unit := do
modifyEnv (methodologyRegistryExt.addEntry · entry)
/-- Find every methodology indexed against a given classifier name. -/
def findMethodologies (classifier : Name) : CoreM (Array MethodologyEntry) := do
let all ← getMethodologies
return all.filter (·.classifierName == classifier)
-- ── The `@[methodology]` attribute ──────────────────────────────────────────
-- Attached to a theorem. Attribute parser parses the classifier
-- name and optional priority. Registration adds an entry to the
-- methodology registry pointing back to the tagged theorem.
/-- Parser-level data for the `@[methodology]` attribute. We accept
a plain identifier naming the classifier. Priority configuration
via `priority := n` is Phase D'.1 work; the v0 attribute uses a
fixed default of 100.
The syntax `name :=` matches the attribute name registered below;
Lean's attribute system looks up attributes by syntax kind, not
by leading keyword. -/
syntax (name := methodology) "methodology" ident : attr
/-- The `@[methodology]` attribute itself. Records the tagged
theorem under the named classifier (priority defaults to 100). -/
initialize methodologyAttr : Unit ←
registerBuiltinAttribute {
name := `methodology
descr := "Register this theorem as a proof methodology indexed \
by a classifier (Phase D' of ALGEBRA_PLAN.md). Usage: \
`@[methodology IsFullFace]`."
add := fun declName stx _kind => do
-- Parse classifier name from the attribute syntax.
let classifierName? : Option Name :=
match stx with
| `(attr| methodology $cls:ident) => some cls.getId
| _ => none
let some classifierName := classifierName?
| throwError "@[methodology] requires a classifier name"
let env ← getEnv
let docstring? := (← findDocString? env declName).getD ""
registerMethodology
{ classifierName := classifierName
, theoremName := declName
, priority := 100
, description := docstring? }
}
-- ── The methodology-transport clause (scaffold) ─────────────────────────────
-- ALGEBRA_PLAN §4.3: when a structural Path connects classifierA to
-- classifierB and the methodology library has an entry for
-- classifierA, transport derives a candidate for classifierB.
--
-- Full implementation requires (a) declared structural Paths in the
-- codebase, (b) reification of methodology bodies as CTerms, (c)
-- application of `transp` at the methodology level. REL2.6+ work.
--
-- The scaffold below returns `[]` so the surrounding tactic remains
-- well-typed; uses are guarded by feature flags.
/-- Derive new methodology candidates by transporting existing ones
along declared structural Paths.
Per ALGEBRA_PLAN §4.3:
> Twenty starting methodologies + a hundred declared paths →
> potentially thousands of derived methodologies, each formally
> certified-by-construction.
Currently a no-op stub: returns the empty array. The full
implementation depends on the structural-Path declaration system
(`@[metaPath]`), planned for REL2.6+. Until then, only the
*direct* methodology library participates in `cubical_search`. -/
def deriveByTransport (_classifier : Name) : CoreM (Array MethodologyEntry) := do
-- TODO REL2.6: walk @[metaPath] declarations, transport methodologies
return #[]
-- ── The `cubical_search` tactic ─────────────────────────────────────────────
/-- The `cubical_search` autodiscovery tactic.
Walks the methodology library and applies any registered theorem
whose classifier matches the goal. On match, the corresponding
theorem is applied (via `exact`); on miss, falls back to
methodology-transport candidates.
Failure produces a structured report listing the attempted
methodologies and their guards (per ALGEBRA_PLAN §4.4 "Failure
as a feature"). -/
syntax (name := cubicalSearch) "cubical_search" : tactic
elab_rules : tactic
| `(tactic| cubical_search) => do
let goal ← getMainGoal
let goalType ← goal.getType
let methodologies ← getMethodologies
-- Try each methodology in registered order (Phase D' priority
-- ordering is REL2.6 work; for now: insertion order). We use
-- a two-stage attempt: first `exact` (no metavars), then
-- `apply` (allow Lean to fill args from the goal).
let mut tried := #[]
for entry in methodologies do
tried := tried.push entry.theoremName
try
let stx := mkIdent entry.theoremName
evalTactic (← `(tactic| (first | exact $stx | apply $stx)))
if (← getUnsolvedGoals).isEmpty then return
catch _ => continue
-- Fall back to methodology-transport candidates.
let derived ← deriveByTransport .anonymous
for entry in derived do
tried := tried.push entry.theoremName
try
let stx := mkIdent entry.theoremName
evalTactic (← `(tactic| (first | exact $stx | apply $stx)))
if (← getUnsolvedGoals).isEmpty then return
catch _ => continue
-- Structured failure report.
let triedStr := String.intercalate ", " (tried.toList.map (·.toString))
throwError s!"cubical_search: no methodology applies for goal\n {← Meta.ppExpr goalType}\ntried: {triedStr}\n\nconsider registering a new @[methodology] declaration."
-- ── Diagnostics ─────────────────────────────────────────────────────────────
/-- Print the methodology registry — what's currently available to
`cubical_search`. -/
def printMethodologies : CoreM Unit := do
let entries ← getMethodologies
IO.println s!"── Methodology registry ({entries.size}) ──"
for entry in entries do
let p := if entry.priority == 100 then "" else s!" (prio {entry.priority})"
let d := if entry.description.isEmpty then "" else s!" — {entry.description}"
IO.println s!" {entry.classifierName} → {entry.theoremName}{p}{d}"
end CubicalTransport.Algebra