The defect
governance-reusable.yml builds the Hypatia scanner from a pinned commit and
then scans the caller's HEAD. Those are different commits, and the pin is
now old enough that the scanner enforcing the gate predates hypatia's own fix
for a false-positive class the gate fires on.
Measured in both directions against hypatia main @ 8e8943f:
git merge-base --is-ancestor bc8812e 8e8943f -> IS an ancestor of main
git merge-base --is-ancestor bc8812e 0e913426 -> is NOT an ancestor of the pin
Corroborated by counting context_safe_line?|@form_ambiguous|label in
lib/hypatia/scanner_suppression.ex: pinned = 4 occurrences, HEAD = 12.
Why this matters beyond one repo
The consequence is not just "the scanner is a bit old". It is a structural
asymmetry in which cures are available to a caller:
Because the scanner binary is built from the pin while the scanned tree is
HEAD, compiled-in suppression cannot cure a gate failure from a consumer
PR. @default_exemptions and @training_corpus_paths live in the scanner
source at the pin, so a consumer merging a fix to them changes nothing about
the gate enforcing their own repo.
Only scanned-tree mechanisms can cure a finding:
.hypatia-baseline.json
.hypatia-ignore
- inline
# hypatia: allow directives
That is a real and non-obvious constraint on every caller, and it pushes
consumers toward baseline entries (file-wide, permanent) when the correct cure
would have been a scanner fix they have already merged.
Evidence from a live consumer
hyperpolymath/hypatia#855 / PR hyperpolymath/hypatia#856. The
Validate Hypatia Baseline gate was red on hypatia main with:
##[error]Gate failed: 5 unfiltered finding(s) at or above 'info'
Three of the five were security_errors/secret_detected on a prose comment
documenting the three @secret_patterns that match on form alone — the comment
is matched by the patterns it documents. bc8812e is precisely the fix for
that shape, is on hypatia main, and is invisible to the gate.
Cured in the consumer with a line-scoped inline directive, because that was the
only mechanism available. The root cause is here.
Blast radius — why this is filed rather than fixed
HYPATIA_PIN bumps affect ~120 caller repos where
Validate Hypatia Baseline is a required status check. A bump can only
make the scanner stricter or differently-behaved, and a newly-strict scanner
reddens callers that are green today, in a required context, without warning.
This is exactly the "gate whose predicate is time-dependent" shape: a bump reds
every correct caller at once. It needs a rollout, not a commit.
Suggested acceptance criteria
- Decide and document the pin-bump policy in the reusable workflow itself
— who bumps it, on what cadence, and what evidence is required. A pin with
no stated policy drifts until it contradicts the repo it is scanning, which
is the present state.
- Before bumping: run the candidate scanner against a sample of callers
and publish the delta (findings added/removed per repo). A bump with no
measured delta is an untested change to ~120 required checks.
- Bump past
bc8812e so the scanner contains the label-aware suppression the
scanned trees already assume.
- State plainly in the workflow, next to the pin, that compiled-in
suppression cannot cure a consumer's gate failure and list the three
scanned-tree mechanisms that can. This is the fact that most misleads
consumers, and it is currently written down nowhere.
- Callers that added a baseline entry or inline directive only to work
around the pin lag should be able to find that out — consider emitting the
scanner commit in the job summary so a consumer can tell which scanner
produced a finding.
Note on scope
Checked against the 80 open issues on this repo: nothing covers this. #964 is a
different stale pin (the dupkey helper, 317101e0).
🤖 Generated with Claude Code
https://claude.ai/code/session_0113HQM9LVGkNCzU1WwkJZSV
The defect
governance-reusable.ymlbuilds the Hypatia scanner from a pinned commit andthen scans the caller's HEAD. Those are different commits, and the pin is
now old enough that the scanner enforcing the gate predates hypatia's own fix
for a false-positive class the gate fires on.
0e913426(2026-09-06)bc8812e— label-aware secretsuppression, fix(rules): job-level permissions/concurrency blind spot + label-aware secret suppression hypatia#782, 2026-09-14
Measured in both directions against hypatia
main@8e8943f:Corroborated by counting
context_safe_line?|@form_ambiguous|labelinlib/hypatia/scanner_suppression.ex: pinned = 4 occurrences, HEAD = 12.Why this matters beyond one repo
The consequence is not just "the scanner is a bit old". It is a structural
asymmetry in which cures are available to a caller:
Because the scanner binary is built from the pin while the scanned tree is
HEAD, compiled-in suppression cannot cure a gate failure from a consumer
PR.
@default_exemptionsand@training_corpus_pathslive in the scannersource at the pin, so a consumer merging a fix to them changes nothing about
the gate enforcing their own repo.
Only scanned-tree mechanisms can cure a finding:
.hypatia-baseline.json.hypatia-ignore# hypatia: allowdirectivesThat is a real and non-obvious constraint on every caller, and it pushes
consumers toward baseline entries (file-wide, permanent) when the correct cure
would have been a scanner fix they have already merged.
Evidence from a live consumer
hyperpolymath/hypatia#855 / PR hyperpolymath/hypatia#856. The
Validate Hypatia Baselinegate was red on hypatiamainwith:Three of the five were
security_errors/secret_detectedon a prose commentdocumenting the three
@secret_patternsthat match on form alone — the commentis matched by the patterns it documents.
bc8812eis precisely the fix forthat shape, is on hypatia
main, and is invisible to the gate.Cured in the consumer with a line-scoped inline directive, because that was the
only mechanism available. The root cause is here.
Blast radius — why this is filed rather than fixed
HYPATIA_PINbumps affect ~120 caller repos whereValidate Hypatia Baselineis a required status check. A bump can onlymake the scanner stricter or differently-behaved, and a newly-strict scanner
reddens callers that are green today, in a required context, without warning.
This is exactly the "gate whose predicate is time-dependent" shape: a bump reds
every correct caller at once. It needs a rollout, not a commit.
Suggested acceptance criteria
— who bumps it, on what cadence, and what evidence is required. A pin with
no stated policy drifts until it contradicts the repo it is scanning, which
is the present state.
and publish the delta (findings added/removed per repo). A bump with no
measured delta is an untested change to ~120 required checks.
bc8812eso the scanner contains the label-aware suppression thescanned trees already assume.
suppression cannot cure a consumer's gate failure and list the three
scanned-tree mechanisms that can. This is the fact that most misleads
consumers, and it is currently written down nowhere.
around the pin lag should be able to find that out — consider emitting the
scanner commit in the job summary so a consumer can tell which scanner
produced a finding.
Note on scope
Checked against the 80 open issues on this repo: nothing covers this. #964 is a
different stale pin (the dupkey helper,
317101e0).🤖 Generated with Claude Code
https://claude.ai/code/session_0113HQM9LVGkNCzU1WwkJZSV