/** * The per-transport record of whether celilo can still READ replies. * * Extracted from the poll command because it now has two readers: the poller * writes it, and the audit asserts on it. Keeping the key format private to the * writer would have meant the audit re-deriving a string literal — the sort of * duplication that silently stops matching. * * The shape it stores is the point. celilo's only per-transport state used to * be the receive cursor, and `writeCursor` returns early when there is no * cursor — which a failed read never produces. So the store could not * REPRESENT a failure, and "unreadable since Tuesday" left exactly the same * trace as "nobody replied since Tuesday" (#501). */ import { eq } from 'drizzle-orm'; import type { DbClient } from '../../db/client'; import { systemConfig } from '../../db/schema'; import { type TransportReadRecord, transportsWithRoutes } from './inbound-poller'; const READ_PREFIX = 'alerting.last_read.'; export function readLastRead(db: DbClient, transportModuleId: string): TransportReadRecord | null { const row = db .select() .from(systemConfig) .where(eq(systemConfig.key, `${READ_PREFIX}${transportModuleId}`)) .get(); if (!row?.value) return null; try { return JSON.parse(row.value) as TransportReadRecord; } catch { // A malformed row must not read as "never succeeded" — that would invent a // fact and page someone about it. return null; } } /** * Record one attempt, carrying the last SUCCESS forward. * * Deliberately has no counterpart to `writeCursor`'s early return: a failure * that writes nothing is why this record did not exist before. Carrying the * success forward is what turns a log into an answer — a run of failures must * not erase when the transport last actually worked. */ export function writeLastRead( db: DbClient, transportModuleId: string, record: TransportReadRecord, ): void { const key = `${READ_PREFIX}${transportModuleId}`; const previous = readLastRead(db, transportModuleId); const lastSuccessAt = record.outcome === 'received' ? record.at : (previous?.lastSuccessAt ?? undefined); const value = JSON.stringify({ ...record, ...(lastSuccessAt ? { lastSuccessAt } : {}) }); const existing = db.select().from(systemConfig).where(eq(systemConfig.key, key)).get(); if (existing) { db.update(systemConfig).set({ value }).where(eq(systemConfig.key, key)).run(); } else { db.insert(systemConfig) .values({ key, value, description: `Last inbound read attempt for ${transportModuleId}` }) .run(); } } export interface TransportReadStatus { transportModuleId: string; last: TransportReadRecord | null; } /** * Read state for every transport that has a route pointing at it. * * Scoped to transports with routes on purpose: a transport nobody is routed to * cannot fail to deliver anyone's acknowledgement, and paging about it would be * noise that trains an operator to ignore this check. */ export function readAllTransportStatuses(db: DbClient): TransportReadStatus[] { return transportsWithRoutes(db).map((transportModuleId) => ({ transportModuleId, last: readLastRead(db, transportModuleId), })); }