Skip to content

fix: backfill a blank canonical image when reusing a canonical artist - #798

Open
sweetmantech wants to merge 2 commits into
mainfrom
feat/backfill-canonical-image
Open

fix: backfill a blank canonical image when reusing a canonical artist#798
sweetmantech wants to merge 2 commits into
mainfrom
feat/backfill-canonical-image

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Row 4 of chat#1911: when resolveOrCreateArtist reuses a canonical artist that has no image, the roster card renders a grey placeholder. Seeding self-heals it ~30s later for new signups (verified live on Grace Ives in the chat#1889 arc), but accounts that already have a catalog never fire seeding — for them the blank is permanent. This backfills the blank at add-time.

Stacked on api#796 — it reuses enrichArtistSpotifyProfile from that PR, so this branch contains #796's commit until it merges. Merge order: api#796 → this.

What it does

In the canonical-reuse path of resolveOrCreateArtist: after linking, if account_info[0].image is blank, call enrichArtistSpotifyProfile (real Spotify avatar + handle + followers) and re-fetch the canonical so the add response itself carries the image — no interim grey window. A canonical with an image is left untouched (filling a blank is not the chat#1866 shared-write problem; overwriting would be). Best-effort: a Spotify outage returns the un-enriched canonical instead of failing the add.

Tests (TDD, red→green)

3 new cases in resolveOrCreateArtist.test.ts (enriches + re-fetches on blank; never touches a canonical with an image; returns the original when the backfill throws). Driving case confirmed RED first. Artists domain: 123 tests green; tsc --noEmit at the 236 pre-existing baseline; eslint clean.

Tracked in chat#1911 row 4.

🤖 Generated with Claude Code


Summary by cubic

Fixes grey placeholders when reusing a canonical artist by backfilling the Spotify avatar at add-time. Also enriches the create-time Spotify attach so verify-socials shows the real handle, followers, and avatar immediately (chat#1911 row 4; chat#1889 row 16).

  • Bug Fixes
    • In resolveOrCreateArtist, when reusing a canonical with no image, call enrichArtistSpotifyProfile and re-fetch the artist; skip if an image exists; never fail the add if Spotify is down.
    • After attaching Spotify on create, call enrichArtistSpotifyProfile to replace the path-based username with real profile data.
    • Added enrichArtistSpotifyProfile helper that fetches the Spotify artist and delegates to enrichSearchedArtistProfile; best-effort and non-throwing.

Written for commit 8d8949f. Summary will update on new commits.

Review in cubic

sweetmantech and others added 2 commits July 29, 2026 15:25
resolveOrCreateArtist's create path saved the URL path segment as the
username, so verify-socials rendered 'Spotify @artist · 0 followers'.
Fetch the real Spotify profile after the attach and reuse
enrichSearchedArtistProfile to write the real handle, follower count
and avatar. chat#1889 row 16.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A reused canonical with no image rendered a grey roster card - forever
for accounts that already have a catalog (no seeding fires), ~30s for
new signups. Enrich from the real Spotify profile at add-time, only
when the image is blank. chat#1911 row 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api Ready Ready Preview Jul 29, 2026 11:07pm

Request Review

@cursor

cursor Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@sweetmantech, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 10403352-2686-4680-8180-6db0bd59ee47

📥 Commits

Reviewing files that changed from the base of the PR and between 3bb0ca2 and 8d8949f.

⛔ Files ignored due to path filters (2)
  • lib/artists/__tests__/enrichArtistSpotifyProfile.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/artists/__tests__/resolveOrCreateArtist.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (2)
  • lib/artists/enrichArtistSpotifyProfile.ts
  • lib/artists/resolveOrCreateArtist.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant Caller as resolveOrCreateArtist Caller
    participant ROCA as resolveOrCreateArtist()
    participant DB as Database
    participant EASP as enrichArtistSpotifyProfile()
    participant Spotify as Spotify API

    Note over Caller,Spotify: Canonical Reuse Path

    Caller->>ROCA: name, accountId, spotifyArtistId
    ROCA->>DB: findCanonicalArtistBySpotifyId(spotifyArtistId)
    DB-->>ROCA: canonicalId (e.g. "canonical-1")
    ROCA->>DB: selectAccountArtistId(accountId, canonicalId)
    alt Not already rostered
        ROCA->>DB: insertAccountArtistId(accountId, canonicalId)
    end
    ROCA->>DB: selectAccountWithSocials(canonicalId)
    DB-->>ROCA: artist with account_info

    alt account_info[0].image is null/blank
        Note over ROCA,Spotify: NEW: Backfill blank canonical image
        ROCA->>EASP: enrichArtistSpotifyProfile(artistId, spotifyArtistId)
        EASP->>Spotify: generateAccessToken()
        Spotify-->>EASP: access_token
        alt Token minted
            EASP->>Spotify: getArtist(spotifyArtistId, token)
            Spotify-->>EASP: spotifyArtist (name, followers, images)
            alt Artist data returned
                EASP->>DB: enrichSearchedArtistProfile(artistId, spotifyArtistId, spotifyArtist)
                DB-->>EASP: Done
            else No artist data
                Note over EASP: Best-effort: skip
            end
        else Token minting failed
            Note over EASP: Best-effort: skip
        end
        EASP-->>ROCA: void (best-effort, never throws)
        ROCA->>DB: CHANGED: selectAccountWithSocials(canonicalId) (re-fetch)
        DB-->>ROCA: healed artist (now with image)
    else image exists or account_info empty
        Note over ROCA: No enrichment (avoid shared-write)
    end
    ROCA-->>Caller: { artist: healedOrOriginal, created: false }

    Note over Caller,Spotify: Create Path

    Caller->>ROCA: name, accountId, spotifyArtistId
    ROCA->>DB: createArtistInDb(...)
    DB-->>ROCA: created artist (new id)
    ROCA->>DB: insertAccountArtistId(accountId, newId)
    ROCA->>DB: updateArtistSocials({ SPOTIFY: url })
    DB-->>ROCA: social attached (path-based username)
    ROCA->>EASP: NEW: enrichArtistSpotifyProfile(artistId, spotifyArtistId)
    Note over EASP: Same flow as above — fetches real Spotify profile
    EASP-->>ROCA: void
    ROCA->>DB: selectAccountWithSocials(newId)
    DB-->>ROCA: artist with enriched social
    ROCA-->>Caller: { artist, created: true }
Loading

Auto-approved: Backfills blank canonical image and enriches create-time profile with real Spotify data, both best-effort and bounded. Tests confirm no overwrite of existing images and safe failure on Spotify outage.

Re-trigger cubic

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