Skip to content

fix(tooling): stop two silent false signals, in test selection and in bootstrap health - #3487

Merged
kyle-sexton merged 3 commits into
mainfrom
claude/repo-improvement-discovery-y2wg3r
Aug 29, 2026
Merged

fix(tooling): stop two silent false signals, in test selection and in bootstrap health#3487
kyle-sexton merged 3 commits into
mainfrom
claude/repo-improvement-discovery-y2wg3r

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

No linked issue

Summary

Two independent false signals found by an evidence-first improvement scan, both of the same shape: a check that reported healthy when it was not. Each is fixed and each now has a test that fails without the fix.

  1. scripts/affected-tests.sh claimed coverage a file did not have, because R3/R4 matched a basename as an unanchored substring. A file with no suite of its own could select many suites and exit 0, so the repo's "a changed file that maps to zero suites is an error" contract silently did not apply. This is the gap class behind the kindle-dedrm firewall defect (fix(kindle-dedrm): compare firewall rule state against 'True', not truthiness #3396).
  2. .claude/cloud-bootstrap.sh reported dozens of failures per session start for a perfectly healthy plugin registry, because claude plugin install --scope user -y already leaves a plugin enabled, so the chain's tail plugin enable exits 1 with "already enabled at user scope" and the three steps were joined with &&. The failure count is the bootstrap's only health signal, and the false alarms buried it.

Fix

Test selection. A file now names another only when the basename appears bounded on both sides by a character outside [A-Za-z0-9_.-]. / is deliberately outside that class, so path-qualified, prose and comment mentions all still count; a trailing run of . is sentence punctuation; a basename the rule cannot spell falls back to the old substring test rather than to zero coverage. Matching stays a basename rule because the cross-plugin copy fan-out depends on it. Exposing the false coverage revealed a real gap it had been masking: several Python files whose only suite is <dir>/tests/test_<stem>.py were unreachable by any name match, since those suites import <module> and never spell the filename, so R2 gained that path arm.

Bootstrap health. The three subcommand exit statuses are now advisory. Verification reads the end state once per run, over every plugin enabledPlugins turns on, and counts a plugin failed only when it is absent at user scope, present without enabled: true, or its own directory under plugins/ changed between the recorded gitCommitSha and HEAD. Cases where the snapshot cannot be determined at all (no resolvable HEAD, no registry, absent or null recorded sha, a commit this clone lacks) fail closed with a named reason rather than reading as healthy. An unreadable plugin list --json fails the batch in one line instead of one warning per plugin.

Verification

Measured, not asserted:

  • Selection hazard, end to end: an uncovered hook body dropped into a scratch clone selected 131 suites at exit 0 before; it is now UNMAPPED at exit 1.
  • Sweep over every tracked file (3,455): 534 files select fewer suites (15.8% fewer selected-suite slots), 4 previously-UNMAPPED files became mapped to the suites that genuinely test them, nothing became unmapped. 25 files dropped to an empty selection, every one a markdown context file whose basename had been landing inside a longer one, and every one already covered by a class in affected-tests-no-suite.txt, so they report as no-suite at exit 0.
  • Bootstrap, live on a real machine: 72 enabled, 0 newly installed, 0 refreshed, 0 failed, where the previous code reported every refresh as failed.
  • Suites: affected-tests.test.sh 56 assertions green (47 before); new .claude/hooks/cloud-bootstrap-plugins.test.sh 32 assertions green, discovered by the existing find plugins .claude/hooks roots with no ci.yml change.

Both changes were reviewed by independent fresh-context verifiers that re-derived the evidence rather than trusting it. The selector verifier recomputed the full sweep itself, hand-read all 190 dropped basename/enclosing-token pairs (only two name the real file, and both keep their suites through other bounded mentions), proved a direct-coverage invariant over all 3,455 files with zero missing a suite that genuinely names it, and killed 8 of its own 10 mutations. The bootstrap verifier ran 19 fail-open probes (glob and space-bearing ids, declare -A re-entry, duplicate ids, degenerate list JSON and registry shapes, no-git-repo, set -u interaction) without constructing a fail-open, and its first pass rejected an earlier version that still printed 0 failed for five bad end states; those five are now pinned by tests, along with the extraction anchors and the block's exit status, since a nonzero exit there would abort the whole bootstrap under set -e.

Related

  • fix(kindle-dedrm): compare firewall rule state against 'True', not truthiness #3396 (the shipped defect exemplifying the false-coverage class)
  • A third scan candidate, a 43x speedup of the shell-portability scan, is deliberately not in this PR. A verifier found a correctness regression in it, so it is parked unmerged on wip/portability-perf-unverified with the defect, the reproducer and the fix shape recorded in its commit message.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T


Generated by Claude Code

claude added 2 commits August 29, 2026 00:32
…lure

`claude plugin install --scope user -y` already leaves the plugin enabled, so
the refresh chain's tail `plugin enable` exits 1 with "already enabled at user
scope" on the healthy path. The three steps were joined with `&&`, so every
successful refresh scored as a failure: the startup line read "65 failed" and
"54 failed" for a registry that was verifiably installed, enabled and at HEAD.
The failure count is the bootstrap's only health signal, and dozens of false
alarms per session start buried it.

The three subcommand exit statuses are now advisory. Verification instead reads
the end state once per run, over every plugin `enabledPlugins` turns on, and
counts a plugin failed only when it is absent at user scope, present there
without `enabled: true`, or its own directory under `plugins/` changed between
the recorded `gitCommitSha` and HEAD. Cases where the snapshot cannot be
determined at all (no resolvable HEAD, no registry, absent or null recorded
sha, a commit this clone lacks) fail closed with a named reason rather than
reading as healthy. An unreadable `plugin list --json` fails the batch in one
line instead of one warning per plugin.

Verified live on this machine: 72 enabled, 0 newly installed, 0 refreshed,
0 failed, where the previous code reported every refresh as failed.

Adds `.claude/hooks/cloud-bootstrap-plugins.test.sh`, 32 assertions driven by a
stub CLI over synthetic registries, discovered by the existing
`find plugins .claude/hooks` roots with no ci.yml change. It pins the five
end states that previously reported "0 failed", the extraction anchors it
depends on, and the block's exit status, since a nonzero exit there would abort
the whole bootstrap under `set -e`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T
…d basename match

R3 and R4 matched a changed file's basename as an unanchored substring of other
files, so a file with no suite of its own could still select many suites and
exit 0. That is not the safe over-selection the header describes, it is
fail-open: the "a changed file that maps to zero suites is an error" contract
silently did not apply. Measured on this tree, a new uncovered hook body
(`utils.sh` under a plugin's hooks/) selected 131 suites at exit 0; it is now
reported UNMAPPED at exit 1. The same hazard is what let `babysit_lease.py`
report five suites, none of them its own, purely because its name is a
substring of `manage_babysit_lease.py`.

A file now names another only when the basename appears bounded on both sides
by a character outside [A-Za-z0-9_.-]. `/` is deliberately outside that class,
so path-qualified mentions, prose mentions and comment mentions all still
count, and a trailing run of `.` is treated as sentence punctuation. A basename
the rule cannot spell falls back to the old substring test rather than to zero
coverage. Matching stays a basename rule because the cross-plugin copy fan-out
depends on it.

Exposing the false coverage revealed a real gap it had been masking: several
Python files whose only suite is `<dir>/tests/test_<stem>.py` were never
reachable by a name match, because those suites say `import <module>` and never
spell the filename. R2 gained that path arm, and four files that were UNMAPPED
now map to the suites that genuinely test them.

Swept over every tracked file: 534 files select fewer suites (15.8% fewer
selected-suite slots), 4 UNMAPPED files became mapped, nothing became unmapped.
25 files dropped to an empty selection, every one a markdown context file whose
basename had been landing inside a longer one, and every one already covered by
a class in scripts/affected-tests-no-suite.txt, so they report as no-suite at
exit 0.

Independently verified: all 190 dropped basename/enclosing-token pairs were
read, only two name the real file (both keep their suites through other bounded
mentions), and a direct-coverage invariant over all 3455 tracked files found no
file missing a suite that genuinely names it. Selection also got faster, since
the frontier is smaller.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T
@kyle-sexton
kyle-sexton enabled auto-merge (squash) August 29, 2026 03:33
@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 6m 42s —— View job


CI code review — PR #3487

  • Gather context (PR body, changed files, gh pr diff)
  • Invoke /review:code-review criteria for this PR
  • Read .claude/cloud-bootstrap.sh, scripts/affected-tests.sh, and both test suites in full (not just the diff)
  • Post summary

Scope reviewed: .claude/cloud-bootstrap.sh, .claude/hooks/cloud-bootstrap-plugins.test.sh (new), docs/CLOUD-SESSIONS.md, scripts/affected-tests.sh, scripts/affected-tests.test.sh.

No blocking correctness or maintainability issues found. Notes from the review:

scripts/affected-tests.shtoken_hits boundary rule (L463-L515): traced the two-stage git grep -Ftoken_hits awk pipeline by hand against the described edge cases (path-qualified mentions, sentence-final ., ellipsis-prefixed mentions, untokenizable basenames falling back to substring, same-basename-in-another-directory staying generous). The -o flag's removal from git grep is required and correctly compensated for — token_hits now needs the full line text to test token boundaries, and its per-line token scan recovers every basename match even though git grep collapses multi-pattern hits on one line to a single output line (previously -o emitted one line per match). The keep() dedup on (path, name) is a net improvement over the old ungrouped hits stream, not a regression.

.claude/cloud-bootstrap.sh — end-state verification (L248-L340): checked the set -euo pipefail interaction the PR description calls out — every subcommand that can legitimately fail (uninstall/install/enable, the plugin list --json capture, both jq -e probes) is now guarded with || true or lives in an if/elif condition, so nothing here can abort the bootstrap under set -e. Traced the action_of bookkeeping and the failed/refreshed/installed partition through the "steady", "refreshed", "stale_refresh_stuck", and "unreadable" scenarios by hand; the counts partition correctly and the docs addition in docs/CLOUD-SESSIONS.md matches the code (e.g. exactly two plugin list calls per run, the git diff <recorded> HEAD -- plugins/<name> staleness check, fail-closed unknowns).

Verified by static reading, not execution: this lane's Bash access is restricted to gh pr diff/view/comment/review, so I could not run scripts/affected-tests.test.sh or the new .claude/hooks/cloud-bootstrap-plugins.test.sh myself, and the PR's own pass counts (56/32 assertions, the 3,455-file sweep, the live-machine numbers) are author-claimed and unverified by me. I did confirm the test file's extraction anchors (^claude_bin=, ^# --- Python CI deps) exist verbatim in the committed .claude/cloud-bootstrap.sh at the expected lines, so the anchor-drift guard the suite depends on is sound against this HEAD.

@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 41s —— View job


Security review — /review:security-review

Skip-gate check: PR is open; not closed. No prior review found on this head. Proceeded to a full read of the diff.

Scope: .claude/cloud-bootstrap.sh, .claude/hooks/cloud-bootstrap-plugins.test.sh (new), docs/CLOUD-SESSIONS.md, scripts/affected-tests.sh, scripts/affected-tests.test.sh. No GitHub Actions workflow files are touched, so no permissions:, trigger, or action-pin surface exists in this PR.

Findings: none.

This is internal dev-tooling logic (CI test-suite selection and a session-start plugin health check), not input-handling code at a trust boundary:

  • All shell interpolations of variable data ("$id", "$recorded", "$name", jq's --arg id "$id") are quoted and passed as discrete arguments — no eval, no unquoted expansion, no string-built commands.
  • git diff --quiet "$recorded" HEAD -- "plugins/$name" and git cat-file -e "${recorded}^{commit}" take $recorded from the plugin registry (installed_plugins.json), which is written by the claude CLI itself, not by external/untrusted input; even a hostile value there is bounded to a git diff/cat-file revision argument, not command execution. -- "plugins/$name" is prefixed, so it can't be parsed as a flag.
  • scripts/affected-tests.sh only changes which local test suites a dev run selects. Per AGENTS.md, CI runs the full suite regardless, so the false-coverage bug this PR fixes was never a CI gating/bypass issue — it's a local-dev-experience defect, correctly framed as a correctness fix rather than a security one.
  • The new test file (cloud-bootstrap-plugins.test.sh) runs entirely against a stub claude CLI and throwaway git fixtures under mktemp -d; no real registry or network calls.
  • No secrets, tokens, auth, or permission-boundary code is touched.

No security issues to report for this PR.
· branch claude/repo-improvement-discovery-y2wg3r

@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown

Last security-reviewed head: 1167eaeb02eb3b38a878e6c0b3abfc6abaf31ba0. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cedd4cb241

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/affected-tests.sh
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-29T03:39:31.596053Z cedd4cb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

The boundary rule put `-` inside the token class, so the shell default-value
operator glues onto the name it precedes: `"${TARGET:-<name>.sh}"` tokenizes to
`-<name>.sh`, and the reverse lookup never reaches the dependent that spells it
that way.

This one does not fail loud. When the referenced file has a co-located suite of
its own it stays MAPPED and the run exits 0, while the dependent's suite is
silently dropped, which is the same silent under-selection this change set
exists to remove. Found by a review bot on the pull request and reproduced
before fixing.

The existing leading-dot strip widens to `[-+=?.]`, covering the whole
`${V:-x}` / `${V:+x}` / `${V:=x}` / `${V:?x}` family. Only `-` is load-bearing:
the other three already fall outside the token class, so awk's split separates
them today. They are stripped anyway so the two sets cannot drift apart if the
class is ever widened. The strip runs after the exact and trailing-dot tests,
so it only ever adds matches, and every pair it admits is one the pre-token
substring rule already served. Measured on the corpus, it re-admits exactly two
pairs and changes no live selection.

The trailing side is unchanged and cannot be fixed the same way: in
`<name>.sh-shaped` the whole token carries the suffix, so no leading strip
reaches it. A file mentioned only that way still reports UNMAPPED at exit 1,
which is the loud direction. The header now states that asymmetry as forced
rather than chosen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGLX1xYgy27JiRqLjoiH8T
@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 53s —— View job


Code review — PR #3487

  • Gather context (PR body, diff, changed files, prior review comments)
  • Invoke /review:code-review and follow its instructions
  • Review new commit 1167eae (Codex fix) for correctness
  • Post findings

Scope of this pass: the lane's prior review already covered cedd4cc (the affected-tests basename-boundary rewrite) and 516e4b3 (the bootstrap health rewrite) in full. This push adds one new commit, 1167eae, which fixes the Codex P2 finding on scripts/affected-tests.sh:525 (shell default-value operators like ${TARGET:-name.sh} weren't treated as token boundaries). This review focuses on that delta.

Verdict: the fix is correct. Traced the token_hits awk pipeline by hand against the new fixture:

  • scripts/affected-tests.sh#L534-L541: for the line TARGET="${TARGET:-defaulted-target.sh}", awk's field split (/[^A-Za-z0-9_.-]+/) does not break on - (it's inside the kept class), so the raw token is -defaulted-target.sh — the exact failure mode described. The widened strip sub(/^[-+=?.]+/, "", t) now removes the leading - and the token matches want["defaulted-target.sh"], pulling in the dependent's suite.
  • The added chars +, =, ? in the strip class are genuinely inert today (they're already split-delimiters, so they can never appear inside a token to begin with) — the comment at L131-L136 says exactly this and frames them as future-proofing against the token class widening, not a currently-live path. Consistent with the code.
  • The strip order (trailing-dot test first, then leading-operator strip on the already trailing-stripped token) composes correctly for combined cases (e.g. an ellipsis-prefixed default) without introducing new false matches, since it only ever adds matches the substring fallback already served (per the PR's "re-admits exactly two pairs" measurement).
  • Header prose (MATCHING section, scripts/affected-tests.sh#L127-L177) was updated in lockstep with the code — the trailing-side asymmetry claim is now accurate now that the leading side is fixed.
  • New regression test (scripts/affected-tests.test.sh#L896-L969): fixture and assertion order are correct — files are written before the git add/commit, and the assertion checks both the target's own suite and the dependent's suite come back, which is the silent-drop failure mode this exists to catch.

Not independently executed: this lane's Bash access did not permit running scripts/affected-tests.test.sh (script execution beyond a fixed allowlist of read-only git/gh commands requires interactive approval not available here), so the "56 assertions green" claim remains author-claimed and unverified by me — my confidence is from the static trace above, not from running the suite.

No findings to report — no inline comments filed.
· branch claude/repo-improvement-discovery-y2wg3r

@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 46s —— View job


Security review — /review:security-review

Skip gate: PR is open. This head already has a successful security review that still applies (skip-gate condition 3).

The earlier security review on this PR covered the full diff through commit cedd4cb and found no issues. The only commit since then, 1167eae, touches only scripts/affected-tests.sh and scripts/affected-tests.test.sh, widening the awk token-boundary strip in token_hits() from sub(/^\.+/, "", t) to sub(/^[-+=?.]+/, "", t) — see scripts/affected-tests.sh#L537 — plus the accompanying doc-comment and test additions.

This is a local, self-contained fix responding to the Codex review's P2 finding about shell default-value operators (${VAR:-name.sh}) not being treated as token boundaries. It:

  • Introduces no new inputs, execution paths, or trust boundaries — it's a character class change inside an awk pattern operating on git grep output already covered by the prior review.
  • Doesn't touch .claude/cloud-bootstrap.sh or any GitHub Actions workflow.
  • Only changes which local dev test suites get selected (per AGENTS.md, CI always runs the full suite regardless), so there's no gating/bypass implication.

No security issues to report for this PR.
· branch claude/repo-improvement-discovery-y2wg3r

@kyle-sexton
kyle-sexton merged commit f8ab565 into main Aug 29, 2026
60 checks passed
@kyle-sexton
kyle-sexton deleted the claude/repo-improvement-discovery-y2wg3r branch August 29, 2026 03:57
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.

2 participants