Rerun failed tracks and edit-and-rebuild existing ones #2

Merged
branderson merged 10 commits from rerun-rebuild into main 2026-07-27 09:19:57 -07:00
Owner

Summary generated by LLM agent

Summary

Adds two related features to the web UI, requested as a follow-up after the Spotify-style theming PR merged:

  • Rerun — re-enqueue a finished or failed job with its exact original input as a new linked job (POST /api/jobs/{id}/rerun).
  • Edit & rebuild — resubmit a job with edited fields (title/artist/lyrics/source/genre/year/language/bpm/cover) and automatically redo only the pipeline stages the edit invalidates, via a new FIELD_STAGE policy map (src/karaoke_maker/rebuild.py) that feeds the existing run_pipeline(..., force_from=...) argument. Everything before the invalidated stage is served from cache.

Supporting changes: uploads are now retained on job failure (previously deleted unconditionally, which made a job that died in acquire permanently un-rerunnable) and covers are always kept since a rebuild inherits cover_path; a retitled song's work directory is relocated rather than duplicated; a superseded output directory (when a retitle changes the output folder's slug) is removed after a successful rebuild; and the frontend gained RERUN / EDIT & REBUILD controls that reuse the existing single song form in a "rebuild mode" rather than duplicating it.

Design doc: ~/specs/2026-07-26-karaoke-maker-rerun-rebuild-design.md. Job persistence across server restarts was scoped out and explicitly deferred (documented in the design doc) — jobs remain in-memory only, same as before this branch.

How this was built

Implemented via Subagent-Driven Development against a 7-task plan, one task per commit, each independently spec- and quality-reviewed:

  1. rebuild.py — field-to-stage mapping, relocate/superseded-output helpers (pure, no web dependency)
  2. Upload retention fix (delete-on-success-only, video only, covers always kept)
  3. rebuilt_from job link + POST /rerun, with job creation factored into a shared _enqueue helper
  4. GET /api/jobs/{id}/input — echoes a job's inputs keyed by form field name, for prefilling the rebuild form
  5. POST /rebuild + worker force_from wiring — the endpoint and the worker land together since one is meaningless without the other
  6. Superseded output directory removal after a successful rebuild
  7. Frontend: action row, rebuild-mode reuse of the single song form, lineage marker on rebuilt jobs

A final whole-branch review (independent from the per-task reviews) caught two real test-coverage gaps — cover inheritance across a rebuild and an accessibility-label test that didn't pin its own literal — both were mutation-verified (the code they're meant to protect was temporarily deleted/broken to confirm the new tests actually catch it) and fixed in the closing commit.

Test plan

  • Full suite passes: 227 passed, 1 skipped (up from the pre-branch baseline of 163 passed, 1 skipped)
  • Every new/changed test was mutation-verified where feasible (temporarily break the code under test, confirm the test fails; restore, confirm it passes) rather than merely asserted to pass
  • Manual browser check of the new UI: RERUN/EDIT & REBUILD control visibility per job status, form-mode swap (heading/button label/CANCEL/prefill), keep-note visibility for inherited files, and the rebuilt-job lineage marker
  • No innerHTML/outerHTML/insertAdjacentHTML introduced (existing guard test enforces this); no external network requests added; focus-preservation on the 3-second poll verified for the new action row and lineage link
  • No changes to cli.py or anything under src/karaoke_maker/stages/
**Summary generated by LLM agent** ## Summary Adds two related features to the web UI, requested as a follow-up after the Spotify-style theming PR merged: - **Rerun** — re-enqueue a finished or failed job with its exact original input as a new linked job (`POST /api/jobs/{id}/rerun`). - **Edit & rebuild** — resubmit a job with edited fields (title/artist/lyrics/source/genre/year/language/bpm/cover) and automatically redo only the pipeline stages the edit invalidates, via a new `FIELD_STAGE` policy map (`src/karaoke_maker/rebuild.py`) that feeds the existing `run_pipeline(..., force_from=...)` argument. Everything before the invalidated stage is served from cache. Supporting changes: uploads are now retained on job failure (previously deleted unconditionally, which made a job that died in `acquire` permanently un-rerunnable) and covers are always kept since a rebuild inherits `cover_path`; a retitled song's work directory is relocated rather than duplicated; a superseded output directory (when a retitle changes the output folder's slug) is removed after a successful rebuild; and the frontend gained RERUN / EDIT & REBUILD controls that reuse the existing single song form in a "rebuild mode" rather than duplicating it. Design doc: `~/specs/2026-07-26-karaoke-maker-rerun-rebuild-design.md`. Job persistence across server restarts was scoped out and explicitly deferred (documented in the design doc) — jobs remain in-memory only, same as before this branch. ## How this was built Implemented via Subagent-Driven Development against a 7-task plan, one task per commit, each independently spec- and quality-reviewed: 1. `rebuild.py` — field-to-stage mapping, relocate/superseded-output helpers (pure, no web dependency) 2. Upload retention fix (delete-on-success-only, video only, covers always kept) 3. `rebuilt_from` job link + `POST /rerun`, with job creation factored into a shared `_enqueue` helper 4. `GET /api/jobs/{id}/input` — echoes a job's inputs keyed by form field name, for prefilling the rebuild form 5. `POST /rebuild` + worker `force_from` wiring — the endpoint and the worker land together since one is meaningless without the other 6. Superseded output directory removal after a successful rebuild 7. Frontend: action row, rebuild-mode reuse of the single song form, lineage marker on rebuilt jobs A final whole-branch review (independent from the per-task reviews) caught two real test-coverage gaps — cover inheritance across a rebuild and an accessibility-label test that didn't pin its own literal — both were mutation-verified (the code they're meant to protect was temporarily deleted/broken to confirm the new tests actually catch it) and fixed in the closing commit. ## Test plan - [x] Full suite passes: `227 passed, 1 skipped` (up from the pre-branch baseline of `163 passed, 1 skipped`) - [x] Every new/changed test was mutation-verified where feasible (temporarily break the code under test, confirm the test fails; restore, confirm it passes) rather than merely asserted to pass - [x] Manual browser check of the new UI: RERUN/EDIT & REBUILD control visibility per job status, form-mode swap (heading/button label/CANCEL/prefill), keep-note visibility for inherited files, and the rebuilt-job lineage marker - [x] No `innerHTML`/`outerHTML`/`insertAdjacentHTML` introduced (existing guard test enforces this); no external network requests added; focus-preservation on the 3-second poll verified for the new action row and lineage link - [x] No changes to `cli.py` or anything under `src/karaoke_maker/stages/`
branderson added 10 commits 2026-07-27 09:05:13 -07:00
Directly assert STAGE_LINE does not match the [rebuild] line, rather than
inferring it from job.stage, which ok_runner's later [acquire] running
line would overwrite either way.
- add test_rebuild_inherits_the_parents_cover: covers the cover_path
  inheritance mechanism in the rebuild endpoint (Task 2's upload-retention
  design relied on it, but nothing exercised it)
- tighten test_lineage_marker_survives_in_the_accessibility_tree to assert
  the literal " rebuilt" screen-reader text, not just that rebuilt_from
  is referenced somewhere in paintCard
- normalize submit's youtube_url/genre/language the same way rebuild does,
  for symmetry, plus a pinning test
- pin acquire's stage outputs to [meta.json, audio.wav] in test_acquire.py,
  since web.py's _require_source hardcodes those same filenames
branderson merged commit 128d4670ef into main 2026-07-27 09:19:57 -07:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: branderson/songtrace#2