Skip to content

fix(ci): the pre-publish bashrs gate went red again — #3187 added two SEC010 to the file #3188 had just cleared, because bashrs never runs on a PR (PMAT-1098) - #3194

Merged
noahgift merged 1 commit into
mainfrom
PMAT-1098-bashrs-gate-2
Sep 12, 2026

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

The release gate went red again, four hours after it was cleared

scripts/dogfood.sh --phase pre-publish on ee76ee39c — the commit that carries #3188's own bashrs fix — returned NO-GO:

[FAIL] bashrs  2 SEC/DET/IDEM error(s) over 293 file(s): SEC010
NO-GO — these gates are RED (fix the root cause; never bypass)

Both findings are in scripts/check_roadmap_diff_additive.sh, at the two cd "$Q.clone" sites #3187 added to the self-test case table — landed four hours after #3188 cleared the previous nine, in the same file family, with nothing in between to catch them.

That gap is the real finding and it has its own issue. The bashrs gate lives inside scripts/dogfood.sh; no CI job runs bashrs on a pull request. So every PR can add SEC/DET/IDEM findings freely and they surface only when a release train reaches its pre-publish gate. This is the second time tonight that has stopped the 0.67.0 train.

The fix

The harness cd'd into the fixture clone so the script under test would see it as cwd. That requirement belongs to the inner shell, so it is now handed the directory and cds itself. Neither site contains a cd of this script's own any more, and the inner bash -c exits 2 if the directory is not usable.

What was measured, rather than assumed

Every alternative was tried against the real file with bashrs 7.3.0 before settling:

attempt result
validate $Q where it is defined still 2
validate immediately before each cd still 2
cd -- form still 2
cd "$TD" && cd <literal> still 2
alias the path through a command substitution worse, 2 → 4
move the cd into the inner shell CLEAN

So the rule is not asking for a check here; it objects to this script performing the cd. Note its own message asks that paths "don't contain .. or start with /", while these are mktemp -d paths and are necessarily absolute.

bashrs fix must not be used on this file. It reported "fixed 21 issues" and corrupted the script: trap 'rm -rf -- "${TD:?}"' EXIT became trap "rm -rf -- "${TD:?}"" EXIT, and it swapped the quote characters inside five assert_row calls, turning valid code into broken code. Filed separately.

Discrimination and acceptance

Restore either cd and SEC010 returns at that exact line. With both moved inward:

check result
check_roadmap_diff_additive.sh CLEAN, no diagnostics of any code
full 293-file surface, the gate's own git ls-files enumeration zero DET/SEC/IDEM; the 7 remaining SC10xx are the #226 class the gate suppresses
bash scripts/check_roadmap_diff_additive.sh --self-test rc=0, 24/24 rows
the two rows whose cd moved row 19 stacked merge_group entry at depth-1 -> deepened and row 20 stacked entry with deepening disabled (mutation): refused by name, both still ok
bash -n clean

APR-RELEASE-001 session 2, ticket PMAT-1098. This unblocks T-2 for the 0.67.0 tag.

🤖 Generated with Claude Code

…runs at release time and never on a PR, so #3187 merged two SEC010 into the same file that had just been cleared

`dogfood.sh --phase pre-publish` on `ee76ee39c` (the commit carrying #3188's own
bashrs fix) returned NO-GO again:

    [FAIL] bashrs  2 SEC/DET/IDEM error(s) over 293 file(s): SEC010

Both in `scripts/check_roadmap_diff_additive.sh`, at the two `cd "$Q.clone"` sites
that #3187 added to the self-test case table four hours after #3188 cleared the
previous nine. Nothing caught them in between, because the bashrs gate lives in
`scripts/dogfood.sh` and no CI job runs it — filed separately, it is the reason
this class keeps landing on the train rather than on the PR that writes it.

The fix: the harness cd'd into the fixture clone so the script under test would
see it as cwd. That requirement belongs to the INNER shell, so it is handed the
directory and cds itself. No `cd` of this script's own remains at either site.

What was measured, not assumed:
  * validating `$Q` at its definition does NOT clear SEC010 (still 2)
  * validating immediately before each `cd` does NOT clear it (still 2)
  * `cd --`, `cd "$TD" && cd <literal>`, and a command-substitution alias do NOT
    clear it; the alias made it worse (2 -> 4)
  * `bashrs fix` CORRUPTS this file — it rewrote `trap 'rm -rf -- "${TD:?}"' EXIT`
    into `trap "rm -rf -- "${TD:?}"" EXIT` and swapped the quote characters inside
    five `assert_row` calls, turning valid code into broken code. Filed separately.
  * restore either `cd` and SEC010 returns at that line; with both moved inward the
    file is CLEAN and the full 293-file surface has ZERO DET/SEC/IDEM

The guard's own case table is unchanged and still green: 24/24 rows, including
row 19 (`stacked merge_group entry at depth-1 -> deepened`) and row 20 (`stacked
entry with deepening disabled (mutation): refused by name`) — the two rows whose
`cd` moved. `bash -n` clean.

Pmat-Ticket: PMAT-1098
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@noahgift
noahgift enabled auto-merge September 12, 2026 21:05
@noahgift noahgift added this to the 0.67.0 milestone Sep 12, 2026
@github-actions

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3194 head=958b8c618ca8a56d4da3cecfb5350aff7670269a verdict=REFUSE class=Q1 arm_rc=1

Shadow mode: this records a verdict and merges nothing. A refusal
to arm is not a block (§13 adds zero rows to §7) — the pull request is
exactly as green as it was.

@noahgift
noahgift added this pull request to the merge queue Sep 12, 2026
Merged via the queue into main with commit 0fd6fbc Sep 12, 2026
19 of 20 checks passed
@noahgift
noahgift deleted the PMAT-1098-bashrs-gate-2 branch September 12, 2026 22:21
noahgift added a commit to guyernest/aprender that referenced this pull request Sep 13, 2026
…e 0.67.0 train three times on findings no PR check saw (paiml#3196) (paiml#3199)

dogfood.sh's bashrs row is the only place the SEC/DET/IDEM filter ran, so a PR could add a finding freely and the train paid for it at the pre-publish gate: 17:33Z (paiml#3115, paiml#3127 -> fixed by paiml#3188), 20:58Z (paiml#3187 -> paiml#3194), 22:48Z (paiml#3068 -> paiml#3198). Three fixes round the merge queue while the tag waited.

scripts/check_bashrs_gate.sh is that gate lifted out where the finding is cheap: same surface enumeration (git ls-files, N+1 receipt asserted), same positive control (a DET002 sentinel that must fire or the run is ENV/2), same code filter. Its --self-test carries a drift gate that greps dogfood.sh for the identical rule tuples, a classifier case table, a must-RED fixture repo built from the incident's exact construct (a --repo argument parsed into a variable and used in a subshell cd; cd "$1" alone is not flagged, measured), its must-GREEN twin carrying paiml#3198's validation, and a vacuity case (gitignored script -> exit 2, named).

Measured on real trees: main @ 0b6f94c -> exit 1, names cuda_rust_fleet_check.sh:129 DET002 and :201 SEC010; paiml#3198's tree -> exit 0. 3 s over 294 files. Wired as a step of guard-cargo, which gate already requires. dogfood.sh is untouched in this change; consolidating its inline row onto this script is the follow-up named in paiml#3196.

Pmat-Ticket: PMAT-1098

Co-authored-by: Noah Gift <claude@noahgift.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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