fix(artists): /api/artists id must equal account_id (drop leaked account_info.id)#734
Conversation
…unt_info.id)
getFormattedArtist spread the raw account_info row (`...info`), leaking
account_info.id into the response as `id` (plus job_title/role_type/company_name/
organization). But /api/artists/{id}/socials|posts|fans key on account_id, so an
agent using the list's `id` for a sub-resource always 404s — the root of the
Apache→OneRPM mis-fetch → fabrication (recoupable/chat#1833).
Replace the blind spread with explicit typed fields and set `id = account_id`, so
`.id` and `.account_id` both resolve for sub-resources. Drops the other dead leaks
too (unused outside getSystemPrompt's separate accountWithDetails object).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe ChangesFormattedArtist id field
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Poem
✨ 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 |
There was a problem hiding this comment.
No issues found across 3 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Client as API Client / LLM Agent
participant Route as /api/artists Route
participant Handler as updateArtistHandler
participant Formatter as getFormattedArtist
participant DB as Database
Note over Client,DB: GET /api/artists — list endpoint
Client->>Route: GET /api/artists
Route->>DB: Query artists with account_info join
DB-->>Route: ArtistQueryRow (row.artist_info with account_info[0])
Route->>Formatter: getFormattedArtist(row)
Formatter->>Formatter: Extract account_id = artist_info.id
Formatter->>Formatter: Extract info = account_info[0]
alt Explicit typed fields from account_info
Formatter->>Formatter: image = info.image
Formatter->>Formatter: instruction = info.instruction
Formatter->>Formatter: knowledges = info.knowledges
Formatter->>Formatter: label = info.label
end
Note over Formatter: id = account_id (not info.id)
Formatter-->>Route: FormattedArtist { id: account_id, account_id, ... }
Route-->>Client: JSON response with id === account_id
Note over Client,DB: GET /api/artists/{id}/socials — sub-resource access
Client->>Route: GET /api/artists/acct-ebae/socials
alt Client used id from list response
Route->>DB: Lookup by acct-ebae (matches account_id)
DB-->>Route: Found
Route-->>Client: 200 Socials data
end
Note over Client,DB: PUT /api/artists/{id} — update (updated handler)
Client->>Handler: PUT /api/artists/acct-ebae
Handler->>DB: Update artist record
DB-->>Handler: Updated row
Handler->>Formatter: getFormattedArtist(row)
Formatter-->>Handler: FormattedArtist with id === account_id
Handler-->>Client: { artist: { account_id: "acct-ebae", id: "acct-ebae", ... } }
Auto-approved: Fixes a data mapping bug in getFormattedArtist to prevent leaking account_info.id and sets id=account_id for sub-resource compatibility. Well-tested, isolated, and low-risk.
Re-trigger cubic
Preview verification —
|
| check | #734 preview (fixed) | main (buggy) |
|---|---|---|
id |
ebae4bb9 (= account_id) |
33adb9fe (= account_info.id leak) |
id === account_id |
✅ true | ✗ false |
GET /api/artists/{id}/socials (using the list id) |
✅ HTTP 200 success |
HTTP 404 error |
leaked job_title/role_type/company_name/organization |
✅ gone | present |
This is the exact footgun from the OneRPM run: on main, the list id (33adb9fe) → /socials 404 ("Artist not found") → the agent fabricated. On the #734 preview, the list id resolves and /socials returns 200.
Reconciliation vs the docs (releases.json → /api/artists)
Documented item fields: account_id, name, image, pinned, socials.
- ✅
account_id,name,image,pinned— match. - ✅ fix(artists): /api/artists id must equal account_id (drop leaked account_info.id) #734 removes 4 undocumented leaked fields (
job_title/role_type/company_name/organization) → response is now closer to the documented contract. ⚠️ Remaining docs↔API drift (mostly pre-existing — flagging for a small docs follow-up, not blockers):id(=account_id) is returned but not in the docs. fix(artists): /api/artists id must equal account_id (drop leaked account_info.id) #734 deliberately keeps it as a forgiving alias (issue option (b)). Reconcile by documentingid(= account_id) — recommended, since the forgiving alias directly serves the LLM-consumer grounding goal — or dropping it (option (a)).instruction,knowledges,labelare returned but not documented.- Docs call the embedded socials field
socials; the API returnsaccount_socials(name mismatch — pre-existing).
Net: #734's core contract fix is verified live — id === account_id, /artists/{id}/socials no longer 404s, and the undocumented leaked fields are gone. Recommend a tiny docs PR to add id/instruction/knowledges/label and reconcile socials↔account_socials so docs ↔ API fully agree.
…e API (#257) Surfaced verifying recoupable/api#734 + #735 (recoupable/chat#1833): - Artist: add `id` (= account_id, forgiving alias for /artists/{id}/* sub-resources), `instruction`, `knowledges`, `label`; rename `socials` -> `account_socials` (the field the API actually returns). - SocialProfile: drop `id` — api#735 removed the dead `account_socials.id` from /api/artists/{id}/socials (only `social_id` is returned now). Docs ↔ API now agree field-for-field (verified against the live #734/#735 previews). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Part of recoupable/chat#1833 (enabler). Base:
main.Problem
getFormattedArtistdid...infoover the rawaccount_inforow, leakingaccount_info.idinto the/api/artistsresponse asid— but the sub-resources/api/artists/{id}/socials|posts|fanskey onaccount_id. An agent that takes the list'sidand calls/artists/{id}/socialsalways 404s. Reproduced live on the Apache→OneRPM run:id=33adb9fe(account_info.id) → "Artist not found";account_id=ebae4bb9→ success. Direct contributor to that email's fabrication.Fix
...infospread with explicit typed fields (image/instruction/knowledges/label).id = account_idso.idand.account_idboth resolve for sub-resources (most forgiving for LLM callers).job_title/role_type/company_name/organization) — unused on this object (only read ongetSystemPrompt's separateaccountWithDetails).account_idunchanged; chat frontend (keys onaccount_id) unaffected.Tests (TDD)
getFormattedArtist.test.ts:id === account_id(neveraccount_info.id); no raw-field leak.updateArtistHandlerexpectation (response now includesid = account_id).lib/artistssuite green (97), tsc + eslint clean.🤖 Generated with Claude Code
Summary by cubic
Fixes /api/artists to set id = account_id so /artists/{id}/socials|posts|fans resolve without 404s. Removes leaked
account_info.idand unused fields from responses.image,instruction,knowledges,labelfromaccount_info(no raw spread).id = account_idso/artists/{id}/socials|posts|fanswork.job_title,role_type,company_name,organization; add tests and update handler expectation.Written for commit a4411ff. Summary will update on new commits.
Summary by CodeRabbit