/** * DB-facing half of the `public_dns` check: the ledger names it watches and * the consecutive-undetermined counters it carries between runs. * * Split from `public-dns.ts` so the audit itself stays a pure function over an * injected probe — the counters are the only state it has, and a check that * owned its own storage could not be tested without one. */ import type { DbClient } from '../../db/client'; import { publicDnsEvidence } from '../../db/schema'; import { listDnsRegistrations } from '../dns-registrations'; import type { PublicDnsEvidence, PublicDnsRecord } from './public-dns'; /** * Every name celilo has asserted publicly. `lastAssertedAt` is when the fleet * last told the registrar about it — the point the record's own TTL is * measured from, so a divergence inside one TTL reads as propagation. */ export function loadPublicDnsRecords(db: DbClient): PublicDnsRecord[] { return listDnsRegistrations(db).map((row) => ({ fqdn: row.fqdn, companion: row.companion, lastAssertedAt: row.refreshedAt ?? row.registeredAt, })); } export function loadPublicDnsEvidence(db: DbClient): PublicDnsEvidence[] { return db .select({ subject: publicDnsEvidence.subject, undeterminedRuns: publicDnsEvidence.undeterminedRuns, }) .from(publicDnsEvidence) .all(); } /** * Replace the whole set. A subject that produced evidence this run is absent * from `evidence` and its counter goes with it — that is what makes the count * consecutive rather than cumulative. */ export function savePublicDnsEvidence(db: DbClient, evidence: PublicDnsEvidence[]): void { db.delete(publicDnsEvidence).run(); if (evidence.length === 0) return; db.insert(publicDnsEvidence) .values( evidence.map((e) => ({ subject: e.subject, undeterminedRuns: e.undeterminedRuns, lastCheckedAt: new Date(), })), ) .run(); }