Skip to content

fix: safely recover stale OMP secondmate markers on relaunch - #254

Merged
dnth merged 5 commits into
mainfrom
fm/fm-boatmate-relaunch-marker
Oct 16, 2026
Merged

dnth merged 5 commits into
mainfrom
fm/fm-boatmate-relaunch-marker

Conversation

@dnth

@dnth dnth commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Intent

Fix the remote OMP second-mate relaunch refusal that prevents Boatmate from restarting after suspension and a Firstmate code update, so InfoConnect builds can run there. The observed sequence was: wake fix PR #251 merged; Firstmate updated from 197f71a to 85a5f00 while Boatmate was suspended and its update was skipped; compute wake and remote doctor restored readiness; the next update synced Boatmate to 85a5f00; fm-spawn.sh boatmate --secondmate then refused with “OMP secondmate home has an unowned or malformed primary-integration marker ... refusing duplicate launch.” The likely cause was an older loaded-extension marker and/or marker PID no longer matching the dead lock owner; prove the cause from code and the observed error and reproduce in a fixture with an old-version marker plus distinct dead lock and marker PIDs. AC1 requires that proof in PR text and receipt. AC2 requires a regression reproducing the post-update, post-suspension refusal and preserving refusals for live owners, symlink, non-file, and unverifiable state. AC3 requires PR text with this exact post-merge sequence: bin/fm-compute-wake.sh boatmate; bin/fm-on.sh boatmate fm-remote-doctor.sh --fix; bin/fm-update.sh; bin/fm-on.sh boatmate fm-remote-secondmate-control.sh relaunch boatmate omp - -. The fixture must exercise the remote relaunch owner end to end with distinct dead lock and marker PIDs and an updated extension. Recovery must run through fm-remote-secondmate-control.sh relaunch; do not clear or bypass the duplicate-launch guard or use fm_omp_clear_stale_runtime_markers on a live or unknown marker. Recover only an owned stale marker after proving owners absent and the marker/runtime/history are valid; live, foreign, or unverifiable marker state must refuse. If the owner path cannot safely recognize the observed marker, report the exact gap rather than widening the guard. Firstmate will gather any live evidence and perform the real Boatmate relaunch after merge; this worker must perform no live Boat actions, no state edits, no sandbox recreation, and no credential output. AC4 requires that safety statement plus a secret scan. Validate with the full No-Mistakes run; drive eligible gates, escalate any ask-user finding under its canonical key, and report the PR URL and green-check outcome when CI first passes.

What Changed

  • Fix OMP secondmate relaunch recovery for an owned stale primary marker after an update. The reported “unowned or malformed primary-integration marker” refusal comes from direct spawn requiring the current extension hash and matching marker/lock PIDs; an older hash or distinct dead PIDs triggers it. The relaunch owner now checks runtime identity, validates older hashes against recorded fast-forward history, and proves both owners absent before retiring runtime markers. Saved sessions remain intact; live, foreign, malformed, symlinked, non-file, or unverifiable state still refuses recovery.

  • Add regressions for direct-launch refusals and remote owner-path recovery with an updated extension, an old-version marker, and distinct dead lock and marker PIDs. Coverage also checks uncertain process probes and retained-session preservation. Recovery uses fixture homes; live Boat actions, live state edits, sandbox recreation, and credential output remain outside this change’s recovery procedure.

  • Document the recovery checks. Firstmate should perform the live Boatmate recovery after merge, in this exact order:

    bin/fm-compute-wake.sh boatmate
    bin/fm-on.sh boatmate fm-remote-doctor.sh --fix
    bin/fm-update.sh
    bin/fm-on.sh boatmate fm-remote-secondmate-control.sh relaunch boatmate omp - -

Risk Assessment

✅ Low: Recovery is bounded to verified stale markers, independently refuses live owners, and preserves the duplicate-launch guard and retained sessions.

Testing

All live scenarios and targeted OMP/lifecycle regressions passed. The broader restart fixture’s sync failure also reproduces at base. CLI evidence was captured; no Boatmate actions or source changes were made.

  • Live validation: ✅ go - 7 of 7 scenarios driven live against the product
Scenario Result Live Evidence
Relaunch after an extension update recovers an old marker with distinct dead owners and preserves the saved session ✅ pass live live-stale-recovery-startup.log; live-success-receipt.log
Relaunch refuses live marker or lock owners, including matching owner PIDs, without stopping them ✅ pass live live-live-marker.log; live-matching-live-owners.log; live-live-lock.log
Permission-denied owner probes refuse recovery and preserve artifacts ✅ pass live live-permission-marker.log; live-permission-lock.log
A marker naming a foreign runtime refuses recovery ✅ pass live live-foreign-runtime.log
Unexplained versions, missing history, and uncommitted extension changes refuse recovery ✅ pass live live-unknown-version.log; live-missing-history.log; live-dirty-closure.log
Malformed, symlink, and directory markers refuse recovery without removal ✅ pass live live-malformed.log; live-symlink.log; live-directory.log
An unverifiable lock owner refuses recovery and preserves session artifacts ✅ pass live live-invalid-lock.log
Evidence: Live recovery and safety-refusal transcripts
=== live-stale-recovery-startup.log ===
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3917240 dead_marker_pid=3917241
relaunched nm-marker-48154681 harness=omp from=omp model=default effort=default backend=herdr endpoint=fm-remote:w3:p2 worktree=~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate


=== live-success-receipt.log ===
$ fm-remote-secondmate-control.sh state nm-marker-48154681
alive
Loaded primary marker:
sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
3922679
~/.bun/bin/omp
~/.bun/bin/omp
Lock PID: 3922679

Durable session pointer:
~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate/state/omp-sessions/retained.jsonl

Retained session first record:
{"type":"session","version":3,"id":"disposable","timestamp":"2026-10-16T00:00:00Z","cwd":"~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate"}

Relaunch transaction:
v1
task=nm-marker-48154681
phase=complete
ts=2026-10-16T02:33:05Z
backend=herdr
endpoint=fm-remote:w3:p2
worktree=~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate
kind=secondmate
from_harness=omp
from_model=default
from_effort=default
to_harness=omp
to_model=default
to_effort=default
worktree_head=7ac06c96d7478de17092dce622041dac1e39f8f1
worktree_dirty=no
children=0
note=none
exit_result=already-stopped
relaunch_tx=3917505.20261016T023253Z.27226

Real OMP terminal:
 Update Available
 New version 18.11.1 is available. Run: omp update
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 $ bin/fm-session-start.sh


 ================================================================================
 SESSION START - ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate
 ================================================================================

 LOCK
 --------------------------------------------------------------------------------
 lock acquired: harness pid 3922679

 BOOTSTRAP
 --------------------------------------------------------------------------------


 ⠏ Running… (⎋ to cancel)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

 π > ⬢ no-model 🙈 > 📁 …15ZB036HH7Y4QGP45NJZB5/.test-phase/mate > ⑂ main > ◫ 22K/? ⟲ ▶─────────────────────────────────
╰─                                                                                          ⇧⇥ to change thinking effort


=== live-live-marker.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker owner is still live; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-matching-live-owners.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker owner is still live; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-live-lock.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP home lock owner is still live; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-permission-marker.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch permission omp - -
Probe-only kernel PID 2 returns EPERM; never signaled.
exit=1
error: OMP primary marker owner is unverifiable; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: permission's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/permission

artifacts_preserved=True; refusal_correct=True


=== live-permission-lock.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch permission omp - -
Probe-only kernel PID 2 returns EPERM; never signaled.
exit=1
error: OMP home lock owner is unverifiable; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: permission's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/permission

artifacts_preserved=True; refusal_correct=True


=== live-foreign-runtime.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker runtime does not match the recorded home; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-unknown-version.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker version is not explained by recorded fast-forward history; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-missing-history.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch permission omp - -
exit=1
error: OMP primary marker version is not explained by recorded fast-forward history; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: permission's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/permission

artifacts_preserved=True; refusal_correct=True


=== live-dirty-closure.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch permission omp - -
exit=1
error: OMP primary closure differs from the recorded home revision; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: permission's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/permission

artifacts_preserved=True; refusal_correct=True


=== live-malformed.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker is malformed; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-symlink.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker is not an ordinary file; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-directory.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP primary marker is not an ordinary file; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True


=== live-invalid-lock.log ===
COMMAND: fm-remote-secondmate-control.sh relaunch probe omp - -
old_version=sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
current_version=sha256:7fe39ebbf64e7bf7299f775b3d67cd50fa88f9af64b877e982e4e9d3840f3ad9
dead_lock_pid=3549969; dead_marker_pid=3549972; live_pid=3549988
exit=1
error: OMP home lock owner is unverifiable; refusing relaunch
error: the OMP secondmate endpoint is not authoritatively absent after graceful exit
error: probe's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at ~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/mate

artifacts_preserved=True; live_owner_survives=True
Evidence: Remote lifecycle regression
tar: ./.test-phase/tmp/fm-remote-secondmate-e2e.lwuC3m/remote-root/.claude/skills: Cannot open: Permission denied
tar: ./.test-phase/tmp/fm-remote-secondmate-e2e.lwuC3m/remote-root: file changed as we read it
tar: Exiting with failure status due to previous errors
ok - overlapping remote home provisioning serializes through publication and rollback
ok - remote seed rollback preserves serialized competing routes
ok - unknown readiness preserves its route and brief for reconciliation
ok - remote seeding checks, repairs, and re-checks readiness, then stops on a remaining gap
ok - remote seeding proceeds once the repair closes every gap
ok - remote seed registers the route and provisions the whole home and project clone on that host
ok - remote inheritance rejects incomplete and superseded payload generations
ok - mixed local and remote routes validate without migration
ok - remote spawn launches on the remote-local backend and records a host-qualified route
ok - markerless remote liveness distinguishes live, unreachable, and missing endpoints without route loss
ok - legacy and mismatched remote endpoints fail closed before backend access
ok - non-herdr remote endpoints are refused without changing either route
ok - remote spawn serializes inheritance through launch publication
ok - marked send and routed reply complete through the existing parent correlation owner
ok - partial remote inheritance retains reread intent through bootstrap convergence
ok - config push and bootstrap serialize remote inheritance convergence
WARNING: watcher still down (same stale episode; last beat: 53s ago, grace 300s) - full banner already printed this episode.
WARNING: queued wakes pending - drain them with bin/fm-wake-drain.sh before anything else.
ok - remote inherited config retains and retries a failed live reread nudge
ok - a remote mate's merged-PR reply settles its landing through the reconcile carrier check and retries without duplication
ok - fleet snapshot projects mixed local and remote structured state
ok - remote update imports and fast-forwards the persistent home on its configured host
ok - the remote restart verb delegates to the host-local control plane and refuses before stopping anything
ok - startup repairs remote readiness before probing without relaunching
ok - startup reports alive legacy backends without changing their routes
ok - unreachable remote state remains unknown with no local respawn or failover
ok - remote retirement refuses child work, then removes only its own endpoint while a shared-session sibling survives
ok - remote spawn refuses a retired route without republishing its metadata
ok - remote OMP delivery replaces the reproducible typed no-turn regression with one bound inbox request, programmatic turn, and handled acknowledgement
ok - a successful remote OMP generation slept and restored on delivery retires its prior runtime markers and delivers exactly once
ok - a failed remote OMP bind retires its generation artifacts, preserves the retained session, and accepts the next launch
ok - Remote failed binds repair absent and malformed pointers without deleting saved sessions
fixture marker contents:
sha256:85dd6dcc1bc69e6976b07212339bb4877b204e709b58315830edc0f261dc92b8
212955
~/.pixi/envs/nodejs/bin/node
~/.no-mistakes/worktrees/dd71c22cc6d7/01M515ZB036HH7Y4QGP45NJZB5/.test-phase/tmp/fm-remote-secondmate-e2e.lwuC3m/remote-root/bin/omp
fixture current closure=sha256:e67c87ebf777f24d80c43c9729b781e43581792a75463b5346de280bbe4355f5 lock_pid=212954 alive=no
ok - a remote OMP relaunch pins the herdr backend even when the remote home configures tmux
ok - remote OMP primary, fallback, result metadata, pane launch, and existing safety refusals hold end to end
ALL TESTS PASSED
Evidence: Test summary and baseline limitation
Live validation: real remote-secondmate-control relaunch completed on real Herdr + OMP in a disposable home after an extension update with distinct dead marker/lock PIDs. The user shell command !bin/fm-session-start.sh inside OMP claimed the real session lock without a model credential. State returned alive, marker and lock agreed on the new live PID, and the saved-session pointer was retained.
All live refusal cases passed: live marker, equal live owners, distinct live lock, permission-denied marker and lock probes, foreign runtime, unexplained version, missing history, dirty closure, malformed marker, symlink marker, directory marker, and invalid lock. Artifacts and owners survived refusals.
Targeted OMP behavior functions, fm-omp-secondmate.test.sh, and fm-remote-secondmate-lifecycle-e2e.test.sh passed. The broader restart suite T2 fixture-sync failure reproduces on the base revision; isolated retry had the same setup limitation.
No Boatmate actions, operator-data edits, credentials, source changes, linters, or static analysis. Disposable Herdr/OMP processes stopped, disposable workspace directories removed, and git status was clean. Evidence is CLI output because this change concerns shell lifecycle behavior rather than UI layout.
- Outcome: 🔧 2 issues found → auto-fixed ✅ across 2 runs (44m12s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (2) ✅
  • 🚨 bin/fm-control-lib.sh:288 - Intent requires “live, foreign, or unverifiable marker state must refuse.” With a missing Herdr endpoint and a valid marker whose live PID equals the lock PID, the new condition [ "$marker_pid" != "$owner_pid" ] skips refusal; line 293 signals that process, then cleanup removes its marker after it exits. Thus recovery can kill a live owner instead of refusing. Enforce live-owner refusal before signaling in this shared preparation boundary, preserving ordinary graceful exit separately. Related sites: bin/fm-control-lib.sh:306 repeats the equality exemption; tests/fm-secondmate-restart.test.sh:1205 and :1276 configure matching owners and expect forced-stop success; docs/configuration.md:331 promises live-owner refusal. This conflicts with explicit acceptance criteria and requires reconciliation.

🔧 Fix applied.
3 issues (2 errors, 1 warning) still open:

  • 🚨 bin/fm-control-lib.sh:288 - Intent requires “live, foreign, or unverifiable marker state must refuse.” With a missing Herdr endpoint and a valid marker whose live PID equals the lock PID, the new condition [ "$marker_pid" != "$owner_pid" ] skips refusal; line 293 signals that process, then cleanup removes its marker after it exits. Thus recovery can kill a live owner instead of refusing. Enforce live-owner refusal before signaling in this shared preparation boundary, preserving ordinary graceful exit separately. Related sites: bin/fm-control-lib.sh:306 repeats the equality exemption; tests/fm-secondmate-restart.test.sh:1205 and :1276 configure matching owners and expect forced-stop success; docs/configuration.md:331 promises live-owner refusal. This conflicts with explicit acceptance criteria and requires reconciliation.
  • 🚨 bin/fm-control-lib.sh:293 - AC2 requires “preserving refusals for live owners.” With a missing endpoint, a valid dead marker PID, and a distinct live lock PID, this path signals the lock owner and clears artifacts after it exits. After suspension, that lock PID may belong to an unrelated process. Round 1 fixed live-marker refusal but left this sibling: the new check probes only marker_pid before "$stop_cmd" "$owner_pid". Refuse live lock owners before signaling; graceful exit already precedes preparation. Related sites: bin/fm-control-lib.sh:297 accepts signal-induced absence; tests/fm-secondmate-restart.test.sh:1019 covers only a lock owner that survives signaling; docs/configuration.md:331 promises live-owner refusal.
  • ⚠️ tests/fm-secondmate-restart.test.sh:1392 - The new FM_TEST_OMP_RESTART_ONLY mode adds an optional execution path that skips the remaining restart suite. Neither the requested regression nor full validation requires this selector. Remove the conditional shortcut and retain the regressions in the ordinary suite.

🔧 Fix applied.
✅ Re-checked - no issues remain.

🔧 **Test** - 2 issues found → auto-fixed ✅
  • 🚨 bin/fm-control-lib.sh:278 - A failed kill -0 probe is treated as proof of absence, including EPERM. Through the real remote relaunch command, a valid marker naming live root-owned PID 2 passed preparation despite 'Operation not permitted'; relaunch replaced its marker with owner PID 2014483 and attempted another launch while PID 2 remained alive. The lock-owner probe has the same ambiguity. Distinguish confirmed absence from permission errors and other unknown results, refusing and preserving artifacts whenever either owner cannot be proven absent.
  • 🚨 live validation verdict: no-go (7 of 8 scenarios were driven live against the product); failed: Relaunch refuses an owner whose liveness probe returns permission denied
  • Live validation: ❌ no-go - 7 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Relaunch recognizes an old marker after a tracked update with distinct dead lock and marker PIDs ✅ pass live live-recovery-final.log; remote-lifecycle.log
Relaunch refuses live marker owners whether their PID equals or differs from the lock PID ✅ pass live live-refusals.log: live-marker-equal and live-marker-distinct
Relaunch refuses a live lock owner and leaves that process running ✅ pass live live-refusals.log: live-lock
Relaunch preserves foreign-runtime and malformed markers ✅ pass live live-refusals.log: foreign-runtime and malformed-marker
Relaunch refuses symlink and directory markers without removing them ✅ pass live live-refusals.log: symlink-marker and directory-marker
Relaunch preserves artifacts when lock ownership or marker history cannot be verified ✅ pass live live-refusals.log: unverifiable-lock and unknown-history
Relaunch refuses an owner whose liveness probe returns permission denied ❌ fail live permission-probe.log
Post-update relaunch reaches a fully ready replacement OMP session ⏸️ untested no The simulated remote lifecycle passed, but native attempts did not complete readiness. The first native pane inherited the terminal server environment and was stopped. A cleared-environment retry enco…
  • TMPDIR="$PWD/.no-mistakes/test-tmp" bash tests/fm-remote-secondmate-lifecycle-e2e.test.sh — passed
  • bash tests/fm-secondmate-restart.test.sh with workspace-local temporary storage — setup refusal; retried from an isolated source copy
  • bash .no-mistakes/test-code/tests/fm-secondmate-restart.test.sh — stopped at an earlier non-OMP restart fixture; the base commit reproduced the same failure
  • bash .no-mistakes/test-code/tests/fm-omp-secondmate.test.sh — passed
  • bash .no-mistakes/test-code/tests/phase-omp-driver.sh — executed the four existing OMP capability, preparation, restart, and closure-update regressions; passed
  • bash .no-mistakes/live-refusals.sh — real remote relaunch command against an isolated Herdr server
  • bash .no-mistakes/live-recovery.sh and recovery retries — native post-update recovery attempts
  • bash .no-mistakes/permission-probe.sh — reproduced permission-denied owner bypass through the real remote relaunch command
  • Scanned the change diff and evidence logs for common credential signatures; stopped disposable servers, removed fixtures, and verified source remained unchanged

🔧 Fix applied.
✅ Re-checked - no issues remain.

  • Live validation: ✅ go - 7 of 7 scenarios driven live against the product
Scenario Result Live Evidence
Relaunch after an extension update recovers an old marker with distinct dead owners and preserves the saved session ✅ pass live live-stale-recovery-startup.log; live-success-receipt.log
Relaunch refuses live marker or lock owners, including matching owner PIDs, without stopping them ✅ pass live live-live-marker.log; live-matching-live-owners.log; live-live-lock.log
Permission-denied owner probes refuse recovery and preserve artifacts ✅ pass live live-permission-marker.log; live-permission-lock.log
A marker naming a foreign runtime refuses recovery ✅ pass live live-foreign-runtime.log
Unexplained versions, missing history, and uncommitted extension changes refuse recovery ✅ pass live live-unknown-version.log; live-missing-history.log; live-dirty-closure.log
Malformed, symlink, and directory markers refuse recovery without removal ✅ pass live live-malformed.log; live-symlink.log; live-directory.log
An unverifiable lock owner refuses recovery and preserves session artifacts ✅ pass live live-invalid-lock.log
  • python3 .test-phase/live.py exercised the real remote relaunch command and refusal boundaries.
  • bash .test-phase/recover.sh launched real Herdr and OMP; !bin/fm-session-start.sh claimed the session lock inside OMP.
  • bash .test-phase/capture.sh verified alive status, matching marker/lock ownership, completed relaunch, and retained session.
  • python3 .test-phase/permission.py and python3 .test-phase/history.py exercised permission and history refusals.
  • Executed four focused OMP behavior functions from tests/fm-secondmate-restart.test.sh.
  • bash .test-phase/code/tests/fm-omp-secondmate.test.sh passed.
  • bash tests/fm-remote-secondmate-lifecycle-e2e.test.sh passed.
  • Broader restart-suite attempts encountered a fixture-sync failure; the same T2 failure reproduced against the base revision.
  • Stopped disposable processes, removed temporary workspace directories, and verified clean git status.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@dnth
dnth merged commit bb51ff2 into main Oct 16, 2026
18 checks passed
@dnth
dnth deleted the fm/fm-boatmate-relaunch-marker branch October 16, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant