fix(guards): close fail-open and latent-test defects found by a repo-wide sweep - #530
Conversation
Wave 1 of a repo-wide behavior-preserving simplification sweep.
render-compose.cjs: remove the unused readNormalized() helper and its entry
in the frozen module.exports. It had no callers, and it is contra-indicated
by filesForTarget() in render.cjs, which deliberately reads workflows as raw
bytes so --check stays byte-identical.
render.cjs: drop the provably-dead first clause of the parseArgs positional
filter. "--check" starts with "-", so !arg.startsWith("-") already subsumed
arg !== "--check".
shellcheck/run.sh: replace the ${arr[@]+"${arr[@]}"} empty-array guard with
the plain quoted form at 5 sites. The file already requires bash 4.4+ via
mapfile -d '' and local -n, where empty arrays are safe under set -u, and it
was the only file in the repo still using that idiom.
Verified: node --test 740 pass / 0 fail (unchanged baseline);
render.cjs --check exit 0; shellcheck/run.test.sh 24 PASS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G5). approval-agent-guardrails.cjs: collapse parseProtectedPaths' nested null/empty guards and manual dedupe loop into a split/trim/filter chain plus a Set. `raw ?? ""` triggers on exactly the same values as the previous `raw != null` check, 0 and false are still stringified rather than dropped, and Set iteration is insertion-ordered so the defaults keep their leading positions and a caller path repeating a default is dropped rather than moved. security-review-absent-mitigate.cjs: hoist the twice-evaluated `fromRulesets || requiredContexts.length === 0` condition into a single needsRulesets binding. Nothing mutates either operand between the two original evaluation sites, so the collapse is equivalent. Verified: node --test 740 pass / 0 fail (unchanged baseline); render.cjs --check exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G3).
formatNoOnlineRunnerMessage branched on labelList.length === 1 to emit
` for \`${labelList[0]}\`` and on length > 1 to emit the joined form. The
two are byte-identical for a single element, because [x].join(sep) returns
x unchanged, so the first branch could never produce different text. The
three-way let/if/else-if collapses to one const ternary.
labelList is already filtered through exactNonEmptyString, so every element
is a string and join is total.
select-runner.yml is regenerated renderer output, not a hand edit: the hunk
is the source hunk plus the 12-space splice indent. Produced by
node .github/scripts/render.cjs.
Verified: render.cjs --check exit 0; node --test 740 pass / 0 fail
(unchanged baseline); osv-scan-guard, find-tracking-issue and
govulncheck-sarif-guard shell suites all exit 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G10). Prose typo in the action's description scalar: "actions/ github-script" -> "actions/github-script". Metadata only; a composite action's description has no runtime effect. Verified: every parsed field other than .description is byte-identical before and after (yq -S 'del(.description)' diff is empty); node --test 740 pass / 0 fail (unchanged baseline). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G4).
splitFlowEntries guarded the final push with
`tail.trim() !== "" || entries.length > 0`, but the very next line filters
every blank-trimming entry out of the result unconditionally. A blank tail is
therefore gone by the time the function returns in both branches, so the
condition could never change the returned array. Pushing the slice directly
removes a condition a reader would otherwise have to prove dead before
trusting the parser.
Equivalence was measured, not assumed: a differential harness parsed all 134
YAML files in the repo plus 15 hand-written flow-collection edge cases
([], [ ], [1,], [,], [ , , ], [,1], [1,,2], {}, {x: 1,}, nested and
quoted-comma forms) and hashed each result before and after. Byte-identical,
with zero files throwing in either run.
Verified: node --test 740 pass / 0 fail (unchanged baseline);
render.cjs --check exit 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G12). laneSource rebuilt the workflows directory by hand while the file already holds workflowsDir, the same const the auto-discovery readdirSync scans. Reusing it closes the drift risk where a lane is discovered in one directory and read from another, and records why in a comment. No assertion, test case, or discovery filter was touched. Assertion count 8 -> 8, case count 4 -> 4, suite total 740 -> 740 with assertion kinds unchanged. Verified: node --test 740 pass / 0 fail (unchanged baseline). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G13).
select-runner.test.cjs: two runGitHubScript tests each spelled out the same
16-key env object, differing only in POLICY and SELF_HOSTED_LABEL. Hoisted it
into a scriptEnv(overrides) factory beside the existing input()/runner()/
response() factories, with a comment recording why every key stays present:
the adapter reads the environment as a complete contract, so a missing key is
a different scenario rather than a shorter fixture.
The third env literal (the generated-bundle test) is deliberately left inline
— it omits ADMITS_ANCILLARY_EVENTS on purpose, and routing it through the
factory would silently add that key and change what the test covers.
render-compose.test.cjs: hoist a twice-inlined require("node:os") to the
top-level requires, matching every other file in the group.
No test case, assertion, or regex was removed, weakened, or narrowed.
Assertion counts 186 -> 186 and 22 -> 22; case counts 56 -> 56 and 13 -> 13;
assertion kinds unchanged; suite total 740 -> 740.
Verified: node --test 740 pass / 0 fail; render.cjs --check exit 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Part of a repo-wide behavior-preserving simplification sweep (group G14). standards-sync-stuck-automerge-alert: replace 17 open-coded new Date(Date.now() - n * 60 * 60 * 1000).toISOString() expressions with the file's own existing HOURS_AGO(n) helper (60 * 60 * 1000 === 3_600_000, so each substitution is exact), and give issue() a title default of ISSUE_TITLE rather than re-typing the literal the lookup tests assert against. standards-sync-automerge-arm: hoist workflowLines (the workflow was split five times) and armingStepIndex (the same findIndex ran three times), and extract mutationCalls() for a filter repeated verbatim in four assertions. standards-sync-app-attestation: add repositoryEntry(fullName, id) for a shape written out seven times. The melodic-software owner stays hardcoded in the helper rather than derived, so the foreign-owner case's fixtures keep exactly the owner they had; the deliberately foreign entry stays inline with a comment. release-tag-drift.test.sh: collapse three copy-pasted usage-error blocks into check_usage(). The `|| rc=$?` capture form is kept verbatim rather than moved into an if-condition, which would suppress set -e inside the subject. pulumi-deploy-guard/guard.test.sh: add jq_edit() for a write-then-move idiom repeated six times, keeping write-then-move (a same-file redirect truncates) and adding a missing `--` to mv. No test case, assertion, or regex was removed, weakened, or narrowed. Assertion counts 61/30/162 unchanged with assertion kinds identical; suite total 740 -> 740; and the two shell suites produce byte-identical runtime case sets against HEAD (13 and 22 cases, same names). File modes unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Found by the repo-wide simplification sweep. These are deliberate behavior changes, not simplifications: each one currently fails in the permissive direction, and three are silent. managed-files-guard/run.sh — `mapfile -t changed < <(git diff …)` discarded git's exit status, because process substitution is not reaped and mapfile returns 0 regardless. An unfetched or bogus BASE_REF/HEAD_REF therefore produced an empty change list, and the guard announced "No managed-file hand-edits in this diff" and exited 0 — passing precisely when it could not see the diff. Now captured via `if ! changed_paths="$(git diff …)"`, the same shape the dest-paths call above already uses. Measured against a stub manifest engine: bad ref old rc=0 "no hand-edits" -> new rc=1 "failed to diff"; managed file edited old rc=1 -> new rc=1 (hit still reported); nothing managed edited old rc=0 -> new rc=0. eol-renormalize/action.yml — `read -ra` stops at the first newline, so a multi-line `paths` input renormalized only its first line, checking fewer files than the caller asked for. Now `read -r -d '' -a … || true`, matching the actionlint, biome and editorconfig actions. Measured: multi-line input old count=1 -> new count=2. claude-lane-incident.cjs — the unattributed-observation dedup key used `observations.indexOf(observation)`, which returns the FIRST matching index, so two entries sharing an object reference collapsed to one key and the incident body under-reported blast radius. Now keyed on the true index from `.entries()`, which also drops the O(n^2) scan. Measured: two repeated references tallied 1 distinct, now 2. probe-billing-usage.cjs — `main().then((code) => process.exit(code))` abandoned pending stdout writes, and this script's entire output is a JSON report. Piped stdout is asynchronous, so a report larger than the pipe buffer was truncated mid-write. Now assigns process.exitCode and lets the process drain. Measured on a 400,011-byte report: process.exit() delivered 131,072 bytes (the pipe buffer); process.exitCode delivers all 400,011. Verified: node --test 740 pass / 0 fail (unchanged); render.cjs --check exit 0; run.sh passes bash -n. shellcheck/shfmt/actionlint are not installed in this environment, so no lint claim is made for the two shell changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 3m 21s —— View job Review summaryReviewed all 21 changed files: the four defect fixes against the specific failure modes described in the PR body, and the remaining simplification/test-refactor diffs for behavior preservation. The four defect fixes are correct.
Simplification diffs preserve behavior. Spot-checked the riskiest ones directly rather than trusting the PR's own claims:
Finding (left as 2 inline comments): the four defect fixes ship with no regression tests. No correctness issues found in the fixes or the simplification diffs themselves. |
|
Claude finished @kyle-sexton's task in 3m 4s —— View job Security review — PR #530
Note: the SummaryNo new vulnerabilities introduced by this diff. I read all 21 changed files ( The four fixes — verified
Everything else in the diffThe remaining 17 files are dead-code removal, redundant-guard removal, and test-fixture hoisting — all mechanical and behavior-preserving on inspection:
No command-injection, credential-handling, or privilege-escalation issues found. Subprocess calls I checked ( |
|
Last security-reviewed head: |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
…lCheck CI caught SC2016 on the one jq_edit call site whose filter carries a jq variable. ShellCheck special-cases jq and recognises `$urn` as jq syntax only when the filter is a direct argument to jq; routed through a shell helper it loses that and reports "Expressions don't expand in single quotes". Inlined that single call rather than adding `# shellcheck disable=SC2016`, so the check stays meaningful instead of suppressed. The other five jq_edit call sites carry no `$` and keep the helper. Verified: guard.test.sh exit 0 with all 22 runtime cases intact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
|
Claude finished @kyle-sexton's task in 1m 8s —— View job Security review — PR #530
Skip gate: no new security-relevant surface since the last review. A successful security review already ran on this PR at head That change inlines one Per the skill's skip gate (§"This head already has a successful security review that still applies"), the prior review at |
Works every remaining deferred finding from the repo-wide sweep in-branch, per the instruction that nothing stay deferred. Each item is either applied here or closed with a concrete reason; none is left undecided and none is filed. Applied — latent bugs: - gitleaks/scan.test.sh: the symlink-contract `*)` arm used `return` inside a top-level `for` loop, so it could never fail the test. Proof against scratch copies with the arm forced: HEAD exits 2 with "return: can only `return' from a function", the fix exits 1 with the intended message. - osv-scanner-pin.test.cjs: an assertion was conditioned on the same value it then checked, so it passed if EITHER wording was present and could not detect the guard's mismatch message being reworded. Now unconditional. Proof: with the message reworded consistently in both the workflow and osv-scan-guard.sh, the old assertion gives pass 5 / fail 0 and the corrected one pass 4 / fail 1. - Invoke-CompositeRunPssa.test.ps1: the non-repo-relative-path loop printed `$custom.Output` on failure where `$outside.Output` is what that case produced, so a failure would dump the previous case's output. Applied — dead code and duplication: - check-run-reconcile.cjs: removed a redundant empty-candidates guard; folded an escape predicate into one literal (differential over 0x00-0x7F plus 390 patterns: emitted regex source byte-identical); hoisted a per-call verdict list to a module-level Set; rebuilt a Map in one construction (key ORDER and value identity checked over 2000 randomized maps). - claude-lane-incident.cjs / classify.cjs: `[...x].sort()` -> `toSorted()`, `x[x.length-1]` -> `x.at(-1)`, both with differentials including the empty and sparse cases. - probe-billing-usage.cjs: extracted the duplicated unknown-payload write; added the missing `result.error` branch to ghApi so a missing binary names ENOENT instead of "failed (exit null)". The `status !== 0` test is untouched. - comment-hygiene/scan-tree.sh: removed a dead initializer. - change-detection/match.sh: replaced a loop whose variable was unused. - composite-run-shellcheck.sh: collapsed a dialect test evaluated twice per iteration. Verified with a shellcheck shim capturing full argv and file bytes across every tracked composite action: 499 lines of extracted script and the 72-line stdout both identical. - osv-scan-guard.sh: escape_property now composes escape_data. Re-rendered via render-osv-scan-guard.cjs, which is the only reason osv-scanner.yml moves. - standards-sync tests: removed a duplicated extractor in favour of the generic one already in the file, and hoisted a repeated pagination fixture pair. - dotnet-format and markdown actions: added `set -euo pipefail` to the three inline bash blocks that lacked it, after executing each block's control flow against a stub to confirm all four outcomes are unchanged. - .gitignore: added .lycheecache, which link-check.yml caches from that path. Closed with reason (not applied), the load-bearing ones: - The spawnSync triage longhand in security-review-absent-mitigate.cjs stays; collapsing it is how a missing binary comes to pass a guard. - claude-lane-incident-write-gate.cjs's two audits stay separate; the file's stated thesis is deliberate redundancy between independent mechanisms. - install-release.sh's two checksum calls gate different things. - A nonempty() helper in release-tag-drift.sh would add five SC2310 findings; the repo already carries disable directives for exactly that shape. - The osv-scanner-pin.json fields no code reads are a human audit record for a supply-chain pin. Also corrected: an earlier claim that comment-hygiene forbids the issue references in five files. Running the repo's own chp::scan_text over all six reports clean, with a positive control confirming it does flag TODO, closes #N, owner/repo#N, GH-N and "issue N". Bare (#200) and repo#399 are deliberately outside the ruleset, so those comments are compliant. Verified: 740 pass / 0 fail; render.cjs --check exit 0; 9 bash suites pass (2 environmental, missing binaries); 68/68 YAML valid; biome clean at CI's scope; no mode or CRLF changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
|
Claude finished @kyle-sexton's task in 1m 20s —— View job Security review — PR #530
Note: the ScopePrior reviews on this PR covered head SummaryNo new vulnerabilities introduced. The commit is the "clear the deferred inventory" pass: mostly dead-code removal,
Everything else in the delta is non-security-relevant: One item worth flagging as a genuine improvement, not a defect: No command-injection, credential-handling, privilege-escalation, or fail-open issues found in this delta. |
Both fixes in this branch corrected bugs that produced no failure signal, and both shipped without a test. Review flagged that a silent bug fixed without a test can be reintroduced silently. Each test below was checked twice: it passes against the fixed source and FAILS against the pre-fix source. claude-lane-incident.test.cjs — the dedup key for unattributable observations used observations.indexOf(observation), and indexOf returns the FIRST index of a value, so two entries carrying the same object reference produced one key and collapsed. The new case passes the same frozen observation twice and asserts classCounts, statusCounts and unrecognized each count 2. A shared reference is the reproducing shape precisely because indexOf compares by identity: two structurally identical but distinct objects already got distinct indices and never triggered the bug. Verified: pass on .entries(), fail on indexOf. probe-billing-usage.test.cjs — new file; this script previously had no test at all. Three cases: the entry point assigns process.exitCode and does not call process.exit (line comments stripped first, so the block's own explanatory comment cannot decide the result); assigning process.exitCode delivers a 400,000-byte payload through a pipe intact; and the real script emits one complete, parseable JSON report under a stub `gh` where every endpoint fails. The first of those is asserted against the source rather than by reproducing a truncated report, and that is deliberate rather than a shortcut. Measured: the report embeds only endpoint paths, HTTP statuses and fixed strings, so it stays near a kilobyte and cannot reach the pipe buffer today — a stub `gh` emitting 500 KB of stderr still yields a 1030-byte report on both the fixed and pre-fix versions. The hazard is latent, arriving the moment anything variable-length is added to the report. A test that could only fail after that future change would not guard this fix; this one fails the moment the exit form regresses. Verified: 744 pass / 0 fail (740 before, +4); render.cjs --check exit 0; biome clean at CI's scope; 9 bash suites pass (2 environmental). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee
Summary
A repo-wide simplification sweep across 132 files in 14 groups, plus fixes for seven defects the sweep uncovered — three fail-open guards, three latent test bugs that could not fail, and a counting bug. Every applied diff was checked by a separate fresh-context agent whose only job was to construct a counterexample disproving behavior preservation.
Nothing is deferred. Every finding is either applied here or closed in-branch with a stated reason; no issues were filed.
The simplification yield is deliberately small: 9 of 14 groups changed nothing. This codebase is mature, and the honest output of a simplification pass over it is a short diff and a long findings list. The defect fixes are worth more than the simplification.
Scope
288 files in the repo, 132 swept. 156 excluded, by class:
fixtures/**and.github/scripts/fixtures/**are deliberately broken inputs (bad/,no-shell/,unterminated-expression/). Their content is the assertion..github/workflows/**,.claude/**, CODEOWNERS, dependabot.docsflag on this run.melodic-software/standards; a local edit is reverted by the next sync PR.*.pinned.ymlmust stay byte-identical to a region of an excluded workflow, so editing one side alone breaks the equality test with no way to repair the other.Two of the upstream-managed exclusions are traps worth naming:
.gitleaks.tomland.editorconfig-checker.jsonhave never been modified by the sync bot, so a git-history heuristic marks them safe to edit. They are not. They were identified from the mapping tables the sync engine renders into its own commit bodies.Fix
Fail-open guards
1.
managed-files-guard/run.shpassed whengitfailed.mapfile -t changed < <(git diff …)discards git's exit status — process substitution is not reaped, somapfilereturns 0 regardless. An unfetched or bogusBASE_REF/HEAD_REFproduced an empty change list, and the guard printed "No managed-file hand-edits in this diff" and exited 0, passing precisely when it could not see the diff. Now captured withif ! changed_paths="$(git diff …)", the shape thedest-pathscall in the same file already used.rc=0"no hand-edits"rc=1"failed to diff"rc=1, hit reportedrc=1, hit reportedrc=0rc=02.
eol-renormalizechecked only the first line of a multi-line pathspec.read -rastops at the first newline. The siblingactionlint,biomeandeditorconfigactions all useread -r -d '' -a … || true; this one had diverged. Measured: multi-line input yielded 1 element, now 2.3.
probe-billing-usagetruncated its own report.main().then((code) => process.exit(code))abandons pending stdout writes, and this script's entire output is a JSON report. Measured on a 400,011-byte payload:process.exit()delivered 131,072 bytes (the pipe buffer);process.exitCodedelivers all of it.Latent test bugs — each one could not fail
4.
gitleaks/scan.test.shusedreturninside a top-levelforloop, so its*)default arm could never fail the test. Forced against scratch copies: HEAD exits 2 withreturn: can only `return' from a function; the fix exits 1 with the intended message.5.
osv-scanner-pin.test.cjshad an assertion conditioned on the same value it then checked, so it passed if either wording was present and could not detect the guard's mismatch message being reworded. Proof, with the message reworded consistently in both the workflow andosv-scan-guard.sh: the old assertion givespass 5 / fail 0, the corrected onepass 4 / fail 1.6.
Invoke-CompositeRunPssa.test.ps1printed$custom.Outputon failure in the path-guard loop, where$outside.Outputis what that case produced — a failure would dump the previous case's output.Counting bug
7.
claude-lane-incidentkeyed unattributed observations onobservations.indexOf(observation), which returns the first matching index, so two entries sharing an object reference collapsed to one key and the incident body under-reported blast radius. Now keyed on the true index from.entries(), which also removes an O(n²) scan.Regression coverage for the two silent fixes
Both #3 and #7 were bugs that produced no failure signal, and both initially shipped without a test — raised in review, and correct. Each new test was checked in both directions: it passes against the fixed source and fails against the pre-fix source.
probe-billing-usage.test.cjsis a new file; that script previously had no test at all. Its regression guard asserts against the source rather than reproducing a truncated report, and that is deliberate: measured, the report embeds only endpoint paths, statuses and fixed strings, so a stubghemitting 500 KB of stderr still yields a 1030-byte report on both the fixed and pre-fix versions. The truncation is latent, arriving the moment anything variable-length enters the report. A test that could only fail after that future change would not guard this fix.Verification
Union pass across every ecosystem the run touched, on the final branch:
node --testrender.cjs --check(gates the requiredselector-contractjob)biomeat CI's exact scopemainEach applied diff went through a dedicated refutation agent asked to produce a concrete counterexample. All returned NOT REFUTED, with the work shown:
shellcheck/run.sh— 40+ element shapes with a positive control proving the harness could detect divergence. Established the removed guard was dead code: on a bash old enough for it to matter,mapfile -daborts first and both versions die identically.select-runner— 61-row element matrix, executed against the rendered workflow copy, not just the source.workflow-yaml— ~1.5M differential cases including exhaustive enumeration of all 299,593 strings of length 0–6 over a targeted alphabet, and branch instrumentation confirming the divergent case was genuinely exercised (~48,700 hits) rather than merely unvisited.Later cleanups carried their own proofs: a differential over
0x00-0x7Fplus 390 patterns for the regex-escape fold, key-order and value-identity checks over 2000 randomized maps for the Map rebuild, and ashellcheckshim capturing full argv plus file bytes across every tracked composite action (499 lines of extracted script, identical).Honest gaps
shellcheck,shfmt,actionlint,biome,lefthookand PSScriptAnalyzer are not installed in the sweep environment. This cost a CI cycle: the first run failed SC2016 on ajq_edittest helper, because ShellCheck recognises$urnas a jq variable only when the filter is a direct argument tojq— routing it through a shell function loses that. Fixed by inlining that one call site rather than suppressing the check.action.ymlfiles are touched only by generic repo-wide sweeps that assert nothing about their inputs, outputs, or step semantics. For those, the refutation pass and the union pass are the only checks that ran.Related
No linked issue.
Correction to an earlier version of this description
An earlier revision claimed
comment-hygieneforbids issue references while five files carry them, and called it a rule/code disagreement. That was wrong. Running the repo's ownchp::scan_textover all six files reports them clean, with a positive control confirming the scanner does flagTODO,FIXME,HACK,closes #123,owner/repo#12,GH-45andissue 77. The ruleset targets closing-keyword+#N,owner/repo#N(requires the slash),GH-Nandissue N; a bare(#200)orrepo#399is deliberately outside it. The header prose is a loose gloss — the patterns are the policy, and CI has been green on those files throughout. Nothing to change.Findings closed rather than applied
Every remaining finding was worked in-branch. These were closed because applying them would be wrong, not merely unnecessary:
spawnSynctriage longhand insecurity-review-absent-mitigate.cjsstays.statusisnullfor ENOENT, signal,maxBufferand timeout, so collapsing that triage is exactly how a missing binary comes to pass a guard.claude-lane-incident-write-gate.cjs's two audits stay separate; the file's stated thesis is deliberate redundancy between two independent mechanisms that cross-check each other.install-release.sh's two checksum calls gate different things (one the cache write, one the copy).nonempty()helper inrelease-tag-drift.shwould introduce five new SC2310 findings — the repo already carries# shellcheck disable=SC2310at five sites for exactly that shape. Trading four duplicated fragments for five suppressions is a net loss.osv-scanner-pin.jsonfields no code reads are a human-readable audit record for a supply-chain pin.dotnetsetup fallback and the PowerShell NUL-reassemble idiom cannot be shared without a new action directory or a new.psm1and a changed load contract for a consumer-facing action.🤖 Generated with Claude Code
https://claude.ai/code/session_01J3DMJtbY5RhnHEVAAFsnee