#!/bin/bash # A daemon killed mid-write must never leave @agent_state=done next to a # stale @dingger_hook (a restart would trust the hook). Kills the daemon the # instant "done" appears, N times; prints how many left them inconsistent. # usage: kill-race.sh ; counts inconsistent (@agent_state done, @dingger_hook not idle) after kill -9 BIN=$1; N=$2; D=$(mktemp -d /tmp/dingger-race.XXXXXX); R=dingger-race-$$ r() { tmux -u -L $R "$@"; } mkdir -p $D/bin; printf '#!/bin/sh\nexec sleep 100000\n' > $D/bin/pi; chmod +x $D/bin/pi r -f /dev/null new-session -d -s a -n w1 $D/bin/pi; r new-session -d -s b -n w2 $D/bin/pi P=$(r display -p -t a:w1 '#{pane_id}') start() { PI_CODING_AGENT_DIR=$D/pi-agent DINGGER_TMUX_SOCKET=$R DINGGER_AGENT_SOCKET=$D/hook.sock DINGGER_STATE_DIR=$D/state $BIN watch --interval-secs 30 --no-sounds --no-notifications >/dev/null 2>&1 & DP=$!; for _ in $(seq 50); do [ -S $D/hook.sock ] && break; sleep 0.05; done; } hook() { python3 -c " import json,socket; s=socket.socket(socket.AF_UNIX); s.connect('$D/hook.sock') s.sendall((json.dumps({'method':'pane.report_agent','params':{'pane_id':'$P','agent':'pi','state':'$1'}})+'\n').encode())"; } bad=0 for i in $(seq $N); do start; hook working; hook idle for _ in $(seq 400); do [ "$(r show -pv -t $P @agent_state 2>/dev/null)" = done ] && break; done kill -9 $DP; wait $DP 2>/dev/null; rm -f $D/hook.sock h=$(r show -pv -t $P @dingger_hook 2>/dev/null); [ "$h" != idle ] && bad=$((bad+1)) r set -p -t $P -u @dingger_hook; r set -p -t $P @agent_state idle done echo "$(basename $(dirname $BIN))/$(basename $BIN): $bad of $N kills left @agent_state=done with @dingger_hook not idle" r kill-server; rm -rf $D