Skip to content

fix(bin/wire-company-brain.sh): heredoc inside $(...) breaks bash 3.2 - #144

Draft
MendixMau wants to merge 1 commit into
masterfrom
fix/wire-brain-bash32
Draft

MendixMau wants to merge 1 commit into
masterfrom
fix/wire-brain-bash32

Conversation

@MendixMau

Copy link
Copy Markdown
Owner

Lane: Direct

What changed and why (one paragraph)

A colleague's doctor.sh run on macOS reported bin/wire-company-brain.sh unparseable (lines 82/85). Root cause: the script built its marker block with a heredoc inside $(cat <<BLK … BLK). bash 3.2's command-substitution scanner does not recognise a heredoc opened inside $(...); it reads the body as shell text, and the apostrophe in "company's" opens a quote it never closes. bash 5 parses it fine, which is why bash -n here never caught it. The block is now read with IFS= read -r -d '' block <<BLK || true and the trailing newline stripped, so the output is byte-identical. The same trap was live in claude-hooks/hooks/context-ceiling.sh and context-watch.sh (a heredoc feeding python's stdin inside $(...)); both fixed the same way. bin/check-portability.sh gains a rule for the pattern so it cannot come back, with <<< here-strings and $((...)) arithmetic stripped first because both false-triggered the raw grep.

Field evidence

  • Trigger: a workshop attendee's doctor.sh FAIL on macOS stock bash 3.2.57 (screenshot, chat-only).
  • bash -n clean on all four scripts; bin/check-portability.sh clean on the branch (163 files).
  • Output of the rebuilt block diffed byte-identical against the old $(cat <<BLK) form; the two hooks re-verified against a synthetic transcript.
  • Reintroducing the pattern in a scratch file is flagged by the new portability rule; <<< and $((x<<2)) are not.
  • Not verified on a real macOS bash 3.2 box in this session (Linux, bash 5 only). The fix pattern (read -d '') is bash 3.2-native and used elsewhere in this repo.

Checklist

  • No client data (names, paths, hostnames) in the diff or this description
  • Size cap: 5 files, +36/-6
  • Test tier: T1 (syntax + guard run + output diff), T2 pending a macOS run
  • Instrument rules: check-portability.sh change is a new rule with the false-positive exclusions it needed; no new artifact consumer
  • Routing row: n/a (no skill change)
  • CHANGELOG line appended under ## Unreleased
  • Bug entry: n/a

🤖 Generated with Claude Code

https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw


Generated by Claude Code

bash 3.2's $(...) scanner does not recognise a heredoc opened inside it: it
scans the body as shell text while hunting for the matching ')', so an
apostrophe in the body ("company's") opens a quote it never closes. Bash 5
parses it fine, so bash -n on a bash-5-only machine cannot reproduce this.

Rebuilt block="$(cat <<EOF ...)" as IFS= read -r -d '' block <<EOF ... EOF,
which keeps every caller's byte-identical output (verified against
init-company-brain.sh + init-project.sh --company: word count, path
resolution, registry, re-wire idempotency, re-point rewrite all unchanged).

The same trap was live in claude-hooks/hooks/context-ceiling.sh and
context-watch.sh (a heredoc feeding python's stdin inside $(...)); fixed the
same way and re-verified end to end against a synthetic transcript (both
correctly computed ctx=6000 from the newest usage record).

Added a bin/check-portability.sh check for the pattern. The raw grep
(\$\([^)]*<<[^<]) false-triggered on $((...)) arithmetic left-shift and <<<
here-strings, so both are stripped before matching; the refined check has
zero hits on the fixed tree and correctly flags a synthetic reintroduction
of the bug.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
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