Skip to content

Decouple tag identity from presentation (Tag.display_name) - #14

Merged
WilfordGrimley merged 2 commits into
masterfrom
worktree-tag-display-name
Jul 14, 2026
Merged

Decouple tag identity from presentation (Tag.display_name)#14
WilfordGrimley merged 2 commits into
masterfrom
worktree-tag-display-name

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Summary

Decouples tag identity (Tag.name, immutable) from tag presentation
(Tag.display_name, freely editable) before more tag data accumulates on
top of the printing/tag consensus system.

  1. Model: Tag.display_name — nullable CharField, additive migration
    0056_tag_display_name. name remains the machine key used by votes,
    tag_vote_statuses, Card.tags, and federation; the field's help text
    spells out "NEVER rename a Tag after creation."
  2. Serialization: Tag.serialise() / SerialisedTag schema (Python +
    TS, quicktype-regenerated) gain displayName. Frontend renders
    displayName ?? name at every tag render site — queue strips
    (NoMatchReasonStrip, PrintingConfirmStrip, QueueTagQuestion),
    TagVotePicker chips, the tag filter UI, and the card detail modal —
    via a shared useTagDisplayName() hook backed by the already-cached
    useGetTagsQuery(). All API submissions/filters still send name.
  3. Seeding: seed_no_match_reason_tags now also backfills
    display_name for its six tags ("Custom art", "Altered frame",
    "Upscaled", "AI art", "No collector line", "Non-English"), and
    seed_default_tags backfills it for the legacy "Full Art"/"Borderless"
    tags. Both are idempotent and only fill when display_name is
    currently None — a manually-edited display name is never clobbered on
    re-seed. No existing tag's name was renamed.
  4. Indexing-pipeline check (no code changes): cardpicker/tags.py's
    Tags.get_tags() / match_tag_fuzzy() / extract() match filename
    bracket tokens against Tag.name and Tag.aliases only — never
    display_name — and Card.tags persists tag_object.name. So this
    stage changes nothing about indexing today. A future change to
    name's key style (not something this PR does) would still break two
    things this PR doesn't touch: stale .lower() filename-bracket matches
    against the old name, and already-persisted Card.tags snapshot arrays
    with no reconciliation migration path. Full writeup in
    docs/features/printing-tags.md's new Stage 5 section.
  5. Docs: one-line additions to docs/federation-v1.md (tag name is
    the immutable interchange key; display_name never federates) and a new
    Stage 5 section in docs/features/printing-tags.md covering the model,
    serialization, hook, seeding, and the item-4 analysis in full.
  6. Tests: serialization includes displayName (backend + a new
    TestGetTags case with a set display name), frontend fallback renders
    raw name when displayName is unset (new TagVotePicker.spec.ts
    case using a mock where only one tag has a display name), and seeding
    idempotence (both test_reason_tags.py and new test_default_tags.py
    assert re-running the seeder never overwrites a manually-set
    display_name).

Test plan

  • Backend: pytest — 459 passed, 4 pre-existing unrelated failures
    (test_integrations.py::TestMTGIntegration::test_valid_url[moxfield],
    [moxfield_without_www], test_sources.py::TestUpdateDatabase::test_comprehensive_snapshot,
    test_upsert — same baseline as master, not touched by this change).
  • Frontend: Jest 123/123 (excluding one pre-existing Node-version-gapped
    file, same as baseline), eslint 0 errors, prettier --check clean,
    npm run build succeeds (static export, all 8 pages).
  • Playwright: 161/161, including the two new/updated tag-display-name
    cases.
  • Manual visual check: screenshotted NoMatchReasonStrip,
    PrintingConfirmStrip, and TagVotePicker against mocks with real
    display names set — confirmed correct rendering (including the
    known-and-intended "Full art" → "Full Art" chip-label change) with no
    loading flicker or layout issues.

Holding as draft for review per task instructions — not merging.

🤖 Generated with Claude Code

https://claude.ai/code/session_016i9S7LQsCL3FGaih3ZTRBJ

Add nullable Tag.display_name (presentation only; name stays the
immutable machine key for votes/Card.tags/federation). Serialize it
through the schema, render displayName ?? name at all 6 frontend tag
render sites via a shared useTagDisplayName hook, and backfill display
names for the 6 no-match-reason tags plus Full Art/Borderless
idempotently without clobbering manual edits.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016i9S7LQsCL3FGaih3ZTRBJ
…y-name

# Conflicts:
#	docs/features/printing-tags.md
@WilfordGrimley
WilfordGrimley marked this pull request as ready for review July 14, 2026 14:17
@WilfordGrimley
WilfordGrimley merged commit 6bda288 into master Jul 14, 2026
6 of 7 checks passed
@WilfordGrimley
WilfordGrimley deleted the worktree-tag-display-name branch July 14, 2026 22:33
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