Skip to content

fix(bin): reset FM_*_OVERRIDE for every spawned pane - #3700

Open
Valentino-Sole wants to merge 10 commits into
kunchenguid:mainfrom
Valentino-Sole:fm/fm-spawn-override-reset
Open

Valentino-Sole wants to merge 10 commits into
kunchenguid:mainfrom
Valentino-Sole:fm/fm-spawn-override-reset

Conversation

@Valentino-Sole

Copy link
Copy Markdown

Intent

Reset FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE for every spawned worker pane so child sessions inherit their own home scope instead of the parent home, fixing false WATCHER-DOWN alarms.

What Changed

  • bin/fm-spawn.sh now prefixes every pane launch line — not just KIND = secondmate — with a reset that leaves FM_ROOT_OVERRIDE, FM_STATE_OVERRIDE, FM_DATA_OVERRIDE, FM_PROJECTS_OVERRIDE, and FM_CONFIG_OVERRIDE genuinely unset (unset, not an empty assignment prefix, since consumers distinguish the two), so a worker pane can no longer inherit a foreign home's overrides from the launching process tree. The reset is spelled twice — the POSIX unset plus a status fish-path-guarded set --erase --global — because unset is not a fish builtin; both spellings discard only stderr and stay statement prefixes so a compound raw launch command runs entirely under the reset. The secondmate-only FM_HOME redirect stays behind it and remains secondmate-exclusive.
  • Added tests/fm-spawn-override-reset.test.sh, which drives real ship and secondmate spawns against a fake tmux pane, captures the literal send-keys -l payload, and replays it through a fake agent that reports its own environment under both the POSIX and fish pane shell families. tests/lib.sh gains shared FM_TEST_SPAWN_RESET_* launch-line literals, and the existing spawn, Kimi, Pi-extension, and secondmate-lifecycle suites were updated for the new prefix (the Pi follow-up e2e now waits for a rendered pane).
  • .gitignore ignores .squish/, with tests/fm-gitignore-config.test.sh asserting that .no-mistakes/, .lavish/, and .squish/ are ignored as directories and leave git status --porcelain clean. docs/configuration.md documents the reset's scope, its unset-vs-empty semantics, that an operator's universal fish variable (set -Ux) deliberately survives it, and that fish panes print one cosmetic interpreter-path line from the shell probe.

Risk Assessment

✅ Low: The change is a well-bounded, unconditional launch-line prefix backed by a genuinely behavioral test (it replays the real captured launch line through an env-reporting fake agent rather than grepping the string), every exact-match assertion site was updated consistently through a single shared constant, and the POSIX pane behavior is directly verified silent and complete; the one residual - whether fish's unknown-command diagnostic is actually suppressed by the 2>/dev/null, which would make the fish assertion at tests/fm-spawn-override-reset.test.sh:258 fail on a developer machine that has fish - was raised in round 5 and explicitly accepted by the author as documented uncertainty.

Testing

Completed 1 recorded test check.

  • Outcome: ⏭️ skipped across 2 runs (1h59m49s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 infos
  • 🚨 bin/fm-spawn.sh:3105 - Intent requires "Reset FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE for every spawned worker pane so child sessions inherit their own home scope instead of the parent home", but SPAWN_OVERRIDE_RESET_VARS covers only the five FM__OVERRIDE names; FM_HOME is neither reset nor pinned for ship/scout panes (the FM_HOME redirect at :3070 stays secondmate-only), and tests/fm-spawn-override-reset.test.sh:221 asserts the opposite ("ship spawn must still hand the launching firstmate's FM_HOME to the worker"). This is not just wording: the same failure class stays reachable. bin/fm-wake-lib.sh:7 resolves FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}", so an inherited FM_HOME takes precedence and the now-unset FM_ROOT_OVERRIDE changes nothing. Concrete path: bin/backends/tmux.sh:69 starts the shared tmux server from whichever process spawns first, and that server passes its startup environment to every later pane; if a secondmate (FM_HOME=<subhome>) starts it, a ship pane the PRIMARY later spawns inherits FM_HOME=<subhome> and its watcher/fm-.sh helpers read the secondmate's state dir - the WATCHER-DOWN false alarm this change targets. The reverse case is equally reachable: a secondmate spawning a ship worker writes the brief and meta under <subhome>/state (fm-spawn.sh:275), but the pane with FM_HOME unset resolves FM_HOME=FM_ROOT, the main checkout. bin/backends/herdr.sh:1458 already unsets FM_HOME together with the same five overrides when starting its server, for exactly this stated reason, so FM_HOME belongs in this boundary too. A bare unset is not sufficient (it breaks the secondmate-launched ship case); pin FM_HOME=<launching firstmate's resolved home> in the launch line for every kind, the way CLAUDE_CONFIG_DIR is pinned at :3051, with the secondmate redirect overriding it. Please confirm whether omitting FM_HOME was intended before this merges.
  • ⚠️ .gitignore:7 - Commit 0df6e84 in this branch added .squish/squish.db, a 724 KB SQLite blob, and 22a1719 removed it again, so the working tree is clean but the blob still lives in the branch's commit objects. Recent main history (75b2de2 "fix: copy PR URLs from durable records (fix: copy PR URLs from durable records #3648)") looks squash-merged, which would keep it out of main - but if this branch is ever merged with history preserved, the blob is permanent and only removable by a history rewrite, exactly the hazard tests/fm-gitignore-config.test.sh now documents. Confirm the merge is a squash, or rewrite the branch to drop the blob.
  • ℹ️ bin/fm-spawn.sh:3105 - The fish guard is a PATH command lookup, so any executable named status on the pane's PATH that exits 0 makes set --erase ... run in a POSIX pane. Verified locally: dash -c &#39;unset FOO; set --erase FOO; echo LAUNCHED&#39; prints "set: Illegal option --" and never reaches the echo - dash and /bin/sh abort the whole command line, so the pane would be created with no agent started and read as a wedged worker (bash is benign, rc=2 with a usage message). The failure mode is silent and costs the launch, not just a stray line. A guard that cannot be shadowed by PATH would be safer; note that the obvious alternative test -n &#34;$FISH_VERSION&#34; is what the csh reasoning in the comment rules out, since csh aborts on an undefined variable.
  • ℹ️ docs/configuration.md:288 - The doc claims the reset "takes effect whatever login shell the pane runs", and the comment at bin/fm-spawn.sh:3097 reasons explicitly about keeping a csh pane's launch intact, but in csh/tcsh unset removes shell variables only - environment variables need unsetenv - so on a csh pane the reset is a silent no-op and the inherited overrides survive exactly as before. bin/backends/tmux.sh:174 does list tcsh|csh as recognized pane shells. Practically the impact is near zero because the pre-existing spawn_send_text_line &#34;$T&#34; &#34;export GOTMPDIR=...&#34; at bin/fm-spawn.sh:3139 is already invalid csh, so a csh pane is not a working pane today. Either drop the csh reasoning and soften the doc claim to the POSIX family plus fish, or add the unsetenv spelling; as written the comment and doc overstate the guarantee.

🔧 Fix: no change: FM_HOME redirect intentionally stays secondmate-only
3 issues (1 warning, 2 infos) still open:

  • ⚠️ bin/fm-spawn.sh:3105 - The fish half of the reset uses set --erase with no scope flag. In fish an unscoped erase removes the variable from the smallest scope in which it is defined, and universal is one of those scopes — universal variables are persisted to ~/.config/fish/fish_variables and shared by every fish session on the machine. FM_ROOT_OVERRIDE is a documented operator-facing override (docs/configuration.md:283, and the env template at docs/configuration.md:796), so a fish operator setting set -Ux FM_ROOT_OVERRIDE /path/to/firstmate is a realistic configuration. Concrete path: that operator spawns any worker; the pane's fish reads the launch line, status fish-path succeeds, and set --erase FM_ROOT_OVERRIDE … runs. One of two things then happens, and both are wrong: either the universal variable is the smallest scope holding the name and it is deleted from disk — a silent, cross-session mutation of the operator's own shell config that outlives the pane and breaks every future fish session's root resolution — or a global env-imported copy shadows it, the erase hits only that copy, the exported universal is still in the pane's environment, and the reset silently does not do its job on exactly the shell it was added for. Both outcomes are invisible because stderr is discarded. Spelling it set --erase --global … confines the erase to the scope an inherited environment variable actually lands in; note the tradeoff that a universal-exported override would then survive the reset, which is why this is a scope decision for the author rather than a mechanical fix. The POSIX half is unaffected — unset in a POSIX shell has no persistent-scope equivalent.
  • ℹ️ tests/fm-spawn-override-reset.test.sh:235 - test_fish_pane_launch_line_clears_overrides skips outright when fish is absent, and neither CI lane installs it (.github/workflows/ci.yml runs bare ubuntu-latest / macos-latest; no fish appears anywhere in the workflows). The skip is also invisible to the runner's gate accounting: bin/fm-test-run.sh:1421 only treats a skip: line as a gate skip when it is the FIRST non-empty output line, and test_ship_spawn_clears_overrides_set_in_parent_env prints ok - … before it. So the fish spelling — the half of the fix that carries the set --erase scope risk above and the whole reason the reset is written twice — will report green in CI without ever having run. Either add fish to the portable serial lane, or make the skip a declared gate-skip token so its absence is at least visible.
  • ℹ️ bin/fm-spawn.sh:3104 - Recorded for the audit trail, no action expected: the stated intent names "FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE", but SPAWN_OVERRIDE_RESET_VARS covers only the five FM_*_OVERRIDE names and FM_HOME is deliberately left inherited for ship/scout panes. The author adjudicated this in the previous round ("Keine Codeaenderung, bewusst so"), and the code, the comment at bin/fm-spawn.sh:3072-3075, docs/configuration.md:288 and tests/fm-spawn-override-reset.test.sh:221 all agree with that decision — it is the intent sentence that is broader than the shipped scope, not the implementation that is inconsistent with itself.

🔧 Fix: scope fish override erase to global scope
3 infos still open:

  • ℹ️ docs/configuration.md:288 - The fix round scoped the fish erase to set --erase --global (bin/fm-spawn.sh:3105), which is right for the inherited-environment case but makes the doc's absolute wording no longer true for the one shell it names. In fish, an exported universal variable (set -Ux FM_STATE_OVERRIDE /some/home/state, a documented operator-facing override per docs/configuration.md:283 and the env template at :796) lives in universal scope, is exported to children, and is untouched by a global-scoped erase. Concrete path: a fish operator with that universal set spawns a ship worker; the pane's fish imports the parent's copy as global, set --erase --global removes only that global copy, and the still-exported universal value is handed to the agent, so the worker's fm-*.sh helpers resolve /some/home/state. Line 287 ("unsets all five ... in the launch line of every spawned pane") and line 288 ("takes effect whatever login shell the pane runs, including fish") both promise more than the code delivers. The behavior itself is defensible - a universal variable is the operator's own machine-wide config, not a foreign home leaking through the launching process tree, which is the failure class the intent names - so the fix is to the sentence, not the flag. Since it is a deliberate scope tradeoff the author chose in the previous round, confirm the wording before narrowing it.
  • ℹ️ bin/fm-spawn.sh:3105 - The 18-line comment above this line explains the double spelling, the status guard, why only stderr is discarded, and why both stay statement prefixes - but says nothing about --global, which the fix round added and which is load-bearing in a non-obvious way. Unscoped, fish's set --erase targets the smallest scope holding the name, so dropping the flag would let the erase delete a persisted universal variable out of the operator's ~/.config/fish/fish_variables, a cross-session mutation that outlives the pane. In a comment block this dense, an unexplained flag reads as removable noise to the next editor. One clause - global is where fish puts an inherited environment variable, and confining the erase there keeps it from reaching the operator's persisted universal config - would pin the decision.
  • ℹ️ tests/fm-spawn-dispatch-profile.test.sh:134 - The exact ~230-character reset prefix is now hardcoded in four test files: tests/fm-spawn-override-reset.test.sh:39 (RESET_PREFIX), tests/fm-kimi-harness.test.sh:208 and :465, tests/fm-spawn-dispatch-profile.test.sh:134 and :387, and a partial copy in tests/fm-secondmate-lifecycle-e2e.test.sh:127. This fix round already had to touch five of those six sites just to add one word (--global), which is the drift cost showing up in practice: a site missed in a future edit fails with a full-string diff that says nothing about which token moved. Hoisting the literal into one shared constant in tests/lib.sh (a plain string constant, not something derived by reading bin/fm-spawn.sh) and referencing it from all six keeps the exact-launch-line assertions intact while making the next spelling change a one-line edit.

🔧 Fix: document fish --global scope and share test reset literal
4 infos still open:

  • ℹ️ bin/fm-spawn.sh:3113 - The POSIX half of the reset carries no stderr redirection: unset $SPAWN_OVERRIDE_RESET_VARS; runs first on every pane, and unset is not a fish builtin, so a fish pane prints fish's unknown-command diagnostic (command name plus the caret-underlined source line) into the pane on every single spawn, before the status fish-path guard is even reached. The comment block directly above claims the cost on a fish pane is "one printed path" (from status fish-path's stdout) and "costs no pane its launch" - the launch part is right, the noise accounting is not: it is that path plus a multi-line error, on exactly the shell the second spelling was added to support. tests/fm-spawn-override-reset.test.sh:test_posix_pane_reset_is_quiet_and_complete asserts quietness only for sh/dash/bash, and test_fish_pane_launch_line_clears_overrides asserts nothing about pane output, so nothing in the suite contradicts the comment. Spelling it unset $SPAWN_OVERRIDE_RESET_VARS 2&gt;/dev/null; silences it and stays csh-parseable (one redirection, not the "second redirection" the comment rules out) - though it does not help csh, where unset ... 2 would then complain about a numeric variable name on stdout. Since the comment reasons explicitly about what gets discarded and why, confirm the noise tradeoff was intended rather than changing it silently.
  • ℹ️ bin/fm-spawn.sh:3147 - Bounding what the new fish spelling actually buys, in case the doc wording is read more broadly than intended. Two sibling text lines are sent into the same pane just before the launch line and are still POSIX-only: spawn_send_text_line &#34;$T&#34; &#34;export GOTMPDIR=$TASK_TMP/gotmp&#34; (:3147) and spawn_send_text_line &#34;$T&#34; &#34;export TRACEPARENT=$SPAWN_TRACEPARENT&#34; (:3152). fish has no export builtin - it answers export FOO=bar with an "Unsupported use of '='" error and sets nothing - so on a fish pane the worker's agent and its go build/go test children never receive GOTMPDIR, and TRACEPARENT is never set (which incidentally makes the pre-existing POSIX-only unset TRACEPARENT at :3115/:3154/:3162 harmless on fish rather than a second leak). Net effect: this change makes the FM_*_OVERRIDE reset fish-correct, which is a real improvement, but a fish pane is still not a fully working pane. docs/configuration.md:288 only claims the reset works on fish, so it is accurate as written; flagging so the fish half is not mistaken for general fish pane support. No change requested inside this change's scope.
  • ℹ️ bin/fm-spawn.sh:3112 - Audit trail only, no action expected - re-verified against the current code, unchanged since the author adjudicated it in round 1 ("Keine Codeaenderung, bewusst so"). The stated intent names "FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE", but SPAWN_OVERRIDE_RESET_VARS covers only the five FM_*_OVERRIDE names; FM_HOME is neither unset nor pinned for ship/scout panes, and the FM_HOME redirect at bin/fm-spawn.sh:3070 remains secondmate-only. The implementation, the comment at :3075-3076, docs/configuration.md:290 and tests/fm-spawn-override-reset.test.sh ("ship spawn must still hand the launching firstmate's FM_HOME to the worker") are all mutually consistent with the author's decision - it is the intent sentence that is broader than the shipped scope, not the code that is inconsistent with itself.
  • ℹ️ .gitignore:7 - Recorded so the author sees the branch's real blast radius: the pipeline's fix round (commit 22a1719) added .squish/ to the repository-wide .gitignore and 39 lines of new coverage in tests/fm-gitignore-config.test.sh, neither of which relates to the FM_*_OVERRIDE reset this branch is about. It was self-remediation for the fixer's own accidental commit of a 724 KB SQLite memory database in 0df6e84. The hygiene itself is sound and the tests are behavioral (they invoke git check-ignore and git status --porcelain against a real seeded repo rather than grepping the .gitignore text), so nothing here is wrong - but a branch named fm/fm-spawn-override-reset now also changes repo-wide ignore policy for a tool not every contributor runs. Related history finding was already reviewed and dismissed by the author in round 1.

🔧 Fix: silence POSIX override unset on fish panes
1 warning still open:

  • ⚠️ bin/fm-spawn.sh:3116 - The newest fix-round commit (674896c, "silence POSIX override unset on fish panes") adds 2&gt;/dev/null to the POSIX half of the reset and rewrites the comment (:3105-3109) to claim that "Every command in the reset discards its own stderr ... without those redirections a fish pane would take fish's unknown-command diagnostic on every spawn". That claim is very likely false for fish, and I could not verify it here: no fish is installed in this worktree environment (command -v fish finds nothing), and CI installs none either (the round-2 finding on that was reviewed and dismissed), so nothing has ever executed this path. Source-level reasoning: a POSIX shell reports a missing command as part of executing that command, so its "command not found" IS covered by the command's own 2&gt;/dev/null - that is exactly why the status fish-path 2&gt;/dev/null guard is silent on sh/dash/bash, and tests/fm-spawn-override-reset.test.sh:test_posix_pane_reset_is_quiet_and_complete confirms it there. fish is different: it resolves the command name during job planning, before the job's redirections are established, and when resolution fails it fires fish_command_not_found and then emits a parser backtrace (fish: Unknown command: unset plus the caret-underlined source line) on the shell's own stderr, not on the job's redirected fd. If that holds, the added redirection changes nothing on a fish pane and the diagnostic still lands there on every spawn - and the unredirected unset TRACEPARENT; prepended at :3118/:3157/:3165 (pre-existing) would print a second one on every relaunch regardless. Concrete failure this creates: tests/fm-spawn-override-reset.test.sh:256-259 now asserts with = without for the fish replay, so on any developer machine that HAS fish the suite fails with "the reset wrote its own diagnostic into a fish pane", while CI stays green because the test skips at :233. Before merging, run that one test on a real fish (fish 3.4+) - it is precisely the right check. If it fails, either revert the 2&gt;/dev/null on the POSIX unset and restore the previous comment wording (accepting the noise, as the pre-existing unset TRACEPARENT lines already do), or gate the POSIX unset behind a guard fish fails silently on; do not leave the comment, docs, and test asserting a silence the shell does not actually provide.

🔧 Fix: no change: fish unset redirect accepted as-is
2 issues (1 warning, 1 info) still open:

  • ⚠️ tests/fm-secondmate-lifecycle-e2e.test.sh:128 - The fix round replaced the old positive assertion (assert_grep &#39;FM_CONFIG_OVERRIDE=&#39;) with assert_no_grep &#34;FM_CONFIG_OVERRIDE=$HOME_DIR/parent-config&#34;, but that pattern can never match the form fm-spawn.sh actually emits, so the guard can never fire. Concrete trace: assert_no_grep is grep -F -- &#34;$1&#34; (tests/lib.sh:323), i.e. an exact fixed string, and every path-valued env prefix in fm-spawn.sh goes through shell_quote (bin/fm-spawn.sh:1216-1220), which unconditionally wraps the value in single quotes -- see bin/fm-spawn.sh:3051 (CLAUDE_CONFIG_DIR=$(shell_quote ...)) and :3070 (FM_HOME=$sq_home). So a regression that carried the parent's config override into the pane would log FM_CONFIG_OVERRIDE=&#39;/tmp/.../main home/parent-config&#39;, never the unquoted FM_CONFIG_OVERRIDE=/tmp/.../main home/parent-config the pattern demands. The sibling line 127 in the same block proves the convention: it asserts FM_HOME=&#39;$SUB_ABS&#39; WITH the quotes, and passes. Net effect: line 128 passes unconditionally today and would keep passing if the leak it names were reintroduced. Real coverage for the reset comes only from line 128's neighbour, assert_grep &#34;$FM_TEST_SPAWN_RESET_POSIX&#34;. Fix is mechanical: quote the path in the pattern (FM_CONFIG_OVERRIDE=&#39;$HOME_DIR/parent-config&#39;) so it matches the emitted spelling.
  • ℹ️ bin/fm-spawn.sh:3116 - Audit-trail record only, no action expected -- re-verified against the current code and unchanged since you adjudicated it in round 1 ("Keine Codeaenderung, bewusst so") and again in round 4. The stated intent names "FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE", but SPAWN_OVERRIDE_RESET_VARS (bin/fm-spawn.sh:3115) covers only the five FM_*_OVERRIDE names; FM_HOME is neither unset nor pinned for ship/scout panes, and the FM_HOME redirect at :3070 remains secondmate-only. The implementation, the comment at :3078-3080, docs/configuration.md:290 and tests/fm-spawn-override-reset.test.sh:219 ("ship spawn must still hand the launching firstmate's FM_HOME to the worker") are all mutually consistent with that decision -- it is the intent sentence that is broader than the shipped scope, not the code that is inconsistent with itself. Recorded because intent conformance is a standing check, not because anything changed.

🔧 Fix: make parent config-override leak assertion non-vacuous
2 infos still open:

  • ℹ️ bin/fm-spawn.sh:3115 - Standing intent-conformance record, no action expected - re-verified against the current code and unchanged since you adjudicated it in round 1 ("Keine Codeaenderung, bewusst so") and again in rounds 4 and 6. The stated intent names "FM_ROOT_OVERRIDE, FM_HOME, and FM_STATE_OVERRIDE", but SPAWN_OVERRIDE_RESET_VARS covers only the five FM_*_OVERRIDE names; FM_HOME is neither unset nor pinned for ship/scout panes, and the FM_HOME redirect at bin/fm-spawn.sh:3070 remains secondmate-only. I re-checked the sibling paths this round for a reachable inversion of the failure and found none: the one in-repo caller that spawns with non-default overrides set is bin/fm-remote-secondmate-control.sh:195-199, and that is a --secondmate spawn whose launch line pins FM_HOME to the same TARGET_HOME the FM_CONFIG_OVERRIDE pointed at, so the pane resolves the identical config/state dirs before and after this change. The implementation, the comment at :3068-3076, docs/configuration.md:290 and tests/fm-spawn-override-reset.test.sh:219 all agree with your decision - it is the intent sentence that is broader than the shipped scope, not the code that is inconsistent with itself.
  • ℹ️ tests/fm-spawn-override-reset.test.sh:4 - The new file's header attributes the FM_*_OVERRIDE vocabulary to AGENTS.md &#34;Layout and state&#34;, but AGENTS.md section 2 does not mention FM_ROOT_OVERRIDE, FM_STATE_OVERRIDE, FM_DATA_OVERRIDE, FM_PROJECTS_OVERRIDE or FM_CONFIG_OVERRIDE at all (grep over AGENTS.md returns nothing for _OVERRIDE). That section explicitly delegates: "docs/configuration.md is the single owner of the top-level operational-home layout and configuration schemas" (AGENTS.md:50), and docs/configuration.md:286-290 is in fact where all five are defined and where this change documents the reset. A reader following the citation lands on a section that owns FM_HOME only and will not find the contract the test claims to anchor to. Point the header at docs/configuration.md instead; purely a comment fix, no behavior involved.
⏭️ **Test** - skipped
  • 🚨 tests failed with exit code -1
  • bin/fm-test-run.sh --changed --exclude-family real-herdr-gated

🔧 Fix: wait for rendered pane in Pi follow-up e2e
1 error still open:

  • 🚨 tests failed with exit code 1
  • bin/fm-test-run.sh --changed --exclude-family real-herdr-gated
⚠️ **Document** - 1 info
  • ℹ️ docs/configuration.md:288 - docs/configuration.md states the FM_*_OVERRIDE reset "takes effect both in POSIX pane shells and in fish" without qualification, but the fish half is gated on status fish-path, which fish only grew in 3.0. On a fish 2.x pane the probe fails, the erase never runs, and the reset is a silent no-op. I left the sentence unqualified deliberately: fish 2.x predates 2018 and a version caveat would be noise for every operator, and the underlying question (whether the probe should tolerate older fish) is a behavior decision, not a documentation one. Flagging it so the choice is visible rather than assumed.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Valentino-Sole and others added 10 commits September 4, 2026 09:24
…mate

An ordinary ship/scout worker's launch line never cleared
FM_ROOT_OVERRIDE/FM_STATE_OVERRIDE/FM_DATA_OVERRIDE/FM_PROJECTS_OVERRIDE/
FM_CONFIG_OVERRIDE - that reset lived only inside the KIND=secondmate
branch. A pane that inherits environment from elsewhere in the launching
process tree could then carry a foreign home's overrides into the
worker's own watcher and fm-*.sh helpers, which then looked at the wrong
home (the recurring false WATCHER-DOWN alarms). Hoist the five-variable
reset out of the KIND-specific branch so it applies to every spawn
regardless of kind, while keeping the FM_HOME redirect (and the
secondmate-only extras riding with it) secondmate-exclusive.

fm-control.sh relaunch and the bootstrap secondmate-liveness respawn
both funnel through this same single LAUNCH-assembly chokepoint in
fm-spawn.sh, so both were already covered by the pre-existing
KIND=secondmate reset and are now covered unconditionally too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AkAKUTzwUaMkU3gcQZMJsf
@greptile-apps

greptile-apps Bot commented Sep 4, 2026 •

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (2): Last reviewed commit: "no-mistakes(document): document fish out..." | Re-trigger Greptile

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