Where: .github/workflows/adr-immutability-check.yml at 74edf84, lines 40–43, under set -euo pipefail:
mapfile -t changes < <(
git diff --name-status "$BASE_SHA" "$HEAD_SHA" -- 'docs/adr/' \
| awk '$2 ~ /^docs\/adr\/[0-9]{4}-.*\.md$/ { print }'
)
if [ ${#changes[@]} -eq 0 ]; then echo "No numbered ADR files changed in this PR."; exit 0; fi
Defect: set -e sees only mapfile's exit status, never the process substitution's. A failing git diff (bad or unreachable SHA) produces no output, mapfile reads zero lines and returns 0, and the script falls into the "no ADR changed" branch — a passing required check on a git error. Harvest 4 makes this load-bearing: dropping the paths: filter and pinning the job name: is exactly what turns the workflow into an always-run, promotable required check (§ Required-checks trap).
Repro: bash -euo pipefail -c 'mapfile -t c < <(git diff bad1 bad2 -- docs/adr/ | awk "{print}"); echo "count: ${#c[@]}"; echo REACHED' → fatal: bad revision, count: 0, REACHED, exit 0.
Fix applied in a target project (https://github.com/crease-data/crease/pull/270, commit fix(ci): adr-immutability-check refuses to pass on a failed git diff): capture with command substitution, whose failure set -e does see —
raw="$(git diff --name-status "$BASE_SHA" "$HEAD_SHA" -- 'docs/adr/')" \
|| { echo "::error::git diff $BASE_SHA $HEAD_SHA failed; not reporting a pass on no data."; exit 1; }
mapfile -t changes < <(printf '%s\n' "$raw" | awk '$2 ~ /^docs\/adr\/[0-9]{4}-.*\.md$/ { print }')
Probed on the extracted run block: no-change → exit 0; bad SHAs → ::error, exit 1; a modified ADR → violation, exit 1; an added ADR → allowed, exit 0. The same shape may exist in other kit workflows that mapfile a process substitution under set -e — worth a grep.
Where:
.github/workflows/adr-immutability-check.ymlat74edf84, lines 40–43, underset -euo pipefail:Defect:
set -esees onlymapfile's exit status, never the process substitution's. A failinggit diff(bad or unreachable SHA) produces no output,mapfilereads zero lines and returns 0, and the script falls into the "no ADR changed" branch — a passing required check on a git error. Harvest 4 makes this load-bearing: dropping thepaths:filter and pinning the jobname:is exactly what turns the workflow into an always-run, promotable required check (§ Required-checks trap).Repro:
bash -euo pipefail -c 'mapfile -t c < <(git diff bad1 bad2 -- docs/adr/ | awk "{print}"); echo "count: ${#c[@]}"; echo REACHED'→fatal: bad revision,count: 0,REACHED, exit 0.Fix applied in a target project (https://github.com/crease-data/crease/pull/270, commit
fix(ci): adr-immutability-check refuses to pass on a failed git diff): capture with command substitution, whose failureset -edoes see —Probed on the extracted run block: no-change → exit 0; bad SHAs →
::error, exit 1; a modified ADR → violation, exit 1; an added ADR → allowed, exit 0. The same shape may exist in other kit workflows thatmapfilea process substitution underset -e— worth a grep.