Skip to content

Test#686

Merged
sweetmantech merged 15 commits into
mainfrom
test
Jun 18, 2026
Merged

Test#686
sweetmantech merged 15 commits into
mainfrom
test

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary by cubic

Fixes catalog visibility for valuation-captured songs. We now carry Spotify artists through capture and run artist linking and notes queuing so these tracks render like manually added songs.

  • Bug Fixes
    • mapUnmappedAlbumTracks keeps track.artists as spotifyArtists during ISRC resolution and dedupe.
    • After upserts, calls linkSongsToArtists(songs) and queueRedisSongs(songs) to link artists and queue note generation.
    • Added a test that asserts captured songs are linked to their Spotify artists and queued for notes.

Written for commit 6fc10cc. Summary will update on new commits.

Review in cubic

sweetmantech and others added 15 commits June 16, 2026 11:40
…ckfill drain (#671)

Two chat#1796 refinements on the historical (Songstats) path:

1. Free-tier card-on-file link. The gate was issuing the paid subscription
   checkout ($99/mo after a 30-day trial). New createCardOnFileSession uses
   Stripe Checkout `mode: "setup"` — collects a card for $0, no subscription,
   no Stripe product. The account then pays only for metered usage via credits.

2. Instant drain. After enqueuing a historical job, fire-and-forget
   start(songstatsBackfillWorkflow) so the backfill begins immediately instead
   of waiting up to 24h for the cron. Safe by reuse: the workflow's budget gate
   (limit − reserve − rolling-30d ledger) caps it to the Songstats quota and
   SKIP LOCKED prevents double-claiming with the daily cron, which stays as the
   backstop. Only kicks when something was actually enqueued.

26 new/updated unit tests; research+stripe+workflows suite 453 green; tsc/lint/format clean.
…t#1797) (#673)

Pacing/backoff + per-step logging for the Songstats backfill drain (chat#1797 bullets 1 & 3). Bounded exponential backoff (fetchSongstatsWithBackoff, 502/503/504/408/429), defer-to-pending past the bound with claimed-batch release, per-step + per-batch logging.
…97) (#674)

Bullet 2 of chat#1797 (code half). Songstats is the rate authority — removes getBackfillBudgetStep, the budget gate, and insertSongstatsQuotaLedger/selectSongstatsQuotaSpent. The drain now claims+processes regardless of the ledger (un-stalls the backfill); the songstats_quota_ledger table is dropped in recoupable/database#35 (apply AFTER this deploys).
…t) (#677)

* feat: POST /api/catalogs create + materialize from valuation snapshot

Creates a catalog owned by the authenticated account (account derived
from credentials via validateAuthContext, never the body). With
from.snapshot_id, materializes the catalog from a completed valuation
snapshot: creates the catalogs row, links account_catalogs, adds the
snapshot's measured ISRCs as catalog_songs, and records the catalog on
the snapshot. Re-claiming the same snapshot is idempotent.

TDD: validateCreateCatalogBody (6 tests) + createCatalogHandler (8 tests),
red->green. New supabase wrappers: insertCatalog, selectCatalogById,
insertAccountCatalog, updateSnapshotCatalog.

Implements recoupable/chat#1801 Phase 2. Matches docs contract recoupable/docs#243.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: re-anchor POST /api/catalogs to merged contract + review fixes

- Flatten request to the merged docs#243 contract: from:{snapshot_id} -> a
  root snapshot field (validator + handler + tests). Error copy follows.
- DRY/SRP: drop the inline success() helper; use the shared successResponse().
- KISS rename: materializeSnapshotCatalog.ts -> createSnapshotCatalog.ts.
- DRY: delete the redundant updateSnapshotCatalog helper; reuse the existing
  updatePlaycountSnapshot(id, fields).

Validator change done red->green. lib/catalog: 24 tests pass; tsc + eslint clean.

Addresses review on PR #677.

* fix: materialize catalog songs from song_measurements, not snapshot.isrcs

Testing the full materialize path surfaced a real bug: a valuation snapshot
is album_ids-scoped, so its own isrcs column is null — createSnapshotCatalog
read snapshot.isrcs and would link an EMPTY catalog. The measured ISRCs live
in song_measurements (snapshot lineage), so source them there.

New selectSnapshotIsrcs(snapshotId) helper (distinct song_measurements.song
for the snapshot). createSnapshotCatalog now uses it.

TDD: new createSnapshotCatalog.test.ts (3 tests) red->green; lib/catalog 27 pass.

Addresses PR #677 verification.

* refactor: reuse selectSongMeasurements (snapshot filter) instead of a new helper

KISS/DRY per review: drop selectSnapshotIsrcs; add an optional snapshot
filter to the existing selectSongMeasurements, and derive distinct ISRCs
in createSnapshotCatalog. lib/catalog + song_measurements: 36 tests pass.

Addresses review on PR #677.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e hidden) (#681)

* fix: LEFT-join artists in catalog-songs read so materialized tracks surface

selectCatalogSongsWithArtists used song_artists!inner -> accounts!inner, so
valuation-captured tracks (which have songs + song_measurements but no
song_artists yet) were filtered out — a materialized catalog read back as 0
songs (verified live on api#677). Drop the two !inner so artist-less songs
return with artists: []; songs!inner stays (catalog_songs.song FK guarantees it).

Closes the read-path half of the song_artists follow-up in recoupable/chat#1801.
Longer-term (option a): the capture pipeline should also write song_artists.

* Update lib/supabase/catalog_songs/selectCatalogSongsWithArtists.ts
…(chat#1793) (#679)

* feat: add X (Twitter) + LinkedIn to the Composio connector whitelist (chat#1793)

Expand the existing whitelist pattern to two new platforms — no
architecture changes:
- SUPPORTED_TOOLKITS (getConnectors.ts) + ENABLED_TOOLKITS (getComposioTools.ts)
- CONNECTOR_DISPLAY_NAMES: twitter → "X (Twitter)", linkedin → "LinkedIn"
- buildAuthConfigs() reads COMPOSIO_TWITTER_AUTH_CONFIG_ID +
  COMPOSIO_LINKEDIN_AUTH_CONFIG_ID
- document both env vars in .env.example

TDD: new buildAuthConfigs unit + expanded getConnectors / handler /
ENABLED_TOOLKITS assertions, RED before GREEN. Full lib/composio suite
green (157 tests).

Implements the contract from docs#244.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: fix lint/format — relocate ENABLED_TOOLKITS test block, reformat toolkit array

- Move the ENABLED_TOOLKITS describe block below the imports (import/first)
- Prettier-format the expanded toolkits array in getConnectors.test.ts

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…680)

* feat: allow artists to connect X (Twitter); keep LinkedIn label-only (chat#1793)

Add `twitter` to ALLOWED_ARTIST_CONNECTORS — artist-facing social, same
class as tiktok/instagram/youtube. `linkedin` is intentionally left out
(label/owner-only).

TDD: isAllowedArtistConnector.test.ts asserts twitter allowed + linkedin
excluded, RED before GREEN. Full lib/composio suite green (157 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: allow artists to connect LinkedIn too (chat#1793)

Reversal of the earlier "LinkedIn label/owner-only" call: per owner
decision 2026-06-18, LinkedIn is now an artist-facing connector like
the others. Add `linkedin` to ALLOWED_ARTIST_CONNECTORS.

TDD: flipped the linkedin assertions (now allowed/included), RED before
GREEN. Full lib/composio suite green (159 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: remove unused ALLOWED_ARTIST_CONNECTORS from api (chat#1793)

The api copy of the artist connector allow-list had no runtime consumer —
only its definition, test, and an (also-unused) barrel re-export. The
connector routes are unopinionated (allow any connector for any account);
the allow-list that actually drives the artist Connectors tab lives in
`chat` (`lib/composio/allowedArtistConnectors.ts`). Removing the dead code.

Supersedes the earlier plan to add twitter/linkedin to this api constant
(decision: owner, 2026-06-18) — the artist allow-list is chat-only.

Deletes isAllowedArtistConnector.ts + its test, and the barrel re-export.
lib/composio suite green (149); no new tsc errors vs test (198 baseline).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in the catalog (#684)

* fix: enrich captured songs with artists + notes (root cause)

The valuation capture path created songs rows from the Spotify track
lookup but discarded track.artists and never ran the manual flow's
enrichment, so captured songs had no song_artists and no notes -> the
chat catalog view's isCompleteSong filter (artist + notes required, on by
default) hid every valuation track (count shown, list empty).

mapUnmappedAlbumTracks now carries track.artists through and runs the
same enrichment as processSongsInput: linkSongsToArtists (auto-creates
the artist account) + queueRedisSongs (queues note generation).

TDD: new test asserts artists are linked + queued; lib/research/playcounts
+ lib/songs 109 tests pass.

Root-cause follow-up on recoupable/chat#1801.

* style: prettier-format the capture-enrichment test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
api Building Building Preview Jun 18, 2026 11:53pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

More reviews will be available in 12 minutes and 52 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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

🚦 How do rate limits work?

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

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, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da0bb9df-3354-4505-9f77-9982e22190ff

📥 Commits

Reviewing files that changed from the base of the PR and between 34b2c84 and 6fc10cc.

⛔ Files ignored due to path filters (1)
  • lib/research/playcounts/__tests__/mapUnmappedAlbumTracks.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (1)
  • lib/research/playcounts/mapUnmappedAlbumTracks.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test

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 and usage tips.

@sweetmantech sweetmantech merged commit 7af8a12 into main Jun 18, 2026
5 of 6 checks passed

@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 2 files

Confidence score: 3/5

  • In lib/research/playcounts/mapUnmappedAlbumTracks.ts, failures in artist-link enrichment now abort the whole mapping path, so successful identifier upserts can be misclassified as bootstrap failures and retried unnecessarily; this can create noisy reprocessing and unstable playcount bootstrapping—make artist-link errors non-fatal (or isolate them) before merging.
  • lib/research/playcounts/mapUnmappedAlbumTracks.ts is over the project’s 100-line guideline, with mapping, artist linking, and Redis queuing concerns combined, which increases the chance of future regressions when touching this flow—split secondary responsibilities into helpers/modules to de-risk follow-up changes.
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/research/playcounts/mapUnmappedAlbumTracks.ts">

<violation number="1" location="lib/research/playcounts/mapUnmappedAlbumTracks.ts:98">
P1: Artist-link enrichment failure now aborts mapping output. This causes successful identifier upserts to be treated as failed bootstrap and retried unnecessarily.</violation>

<violation number="2" location="lib/research/playcounts/mapUnmappedAlbumTracks.ts:98">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

File exceeds the 100-line limit (107 lines). Split secondary concerns (artist linking and Redis queuing) into a separate module or helper to bring this file back under 100 lines and preserve single responsibility.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant AP as Apify Actor
    participant API as API Route
    participant MUAT as mapUnmappedAlbumTracks
    participant SPOT as Spotify API
    participant DB as Supabase DB
    participant SL as Song Service
    participant AL as Artist Link Service
    participant RQ as Redis Queue

    Note over AP,RQ: Catalog enrichment flow for valuation-captured tracks

    AP->>API: Trigger album playcount sync
    API->>MUAT: mapUnmappedAlbumTracks(albums, mappedTracks)

    MUAT->>SPOT: getTracks(trackIds)
    SPOT-->>MUAT: Track objects with artists

    MUAT->>MUAT: Extract spotifyArtists from track.artists

    Note over MUAT: Dedupe by ISRC, carry spotifyArtists through deduplication

    alt New tracks found
        MUAT->>DB: upsertSongs(songs without spotifyArtists)
        DB-->>MUAT: Songs upserted

        MUAT->>DB: upsertSongIdentifiers(track IDs, ISRCs)
        DB-->>MUAT: Identifiers upserted

        MUAT->>AL: linkSongsToArtists(songs with spotifyArtists)
        AL->>DB: Link songs to Spotify artists (auto-create artists)
        DB-->>AL: Artist links created
        AL-->>MUAT: Complete

        MUAT->>RQ: queueRedisSongs(songs)
        RQ-->>MUAT: Queued for note enrichment
    end

    MUAT-->>API: Map of trackId -> ISRC
    API-->>AP: Response
Loading

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

Re-trigger cubic

// manual/CSV flow — link artists (auto-creating the artist account) and
// queue note generation — so valuation tracks aren't "missing info" and
// render in the catalog view rather than being filtered out.
await linkSongsToArtists(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: Artist-link enrichment failure now aborts mapping output. This causes successful identifier upserts to be treated as failed bootstrap and retried unnecessarily.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/research/playcounts/mapUnmappedAlbumTracks.ts, line 98:

<comment>Artist-link enrichment failure now aborts mapping output. This causes successful identifier upserts to be treated as failed bootstrap and retried unnecessarily.</comment>

<file context>
@@ -72,6 +91,13 @@ export async function mapUnmappedAlbumTracks(
+    // manual/CSV flow — link artists (auto-creating the artist account) and
+    // queue note generation — so valuation tracks aren't "missing info" and
+    // render in the catalog view rather than being filtered out.
+    await linkSongsToArtists(songs);
+    await queueRedisSongs(songs);
+
</file context>
Suggested change
await linkSongsToArtists(songs);
await linkSongsToArtists(songs).catch(error => {
console.error("[playcounts] artist linking failed:", error);
});

@@ -4,6 +4,10 @@ import { upsertSongs } from "@/lib/supabase/songs/upsertSongs";
import { upsertSongIdentifiers } from "@/lib/supabase/song_identifiers/upsertSongIdentifiers";

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: Custom agent: Enforce Clear Code Style and Maintainability Practices

File exceeds the 100-line limit (107 lines). Split secondary concerns (artist linking and Redis queuing) into a separate module or helper to bring this file back under 100 lines and preserve single responsibility.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/research/playcounts/mapUnmappedAlbumTracks.ts, line 98:

<comment>File exceeds the 100-line limit (107 lines). Split secondary concerns (artist linking and Redis queuing) into a separate module or helper to bring this file back under 100 lines and preserve single responsibility.</comment>

<file context>
@@ -72,6 +91,13 @@ export async function mapUnmappedAlbumTracks(
+    // manual/CSV flow — link artists (auto-creating the artist account) and
+    // queue note generation — so valuation tracks aren't "missing info" and
+    // render in the catalog view rather than being filtered out.
+    await linkSongsToArtists(songs);
+    await queueRedisSongs(songs);
+
</file context>

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