Skip to content

Commit 9fbb5a2

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-12016-cli-command-id-coupling
2 parents 53573b0 + cd25417 commit 9fbb5a2

3 files changed

Lines changed: 89 additions & 3 deletions

File tree

scripts/gen-sdui-manifest.sh

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,33 @@ trap 'sdui_on_signal INT' INT
582582
trap 'sdui_on_signal TERM' TERM
583583
trap 'sdui_on_signal HUP' HUP
584584

585-
readarray -t DUMP_DEV_ARGV < <(sdui_dev_server_cmd "$DUMP_PORT")
585+
# READ LOOP, NOT `readarray` — THE BASH 3.2 FLOOR. `readarray`/`mapfile` are
586+
# bash 4 builtins and `/usr/bin/env bash` is bash 3.2.57 on macOS (Apple ships
587+
# no bash 4+, for licensing reasons). This is the sharpest site in the repo for
588+
# that defect: `pnpm sdui:manifest` is the literal `→ NEXT STEP` that
589+
# `scripts/bump-objectui.sh` prints on its way out, and per the comment at the
590+
# head of this file the ratchet is an on-demand gate by decision (#5960) — the
591+
# only routine CI invocation is `cut-rc.yml`'s pre-publish run, a handful of
592+
# times a month on Linux. So the ONE host this line is normally executed on is
593+
# the operator's laptop, and on a Mac it aborted there. Measured with the
594+
# builtin disabled (`enable -n mapfile readarray` via `BASH_ENV`, which
595+
# reproduces the macOS symptom byte for byte): `readarray: command not found`,
596+
# status 127 under `set -e` — and it aborts HERE, after the EXIT/INT/TERM traps
597+
# are armed but before any server is spawned, so the operator is handed a bare
598+
# builtin error at the exact step the pin bump just told them to run.
599+
#
600+
# Keep this loop bash-3.2-clean: no `mapfile`, no `readarray`, no `declare -A`,
601+
# no `${x^^}`/`${x,,}`. Two details are load-bearing: `DUMP_DEV_ARGV=()` before
602+
# the loop (under `set -u` a loop that appends nothing never creates the array,
603+
# and the expansion below would abort with `unbound variable`), and the `if`
604+
# rather than a trailing `[[ … ]] &&` (with the `&&` form the `while` takes
605+
# status 1 whenever the last line read fails the test, which under `set -e`
606+
# kills the caller as soon as such a loop sits last in a function).
607+
DUMP_DEV_ARGV=()
608+
dump_argv_line=''
609+
while IFS= read -r dump_argv_line; do
610+
if [[ -n "$dump_argv_line" ]]; then DUMP_DEV_ARGV+=("$dump_argv_line"); fi
611+
done < <(sdui_dev_server_cmd "$DUMP_PORT")
586612
sdui_spawn_detached "$DUMP_PID_FILE" "$DUMP_DEV_LOG" "${DUMP_DEV_ARGV[@]}"
587613

588614
# Failing here is a REFUSAL TO GUESS, not an inconvenience: the alternative is

scripts/pm/os-regen-merge.sh

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,44 @@ echo "→ fetching origin/main"
6565
git fetch origin main
6666

6767
# The single authoritative list, read at run time.
68-
mapfile -t regen_paths < <(grep 'merge=os-regen' .gitattributes | awk '{print $1}')
68+
#
69+
# READ LOOP, NOT `mapfile` — THE BASH 3.2 FLOOR. `mapfile`/`readarray` are bash
70+
# 4 builtins and `/usr/bin/env bash` is bash 3.2.57 on macOS (Apple ships no
71+
# bash 4+, for licensing reasons). This script is run BY HAND, in an agent's or
72+
# a maintainer's worktree, and it has no CI path at all — nothing in
73+
# `.github/workflows/` invokes it — so a bash-4 builtin here does not fail on a
74+
# fringe host, it fails on the ordinary one, and no CI run can ever say so.
75+
# Measured with the builtin disabled (`enable -n mapfile readarray` via
76+
# `BASH_ENV`, which reproduces the macOS symptom byte for byte):
77+
# `mapfile: command not found`, then `set -e` kills the run at status 127 —
78+
# AFTER `git fetch origin main` and BEFORE step 1, i.e. with the merge sequence
79+
# whose ORDER is this script's entire reason for existing not begun. The
80+
# operator is left to perform steps 1–3 by hand, which is the trap the script
81+
# was written to remove.
82+
#
83+
# Keep this loop bash-3.2-clean: no `mapfile`, no `readarray`, no `declare -A`,
84+
# no `${x^^}`/`${x,,}`. Two details are load-bearing and neither is obvious:
85+
#
86+
# `regen_paths=()` BEFORE the loop. Under `set -u` a loop that appends
87+
# nothing never creates the array at all, so `${#regen_paths[@]}` below
88+
# aborts with `unbound variable` — and "grep matched nothing" is precisely
89+
# the case the refusal below exists to REPORT. Measured: without the
90+
# declaration the empty input dies at `regen_paths: unbound variable`; with
91+
# it, `count=0` and the refusal prints.
92+
#
93+
# `if [[ -n … ]]; then …; fi`, not a trailing `[[ -n … ]] && …`. Measured:
94+
# with the `&&` form the `while` takes status 1 whenever the LAST line read
95+
# fails the test, and under `set -e` that kills the caller the moment such a
96+
# loop is the last command of a function — silently correct today, a landmine
97+
# for the next refactor. The `if` form returns 0 on the same input. (This is
98+
# the form #12142 standardised; its own note attributes the trap to the empty
99+
# list, which measures clean — an all-empty read leaves the body unexecuted
100+
# and the `while` at status 0.)
101+
regen_paths=()
102+
regen_line=''
103+
while IFS= read -r regen_line; do
104+
if [[ -n "$regen_line" ]]; then regen_paths+=("$regen_line"); fi
105+
done < <(grep 'merge=os-regen' .gitattributes | awk '{print $1}')
69106
if [ "${#regen_paths[@]}" -eq 0 ]; then
70107
echo "✗ no merge=os-regen entries found in .gitattributes — refusing to guess" >&2
71108
exit 1

scripts/publish-smoke.sh

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,30 @@ mkdir -p "$DEV_TMPDIR"
671671
# `\x1b[31m…ERROR…` line the negative test produced).
672672
# TMPDIR: see the collision-safety block — it is what makes the runtime state
673673
# file this run reads back provably its own.
674-
mapfile -t DEV_ARGV < <(smoke_dev_server_argv)
674+
# READ LOOP, NOT `mapfile` — THE BASH 3.2 FLOOR. `mapfile`/`readarray` are
675+
# bash 4 builtins and `/usr/bin/env bash` is bash 3.2.57 on macOS (Apple ships
676+
# no bash 4+, for licensing reasons). Unlike its two siblings in this sweep
677+
# this line IS reached by CI — `publish-smoke.yml` runs this script on Linux
678+
# with bash 5, where the builtin exists — so CI is green over it in both
679+
# directions and says nothing at all about the defect or this repair. What CI
680+
# does not cover is the OTHER way this script is run: by hand, to reproduce a
681+
# publish-smoke failure locally, which on a Mac died here. Measured with the
682+
# builtin disabled (`enable -n mapfile readarray` via `BASH_ENV`, which
683+
# reproduces the macOS symptom byte for byte): `mapfile: command not found`,
684+
# status 127 under `set -e`.
685+
#
686+
# Keep this loop bash-3.2-clean: no `mapfile`, no `readarray`, no `declare -A`,
687+
# no `${x^^}`/`${x,,}`. Two details are load-bearing: `DEV_ARGV=()` before the
688+
# loop (under `set -u` a loop that appends nothing never creates the array, and
689+
# the expansion below would abort with `unbound variable`), and the `if` rather
690+
# than a trailing `[[ … ]] &&` (with the `&&` form the `while` takes status 1
691+
# whenever the last line read fails the test, which under `set -e` kills the
692+
# caller as soon as such a loop sits last in a function).
693+
DEV_ARGV=()
694+
dev_argv_line=''
695+
while IFS= read -r dev_argv_line; do
696+
if [[ -n "$dev_argv_line" ]]; then DEV_ARGV+=("$dev_argv_line"); fi
697+
done < <(smoke_dev_server_argv)
675698
(cd "$APP_DIR" && exec "${DEV_ARGV[@]}") \
676699
> "$SERVER_LOG" 2>&1 &
677700
SERVER_PID=$!

0 commit comments

Comments
 (0)