feedBack/static/js
Byron Gamatos 8d0e270345
refactor(app): carve the JUCE/desktop audio shims out of app.js (R3a) (#893)
* refactor(app): carve resume-session out of app.js (R3a)

static/js/resume-session.js (157) — the snapshot taken when you leave a song and the
pill that offers it back. Bodies VERBATIM. app.js 7,727 → 7,601.
Fifth slice out of the strongly-connected core. ONE hook (playSong) + a
currentFilename getter.

S.pendingResume JOINS THE CONTAINER — on demand, exactly as intended. app.js WRITES
it (playSong({ resume }) arms it; the song:ready listener consumes it) while this
module reads it, so it cannot be a plain export: an imported binding is read-only.
Same reason isPlaying is there. The container grows one field per carve that needs
it, never speculatively.

THE CONTRACT TEST CAUGHT THE MISSING HOOK, again on a path nothing executes:
"playSong is read by a module but never wired by app.js — it would throw at runtime".
Second time it has caught a real wiring gap the moment it appeared.

A REAL TRAP, worth remembering: I first did the S.pendingResume rewrite by feeding
acorn's identifier RANGES from node into python, and it corrupted the file
(`_pS.pendingResume null;`). **Acorn's offsets are UTF-16 code units; Python's string
indices are code points.** static/app.js contains emoji, so every offset past one
drifts. Do an AST-driven rewrite in the SAME language that produced the offsets.
`node --check` caught it; a silent version of that bug is very easy to imagine.

VERIFIED. A/B against origin/main in two browsers, real song: the window API
(resumeLastSession / _snapshotResumeSession / _readResumeSession /
_clearResumeSession), snapshot, read-back, and clear — IDENTICAL, zero page errors.
HONEST LIMIT: my probe never got the snapshot to actually PERSIST (there is a guard
beyond the 3s minimum position that a scripted playSong does not satisfy), so that
path is verified only as identical-to-main, not as observed-working. The real
coverage is tests/browser/resume-session.spec.ts, which drives the flow properly.

Zero harnesses broke. pytest 2396, node 1040/1040, ESLint 0 (no-cycle clean),
tailwind clean, Codex 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(app): carve the JUCE/desktop audio shims out of app.js (R3a)

static/js/juce-audio.js (994) — bodies VERBATIM. app.js 7,603 → 6,643.
THE LARGEST SINGLE SLICE of the whole carve phase: 960 lines, ~13% of what was left.

Three self-installing IIFEs:
  _installJuceEngineRoutingWatcher (444)  routes a song to the JUCE engine or HTML5 as
                                          the desktop output enters/leaves exclusive/ASIO
  _installRendererBusFeeder        (337)  feeds the highway renderer bus from whichever
                                          transport is actually running
  _installJuceAudioElementShim     (156)  patches audio.play/pause so the rest of the app
                                          keeps talking to the <audio> element while JUCE
                                          owns the transport

They EXPORT NOTHING — all three publish through `window.*` (_juceMode,
_reevaluateJuceRouting, _reevaluateRendererBus, …). So app.js needs only a
side-effect import plus the one binding it actually uses
(_resetJuceAudioShimChain, which the shim IIFE assigns).

THE ORDERING QUESTION, CHECKED RATHER THAN ASSUMED. Importing this module runs the
IIFEs EARLIER than before: imports evaluate ahead of app.js's body, and therefore
ahead of configureHost(). A hook read at IIFE-execution time would THROW. So I walked
the AST at IIFE-body depth to see what they actually touch when they run: nothing but
listener registration, and `audio.play`/`audio.pause` patching — and `audio` is itself
an imported module now. Verified in the browser: both are patched on the carved build
exactly as on main, which proves the shim installs correctly at its new, earlier point.
(Had I got this wrong, host.js throws loudly rather than silently misbehaving — which
is the whole reason it has no no-op defaults.)

VERIFIED. A/B against origin/main in two browsers: the entire window.* surface the
IIFEs publish (_juceMode, _juceOutputIsExclusive, _reevaluateJuceRouting,
_reevaluateRendererBus, _clearJuceRerouteMemo), audio.play/pause patched, a real song
loading and togglePlay driving the public mirror — IDENTICAL, zero page errors.

Harnesses: juce_engine_reroute (19 tests) + renderer_bus_feeder (13) slice the IIFEs by
signature — retargeted, and each sandbox gains a `host` object routed at its EXISTING
stubs so every assertion holds unchanged. test_plugin_runtime_idempotence is SPLIT: 3 of
its 4 source-asserts stayed in app.js, the sm.emit('song:resume') one moved.

pytest 2396, node 1040/1040, ESLint 0 (no-cycle clean), tailwind clean, Codex 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 22:44:03 +02:00
..
audio-el.js refactor(app): give the <audio> element a module of its own (R3a) (#886) 2026-07-11 20:44:01 +02:00
count-in.js refactor(app): carve count-in (and the song-credits overlay) out of app.js (R3a) (#890) 2026-07-11 22:05:22 +02:00
diagnostics-export.js refactor(app): carve the diagnostics-bundle export out of app.js (R3a) (#881) 2026-07-11 18:52:47 +02:00
dom.js refactor(app): carve the DOM/modal primitives out of app.js (R3a) (#882) 2026-07-11 18:59:44 +02:00
highway-colors.js refactor(app): carve the highway string-colours out of app.js (R3a) (#883) 2026-07-11 19:22:14 +02:00
host.js refactor(app): the host seam + carve section practice out of app.js (R3a) (#887) 2026-07-11 20:58:41 +02:00
juce-audio.js refactor(app): carve the JUCE/desktop audio shims out of app.js (R3a) (#893) 2026-07-11 22:44:03 +02:00
loops.js refactor(app): carve the A–B loop out of app.js (R3a) (#888) 2026-07-11 21:32:31 +02:00
player-controls.js refactor(app): carve the player controls out of app.js (R3a) (#891) 2026-07-11 22:12:34 +02:00
player-state.js refactor(app): carve the JUCE/desktop audio shims out of app.js (R3a) (#893) 2026-07-11 22:44:03 +02:00
plugin-loader.js refactor(app): carve settings backup + plugin updates out of app.js (R3a) (#885) 2026-07-11 19:42:54 +02:00
resume-session.js refactor(app): carve the JUCE/desktop audio shims out of app.js (R3a) (#893) 2026-07-11 22:44:03 +02:00
section-practice.js refactor(app): the host seam + carve section practice out of app.js (R3a) (#887) 2026-07-11 20:58:41 +02:00
settings-io.js refactor(app): carve settings backup + plugin updates out of app.js (R3a) (#885) 2026-07-11 19:42:54 +02:00
tuning-display.js refactor(app): carve the tuning-display helpers out of app.js (R3a) (#884) 2026-07-11 19:37:44 +02:00
viz.js refactor(app): carve the viz layer out of app.js — and delete the loader seam (R3a) (#880) 2026-07-11 18:41:52 +02:00