Skip to content

Every rostered account sees a catalog valuation: auto-fill pre-funnel catalogs + land the homepage-honesty fleet (successor to #1859) #1863

Description

@sweetmantech

Successor to chat#1859 (closed — the P1 canonical-artist funnel fix shipped + verified: a brand-new customer now completes a valuation and sees their number on chat.recoupable.dev, witnessed live). That issue made the funnel work for new customers. This one extends the same catalog-valuation experience to existing customers — and lands the homepage-honesty fleet that was in flight when #1859 closed. (Business context, once: new-signup coverage is done; the retention win now is the installed base seeing value on day one of the feature.)

Goal

Every rostered account — not just funnel-claimed ones — opens chat.recoupable.dev and sees an honest catalog valuation for their artists, and the homepage modules read truthfully for everyone:

  1. Coverage: an account that has artists in its roster but never ran the funnel gets a catalog materialized from its roster → songs graph, so the artist-scoped hero (GET /api/catalogs/{catalogId}/measurements?artist_account_id=…) returns a value. Today 588 of 608 rostered accounts (~97%) see nothing, all because no catalog was ever created (analysis).
  2. Homepage honesty (all customers): task runs carry real titles, the starter card offers the valuation report, in-progress valuations are labeled partial, and the $0/0-stream release tail is collapsed.
  3. Handoff polish: intent resume after OTP is reliable; the marketing header reflects auth state (+ logout).
  4. Integrity: the two valuation-formula implementations cannot silently drift.

Done at the macro level when: the coverage query (in the analysis) returns ~0 accounts-with-roster-but-no-valuation, and a returning existing customer opens the homepage and sees an honest valuation for a roster artist — witnessed live on prod.

PRs (updated 2026-07-08 — ship-priority order, top to bottom; 10 open, migrated from #1859; 1 new item)

PR Item Base State
tbd — design note → api + chat ⭐ HIGH: auto-fill catalogs for all rostered accounts — materialize a catalog from each account's roster→songs graph so the hero shows a valuation for every account main ⬜ not started — the single biggest coverage lever (588/608, analysis); needs the decision note first (trigger, cost control at scale, refresh cadence, ownership)
docs#268 Run titles: TaskRunResponse gains nullable title (contract) main 🔄 open — merge first of the titles trio
api#764 Run titles: reverse filter[schedule] lookup against scheduled_actions main 🔄 open — 3,950 tests; fails open both layers; authed pass pending
chat#1857 Run titles: HomeRunRow renders the real title, getTaskDisplayName fallback main 🔄 open — 131 tests; safe either side of the api#764 deploy
chat#1856 Starter card: prefer the "Weekly valuation + streams report" /agents template main 🔄 open — 127 tests; MERGEABLE; gap re-confirmed live 2026-07-08
marketing#42 Valuation card: collapse the $0/0-stream release tail main 🔄 open — TDD'd, build green; 22 $0 rows above the CTA (07-08)
marketing#45 Intent resume: persist pending intent to sessionStorage at the auth gate; 15-min staleness guard main 🔄 open — TDD 80/80; failure is remount-dependent/intermittent (07-08 walkthroughs auto-resumed)
api#765 + marketing#44 Drift guard: byte-identical golden valuation fixture + lockstep tests in both repos main 🔄 both open — zero divergence re-confirmed live 2026-07-08 (card $2.1M ↔ api mid $2,058,990); land as a same-day pair
marketing#43 Marketing header auth state: signed-in indicator + Open app + logout main 🔄 open — build green; also the manual escape hatch for the stale-session dead end (see Open)
mono#45 Root AGENTS.md: retire stale test-branch PR guidance + internal issue-workflow skills section main 🔄 open — docs-only; ⚠ CONFLICTING with main, needs a rebase
tbd — marketing Label in-progress valuations as partial on the card main ⬜ not started (completed runs reconcile — only partial-as-final display remains)

Merge sequencing: the ⭐ auto-fill is the headline but design-gated — write the decision note first, then it splits into api (catalog-materialization trigger/job) + chat (surface) PRs. The homepage-honesty fleet is independent and ready to land now: titles trio docs#268 → api#764 → chat#1857 (contract-first; chat safe either side), then chat#1856 / marketing#42 / marketing#45 / marketing#43 in any order; drift-guard api#765 + marketing#44 land as a same-day pair; mono#45 needs a rebase before it can merge.

Open — coverage (the headline: existing customers)

  • ⭐ HIGH — Auto-fill the account catalog for pre-funnel accounts (roster → songs graph), so the hero lights up for every account. (raised by sweetman 2026-07-06; prototype worked — 15 artists / 880 releases via measurement-jobs + catalogs/songs)
    • Why: 588 of 608 rostered accounts (~97%) see no valuation on any artist — every one because a catalog was never materialized (no "has catalog but hero dark" cohort; all 20 catalog-owners resolve correctly post-P1). Coverage analysis 2026-07-08. Distinct from New-customer funnel delivers the Catalog HQ promise: land the canonical-artist P1 quartet + in-flight fleet, close the remaining funnel gaps #1859's P1 (that was funnel accounts whose catalog pointed at a duplicate artist; this is the ~97% who never had a catalog at all).
    • Fix (needs a decision note first): decide trigger (on artist-add? on first chat? a one-time backfill sweep?), cost control at 588-account scale (measurement-job spend across every roster), catalog shape, refresh cadence, ownership semantics — then implement the materialization (api) + surface (chat).
    • Done when: the coverage query returns ~0 accounts-with-roster-but-no-valuation; a returning existing customer sees a valuation for a roster artist, live on prod.

Open — homepage honesty (all customers; the in-flight fleet)

  • Real run titles on the homepage. (→ docs#268 · api#764 · chat#1857)
    • Why: run rows all read "Scheduled Task" (verified live 2026-07-07). Not observable on a day-one account (no runs yet) — bites on the return visit, so it matters most for existing customers. Perf note: one Trigger.dev call per schedule per list load — cache/TTL if schedule counts grow.
    • Done when: signed-in homepage lists runs by task title (fallback intact); verified live post-deploy.
  • Valuation starter card + partial labeling + $0-tail collapse. (→ chat#1856 · marketing#42 · partial-labeling _tbd_)
    • Why: starter card offered a generic dashboard, not the valuation report (re-confirmed on a fresh account 2026-07-08); the card can present a partial measurement as final (07-06: $1.4M partial vs $2.1M complete); 22 $0 · 0 streams rows sat above the CTA (07-08).
    • Done when: starter card offers "Weekly valuation + streams report"; in-progress valuations visibly labeled partial; no $0 rows render.

Open — handoff polish + integrity

  • Intent resume: "Value my catalog" auto-runs after the OTP — every time. (→ marketing#45) The pendingRun ref dies on the remount fresh-signup can cause; both 07-08 walkthroughs auto-resumed, so the failure is intermittent — ship I add new tool #45 as hardening. Done when: search → Value → OTP → runs with no further clicks, on a fresh account.
  • Marketing header auth state (+ logout). (→ marketing#43) Header shows Sign In/Sign Up while a live token sits in localStorage; the missing logout is half of the stale-session dead end below.
  • Drift guard: valuation-formula lockstep. (→ api#765 · marketing#44) Formula implemented twice; zero divergence confirmed live 2026-07-08 but unguarded. Hardening nit: assert the fixture SHA in each test so a lone-repo edit fails loudly. Done when: both suites green against the identical fixture; a single-repo formula change fails that repo's CI.
  • Root AGENTS.md cleanup. (→ mono#45) Docs-only; needs a rebase (currently conflicting).

Open — UX dead ends (found 2026-07-08, no PR yet)

  • Stale-Privy-session dead end — "User already has one email account linked." On a device holding a leftover Privy session (the httpOnly cookie at privy.recoupable.dev survives localStorage/cookie clears, and marketing has no logout), a new email + valid OTP fails with a cryptic error and no recovery path (reproduced 2026-07-08). Fix: handle the link-conflict error — log out the stale session and retry as a fresh login; land marketing#43's logout as the manual escape hatch. Done when: on a device holding account A's session, account B's email + valid OTP signs into B (or a one-click recovery is offered), verified live.
  • Circular homepage CTA — catalog-owning accounts are offered "Get a free catalog valuation →" back to marketing. (witnessed 2026-07-08). The P1 hero should replace it once it lights up, but the fallback must never offer the funnel to an account that already owns a catalog. Done when: an account owning ≥1 catalog never sees the marketing valuation CTA on the homepage.

Open — carried funnel/platform items (from #1859, unblocked, pick from the top)

  • Verify-and-close: the 1,000-row aggregate cap. Believed fixed by api#763 (merged 2026-07-07). One authed check: GET /api/catalogs/7d3e5c35…/measurements?limit=1 reports measured_song_count 2,679 and a band consistent with 16.31B streams → then close.
  • api: the artistName filter on GET /api/catalogs/songs no-ops on unlinked songs. Latent since api#681 (LEFT-join); returns every row for a non-member artist. No longer load-bearing for the hero — still a correctness bug for other consumers. RED test first: filtered query on a catalog with unlinked songs returns 0.
  • Data bug: lowercased Spotify artist ids in socials.profile_url (10 of 15 roster artists) — album resolution 502s. api#768's ingest is case-preserved (forward path); remaining: find the normalize-on-write culprit + backfill existing rows (lower(id) match makes it mechanical).
  • Ops: chat previews' Privy test app is at its user cap. Blocks fresh-account testing on previews. Workaround: fresh-account passes run on prod with plus-aliases. Fix: raise the cap in the Privy dashboard; decide the preview api-base story (previews call test-recoup-api.vercel.app).
  • Ops nit: flip the recoupable.com redirect from 307 to 301/308 (Vercel domain settings) so six years of .com link equity transfers.

Architecture decisions (carried from #1859)

  • Homepage = valuation-first dashboard ("Catalog HQ"); chat = command bar. (sweetman, 2026-07-06)
  • Valuation band derived at read time, server-side; one formula. Two implementations temporarily guarded by the byte-identical golden fixture; a shared package is the endgame.
  • Artist scoping happens inside the measurements endpoint (artist_account_id filter via catalog_songs ∩ song_artists); per-artist catalogs rejected. REST shape: path for identity, query for modifiers.
  • Claim-time canonical attach is the roster source of truth for funnel signups (shipped in New-customer funnel delivers the Catalog HQ promise: land the canonical-artist P1 quartet + in-flight fleet, close the remaining funnel gaps #1859) — find/reuse the canonical artist via the songs graph, never mint per-signup duplicates.
  • All homepage data flows through api.recoupable.dev endpoints — no direct Supabase reads from chat.

Source references

  • Parent (closed): chat#1859 — the P1 canonical-artist funnel fix (new customers). Key threads: coverage analysis · P1 live witness · backfill closeout · 07-08 fresh-account walkthrough + escalation. Grandparent: chat#1850 (Catalog HQ build + launch).
  • Separate security tracker: chat#1860 — connector authority hardening (independent of this coverage work).
  • Code anchors: chat/lib/home/*, marketing/hooks/useCatalogValuation.ts, api/lib/catalog/attachCanonicalArtistToAccount.ts, endpoint GET /api/catalogs/{catalogId}/measurements, measurement-jobs + catalogs/songs (the auto-fill prototype path).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions