Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion scripts/gen-sdui-manifest.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -582,7 +582,33 @@ trap 'sdui_on_signal INT' INT
trap 'sdui_on_signal TERM' TERM
trap 'sdui_on_signal HUP' HUP

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

# Failing here is a REFUSAL TO GUESS, not an inconvenience: the alternative is
Expand Down
39 changes: 38 additions & 1 deletion scripts/pm/os-regen-merge.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,44 @@ echo "→ fetching origin/main"
git fetch origin main

# The single authoritative list, read at run time.
mapfile -t regen_paths < <(grep 'merge=os-regen' .gitattributes | awk '{print $1}')
#
# READ LOOP, NOT `mapfile` — THE BASH 3.2 FLOOR. `mapfile`/`readarray` are bash
# 4 builtins and `/usr/bin/env bash` is bash 3.2.57 on macOS (Apple ships no
# bash 4+, for licensing reasons). This script is run BY HAND, in an agent's or
# a maintainer's worktree, and it has no CI path at all — nothing in
# `.github/workflows/` invokes it — so a bash-4 builtin here does not fail on a
# fringe host, it fails on the ordinary one, and no CI run can ever say so.
# Measured with the builtin disabled (`enable -n mapfile readarray` via
# `BASH_ENV`, which reproduces the macOS symptom byte for byte):
# `mapfile: command not found`, then `set -e` kills the run at status 127 —
# AFTER `git fetch origin main` and BEFORE step 1, i.e. with the merge sequence
# whose ORDER is this script's entire reason for existing not begun. The
# operator is left to perform steps 1–3 by hand, which is the trap the script
# was written to remove.
#
# Keep this loop bash-3.2-clean: no `mapfile`, no `readarray`, no `declare -A`,
# no `${x^^}`/`${x,,}`. Two details are load-bearing and neither is obvious:
#
# `regen_paths=()` BEFORE the loop. Under `set -u` a loop that appends
# nothing never creates the array at all, so `${#regen_paths[@]}` below
# aborts with `unbound variable` — and "grep matched nothing" is precisely
# the case the refusal below exists to REPORT. Measured: without the
# declaration the empty input dies at `regen_paths: unbound variable`; with
# it, `count=0` and the refusal prints.
#
# `if [[ -n … ]]; then …; fi`, not a trailing `[[ -n … ]] && …`. Measured:
# with the `&&` form the `while` takes status 1 whenever the LAST line read
# fails the test, and under `set -e` that kills the caller the moment such a
# loop is the last command of a function — silently correct today, a landmine
# for the next refactor. The `if` form returns 0 on the same input. (This is
# the form #12142 standardised; its own note attributes the trap to the empty
# list, which measures clean — an all-empty read leaves the body unexecuted
# and the `while` at status 0.)
regen_paths=()
regen_line=''
while IFS= read -r regen_line; do
if [[ -n "$regen_line" ]]; then regen_paths+=("$regen_line"); fi
done < <(grep 'merge=os-regen' .gitattributes | awk '{print $1}')
if [ "${#regen_paths[@]}" -eq 0 ]; then
echo "✗ no merge=os-regen entries found in .gitattributes — refusing to guess" >&2
exit 1
Expand Down
25 changes: 24 additions & 1 deletion scripts/publish-smoke.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,30 @@ mkdir -p "$DEV_TMPDIR"
# `\x1b[31m…ERROR…` line the negative test produced).
# TMPDIR: see the collision-safety block — it is what makes the runtime state
# file this run reads back provably its own.
mapfile -t DEV_ARGV < <(smoke_dev_server_argv)
# READ LOOP, NOT `mapfile` — THE BASH 3.2 FLOOR. `mapfile`/`readarray` are
# bash 4 builtins and `/usr/bin/env bash` is bash 3.2.57 on macOS (Apple ships
# no bash 4+, for licensing reasons). Unlike its two siblings in this sweep
# this line IS reached by CI — `publish-smoke.yml` runs this script on Linux
# with bash 5, where the builtin exists — so CI is green over it in both
# directions and says nothing at all about the defect or this repair. What CI
# does not cover is the OTHER way this script is run: by hand, to reproduce a
# publish-smoke failure locally, which on a Mac died here. Measured with the
# builtin disabled (`enable -n mapfile readarray` via `BASH_ENV`, which
# reproduces the macOS symptom byte for byte): `mapfile: command not found`,
# status 127 under `set -e`.
#
# Keep this loop bash-3.2-clean: no `mapfile`, no `readarray`, no `declare -A`,
# no `${x^^}`/`${x,,}`. Two details are load-bearing: `DEV_ARGV=()` before the
# loop (under `set -u` a loop that appends nothing never creates the array, and
# the expansion below would abort with `unbound variable`), and the `if` rather
# than a trailing `[[ … ]] &&` (with the `&&` form the `while` takes status 1
# whenever the last line read fails the test, which under `set -e` kills the
# caller as soon as such a loop sits last in a function).
DEV_ARGV=()
dev_argv_line=''
while IFS= read -r dev_argv_line; do
if [[ -n "$dev_argv_line" ]]; then DEV_ARGV+=("$dev_argv_line"); fi
done < <(smoke_dev_server_argv)
(cd "$APP_DIR" && exec "${DEV_ARGV[@]}") \
> "$SERVER_LOG" 2>&1 &
SERVER_PID=$!
Expand Down
Loading