/** * Does a Codex rollout still look the way this streamer reads it? * * Everything built on Codex history — the conversation list, detail, search, * resume identity, and a fork's inherited prefix — parses an on-disk format * that Codex owns, does not version, and changes without telling anyone. It has * already changed once here: `forked_from_ordinal_exclusive` appears in exactly * one of the 38 fork rollouts on the machine this was written on, and its * absence is why every earlier fork opened as an empty conversation for months. * * That is the failure mode worth paying for. A format change does not throw — * it renders a conversation short, or empty, or a fork with turns it never * inherited, and every one of those looks like a bug in this app rather than a * moved contract. * * So this asserts the handful of things the readers actually depend on, and * NOTHING ELSE. A canary that fires on a benign addition gets muted, and a * muted canary is worse than none — Codex is free to add line types, payload * fields and roles, and every one of those must pass silently. */ /** What broke, in terms of the assumption it breaks. */ export type CodexFormatFindingCode = /** First line is not a `session_meta` — every reader starts there. */ "first_line_not_session_meta" /** `session_meta` carries no id, so the file names no conversation. */ | "session_meta_missing_id" /** * Ordinals are not one-per-line ascending. `readMessagesBeforeOrdinal` treats * a line ordinal as a position, and falls back to the line counter when the * field is absent — both are wrong the moment ordinals skip or repeat, and a * fork's cut then lands in the wrong place with no error. */ | "ordinals_not_sequential" /** * Lines that are structurally messages exist, but the render rule matched * none of them — a renamed role, type, or content shape. This is the silent * empty-conversation case. */ | "no_messages_parsed" /** * A fork that names its source but not where the source stops. Its inherited * history cannot be reconstructed, so it opens showing only its own turns. */ | "fork_link_without_cut" /** Most lines are not JSON at all — the container itself changed. */ | "not_jsonl"; export interface CodexFormatFinding { code: CodexFormatFindingCode; detail: string; } /** Lines read before giving up: enough to see the shape, bounded for a 68 MB rollout. */ export declare const CANARY_LINE_BUDGET = 2000; /** * Audit the opening `lines` of one rollout. * * Pure and synchronous so the assumptions can be tested against drifted * fixtures rather than only against healthy ones — a canary nobody has seen * fire is a canary nobody knows is wired up. */ export declare function auditCodexRolloutLines(lines: string[]): CodexFormatFinding[]; /** * The newest rollouts under `roots`, newest first. * * Newest is the whole point: an old file proves only what Codex used to write, * and the drift worth catching is in what it writes now. Date-partitioned * directories (`/YYYY/MM/DD`) mean the newest day's directory is enough — * walking every rollout would be a full-tree stat on a machine with thousands. */ export declare function findNewestRollouts(roots: string[], limit: number, fs: { readdirSync: (p: string) => string[]; statSync: (p: string) => { mtimeMs: number; isDirectory(): boolean; }; existsSync: (p: string) => boolean; }, join: (...parts: string[]) => string): string[]; export interface CanaryDeps { readdirSync: (p: string) => string[]; statSync: (p: string) => { mtimeMs: number; isDirectory(): boolean; }; existsSync: (p: string) => boolean; readFileSync: (p: string, enc: "utf8") => string; join: (...parts: string[]) => string; } export interface CanaryReport { audited: number; findings: Array<{ filePath: string; } & CodexFormatFinding>; } /** How many of the newest rollouts each sweep looks at. */ export declare const CANARY_SAMPLE_SIZE = 3; /** * One sweep: audit the newest rollouts and report what no longer holds. * * Returns rather than logs so the caller owns the log vocabulary and a test can * assert on findings instead of on log lines. */ export declare function sweepCodexFormat(roots: string[], deps: CanaryDeps): CanaryReport; //# sourceMappingURL=codexFormatCanary.d.ts.map