Added opt-in canonical observer polling lifecycle

This commit is contained in:
2026-10-20 20:11:57 -04:00
parent 8cfcf6c025
commit 7025c37390
8 changed files with 200 additions and 15 deletions
+10 -2
View File
@@ -8,13 +8,21 @@ import { custodyStorage, postgresConfig } from './postgres-config.ts';
/** No automatic SQLite reinterpretation or fallback after a database connection/configuration failure. */
export async function openCustodyStorage(directory: string, options: CustodyOptions, env = process.env): Promise<CustodyMarket | PostgresCustody> {
const storage = custodyStorage(env), marker = join(directory, 'testnet', 'custody-postgres.json');
const observerMode = env.WIKIDECK_CUSTODY_CANONICAL_REHEARSAL;
if (observerMode !== undefined && observerMode !== '0' && observerMode !== '1') {
throw new Error('WIKIDECK_CUSTODY_CANONICAL_REHEARSAL must be exactly 0 or 1');
}
if (observerMode === '1' && (env.NODE_ENV === 'production' || storage !== 'postgres' || env.WIKIDECK_PG_DISPOSABLE_TEST !== '1')) {
throw new Error('Canonical observer rehearsal requires PostgreSQL and the disposable database test guard');
}
const custodyOptions = observerMode === '1' ? { ...options, disposableSaleRehearsal: true } : options;
await mkdir(join(directory, 'testnet'), { recursive: true, mode: 0o700 });
let existing: { version: number; custodianId: string } | undefined;
try { existing = JSON.parse(await readFile(marker, 'utf8')); }
catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
if (storage === 'sqlite') {
if (existing) throw new Error('Custody data directory is bound to PostgreSQL; SQLite fallback prohibited');
return CustodyMarket.open(directory, options);
return CustodyMarket.open(directory, custodyOptions);
}
const source = join(directory, 'testnet', 'custody-sandbox.sqlite');
let frozen: string | undefined;
@@ -27,7 +35,7 @@ export async function openCustodyStorage(directory: string, options: CustodyOpti
if (!frozen) throw new Error('Existing SQLite custody requires explicit stopped-node import before PostgreSQL activation');
} finally { db.close(); }
} catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
const market = await PostgresCustody.open(await postgresConfig(env), options);
const market = await PostgresCustody.open(await postgresConfig(env), custodyOptions);
try {
if (frozen && await market.importSource() !== frozen) throw new Error('PostgreSQL import does not match local frozen custody source');
if (existing && (existing.version !== 1 || existing.custodianId !== market.id)) throw new Error('PostgreSQL custodian differs from data-directory binding');