Skip to content
Open
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
11 changes: 11 additions & 0 deletions .context/LEARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
| 2026-08-23 | Codex trust and hook wiring facts verified against codex 0.148 |
| 2026-08-23 | hack scripts must survive macOS /bin/bash 3.2 and BSD grep |
| 2026-08-23 | make lint SA5011 false positives mean a corrupted golangci-lint cache |
| 2026-08-19 | Empty-array expansion under set -u kills lint-drift.sh on stock macOS bash 3.2 |
| 2026-07-25 | Using the proprietary sibling repo as design evidence leaks its internals into tracked files |
| 2026-07-25 | Skill and doc examples of a serialized structure must round-trip through the real parser |
| 2026-07-25 | A guard derived from a capability accessor silently lifts when the accessor is extended |
Expand Down Expand Up @@ -88,6 +89,16 @@ DO NOT UPDATE FOR:

---

## [2026-08-19-211547] Empty-array expansion under set -u kills lint-drift.sh on stock macOS bash 3.2

**Context**: make audit had never passed on this stock macOS machine: lint-drift.sh died with "exclude_args[@]: unbound variable" because bash 3.2 treats expanding an empty array as an unset-variable error under set -u. (The sibling lint-docstrings.sh gotchas — apostrophe in a $( ) comment, grep -P on BSD grep — are covered by the 2026-08-23 "hack scripts must survive macOS /bin/bash 3.2 and BSD grep" learning.)

**Lesson**: Bash 3.2 under set -u aborts on ${arr[@]} when the array is empty; bash 4.4+ made this legal, so Linux CI never sees it.

**Application**: In hack/ scripts guard every possibly-empty array expansion with ${arr[@]+"${arr[@]}"}. Per specs/hack-script-portability.md.

---

## [2026-07-25-124457] Using the proprietary sibling repo as design evidence leaks its internals into tracked files

**Context**: While deciding the pd-m4 add-path shape, I read the sibling repo's convention file to settle the question, then quoted its guide text and attributed the decision to it in a tracked plan file. An unrelated build warning prompted the sweep that caught it.
Expand Down
5 changes: 4 additions & 1 deletion hack/lint-drift.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ drift_grep() {
for ex in "$@"; do
exclude_args+=(--exclude="$ex")
done
grep -rn --include='*.go' --exclude='*_test.go' "${exclude_args[@]}" \
# ${arr[@]+...} guard: bash 3.2 (macOS default) treats an empty
# array expansion as unbound under `set -u`.
grep -rn --include='*.go' --exclude='*_test.go' \
${exclude_args[@]+"${exclude_args[@]}"} \
-E "$pattern" internal/ 2>/dev/null || true
}

Expand Down
39 changes: 39 additions & 0 deletions specs/hack-script-portability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Spec: hack/ Script Portability — macOS Default Toolchain

## Problem

`make audit` fails before running a single real check on a stock
macOS machine (bash 3.2, BSD grep):

`hack/lint-drift.sh` — `"${exclude_args[@]}"` on an empty array
aborts under `set -u` on bash 3.2 ("unbound variable"; bash 4.4+
treats it as empty).

This failure predates any feature work and masks real findings: the
audit gate cannot run at all on contributor machines with the default
macOS toolchain.

The sibling `hack/lint-docstrings.sh` portability bugs (apostrophe in
a `$( … )` comment, `grep -cP` on BSD grep) were fixed upstream; see
`specs/lint-docstrings-macos-portability.md`.

## Fix

Minimal, behavior-preserving substitution that runs identically under
GNU and BSD toolchains:

- `${arr[@]+"${arr[@]}"}` guard for empty-array expansion.

## Non-Goals

- Rewriting the lint scripts in Go (tracked in TASKS.md: "Replace
hack/lint-drift.sh with AST-based Go tests"; "Rewrite lint-style
scripts in Go as ctxctl subcommands"). This spec only unblocks the
gate until that lands.
- A full portability audit of every script under `hack/` (only the
`make audit` chain is in scope).

## Verification

`./hack/lint-drift.sh` completes on macOS (bash 3.2.57, BSD grep)
with the same findings as on a GNU toolchain: `lint-drift: clean`.
Loading