/** * Normalized observable traces — the single comparison surface for differential parity. * * A trace is an ordered list of observable events plus a completion record. * Comparison is structural equality on traces, NOT on emitter strings or raw runtime values. * * Normalization rules (enforced by [[harness]] before comparison): * - RNG seeded; clocks frozen. * - Errors canonicalized to {kind, messagePattern} — never raw exception text. * - Event order is the source of truth for side-effect ordering. */ export type CompletionKind = 'normal' | 'return' | 'throw' | 'break' | 'continue'; export interface CompletionRecord { kind: CompletionKind; /** Present on `return`. Structurally cloned at write time. */ value?: unknown; /** Present on `throw`. Canonicalized error shape. */ error?: CanonicalError; /** Present on `break`/`continue` if a label was specified. */ label?: string; } /** * Canonical error shape. Cross-target equality compares `kind` exactly and * `messagePattern` as a regex match against the runtime error message — * NOT raw text, which diverges between V8 and CPython. * * `message` carries an EVALUATED LITERAL message and is ONLY set for an * EXPLICIT `throw new Error("…")` body-statement (where the message text is * authored as a string literal and is therefore byte-identical across V8 and * CPython — `Error("x").message` === `str(Exception("x"))`). It exists so a * caught-binding `.message` read can return the exact literal. The * messagePattern-based canonicalization (used by the fixture differential * harness for IMPLICIT/primitive throws, whose raw text diverges) is left * untouched: `message` and `messagePattern` are independent, and an error may * carry either, both, or neither. */ export interface CanonicalError { kind: string; messagePattern?: RegExp; /** Evaluated literal message of an explicit `throw new Error("…")`. */ message?: string; } export type TraceEvent = { op: 'stdout'; text: string; } | { op: 'stderr'; text: string; } | { op: 'assign'; target: string; value: unknown; } | { op: 'call'; fn: string; args: unknown[]; } | { op: 'iter-next'; binding: string; value: unknown; } | { op: 'iter-done'; } | { op: 'enter'; nodeType: string; } | { op: 'exit'; nodeType: string; }; export interface Trace { events: TraceEvent[]; completion: CompletionRecord; } /** Empty starter trace — used by reference runner before any event is recorded. */ export declare function emptyTrace(): Trace; /** * Structural trace equality. Two traces are equal iff their event lists match * element-wise and their completion records agree on kind + value/error. * `RegExp` patterns compare by source+flags, not identity. */ export declare function tracesEqual(a: Trace, b: Trace): boolean; /** * Recursive structural equality for trace payloads. Handles the cross-target * surface honestly: * * - `Object.is` for primitive identity so `NaN === NaN` and `+0 !== -0`. * - `undefined` is a real value, not silently dropped (vs `JSON.stringify`). * - `RegExp` compares by source + flags. * - `Map` and `Set` get true structural comparison (not `{}`). * - Arrays and plain objects recurse. * - Circular references throw — traces should never contain cycles. * * Exported so contracts that need bespoke comparison can reuse it. */ export declare function deepEqual(a: unknown, b: unknown, seen?: WeakSet): boolean; export declare function eventsEqual(a: TraceEvent, b: TraceEvent): boolean; export declare function completionsEqual(a: CompletionRecord, b: CompletionRecord): boolean;