handoff: the player rules learned the hard way, and the dev-first lane for player changes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6897PWcUEwHiqZMcVnNF6
This commit is contained in:
teahubxyzandClaude Fable 5.1 committed 2026-10-21 09:36:43 +00:00
1 parent d0797bc2c3
commit b1c8e231d7
1 file changed
+17
+17
View File
@@ -58,6 +58,23 @@ do. Read ARCHITECTURE.md first.
- One static page, no build step, no framework, no keys in the page.
- STORAGE.md's contract (chai's DB adapter targets it).
## Player rules (each one cost a regression on the phone; don't relearn them)
- **Player changes go to `dev` first** (dev.gandora.lol), get tapped through on an iPhone, then merge to `main`.
Anything touching `startNow / toHolding / toPlaying / bed / crackleOn / prime / setSource` counts. Features that
don't touch the player (modes, DJ sheet, stats, covers) may go straight to main.
- Run `sh tools/harness.sh safari` as well as the Chrome modes: WebKit is the iPhone's engine (play() policy, one
audio session) and the Chrome loop mode currently hangs on hb-5.
- iOS ignores `audio.volume`. A level is baked into the sample (`makeCrackle(seconds, gain)`), never set on the element.
- Never set `state.playing = true` before `play()` resolves. The flag follows the promise (`playNow`); a refusal shows
TAP TO PLAY. Setting it early gives a "playing" UI with no sound and a play button that needs two taps.
- Only one `<audio>` carries the station. A second element (previews) can interrupt the first on iOS; after one
plays, expect the next `play()` on the main element to be refused and handled by TAP TO PLAY.
- The hold between tracks must keep `ended` firing: hold on a real looping clip with its own URL (silence when room
tone is OFF), never on `SILENCE`, which the `ended` handler ignores.
- The crackle bed is Web Audio and must never start over the music: `bedStart` refuses while the phase is playing and
the element is playing or a play() is pending.
## What's next (agreed directions, not started)
- Text embeddings for every sheet, audio embeddings (Gemini Embedding 2) for kept/reacted tracks; the taste map