/**
 * Trace — a UI-free, JSON-lossless snapshot of a run for OFFLINE REPLAY.
 *
 * `localObservability()` (Tier-3 / Debug) retains a live model during a run.
 * `serializeTrace()` freezes that model into a `Trace` — plain JSON you can
 * persist (file, Redis, a bug report) and later rehydrate WITHOUT re-running
 * the agent. `agentfootprint-lens`'s `<Replay trace={…} />` consumes it and
 * draws the flowchart via the existing translators.
 *
 * A `Trace` stores the domain-event log (the single source of truth the Lens
 * already reads) plus, since 7.8, the run's footprintjs snapshot. The step
 * graph is ALWAYS a derived projection of those events (footprint.js's "graph
 * is derived, never post-processed" principle) — it is rebuilt at render time,
 * never stored. Storing a derived graph would be redundant AND a redaction
 * hazard: a second content surface a per-event `redact` could never reach.
 *
 * WHAT A TRACE CAN AND CANNOT DRIVE
 * ─────────────────────────────────
 * `<Replay trace={…} />` draws the chart from `structure`, and that is all it
 * draws: a static shape, not a lit-up path. It does not read `trace.events` —
 * time-travel over them is a planned refinement, and until it lands an offline
 * `<Replay>` is a strictly smaller view than the live `<Lens>`, not a match
 * for it.
 *
 * For the full viewers — `<Lens>`, ExplainableShell, WhereFrom, the commit
 * axis — what you want is a RECORDING: `{ snapshot, events, structure }`, the
 * shape `recordRun()` produces and lens's `observeRecording()` consumes. Note
 * `events` there means the TYPED agentfootprint stream (`runner.on('*')`),
 * which is not the domain-event log a Trace carries: the two are different
 * projections of the same run, and a Trace holds only the second. So a Trace
 * with a `snapshot` can drive the snapshot-fed surfaces, but it is not itself
 * a recording — reach for `recordRun()` when the destination is a viewer.
 *
 * PII / trust boundary: the event log carries real content — `llm.end.content`,
 * `tool.start.args`, `tool.end.result`, `context.injected.contentSummary`,
 * `run`/`subflow` `payload`, `decision.branch.rationale`. A live, in-process
 * model is fine, but **serializing is a trust-boundary crossing** (the trace
 * can travel). So redaction is applied HERE, at serialize time, via a
 * consumer `redact` function — PII never enters the `Trace`. `redactContent`
 * is a ready-made redactor covering every content field. The result is
 * self-describing: `trace.redaction`. See
 * `docs/design/local-observability-and-pii.md`.
 *
 * Because `getEvents()` is FLAT (parent + every subflow), one `redact` pass
 * covers the whole tree — no per-subflow inheritance needed here. (The engine's
 * `RedactionPolicy` separately propagates to subflows for the OBSERVER mirror.)
 */
import type { DomainEvent } from './BoundaryRecorder.js';
import { type StepGraph } from './FlowchartRecorder.js';
/**
 * How a `Trace` was redacted before serialization.
 * - `'none'`   — raw content (no `redact`, no policy). A `<Replay>` UI may warn.
 * - `'pii'`    — a consumer `redact` ran (the default label when one is given).
 * - `'policy'` — the run was covered by a declarative footprintjs
 *   `RedactionPolicy` (an agent's `redact`), so every event this Trace holds —
 *   and its snapshot, when it carries one — was SERVED under it: the
 *   placeholder wherever the policy selected a value. It selects by name,
 *   never by content: free text under a name nobody selected is still there.
 */
export type TraceRedaction = 'none' | 'pii' | 'policy';
/** Cheap headline rollup, so a consumer can show totals without folding `events`. */
export interface TraceSummary {
    readonly tokens: {
        readonly input: number;
        readonly output: number;
    };
    readonly llmCalls: number;
    readonly toolCalls: number;
    readonly durationMs?: number;
}
/**
 * A JSON-lossless, UI-free snapshot of one run. Persist it, ship it, replay it.
 * `events` ARE the timeline (the graph is a derived projection, rebuilt at
 * render); `structure` is the chart; `snapshot` is the state the run left.
 */
export interface Trace {
    /** Schema version. Bump on a breaking shape change. */
    readonly version: 1;
    /** The domain-event log — the whole timeline. Already redacted if `redact` ran. */
    readonly events: readonly DomainEvent[];
    /**
     * The serialized STATIC chart structure (footprint.js `buildTimeStructure`).
     * Design-time data (stage ids/names/types/edges) — UI-free. `<Replay>` draws
     * the flowchart from this. NOT runtime-redacted (it carries no user data; the
     * `redact` function targets runtime events).
     *
     * Absent, `<Replay>` has nothing to draw and says so.
     */
    readonly structure?: unknown;
    /**
     * The run's footprintjs snapshot (`runner.getLastSnapshot()`) — shared
     * state, the commit log, and every attached recorder's data.
     *
     * This is the piece the snapshot-fed surfaces need and the event log cannot
     * supply: ExplainableShell's memory and provenance panels, WhereFrom, and
     * the commit axis all read the commit log, which is a footprintjs artifact
     * and appears nowhere in `events`. Without it a Trace draws a chart and a
     * timeline and nothing else — which is what every Trace captured before 7.8
     * is, and why they replay as a static picture.
     *
     * `unknown` on purpose: this is footprintjs's shape, not agentfootprint's,
     * and a Trace is a transport — it should not pin a peer's type into its own
     * schema. Cast at the consumer.
     *
     * NOT redacted by `redact`, which runs per domain event and cannot reach
     * inside a snapshot. This field is `runner.getLastSnapshot()`, which under
     * the run's own redaction policy (an agent's `redact`) is footprintjs's
     * redacted view — so a run whose state holds secrets wants that policy set
     * at run time. That is why `enable.localObservability({ includeSnapshot:
     * true })` is opt-in and a redacted Trace does not quietly grow a second
     * content surface.
     */
    readonly snapshot?: unknown;
    /** Optional headline totals. */
    readonly summary?: TraceSummary;
    /** Self-describing redaction state — travels with the trace. */
    readonly redaction: TraceRedaction;
    /** Wall-clock capture time, stamped by the caller (the engine has no clock here). */
    readonly capturedAtMs?: number;
}
export interface SerializeTraceOptions {
    /**
     * Consumer redaction — runs once per domain event at the serialize boundary,
     * so PII never enters the `Trace`. Return a scrubbed COPY (do not mutate the
     * input — the live model still references it). Use `redactContent` for a
     * ready-made redactor. When omitted, content is raw.
     */
    readonly redact?: (event: DomainEvent) => DomainEvent;
    /** Override the `redaction` label. Defaults to `'pii'` when `redact` is given, else `'none'`. */
    readonly redactionLabel?: TraceRedaction;
    /** The serialized static chart (`getSpec().buildTimeStructure`) — what `<Replay>` draws. */
    readonly structure?: unknown;
    /**
     * The run's footprintjs snapshot (`runner.getLastSnapshot()`) — the commit
     * log and recorder data the snapshot-fed panels read. `enable.localObservability()`
     * fills this for you; pass it explicitly when calling `serializeTrace` by hand.
     */
    readonly snapshot?: unknown;
    /** Optional precomputed headline rollup. */
    readonly summary?: TraceSummary;
    /** Wall-clock capture time. Pass `Date.now()` from the call site. */
    readonly capturedAtMs?: number;
}
/**
 * Ready-made redactor: replaces every content-bearing field with a marker,
 * keeping structure/counts for a useful replay. Covers ALL `DomainEvent`
 * content surfaces — pass it to `getTrace({ redact: redactContent })`.
 *
 * Returns a copy only when it changes something, so unaffected events stay
 * referentially identical (cheap) and the caller's live model is never mutated.
 */
export declare function redactContent(event: DomainEvent): DomainEvent;
/**
 * Freeze a live run model into a `Trace`. Pure: pass the `BoundaryRecorder`'s
 * `getEvents()` output.
 *
 *   const trace = serializeTrace(handle.boundary.getEvents(), {
 *     redact: redactContent,                      // PII stripped before it enters the trace
 *     structure: agent.getSpec().buildTimeStructure,  // the chart
 *     snapshot: agent.getLastSnapshot(),          // state + commit log + recorders
 *     capturedAtMs: Date.now(),
 *   });
 *   fs.writeFileSync('run.trace.json', JSON.stringify(trace));
 *
 * `enable.localObservability().getTrace()` passes all three for you.
 */
export declare function serializeTrace(events: readonly DomainEvent[], options?: SerializeTraceOptions): Trace;
/**
 * Rebuild the step graph from a `Trace` — the offline half of replay. The graph
 * is ALWAYS a derived projection of `trace.events`; because those events were
 * already redacted at serialize time, the rebuilt graph is clean too (no extra
 * redaction needed — that's exactly why the graph is never stored). UI-free:
 * `agentfootprint-lens`'s `<Replay>` translates this `StepGraph` into its
 * xyflow render model.
 */
export declare function traceToStepGraph(trace: Trace): StepGraph;
