Skip to content

fix(etl): persist orig_filename and stop track updates from unlinking stems - #421

Merged
dylanjeffers merged 1 commit into
mainfrom
fix/etl-stem-of-orig-filename
Jul 27, 2026
Merged

fix(etl): persist orig_filename and stop track updates from unlinking stems#421
dylanjeffers merged 1 commit into
mainfrom
fix/etl-stem-of-orig-filename

Conversation

@dylanjeffers

Copy link
Copy Markdown
Contributor

Context

Pairs with AudiusProject/api#995 (the July 2026 "contest stems invisible" incident — Andrew Lux's "Alone" remix contest). The api PR is the unblocking change: it makes /v1/tracks/{id}/stems tolerate the row shapes the ETL currently produces. This PR fixes the ETL so those shapes stop being produced — it prevents recurrence rather than unblocking anything.

Verified against the incident's real chain data: the on-chain create txs (core blocks 28480416–28480440) always carried correct stem_of and orig_filename; the losses documented below are write-path gaps, not chain/client issues.

Changes

  1. Persist orig_filename on track create/update. The create handler never extracted it, so only legacy Python-indexed rows carry a value; /v1/tracks/{id}/stems reads it for stem download filenames (NULLs there 500'd the endpoint before api#973/#995). On update it gets the same never-clear treatment as the CIDs, since only the upload flow sets it and clients resend the full track object on edit.

  2. Ignore an explicit "stem_of": null on update. Clients send the full track object on edit, so a carried null permanently unlinked a stem from its parent — the same failure class as the CID wipe fixed in fix(etl): don't let track updates wipe CIDs via explicit null #410. No edit flow legitimately detaches a stem: removing one means deleting the stem track.

  3. Upsert the stems join row when an update carries stem_of. Keeps the join table in sync with the jsonb and provides an on-chain repair path (a signed UpdateTrack can restore a lost parent link).

Tests

stem_repro_test.go replays the exact on-chain create tx from the incident (user 8151, track 61740430, core block 28480422) and asserts: stem_of + stems row persist on create, orig_filename persists, an explicit "stem_of": null update does not unlink, and an update carrying stem_of restores a deleted stems row. Full processors/entity_manager suite passes.

Follow-up

Once released, bump the ETL pin in AudiusProject/api (same flow as api#994 did for #410).

🤖 Generated with Claude Code

Three parity/robustness fixes to entity-manager track writes, found while
investigating stems that never appeared on a remix contest page
(AudiusProject/api#995):

- Persist orig_filename on create and update (never-clear, like the
  CIDs). Only legacy Python-indexed rows carried it, and downstream
  consumers (/v1/tracks/{id}/stems) read it for stem download filenames.
- Ignore an explicit "stem_of": null on update. Clients send the full
  track object on edit, so a carried null permanently unlinked the stem
  from its parent — same failure class as the CID wipe fixed in #410. No
  edit flow legitimately detaches a stem; removing one means deleting
  the stem track.
- Upsert the stems join row when an update carries stem_of, keeping the
  join table in sync and giving an on-chain repair path for stems whose
  link was lost.

The regression test replays the exact on-chain create tx from the
incident (core block 28480422) and covers all three behaviors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dylanjeffers
dylanjeffers merged commit 1d9f697 into main Jul 27, 2026
8 of 9 checks passed
@dylanjeffers
dylanjeffers deleted the fix/etl-stem-of-orig-filename branch July 27, 2026 21:48
This was referenced Jul 27, 2026
@raymondjacobson

raymondjacobson commented Jul 27, 2026 via email

Copy link
Copy Markdown
Contributor

dylanjeffers added a commit to AudiusProject/api that referenced this pull request Jul 27, 2026
…audio#421) (#996)

Bumps both `github.com/OpenAudio/go-openaudio` and `.../pkg/etl` pins
from `b4a5ebe` (2026-07-16) to `1d9f697` — the merge of
**OpenAudio/go-openaudio#421**, same flow as #994 did for the #410 CID
fix.

## What the new pin brings (ETL / entity manager)

- Persist `orig_filename` on track create/update (never-clear, like the
CIDs) — new stem rows no longer rely on the `/stems` endpoint's title
fallback
- Ignore explicit `"stem_of": null` on track updates so client edits
can't unlink a stem from its parent (#410 failure class)
- Upsert the `stems` join row when an update carries `stem_of` (on-chain
repair path for lost links)

Intervening upstream commits also included (library-only for api):
mediorum transcode/retry fixes (#338, #417#419) and core/logging spam
guards (#420). Nothing release- or mainnet-config-related.

## Relation to #995

#995 is the unblocking change (endpoint tolerates NULLs already in the
DB); this bump prevents recurrence at the write path. Both trace back to
the July stems-invisible incident (Andrew Lux's "Alone" remix contest).

Verified locally: `go build ./...`, stems endpoint tests, and `go test
./indexer/...` all pass on the new pin.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <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.

2 participants