-
feat(bounds): the boundary lab — decide a cut by ear in seconds, not a full pass · 192c6e9e
The set-judge answers "is this track a keeper". This answers the question that actually blocked the release: where exactly does one track become the next. After three failed detectors (cut_lens3 declared a dead end in 5f7db02a), #13 and #15 are ear-only by nature — the two tracks share their sounds across the switch, so no timbral lens can see the handover. The tool's job is therefore to make one ear call cheap, not to avoid asking. build_bounds_set.py renders a ±45 s FLAC clip per boundary instead of seeking the 817 MB master. A boundary audition is a scrub — dozens of small seeks around one point — and seeking a long FLAC depends on a seektable the browser may not use well; local clips make every seek instant for a few MB total. Clips are re-encoded, never `-c copy`, because FLAC stream-copy snaps to frame boundaries and every marker inside the clip would inherit that offset. Clip time and master time are kept explicitly apart (`clipStart`), converted in exactly two functions. The UI shows each cut's candidates as labelled markers on the waveform, drawn as regions rather than positioned divs so they stay glued to the audio through zoom and scroll. `takeover` leads the list because it landed within 0.7 s on both boundaries that also had ear answers — with the caveat printed on screen, since that is n=2 on the cases that were already easy. Boundaries with NO candidate are shown with an explicit notice rather than omitted: those are precisely the ones needing a human, and hiding them would hide the work. Fixes a real bug in the SHARED player while here: `ws.zoom()` needs a decoded buffer, which the peaks path never has, so it threw "No audio loaded" from an effect and blanked the entire page. Same message as the peaks+url trap, entirely different cause. Now guarded and failed-soft — zoom is a convenience and must never take the tool down. The judge had this latent too. bounds-smoke.mjs, 11 assertions, all passing. Two of them exist because the first version of this test passed while proving nothing: querySelector('audio') is null by construction (wavesurfer owns the element and never puts it in the DOM), so the playback probe would have "passed" forever on a dead transport. It now reads the transport clock and the Pause button — what a human sees. A positional selector also silently picked the header's counter instead of the clock, hence the explicit data-testid.
PLN (Algolia) authored192c6e9e
| Name |
Last commit
|
Last update |
|---|---|---|
| .. | ||
| public | Loading commit data... | |
| scripts | Loading commit data... | |
| src | Loading commit data... | |
| .gitignore | Loading commit data... | |
| README.md | Loading commit data... | |
| audio-mounts.json | Loading commit data... | |
| bounds.html | Loading commit data... | |
| eslint.config.js | Loading commit data... | |
| index.html | Loading commit data... | |
| judge.html | Loading commit data... | |
| package-lock.json | Loading commit data... | |
| package.json | Loading commit data... | |
| sextant.html | Loading commit data... | |
| tsconfig.app.json | Loading commit data... | |
| tsconfig.json | Loading commit data... | |
| tsconfig.node.json | Loading commit data... | |
| vite.config.ts | Loading commit data... |