Skip to content

fix(hypatia-reusable): really run panic-attack, and never record a skip as a pass - #1256

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/hopeful-cray-40atxw
Oct 14, 2026
Merged

hyperpolymath merged 2 commits into
mainfrom
claude/hopeful-cray-40atxw

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Problem

The "Run panic-attack assail" step in .github/workflows/hypatia-scan-reusable.yml did nothing. Nothing in the job installed panic-attack. On main's Hypatia run at 7d2041a (run 38484072239, job 115593368840) the log says panic-attack not available in CI — skipping. The step then wrote a bare [] to panic-attack-findings.json, and that reads exactly like a clean scan. The CRG Immaculate-Guide evidence bullet (COMPONENT-READINESS-GRADES.adoc, the "panic-attack assail passes (no Critical/High findings)" line) treats that file as a pass.

The "installed" branch was broken too:

  • panic-attack assail . without --output prints a human-readable banner, not JSON.
  • 2>&1 mixed stderr into the file.
  • || true swallowed any failure.

Change (owner ruling: both (a) and (b); stays advisory)

(a) Install from a pinned source commit. The job builds panic-attack v2.5.5 at commit 2dc1393c with cargo install --git … --rev <sha> --locked. self-test.yml already installs ijson-jcs the same way.

  • No release binary exists to checksum instead. The v2.5.5 asset returns 404, and upstream's release.yml packages README.md, ROADMAP.md and SECURITY.md, which the repo does not have.
  • The binary is cached by commit with the actions/cache pin already in use. A restored binary is used only when cargo's .crates.toml names the pinned commit.
  • A failed build removes ~/.panic-attack, so nothing half-built gets cached.
  • The build is capped at 10 minutes and the scan at 5. The job timeout rises from 30 to 45 minutes to match, so neither cap can fail the job.

(b) Make every non-result explicit. panic-attack-findings.json is now a status envelope and never a bare array:

{status: "ran" | "not_run" | "error", tool, ref, reason, exit_code, counts, report}
  • Each of these produces an explicit status, a ::warning, and a step-summary section saying the scan is not a pass: tool missing, cargo missing, build failure, crash, the 5-minute cap, or a missing or invalid report.
  • A real run embeds panic-attack's own report and counts the unsuppressed findings by severity. Findings produce an advisory warning. They never gate.
  • The scan runs before the standards checkout, so it scans the caller's tree and not .standards-checkout/scripts.

Docs. The CRG evidence bullet now says what counts in CI: status: "ran" with zero critical and zero high.

Also in this PR: a fix for main's red Repo self-tests

hyperpolymath/standards#1249 added two jobs to governance-reusable.yml: JS runtimes — environment provisions Bun first and JS runtimes — ${{ matrix.runtime }}. It did not add them to the frozen job-name list in tests/test_governance_reusable_shape.sh. As a result, Repo self-tests fails on main and on every PR based on it, including hyperpolymath/standards#1255, with "job names drifted from the frozen list".

gates.json context_freeze allows adding a job, so commit b1d9cb3 adds both names to the list, and they are frozen from now on. Both are blocking jobs, so neither belongs in never_required_contexts. The test now passes 14 of 14.

Consumers

Nothing in this repo, gitbot-fleet or hypatia reads panic-attack-findings.json or the hypatia-scan-findings artifact. panicbot runs panic-attack itself. No consumer needs changes for the new shape.

Verification

  • scripts/tests/hypatia-blocking-gate-test.sh now extracts and runs both new steps against fixtures, through Ruby and through the awk fallback (mawk and gawk), with 46 PASS on each. The new cases are:
    • the skip path (not_run, never [])
    • clean, findings (suppressed findings excluded), crash, the 5-minute cap, no report, and a bad severity
    • install with no cargo, a stale cache from another commit, a valid cache, a failed build, an empty build, and a pinned build
    • the cargo arguments include --rev <sha> and --locked
  • With the old step body swapped back in, the new skip-path case fails and prints the bare [].
  • End-to-end with the real pinned binary on this repo: status: ran, 10 critical, 1 high and 23 medium (unsuppressed), step exit 0.
  • The exact cargo install command builds v2.5.5 in about 3 minutes, and .crates.toml records ?rev=<sha>#<sha>, which is what the cache check relies on.
  • scripts/check-lock-sync.sh passes. No new uses: was added.
  • scripts/check-workflow-duplicate-keys.sh and scripts/check-inline-python.sh pass.
  • The local full-suite run showed the same failure set with and without this PR. All of those failures but test_governance_reusable_shape.sh come from this container lacking ijson-jcs, bun, deno and mikefarah's yq. CI, which has those tools, failed only on test_governance_reusable_shape.sh, which the commit above fixes.

Note

Once merged, every estate caller's Hypatia run will show the real panic-attack counts as an advisory warning. This repo alone has 10 critical and 1 high.

🤖 Generated with Claude Code

https://claude.ai/code/session_01N6my4F3ohjwFReLW8cYYqC

…ip as a pass

The "Run panic-attack assail" step was a silent no-op. Nothing installed
panic-attack, so every run took the else branch and wrote a bare `[]` to
panic-attack-findings.json, which reads exactly like a clean scan (the CRG
"panic-attack assail passes" evidence). The installed branch was broken too.
`assail .` without --output prints a human banner, not JSON. And `2>&1 || true`
mixed stderr into the file and swallowed any failure.

Owner ruling: do both. Install it, and make every non-result explicit.
It stays advisory, because this reusable is called estate-wide.

* Install panic-attack v2.5.5 from source at a pinned commit:
  `cargo install --git … --rev <sha> --locked`, the same pattern self-test.yml
  uses for ijson-jcs. There is no release binary to checksum instead. The
  binary is cached by commit, and a restored binary is used only when cargo's
  .crates.toml names the pinned commit. The build is capped at 10 minutes and
  the scan at 5, and the job timeout rises by those 15 minutes, so neither
  can fail the job.
* panic-attack-findings.json becomes a status envelope:
  {status: ran|not_run|error, tool, ref, reason, exit_code, counts, report}.
  A skip, a failed build, a crash, a timeout or a missing or invalid report
  each gives an explicit status, a ::warning and a step-summary line saying
  it is not a pass. A real run embeds panic-attack's own report and counts
  the unsuppressed findings by severity.
* The scan runs before the standards checkout, so it scans the caller's tree
  and not .standards-checkout/scripts.
* hypatia-blocking-gate-test.sh now executes both new steps (Ruby and awk
  extraction) against fixtures: the skip path, clean, findings, crash, the
  5-minute cap, no report, a bad severity, no cargo, a stale cache, a valid
  cache, a failed build, an empty build and a pinned build.
* The CRG Immaculate-Guide evidence bullet says what counts: status "ran"
  with zero critical and high.

No action is added, so actions.lock is unchanged (check-lock-sync.sh passes).
Nothing in standards, gitbot-fleet or hypatia reads panic-attack-findings.json,
so no consumer needs the new shape handled.

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

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2348f646-3c0c-4a47-abf8-cb91d32545ec
📥 Commits

Reviewing files that changed from the base of the PR and between 934b879 and b1d9cb3.

📒 Files selected for processing: 4
  • .github/workflows/hypatia-scan-reusable.yml
  • component-readiness-grades/COMPONENT-READINESS-GRADES.adoc
  • scripts/tests/hypatia-blocking-gate-test.sh
  • tests/test_governance_reusable_shape.sh
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38556818501

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

#1249 added two jobs to governance-reusable.yml, "JS runtimes — environment
provisions Bun first" and "JS runtimes — ${{ matrix.runtime }}". It did not add
them to the frozen context list in tests/test_governance_reusable_shape.sh.
That turned Repo self-tests red on main and on every PR based on it ("job names
drifted from the frozen list").

Adding a job is allowed (gates.json context_freeze: "Adding a job is allowed").
This adds both names, so they are frozen from now on like the rest. Both are
blocking jobs, not advisory, so neither belongs in never_required_contexts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N6my4F3ohjwFReLW8cYYqC
@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38557102702

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review October 14, 2026 11:31
hyperpolymath pushed a commit that referenced this pull request Oct 14, 2026
…1255/#1256)

Self Test has been red on main since #1249 added the js-runtimes jobs to
governance-reusable.yml without adding their names to the frozen context
list. This is the identical change carried by #1255 and #1256, ported so
this PR's Self Test can go green; it no-ops once either lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LiQzWJdcPfRU6YMDGRG8Xi
@hyperpolymath
hyperpolymath merged commit 25824f3 into main Oct 14, 2026
70 checks passed
@hyperpolymath
hyperpolymath deleted the claude/hopeful-cray-40atxw branch October 14, 2026 11:34
hyperpolymath added a commit that referenced this pull request Oct 14, 2026
…n bumpers (#1254)

## Why

`scripts/apply-workflow-pins-remote.sh`, the scheduled pin applier,
fetches and commits only `*.yml`. The local `propagate-workflow-pins.sh`
has the same gap. Both re-point `uses: hyperpolymath/standards/...@SHA`
and leave `actions.lock` keyed to the old commit. `check-lock-sync.sh`
rejects that state, and its own header records GitHub refusing such runs
at startup.

The ledger census in `apply-workflow-pins.yml` counts 200 of 368
governance callers with an `actions.lock`. A fix-mode run would
therefore have opened PRs that stop those repos' reusable-calling
workflows.

This came up while fixing a stale `da2c748` pin, whose unpinned
`gh-actions-lock` fails Actions lockfile verify. That fix landed in
[resource-algebra#6](hyperpolymath/resource-algebra#6)
and
[rsr-template-repo#237](hyperpolymath/rsr-template-repo#237),
and both needed this relock done by hand.

## What

- **`scripts/relock-standards-pin.sh`** (new) moves a consumer's lock to
the target standards commit:
  - re-keys the per-workflow entries;
- rebuilds the standards dependency record from what the reusables
called with a full pin use at the target;
  - copies the records those need verbatim from standards' own lock;
  - prunes only records the old standards record alone kept alive;
  - keeps `gh-actions-lock`'s record order.
- **Short pins.** A short pin of 7 or more hex that prefixes the target
is current. This matches the applier, which counts it FRESH and leaves
it as written. It keeps its own short-keyed record, untouched.
- **It is fail-closed.** It leaves the lock untouched and exits 1 when:
  - a workflow pins another standards commit, or a pin under 7 hex;
  - a reusable is absent at the target;
  - the old record is missing;
  - a needed record is in neither lock;
- a workflow's standards entries would not name exactly the refs it
pins.
- **The applier** fetches `actions.lock` with the workflows and relocks
it in the same verified commit. A repo whose lock can't follow is
reported `LOCK-REFUSED` and not landed. In fix mode it fetches the
target commit if the CI checkout lacks it, and a new known-answer
control fails the run if the relock is missing.
- **The propagator** relocks before staging and reports `RELOCKED` /
`LOCK-REFUSED`. On a refusal it restores the workflows it rewrote,
uncommitted edits included, stages nothing, and leaves the branch alone.
Any refusal makes it exit 1.
- **Ported:** the frozen job-name fix that #1255 and #1256 also carry.
Self Test is red on main without it.

## Evidence

- **Known answers.** On resource-algebra and rsr-template-repo,
re-pinned from `da2c748` to `ae36881`, the relock reproduces byte for
byte the locks verified by hand there. Both pass `check-lock-sync.sh`.
resource-algebra's lock relocked to `934b879` passes the governance
gate's own `update-actions-lock.sh --verify-local` with gh-actions-lock
v0.2.0.
- **`scripts/tests/relock-standards-pin-test.sh`**, offline, 16 checks:
  - the known answer, and idempotence;
  - eight refusals that leave the lock byte-identical;
  - the no-lock no-op;
  - short pins at 7, 12 and 39 hex, each passing `check-lock-sync.sh`.
- **`scripts/tests/propagate-workflow-pins-test.sh`**: 29 of 29.
- **Mutants**, all killed:
- from the first round: no iteration, no pruning, no record copying, no
stale-pin refusal, over-pruning, no sorting;
- from the review round: exact-match only, every pin feeding the record,
no 7-hex minimum, no consistency guard, no restore, no early return.
- **Existing suites.** `check-lock-sync-test.sh` 13 of 13, and the
applier's `--self-test`.

The review round built on CodeRabbit's autofix commits (`cccec83`,
`5fd1373`) and kept their tests.

Not exercised: a live fix-mode applier run. It needs the dedicated App
credential, and it is the owner's dispatch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01LiQzWJdcPfRU6YMDGRG8Xi

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.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.

2 participants