From 40d7ec9cfc050bde311fa1e79a83563b4706f88d Mon Sep 17 00:00:00 2001 From: Daan Aerts Date: Sun, 23 Aug 2026 23:31:32 +0200 Subject: [PATCH 1/2] fix(bin): recover legacy child endpoint records during forced secondmate teardown Forced teardown of a secondmate home refused outright on the first child task record written before the endpoint_task_id binding existed, stranding the whole home with no supported lifecycle action. Both recursive preflights over a secondmate's own children called the bare offline endpoint validator, which cannot settle that one record shape and returns the recoverable code 2. The stated reason for not wiring the live resolver in - that a recursive preflight holds no per-child metadata lock - no longer held: preflight_descendant_task_locks already acquires every descendant task's control and metadata lock and holds them until teardown exits. Route both loops through one shared validate_child_task_endpoint, which upgrades a legacy record through fm_backend_resolve_task_endpoint only while this teardown provably holds that exact child's own metadata lock, reads the live label proof as the child home (zellij and cmux scope runtime titles by owning home tag), and defers rather than deciding on the cheap pre-lock pass. Every other refusal, and a legacy record the live endpoint cannot prove, still refuses with nothing mutated. Also guard fm_backend_zellij_tab_matches_label against an unread tab list: an absent or unreachable zellij produces no output, and `jq -e` over empty input exits 0 on jq 1.6, so the label proof could pass vacuously and bind an endpoint nothing was read from. --- bin/backends/zellij.sh | 7 +- bin/fm-teardown.sh | 92 +++++++++++------ tests/fm-backend-zellij.test.sh | 24 +++++ tests/fm-secondmate-safety.test.sh | 155 +++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+), 30 deletions(-) diff --git a/bin/backends/zellij.sh b/bin/backends/zellij.sh index 56478f7db35..d06b5258864 100644 --- a/bin/backends/zellij.sh +++ b/bin/backends/zellij.sh @@ -304,7 +304,12 @@ fm_backend_zellij_pane_exists() { # fm_backend_zellij_tab_matches_label() { #