/** * session-payload-decode — the shared, generic decoder for a stored session's * opaque `payload` blob (the inverse of each tool's `build*SessionPayload`). * * Session replay needs every tool (`fit`/`graph`/`sim`) * to read a persisted session back into a {@link SignalEnvelope} projection. The * persisted detail shares ONE structural shape — `{ summary, checks[] }`, each * check a `{ checkSlug, passed, violationCount?, durationMs, findings[] }` — so * the decode of THAT structure lives here once, parameterised by the few * per-tool differences (error-label, whether `filePath`/`violationCount` are * required, whether findings carry a metadata bag). * * This holds NO tool vocabulary: it does not know about fit checks, graph rules, * severity→category mapping, or signal IDs. Those projections stay in each * engine's `session-replay.ts` (`replaySignal`). What lives here is purely the * structural shape session-store persists — a faithful counterpart to the * package's opaque-payload charter: session-store owns persistence AND the * structural decode for replay, while tool semantics remain in the engines. * * The decoder tolerates legacy payloads that lack a top-level `__version` * (treated as v1 with best-effort projection). Tools should prefer their own * `*ReplayFromSession` functions (which call this decoder) for full projection * to their live result types; this module only gives the common structural * skeleton + the detected `payloadVersion` when present. */ import type { SignalEnvelope } from '@opensip-cli/contracts'; import type { SignalRepair } from '@opensip-cli/core'; /** JSON-safe scalar — the metadata-value subset the persisted shape permits. */ export type SessionPayloadScalar = string | number | boolean; /** A decoded finding row — the structural superset across all tools. */ export interface DecodedSessionFinding { readonly ruleId: string; readonly message: string; readonly severity: 'error' | 'warning'; readonly filePath?: string; readonly line?: number; readonly column?: number; readonly suggestion?: string; readonly metadata?: Readonly>; /** Structured repair guidance (ADR-0086), preserved across the round-trip. */ readonly repair?: SignalRepair; } /** A decoded per-check row. */ export interface DecodedSessionCheck { readonly checkSlug: string; readonly passed: boolean; readonly violationCount?: number; readonly durationMs: number; readonly findings: readonly DecodedSessionFinding[]; } /** The decoded session payload — `summary` + rule/check-grouped `checks[]`. */ export interface DecodedSessionPayload { readonly summary: SignalEnvelope['verdict']['summary']; readonly checks: readonly DecodedSessionCheck[]; /** * Detected inner `__version` from the opaque tool payload (or undefined for * legacy pre-__version rows, which callers treat as v1 with projection). * This is the value of the top-level numeric key if present and valid. */ readonly payloadVersion?: number; } /** Per-tool decode options — the only points where the tools' payloads differ. */ export interface DecodeSessionPayloadOptions { /** Tool label used in error messages (e.g. `'fit'`). */ readonly tool: string; /** When true, every finding must carry a string `filePath` (graph). */ readonly requireFilePath?: boolean; /** When true, every check must carry a numeric `violationCount` (graph/sim). */ readonly requireViolationCount?: boolean; /** When true, decode each finding's scalar `metadata` bag (graph). */ readonly allowMetadata?: boolean; } /** * Decode a stored session payload into its structural {@link DecodedSessionPayload}. * * @param payload - the opaque `StoredSession.payload` blob. * @param opts - per-tool decode options (label + required-field toggles). * @returns the decoded `{ summary, checks[] }` structure, plus `payloadVersion` * (the detected inner `__version` if present and valid; undefined for legacy * payloads that pre-date the convention — callers treat missing as v1). * @throws {TypeError} when `payload`/`checks`/`findings` are not the expected * object/array shapes. * @throws {Error} when a required scalar field is missing or mistyped, or a * finding severity is not `error`/`warning`. */ export declare function decodeSessionPayload(payload: unknown, opts: DecodeSessionPayloadOptions): DecodedSessionPayload; /** * Decode the `summary` verdict-counts block. * * @throws {Error} when the value is missing or any count is not a number. */ export declare function decodeSummary(value: unknown, label: string): SignalEnvelope['verdict']['summary']; /** @throws {Error} when the field is not a finite number (ADR-0180). */ export declare function numberField(source: Record, field: string, label: string): number; /** @throws {Error} when the field is not a string. */ export declare function stringField(source: Record, field: string, label: string): string; /** @throws {Error} when the field is not a boolean. */ export declare function booleanField(source: Record, field: string, label: string): boolean; //# sourceMappingURL=session-payload-decode.d.ts.map