Skip to content

fix(bin): keep --no-projects remote seeding working on stock macOS bash - #3541

Open
zeeshaanahmad wants to merge 1 commit into
kunchenguid:mainfrom
zeeshaanahmad:up-remote-home-seed-no-projects-bash32
Open

fix(bin): keep --no-projects remote seeding working on stock macOS bash#3541
zeeshaanahmad wants to merge 1 commit into
kunchenguid:mainfrom
zeeshaanahmad:up-remote-home-seed-no-projects-bash32

Conversation

@zeeshaanahmad

@zeeshaanahmad zeeshaanahmad commented Sep 2, 2026

Copy link
Copy Markdown

Intent

Fix bin/fm-remote-home-seed.sh so --no-projects works on stock macOS bash 3.2. The project loop expands "${PROJECT_NAMES[@]}" unguarded; --no-projects leaves that array empty, and bash 3.2 treats an empty array's [@] expansion as an unbound variable under set -u, so the seed aborts with 'PROJECT_NAMES[@]: unbound variable' and the remote secondmate spawn fails. Guard the expansion so an empty project list is a valid no-op on bash 3.2 as well as on newer bash. The branch is based on upstream main and is contributed from a fork; the validation pipeline was run against the fork remote with the CI step skipped, because this repository's CI runs on the upstream pull request rather than on the fork.

What Changed

  • In bin/fm-remote-home-seed.sh, guard the "${PROJECT_NAMES[@]}" expansion in the project loop with the ${PROJECT_NAMES[@]+"${PROJECT_NAMES[@]}"} idiom so an empty PROJECT_NAMES array (produced when --no-projects is passed) is a valid no-op instead of triggering an unbound-variable error.
  • Adds a comment explaining that bash 3.2 (macOS's stock shell, which env bash resolves to on a Mac) treats "${ARR[@]}" on an empty array as unbound under set -u, unlike newer bash versions.

Risk Assessment

✅ Low: Single-file, 5-line change applying the standard bash 3.2-safe empty-array guard exactly where the described unbound-variable failure occurs; verified against real bash 3.2 that the fix resolves the failure, preserves element quoting, and that the one other unguarded PROJECT_NAMES[@] use is unreachable when the array is empty.

Testing

Reproduced the exact reported bash 3.2 failure in isolation (unguarded "${PROJECT_NAMES[@]}" on an empty array aborts with 'unbound variable' under set -u; the fixed guarded expansion ${PROJECT_NAMES[@]+"${PROJECT_NAMES[@]}"} completes cleanly), then confirmed the fix end-to-end by running the existing tests/fm-remote-secondmate-trace-context.test.sh under this machine's actual stock bash 3.2.57 (both bash and /bin/bash resolve to it here), which invokes fm-remote-home-seed.sh with --no-projects twice and drives the full remote secondmate spawn afterward — all assertions passed. An initial run appeared to hang/time out at the 3-minute mark, but this was CPU contention from a concurrent shellcheck lint phase in the same outer pipeline (confirmed via ps), not a fix regression; a clean re-run after that contention cleared finished in ~2:39 with all tests passing. No source or test changes were needed; worktree is clean with no transient artifacts left behind.

Evidence: Isolated bash 3.2 before/after reproduction
Pre-fix pattern for project in "${PROJECT_NAMES[@]}" on an empty array under set -eu (bash 3.2.57):
/bin/bash: line 5: PROJECT_NAMES[@]: unbound variable (exit=1)

Post-fix pattern for project in ${PROJECT_NAMES[@]+"${PROJECT_NAMES[@]}"} on an empty array under set -eu (bash 3.2.57):
no-op reached (expected with the fixed guarded expansion) (exit=0)
Evidence: tests/fm-remote-secondmate-trace-context.test.sh full run under bash 3.2.57
ok - disabled: a remote-routed second mate records and receives no carrier and stays enabled-off end to end
ok - enabled: a remote-routed second mate receives one carrier in its pane, identical to the parent's recorded identity, before launch
ok - relaunch: a remote-routed second mate keeps one stable identity across restarts
ok - boundary: each remote-routed second mate roots its own trace and never adopts the spawning environment's carrier
ok - allowlist: the remote receiver accepts exactly the declared inherited-material set, including the enablement flag
ok - delivery: a parent-supplied carrier is accepted only for a secondmate launch and only as a strict W3C value
ALL TESTS PASSED
EXIT:0

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

⏭️ **Rebase** - skipped

Step was skipped.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Isolated bash 3.2.57 repro: pre-fix for project in "${PROJECT_NAMES[@]}" on an empty array under set -eu fails with PROJECT_NAMES[@]: unbound variable; post-fix for project in ${PROJECT_NAMES[@]+"${PROJECT_NAMES[@]}"} completes as a no-op (exit 0)
  • /bin/bash tests/fm-remote-secondmate-trace-context.test.sh (this environment's default bash and /bin/bash are both stock macOS bash 3.2.57) — exercises bin/fm-remote-home-seed.sh ... --no-projects twice end-to-end (real script, set -eu) followed by real fm-spawn.sh --secondmate remote spawns; all 6 assertions passed, ALL TESTS PASSED, exit 0
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

fm-remote-home-seed.sh expanded "${PROJECT_NAMES[@]}" unguarded when
walking the project list. --no-projects leaves that array empty, and
bash 3.2 - macOS's stock shell, which `env bash` still resolves to on a
Mac - treats an empty array's [@] expansion as an unbound variable
under set -u, so the seed aborted before it ever reached remote
provisioning.

Use the guarded expansion the repo already uses elsewhere for this
case, so the loop is skipped rather than fatal.

Verified failing on unpatched upstream main (8988af2) on macOS with
stock bash 3.2: `bin/fm-remote-home-seed.sh ... --no-projects` fails
with "PROJECT_NAMES[@]: unbound variable" at the loop this patches;
tests/fm-remote-secondmate-trace-context.test.sh and
tests/fm-remote-secondmate-lifecycle-e2e.test.sh, both of which drive
the --no-projects path, fail the same way unpatched and pass with this
fix.
@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge, with no actionable regressions identified.

The guarded expansion skips the project loop for an empty array on Bash 3.2 while retaining quoted, element-preserving expansion when projects are present.

Reviews (1): Last reviewed commit: "fix(bin): keep --no-projects remote seed..." | Re-trigger Greptile

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate:

HEAD e9e8e3c463928b09ce7ddffe742427a503d9d6ff — MERGEABLE/UNSTABLE. Linked #3537. workflow-zero (only bin/fm-remote-home-seed.sh). Author not blocked. Security: clean.

Attestation: MISSING — no head-bound no-mistakes attestation. NM 33659002660 FAILURE ("PR was not raised through no-mistakes"). CI 33659002709 approved this pass and queued.

Contract-class: restore — script usage already documents --no-projects as a valid way to seed with an empty project list. Unguarded \"${PROJECT_NAMES[@]}\" aborts under bash 3.2 + set -u when the array is empty (stock macOS env bash). Guarded expansion (${PROJECT_NAMES[@]+\"${PROJECT_NAMES[@]}\"}) is the same form this repo already uses elsewhere (e.g. in fm-test-run.sh). Restores the documented --no-projects path; no new default behavior.

VISION (per rule, evidence = usage header + one-line loop fix):

  1. One captain, one interface — aligns (seed plumbing only).
  2. Authority is explicit and never inferred — aligns (--no-projects remains explicit).
  3. Scripts own the mechanics, agents own the judgment — aligns (bash portability fix in a script).
  4. A restart is a non-event — aligns (seed can complete so remote home exists).
  5. Delegation with a spine — aligns (no new task shape).
  6. The fleet outlives any vendor — aligns (stock macOS bash 3.2 portability).
  7. Scope — aligns (command-layer remote seed). Closing: aligns.

This is waiting on you (the author), not a captain decision. Please git push no-mistakes to bind attestation to HEAD. Fork workflows approved after diff review (run ids 33659002709, 33659002660). When attestation MATCH + NM/CI green, this restore can auto-merge.

workflow-approvals this pass: 33659002709, 33659002660

@zeeshaanahmad

Copy link
Copy Markdown
Author

The no-mistakes pipeline has now been run against this branch, and its pr step wrote the ## Pipeline section into the description above. The attestation names this exact head, with review, test and document each completed.

The pipeline was run against the fork remote with the ci step skipped, since CI here runs on the upstream pull request rather than on the fork. The Require no-mistakes run triggered by that description update is queued as action_required, so it needs a maintainer to approve the workflow run before it can report a result.

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.

2 participants