fix(chat-store): the index seam must not widen the table's column types - #347
fix(chat-store): the index seam must not widen the table's column types#347drewstone wants to merge 1 commit into
Conversation
`ChatExtraIndexes` returned `unknown[]`, which forced a cast on the whole
extra-config array passed to `sqliteTable`. That cast widened every column in
the emitted types to drizzle's cross-dialect union, so a consumer's
`db.select({ id: messages.id })` stopped compiling — five errors on one line in
gtm, against a package whose own typecheck was clean.
The callback now returns drizzle's `SQLiteTableExtraConfigValue[]`, so the
spread stays inside the union `sqliteTable` expects and no cast is needed.
The added tests pin insert/select behaviour and the column types this package
can see. They are honest about what they do not do: the widening is invisible
here and only appears through the emitted `.d.ts`, so the guard is a consumer's
typecheck — which is what caught it.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — f331bdfd
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-29T19:47:55Z
tangletools
left a comment
There was a problem hiding this comment.
🟢 Value Audit — sound
| Verdict | sound |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 370.9s (2 bridge agents) |
| Total | 370.9s |
💰 Value — sound
Tightens the index-seam return type from unknown[] to drizzle's own SQLiteTableExtraConfigValue[], letting the as never cast be dropped so the built tables keep their inferred column types — correct, minimal, proven by drizzle's own type signature.
- What it does: Two-commit follow-up to #346.
ChatExtraIndexes(src/chat-store/schema.ts:101) and the internalextraIndexeshelper (schema.ts:119) now returnSQLiteTableExtraConfigValue[]instead ofunknown[]. That type is exactly what drizzle'ssqliteTableextra-config callback is declared to return (drizzlesqlite-core/table.d.ts:22,28), so the spread...extraIndexes(...)stays inside the union th - Goals it achieves: Restore correct emitted
.d.tscolumn types for consumers ofcreateChatTables. #346'sunknown[]+as neverwidened every column to drizzle's cross-dialect union in the emitted types; this package's own typecheck stayed green, but a consumer whosedbmeets the table (gtm) hit 5 errors on a singledb.select. The fix makes the seam type-check cleanly on its own, with no consumer-visible wi - Assessment: Good change, in the grain of the codebase. It uses drizzle's own exported type for exactly the slot drizzle defines — no invented wrapper, no broader redesign. It targets the root cause (the
as nevercast that was forced byunknown[]) rather than patching symptoms. The new tests are unusually honest: their leading comment explicitly states they do NOT catch the regression (the widening is invi - Better / existing approach: none — this is the right approach. Searched for
SQLiteTableExtraConfigValueacross the repo (3 hits, all this PR) and read the sibling factorycreateTeamTables(src/teams/drizzle/schema.ts:44) which has no index seam and no cast. The seam itself is justified (it's what #346 added so a product with one extra index can adopt the factory instead of hand-rolling a duplicate), so eliminating it is - Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content
🎯 Usefulness — sound
A minimal, correct type fix that swaps an invented unknown[]+as never escape hatch for drizzle's own canonical extra-config type, unblocking the seam's first consumer (gtm-agent) whose typecheck the old widening broke.
- Integration: The
threadExtraIndexes/messageExtraIndexesseam lives oncreateChatTables(src/chat-store/schema.ts:85,88), exported via the/chat-storesubpath and composed bycreateChatStore(src/chat-store/store.ts:2). It is reachable and its first real consumer is gtm-agent — PR #346 built this seam specifically to let gtm drop its hand-rolled duplicatemessagetable (the PR body of #346 names exa - Fit with existing patterns: Fits the grain perfectly and removes a competing workaround rather than adding one. The prior
unknown[]return forced anas nevercast on the whole config array, which fought drizzle's type inference and widened emitted columns to the cross-dialect union. The fix usesSQLiteTableExtraConfigValue— verified to be the exact typesqliteTable's array-config overload already expects (drizzle-or - Real-world viability: Pure type-level change: a return-type annotation narrows from
unknown[]toSQLiteTableExtraConfigValue[]and theas nevercast is dropped. Zero runtime behavior change, and the runtime tests pin that insert/select/index behavior is identical with or without product indexes. The load-bearing proof is consumer-facing: the PR body shows gtm-agent's typecheck going 5 errors → 0 against the produ - Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
No concerns — sound change, no better or existing approach found. ✅
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
✅ No Blockers —
|
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 1 non-blocking finding — f331bdfd
Full multi-shot audit completed 2/2 planned shots over 2 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-07-29T19:56:55Z · immutable trace
Follow-up to #346, caught by the first consumer that adopted it.
ChatExtraIndexesreturnedunknown[]. That forced a cast on the wholeextra-config array handed to
sqliteTable, and the cast widened every columnin the emitted types to drizzle's cross-dialect union. agent-app's own
typecheck stayed clean; gtm's produced five errors on a single
db.select:The callback now returns drizzle's own
SQLiteTableExtraConfigValue[], so thespread stays inside the union
sqliteTableexpects and no cast is needed.About the tests
Three new assertions pin that a table built WITH product indexes still inserts,
selects, and reports SQLite column types the same as one built without.
They did not catch this regression, and the comment says so. Reverting to
unknown[]+ the cast produces 0 errors in this package — the widening isinvisible from inside it and only appears through the emitted
.d.tsin aconsumer whose own
dbtype meets the table. Writing that down beats leaving aguard that reads stronger than it is; the real guard is a consumer's typecheck,
which is where the defect surfaced.
Verification
And the consumer that found it, on this build: