- 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
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.
Final whole-branch review fix wave (5 items):
- copyPath: fall back to execCommand("copy") via an off-screen textarea,
then to selecting the path text, since navigator.clipboard is undefined
outside secure contexts (i.e. this app's normal http:// deployment)
- refreshDetail: snapshot selectedId before fetching and discard the
response if selection changed while in flight, so a slow response can no
longer permanently mis-pair the review panel with the wrong job now that
polling stops when idle
- .st-queued: give the sidebar rail a colour that clears 3:1 against --panel
- now-bar: #now-label reflects running/idle state instead of always reading
"NOW RUNNING"
- empty-state copy: distinguish a failed job from "nothing to review", fix
the queue-empty messages to not ask the user to select something that
doesn't exist, and normalise voice to lowercase/unpunctuated
- package stage: cache off a package.done sentinel written only after every
sub-step succeeds, instead of the txt/mp3 files that land first. A partial
failure (e.g. ffprobe/PIL error after txt+mp3 are written) no longer looks
cached, so a retry actually finishes the folder instead of being skipped.
- package stage: a corrupt/non-image cover file now degrades to the existing
no-cover path (drop #COVER header) instead of raising UnidentifiedImageError.
- consolidate the three independent language-code tables (lyrics._LANG_MAP,
notes._PYPHEN, whisper_client._ISO) into languages.LANGUAGES so a language
known to one call site can't be silently mishandled by another (e.g.
Japanese reaching Whisper correctly but syllabifying with English rules).
- web.py: remove a job's uploads/<job_id> dir once it reaches a terminal
state; safe because acquire copies the upload into the per-song work dir
and package reads cover_path directly, both inside the synchronous
runner() call that precedes cleanup.