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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions