Expand description
Cross-process advisory lock enforcing INV-15’s single-owner-process invariant, held for the
lifetime of a crate::DurableContext opened via
LocalBackend::open_execution_exclusive.
Two processes can independently derive the same ExecutionId — the P1 agent-turn adapter
keys it on (ConversationId, sqlite_path), so two CLI instances pointed at the same memory
database and the same conversation always agree on the id (#6122). Without a lock, both
processes race LocalBackend::open_execution’s plain SELECT-then-INSERT and both drive
next_step from 0, corrupting the journal (ReplayDivergence/ReplayIntegrity on whichever
process loses the race). ExecutionLock closes that race with a non-blocking, exclusive
flock(2) on a lock file named after the execution’s UUID.
§Why not zeph_common::pidfile::PidLockGuard
PidLockGuard (the primitive backing zeph-core::daemon::PidGuard and
zeph-scheduler::pidfile::PidFile) unlinks its lock file before its file descriptor closes
(see its Drop impl). That ordering is safe for a pid file acquired once at daemon startup and
released once at shutdown — vanishingly unlikely to race a concurrent acquirer — but is a real
flock+unlink TOCTOU hazard for a lock acquired and released once per conversation turn under
real contention (e.g. many CI agents sharing a testing database): a second process racing the
unlink window can open(O_CREAT) a fresh inode at the just-unlinked path and flock it
immediately, believing it holds the lock, while the first process’s descriptor — still open on
the now-orphaned original inode — has not actually released yet. ExecutionLock instead
mirrors zeph-session::log::SessionEventLog’s own AdvisoryLock: the lock file is never
unlinked. It is a permanent sentinel, and the kernel releasing the flock when the holding
process’s descriptors close (including on SIGKILL) is the only correctness signal — no
unlink/re-create race, no PID-liveness polling needed.
Structs§
- Execution
Lock - Holds the advisory lock for one
ExecutionIdwhile alive; releases it on drop.