/** * Shared contracts and helpers for the reconciliation scanner modules. * * The drift detector (diff.ts), the correction builder (repair.ts), and the * scan orchestrator (ReconciliationScanner.ts) all operate on the durable * desired state, the visible state, and the outbox. This module owns those * shared types, the SQL statements that read them, and the small helpers that * decode canonical rows into the internal desired-row shape, so the role * modules can import from one place without importing each other. */ import type { NormalizedCell } from "../../../../contracts/encoding/types.js"; import { READ_DESIRED_SYSTEM_STATE_SQL, RECONCILIATION_SCAN_CHUNK_SIZE, RECONCILIATION_SCAN_ENTITY_PAGE_SIZE, readActiveEntityPageWithSql, readEntityBindingsWithSql, readEntityFieldsWithSql, readReconciliationDesiredSystemStateChunkWithSql, type ReconciliationDesiredChunkCursor, type ReconciliationDesiredEntityChunk, type ReconciliationDesiredSystemStateRow } from "../../../../storage/sync/outbound/reconciliationSql.js"; import type { SqlExecutor, SqlStorageAdapter } from "../../../../contracts/storage/sql.js"; import type { SyncSheetsProvider } from "../../../../contracts/sheets/syncSheets.js"; export { READ_DESIRED_SYSTEM_STATE_SQL, RECONCILIATION_SCAN_CHUNK_SIZE, RECONCILIATION_SCAN_ENTITY_PAGE_SIZE, readActiveEntityPageWithSql, readEntityBindingsWithSql, readEntityFieldsWithSql, readReconciliationDesiredSystemStateChunkWithSql, }; export type { ReconciliationDesiredChunkCursor, ReconciliationDesiredEntityChunk, ReconciliationDesiredSystemStateRow, }; export declare const DEFAULT_RECONCILIATION_ROLE = "typed-sheets-reconciler"; export declare const DEFAULT_RECONCILIATION_LEASE_MS = 60000; export declare const DEFAULT_SYSTEM_TOMBSTONE_FIELD = "_deleted"; /** Builder used by the scanner to produce fresh effect/commit identifiers. */ export type ReconciliationIdFactory = () => string; export interface DesiredRow { readonly entityId: string; readonly rowBindingId: string; readonly anchorReference: string; readonly entityRevision: number; readonly fields: Record; readonly fieldRevisionHash: string; } export interface LatestVisibleSqlShape { readonly confirmed_visible_revision: number | null; readonly confirmed_snapshot_hash: string | null; } export interface LatestEffectSqlShape { readonly effect_id: string; readonly stream_sequence: number | null; readonly expected_visible_revision: number | null; readonly expected_visible_hash: string | null; readonly status: string; readonly last_error_code: string | null; readonly payload_json: string | null; } export declare const READ_LATEST_VISIBLE_STATE_SQL = "\n SELECT confirmed_visible_revision, confirmed_snapshot_hash\n FROM sheet_visible_state\n WHERE physical_sheet_id = ? AND projection = 'system_state' AND row_binding_id = ?\n"; export declare const READ_LATEST_EFFECT_SQL = "\n SELECT effect_id, stream_sequence, expected_visible_revision, expected_visible_hash, status, last_error_code, payload_json\n FROM sheet_effect_outbox\n WHERE logical_sheet_id = ? AND target_kind = 'entity' AND target_id = ?\n ORDER BY stream_sequence DESC\n LIMIT 1\n"; /** * Reads the active `failed` effect for one target stream. * * At most one `failed` effect can be active per stream: a failed effect is * never in `('applied','superseded')`, so the durable predecessor guard blocks * every later effect until it is superseded. The caller decides whether the * code is terminal (non-recoverable) and must be superseded by a repair. */ export declare const READ_FAILED_HEAD_SQL = "\n SELECT effect_id, last_error_code\n FROM sheet_effect_outbox\n WHERE logical_sheet_id = ? AND target_kind = 'entity' AND target_id = ? AND status = 'failed'\n ORDER BY stream_sequence DESC\n LIMIT 1\n"; export interface FailedHeadSqlShape { readonly effect_id: string; readonly last_error_code: string | null; } /** * Reads every active `failed` effect of one logical sheet, newest stream * first, so the scanner can detect terminal heads on streams whose Sheet row * already matches canonical (drift-free rows never reach per-drift repair * planning). */ export declare const READ_FAILED_HEADS_SQL = "\n SELECT effect_id, target_id, last_error_code\n FROM sheet_effect_outbox\n WHERE logical_sheet_id = ? AND target_kind = 'entity' AND status = 'failed'\n ORDER BY stream_sequence DESC\n"; export interface FailedHeadsSqlShape { readonly effect_id: string; readonly target_id: string; readonly last_error_code: string | null; } /** * Returns the terminal (non-recoverable) failed head effect id per target * stream for one logical sheet. * * Recoverable failed heads stay on the worker retry path and are never * superseded by reconciliation, mirroring `readTerminalFailedHeadWithSql`. */ export declare function readTerminalFailedHeads(context: ScanContext): Promise>; /** * Reads terminal failed heads inside the caller's SQL context so the chunked * scan can share one read with its pages instead of opening a second one. */ export declare function readTerminalFailedHeadsWithSql(sql: SqlExecutor, logicalSheetId: string): Promise>; export interface ScanContext { readonly storage: SqlStorageAdapter; readonly provider: SyncSheetsProvider; readonly physicalSheetId: string; readonly logicalSheetId: string; readonly systemFields: readonly string[]; readonly tombstoneField: string | undefined; readonly schemaVersion: number; readonly writerId: string; readonly now: () => number; readonly createId: ReconciliationIdFactory; readonly role: string; readonly leaseDurationMs: number; } export declare function readDesiredSystemState(context: ScanContext): Promise; export declare function readDesiredSystemStateWithSql(sql: SqlExecutor, context: Pick): Promise; /** One entity's fields accumulated across chunk boundaries. */ export interface PartialDesiredRow { readonly entityId: string; readonly rowBindingId: string; readonly anchorReference: string; readonly entityRevision: number; readonly fields: Record; } /** Completed desired rows plus the trailing entity still missing fields. */ export interface DesiredChunkResult { readonly completed: readonly DesiredRow[]; readonly carry: PartialDesiredRow | undefined; } /** * Groups one ordered page of flat canonical rows into completed desired * rows. A page may split an entity's fields across the boundary, so the * trailing entity is returned as `carry` and must seed the next call; only * `flushDesiredCarry` after the last page finalizes it. Completed rows are * finalized (tombstone default + revision hash) exactly like the full-load * reader, in global `(entity_id, field_name)` order. */ export declare function assembleDesiredChunk(rows: readonly ReconciliationDesiredSystemStateRow[], carry: PartialDesiredRow | undefined, tombstoneField: string | undefined): DesiredChunkResult; /** Finalizes the trailing entity after the last page. */ export declare function flushDesiredCarry(carry: PartialDesiredRow | undefined, tombstoneField: string | undefined): DesiredRow | undefined; export declare function ensureTombstoneField(row: DesiredRow, tombstoneField: string | undefined): void; export declare function computeFieldRevisionHash(fields: Readonly>): string; export declare function decodeNormalizedCell(value: string): NormalizedCell; //# sourceMappingURL=shared.d.ts.map