Skip to content

Remove dead columns and tables left by deleted features #3015

Closed
5 of 5 issues completed
Closed

Description

@mroderick

Problem

Follow-up to the members.unsubscribed removal (#3007, merged in #3013/#3014). A scan of every table and column in the schema (46 tables, 377 columns) found four orphaned tables and three dead columns. Each item's feature code was removed months or years ago; only the schema and the production rows remain.

Findings

Dead tables — no model, controller, route, or view references remain:

Table Columns Production rows Code removed in
jobs 21 164 f25f10b8 (2022-07-22, "remove job board code")
courses 14 6 4fb0f938 (2022-04-12, "Deletes deprecated Course code")
course_invitations 8 1755 4fb0f938
course_tutors 4 7 4fb0f938

Dead columns on live tables:

Column Production data Last usage removed in
meetings.invites_sent 51 meetings, all non-null (default false) 39bbbe52 (2020-12-02)
workshops.sign_up_url 3 non-null of 2603, all pre-2014 c9391a35 (2014-09-09)
events.coach_description 3 non-null of 260, all pre-2016 de44fe17 (2016-06-14)

events.coach_description has one residual write: spec/fabricators/event_fabricator.rb sets a Faker value. It goes with the drop.

Work plan

Sub-issues, ordered. Each column drop follows the #3007 two-step (see "Why the ignore step comes first"): a PR that adds the column to ignored_columns, then a separate PR that drops it.

  1. Remove the stale ignored_columns entries from Member — both referenced columns are already gone.
  2. Drop meetings.invites_sent (two PRs).
  3. Drop workshops.sign_up_url (two PRs).
  4. Drop events.coach_description (two PRs; includes the fabricator cleanup).
  5. Drop the four dead tables (one PR; no ignore step needed because nothing references them).

Why the ignore step comes first

Same reasoning as #3007, shortened: the release phase runs migrations before new dynos boot, and under Heroku preboot old dynos keep serving against the new schema during the window. Rails 8.1 builds explicit column lists, so an old release serving after the drop would fail every query on that table with PG::UndefinedColumn. Adding the column to ignored_columns and deploying first takes it out of the new release's SELECT list; the second deploy then drops it safely.

Verification notes
  • ast-grep scan over app, lib, config, spec matched every column name as identifier, symbol, hash key, and string; word-boundary grep over HAML/ERB; raw SQL and string scan over db/. Zero references for every item above.
  • Association cross-check: the columns are not implicit foreign keys. No belongs_to (default or explicit foreign_key) resolves to invites_sent, sign_up_url, or coach_description, and none is part of a polymorphic pair.
  • Database-level: no views or triggers reference any of the three columns; no foreign keys, views, or triggers touch the four tables; events.coach_description is absent from all controller params.expect whitelists.
  • Production counts from a snapshot of the production dump (2026-10-12). invites_sent was read once more before being ignored; sign_up_url and coach_description have not been read since their commits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions