Skip to content

fix(ci): move the estate's gh-actions-lock pin to v0.2.0, with a real-binary contract test - #1250

Merged
hyperpolymath merged 5 commits into
mainfrom
claude/new-session-th4e9w-lock-v020
Oct 14, 2026
Merged

hyperpolymath merged 5 commits into
mainfrom
claude/new-session-th4e9w-lock-v020

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Why

gh-actions-lock v0.1.6 refuses to read a lockfile v0.0.3:

lockfile version v0.0.3 is newer than this binary supports (v0.0.2); upgrade the tool that reads this lockfile

Every current gh actions-lock writes v0.0.3, so a lock refreshed with an upgraded extension fails every v0.1.6 reader:

  • governance's Actions lockfile verify at this tree's HEAD;
  • the scorecard reconciler;
  • the lock regen;
  • the copied workflow-linter.yml in each repo.

That is what turned proof-burrower#111/#112 red. rsr-template-repo's lock is already v0.0.3.

Owner decision (selector, 2026-10-14): move the estate to v0.2.0.

What

  1. All four gh extension install github/gh-actions-lock --pin sites move from v0.1.6 to v0.2.0: governance-reusable, scorecard-reusable ×2, and dependabot-lock-regen.
  2. scripts/update-actions-lock.sh (the one lock verifier) narrowly accepts the two new v0.2.0 finding classes. v0.1.6 never reported them, and both contradict measured behaviour:
    • not-pinned with no dependency ("workflow has no lockfile entry"). Accepted only when every uses: in the workflow is ./… or $/…, or there is none. GitHub runs these workflows without an entry: lock-sync-gate (only run: steps), and scorecard, secret-scanner and self-ci (only ./ reusable calls), all green on main.
    • local-action ("local path actions are not supported, rewrite to $/…"). Accepted only when every ./ action the workflow uses exists in the checkout. The estate measured the reverse: check-lock-sync.sh fails the $/ rewrite as invalid.
    • Still blocking: an unlisted workflow with a remote action, a not-pinned dependency, a missing ./ action, and every other category.
  3. New scripts/tests/gh-actions-lock-contract-test.sh runs the real binary, offline. It checks:
    • one pin version everywhere, and that the binary is that version;
    • v0.0.2 and v0.0.3 both verify, and the lock is left byte-identical;
    • a too-new lockfile is refused loudly;
    • the JSON shape and the categories the verifier and reconcile-scorecard-actions-lock.rb key on;
    • the verifier, end to end, accepts the three false-positive classes and rejects the four blocking cases.
  4. self-test.yml installs the pinned release (HTTPS-only redirects, SHA-256 checked) so the contract runs on every PR.

Evidence

Check Result
Contract test on v0.2.0 19/19
Negative control: v0.1.6 fails 8, every v0.0.3- or v0.2.0-specific check
Mutant: no dependency check caught
Mutant: no nothing-to-pin check caught
Mutant: no ./ existence check caught
Mutant: one pin left at v0.1.6 caught
No binary exit 2
update-actions-lock-test.sh (fake gh) 5 new cases pass
gate, regen, complete-job-refs tests pass

Verdicts of update-actions-lock.sh --verify-local:

Tree v0.1.6 v0.2.0
echidna main 0 0
echidnabot main 0 0
standards main 0 0
proof-burrower main (real #110 drift) 1 1
proof-burrower#112 (lock v0.0.3) 2 (cannot read) 0
rsr-template-repo main (lock v0.0.3) 2 (cannot read) 0

Correction to the first version of this PR. I first reported "identical verdicts on four repos" from exit codes alone. That hid the two new categories on standards, which made this PR's first self-lint red. Item 2 fixes that, and the table above now compares the categories as well as the exit codes.

Notes

  • Pre-existing, not from this PR:
    • check-lock-sync-test.sh and check-actions-lock-gate-test.sh fail in an environment whose awk is mawk, or whose yq is the Python wrapper; they pass with mikefarah yq.
    • actionlint v1.7.7 doesn't know job.workflow_sha.
  • The remaining SonarCloud annotations are style smells ([[ vs [, explicit return) matching the surrounding scripts. The security finding (unrestricted curl -L redirects) is fixed.
  • For S7 (KYAML workflows): under --verify-local, v0.1.6 and v0.2.0 gave identical findings on a KYAML fixture. YAML-POLICY.adoc's "v0.1.6 cannot see a uses: inside a KYAML workflow" needs a fix-mode measurement before it changes.

Status: TESTED (real binary, offline).

Companions:

🤖 Generated with Claude Code

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

…-binary contract test

v0.1.6 refuses to read lockfile v0.0.3 ("newer than this binary
supports"), and every current `gh actions-lock` writes v0.0.3. One lock
refreshed with an upgraded extension therefore failed every v0.1.6
reader: governance's Actions lockfile verify at this tree's HEAD, the
scorecard reconciler, the lock regen, and each repo's copied
workflow-linter (proof-burrower#111/#112).

v0.2.0 reads v0.0.2 and v0.0.3. On the main locks of echidna,
echidnabot, proof-burrower and standards, scripts/update-actions-lock.sh
--verify-local gives the same verdict under both versions.

scripts/tests/gh-actions-lock-contract-test.sh runs the real binary
(offline, --verify-local) and pins the contract the lock tooling relies
on:
- every pin in .github/workflows/ names one version;
- both lockfile versions are read;
- a too-new lockfile is refused loudly;
- the JSON shape and the four finding categories are as expected;
- update-actions-lock.sh accepts reusable-workflow coverage and rejects
  a real desync.

12/12 on v0.2.0. Negative controls: v0.1.6 fails 6 of 12, disagreeing
pins fail 2, and no binary exits 2. self-test.yml installs the pinned
release, checked against its SHA-256.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
@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 40 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: b23726a0-6ce7-42d5-91ed-d6cca897473d
📥 Commits

Reviewing files that changed from the base of the PR and between 75064de and f6b32bc.

📒 Files selected for processing: 9
  • .github/workflows/dependabot-lock-regen.yml
  • .github/workflows/governance-reusable.yml
  • .github/workflows/scorecard-reusable.yml
  • .github/workflows/self-test.yml
  • scripts/check-lock-sync.sh
  • scripts/complete-job-refs.sh
  • scripts/tests/gh-actions-lock-contract-test.sh
  • scripts/tests/update-actions-lock-test.sh
  • scripts/update-actions-lock.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/38546323549

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)

On standards' own tree, governance's Actions lockfile verify failed
under v0.2.0. v0.2.0 reports two categories v0.1.6 never did, and both
contradict what GitHub and the estate measure.

- `not-pinned` with no dependency ("workflow has no lockfile entry").
  A v0.1.6-written lock omits workflows that have nothing to pin.
  GitHub runs them without an entry: lock-sync-gate (only `run:`
  steps), and scorecard, secret-scanner and self-ci (only ./ reusable
  calls) all succeed on main. The finding is accepted only when every
  `uses:` in the workflow is ./… or $/…, or there is none.
- `local-action` with no dependency ("local path actions are not
  supported; rewrite to $/…"). The estate measured the opposite:
  check-lock-sync.sh fails the `$/` spelling as an invalid rewrite. The
  finding is accepted only when every ./ action the workflow uses
  exists in the checkout.

Any other finding still blocks: an unlisted workflow with a remote
action, a not-pinned dependency, or a missing ./ action.

Evidence:
- update-actions-lock-test.sh adds 5 cases (fake gh).
- gh-actions-lock-contract-test.sh: 19/19 on the real v0.2.0 binary.
  The rule mutants (no dependency check; no nothing-to-pin check; no
  existence check) are each caught.
- Verdicts across six trees, v0.1.6 vs v0.2.0:
  - echidna, echidnabot and standards main: identical;
  - proof-burrower main: identical (red for real drift);
  - proof-burrower#112 and rsr-template-repo, both v0.0.3 locks: v0.1.6
    exits 2 (cannot read); v0.2.0 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
hyperpolymath added a commit that referenced this pull request Oct 14, 2026
…1251)

## Why

A sweep copied a "Verify immutable action lockfile" step into repos'
`workflow-linter.yml`. The step downloads gh-actions-lock **v0.1.6** and
runs it raw, beside governance's lockfile gate. v0.1.6 cannot read
lockfile v0.0.3, so the step goes red whenever a current tool refreshes
a repo's lock. That is what failed "Workflow Security Linter /
lint-workflows" on proof-burrower#111/#112.

The step didn't come from rsr-template-repo; that template's linter
never had it. So fixing the template wouldn't reach the repos that carry
it, and the estate needs a list of them.

Owner decisions 2026-10-14 (selector):
- drop the step from copied linters;
- pilot first: proof-burrower#113, echidna#437 and echidnabot#181;
- clear the rest of the estate in the wave;
- move the estate's own pin to v0.2.0 in #1250.

## What

- `scripts/check-copied-lock-step.sh REPO_DIR [SLUG]` lists every
workflow that downloads or installs gh-actions-lock itself, with the
version it pins. Output is TSV: `repo workflow pins`.
  - Exit codes: 0 none found, 1 found, 2 usage error.
  - Report-only; it never edits.
- standards is skipped, because its installs are the estate pin, which
`gh-actions-lock-contract-test.sh` (#1250) holds to one version.
- `lockfile-drift-detect.yml` (weekly, report-only) runs the detector
over the clones it already makes. It adds a `copied-lock-step.tsv`
artifact, a step-summary section and a row in the tracking issue's
table. There's no new `uses:`, so `actions.lock` is unchanged.

## Evidence

- `scripts/tests/check-copied-lock-step-test.sh`: **8/8**. Cases:
  - raw download, with version extraction;
  - `gh extension install`, pinned and unpinned, one row per workflow;
  - a KYAML `run:` scalar;
  - comment-only mentions are not counted;
  - standards skipped;
  - no workflows;
  - usage errors.
- Mutants "comments counted" and "standards not skipped" each fail the
suite.
- Real repos: it flags `main` of proof-burrower, echidna and echidnabot
(v0.1.6), and finds nothing on their fixed branches.
- actionlint clean; duplicate-key check clean; the sweep's `run:` passes
`bash -n`.

Status: TESTED locally. It hasn't run live yet; the first scheduled or
dispatched sweep after merge produces the wave's list.

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

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---
_Generated by [Claude
Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

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

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)

SonarCloud rated #1250's new code C for security: `curl -fsSL` follows
redirects with no protocol restriction. The fix uses the estate idiom
from ci-pipeline.yml and k9-contractile.yml (--proto '=https'
--proto-redir '=https' --tlsv1.2). The download was re-fetched with
these flags and still matches the pinned SHA-256.

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

Copy link
Copy Markdown
Contributor

K9 contract conformance

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

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)

@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

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

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 added a commit to hyperpolymath/proof-burrower that referenced this pull request Oct 14, 2026
…w linter (#113)

## Summary

"Workflow Security Linter / lint-workflows" has failed on every `main`
push since 2026-10-05, and now on #111/#112. It failed for two reasons,
both caused by the copied "Verify immutable action lockfile" step:

- **Version skew.** The step pins its own gh-actions-lock **v0.1.6**,
which cannot read lockfile **v0.0.3**:

  ```
  lockfile version v0.0.3 is newer than this binary supports (v0.0.2)
  ```

Every current `gh actions-lock` writes v0.0.3, including the
regeneration in #112.
- **Duplicate verifier.** It ran a second lock check beside
governance's, with its own version pin. That pin drifts from the
estate's, and the raw tool doesn't apply the reusable-workflow coverage
rule that governance's verifier applies.

Governance's **Actions lockfile verify** (standards
`scripts/update-actions-lock.sh`) is the single tested implementation.
This PR removes the duplicate step and leaves a comment pointing at the
gate.

Owner decision 2026-10-14 (selector): drop the lock step from copied
linters, and move the estate to gh-actions-lock v0.2.0
(hyperpolymath/standards#1250). Pilot repos first: proof-burrower,
echidna, echidnabot. The rest of the estate follows in the wave.

## Changes

- `.github/workflows/workflow-linter.yml`: the pinned-binary lock step
is replaced by a comment. The SPDX, permissions and duplicate-workflow
checks are unchanged.
- No `uses:` changes, so `actions.lock` is untouched.

## RSR Quality Checklist

### Required

- [x] Tests pass: the remaining linter steps are unchanged.
- [x] Code is formatted (n/a, YAML only).
- [x] Linter is clean: actionlint v1.7.7 clean; the workflow
duplicate-key check is clean.
- [x] No banned language patterns.
- [x] No `unsafe` blocks without `// SAFETY:` comments (n/a).
- [x] No banned functions (n/a).
- [x] SPDX license headers present on all new/modified source files.
- [x] No secrets, credentials, or `.env` files included.

### As Applicable

- [ ] `.machine_readable/descriptiles/STATE.a2ml` updated (n/a; A2ML is
retired)

## Testing

- Reproduced the failure locally with the release binaries: v0.1.6
`--rescan --no-fix` on #111's lock exits 2 with the message above.
- Governance's verifier still covers this repo: governance.yml pins
standards 8f2ee508, whose `actions-lock-verify` job passed on #111/#112.
- This repo's `main` lock is stale (#110). It stays red under
governance's gate until #112 lands, which is the intended behaviour.

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

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---
_Generated by [Claude
Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
@hyperpolymath
hyperpolymath merged commit c11c255 into main Oct 14, 2026
65 checks passed
@hyperpolymath
hyperpolymath deleted the claude/new-session-th4e9w-lock-v020 branch October 14, 2026 10:16
hyperpolymath added a commit to hyperpolymath/echidna that referenced this pull request Oct 14, 2026
…w linter (#437)

## Summary

The copied "Verify immutable action lockfile" step in
`workflow-linter.yml` pins its own gh-actions-lock **v0.1.6**, which
cannot read lockfile **v0.0.3**. Every current `gh actions-lock` writes
v0.0.3, so the step fails the first time a current tool refreshes this
repo's lock. That has already happened in proof-burrower (#111/#112
there). The step was also a second verifier with a second version pin.

Governance already verifies the lock through standards
`scripts/update-actions-lock.sh`. This repo's governance pin (571cc734)
runs it inside its workflow-lint job. That is one tested implementation,
with one pin, and it accepts reusable-workflow coverage.

Owner decision 2026-10-14 (selector): drop the lock step from copied
linters, and move the estate to gh-actions-lock v0.2.0
(hyperpolymath/standards#1250). Pilot repos first: proof-burrower,
echidna, echidnabot.

## Changes

- `.github/workflows/workflow-linter.yml`: the pinned-binary lock step
is replaced by a comment pointing at the governance gate. The
issue-regression and allow-fail steps are unchanged.
- No `uses:` changes, so `actions.lock` is untouched.

## RSR Quality Checklist

### Required

- [x] Tests pass: `scripts/ci/test-issue-regressions.sh` passes.
- [x] Code is formatted (n/a, YAML only).
- [x] Linter is clean: actionlint v1.7.7 clean; the workflow
duplicate-key check is clean.
- [x] No banned language patterns.
- [x] No `unsafe` blocks without `// SAFETY:` comments (n/a).
- [x] No banned functions (n/a).
- [x] SPDX license headers present on all new/modified source files.
- [x] No secrets, credentials, or `.env` files included.

## Testing

- Standards `update-actions-lock.sh --verify-local` on this branch
passes (exit 0) under both gh-actions-lock v0.1.6 and v0.2.0.
- `lint-workflows` is green on `main` today. This removes the failure
before it happens rather than fixing a red check.

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

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---
_Generated by [Claude
Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit to hyperpolymath/echidnabot that referenced this pull request Oct 14, 2026
…w linter (#181)

## Summary

The copied "Verify immutable action lockfile" step in
`workflow-linter.yml` pins its own gh-actions-lock **v0.1.6**, which
cannot read lockfile **v0.0.3**. Every current `gh actions-lock` writes
v0.0.3, so the step fails the first time a current tool refreshes this
repo's lock. That has already happened in proof-burrower. The step was
also a second verifier with a second version pin.

Governance's **Actions lockfile verify** job (this repo pins standards
fad242d3, which has it) already runs standards
`scripts/update-actions-lock.sh`. That is one tested implementation,
with one pin, and it accepts reusable-workflow coverage.

Owner decision 2026-10-14 (selector): drop the lock step from copied
linters, and move the estate to gh-actions-lock v0.2.0
(hyperpolymath/standards#1250). Pilot repos first: proof-burrower,
echidna, echidnabot.

## Changes

- `.github/workflows/workflow-linter.yml`: the pinned-binary lock step
is replaced by a comment pointing at the governance gate. The SPDX and
permissions checks are unchanged.
- No `uses:` changes, so `actions.lock` is untouched.

## Testing

- actionlint v1.7.7 clean; the workflow duplicate-key check is clean.
- Standards `update-actions-lock.sh --verify-local` on this branch
passes (exit 0) under both gh-actions-lock v0.1.6 and v0.2.0.
- `lint-workflows` is green on `main` today. This removes the failure
before it happens rather than fixing a red check.

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

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---
_Generated by [Claude
Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath pushed a commit that referenced this pull request Oct 14, 2026
Resolves the one conflict, in .github/workflows/self-test.yml: this
branch and main (#1250) both add setup steps after the ijson-jcs
install. Both blocks are kept: the Bun, Deno and pnpm setup this branch
needs for js-runtimes-test.sh, then main's hash-checked gh-actions-lock
install for gh-actions-lock-contract-test.sh. actions.lock merged
cleanly; every uses: in the merged workflow is keyed in it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4U5XuN4NWs8FTxoe5PuH7
hyperpolymath added a commit that referenced this pull request Oct 14, 2026
…weep (#1248)

## What

`dependabot-lock-regen.yml` only repaired **open** Dependabot and
applier PRs. A stale `actions.lock` that had already reached a default
branch stayed stale. That happened with proof-burrower#110, which
dependabot-automerge merged red because "Actions lockfile verify" is not
a required check. After that, every caller workflow in the repo hits
`startup_failure` and its required checks never report.
proof-burrower#111 sat on "analyze (actions, none) — Expected" for this
reason.

This PR adds a default-branch repair mode, `REGEN_MAIN=1`:

- **When it runs.** A new daily `41 4 * * *` tick, or a dispatch with
`main-repair: true`. The half-hourly ticks behave as before.
- **What it does.** For each repo it runs the same repair chain on the
default branch:
  1. `gh actions-lock`
  2. relock-sha-keys
  3. complete-job-refs
  4. close-lock
  5. prune-stale
  6. `--verify-local`
  7. `check-lock-sync.sh`

If the lock changes, it creates `chore/regenerate-actions-lock` from the
default-branch head, commits the lock through `createCommitOnBranch`
(with `expectedHeadOid`), and opens one lock-only PR.
- **Safety.**
  - It skips a repo that already has the repair PR open.
  - It skips a repo whose default branch moved during the run.
  - It skips an unverified regeneration.
- It reuses an existing repair branch only when the branch's head commit
is its own leftover repair commit. It never force-moves a branch it did
not write.
- `select_prs` now also matches bot-authored PRs from the repair branch,
so later sweeps keep that PR's lock current.
- **No new `uses:`.** The gh-actions-lock pin is the estate pin, which
matches the governance reusable workflow. Since `main` was merged in
(58d3c80, carrying #1250), both are v0.2.0.
`scripts/tests/gh-actions-lock-contract-test.sh` holds every install to
one version.

## Owner action this depends on (decision O11, "App + regen + required")

The workflow is `disabled_manually` and the applier App doesn't exist
yet. To turn this on:

1. Create the applier App with Contents R/W, Workflows R/W and **Pull
requests R/W** (R/W is new for this mode).
2. Install it on both owners.
3. Set `vars.APP_ID` and `secrets.APP_PRIVATE_KEY` on standards.
4. Re-enable `dependabot-lock-regen.yml`.

After one green sweep, the follow-up makes "Actions lockfile verify"
required, so a red lock can no longer auto-merge.

## Evidence

- `scripts/tests/regen-dependabot-locks-test.sh`: **59/59 pass**. New
cases:
  - stale lock → PR opened;
  - current lock → no-op;
  - dry run;
  - unverified regeneration;
  - default branch moved;
  - repair PR already open;
  - `select_prs`, bot vs human author;
  - foreign branch refused;
  - own leftover reused;
  - PR creation refused;
  - `REGEN_MAIN` wiring on and off.
- Mutants: "always force-move the branch" and "ignore an open repair PR"
each fail the suite.
- `bash -n`: clean. actionlint v1.7.7: clean. Workflow duplicate-key
check: clean.

Status: TESTED (stubbed `gh`, local fixture clone). Not yet run live,
because the App is absent.

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

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---
_Generated by [Claude
Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit to hyperpolymath/resource-algebra that referenced this pull request Oct 14, 2026
…in (#7)

## Summary

**This fixes `governance / Actions lockfile verify`, red on `main`.** It
is the follow-up promised in #4.

At `da2c748`, governance's lock gate had two problems:

- it checked out its scripts at a fixed helper pin (`874ffe5`);
- it installed gh-actions-lock unpinned.

Under v0.2.0, the verifier accepted each of the seven job-level reusable
refs as coverage ("Accepted reusable-workflow lock coverage …"). It
still failed, because v0.2.0 reports those refs as `stale` at `error`
severity, and that old verifier failed on any error-severity finding.
hyperpolymath/standards#1250 fixed this: the verifier decides by
category, gh-actions-lock is pinned to v0.2.0, and the gate runs at the
reusable's own commit (`job.workflow_sha`).

## Changes

- **Six workflows** move from `hyperpolymath/standards@da2c748` to
`@934b879f6068295e42dac20d80e010d555ebec82` (standards `main`):
governance, hypatia-scan, mirror, rust-ci, scorecard and secret-scanner.
- **`actions.lock`**, repaired with standards' own chain
(`complete-job-refs.sh` → `close-lock.sh` → orphan prune):
- The `hyperpolymath/standards` record is rewritten at the new pin. Its
`uses:` is the union over the called workflows.
- The new union adds four refs, each now with its own record:
`oven-sh/setup-bun` and `denoland/setup-deno` (from the js-runtimes jobs
that #1249 added to governance), plus `actions/upload-artifact@cf430e0`
and `dtolnay/rust-toolchain@e2a55d2`.
- The old `da2c748` record is removed, along with the three refs only it
named.
- The repair ran offline. `close-lock.sh`'s `GH_BIN` stub answered from
local git (standards and cicd-suite) and from ids already recorded in
estate locks. Where the stub can't answer, close-lock skips the ref
(exit 3) and writes no guessed record.
- **`CHANGELOG.adoc`**: an entry.

**What the new pin brings.** Governance at `934b879` includes the
js-runtimes jobs from standards#1249. This repo has no `package.json`,
so they pass with a notice (denominator 0).

## RSR Quality Checklist

### Required

- [x] Tests pass (see Testing)
- [x] Code is formatted
- [x] Linter is clean
- [x] No banned language patterns
- [x] No `unsafe` blocks without `// SAFETY:` comments
- [x] No banned functions
- [x] SPDX license headers present on all new/modified source files
(unchanged headers; no new files)
- [x] No secrets, credentials, or `.env` files included

### As Applicable

- [x] `CHANGELOG` or release notes updated

## Testing

Run with the real gh-actions-lock v0.2.0 (`linux-amd64`, SHA-256
`79ec84c1…` as pinned in standards' `self-test.yml`) and mikefarah yq
v4.44.3:

| Gate scripts | Tree | Result |
|---|---|---|
| `da2c748`-era (`874ffe5`) | resource-algebra `main` | **exit 1**:
`lockfile verification FAILED`, the same failure CI shows |
| standards `main` (`934b879`) | resource-algebra `main` | exit 0 |
| standards `main` (`934b879`) | this branch | exit 0: `Immutable direct
and transitive lockfile coverage verified.` |

```
./scripts/check-lock-sync.sh
  * every lockfile entry is still referenced
  * every ref named in the lockfile resolves to a dependencies: record (0 dangling edges)
  * every workflow file has a lockfile key (zero-uses: workflows included)
```

Still red on `main`, and not this PR's: `openssf-compliance` and
`call-estate-audit` (as noted on #4).

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

https://claude.ai/code/session_01Y6FD63UrriRBHqmhhEca9t

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Y6FD63UrriRBHqmhhEca9t)_

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated the project’s automated governance, security scanning,
mirroring, and Rust CI checks. These maintenance changes do not add or
remove user-facing features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
hyperpolymath added a commit to hyperpolymath/hypatia that referenced this pull request Oct 20, 2026
…928)

## Why

gh-actions-lock v0.2.0 writes lockfile **v0.0.3**, and the estate's lock
gate now pins v0.2.0 (hyperpolymath/standards#1250).
`Hypatia.Rules.ActionsLock` accepts only v0.0.2.
- **Other repositories:** any repo whose lock is regenerated with the
estate's tool fails closed with:
  ```
  invalid_actions_lock: {:line, 4, {:unsupported_version, "v0.0.3"}}
  ```
The finding comes from both `workflow_audit` and `workflow_hardening`,
at high severity. It happened on hyperpolymath/palimpsest-license#177 as
code-scanning alerts 347 and 349.
- **This repository:** Hypatia's own `actions.lock` has been v0.0.3
since #926. Its existing test `"parses the repository's authoritative
generated lockfile"` therefore fails against the unpatched module.

## What

**114d015.** For github.com dependencies, v0.0.3 uses the v0.0.2 line
grammar. I measured this on this repo's lock and on
`rsr-template-repo`'s, both v0.0.3:
- the same `workflows:` and `dependencies:` sections;
- the same record fields (`ref`, `commit`, `owner_id`, `repo_id`,
`uses`);
- the same `'<path>': []` form for a workflow with nothing to lock.

So:
- `@supported_version "v0.0.2"` becomes `@supported_versions ["v0.0.2",
"v0.0.3"]`, both parsed by the one strict grammar.
- Every other version string is still `{:unsupported_version, v}`, and a
second `version:` line is still `:duplicate_version`.

**a50c0e5** is for CodeRabbit's finding on #929. v0.0.3 adds one
optional per-dependency field, `hostname`. The v0.2.0 binary has
`json:"hostname,omitempty"`, and it is written only for GHE.com
data-residency tenants, never for github.com. Neither real v0.0.3 lock
in the estate carries it. Rather than model multi-host identity for
hosts the estate doesn't use:
- `hostname: 'github.com'` is accepted, as the default it states;
- any other host is refused by name, `{:unsupported_dependency_hostname,
host}`;
- in a v0.0.2 lock, the field is still malformed.

The moduledoc records both points.

## Tests

`test/rules/actions_lock_test.exs` gains three cases:
- v0.0.3 is accepted with the same association semantics, and a
malformed v0.0.3 lock still fails closed.
- `v0.0.1`, `v0.0.4`, `v0.1.0` and a bare `0.0.3` are each refused, and
a second version line is a duplicate.
- `hostname` behaves as listed above, including a duplicate `hostname`
line.

I couldn't run the full suite in my sandbox, because repo.hex.pm is
blocked there, so `mix deps.get` cannot run. Instead I ran this test
file standalone against the compiled module with Elixir 1.14. I left out
only the legacy `Hypatia.Rules` case, which needs the full engine.

| Module | Result |
|---|---|
| patched | **15 / 15 pass** |
| unpatched (`main`) | the own-lock test fails |

The patched parser also reads four real locks:
- this repo's: v0.0.3, 40 dependencies;
- rsr-template-repo's: v0.0.3, 37;
- palimpsest-license's: v0.0.2, 38;
- standards': v0.0.2, 26.

`lib/rules/actions_lock.ex` is formatter-clean. I left the untouched
test lines as CI's Elixir 1.17 formatter has them.

## Relation to #929

#929 merges this branch unchanged (114d015 and a50c0e5), so CI there
exercises this code too. The two PRs merge in either order.

## Follow-up

When this merges, standards' `hypatia-scan-reusable.yml` and
`governance-reusable.yml` can move their default `hypatia-ref` from
`51ab649` to the merge commit. That makes the estate scanner accept
v0.0.3 locks.

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

https://claude.ai/code/session_01LET2eHeDbN3b4WuxYjMUX9

---------

Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.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