Promote test → main: measurements + measurement-jobs (chat#1796)#670
Conversation
The read half of the chat#1796 consolidation, against docs#242, TDD throughout.
- GET /api/research/tracks/{id}/measurements — a track's measured series from
the store (granularity=daily); aggregate=run_rate returns the trailing-window
annualized run-rate (a projection via computePlaycountDeltas). Provider-neutral
{id} (ISRC or Spotify track id, resolved to ISRC). Replaces track/historic-stats
+ track/playcount-deltas.
- GET /api/research/albums/{id}/measurements — latest count per track; a thin
remap over getAlbumPlaycounts. Replaces playcounts.
Heavy reuse of existing store reads (selectSongMeasurements, computePlaycountDeltas,
getAlbumPlaycounts); legacy endpoints keep serving (deprecated in docs#242 only).
24 new unit tests (resolver, both data fns, both validators, both handlers);
full lib/research suite green (268); tsc + lint clean on touched files.
…drain (chat#1796) (#668) * feat(research): measurement-jobs write resource + retryable backfill drain Implements the chat#1796 api consolidation (write side) against the docs contract (recoupable/docs#242), TDD throughout. measurement-jobs (the ingest resource that replaces snapshots + the never-built backfill verb, and unblocks the catalog-value-estimator seed in skills#43): - POST /api/research/measurement-jobs {scope, source} - source=current -> reuses the snapshot pipeline (maps snapshot_id -> id) - source=historical -> resolves scope to ISRCs, enqueues Songstats backfill ranked by latest count, skips songs already carrying songstats history - GET /api/research/measurement-jobs/{id} -> poll a current job (uncharged) retryable backfill drain (fixes the starvation root cause's robustness gap): - backfillTrackStep: 404 -> done (terminal no-data); 429/5xx/timeout -> failed (transient, reclaimable) instead of permanently stranding tracks - reclaimStaleBackfillRows: resets failed + orphaned in_progress rows to pending - playcount-maintenance cron reclaims before each drain (auto-recovers the 2 stranded rows) 29 new/updated unit tests; full research+workflows suite green (291); tsc clean on touched files; lint clean. * refactor(research): drop bespoke measurement-job status endpoint (docs#242 review) Per review on docs#242 (DRY): GET /research/measurement-jobs/{id} duplicated the generic GET /api/tasks/runs, and the old snapshot flow had no status endpoint. Remove the GET status route/handler/data fn + test. POST still returns the job id. * chore: prettier format playcountMaintenanceHandler test (fix CI format check) * refactor(research): address api#668 review — card-on-file gate, terminal/retryable backfill, KISS reclaim Review feedback on chat#1796 (sweetmantech + bots): - **Card on file (Songstats gate):** `historical` measurement-jobs now require a payment method (they spend the capped Songstats quota). New ensureSongstatsPaymentMethod: 402 + free-tier Stripe Checkout link when no card. `current` (Apify) is exempt. - **backfillTrackStep:** only 408/429/5xx are retryable (`failed`); 404 + other permanent 4xx are terminal (`done`) — prevents reclaim from recycling perma-fails. - **KISS:** moved the reclaim into updateSongstatsBackfillQueue.ts as reclaimStaleSongstatsBackfillRows; it now throws on DB error instead of masking it as 0; stronger test asserts the and() grouping. - **enqueueHistoricalBackfill:** bounded-concurrency batches (25) instead of N serial upserts. DRY/idempotency unchanged (already enforced: skip songstats-having songs + upsert dedup + drain skips done). 39 unit tests; research+workflows suite 313 green; tsc/lint/format clean. * refactor(backfillTrackStep): flatten status classification into named vars (KISS, api#668 review)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThree new REST endpoints are added: ChangesResearch Measurements & Measurement Jobs API
Sequence Diagram(s)sequenceDiagram
participant Client
participant Route as Next.js Route
participant Validator
participant Logic as Business Logic
participant DB as Supabase / Stripe
rect rgba(100, 149, 237, 0.5)
Note over Client,DB: POST /api/research/measurement-jobs (historical)
Client->>Route: POST with scope + source=historical
Route->>Validator: validateCreateMeasurementJobRequest
Validator->>DB: validateAuthContext
Validator->>DB: ensureSongstatsPaymentMethod → Stripe customer lookup
alt No payment method
DB-->>Validator: 402 + Stripe Checkout URL
Validator-->>Client: 402 checkoutUrl
end
Validator-->>Logic: ValidatedCreateMeasurementJobRequest
Logic->>DB: resolveScopeSongs → ISRC list
Logic->>DB: enqueueHistoricalBackfill → upsert songstats_backfill_queue
Logic-->>Client: 202 enqueued + skipped counts
end
rect rgba(144, 238, 144, 0.5)
Note over Client,DB: GET /api/research/tracks/{id}/measurements
Client->>Route: GET with id + ?aggregate=run_rate&window=90d
Route->>Validator: validateGetTrackMeasurementsRequest
Validator->>DB: auth + ensureResearchCredits
Validator-->>Logic: ValidatedGetTrackMeasurementsRequest
Logic->>DB: resolveTrackIsrc → ISRC
Logic->>DB: fetch song_measurements rows
Logic->>Logic: computePlaycountDeltas → annualized run_rate
Logic-->>Client: 200 data.aggregate
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Promote the two merged chat#1796 PRs from
testtomain(prod).Includes:
measurement-jobswrite resource (POST /research/measurement-jobs,source: current|historical) + card-on-file gate onhistorical+ retryable backfill drain / reclaim.measurementsread collection (GET /research/tracks|albums/{id}/measurements, series +aggregate=run_rate+latest).Both verified on preview (results in the respective PRs). Additive — legacy endpoints keep serving. After this lands, the catalog-value-estimator seed (skills#43) works against prod.
Summary by cubic
Promotes consolidated research measurement APIs to prod: adds
POST /api/research/measurement-jobsfor ingest andGET /api/research/tracks|albums/{id}/measurementsfor reads. Also adds a Songstats card-on-file gate and makes the historical backfill drain retryable with automatic reclaim in maintenance. Legacy endpoints remain available.New Features
POST /api/research/measurement-jobs—{ scope, source }:source: "current"uses the snapshot pipeline (mapssnapshot_id→id).source: "historical"enqueues Songstats backfill ranked by latest counts; skips songs already backfilled; bounded concurrency; returns 202.historicalrequires a payment method;currentdoes not.GET /api/research/tracks/{id}/measurements— daily series;?aggregate=run_rateover a trailing window.{id}can be ISRC or a Spotify track id (resolved to ISRC).GET /api/research/albums/{id}/measurements— latest count per track (thin remap of playcounts). CORS preflight added for new routes.Reliability
failed(reclaimable); 404 and other permanent 4xx are markeddone(terminal).failedand stalein_progressrows before draining and reports the reclaimed count.Written for commit 318ae4a. Summary will update on new commits.
Summary by CodeRabbit
New Features
Improvements