3.9 KiB
name, description
| name | description |
|---|---|
| dankvoice-bundle-swap-red-proof | Prove a dankvoice behavior test is red against the pre-change bundle by pointing DV_EXT at git show HEAD:dist/index.js, with the driver extracted from the bats heredoc into a pinned scratch directory. Use before claiming a new bats assertion is red-capable. |
Prove a new tests/behavior.bats assertion is red-capable — that it fails against the previous build, not just passes against the new one — without stashing, branching, or editing src/.
Why
tests/behavior.bats is a black-box suite: the plugin bundle is loaded through DV_EXT, so a different bundle is the red side. Stashing the fix would break the dist byte-identity pin test and the shared worktree.
Working recipe
cd ~/Projects/dankvoice # or the feature worktree: ~/Projects/wt-dv-*
bun run build # current src = the green side
git show HEAD:dist/index.js > /tmp/old-dist.js # the red side (pre-change bundle)
W=/tmp/dv-redproof # PINNED name; see traps below
rm -rf "$W" && mkdir -p "$W/bin"
cat > "$W/player.sh" <<'SH'
#!/usr/bin/env bash
printf '%s\n' "$*" >> "$DV_STUB_LOG"
for arg in "$@"; do case "$arg" in *.wav) cp "$arg" "$DV_COPY" ;; esac; done
sleep "${DV_HOLD:-0.1}"
SH
chmod +x "$W/player.sh"
ln -s "$W/player.sh" "$W/bin/pw-play"
printf '#!/usr/bin/env bash\nprintf "116\\talsa_output.usb-KT.0\\taudio/sink\\t*\\n"\n' > "$W/bin/wpctl"
chmod +x "$W/bin/wpctl"
# The driver lives inside the bats file as a heredoc: extract it verbatim.
end=$(grep -n '^TS$' tests/behavior.bats | cut -d: -f1)
sed -n "86,$((end - 1))p" tests/behavior.bats > "$W/driver.ts"
export DV_EXT="$PWD/dist/index.js" DV_STUB="$W/player.sh" DV_STUB_LOG="$W/player.log" \
DV_COPY="$W/played.wav" DV_OMPCONFIG=/dev/null DANKVOICE_CONFIG="$W/settings.json" \
DV_MODELS="$W/models.yml" DV_WPCTL=x DV_SELECT=""
for ext in /tmp/old-dist.js "$PWD/dist/index.js"; do
rm -f "$W/player.log" "$DANKVOICE_CONFIG"
DV_EXT="$ext" bun "$W/driver.ts" <scenario> 2>&1 | grep -E '^PLAYS|^CALLS|^NOTIFY|^SETTINGS'
done
The scenario name is the driver's third argv (speak, auto, repeat, humanizecycle, badurl, …); the bats -f test body's env (DV_PLAYER_BIN, DV_SETTINGS_JSON, DANKVOICE_VERBOSITY, …) is passed the same way. DV_SELECT holds the menu answers, |-separated, consumed in order.
Traps, each one cost a turn
- The scratch directory must be pinned by name.
ls -dt /tmp/tmp.*picks up other sessions' temp dirs, and thenplayer.shanddriver.tslive in different directories — the run silently does the wrong thing. - The stub must append to
$DV_STUB_LOG. The driver counts player invocations from that file; a stub that onlysleeps reportsPLAYS 0for both bundles and the whole proof reads as "fix does nothing". DV_EXTis required. Missing it yieldsCannot find package 'undefined'from the driver, which looks like a broken driver, not a missing env var.DV_SETTINGS_JSONsupports__PORT__(the driver substitutes the fixture port), so a preseed can name a prefixed route — needed whenever the test is about which endpoint got resolved.- Never run this while a
batsrun is in flight in the same repo:setup()runsbun run build, so two runs clobberdist/and the pin test.
Reading the result
Red side must show the defect (PLAYS 0, 644, a chat CALL with the wrong prefix, Invalid URL), green side the fix — assert on printed markers only (PLAYS, CALLS, CALL <url>, NOTIFY, SETTINGS). CALLS counts /audio/speech calls only; the rewrite call appears as its own CALL /…/chat/completions … sys=<full system prompt> line, which is how prompt-level knobs (verbosity, heckle) are observed.
Prefer this over a synthetic leak: if the check already caught a real leftover/failure once, that event is the sensitivity proof — say so in the commit message instead of faking one.