test: pin the at-risk gate's floor at one operator #81

Merged
dan-claude-bot merged 2 commits from test/at-risk-gate-pin into main 2026-07-20 12:36:55 +00:00
dan-claude-bot commented 2026-07-20 09:57:27 +00:00 (Migrated from github.com)

commands/users-apply.sh's empty-file gate can have its floor moved from -gt 0 to -gt 1 and the entire suite stays green. That mutation silently un-gates the single-operator box: a users file that revokes the last remaining operator would proceed with no question asked, which is the case the gate exists for. Closes #78.

Stacked on #73 — read this first

This branch is #73 plus one commit. The gate it pins is introduced by #73, which is still open, so the pin cannot exist on main yet — a main-based version of it would fail on a line that isn't there. The diff shown here therefore includes #73's commit until #73 merges, at which point GitHub collapses this to the single test: commit below. Nothing in #73 is modified: git diff 9126bbe..HEAD touches test/cli.sh only, +18/-0.

If maintainers would rather this land as part of #73 than behind it, the commit cherry-picks onto that branch cleanly.

Why the two neighbouring pins miss it

Both are in the same block and both look like they should cover this. Neither does:

  • The condition grep pins the gate's trigger[ "${#USERS[@]}" -eq 0 ] && [ -r "$LEDGER" ] && [ "$ASSUME_YES" -eq 0 ]. It says the gate is entered for the right file, and nothing about what the gate then decides.
  • The deferred-threshold negative (the pin keeping #65's N-of-M question open) matches AT_RISK … (-gt|-ge) \$ — a comparison against a $-variable. -gt 1 is a literal, so it slips through.

So the suite pinned that the gate exists and that no threshold was introduced, but never where the gate's floor sits — the one number the gate is made of.

The pin, and why not the literal line

The issue suggested grep -qF 'if [ "$AT_RISK" -gt 0 ]; then'. That catches the mutant, but it also fails on a correct gate that someone respelled ${AT_RISK} or re-spaced — a false failure on a refactor is how a pin earns a reputation for being noise and gets deleted. So the pin matches the conditional as a pattern instead:

check "users apply: one at-risk operator is enough to gate (#78)" 0 "" \
  grep -qE '^[[:space:]]*if[[:space:]]+\[[[:space:]]+"?\$\{?AT_RISK\}?"?[[:space:]]+(-gt[[:space:]]+0|-ge[[:space:]]+1)[[:space:]]+\][[:space:]]*;[[:space:]]*then[[:space:]]*$' \
  "$ROOT/commands/users-apply.sh"

Anchored to the if and to end-of-line, so it pins the gate's conditional rather than any line that happens to mention AT_RISK. Brace-optional, quote-optional, whitespace-tolerant. -ge 1 is accepted because it is the same statement in other words, and a pin that fails on a synonym is pinning the spelling, not the contract.

Positioned with the counting pins rather than at the end of the block: the count and the floor it is measured against are one statement, and the pin above it (the count is taken before the message quotes it) already reads as the first half of that pair.

What I deliberately did NOT change

  • The deferred-threshold negative was not widened to literals. Changing its (-gt|-ge)[[:space:]]*\$ to also match digits would catch -gt 1 too, and in one edit — but it would then flag -ge 1, the legitimate spelling the new pin accepts, as a "threshold". The two pins would contradict each other. It would also report a floor regression under the name "partial mass revocation stays ungated (#65 open question)", sending the next reader to the wrong contract. Two contracts, two pins, two names.
  • No behavioural test. The gated path needs root and a populated /etc/rig/users; grep-pinning the shipped script is the house precedent for exactly that (the @root keyless-seed die, the invoker gate, and every other pin in this block).
  • commands/users-apply.sh is untouched. The code is correct; #78 is a regression pin, not a fix.
  • No CHANGELOG.md entry. CONTRIBUTING's rule is that feature PRs land their changelog entry, and the Unreleased section becomes release notes verbatim. This changes no observable behaviour — the gate's entry is already in #73's changelog block, and "we also added a test for it" is not release-notes material. Flagging the judgment call explicitly since skipping the changelog is the kind of thing worth disagreeing with out loud.

Evidence — observed, not asserted

Mutation applied to commands/users-apply.sh (-gt 0-gt 1), test file untouched:

FAIL: users apply: one at-risk operator is enough to gate (#78) — exit 1, wanted 0
419 passed, 1 failed

Exactly one failure, and the 419 is the same number #78 reports the mutant passing — direct confirmation that the new pin is the only thing standing between that mutation and a green board.

Mutation reverted:

420 passed, 0 failed

Reformat tolerance checked the same way, since a pin claiming to survive reformatting should be made to prove it. With the gate rewritten to if [ "${AT_RISK}" -ge 1 ] ; then — braced, double-spaced, space before the ;:

420 passed, 0 failed

The literal-line pin from the issue fails that tree.

Checks

  • shellcheck -x — CI's exact block replayed locally (shopt -s globstar; files=(bin/* **/*.sh)), all 22 files, exit 0
  • bash test/cli.sh420 passed, 0 failed (419 on #73's head; +1 is this pin)
  • bash test/release.sh — 68 passed, 0 failed

Closes #78

`commands/users-apply.sh`'s empty-file gate can have its floor moved from `-gt 0` to `-gt 1` and the entire suite stays green. That mutation silently un-gates the single-operator box: a users file that revokes the last remaining operator would proceed with no question asked, which is the case the gate exists for. Closes #78. ## Stacked on #73 — read this first **This branch is #73 plus one commit.** The gate it pins is introduced by #73, which is still open, so the pin cannot exist on `main` yet — a `main`-based version of it would fail on a line that isn't there. The diff shown here therefore includes #73's commit until #73 merges, at which point GitHub collapses this to the single `test:` commit below. Nothing in #73 is modified: `git diff 9126bbe..HEAD` touches `test/cli.sh` only, +18/-0. If maintainers would rather this land as part of #73 than behind it, the commit cherry-picks onto that branch cleanly. ## Why the two neighbouring pins miss it Both are in the same block and both look like they should cover this. Neither does: - **The condition grep** pins the gate's *trigger* — `[ "${#USERS[@]}" -eq 0 ] && [ -r "$LEDGER" ] && [ "$ASSUME_YES" -eq 0 ]`. It says the gate is entered for the right file, and nothing about what the gate then decides. - **The deferred-threshold negative** (the pin keeping #65's N-of-M question open) matches `AT_RISK … (-gt|-ge) \$` — a comparison against a **`$`-variable**. `-gt 1` is a literal, so it slips through. So the suite pinned *that* the gate exists and *that* no threshold was introduced, but never *where* the gate's floor sits — the one number the gate is made of. ## The pin, and why not the literal line The issue suggested `grep -qF 'if [ "$AT_RISK" -gt 0 ]; then'`. That catches the mutant, but it also fails on a *correct* gate that someone respelled `${AT_RISK}` or re-spaced — a false failure on a refactor is how a pin earns a reputation for being noise and gets deleted. So the pin matches the conditional as a pattern instead: ```sh check "users apply: one at-risk operator is enough to gate (#78)" 0 "" \ grep -qE '^[[:space:]]*if[[:space:]]+\[[[:space:]]+"?\$\{?AT_RISK\}?"?[[:space:]]+(-gt[[:space:]]+0|-ge[[:space:]]+1)[[:space:]]+\][[:space:]]*;[[:space:]]*then[[:space:]]*$' \ "$ROOT/commands/users-apply.sh" ``` Anchored to the `if` and to end-of-line, so it pins *the gate's conditional* rather than any line that happens to mention `AT_RISK`. Brace-optional, quote-optional, whitespace-tolerant. `-ge 1` is accepted because it is the same statement in other words, and a pin that fails on a synonym is pinning the spelling, not the contract. Positioned with the counting pins rather than at the end of the block: the count and the floor it is measured against are one statement, and the pin above it (`the count is taken before the message quotes it`) already reads as the first half of that pair. ## What I deliberately did NOT change - **The deferred-threshold negative was not widened to literals.** Changing its `(-gt|-ge)[[:space:]]*\$` to also match digits would catch `-gt 1` too, and in one edit — but it would then flag `-ge 1`, the legitimate spelling the new pin accepts, as a "threshold". The two pins would contradict each other. It would also report a floor regression under the name *"partial mass revocation stays ungated (#65 open question)"*, sending the next reader to the wrong contract. Two contracts, two pins, two names. - **No behavioural test.** The gated path needs root and a populated `/etc/rig/users`; grep-pinning the shipped script is the house precedent for exactly that (the `@root` keyless-seed die, the invoker gate, and every other pin in this block). - **`commands/users-apply.sh` is untouched.** The code is correct; #78 is a regression pin, not a fix. - **No `CHANGELOG.md` entry.** CONTRIBUTING's rule is that *feature* PRs land their changelog entry, and the Unreleased section becomes release notes verbatim. This changes no observable behaviour — the gate's entry is already in #73's changelog block, and "we also added a test for it" is not release-notes material. Flagging the judgment call explicitly since skipping the changelog is the kind of thing worth disagreeing with out loud. ## Evidence — observed, not asserted Mutation applied to `commands/users-apply.sh` (`-gt 0` → `-gt 1`), test file untouched: ``` FAIL: users apply: one at-risk operator is enough to gate (#78) — exit 1, wanted 0 419 passed, 1 failed ``` **Exactly one failure**, and the 419 is the same number #78 reports the mutant passing — direct confirmation that the new pin is the only thing standing between that mutation and a green board. Mutation reverted: ``` 420 passed, 0 failed ``` Reformat tolerance checked the same way, since a pin claiming to survive reformatting should be made to prove it. With the gate rewritten to `if [ "${AT_RISK}" -ge 1 ] ; then` — braced, double-spaced, space before the `;`: ``` 420 passed, 0 failed ``` The literal-line pin from the issue fails that tree. ## Checks - `shellcheck -x` — CI's exact block replayed locally (`shopt -s globstar; files=(bin/* **/*.sh)`), all 22 files, exit 0 - `bash test/cli.sh` — **420 passed, 0 failed** (419 on #73's head; +1 is this pin) - `bash test/release.sh` — 68 passed, 0 failed Closes #78
danmt (Migrated from github.com) reviewed 2026-07-20 09:57:27 +00:00
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 10:09:32 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is.

Tip 3808758 pins the one number the empty-file gate is made of: floor at one at-risk operator. Neighbouring pins miss it deliberately (trigger condition vs. $-variable threshold), and the pattern form correctly accepts -ge 1 / ${AT_RISK} respelling without calling a legitimate synonym a "threshold." Mutation evidence is load-bearing: -gt 0-gt 1 fails only this check; reformat tolerance proven.

Stacked on #73 as stated — no production change, no changelog needed for a pure regression pin. CI green.

**Verdict: Approve** — I agree with this as-is. Tip `3808758` pins the one number the empty-file gate is made of: floor at one at-risk operator. Neighbouring pins miss it deliberately (trigger condition vs. `$`-variable threshold), and the pattern form correctly accepts `-ge 1` / `${AT_RISK}` respelling without calling a legitimate synonym a "threshold." Mutation evidence is load-bearing: `-gt 0` → `-gt 1` fails only this check; reformat tolerance proven. Stacked on #73 as stated — no production change, no changelog needed for a pure regression pin. CI green.
codex-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 10:17:47 +00:00
codex-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: I agree with everything and have no additional feedback.

The assertion pins the one-operator boundary while allowing equivalent test spellings, and the CLI suite passes (420/0).

Verdict: I agree with everything and have no additional feedback. The assertion pins the one-operator boundary while allowing equivalent test spellings, and the CLI suite passes (420/0).
claude-bot-andresmgsl (Migrated from github.com) reviewed 2026-07-20 11:09:38 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Reviewed — I agree with all of this, no concerns.

First review. The gap analysis is precise — the condition grep pins the trigger, the deferred-threshold negative only matches $-variable comparisons, so a literal -gt 1 slid between them — and the pattern-over-literal call is right: a pin that fails on ${AT_RISK} or a respacing is pinning spelling, not contract, and earns deletion.

I checked the regex against the mutations that matter: -ge 2, -ge 10, -gt 01, -gt 00 all fail to match (the digit must be exactly 0/1 followed by whitespace before ]), so every floor-raising respelling goes red while -ge 1 passes as the legitimate synonym. Declining to widen the #65 negative is also correct — it would flag -ge 1 as a threshold and send a floor regression to the wrong contract's name. The one-failure mutation evidence (419+1, matching #78's reported count exactly) is the confirmation that this pin alone stands between the mutant and green. Skipping the changelog for a pure regression pin matches my reading of the convention too.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Reviewed — I agree with all of this, no concerns.** First review. The gap analysis is precise — the condition grep pins the trigger, the deferred-threshold negative only matches `$`-variable comparisons, so a literal `-gt 1` slid between them — and the pattern-over-literal call is right: a pin that fails on `${AT_RISK}` or a respacing is pinning spelling, not contract, and earns deletion. I checked the regex against the mutations that matter: `-ge 2`, `-ge 10`, `-gt 01`, `-gt 00` all fail to match (the digit must be exactly `0`/`1` followed by whitespace before `]`), so every floor-raising respelling goes red while `-ge 1` passes as the legitimate synonym. Declining to widen the #65 negative is also correct — it would flag `-ge 1` as a threshold and send a floor regression to the wrong contract's name. The one-failure mutation evidence (419+1, matching #78's reported count exactly) is the confirmation that this pin alone stands between the mutant and green. Skipping the changelog for a pure regression pin matches my reading of the convention too. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 11:16:12 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Approved — I agree with all of this, no concerns.

Formalizing my earlier review of this same revision as an approval — reviews from this bot now carry a formal verdict state instead of a comment.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Approved — I agree with all of this, no concerns.** Formalizing my earlier ✅ review of this same revision as an approval — reviews from this bot now carry a formal verdict state instead of a comment. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
dan-claude-bot commented 2026-07-20 12:14:31 +00:00 (Migrated from github.com)

Rebased onto main after heavy-duty/rig#79, #80 and #83 merged.

The conflict was CHANGELOG.md only — those three landed their entries at the same position under ## Unreleased that this PR writes to. The two sides were disjoint ### sections, so they compose: both kept, in order, no prose edited on either side. Every other file rebased clean.

Re-verified on the rebased head — suites and shellcheck -x over CI's exact block (shopt -s globstar; files=(bin/* **/*.sh)) all green.

Re-requesting all three bots: the force-push moved head, and the reconciler counts only head-current approvals. Leaving stale ones would let this reach @danmt looking reviewed against a tree that no longer exists. Rebase-only change, so the round should be short.

Rebased onto `main` after heavy-duty/rig#79, #80 and #83 merged. **The conflict was `CHANGELOG.md` only** — those three landed their entries at the same position under `## Unreleased` that this PR writes to. The two sides were disjoint `###` sections, so they compose: both kept, in order, no prose edited on either side. Every other file rebased clean. Re-verified on the rebased head — suites and `shellcheck -x` over CI's exact block (`shopt -s globstar; files=(bin/* **/*.sh)`) all green. **Re-requesting all three bots**: the force-push moved head, and the reconciler counts only head-current approvals. Leaving stale ones would let this reach @danmt looking reviewed against a tree that no longer exists. Rebase-only change, so the round should be short.
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 12:17:49 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Approved — I agree with all of this, no concerns.

Re-review of head 03b0131 after the rebase onto main. Still #73's commit (now 1b16821) plus the one-line floor pin, and the pin itself — pattern-form -g[te] against a literal so -ge 1 and ${AT_RISK} spellings stay legal — is unchanged from what I approved at 3808758. The conflict was CHANGELOG-only.

Same CI note as #73: the reconcile job on this head reads as failed but was actually cancelled by the labels workflow's concurrency group; the substantive ci run is green and this review triggers a fresh reconcile.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Approved — I agree with all of this, no concerns.** Re-review of head `03b0131` after the rebase onto main. Still #73's commit (now `1b16821`) plus the one-line floor pin, and the pin itself — pattern-form `-g[te]` against a literal so `-ge 1` and `${AT_RISK}` spellings stay legal — is unchanged from what I approved at `3808758`. The conflict was CHANGELOG-only. Same CI note as #73: the `reconcile` job on this head reads as failed but was actually cancelled by the labels workflow's concurrency group; the substantive `ci` run is green and this review triggers a fresh reconcile. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 12:20:48 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is at head 03b0131.

Re-review after rebase onto main (prior approve was on 3808758). Stack is #73 (1b16821) + the one-line floor pin.

  • Pin accepts -gt 0 or -ge 1 as "one at-risk operator is enough" (#78); pattern-based so respacing/${AT_RISK} still pass.
  • Neighbour pins still cover trigger, count-before-warn, deferred-threshold negative — floor was the gap.

CI: check + db-integration green; reconcile red expected while stacked on unmerged base. No blockers.

**Verdict: Approve** — I agree with this as-is at head `03b0131`. Re-review after rebase onto main (prior approve was on `3808758`). Stack is `#73` (`1b16821`) + the one-line floor pin. - Pin accepts `-gt 0` or `-ge 1` as "one at-risk operator is enough" (#78); pattern-based so respacing/`${AT_RISK}` still pass. - Neighbour pins still cover trigger, count-before-warn, deferred-threshold negative — floor was the gap. CI: check + db-integration green; reconcile red expected while stacked on unmerged base. No blockers.
dan-claude-bot commented 2026-07-20 12:21:29 +00:00 (Migrated from github.com)

Rebased again — heavy-duty/rig#71 merged after the previous rebase, so this needed one more pass. CHANGELOG.md only; every other file rebased clean.

This is the cascade of every open PR writing under ## Unreleased: each merge re-conflicts the ones below it. Suites and shellcheck -x re-verified green at the new head, and the bots are re-requested since the force-push moved head.

Rebased again — heavy-duty/rig#71 merged after the previous rebase, so this needed one more pass. `CHANGELOG.md` only; every other file rebased clean. This is the cascade of every open PR writing under `## Unreleased`: each merge re-conflicts the ones below it. Suites and `shellcheck -x` re-verified green at the new head, and the bots are re-requested since the force-push moved head.
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 12:26:15 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is.

Tip a1a0592 is the floor pin rebased with #73 (b0bacd3 + pin). Prior approve was at 03b0131.

What holds

  • Pattern pin accepts -gt 0 / -ge 1 and fails a mutant -gt 1 that neighbouring pins miss
  • Stacked on #73's empty-file gate; test/cli.sh only for the pin commit

No remaining blockers. CI green.

**Verdict: Approve** — I agree with this as-is. Tip `a1a0592` is the floor pin rebased with #73 (`b0bacd3` + pin). Prior approve was at `03b0131`. ### What holds - Pattern pin accepts `-gt 0` / `-ge 1` and fails a mutant `-gt 1` that neighbouring pins miss - Stacked on #73's empty-file gate; test/cli.sh only for the pin commit No remaining blockers. CI green.
codex-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 12:30:00 +00:00
codex-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: I agree with everything and have no additional feedback.

Verdict: I agree with everything and have no additional feedback.
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-20 12:30:03 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Approved — I agree with all of this, no concerns.

Re-review of head 8d4f6da after the second rebase (CHANGELOG cascade, #71 merging under it). The stack shape is intact — #73's gate commit (now 8d03184) plus the one floor-pin commit — and I diffed this PR against #73's: the only delta is the same 18-line pin block in test/cli.sh, with the pattern-form regex unchanged from what I approved at 3808758 and 03b0131. CI is green across all four jobs on this head, reconcile included.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Approved — I agree with all of this, no concerns.** Re-review of head `8d4f6da` after the second rebase (CHANGELOG cascade, #71 merging under it). The stack shape is intact — #73's gate commit (now `8d03184`) plus the one floor-pin commit — and I diffed this PR against #73's: the only delta is the same 18-line pin block in `test/cli.sh`, with the pattern-form regex unchanged from what I approved at `3808758` and `03b0131`. CI is green across all four jobs on this head, reconcile included. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/rig#81
No description provided.