Add rebuild-from-scratch, delete, and cross-restart persistence for songs #5

Merged
branderson merged 8 commits from song-rebuild-persistence into main 2026-07-28 03:25:49 -07:00
Owner

Summary generated by LLM agent

Summary

Three related fixes to the webui's job handling:

  • Rebuild from scratch: new POST /api/jobs/{id}/rebuild-full forces every
    pipeline stage to rerun unconditionally (reuses the existing force_from
    mechanism, pinned to the first stage), for cases where an unchanged
    resubmission would otherwise replay every stage as "cached, skipping" even
    when output_dir is empty.
  • Delete: new DELETE /api/jobs/{id} removes a song's work/output
    directories and drops it from the job list, gated the same way other
    mutating endpoints are (409 while queued/running).
  • Cross-restart persistence: the worker now writes a work_dir/<slug>/input.json
    sidecar right after the slug is resolved (ordered to avoid racing
    relocate_work's collision check), and a new _discover_jobs startup scan
    reconstructs done/failed jobs from those sidecars before the worker
    thread starts, so songs survive a server restart instead of disappearing
    from the UI.
  • Frontend: "REBUILD FROM SCRATCH" and "DELETE" buttons wired up next to the
    existing rerun/edit actions, plus a clearDetail() fix so the review panel
    resets correctly when no job is selected (e.g. after deleting the last song).

Built via superpowers subagent-driven-development: 5 planned tasks, each with
its own task-scoped review, followed by a whole-branch final review that
caught and fixed 3 Important issues before merge (see below).

Notable fixes from final review

  • DELETE now checks for any other job sharing the same slug that's still
    queued/running (e.g. a rebuild-from-scratch child) and returns 409 instead
    of deleting the directories out from under it.
  • _discover_jobs no longer crashes the whole server on startup if one
    song's sidecar/notes file was left corrupt/torn by an interrupted process
    — it skips that entry and continues.

Two minor items were identified and deliberately deferred (not blocking):
DELETE doesn't clean up a failed job's retained video upload directory, and
rebuildFullJob/rerunJob share near-identical fetch/error-handling code in
the frontend that could be factored out later.

Test plan

  • Full suite green: pytest -q → 251 passed, 1 skipped
  • Each of the 5 implementation tasks individually reviewed (spec +
    quality) with clean verdicts
  • Whole-branch final review, findings fixed, scoped re-review clean
  • Manual smoke test in a browser (rebuild-from-scratch, delete, and a
    server-restart reload) — not yet done by a human
**Summary generated by LLM agent** ## Summary Three related fixes to the webui's job handling: - **Rebuild from scratch**: new `POST /api/jobs/{id}/rebuild-full` forces every pipeline stage to rerun unconditionally (reuses the existing `force_from` mechanism, pinned to the first stage), for cases where an unchanged resubmission would otherwise replay every stage as "cached, skipping" even when `output_dir` is empty. - **Delete**: new `DELETE /api/jobs/{id}` removes a song's work/output directories and drops it from the job list, gated the same way other mutating endpoints are (409 while queued/running). - **Cross-restart persistence**: the worker now writes a `work_dir/<slug>/input.json` sidecar right after the slug is resolved (ordered to avoid racing `relocate_work`'s collision check), and a new `_discover_jobs` startup scan reconstructs `done`/`failed` jobs from those sidecars before the worker thread starts, so songs survive a server restart instead of disappearing from the UI. - Frontend: "REBUILD FROM SCRATCH" and "DELETE" buttons wired up next to the existing rerun/edit actions, plus a `clearDetail()` fix so the review panel resets correctly when no job is selected (e.g. after deleting the last song). Built via superpowers subagent-driven-development: 5 planned tasks, each with its own task-scoped review, followed by a whole-branch final review that caught and fixed 3 Important issues before merge (see below). ## Notable fixes from final review - `DELETE` now checks for any *other* job sharing the same slug that's still queued/running (e.g. a rebuild-from-scratch child) and returns 409 instead of deleting the directories out from under it. - `_discover_jobs` no longer crashes the whole server on startup if one song's sidecar/notes file was left corrupt/torn by an interrupted process — it skips that entry and continues. Two minor items were identified and deliberately deferred (not blocking): DELETE doesn't clean up a failed job's retained video upload directory, and `rebuildFullJob`/`rerunJob` share near-identical fetch/error-handling code in the frontend that could be factored out later. ## Test plan - [x] Full suite green: `pytest -q` → 251 passed, 1 skipped - [x] Each of the 5 implementation tasks individually reviewed (spec + quality) with clean verdicts - [x] Whole-branch final review, findings fixed, scoped re-review clean - [ ] Manual smoke test in a browser (rebuild-from-scratch, delete, and a server-restart reload) — not yet done by a human
branderson added 6 commits 2026-07-28 03:18:31 -07:00
- DELETE now checks under the shared lock whether another job with the
  same slug is queued/running before removing the job entry, so
  deleting a done parent can no longer rmtree a rebuild's active
  work/output directories.
- _discover_jobs now wraps the iterdir/stat/read_warnings calls in the
  same try/except as the JSON parse, so one corrupt or torn sidecar
  file (e.g. from a killed mid-write) no longer crashes the whole app
  at boot.
- Fixed test_delete_tolerates_a_work_dir_that_is_already_gone, which
  had become vacuous since _write_sidecar now eagerly creates the work
  dir; it now removes the dir before asserting DELETE tolerates its
  absence.
- Added a regression test covering the DELETE slug-collision race.
branderson added 1 commit 2026-07-28 03:23:12 -07:00
# Conflicts:
#	src/songtrace/web.py
#	tests/test_web.py
branderson added 1 commit 2026-07-28 03:25:17 -07:00
branderson merged commit f560c44170 into main 2026-07-28 03:25:49 -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#5