--- name: dankvoice-bats-serialization description: "Run dankvoice bats suites without hangs: serialize builds on shared dist/, DV_HOLD is seconds, stub needs sleep&wait trap before hold, timing tests assert CALLS/at not tail PLAYS." --- # Dankvoice bats: serialization and hang-proofing ## Serialize builds on the shared artifact `tests/behavior.bats` setup runs `bun run build` into the repo's shared `dist/index.js` before EVERY test (`DV_EXT="$REPO/dist/index.js"`). Any second concurrent bats run, `bun run build`, or `bun run typecheck` racing the same repo contends on that file and can stall single tests past 60 s. NEVER run two bats processes (or bats + build) against `~/Projects/dankvoice` at the same time — including harness background jobs. If a suite gets backgrounded, kill it before launching any other repo command; re-run serially. ## The stub player's units and traps - `DV_HOLD` is in **seconds** (`sleep "${DV_HOLD:-0.1}"`), not ms. `DV_HOLD=1500` means a 25-minute "hung" test. Use `DV_HOLD=2` for multi-second holds. - The stub must sleep as `sleep "${DV_HOLD:-0.1}" &` + `wait $!`, with `trap 'printf "KILLED\n" >> "$DV_STUB_LOG"; exit 143' TERM` installed **before** the sleep: a foreground `sleep` defers the trap until the sleep finishes, so SIGTERM-kill tests (shutdown/interrupt pins) stay red and every kill test eats the full hold. - Keep the `cp *.wav "$DV_COPY"` loop when editing the stub — the byte-equality test depends on it. ## Timing-sensitive assertions The driver prints `PLAYS` from the stub log at scenario end (~800 ms settle), so with a long `DV_HOLD` in-flight playback is UNDERCOUNTED — assert `CALLS`/arrival timestamps, not tail `PLAYS`. The fixture stamps every request with `at=` (ms since driver start, comparable between CALL lines); prefetch overlap = `t2 - t1 < 1500` with `DV_HOLD=2` (sequential chain cannot answer inside 2000 ms). ## Diagnosing a hung bats test (deterministic recipe) 1. `timeout 45 bats -f "" tests/behavior.bats; echo rc=$?` — rc=124 confirms hang. 2. Launch the same test as a background job, then probe live: `pgrep -af "driver.ts|bats"` and `ps afx | grep -E "sleep|stub"` — a `sleep ` child with N seconds in the stub log names the culprit (usually DV_HOLD misuse). 3. Detached `(cmd &)` inside a temp shell is KILLED when the shell exits — use the harness background jobs for anything you must probe. 4. Direct driver repro: extract the heredoc with `sed -n '/cat > "$WORK\/driver.ts" <<.TS./,/^TS$/p' tests/behavior.bats | sed '1d;$d' > $W/driver.ts`, build a fresh ext, then run `bun $W/driver.ts ` with the env the setup block exports. Caveat: hand-made fixture env can yield different segment counts than bats — trust in-bats numbers for assertions.