--- id: ML-153 title: Move MusicBrainz data transformations out of Record schema status: Done assignee: [] created_date: "2026-04-30 10:48" updated_date: "2026-04-30 12:20" labels: - refactor - records - musicbrainz dependencies: [] references: - lib/music_library/records/record.ex - lib/music_brainz/release_group.ex priority: medium --- ## Description The `Record` schema (`lib/music_library/records/record.ex`) contains MusicBrainz-specific data transformation functions that belong in the MusicBrainz API layer, not in the database schema: - `parse_artists/1` — extracts artist credits from MusicBrainz API response - `parse_subtype/2` / `parse_secondary_types/1` — maps MusicBrainz type strings to `Record` enum values - `attrs_from_release_group/1` — builds a changeset attrs map from a MusicBrainz release group These functions are called by `add_musicbrainz_data/2` (changeset pipeline) and during MusicBrainz import flows. Move the parsing functions to appropriate `MusicBrainz` modules (e.g., `MusicBrainz.ReleaseGroup` already has related helpers) and keep only struct introspection/presentation functions on `Record` (`artist_names/1`, `releases/1`, `released?/1`, `format_release_date/1`, etc.). Update callers in: - `Record.changeset/2` and `add_musicbrainz_data/2` - `Records` context (import functions) - Any tests that reference the moved functions directly ## Acceptance Criteria - [x] #1 `parse_artists/1`, `parse_subtype/2`, `parse_secondary_types/1`, and `attrs_from_release_group/1` are moved to `MusicBrainz` modules - [x] #2 `Record` schema retains only struct introspection and presentation helpers - [x] #3 All callers are updated to use the new locations - [x] #4 Full test suite passes - [x] #5 `@moduledoc` on moved functions explains their purpose ## Implementation Notes `parse_artist_credits/1` and `parse_record_type/2` moved to `MusicBrainz.ReleaseGroup` — these are pure MusicBrainz data parsing functions with no Record schema knowledge. `attrs_from_release_group/1` stays on `Record` because it maps MusicBrainz response fields to Record changeset keys (an implicit Record schema dependency). The Record schema now delegates parsing to `ReleaseGroup.parse_artist_credits/1` and `ReleaseGroup.parse_record_type/2`, keeping the coupling boundary clean: MusicBrainz modules parse MusicBrainz data; the Record schema owns its own field mapping. ## Final Summary Moved `parse_artist_credits/1` and `parse_record_type/2` to `MusicBrainz.ReleaseGroup`. `attrs_from_release_group/1` kept on `Record` to avoid reverse dependency — it now delegates parsing to the new MusicBrainz functions. `Record.update_artists/1` uses `ReleaseGroup.parse_artist_credits/1`. All 884 tests pass.