/** * `chat-recall verify --deep` — does the server actually hold what this machine * has, per session? * * Every silent-loss incident in this codebase was found by a human asking about * one specific session. Nothing reported them, because every symptom looks like * healthy operation: `15604 skipped` is what a fully-synced corpus prints too. * This is the check that turns "did session X make it?" from an investigation * into a command. * * It compares in the unit the server's shrink guard uses — `gzipContainer().size` * of the local union versus the archive's stored `size` — so a difference means * the server is genuinely missing records, not that two measurements disagree. * Sub-unit noise is ignored via a tolerance. * * Both sides must be the REDACTED container (see Deps.localContainerSize): the * archive stores what was shipped, and what was shipped had its secrets * replaced by sentinels. * * Deliberately NOT an mtime comparison: the server stores the client-sent mtime, * which drifts sub-second against the file for essentially every session. An * mtime-based version of this check reported 9,975 of 10,032 sessions suspect * when the true number was 13. * * Classification matters as much as detection: * pending — the ledger knows there is more to send; it will go on its own * STRANDED — the ledger claims complete while the server holds less, so * nothing will ever re-ship it. This is the actionable class. */ export interface VerifyFinding { sessionId: string; projectPath: string; localSize: number; serverSize: number; deficit: number; /** Ledger claims complete ⇒ nothing will re-ship it without intervention. */ stranded: boolean; } export interface VerifyReport { server: string; checked: number; complete: number; missingArchive: number; pending: VerifyFinding[]; stranded: VerifyFinding[]; } interface Deps { listSessions(sinceMs: number): Array<{ rawId: string; prefixedId: string; projectPath: string; mtime: number; }>; /** * Size of the container as it WOULD BE SHIPPED — i.e. REDACTED, then gzipped. * * This is a hard requirement, not a preference. The sync path redacts before * archiving, so measuring the raw container compares two different artifacts: * a long secret becomes a short sentinel and the local side reads bigger * forever. Two sessions were reported stranded through a full repair+sync * cycle for exactly this reason — the deficit was redaction, not loss, and no * amount of re-shipping could ever close it. */ localContainerSize(rawId: string): number | null; fileSize(rawId: string): number; serverSizes(server: string, token: string): Promise>; } /** * Pure comparison, injectable so it can be tested without a server or a real * transcript corpus. */ export declare function verifyAgainstServer(server: string, token: string, sinceMs: number, deps: Deps, now?: number): Promise; /** Every configured target, so a multi-server setup is verified as a whole. */ export declare function verifyTargets(): Array<{ serverUrl: string; token: string; }>; export {}; //# sourceMappingURL=verify-deep.d.ts.map