What's wrong
schema.ts and tables.ts are two hand-maintained descriptions of the same schema, and they have already drifted:
tables.ts:22 declares FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE
schema.ts:41-42 declares .references(() => chatsTable.id) with no onDelete
The guard test that is supposed to catch this compares column names only (reconcile-columns.test.ts:177-179). Types, NOT NULL, DEFAULT, foreign keys and indexes are all unchecked.
The live hole is indexes. There are four index(...) declarations in schema.ts:65-69,104-109 and four CREATE INDEX IF NOT EXISTS in tables.ts:52-60,88-96, and reconcileColumns handles columns only (reconcile-columns.ts:38-52). So an index added to schema.ts alone reaches no database and no test fails. This drift class already caused a shipped 500 — documented in the comment at reconcile-columns.ts:9-17.
Proposed change
Keep the createTables(database) signature, but generate its body from appTables via getTableConfig, sharing the column-fragment builder with addColumnStatement (reconcile-columns.ts:58-75), which already emits type / NOT NULL / DEFAULT.
One trap to watch: the ALTER path synthesizes a backfill default ('' / 0) for $defaultFn NOT NULL columns. The CREATE path must not inherit that, or fresh installs get databaseId TEXT NOT NULL DEFAULT ''.
Scope
The tables.ts body, a small exported helper in reconcile-columns.ts, plus tests. Zero call sites change.
Risks
Bounded to fresh installs receiving never-shipped DDL. Safety net: keep today's DDL as a test fixture and assert pragma_table_info + pragma_index_list equality between a fixture-built and a generator-built in-memory database.
Validation
Add the pragma_table_info / pragma_index_list equality test described above. Extend the guard test beyond column names.
Blocked on
Two decisions have to be made in order:
- Do the dead-
chats/messages deletion first — removing the only foreign key makes the generator strictly simpler.
- This overlaps with the "delete the unreachable
drizzle/ folder" issue. Deleting drizzle/ is unconditionally correct; whether the documentation should then point at a generator or at hand-written DDL depends on whether this issue is taken. Decide this one first.
Found in a codebase-wide simplification audit (F-S03-b). Confidence: medium — not a line-count win; the payoff is eliminating a drift class that has already shipped a bug.
What's wrong
schema.tsandtables.tsare two hand-maintained descriptions of the same schema, and they have already drifted:tables.ts:22declaresFOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADEschema.ts:41-42declares.references(() => chatsTable.id)with noonDeleteThe guard test that is supposed to catch this compares column names only (
reconcile-columns.test.ts:177-179). Types,NOT NULL,DEFAULT, foreign keys and indexes are all unchecked.The live hole is indexes. There are four
index(...)declarations inschema.ts:65-69,104-109and fourCREATE INDEX IF NOT EXISTSintables.ts:52-60,88-96, andreconcileColumnshandles columns only (reconcile-columns.ts:38-52). So an index added toschema.tsalone reaches no database and no test fails. This drift class already caused a shipped 500 — documented in the comment atreconcile-columns.ts:9-17.Proposed change
Keep the
createTables(database)signature, but generate its body fromappTablesviagetTableConfig, sharing the column-fragment builder withaddColumnStatement(reconcile-columns.ts:58-75), which already emitstype / NOT NULL / DEFAULT.One trap to watch: the ALTER path synthesizes a backfill default (
''/0) for$defaultFnNOT NULL columns. The CREATE path must not inherit that, or fresh installs getdatabaseId TEXT NOT NULL DEFAULT ''.Scope
The
tables.tsbody, a small exported helper inreconcile-columns.ts, plus tests. Zero call sites change.Risks
Bounded to fresh installs receiving never-shipped DDL. Safety net: keep today's DDL as a test fixture and assert
pragma_table_info+pragma_index_listequality between a fixture-built and a generator-built in-memory database.Validation
Add the
pragma_table_info/pragma_index_listequality test described above. Extend the guard test beyond column names.Blocked on
Two decisions have to be made in order:
chats/messagesdeletion first — removing the only foreign key makes the generator strictly simpler.drizzle/folder" issue. Deletingdrizzle/is unconditionally correct; whether the documentation should then point at a generator or at hand-written DDL depends on whether this issue is taken. Decide this one first.Found in a codebase-wide simplification audit (F-S03-b). Confidence: medium — not a line-count win; the payoff is eliminating a drift class that has already shipped a bug.