infoductor/Infoductor/Foundation/Restructure.lean
Maximus Gorog ba0a49823b Phase A: Foundation lib — meta-mirror, Edit/Context, restructure, registries
Initial commit.  Six modules extracted from
cubical-transport-hott-lean4/CubicalTransport/Algebra/ and
re-namespaced as `Infoductor`:

- Foundation/Meta.lean         — MetaCType, MetaClassifier,
                                 MetaArtifact, MetaPosition
                                 (with manual mutual decEq for
                                 MetaClassifier's recursive
                                 lattice arms)
- Foundation/Edit.lean         — Edit monad + Context comonad +
                                 distributive law +
                                 MetaClassifier.atPosition
                                 with lattice laws as theorems
- Foundation/Restructure.lean  — universal `restructure` (5-field
                                 comp-shaped operation), 6 frozen
                                 aliases, headless apply +
                                 brokenRefs / selfConsistent /
                                 Edit.guarded
- Foundation/MacroAlias.lean   — @[macroAlias] attribute +
                                 EnvExtension registry
- Foundation/MetaPath.lean     — @[metaPath src target]
                                 attribute + registry +
                                 findPathsFromSource/ToTarget
- Foundation/Methodology.lean  — @[methodology classifier]
                                 attribute + registry +
                                 deriveByTransport (walks
                                 metaPath registry) +
                                 tryEntryAsClosed primitive +
                                 cubical_search reference
                                 demonstrator

Builds clean on lean4 v4.30.0-rc2, ten oleans.  No deps beyond
Lean stdlib.  Sub-libs Tactics / Pantograph / Runner are planned
under the same lakefile.toml but not yet implemented.

Pairs with Pantograph as the conductor sits atop the pantograph
on an electric train.  "Info-ductor" — conducts information
(structure / classifications / methodology) through a Lean
codebase.

Forgejo: http://maxgit.wg:3000/max/infoductor

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

185 lines
8 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.

/-
Infoductor.Foundation.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 Infoductor.Foundation.Edit
namespace Infoductor
-- ── 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 Infoductor