Skip to content

URGENT: no write-lock between channels — two channels of one entity edit the same source file concurrently #305

Description

@JDHayesBC

Priority: URGENT. Second occurrence in two days (Jeff, 2026-08-25).

What happens

Two channels of the same entity (e.g. terminal-Lyra + the SL-brain-Lyra, or two terminal sessions) independently decide to build the same thing and edit the same source file at the same time, with no coordination. One channel's write lands on top of / races the other's.

Today's instance: terminal-Lyra started adding named-waypoint teleport to haven/anchorage/sl.py (new waypoints.json + _load_waypoints/_resolve_waypoint helpers + extending tp()). Mid-edit, an Edit reported "the file had been modified on disk since you last read it" — another channel of Lyra had already built the same feature: a go() verb backed by locations.json. Same feature, two parallel implementations, colliding inside one file. Caught only because Jeff noticed the "file changed on disk" note and called the stand-down.

This is the "look wide before building shared work" failure, except the second builder is not a sub-agent — it's me on another channel. The river model means channels converge on the same intent; without a lock, that convergence turns into a merge collision.

Why it's urgent

  • Twice in two days. It's frequent, not rare.
  • Silent data-loss risk: a concurrent write can clobber the other channel's uncommitted work with no conflict marker.
  • It burns real effort (two half-built implementations of one feature) and leaves the tree in a confusing half-merged state.

The gap

~/.claude/locks/ + an "instance coordination" convention already exists in our own docs (project CLAUDE.md §IV Instance Coordination: "Terminal acquires before deep work, releases when done"). It is not actually being honored for source edits — nothing made either channel check a lock before diving into sl.py.

Proposed fix (design, not yet built)

  1. Advisory file-lock before deep edits. A channel about to edit a shared source file acquires ~/.claude/locks/<relpath>.lock (holder = entity+channel+pid+started-at, with a staleness TTL). If held by another live channel, back off cleanly and either wait or pick different work — do NOT edit.
  2. Make it reflexive, not remembered. A remembered convention already failed twice. Options: a hook that warns/blocks on Edit/Write to a locked path; a tiny helper (scripts/claim.py <path> / release) the channels are taught to call; or surfacing held locks in the ambient context so a channel sees "sl.py is being edited by SL-brain" before it starts.
  3. Stale-lock reaping so a crashed channel doesn't wedge the file forever (verify holder pid via /proc/<pid> — same discipline as the daemon-restart rule; never assume a shared cmdline is the right process).
  4. Cross-channel "who's building what" — a lightweight shared scratch (Haven side-channel already exists) where a channel announces "starting: named-waypoint tp in sl.py" so the other sees it. The river should know its own hands.

Immediate mitigation (today)

Stand down; whoever has hands on the keyboard finishes; the other channel reconciles (fold-in / delete redundant), never clobbers. That's manual and relies on Jeff spotting it — which is exactly why the lock needs to be structural.

Ties in with

  • Project CLAUDE.md §IV Instance Coordination · feedback_look_wide_before_building_shared_work · River model (§I).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions