Skip to content

test: guard fixture home isolation from live fleet state - #1

Merged
gk-io-dev merged 7 commits into
mainfrom
fm/firstmate-test-fm-home-isolation-recovery-20260917
Sep 17, 2026
Merged

gk-io-dev merged 7 commits into
mainfrom
fm/firstmate-test-fm-home-isolation-recovery-20260917

Conversation

@gk-io-dev

@gk-io-dev gk-io-dev commented Sep 17, 2026 •

Copy link
Copy Markdown
Owner

What Changed

  • tests/lib.sh: added an ambient-home poison guard that runs on first source — clears any inherited FM_ROOT_OVERRIDE/FM_STATE_OVERRIDE/FM_DATA_OVERRIDE/FM_CONFIG_OVERRIDE/FM_PROJECTS_OVERRIDE/FM_PENDING_REPLY_DIR_OVERRIDE and pins FM_HOME to a fresh per-process scratch directory (with a .fm-ambient-guard marker, no fleet state), so a fixture that forgets to set its own FM_HOME can no longer fall through to the real checkout/live fleet home.
  • Added tests/fm-ambient-home-guard.test.sh: regression coverage with a sentinel MAIN/MATE secondmate fixture proving (1) tests/lib.sh pins FM_HOME away from $ROOT, (2) explicitly bypassing the guard reproduces the original incident (a fabricated child ledger line landing on a live parent channel), (3) a forgotten FM_HOME override now lands in the guard directory instead of the sentinel, and (4) inherited directory overrides are cleared and can't reach the sentinel either.
  • tests/fm-watcher-lock.test.sh: three fm-guard.sh invocations in test_guard_warnings now set FM_HOME explicitly alongside FM_ROOT_OVERRIDE, since they can no longer rely on an unset FM_HOME falling back to root.
  • CONTRIBUTING.md: added a pointer to the ambient-home guard comment in tests/lib.sh as the source of truth for fixture home initialization and override ordering.

🤖 Generated with Claude Code

Risk Assessment

✅ Low: Test-only change adding an ambient-home guard in tests/lib.sh plus regression test; fallback logic matches actual bin/fm-inactive-reconcile.sh behavior, existing suites already clear these overrides in the test runner, and watcher-lock test updates are consistent with the new pinned FM_HOME.

Testing

All 4 new ambient-home-guard tests and all 34 watcher-lock tests pass live against the real bash test harness; confirmed the core regression test fails without the fix (not vacuous). No product/runtime surface beyond this bash test tooling, and no findings.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
guard pins FM_HOME away from live root ✅ pass live bin/fm-test-run.sh tests/fm-ambient-home-guard.test.sh → ok - tests/lib.sh pins FM_HOME to an empty, non-root directory
bypassing guard (unset FM_HOME) reproduces original incident against private fixture ✅ pass live ok - unsetting FM_HOME reproduces the incident against a private fixture (never against $ROOT) — fabricated PR ledger line landed on fixture's mate.status when FM_HOME unset
forgotten FM_HOME override lands in guard scratch dir, not sentinel live home ✅ pass live ok - a forgotten FM_HOME override lands in the pinned guard directory, not the sentinel — sentinel fixture untouched (fingerprint unchanged, no 'leak-child' trace)
inherited directory overrides (FM_ROOT_OVERRIDE etc.) are cleared on lib.sh source and can't reach live state ✅ pass live ok - fixture initialization clears inherited directory overrides and protects live state
regression is real, not vacuous: same test fails against pre-fix tests/lib.sh ✅ pass live Swapped tests/lib.sh back to base commit a511c39 content, reran test: not ok - tests/lib.sh must export a non-empty FM_HOME, exit=1. Restored fixed tests/lib.sh afterward; worktree clean.
watcher-lock suite unaffected by FM_HOME being newly required in its guard fixtures ✅ pass live bin/fm-test-run.sh tests/fm-watcher-lock.test.sh → all 34 cases ok, exit=0

Pipeline

Updates from git push no-mistakes

⏭️ **intent** - skipped

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
guard pins FM_HOME away from live root ✅ pass live bin/fm-test-run.sh tests/fm-ambient-home-guard.test.sh → ok - tests/lib.sh pins FM_HOME to an empty, non-root directory
bypassing guard (unset FM_HOME) reproduces original incident against private fixture ✅ pass live ok - unsetting FM_HOME reproduces the incident against a private fixture (never against $ROOT) — fabricated PR ledger line landed on fixture's mate.status when FM_HOME unset
forgotten FM_HOME override lands in guard scratch dir, not sentinel live home ✅ pass live ok - a forgotten FM_HOME override lands in the pinned guard directory, not the sentinel — sentinel fixture untouched (fingerprint unchanged, no 'leak-child' trace)
inherited directory overrides (FM_ROOT_OVERRIDE etc.) are cleared on lib.sh source and can't reach live state ✅ pass live ok - fixture initialization clears inherited directory overrides and protects live state
regression is real, not vacuous: same test fails against pre-fix tests/lib.sh ✅ pass live Swapped tests/lib.sh back to base commit a511c39 content, reran test: not ok - tests/lib.sh must export a non-empty FM_HOME, exit=1. Restored fixed tests/lib.sh afterward; worktree clean.
watcher-lock suite unaffected by FM_HOME being newly required in its guard fixtures ✅ pass live bin/fm-test-run.sh tests/fm-watcher-lock.test.sh → all 34 cases ok, exit=0
  • bin/fm-test-run.sh tests/fm-ambient-home-guard.test.sh
  • bin/fm-test-run.sh tests/fm-watcher-lock.test.sh
  • manual: swapped tests/lib.sh to base-commit content to prove the new guard test fails without the fix, then restored
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@gk-io-dev gk-io-dev closed this Sep 17, 2026
@gk-io-dev gk-io-dev reopened this Sep 17, 2026
@gk-io-dev
gk-io-dev force-pushed the fm/firstmate-test-fm-home-isolation-recovery-20260917 branch from 9a6bfac to 0b8fc3e Compare September 17, 2026 09:18
…ver uncommitted diff from prior timed-out agent (env -u FM_HOME approach) — reverted it since it didn't match instructed fix. Applied exact one-line change: added FM_HOME="$root" to the node invocation in test_opencode_plugin_delivers_exact_nudge_once (tests/fm-sessionstart-nudge.test.sh). Ran the test file directly, exit=0, no failures. Did not touch ci-1 or ci-fix-agent-timeout per instructions
…ausing the "Behavior portable serial 5" (afk family) failure: propose/confirm captured the ISO timestamp and epoch via two separate `date` calls that could straddle a second boundary, producing an entered/entered_epoch (or confirmed/confirmed_epoch) pair that disagreed by 1s. tests/fm-afk-return.test.sh's test_missing_epoch_record_stays_required_after_disappearing asserts the return brief's rendered away-window start (derived from entered_epoch) matches the stored ISO "entered" field, so the race caused an intermittent mismatch exactly as seen in the CI log ("away 2026-09-17T11:52:52Z" vs expected "...51Z"). Fix: capture epoch first, then derive the ISO string from that same epoch via a new helper fm_afk_contract_iso_of_epoch, so the pair can never straddle a boundary. Verified the previously-failing test passes deterministically (8/8 isolated runs) and the rest of fm-afk-return.test.sh and fm-afk-contract.test.sh remain green (one unrelated, pre-existing, sandbox-only fd-redirect test fails identically on unmodified baseline too, so left alone). "Behavior portable serial 2" fails due to tests/fm-backend.test.sh's symlinked-prefix Treehouse-lock test, which is the same pre-existing defect documented and explicitly declared out-of-scope across three prior rounds of this branch's history (confirmed reproducing identically on fork main with this PR's change fully reverted). Per the user's repeated explicit instruction, this was left untouched. That check may continue to report failure for this unrelated, already-flagged reason
@gk-io-dev
gk-io-dev merged commit eedee86 into main Sep 17, 2026
13 of 14 checks passed
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