Skip to content

OpenCode secondmate never arms its own supervision watcher (isPrimaryRoot excludes secondmate homes) #582

Description

@boyangwang

Problem

On the OpenCode harness, a secondmate (a firstmate running in its own FM_HOME) never arms its own supervision watcher. Its .opencode/plugins/fm-primary-watch-arm.js shows WATCHER DOWN - SUPERVISION IS OFF (last beat: never) while a crewmate is in flight, so it receives no proactive wakes and has to hand-supervise.

Reproduced 2026-07-15 (OpenCode 1.18.0, GLM 5.2): a secondmate spawned a crewmate; state/.last-watcher-beat in the secondmate home was absent and no fm-watch.sh process existed for that home for the entire session.

Root cause

isPrimaryRoot(root, home) in .opencode/plugins/fm-primary-watch-arm.js returns false for any root that carries a .fm-secondmate-home marker:

if (existsSync(`${root}/.fm-secondmate-home`)) return false;

A secondmate home always has that marker, so ensureArm() returns "not-primary" on every session.idle and the watcher never arms. But a secondmate IS the primary of its own home and must arm its own watcher to supervise its own crewmates - consistent with the turn-end guard, which already "guards both the main primary and a secondmate's own primary session".

Proposed patch

Drop the blanket exclusion; keep only the home/root MISMATCH guard, which already prevents arming a foreign secondmate home. sessionOwnsLock() continues to gate arming to the lock-owning session, so this can never arm a foreign home's watcher.

-  if (existsSync(`${root}/.fm-secondmate-home`)) return false;
-  if (home && home !== root && existsSync(`${home}/.fm-secondmate-home`)) return false;
+  // A secondmate home carries a .fm-secondmate-home marker but IS the primary of its own
+  // home and must arm its own watcher to supervise its own crewmates. Only a home/root
+  // MISMATCH is disqualifying; a secondmate's own session has root === home.
+  // sessionOwnsLock() still gates arming to the session that owns this home's lock.
+  if (home && home !== root && existsSync(`${home}/.fm-secondmate-home`)) return false;

Offer

Happy to open a PR with this change plus a regression test if that is welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions