PtcRunner.TraceLog.Introspection (PtcRunner v0.13.0)

Copy Markdown View Source

Host-bound, read-only introspection over recorded turn-log sessions, packaged as the log/ capability prelude (plan P3, D4).

This is the proving consumer for "preludes are the sole opt-in mechanism": the Elixir surface stays deliberately boring — plain data access over the turn log (list sessions, fetch a session's turns/programs/tool-calls). Higher-level analysis (dedup detection, cost aggregation, where-did-it-waste-turns) lives in the PTC-Lisp programs that call these exports, not here.

Wiring

source = sink_pid_or_jsonl_path_or_event_list
PtcRunner.Lisp.run(program,
  prelude: PtcRunner.TraceLog.Introspection.prelude_source(),
  tools: PtcRunner.TraceLog.Introspection.tools(source))

The log/ prelude's exports invoke typed tools (tool/log_sessions, …), so the compiler infers tool:log_sessions-style requires. Attach fails closed unless the host grants those tools (the tools/0 map). Read-only by design (the two-grant rule, D4): there is no live-session control here.

Memory model (P2 of docs/plans/sandbox-heap-rebaseline.md)

The granted closures are thin proxies: projections are computed host-side — inside the MemorySink for pid sources, inside a PtcRunner.TraceLog.Introspection.Holder started by tools/2 for path and list sources — so only each call's RESULT enters the sandbox and a program's heap cost tracks result size, never log size. Call tools/2 once per grant (each path/list call starts a holder owned by the calling process; it stops when that process goes down). A stopped sink/holder surfaces as a clear, recoverable tool error, not a hang.

Trust

Recorded sessions are untrusted data — they may contain adversarial or junk programs. These tools return them as evidence to be analyzed, never as instructions to follow.

Summary

Types

A turn-log source: an in-memory sink pid, a JSONL trace path, or an already loaded list of event maps.

Functions

The log/ introspection prelude source. Attach it with the tools/1 grant.

Builds the granted, host-bound tool closures over source.

Types

source()

@type source() :: pid() | String.t() | [map()]

A turn-log source: an in-memory sink pid, a JSONL trace path, or an already loaded list of event maps.

Functions

prelude_source()

@spec prelude_source() :: String.t()

The log/ introspection prelude source. Attach it with the tools/1 grant.

tools(source, opts \\ [])

@spec tools(
  source(),
  keyword()
) :: %{optional(String.t()) => (map() -> term())}

Builds the granted, host-bound tool closures over source.

Grant these as tools:; the keys ("log_sessions", "log_turns", "log_programs", "log_tool_calls") match the tool:<name> requirements the log/ prelude infers. All closures are read-only and return string-keyed data.

Path and list sources start a Holder owned by the calling process (see the memory-model section above). Options: :max_bytes — the holder's serialized-size load cap; raises ArgumentError for oversized logs.