Skip to content

fix(artists): /api/artists id must equal account_id (drop leaked account_info.id)#734

Merged
sweetmantech merged 2 commits into
mainfrom
fix/artists-id-consistency
Jul 1, 2026
Merged

fix(artists): /api/artists id must equal account_id (drop leaked account_info.id)#734
sweetmantech merged 2 commits into
mainfrom
fix/artists-id-consistency

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Part of recoupable/chat#1833 (enabler). Base: main.

Problem

getFormattedArtist did ...info over the raw account_info row, leaking account_info.id into the /api/artists response as id — but the sub-resources /api/artists/{id}/socials|posts|fans key on account_id. An agent that takes the list's id and calls /artists/{id}/socials always 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

  • Replace the blind ...info spread with explicit typed fields (image/instruction/knowledges/label).
  • Set id = account_id so .id and .account_id both resolve for sub-resources (most forgiving for LLM callers).
  • Drops the other dead leaks (job_title/role_type/company_name/organization) — unused on this object (only read on getSystemPrompt's separate accountWithDetails).
  • account_id unchanged; chat frontend (keys on account_id) unaffected.

Tests (TDD)

  • New RED→GREEN getFormattedArtist.test.ts: id === account_id (never account_info.id); no raw-field leak.
  • Updated updateArtistHandler expectation (response now includes id = account_id).
  • Full lib/artists suite 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.id and unused fields from responses.

  • Bug Fixes
    • Map only image, instruction, knowledges, label from account_info (no raw spread).
    • Set id = account_id so /artists/{id}/socials|posts|fans work.
    • Drop leaked fields: job_title, role_type, company_name, organization; add tests and update handler expectation.

Written for commit a4411ff. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Fixed artist pages and related endpoints so the displayed artist ID now consistently matches the correct account-based identifier.
    • Improved artist data rendering to avoid accidental carryover of unrelated fields, ensuring the returned details are accurate and predictable.

…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>
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
api Ready Ready Preview Jul 1, 2026 10:00pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7b82de24-8215-42bf-8b7f-4ed45e8c435b

📥 Commits

Reviewing files that changed from the base of the PR and between b3bac3c and a4411ff.

⛔ Files ignored due to path filters (2)
  • lib/artists/__tests__/getFormattedArtist.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/artists/__tests__/updateArtistHandler.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (1)
  • lib/artists/getFormattedArtist.ts

📝 Walkthrough

Walkthrough

The FormattedArtist interface gains a new id field mirroring account_id. The getFormattedArtist function's return object was changed to explicitly assign image, instruction, knowledges, and label from info instead of spreading it, and now sets id explicitly to the computed account_id.

Changes

FormattedArtist id field

Layer / File(s) Summary
Type and mapping update
lib/artists/getFormattedArtist.ts
Adds id: AccountRow["id"] to FormattedArtist and updates getFormattedArtist to explicitly map fields from info and set both account_id and id to the computed account_id, rather than spreading info.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • recoupable/api#416: The getFormattedArtist output consumed by the GET /api/artists/[id] endpoint is directly affected by the id/field mapping changes here.

Poem

A rabbit hops through fields of code,
Finds account_id a new abode,
No more spreading, just clean maps drawn,
id now mirrors from the dawn,
Clean and explicit, the fields all show! 🐰✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/artists-id-consistency

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.

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

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", ... } }
Loading

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

@sweetmantech

Copy link
Copy Markdown
Contributor Author

Preview verification — /api/artists id is now account_id; sub-resources resolve

Tested this PR's preview (https://api-40n5c2j9v-recoup.vercel.app, head 8c76b51b) against test-recoup-api.vercel.app (= main, still buggy) with the same token, using Apache (account_id ebae4bb9) as the fixture.

Functional result — before/after

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 documenting id (= account_id) — recommended, since the forgiving alias directly serves the LLM-consumer grounding goal — or dropping it (option (a)).
    • instruction, knowledges, label are returned but not documented.
    • Docs call the embedded socials field socials; the API returns account_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 socialsaccount_socials so docs ↔ API fully agree.

@sweetmantech sweetmantech merged commit 756252a into main Jul 1, 2026
4 of 6 checks passed
sweetmantech added a commit that referenced this pull request Jul 1, 2026
sweetmantech added a commit to recoupable/docs that referenced this pull request Jul 1, 2026
…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>
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