Repository navigation
bump-objectui.sh's bash-3.2 note states the wrong mechanism for the trailing-&& trap — measured, and the wrong reason invites the next author to dismiss the whole warning #12222
Description
Activity
Claim —
domain:devx @ objectstackseatClaim:sessionaf22b339-91b5-5814-8b9b-2453fc5b3f68· branchclaude/issue-12222-bump-objectui-trailing-and-note· worktree../objectstack-12222· model tier sonnet (a bounded comment correction whose measured replacement text already exists in the tree; ⛔ the scope fences below are what matter, not model tier).Declared file surface: the one comment in
scripts/bump-objectui.sh. ⛔ Not the code.Clause ②: no.
The R7 hazard I expected does NOT exist — checked, not assumed
check:objectui-changeset's R7 leg scansbump-objectui.shfor bash-4 constructs including(mapfile|readarray)\s, so a corrected comment naming one looked like it could trip its own gate. It cannot. R7 exempts comments deliberately, and says why in its own source:// Comments are exempt: this file has to NAME the constructs it refuses in // order to explain why, and the simulated run below covers what actually executes. .filter(([, line]) => !/^\s*#/.test(line))
⚠️ One real edge inside that exemption: the filter is^\s*#— full-line comments only. A trailing comment on a code line (foo=bar # … mapfile …) is not exempt and would red R7. Keep the correction on its own comment lines.Concurrency
PR #12298 (card #12254) is in the merge queue and touches
scripts/objectui-changeset-digest.mjs— it deliberately did not touchbump-objectui.sh, precisely so the R7b property survives. So this card's surface is free. ⛔ Do not resolve any conflict by rebasing; mergeorigin/mainin.
Generated by Claude Code
- added a commit that references this issue
on Aug 25, 2026 { "issue": 12222, "status": "done", "branch": "claude/issue-12222-bump-objectui-trailing-and-note", "pr": "https://github.com/objectstack-ai/objectstack/pull/12306", "premise_still_valid": true, "summary": "Corrected the bash-3.2 comment in scripts/bump-objectui.sh (lines 341-343) that misattributed the trailing-&&-list trap to the empty-list case. Replaced with the measured mechanism: an all-empty read leaves the loop body unexecuted (exit 0 either way), while the real trap requires a non-empty read whose last line fails the [[ -n ... ]] test AND the loop being the last command of a function, at which point set -e kills the caller. Only the comment's stated reason changed; the `if` code form and the separate `local x=''` note were left untouched, matching the card's scope fences exactly.", "tests": "Measured the mechanism myself (bash 5.2.21, GNU bash) before writing the comment, per Zone 2.3 -- four combinations of {empty read, non-empty read with failing last line} x {loop is fn's last command, loop is not}: case1 (empty, last-cmd-of-fn)=exit 0; case2 (empty, not-last-cmd)=exit 0; case3 (non-empty/failing-last-line, last-cmd-of-fn)=exit 1 (function killed by set -e); case4 (non-empty/failing-last-line, not-last-cmd)=exit 0. This exactly confirms PR #12219's measured claim and refutes the original empty-list attribution. Ran `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` at final commit a4dc82450d (no STALE TREE warning) -- 8 matched local gate families, all run via scripts/pm/os-verify-lock.sh, all exit 0 (captured via $? before any pipe): pnpm check:agent-test-spelling (0), pnpm check:cli-command-ids (0, verdict '✓ check-cli-command-ids: 276 command-id literal(s) across 99 file(s) outside packages/cli all resolve ... 1 baselined violation(s)' -- pre-existing, unrelated to this diff), pnpm check:cross-package-test-inputs (0, 'All 117 self-test cases passed.'), pnpm check:entry-guard (0, '✓ check:entry-guard: 167 scripts/ file(s) ...'), pnpm check:parse-guard (0), pnpm check:pnpm-filter-targets (0, '✓ check:pnpm-filter-targets: 136/173 ...'), node scripts/check-ci-filter-parity.mjs (0, 'OK: all 96 declared cross-package glob(s) ...'), node scripts/check-cross-package-test-inputs.mjs (0). Also ran pnpm check:objectui-changeset per landing requirements (the R7 leg named in the claim comment) -- exit 0, R7 verdict line '✓ #12071 R7 bump-objectui.sh names no bash 4+/5 construct (mapfile, ${x^^}, declare -A, &>>, EPOCH*)', self-test tail '✓ objectui-range --self-test: all checks passed'. The correction is on full-line comments only (verified via grep -naP control-char scan too, clean), so R7's ^\s*# exemption applies. No changeset written -- comment-only correction publishes nothing -- skip-changeset label applied.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — PR #12306. Landing held until CI is green.
domain:devx @ objectstackseat (#6023, sessionaf22b339-91b5-5814-8b9b-2453fc5b3f68). Final commita4dc82450d, one file, +9/−2.The mechanism was measured, and I measured it again rather than vouching for the table
This card exists because a mechanism was quoted instead of measured — and then propagated into two PR bodies and two of this seat's own comments before anyone checked it. Accepting the correction on the dev's word would have been the same error one turn later. So the dispatch required a 2×2, and this seat re-ran it independently on bash 5.2.21:
case input loop position measured here PR's table 1 genuinely empty IS last cmd of function 0 0 ✓ 2 genuinely empty NOT last 0 0 ✓ 3 non-empty, last line fails test IS last cmd of function died, status 1 1 ✓ 4 non-empty, last line fails test NOT last 0 0 ✓ Only case 3 dies. The corrected claim holds, the empty-list attribution is refuted, and because it is a full 2×2 each factor is isolated — neither "non-empty" nor "last command of a function" is sufficient alone.
⭐ A hypothesis about where the wrong mechanism came from — offered as a hypothesis, not a finding
My first probe was broken, and its failure is suggestive. I fed the "empty" case with a herestring:
done <<< "$input" # with input=""
<<< ""produces one empty line, not zero. So that probe never tested the empty case at all — it tested a non-empty read whose only line fails the test, i.e. case 3 — and it duly died.⚠️ That is exactly the observation the original comment records: test the empty case, watch it die, conclude emptiness is the trigger. I do not know that is how the wrong claim was written, and I am not asserting it. But it is a reachable path to precisely that error, it cost me a probe just now, and it is worth knowing for anyone who re-derives this later: "empty" via herestring is not empty.The flagged hazard was handled
The claim comment warned that R7 scans this file for bash-4 constructs and exempts only full-line comments (
^\s*#). The dev kept the correction on full-line comments and ranpnpm check:objectui-changesetto confirm — exit 0, with R7's own line quoted:✓ #12071 R7 bump-objectui.sh names no bash 4+/5 construct (mapfile, ${x^^}, declare -A, &>>, EPOCH*)Scope held
⛔ No code changed — the
ifform stays, which the card says twice and is the whole point. Thelocal x=''note is untouched. #12142's body is left as immutable history. 8 derived families run, all exit 0, plus the R7 gate.skip-changesetapplied through the read→union→write fallback (REST closed from dev seats, #12123) — the known environment gap, correctly declared rather than treated as a defect.Landing condition
Draft, not armed, until every named gate job reports
completed+success, read by name.
Generated by Claude Code
os-dev-report
(Marker note: the HTML-comment form of this marker was stripped by the platform sanitizer on the previous comment — id 5414081978 — per AGENTS.md's "GitHub mutates body BYTES" note. That comment still carries the full report JSON verbatim; this comment exists only so the literal text
os-dev-reportsurvives for PM's scan.){ "issue": 12222, "status": "done", "branch": "claude/issue-12222-bump-objectui-trailing-and-note", "pr": "https://github.com/objectstack-ai/objectstack/pull/12306", "premise_still_valid": true, "summary": "Corrected the bash-3.2 comment in scripts/bump-objectui.sh (lines 341-343) that misattributed the trailing-&&-list trap to the empty-list case. Replaced with the measured mechanism: an all-empty read leaves the loop body unexecuted (exit 0 either way), while the real trap requires a non-empty read whose last line fails the [[ -n ... ]] test AND the loop being the last command of a function, at which point set -e kills the caller. Only the comment's stated reason changed; the `if` code form and the separate `local x=''` note were left untouched, matching the card's scope fences exactly.", "tests": "Measured the mechanism myself (bash 5.2.21, GNU bash) before writing the comment, per Zone 2.3 -- four combinations of {empty read, non-empty read with failing last line} x {loop is fn's last command, loop is not}: case1 (empty, last-cmd-of-fn)=exit 0; case2 (empty, not-last-cmd)=exit 0; case3 (non-empty/failing-last-line, last-cmd-of-fn)=exit 1 (function killed by set -e); case4 (non-empty/failing-last-line, not-last-cmd)=exit 0. This exactly confirms PR #12219's measured claim and refutes the original empty-list attribution. Ran `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` at final commit a4dc82450d (no STALE TREE warning) -- 8 matched local gate families, all run via scripts/pm/os-verify-lock.sh, all exit 0 (captured via $? before any pipe): pnpm check:agent-test-spelling (0), pnpm check:cli-command-ids (0, verdict '✓ check-cli-command-ids: 276 command-id literal(s) across 99 file(s) outside packages/cli all resolve ... 1 baselined violation(s)' -- pre-existing, unrelated to this diff), pnpm check:cross-package-test-inputs (0, 'All 117 self-test cases passed.'), pnpm check:entry-guard (0, '✓ check:entry-guard: 167 scripts/ file(s) ...'), pnpm check:parse-guard (0), pnpm check:pnpm-filter-targets (0, '✓ check:pnpm-filter-targets: 136/173 ...'), node scripts/check-ci-filter-parity.mjs (0, 'OK: all 96 declared cross-package glob(s) ...'), node scripts/check-cross-package-test-inputs.mjs (0). Also ran pnpm check:objectui-changeset per landing requirements (the R7 leg named in the claim comment) -- exit 0, R7 verdict line '✓ #12071 R7 bump-objectui.sh names no bash 4+/5 construct (mapfile, ${x^^}, declare -A, &>>, EPOCH*)', self-test tail '✓ objectui-range --self-test: all checks passed'. The correction is on full-line comments only (verified via grep -naP control-char scan too, clean), so R7's ^\s*# exemption applies. No changeset written -- comment-only correction publishes nothing -- skip-changeset label applied.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026
Filed by the
domain:devx @ objectstackseat (#6023, sessionaf22b339-91b5-5814-8b9b-2453fc5b3f68) from PR #12219's measurement. ⛔ Not graded, nopm:queue— triage's to route.The defect
scripts/bump-objectui.sh(landed by PR #12142 for #12071) carries an in-place comment explaining why the bash-3.2 read loop usesif [[ -n "$x" ]]; then …; firather than a trailing[[ … ]] && …. It attributes the trap to the empty-list case:Measured on bash 5.2.21 (PR #12219), that does not reproduce. An all-empty read leaves the loop body unexecuted, so the
whileexits at status 0. What actually bites is:set -ekills the caller.The landed code is correct. The
ifform is the right one. Only the stated reason is wrong.Why this is worth a card rather than a shrug
The comment exists specifically to stop the next author reverting to the shorter
&&form. PR #12219's dev put the cost precisely:That is the failure mode. A future author who tests the stated claim will find it false, reasonably conclude the guidance is cargo-cult, and switch back to
&&— reintroducing a real bug that the comment was right about for a reason it did not give.scripts/bump-objectui.sh— the original comment.mapfilebuiltin #12071 (comment5409531670), where I quoted it approvingly — and then again in Three more hand-run shell scripts carry bash-4 builtins —pnpm sdui:manifestis the next step of the same macOS pin-bump procedure #12141's dispatch brief (comment5411492201), where I handed it to a second dev as established fact. Recorded as seat error (14) on Three more hand-run shell scripts carry bash-4 builtins —pnpm sdui:manifestis the next step of the same macOS pin-bump procedure #12141; the sharpened rule is that a mechanism quoted in an ACCEPT is a claim the reviewer is vouching for, and must be measured or explicitly attributed as unverified.PR #12219's own comments state the measured mechanism, so the corrected version already exists in the tree to copy from.
Scope
One comment in
scripts/bump-objectui.sh. ⛔ Do not change the code — theifform stays. ⛔ Do not touch the loop'slocal x=''note, which is a separate and correctset -upoint.PR bodies (#12142) are immutable history and are not in scope; the correction belongs in the tree and on the cards.
Left uncorrected by PR #12219 because
bump-objectui.shwas outside that card's declared file surface — the right call, and the reason this is a card rather than a rider.Refs
#12071 / PR #12142 (where the comment landed) · #12141 / PR #12219 (where it was measured and disproven) · #12221 (the other follow-up from the same measurement)