docs(research): reconcile playcount contract with live api behavior

Merged
SW
4mo ago
+119-14

What

The reconcile step for the playcount family — every divergence found while live-verifying recoupable/api#657 and recoupable/api#660 (results tables on those PRs), fixed on the docs side. The live response is ground truth.

track-stats

  • Description now states the sourcing model: Spotify served Apify-first from the measurement store (TTL-refreshed platform-displayed counts), Songstats for other sources, upstream status passthrough (e.g. 429 on quota exhaustion — observed live).
  • captured_at scoped: present only on store-served entries.
  • Store-served entries' data carries only streams_total (platform-displayed count caveat referenced).
  • Minimal { result, stats } envelope documented for fully-store-served responses.

track-historic-stats

  • Store-only Spotify history (snapshot + backfilled points, per-point data_source), the partial-response + backfill-enqueue behavior, and the minimal envelope.

playcounts (the real catch)

  • Nullability was inverted: docs had isrc nullable and spotify_track_id required; the implementation never emits a null isrc (mapped tracks only) but can emit a null spotify_track_id. Swapped.
  • album.label/album.copyright honestly marked always null until snapshots persist album metadata; album.name sourced from the song record, not the platform page.
  • Mapped-tracks-only coverage stated.

All four playcount-family endpoints

  • 402 documented with the real body (insufficient_credits, remaining_credits, required_credits, checkoutUrl — shape read from buildInsufficientCreditsResponse), via a new ResearchInsufficientCreditsResponse schema.

Verification

Additive-leaning diff (84+/13−, the deletions are replaced descriptions); mint validation passes. track-playcount-deltas needed no changes — it matched the contract exactly.

Closes the docs-reconciliation follow-up noted on recoupable/chat#1791.

🤖 Generated with Claude Code


Summary by cubic

Reconciled research playcount docs with live API behavior. Tightened field contracts, moved sourcing details into response schemas, and added explicit 402 across endpoints plus 429 passthrough on stats endpoints.

  • Bug Fixes

    • playcounts: isrc required; spotify_track_id nullable. Album name/label/copyright clarified; mapped-tracks only.
    • Sourcing/envelopes: captured_at only for store-served; store-served data only streams_total; minimal { result, stats } when fully store-served; Spotify history from store with per-point data_source and enqueue backfill.
    • Declared 429 passthrough (ResearchErrorResponse) on track-stats and track-historic-stats.
    • OpenAPI 3.1 nullability: use type: [string, null] for spotify_track_id and album fields.
  • New Features

    • Added 402 Insufficient Credits to all playcount endpoints with ResearchInsufficientCreditsResponse; error, remaining_credits, required_credits, checkoutUrl required; declineReason optional.

Summary by CodeRabbit

  • Documentation
    • Updated API documentation for track stats and playcount endpoints to document insufficient research credits responses and checkout URLs for purchasing additional credits.
    • Improved field descriptions to clarify data availability based on data source and enhanced endpoint behavior documentation including provider routing and refresh mechanics.