Skip to content

Migrate sector taggings onto the canonical sector list#1756

Open
maebeale wants to merge 1 commit into
mainfrom
maebeale/tehran-v1
Open

Migrate sector taggings onto the canonical sector list#1756
maebeale wants to merge 1 commit into
mainfrom
maebeale/tehran-v1

Conversation

@maebeale

@maebeale maebeale commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

What is the goal of this PR and why is this important?

  • PR Add sector descriptions and refresh the canonical sector list #1703 refreshed Sector::SECTOR_TYPES to the new canonical service-area list, seeded descriptions, and made seeds create the new names while unpublishing (not destroying) the legacy ones.
  • It deliberately did not migrate taggings. So in production every existing workshop/story/video/etc. tagging is stranded on a now-unpublished legacy sector (e.g. Child Abuse, Criminal/Legal, Student), while the new published sectors (Child Abuse/Neglect, Court/Legal System, Education) are empty.
  • This task closes that gap by re-homing the taggings, so the published canonical sectors carry the real data.

How did you approach the change?

  • Added lib/tasks/consolidate_sectors.rake (data:consolidate_sectors), dry-run by default; DRY_RUN=false to apply.
  • Rename when it's a 1:1 name change (9 sectors, e.g. Criminal/Legal → Court/Legal System): in-place update!, which keeps the same row and all its taggings — nothing is removed.
  • Merge (via ModelDeduper) only when two rows must collapse into one:
    • Student and Education/Schools both map to Education — a genuine 2:1 merge.
    • If the canonical name already exists (i.e. Add sector descriptions and refresh the canonical sector list #1703 seeds ran first), a rename would collide, so it falls back to a merge onto the seeded published record.
    • The merge re-points all taggings onto the kept sector, then removes the redundant empty row. Taggings are never lost — this is the same merge the admin dedupe screen performs.
  • Idempotent: a second run is a clean no-op.
  • Verified end-to-end against the dev DB: 21 → 31 sectors, Student's taggings folded into Education with no loss, second run skipped all steps. Rubocop clean.

Anything else to add?

  • No taggings are ever destroyed. Simple name changes keep their original sectors row (rename); only a genuine 2:1 merge removes a now-empty redundant row, which is the standard behavior of the existing ModelDeduper dedupe code.

🤖 Generated with Claude Code

PR #1703 refreshed SECTOR_TYPES and seeded the new names but left existing
taggings stranded on the unpublished legacy sectors. This task re-homes those
taggings — renaming legacy sectors in place where the canonical name does not
yet exist, or merging into it via ModelDeduper where it does — so the new
published sectors carry the real workshop/story/etc. taggings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# The target name is already taken by a different record, so an in-place
# rename would violate the uniqueness validation. Fall back to a merge.
puts " COLLISION #{from.inspect} -> #{to.inspect}: target ##{existing_target.id} exists, merging instead"
merges << [ from, to ]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: This collision branch is what makes the task deploy-order-agnostic: once #1703 seeds have created the new canonical name, an in-place rename would violate the uniqueness validation, so we route it through a merge onto the already-seeded published record instead.

target = find_by_name.call(target_name)
# In a dry run the prerequisite rename hasn't been persisted, so resolve
# the target back through its pre-rename name to preview accurately.
target ||= find_by_name.call(renames.key(target_name))

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Dry-run only: the prerequisite rename (e.g. Education/Schools → Education) is not persisted in a dry run, so the merge target wont be found by its new name. Resolving back through renames.key lets the dry run preview the Student → Education merge accurately.

@maebeale maebeale marked this pull request as ready for review June 18, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant