Fix filing taxonomy schema mismatch by adding explicit column verification

The filing_taxonomy_snapshot table was missing parser_engine and related columns
on databases created before the taxonomy surface sidecar migration. This caused
filing sync workflows to fail with 'table has no column named parser_engine'.

Changes:
- Add TAXONOMY_SNAPSHOT_REQUIRED_COLUMNS constant for required columns
- Add verifyCriticalSchema() to fail fast at startup if schema is incompatible
- Reorder ensureTaxonomySnapshotCompat to check table existence before column ops
- Add explicit column verification after ALTER TABLE attempts
- Add regression tests for missing column detection

Fixes #2
This commit is contained in:
2026-03-15 13:15:01 -04:00
parent 529437c760
commit 7a42d73a48
3 changed files with 88 additions and 5 deletions

View File

@@ -11,7 +11,8 @@ import { schema } from './schema';
import {
ensureLocalSqliteSchema,
hasColumn,
hasTable
hasTable,
TAXONOMY_SNAPSHOT_REQUIRED_COLUMNS
} from './sqlite-schema-compat';
type AppDrizzleDb = ReturnType<typeof createDb>;
@@ -132,6 +133,27 @@ function ensureSearchVirtualTables(client: Database) {
client.exec('CREATE INDEX IF NOT EXISTS `search_chunk_vec_lookup_idx` ON `search_chunk_vec` (`scope`, `user_id`, `source_kind`, `ticker`);');
}
function verifyCriticalSchema(client: Database) {
if (!hasTable(client, 'filing_taxonomy_snapshot')) {
return;
}
const missingColumns: string[] = [];
for (const columnName of TAXONOMY_SNAPSHOT_REQUIRED_COLUMNS) {
if (!hasColumn(client, 'filing_taxonomy_snapshot', columnName)) {
missingColumns.push(columnName);
}
}
if (missingColumns.length > 0) {
throw new Error(
`[db] CRITICAL: Database schema is incompatible. ` +
`filing_taxonomy_snapshot is missing columns: ${missingColumns.join(', ')}. ` +
`Delete the database file and restart to rebuild schema.`
);
}
}
export function getSqliteClient() {
if (!globalThis.__fiscalSqliteClient) {
configureCustomSqliteRuntime();
@@ -147,6 +169,7 @@ export function getSqliteClient() {
client.exec('PRAGMA busy_timeout = 5000;');
loadSqliteExtensions(client);
ensureLocalSqliteSchema(client);
verifyCriticalSchema(client);
ensureFinancialIngestionSchemaHealthy(client, {
mode: resolveFinancialSchemaRepairMode(process.env.FINANCIAL_SCHEMA_REPAIR_MODE)
});
@@ -176,5 +199,6 @@ export const __dbInternals = {
hasColumn,
hasTable,
isVectorExtensionLoaded,
loadSqliteExtensions
loadSqliteExtensions,
verifyCriticalSchema
};