docs: align 7 research response schemas with actual API behavior#140
Conversation
Surfaced while comparing the merged docs to a full re-test of the research endpoints on the recoupable/api#366 preview (see recoupable/api#366 (comment) through #issuecomment-4263097490). Each of the schemas below either advertised fields that never appear in responses or omitted fields that always do. All changes are spec-only — no api behavior change. /research/track response - Document `cm_statistics` (nested platform stats blob) - Document tempo / moods / activities (common nullable fields) /research/playlist response - Drop `curator_name` (never returned) → surface as `owner_name` - Drop `num_tracks` (never returned) → real field is `num_track` - Add playlist_id (platform-native), owner_id, user_id, image_url, editorial, personalized, catalog, code2, active_ratio, suspicion_score, fdiff_week/month, last_updated, sys_last_updated, genres/moods/activities + their smart-ordered counterparts, tags /research/charts response - `data` is an array, not an object (50 entries in practice) - Document `length` (total entry count) /research/profile response - Drop `hometown`, `sp_followers`, `sp_monthly_listeners`, `tags` — none are returned (longitudinal platform metrics live behind /research/metrics; use `hometown_city`/`current_city` for geography) - Add: band/band_members, gender fields, code2, isni, cover_url, hometown_city, current_city(_id), cm_artist_rank/cm_artist_score, cm_statistics, career_status, genreRank/subGenreRank1/2, genre_smart_ordered, moods, activities, booking_agent, press_contact, general_manager, topSongwriterCollaborators /research/metrics response - Replace documented `{data: [...]}` wrapper with flat per-platform time-series fields. For Spotify: `link`, `followers`, `listeners`, `popularity`, `followers_to_listeners_ratio` — each an array of `{timestp, value}` points. /research/audience response - Add the likers/engagement field family: audience_likers_genders (+per_age), audience_likers_ethnicities, audience_likers_interests, audience_likers_brand_affinities, likers_top_countries, likers_top_cities, notable_followers, followers, avg_likes_per_post, avg_commments_per_post (sic — upstream typo), engagement_rate, timestp - Add audience_ethnicities, audience_interests /research/curator response - Drop `followers` / `num_playlists` (neither returned) - Add per-platform follower fields: instagram_followers, facebook_followers/fans, twitter_followers/retweets, youtube_subscribers/views, soundcloud_followers, tiktok_followers/likes (all nullable) - Add user_id, submithub_id, last_updated, suspicion_score, tags, tag_ids, tag_names, spotifySocialUrls, cm_statistics /research/extract response - No change. Prior audit flagged errors as drift, but the field is already correctly optional (not in `required`) with a description noting conditional presence. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughUpdated OpenAPI schemas for six Research API responses to document expanded Chartmetric payloads, adding audience engagement metrics, platform follower counts, identity fields, curator/playlist metadata, time-series structures for metrics, and track analysis data across multiple schema definitions. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@api-reference/openapi/research.json`:
- Around line 4893-4912: Add explicit type declarations for the two permissive
schema entries: for band_members, change the schema to declare its type as
["array","null"] and ensure the array items are typed as objects (e.g., items: {
type: "object", additionalProperties: true }) while retaining nullable
semantics; for hometown_city, declare its type as ["object","null"] and add
additionalProperties: true to represent the Chartmetric hometown-city object.
Update the definitions that currently only have "nullable": true and
"description" so they include these explicit "type" and "additionalProperties"
(and "items" for band_members) entries.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c5399f2a-cf9b-4128-b42e-739a913deacf
📒 Files selected for processing (1)
api-reference/openapi/research.json
| "band_members": { | ||
| "nullable": true, | ||
| "description": "Band-member objects when known." | ||
| }, | ||
| "gender": { | ||
| "type": "string", | ||
| "nullable": true | ||
| }, | ||
| "gender_title": { | ||
| "type": "string", | ||
| "nullable": true | ||
| }, | ||
| "pronoun_title": { | ||
| "type": "string", | ||
| "nullable": true | ||
| }, | ||
| "hometown_city": { | ||
| "nullable": true, | ||
| "description": "Chartmetric hometown-city object (null when unknown)." | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, examine the actual file to confirm the current state
head -n 4920 api-reference/openapi/research.json | tail -n 50Repository: recoupable/docs
Length of output: 1463
🏁 Script executed:
# Search for test fixtures or example API responses containing band_members
rg "band_members" --type json -A 3 -B 3Repository: recoupable/docs
Length of output: 574
🏁 Script executed:
# Search for test fixtures or example API responses containing hometown_city
rg "hometown_city" --type json -A 3 -B 3Repository: recoupable/docs
Length of output: 537
🏁 Script executed:
# Look for other properties in the file that also lack explicit `type` but have `nullable`
rg '"nullable"\s*:\s*true' api-reference/openapi/research.json | head -20Repository: recoupable/docs
Length of output: 644
🏁 Script executed:
# Check the OpenAPI spec version and overall schema structure
head -n 20 api-reference/openapi/research.jsonRepository: recoupable/docs
Length of output: 834
🏁 Script executed:
# Search for test fixtures or example data files
find . -type f \( -name "*fixture*" -o -name "*example*" -o -name "*mock*" \) -name "*.json" | head -20Repository: recoupable/docs
Length of output: 41
🏁 Script executed:
# Search for any TypeScript/JS type definitions or interface files that might document these fields
rg "band_members|hometown_city" --type ts --type tsx --type js -B 2 -A 2Repository: recoupable/docs
Length of output: 86
🏁 Script executed:
# Look for any documentation or comments about the structure of these fields
rg "Band-member|hometown" -i --type mdRepository: recoupable/docs
Length of output: 41
🏁 Script executed:
# Check if there are git changes that show what this looked like before
git log --oneline -20 -- api-reference/openapi/research.jsonRepository: recoupable/docs
Length of output: 131
🏁 Script executed:
# Examine the recent commit that changed the research.json
git show aab48da --stat | head -30Repository: recoupable/docs
Length of output: 1452
🏁 Script executed:
# Look at the diff for the specific properties we're concerned with
git show aab48da -- api-reference/openapi/research.json | grep -A 10 -B 10 "band_members\|hometown_city" | head -80Repository: recoupable/docs
Length of output: 2359
🏁 Script executed:
# Check if there's any backend code or API implementation in the repo
find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.py" \) | grep -E "(research|api)" | head -20Repository: recoupable/docs
Length of output: 41
Add explicit type declarations for band_members and hometown_city.
Both properties declare only nullable: true + description with no type, making the schema permissive to any value. Based on the descriptions and OpenAPI 3.1.0 semantics, these should declare explicit types:
band_members: "Band-member objects when known" → likely"type": ["array", "null"]with array items typed as objectshometown_city: "Chartmetric hometown-city object" → likely"type": ["object", "null"]
For consistency with the surrounding nullable: true style, add type alongside additionalProperties: true:
Suggested changes
"band_members": {
+ "type": "array",
"nullable": true,
+ "items": { "type": "object", "additionalProperties": true },
"description": "Band-member objects when known."
}, "hometown_city": {
+ "type": "object",
"nullable": true,
+ "additionalProperties": true,
"description": "Chartmetric hometown-city object (null when unknown)."
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "band_members": { | |
| "nullable": true, | |
| "description": "Band-member objects when known." | |
| }, | |
| "gender": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "gender_title": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "pronoun_title": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "hometown_city": { | |
| "nullable": true, | |
| "description": "Chartmetric hometown-city object (null when unknown)." | |
| }, | |
| "band_members": { | |
| "type": "array", | |
| "nullable": true, | |
| "items": { "type": "object", "additionalProperties": true }, | |
| "description": "Band-member objects when known." | |
| }, | |
| "gender": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "gender_title": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "pronoun_title": { | |
| "type": "string", | |
| "nullable": true | |
| }, | |
| "hometown_city": { | |
| "type": "object", | |
| "nullable": true, | |
| "additionalProperties": true, | |
| "description": "Chartmetric hometown-city object (null when unknown)." | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi/research.json` around lines 4893 - 4912, Add explicit
type declarations for the two permissive schema entries: for band_members,
change the schema to declare its type as ["array","null"] and ensure the array
items are typed as objects (e.g., items: { type: "object", additionalProperties:
true }) while retaining nullable semantics; for hometown_city, declare its type
as ["object","null"] and add additionalProperties: true to represent the
Chartmetric hometown-city object. Update the definitions that currently only
have "nullable": true and "description" so they include these explicit "type"
and "additionalProperties" (and "items" for band_members) entries.
Combine the design/narrative overhaul (new 8-tab IA, deprecation notices, rebuilt Agent Onboarding, achromatic design system) with all API doc updates shipped to main since the branch diverged: - 8 research PRs (#132-#140): schema hardening, /research/track id-proxy, /research/curator Chartmetric contract, /research/track/playlists, error responses aligned with handler enforcement - Artist surface rename: /api/artist/socials -> /api/artists/{id}/socials - New endpoints: artists/pin, artists/unpin, admins/agent-signups - Removed dead surfaces: artist/segments, chat/segment, segment/fans - Caption length default -> none Conflict resolutions: - docs.json: kept design IA (Overview/Chat/Research/Artists/Catalog/Content/ Automation/Accounts), spliced in all new endpoints from main, removed stale nav refs to deleted surfaces - index.mdx, quickstart.mdx: kept design copy (richer, superseded main's verbose endpoint listing with card-based IA) - openapi/content.json: auto-merge preserved design's deprecation of /api/content/create alongside main's untouched body research.json, accounts.json, releases.json are byte-identical to main. 131 API mdx files / 131 nav entries / 0 orphans / 0 broken intra-doc links. Made-with: Cursor
Summary
Surfaced while comparing the merged OpenAPI spec against a full re-test of every research endpoint on recoupable/api#366's preview deployment (test comments: 1 / 2 / 3 / 4 / 5 / 6). Tested with artist "El Gran Combo de Puerto Rico" (Chartmetric id 207089) across 44 captured response bodies.
All changes are spec-only — no api behavior change.
Changes at a glance
/research/trackcm_statistics,tempo,moods,activities/research/playlistcurator_name/num_tracks(never returned) → useowner_name/num_track; add 15+ real fields/research/chartsdatais an array (not object); addlength/research/profilehometown/sp_followers/sp_monthly_listeners/tags(use/research/metricsfor longitudinal platform metrics); add 15+ real fields/research/metrics{data: [...]}wrapper with flat per-platform time-series fields (followers/listeners/popularity/followers_to_listeners_ratio)/research/audienceaudience_likers_*field family + engagement aggregates (followers,avg_likes_per_post,engagement_rate)/research/curatorfollowers/num_playlists; add per-platform follower fields (instagram_followers,facebook_followers, etc.) +cm_statisticsWhy
Every docs/actual drift item from the audit falls into one of two buckets:
/playlistadvertisingcurator_namewhen the real field isowner_name,/profileadvertisingsp_followerswhen longitudinal platform metrics live behind/research/metrics. These mislead integrators into writing code against fields that never populate.audience_likers_*family on/audience,cm_statisticson/track//profile//curator, per-platform follower fields on/curator. Not strictly wrong (additionalProperties: truelets them through), but LLM/SDK consumers won't know to use them.Each schema now matches what the PR #366 preview actually returns, spot-checked against El Gran Combo de Puerto Rico responses.
Test plan
🤖 Generated with Claude Code
Summary by cubic
Aligns the OpenAPI docs for seven research endpoints with actual API responses. Adds missing fields, removes unused ones, and fixes response shapes; no API behavior changes.
/research/chartsuses adataarray and addslength;/research/metricsreturns root-level time-series arrays of{timestp, value}(link,followers,listeners,popularity,followers_to_listeners_ratio)./research/track(cm_statistics,tempo,moods,activities);/research/playlist(owner/IDs, image/editorial/personalized, country/catalog, activity ratio, suspicion/deltas/timestamps, tags/genres/moods/activities);/research/profile(identity/geo, ranks,cm_statistics, career status, genre ranks/ordering, moods/activities, contacts, collaborators);/research/audience(likers fields, engagement aggregates,timestp, notable followers, ethnicities/interests);/research/curator(per-platform follower metrics,user_id/submithub_id,suspicion_score, tags/social URLs,cm_statistics)./research/playlist(curator_name,num_tracks→owner_name,num_track),/research/profile(sp_followers,sp_monthly_listeners,tags),/research/curator(followers,num_playlists).Written for commit aab48da. Summary will update on new commits.
Summary by CodeRabbit