Skip to content

feat: homepage valuation hero (Catalog HQ 1/3, chat#1850)#1852

Open
sweetmantech wants to merge 3 commits into
mainfrom
feat/home-valuation-hero
Open

feat: homepage valuation hero (Catalog HQ 1/3, chat#1850)#1852
sweetmantech wants to merge 3 commits into
mainfrom
feat/home-valuation-hero

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

What this does

First PR of the Catalog HQ homepage stack (#1850, "Open — chat homepage: Catalog HQ").

For accounts with at least one catalog, the homepage now renders a valuation hero above the chat area: artist name + avatar, the estimated catalog value (display treatment on the mid figure), the low-to-high range, and the measured-track count — the same number the marketing valuation card showed the lead.

  • Data path: existing GET /api/accounts/{accountId}/catalogs (what the Catalogs page uses) → new GET /api/catalogs/measurements?catalogId= (per-ISRC latest measurements + valuation: { low, mid, high }; contract per Valuation-first homepage (Catalog HQ): surface catalog value + task runs on chat home; fix the .dev cross-domain auth regression #1850, implemented in a parallel api PR).
  • Graceful degradation is the core contract: the measurements endpoint is not on prod yet. Endpoint 404/error, error envelope, catalogs failure, or zero catalogs → the homepage renders exactly the current greeting ("Ask me about {artist}") with zero regression. retry: false on the measurements query so a 404 falls back immediately.
  • Composed hooks per the chat hooks conventions: useHomeValuation composes useCatalogs + new useCatalogMeasurements + ArtistProvider; no transport changes. The hero-visibility decision is a pure function (getValuationHeroState) with full unit coverage.
  • hideGreeting is an optional, default-false prop threaded HomePage → NewChatBootstrap → Chat, so every other Chat mount is untouched.
  • Design per DESIGN.md: shadow-as-border card, achromatic chrome, tabular numerals with tight tracking on the dollar figure. Note: the chat app does not currently load Geist Pixel Square (only Plus Jakarta Sans/Geist are wired in app/globals.css), so the figure uses the app's existing heading font at display scale rather than adding a new font in this PR.

Tests (TDD — confirmed RED before implementing)

14 new unit tests, full suite 97 passed (28 files):

  • lib/home/__tests__/getValuationHeroState.test.ts — hero hidden while loading / no catalogs / catalogs failed / measurements failed / no valuation band; shown with band + measured-track count when data is complete (the Done-when).
  • lib/catalog/__tests__/getCatalogMeasurements.test.ts — GET URL + bearer auth, 404 throws, error envelope throws.
  • lib/catalog/__tests__/formatValuationAmount.test.ts$1.4M / $959K / $2M compact formatting.

pnpm exec tsc --noEmit: no new errors (the two pre-existing failures in lib/emails/__tests__/extractSendEmailResults.test.ts and components/VercelChat/tools/SpotifyDeepResearchResult.tsx are on main and untouched). eslint clean on all changed files (next lint itself is broken repo-wide under Next 16).

Screenshots

N/A — the measurements endpoint is not live on prod/preview yet, so the hero cannot render there; the verifiable behavior on preview is the fallback (unchanged greeting), which I verified (see PR comment).

Stack

Part of a 3-PR stack for chat#1850 (merge in order, each PR only after its base):

  1. this PR feat/home-valuation-hero → base main
  2. feat/home-tasks-module → base feat/home-valuation-hero
  3. feat/home-command-bar → base feat/home-tasks-module

After this merges, PR 2 gets re-targeted to main. Note: the tracking issue's PR table says base test, but the repo retired test as a PR target (#1843) — the stack bases on main per current CLAUDE.md.

Closes nothing on its own — tracked in #1850.

🤖 Generated with Claude Code


Summary by cubic

Adds a valuation hero to the homepage for catalog accounts, showing the estimated value, range, and measured tracks; it hides the default greeting when visible. Artist-scoped and now verified client-side to avoid mislabeling, meeting #1850.

  • New Features

    • Render ValuationHero above chat when valuation data exists; otherwise keep the greeting. Shows the catalog label when no artist is selected; shows the artist label only when matched.
    • New useHomeValuation hook composing useCatalogs, useCatalogMeasurements, useCatalogSongs with helpers findArtistCatalog, getValuationHeroState, and isArtistCatalogMatch.
    • Data pipeline: getCatalogMeasurements (GET /api/catalogs/measurements) and formatValuationAmount for compact USD; 404/error/missing data hides the hero (retry: false).
  • Bug Fixes

    • Prevent mismatched artist labels by verifying the artist–catalog pairing client-side with isArtistCatalogMatch (catalog name match or artist in song artists; null/unlinked songs match nobody), and hide the hero while resolving or on no match.

Written for commit 7355a77. Summary will update on new commits.

Review in cubic

For accounts with >=1 catalog, the homepage renders the estimated catalog
value (artist, mid figure with display treatment, low-to-high range,
measured-track count) above the chat area, fed by the new
GET /api/catalogs/measurements endpoint via composed hooks
(useCatalogs -> useCatalogMeasurements -> useHomeValuation).

The endpoint is still rolling out: any failure (404, error envelope, no
catalogs) hides the hero and keeps the existing greeting untouched.

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

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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.

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview Jul 6, 2026 10:15pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next review available in: 6 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

Run ID: bf4b8aae-a844-480a-abe0-97b58a4c6564

📥 Commits

Reviewing files that changed from the base of the PR and between a58a467 and 7355a77.

⛔ Files ignored due to path filters (5)
  • lib/catalog/__tests__/formatValuationAmount.test.ts is excluded by !**/*.test.* and included by lib/**
  • lib/catalog/__tests__/getCatalogMeasurements.test.ts is excluded by !**/*.test.* and included by lib/**
  • lib/home/__tests__/findArtistCatalog.test.ts is excluded by !**/*.test.* and included by lib/**
  • lib/home/__tests__/getValuationHeroState.test.ts is excluded by !**/*.test.* and included by lib/**
  • lib/home/__tests__/isArtistCatalogMatch.test.ts is excluded by !**/*.test.* and included by lib/**
📒 Files selected for processing (11)
  • components/Home/HomePage.tsx
  • components/Home/ValuationHero.tsx
  • components/VercelChat/NewChatBootstrap.tsx
  • components/VercelChat/chat.tsx
  • hooks/useCatalogMeasurements.ts
  • hooks/useHomeValuation.ts
  • lib/catalog/formatValuationAmount.ts
  • lib/catalog/getCatalogMeasurements.ts
  • lib/home/findArtistCatalog.ts
  • lib/home/getValuationHeroState.ts
  • lib/home/isArtistCatalogMatch.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/home-valuation-hero

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 528523bada

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread hooks/useHomeValuation.ts Outdated
const { data: catalogsData, isError: catalogsFailed } = useCatalogs();
const catalogs = catalogsData?.catalogs;
const { data: measurements, isError: measurementsFailed } =
useCatalogMeasurements(catalogs?.[0]?.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Tie the valuation to the displayed artist

When an account has multiple catalogs and the user has selected an artist that is not represented by catalogs[0], this fetches measurements for the first catalog but the returned hero is labeled with selectedArtist?.name and selectedArtist?.image. That makes the homepage show one catalog's valuation under another artist's name/avatar; choose the catalog that matches the selected artist or label the card with the catalog whose measurements were fetched.

Useful? React with 👍 / 👎.

@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.

2 issues found across 12 files

Confidence score: 3/5

  • In hooks/useHomeValuation.ts, valuation data appears to be fetched from a source that can drift from the current selectedArtist, so the hero may show the wrong artist identity for the catalog being valued; merging as-is risks user-facing trust issues and incorrect context in valuation flows — align the fetch key/source with the active artist/catalog before merging and verify with a multi-artist account case.
  • In lib/catalog/getCatalogMeasurements.ts, missing try/catch logging breaks the API error-reporting consistency used elsewhere, which can make production failures harder to diagnose even if behavior otherwise matches; add the same console.error + re-throw pattern before merging to preserve observability.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/catalog/getCatalogMeasurements.ts">

<violation number="1" location="lib/catalog/getCatalogMeasurements.ts:29">
P2: Add a try/catch wrapper with console.error logging before re-throwing, matching the established error-logging pattern used by every other catalog API fetcher (getCatalogs, getCatalogSongs, getSongsByIsrc, postCatalogSongs). Without it, HTTP and network errors from this endpoint will be thrown without the diagnostic console.error that the rest of the codebase emits, making production debugging harder.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

* The endpoint is being rolled out; callers must treat any thrown error as
* "no valuation available" and fall back gracefully.
*/
export async function getCatalogMeasurements(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Add a try/catch wrapper with console.error logging before re-throwing, matching the established error-logging pattern used by every other catalog API fetcher (getCatalogs, getCatalogSongs, getSongsByIsrc, postCatalogSongs). Without it, HTTP and network errors from this endpoint will be thrown without the diagnostic console.error that the rest of the codebase emits, making production debugging harder.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/catalog/getCatalogMeasurements.ts, line 29:

<comment>Add a try/catch wrapper with console.error logging before re-throwing, matching the established error-logging pattern used by every other catalog API fetcher (getCatalogs, getCatalogSongs, getSongsByIsrc, postCatalogSongs). Without it, HTTP and network errors from this endpoint will be thrown without the diagnostic console.error that the rest of the codebase emits, making production debugging harder.</comment>

<file context>
@@ -0,0 +1,55 @@
+ * The endpoint is being rolled out; callers must treat any thrown error as
+ * "no valuation available" and fall back gracefully.
+ */
+export async function getCatalogMeasurements(
+  catalogId: string,
+  accessToken: string,
</file context>

Comment thread hooks/useHomeValuation.ts Outdated
@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Preview verification (sha 528523b, https://chat-git-feat-home-valuation-hero-recoup.vercel.app/):

  • Vercel preview build: SUCCESS.
  • Loaded the preview homepage in a fresh browser session (signed out). It renders exactly the current experience: 'Ask me about your roster' greeting, chat input, Privy login modal — no hero, no layout shift, zero console errors. This is the graceful-fallback path working as designed.
  • As expected, the hero itself cannot render on this preview: GET /api/catalogs/measurements is not live on prod (it ships in a parallel api PR), and the hero requires it. The hidden-hero fallback is exactly what this deployment should show.
  • Not verified on preview: the authenticated hero-visible state (needs the api endpoint live + an authenticated session; Privy OTP retrieval wasn't available to me in this run). That state is covered by the unit tests on getValuationHeroState and should be re-checked visually once the api PR deploys.

@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Live preview verification — 2026-07-06 (authenticated pass)

Setup: api test branch synced with main (b059655d) so test-recoup-api.vercel.app serves the new measurements endpoint (live 21:15:48Z); signed into this PR's preview (chat-ghki7iqd0-recoup.vercel.app) via Privy OTP as an account owning a measured catalog.

Done-when criterion Result
Account with catalog + endpoint data → hero shows the dollar figure without touching chat ✅ Hero renders $150.3K · Range $103.2K to $211.4K · 5 tracks measured on load
Values come from the real endpoint GET test-recoup-api.vercel.app/api/catalogs/measurements?catalogId=7d3e5c35… → 200 (observed in the network log); rendered values match the API band to the displayed precision (mid $150,299 / low $103,227 / high $211,410)
No catalog or endpoint failure → unchanged greeting ✅ (verified signed-out earlier — greeting identical, 0 console errors)
Chat input unaffected below the hero ✅ input + model picker render normally under the hero

hero rendering live valuation

(screenshot hosted on the evidence/chat1852-verification branch; safe to delete after merge)

🐛 One real finding — artist/catalog pairing

The hero shows the selected artist (Ana Bárbara, this account's active workspace artist) next to the valuation of a Del Water Gap catalog. The artist label comes from the workspace context while the catalog is just the account's first/only catalog — the two aren't linked. Correct for the target funnel case (fresh valuation lead: one artist, one catalog) but wrong pairing on multi-artist accounts like this one.

Suggested fix (fine as a fast-follow, doesn't block the stack): derive the hero's label from the catalog (catalogs.name, e.g. "Del Water Gap Catalog") instead of the active artist — or match catalog→artist when resolvable and fall back to the catalog name.

Notes for the record

  • Preview auth constraint discovered: chat previews use the test-mode Privy app (cmc52us2g…), which has hit its user cap — brand-new emails get "Unable to sign in / test application has reached its user limit." Existing users sign in fine. Fresh-account preview testing is blocked until that app is upgraded (tracked on chat#1850).
  • The [TEST]-named catalog used here is the one seeded during api#757 verification; delete anytime.

🤖 Generated with Claude Code

…ngs in the catalog before pairing

The hero paired the workspace's selected artist with the account's first
catalog unconditionally, so switching artists kept showing another
catalog's value under the new artist's name (trust-killer on
multi-artist accounts, caught in live preview verification on
#1852).

Now: with no artist selected the hero shows the whole catalog's value
under the catalog name; with an artist selected it resolves the catalog
by name match (findArtistCatalog), verifies the pairing via the existing
GET /api/catalogs/songs artistName filter (total_count > 0, pageSize 1),
and hides while resolving, on zero match, or on check failure — falling
back to the greeting. Switching artists re-resolves.

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

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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.

@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Fix pushed: artist-scoped hero (537fb3f6)

Addresses the artist/catalog mismatch from the live verification above — sweetman confirmed the severity: switching artists kept showing another catalog's value under the new artist's name, an immediate trust-killer for multi-artist accounts.

New behavior:

  • No artist selected → hero shows the whole catalog's value under the catalog name (per sweetman's call, 2026-07-06).
  • Artist selected → the catalog is resolved by name match (findArtistCatalog, marketing's "{Artist} Catalog" convention, first-catalog fallback), then the pairing is verified with data: GET /api/catalogs/songs?catalogId&artistName&pageSize=1total_count > 0 (existing endpoint + filter, no new api surface). Hero renders only for a verified pair; hides while resolving, on zero match, or on check failure — falling back to the greeting. Switching artists re-resolves.
  • Measurements are now read from the matched catalog, not blindly catalogs[0].

Verification: TDD (RED→GREEN) — resolver + new findArtistCatalog at 15 tests; full suite on this branch 105/105; stack rebased (chat#1853c2d0e251, chat#185429ad23f4) and green at the top (122/122); tsc adds 0 errors (8 pre-existing on main). Live authed re-check on the new preview pending (Privy OTP required); the decisive manual case: account with Ana Bárbara selected + a Del Water Gap catalog → no hero (greeting), which was the failing scenario.

🤖 Generated with Claude Code

@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.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/catalog/getCatalogMeasurements.ts">

<violation number="1" location="lib/catalog/getCatalogMeasurements.ts:29">
P2: Add a try/catch wrapper with console.error logging before re-throwing, matching the established error-logging pattern used by every other catalog API fetcher (getCatalogs, getCatalogSongs, getSongsByIsrc, postCatalogSongs). Without it, HTTP and network errors from this endpoint will be thrown without the diagnostic console.error that the rest of the codebase emits, making production debugging harder.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread lib/home/getValuationHeroState.ts
…tistName filter no-ops on unlinked songs

Live preview verification caught the api-side hole: GET /api/catalogs/songs
with artistName=Ana+Bárbara returned all 6 songs (total_count 6,
artists:[null]) of a catalog she has no songs in — the filter rides the
artists join that api#681 relaxed to a LEFT-join, so unlinked songs pass
any artist filter. The hero therefore now fetches the catalog's songs
unfiltered and matches client-side (isArtistCatalogMatch): catalog named
for the artist, or the artist present in a song's artists array. Null- or
unlinked songs match nobody. api-side filter fix tracked on
#1850.

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

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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.

@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.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="hooks/useHomeValuation.ts">

<violation number="1" location="hooks/useHomeValuation.ts:47">
P1: The artist verification only checks the first page of songs (up to 50), so a legitimate artist match can be missed when the catalog has more than 50 songs and the artist's songs appear on later pages. When that happens, the valuation hero will silently fall back to the greeting even though the artist belongs to the catalog — a false negative that breaks the hero for larger catalogs.

The root cause is in the shift from API-side filtering (previous `pageSize: 1, artistName: selectedArtistName` → read `total_count`) to client-side matching (fetch 50 songs, check locally). The new approach intentionally avoids the API's `artistName` filter because it no-ops on unlinked songs, but it needs to check all songs — not just the first page — to be correct.

Suggestions (not all in scope for this PR):
- Fetch multiple pages until a match is found or songs are exhausted (use `hasNextPage`/`fetchNextPage` from the existing infinite query)
- Or, bump `pageSize` to a value that covers the full catalog (tradeoff: larger payload)
- Or, fetch all pages into a flat array before checking</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread hooks/useHomeValuation.ts
pageSize: 50,
enabled: !!catalog?.id && !!selectedArtistName,
});
const songsPage = catalogSongs?.pages?.[0]?.songs;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: The artist verification only checks the first page of songs (up to 50), so a legitimate artist match can be missed when the catalog has more than 50 songs and the artist's songs appear on later pages. When that happens, the valuation hero will silently fall back to the greeting even though the artist belongs to the catalog — a false negative that breaks the hero for larger catalogs.

The root cause is in the shift from API-side filtering (previous pageSize: 1, artistName: selectedArtistName → read total_count) to client-side matching (fetch 50 songs, check locally). The new approach intentionally avoids the API's artistName filter because it no-ops on unlinked songs, but it needs to check all songs — not just the first page — to be correct.

Suggestions (not all in scope for this PR):

  • Fetch multiple pages until a match is found or songs are exhausted (use hasNextPage/fetchNextPage from the existing infinite query)
  • Or, bump pageSize to a value that covers the full catalog (tradeoff: larger payload)
  • Or, fetch all pages into a flat array before checking
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At hooks/useHomeValuation.ts, line 47:

<comment>The artist verification only checks the first page of songs (up to 50), so a legitimate artist match can be missed when the catalog has more than 50 songs and the artist's songs appear on later pages. When that happens, the valuation hero will silently fall back to the greeting even though the artist belongs to the catalog — a false negative that breaks the hero for larger catalogs.

The root cause is in the shift from API-side filtering (previous `pageSize: 1, artistName: selectedArtistName` → read `total_count`) to client-side matching (fetch 50 songs, check locally). The new approach intentionally avoids the API's `artistName` filter because it no-ops on unlinked songs, but it needs to check all songs — not just the first page — to be correct.

Suggestions (not all in scope for this PR):
- Fetch multiple pages until a match is found or songs are exhausted (use `hasNextPage`/`fetchNextPage` from the existing infinite query)
- Or, bump `pageSize` to a value that covers the full catalog (tradeoff: larger payload)
- Or, fetch all pages into a flat array before checking</comment>

<file context>
@@ -36,21 +39,28 @@ const useHomeValuation = (): HomeValuationState => {
     enabled: !!catalog?.id && !!selectedArtistName,
   });
-  const artistSongCount = artistSongs?.pages?.[0]?.pagination.total_count;
+  const songsPage = catalogSongs?.pages?.[0]?.songs;
+  const artistMatched =
+    catalog && selectedArtistName && songsPage
</file context>

@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Live verification of the artist-scoping fix — 2026-07-06 (head 7355a775, branch-alias preview)

Signed into chat-git-feat-home-valuation-hero-recoup.vercel.app with the same multi-artist account that exposed the bug. The failing scenario now passes.

Check Before (528523ba) After (7355a775)
Ana Bárbara selected, account owns a Del Water Gap catalog ❌ Hero showed "Ana Bárbara — $150.3K" (another catalog's money) No hero — greeting "Ask me about Ana Bárbara"
Switch artist (→ Apache) ❌ Value stayed put under the new artist ✅ Re-resolves: greeting follows the artist, hero stays hidden
Network path catalogs/songs?…&artistName=… (filter no-ops, total_count: 6 for an artist with 0 songs) catalogs/songs?catalog_id=…&page=1&limit=50 (no filter param) + client-side match — null-linked songs match nobody
Console clean (one pre-existing form-field a11y notice, unrelated)

Ana Bárbara selected — greeting, no hero
Apache selected — greeting follows, no hero

Root cause of the first attempt's failure (for the record): the api's artistName filter on GET /api/catalogs/songs doesn't filter unlinked songs — artistName=Ana+Bárbara returned all 6 songs (artists:[null]) of a catalog she has no songs in. Latent since api#681 relaxed the artists join to a LEFT-join; my first commit (537fb3f6) trusted that filter. The shipped fix (7355a775) matches client-side against catalog name / the songs' artists arrays instead. api-side filter fix logged as an Open item on chat#1850.

Positive case caveat, stated honestly: this account's roster has no artist with songs in its catalog, so the hero-visible path wasn't re-exercised live after the rework — it's covered by the unit matrix (21 lib/home tests incl. object/string artist shapes and the name-convention match) and its rendering path (unchanged ValuationHero) was live-verified earlier today ($150.3K screenshot above). The real funnel case (claimed catalog named "{Artist} Catalog" + artist-linked songs via api#684) satisfies the matcher two ways.

Stack state: 18532874fedd, 1854efd97b87 (rebased on this fix), 128/128 at the top, tsc 0 new errors.

🤖 Generated with Claude Code

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