Repository navigation
chore(cost-insights): drop the cost_insight_* tables and schema - #5024
Conversation
Final step of the Cost Insights shutdown. The UI and API were removed in #4993 and all reads and writes in #4996, so the twelve tables have been unused since then. Migration 0204_drop_cost_insight_tables drops all twelve with CASCADE. This is safe to run at any point relative to the deploy: no non-Cost- Insights table has a foreign key to any of them and no view references them, so the drop is self-contained and no currently deployed code touches them. The 27 foreign keys involved all originate from the dropped tables. Also removed: - 12 table definitions, 16 inferred row types, and the CostInsightEvent snapshot Zod schemas from packages/db/src/schema.ts - the 7 Cost Insights enums from schema-types.ts, their schema.ts import, and their SCHEMA_CHECK_ENUMS registry entries - the matching expected-value entries in schema.test.ts, which must land with the registry change or the registry test fails - packages/db/src/cost-insight-event-snapshot.test.ts, whose only subject was CostInsightEventSnapshotSchema - .specs/cost-insights.md, fully orphaned once #4996 removed the last CONTEXT.md reference to it Dropping cost_insight_owner_hour_driver_buckets also removes an ON DELETE NO ACTION foreign key from actor_user_id to kilocode_users, which could previously block hard user deletion. Deliberately kept: the discontinued-notice routes, and the two untracked production indexes the deleted maintenance script used to manage. Those are not in Drizzle, cannot be dropped from a transactional migration, and one may still serve organization usage queries, so they are left for a separate operational decision.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryIncremental review of the follow-up CONTEXT.md cleanup (removal of the Cost Insights domain row and the "fully removed" bullet, applying the author's own two line-deletion suggestions): both deletions match the PR's stated scope, the two remaining Cost Insights mentions are the deliberately kept behavioral notes about spend recording and the discontinued-notice routes, and the table and list structure remain intact. Files Reviewed (1 file)
Previous Review Summary (commit d8363fd)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit d8363fd)Status: No Issues Found | Recommendation: Merge Executive SummaryVerified the Cost Insights table shutdown end-to-end: the migration drops exactly the 12 Files Reviewed (9 files)
Reviewed by kimi-k3 · Input: 53.4K · Output: 4K · Cached: 185.3K Review guidance: REVIEW.md from base branch |
Final PR of the Cost Insights shutdown, after #4993 (UI and API) and #4996 (all reads and writes). The twelve tables have been unused since #4996 merged.
The migration
0204_drop_cost_insight_tables.sql— twelveDROP TABLE ... CASCADEstatements and nothing else. Generated bypnpm drizzle generate; no hand-editing of DDL, snapshots, or the journal.Deploy ordering is a non-issue. I verified against
0203_snapshot.jsonthat no non-Cost-Insights table has a foreign key to any of these tables, and no view references them. All 27 foreign keys involved originate from the dropped tables. Combined with #4996 removing every read and write, the migration is safe to run before, during, or after the code deploy.CASCADEtherefore only tears down the feature's own intra-table foreign keys, indexes, and constraints — it cannot reach outside the set.One incidental improvement:
cost_insight_owner_hour_driver_buckets.actor_user_idwas anON DELETE NO ACTIONforeign key tokilocode_users, so it could previously block hard user deletion. That blocker is gone.Schema and code removed
packages/db/src/schema.ts(−921): 12 table definitions, 16 inferred row types, theCostInsightEventSnapshotZod schemas, theschema-typesimport, and theSCHEMA_CHECK_ENUMSregistry entries.packages/db/src/schema-types.ts(−69): the 7 Cost Insights enums. I confirmed all 7 have zero consumers outsidepackages/db.packages/db/src/schema.test.ts(−19): the expected enum values. This must land with the registry change — removing one without the other fails the registry test withMissing enums.packages/db/src/cost-insight-event-snapshot.test.ts: deleted; its only subject wasCostInsightEventSnapshotSchema..specs/cost-insights.md: deleted. It was fully orphaned — chore(cost-insights): stop all writes to the cost_insight_* tables #4996 removed the lastCONTEXT.mdreference, and contrary to what I assumed, it was never listed in thespecsskill index, so no index entry needed updating.CONTEXT.md: the "scheduled to be dropped" language is now inaccurate.Deliberately kept
The discontinued-notice routes from #4993, so old bookmarks and previously sent alert emails still land on an explanation.
Two untracked production indexes. I told you in #4996 that these would be dropped in this migration. That was wrong, and worth correcting:
IDX_coding_plan_terms_credit_transactioncoding_plan_terms(credit_transaction_id)idx_microdollar_usage_org_created_atmicrodollar_usage(organization_id, created_at) WHERE organization_id IS NOT NULLNeither is known to Drizzle — absent from
schema.ts, all 204 prior migrations, and every snapshot. They exist only where the now-deleted maintenance script was run, sodrizzle generatewill not emit drops for them.DROP INDEX CONCURRENTLYcannot run inside Drizzle's transactional migration, and a plainDROP INDEXwould take anACCESS EXCLUSIVElock onmicrodollar_usage, one of the hottest tables in the system. The second index also plausibly still helps organization usage queries over a time range. Left for a separate operational decision informed by real production index-usage stats rather than a guess from code.Verification
pnpm drizzle generateproduced only the intended drops;pnpm drizzle checkreportsEverything's fine.pnpm drizzle migrateapplied locally, then confirmed viapsql: 0cost_insight%tables remain, 214 public tables remain, andkilocode_users,organizations,microdollar_usage,coding_plan_terms,credit_transactionsare all intact.pnpm drizzle:verify-bootstrappasses, proving the full 0000 → 0204 chain replays on an empty database (0179 and 0183 create these tables, 0204 drops them).scripts/typecheck-all.shandscripts/lint-all.sh: 0 errors across all workspaces. Repo-widepnpm format:checkclean.schema.test.ts+schema-types.test.ts: 42 tests pass, covering both the schema-versus-snapshot parity check and the enum registry.apps/websuite: 700 suites, 8,943 tests pass.services/kiloclaw-billing: 184 tests pass.Pre-existing gap found while verifying
packages/dbtests do not run anywhere.apps/web/jest.config.ts:38lists<rootDir>/../../packages/db/src/**/*.test.tsintestMatch, butrootsis unset so it defaults toapps/weband Jest never crawls that directory.packages/db/package.jsonhas onlytypecheckandlint, and no other Jest config covers it.So
schema.test.ts— which exists specifically to fail with "Schema is out of date! Run 'pnpm drizzle generate'" — is never executed by CI. I ran it explicitly via--rootsto validate this change. Not fixed here since it is unrelated to this PR and would newly enforce assertions across the whole schema, but it should be fixed separately.Also note
packages/db/src/client.test.tsfails under that ad-hoc invocation. I verified by stashing this branch that it fails identically on cleanorigin/main, so it is pre-existing and unrelated.