fix(wake): per-session lock and cursor so every session wakes, not just one
Both the cold-idle watcher and the Stop-hook drain defaulted to a single
lock (~/.murmur-coldidle-watch.lock) and a single cursor
(~/.murmur-wake-cursor) shared by every session on the host.
Consequences measured on 2026-08-26 with seven live sessions:
* only the lock holder polled the DB; every other watcher slept on flock
and never woke its own session;
* an inbound message therefore woke a random session rather than the one
holding the conversation context;
* the shared cursor made this worse — whichever session drained first
advanced it to the tip, so the message was gone for the others.
Over 23-26.08, 24 sessions ran the start skill, 13 actually launched a
watcher, and exactly one stood post at any moment.
Both scripts now derive their defaults from CLAUDE_CODE_SESSION_ID
(overridable via MURMUR_WAKE_SESSION_KEY), so each session gets its own
lock and its own cursor. flock still guards against duplicate instances,
but now only within one session. Explicit MURMUR_WATCH_LOCK /
MURMUR_WAKE_CURSOR keep overriding the defaults, and a run outside Claude
Code falls back to the legacy shared paths.
A per-session cursor starts out missing, which would make the first poll
read the whole inbound history as new, so both scripts now seed the cursor
to the current tip on first run: a session watches from its own start.
wake-drain-claude.sh additionally picks up the daemon path already in use
on the deployed copy (/opt/lifecoach/murmur), replacing the stale
mur-mur-v2 symlink default.
Verified: two watchers with different session ids run concurrently without
blocking, both seed to the live tip, and a single injected inbound message
wakes both exactly once. A
alexfrmn committed
bd7a0524589c930930b822fc43f68cfd4b34fcd1
Parent: 7208903