chore(database): stop declaring the dead tables and columns, ahead of the migration that drops them (cleanup round 2, 1/2)

Merged
DA
7d ago
+4116-971

Summary

Cleanup round 2, step 2, PR 1 of 2 (Dean approved: do #2). The expand/contract half that stops naming the dead tables and columns. The drop migration follows in PR 2 once this is live in production.

Nothing in the code reads or writes these, and the README already said so. No schema module declares them now, so no Drizzle insert names them, and the drift check (apps/web/tests/drizzle-schema.test.ts) lists them as waiting on their drop:

  • Tables (new PENDING_DROP_TABLES, same terms as PENDING_DROP, held by a test that fails once one is gone): events, provider_cursors, provider_key, roster_snapshot, transcript_mark, observation_pass, workspace_file, workspace_embedding, devices, account_workspace_preference, introduction_usage. The schemas/{devices,roster,vault,workspace}.ts modules and their package exports go.
  • provider_key is NOT the BYOK table. BYOK keys live in account_provider_key (migration 0080_account_provider_key, schemas/account-provider-key.ts, models/provider-key-store.ts), which this PR doesn't touch. provider_key is the earlier vault table (schemas/vault.ts). No code imports its providerKey declaration, and production holds 9 rows.
  • Columns (PENDING_DROP):
    • account_preference.default_workspace_provider
    • on conversations:
      • the observed-session columns provider_id, provider_session_id, workspace
      • spawned_by_message_id and completion_delivered_at (0 non-null rows in production)
      • next_event_seq, which numbered the events rows
      • the three memory_flush_* columns ("nothing writes the column now")
    • The indexes over them (conversations_observed_session, conversations_undelivered_children) go with the columns in PR 2.
  • Kept, because they're live: a child conversation's parent_conversation_id, label, title, and expects_completion. brain-host/conversation.ts's openChildConversation writes them for every subagent and coding-agent worker (38 child rows in production), and child-titles.ts and coding-agent-store.ts read title.
  • drizzle.__drizzle_migrations: core/migrator.ts's one-time bootstrapFromDrizzleHistory (and DRIZZLE_MIGRATIONS_TABLE) goes, along with its two tests. Every database the deployments migrate already records its history in effect_sql_migrations (101 rows in production, and every Neon preview branches from production). The table itself is dropped in PR 2.
  • @sidecar/wire's CONVERSATION_EVENT_KIND typed only the events column, so it goes. RATING_WORD stays. knip then flagged schemas/_helpers.ts's timestamps and the test helper instantColumn as unused, so they go too.
  • Migration 20261013120444_dead_tables_pending_drop is the one pnpm db:generate wrote, with its statements emptied out, per apps/web/server/README.md's two-deployment rule. Its snapshot already records the shape after the drop, so schemas/__tests__/migrations.test.ts stays green, and applying it changes nothing.

Production row counts PR 2 will drop: events 2155, provider_cursors 403, provider_key 9, roster_snapshot 3, transcript_mark 3, observation_pass 3, workspace_file 65, workspace_embedding 380, devices 22, account_workspace_preference 3, introduction_usage 31, drizzle.__drizzle_migrations 22; and 3 non-null default_workspace_provider values, 969/969/479 provider_id/provider_session_id/workspace values on the observed conversation rows (the rows themselves stay).

Tests

  • New apps/web/tests/dead-tables-dropped.test.ts makes PR 2's drop on its own database (every dead table and column gone) and then runs the store paths that write beside them or cascade through them. Each one still answers:

    • account preferences and the plan template
    • a plan and its conversation
    • a child conversation and its title
    • the account's deletion

    It fails without this PR's schema change (column "default_workspace_provider" of relation "account_preference" does not exist), which is the release-overlap window it guards.

  • Deleted, because they held only the dead shape, with no behavior test left to cover them: storage-schema.test.ts's event-ledger and claim tests, the observed-session uniqueness test, the provider-cursor test, and the completion-sweep index row; voice-schema.test.ts's device-departure test (voice_sessions.device_id has no foreign key); effect-migrator.test.ts's two bootstrap tests.

  • grep: no production source names any dropped table or column. tsc over apps/web after removing the declarations only flagged test files.

Evidence

  • Platform-independent checks: ./scripts/check.sh locally: knip, discarded-effect, typecheck, and tests (1132 + shards) passed; lint first failed on biome formatting of the new test and snapshot, fixed, and pnpm lint then exits 0. CI runs the whole check plus the Postgres migrations and store job
  • macOS Electron verification (./scripts/verify.sh): not run. No Mac or UI change, and this is a Linux VM; CI cannot verify the Mac (LUKE-159 is the manual Mac pass)

Invariants

  • ./scripts/check.sh green. No renderer/UI change.
  • JSON Schema goldens unchanged.
  • The behavior change (no insert names a dropped column) has the post-drop store test that fails without it; no change-detector test added.
  • Gateway envelope goldens unchanged.
  • No new as type assertion.
  • No Effect.runPromise/runSync/runFork added.
  • No raw async primitive added.
  • No discarded Effect.
  • Test count delta listed above (tests removed with the dead tables; one store test added).
  • No hand-rolled file replaced.
  • apps/web/server/README.md's migration-runner paragraph and dead-tables paragraph are edited; root AGENTS.md/CLAUDE.md untouched.
  • PRIVACY.md unchanged.
  • Package deps unchanged; @sidecar/database drops four schema subpath exports.
  • Barrel/door rule untouched.

Notes

  • PR 2 (the drop): once this is live in production, take a Neon snapshot, re-verify against the live release, then write a --custom migration of DROP TABLE IF EXISTS … CASCADE / DROP COLUMN IF EXISTS / DROP TABLE IF EXISTS drizzle.__drizzle_migrations, empty the two pending-drop lists, delete this PR's post-drop test, and drop events from store-writer-boundary.test.ts's guard.
  • Also dead and left alone (not on the approved list): voice_sessions.device_id ("nothing writes it any more").

šŸ¤– Generated with Claude Code


Open workspace in Conductor


Devin Review