Research-Stack/2-Search-Space/PIST/Trace.lean
Brandon Schneider 2a2aa0535f feat(pist): remove dead PISTMachine root; add Trace tactic module
lakefile.toml (PIST lib roots):
- Remove "PISTMachine" — PISTMachine.lean does not exist; dead root
  would cause lake build PIST to fail with "unknown module" error
- "Trace" was already added in the prior dirty change; committed here
  paired with the file it requires

2-Search-Space/PIST/Trace.lean (new):
- Lean 4 tactic `trace_state_json "tag"` for Tier 2 flexure recording
- Emits structured goal-state JSON (target, hypotheses, goal_count)
  prefixed with @@PIST_TRACE_JSON@@ sentinel to logInfo stdout
- Python trace bridge parses the sentinel to capture mid-proof state
- Namespace: PIST.Trace; no sorry, no float, no external deps beyond Lean

Generated with Devin (https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-26 21:32:41 -05:00

68 lines
1.8 KiB
Text

import Lean
open Lean Elab Tactic Meta
set_option pp.pretty true
/-!
# PIST Trace — goal-state snapshotter for Tier 2 flexure recording.
Provides a tactic `trace_state_json "tag"` that emits structured goal-state
snapshots to `logInfo` with a `@@PIST_TRACE_JSON@@` sentinel that the Python
trace bridge can parse from stdout.
Usage:
```lean
import PIST.Trace
theorem t (n : Nat) : n + 0 = n := by
trace_state_json "step_0_before"
simp
trace_state_json "step_0_after"
```
-/
namespace PIST.Trace
private def goalToJson (g : MVarId) : MetaM Json := do
let decl ← g.getDecl
let target ← instantiateMVars decl.type
let targetFmt ← ppExpr target
let mut hyps : Array Json := #[]
for localDecl in decl.lctx do
if !localDecl.isImplementationDetail then
let ty ← instantiateMVars localDecl.type
let tyFmt ← ppExpr ty
hyps := hyps.push <| Json.mkObj [
("name", Json.str localDecl.userName.toString),
("type", Json.str tyFmt.pretty)
]
return Json.mkObj [
("target", Json.str targetFmt.pretty),
("goal_index", Json.num (toNat g.index)),
("hypotheses", Json.arr hyps),
("hypothesis_count", Json.num hyps.size)
]
/-- Emit a structured goal-state snapshot tagged with `tag`.
The output is prefixed with `@@PIST_TRACE_JSON@@` so the Python bridge
can scrape it from Lean's stdout.
-/
elab "trace_state_json" tag:str : tactic => do
let goals ← getGoals
let goalJsons ← goals.mapM goalToJson
let payload : Json := Json.mkObj [
("event", Json.str "pist_trace_state"),
("tag", Json.str tag.getString),
("goal_count", Json.num goals.size),
("goals", Json.arr goalJsons)
]
-- Emit to logInfo so it appears in stdout
logInfo m!"@@PIST_TRACE_JSON@@{payload.compress}"
end PIST.Trace