cubical-transport-hott-lean4/CubicalTransport/Algebra/Restructure.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

185 lines
8.1 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.Restructure — the universal macro
==========================================================
Phase B of `docs/ALGEBRA_PLAN.md`. Defines the `restructure`
operation — a function with the same five-field shape as
`comp i A φ u t`, lifted to the meta-source-code level.
Per ALGEBRA_PLAN §0:
> One macro. Built from `comp`. Aliases accrue by usage; tactics
> are search over a library that grows under structural-Path
> declarations alone.
All 32 enumerated macros from the original sketch are *frozen
partial applications* of this single `restructure`; the alias
layer in `Algebra/MacroAlias.lean` lets users (or the system)
name recurring patterns.
-/
import CubicalTransport.Algebra.Edit
namespace CubicalTransport.Algebra
-- ── The universal `restructure` operation ───────────────────────────────────
/-- `restructure i ctx φ witness fallback` — the universal source-
mutation operation. Five fields, each mirroring a field of
`comp i A φ u t`:
· `i : MetaPosition` — where in source.
· `ctx : MetaCType` — meta-type of the artifact.
· `φ : MetaClassifier` — when this restructuring applies.
· `witness : MetaArtifact` — new content valid on φ.
· `fallback : MetaArtifact` — existing content off-φ.
The result is an `Edit Unit`: a single `EditOp` whose content is
`witness` (when `φ` matches at `i`) or `fallback` (otherwise).
The `ctx` argument is currently used only for documentation /
diagnostics — Phase C's `@[macroAlias]` attribute consumes it
when binding aliases. Future Phase D' may use it to dispatch
different rendering / preview modes in the widget. -/
def restructure (i : MetaPosition) (_ctx : MetaCType)
(φ : MetaClassifier) (witness fallback : MetaArtifact) : Edit Unit :=
let active := φ.atPosition i
let chosen := if active then witness else fallback
let label := if active then "hit" else "miss"
Edit.emit
{ position := i
, newContent := chosen
, oldContent := none
, description := s!"restructure φ={label} at {repr i}" }
-- ── The 32 macros as frozen aliases ─────────────────────────────────────────
-- Per ALGEBRA_PLAN §2.3 every "macro" in the original 32-item list
-- is a frozen partial application. These are the foundational
-- aliases; a downstream user / agent can register more via
-- `@[macroAlias]` (Phase C).
/-- Frozen alias: `transport_artifact i ctx w` — `restructure` with
`φ = .always`, `witness = fallback = w`. Always applies; just
relocates `w` to `i`. -/
@[reducible]
def transport_artifact (i : MetaPosition) (ctx : MetaCType) (w : MetaArtifact) :
Edit Unit :=
restructure i ctx .always w w
/-- Frozen alias: `relocate_invariant i src dst` — moves a file's
content from `src` to `dst`, classifier set to "in source file." -/
@[reducible]
def relocate_invariant (decl : Lean.Name) (src dst : String) : Edit Unit :=
restructure { declName := decl, filePath := dst, range := none }
.file (.inFile src) (.refTo decl) .empty
/-- Frozen alias: `rename_throughout x y` — emit a rename edit for
declaration `x` (witness on `.atDecl x`, fallback `.empty`). -/
@[reducible]
def rename_throughout (oldName newName : Lean.Name) : Edit Unit :=
restructure { declName := oldName, filePath := "", range := none }
.definition (.atDecl oldName) (.refTo newName) .empty
/-- Frozen alias: `define_question_shape S` — register a new question
schema as an inductive declaration. -/
@[reducible]
def define_question_shape (declName : Lean.Name) (witness : MetaArtifact) :
Edit Unit :=
restructure { declName := declName, filePath := "", range := none }
.inductive_ .always witness .empty
/-- Frozen alias: `compose_proof_fragments` — pure `restructure` with
no freezing. This is the "raw" `restructure` exposed under a
documentary name; identical in behaviour. -/
@[reducible]
def compose_proof_fragments
(i : MetaPosition) (ctx : MetaCType) (φ : MetaClassifier)
(w f : MetaArtifact) : Edit Unit :=
restructure i ctx φ w f
/-- Frozen alias: `materialize` — emit a piece of raw Lean source at
a position. The leaf operation; everything else composes from
here. -/
@[reducible]
def materialize (i : MetaPosition) (ctx : MetaCType) (src : String) :
Edit Unit :=
restructure i ctx .always (.source src) .empty
-- ── Headless interpreter: apply edits to an in-memory buffer ────────────────
-- Phase 5.3 No-LSP fallback: same operations as `lake exe
-- algebra-restructure` subcommands. Useful for batch CI runs.
/-- A simple in-memory source buffer. Maps file paths to current
contents. `applyOp` mutates the buffer in place. -/
abbrev SourceBuffer := Std.HashMap String String
/-- Apply a single `EditOp` to a source buffer. For now this is a
crude full-file overwrite when `position.range` is `none`; range-
based partial overwrites are scheduled for the LSP-backed
integration in `Algebra/EditLSP.lean`.
Returns the updated buffer. Diagnostic lines printed to
`IO.stderr` describe what changed. -/
def EditOp.apply (op : EditOp) (buf : SourceBuffer) : IO SourceBuffer := do
let path := op.position.filePath
match op.newContent with
| .source s =>
IO.eprintln s!"[restructure] writing {path} (decl {op.position.declName})"
return buf.insert path s
| .empty =>
IO.eprintln s!"[restructure] removing {path} (decl {op.position.declName})"
return buf.erase path
| .refTo n =>
IO.eprintln s!"[restructure] {path}: rename / link → {n}"
return buf
| .declAt _ =>
IO.eprintln s!"[restructure] {path}: emit syntax (LSP-bound; headless skipped)"
return buf
/-- Run an `Edit` headless: apply every emitted op in order to an
initial source buffer. Returns the final buffer plus the
computation's value. -/
def Edit.runHeadless {α : Type} (e : Edit α) (initial : SourceBuffer) :
IO (α × SourceBuffer) := do
let mut buf := initial
for op in e.ops do
buf ← op.apply buf
return (e.result, buf)
-- ── Soundness guard scaffold ────────────────────────────────────────────────
-- ALGEBRA_PLAN §3.3: every Edit passes through `preserve_typing`.
-- The full integration requires invoking `lean` on a fresh source
-- buffer; the data-level guard here checks that no edit deletes
-- a declaration that other edits in the same batch reference.
/-- The names referenced by an `EditOp` (as a `MetaArtifact.refTo`). -/
def EditOp.referenced : EditOp → List Lean.Name
| { newContent := .refTo n, .. } => [n]
| _ => []
/-- The decl-name *removed* by an `EditOp` (when content is `.empty`). -/
def EditOp.removed : EditOp → List Lean.Name
| { newContent := .empty, position := p, .. } => [p.declName]
| _ => []
/-- A "broken reference" predicate: does this batch reference any
name that the same batch removes? The structural check that
runs in any environment, headless or not. -/
def Edit.brokenRefs {α : Type} (e : Edit α) : List Lean.Name :=
let removed := e.ops.flatMap EditOp.removed
let referenced := e.ops.flatMap EditOp.referenced
referenced.filter (· ∈ removed)
/-- The structural soundness check: an `Edit` is *self-consistent*
if no op references a name another op in the batch removes.
Full type-checking of the post-edit buffer is the LSP-integrated
layer's job (`Algebra/EditLSP.lean`). -/
def Edit.selfConsistent {α : Type} (e : Edit α) : Bool :=
e.brokenRefs.isEmpty
/-- Guarded wrapper: aborts the edit if its self-consistency check
fails. Mirrors the `Edit.guarded` shape in ALGEBRA_PLAN §3.3. -/
def Edit.guarded {α : Type} [Inhabited α] (e : Edit α) :
Except String (Edit α) :=
if e.selfConsistent then .ok e
else .error s!"restructure batch breaks references: {repr e.brokenRefs}"
end CubicalTransport.Algebra