Lock ordering is scope first, run second.
Rules:
- Compute the workspace scope from the git root or
DEADRECKON_SCOPE_ROOT. - Acquire the scope/task lock at
/Users/gdc/.deadreckon/locks/<scope>--<task>.lock. - Only after the scope lock is held, mutate files under
runstate/<scope>/runs/<run-id>/. - Never acquire locks in the reverse order.
- Release is idempotent; stale lock reclaim uses heartbeat age plus PID liveness.
Different scopes may run the same task key concurrently. A second run in the same scope/task is refused with the first run id and phase so the operator can attach, kill, or resume the owner.