chore(ci): tier B of the CI audit — the release cache pair and the site-node composite - #968
Conversation
… job aggregators setup-alsa: 11 bare apt-get copies (4 comment variants, none retried) become one composite carrying the #633 WHY and the smoke job's mirror-retry envelope — the flake class that costs a full re-run per occurrence. require-jobs: the three byte-identical jq aggregators become one composite (ci.yml's gate keeps its policy-pinned per-group env reads). The hygiene job's five Go tools cache on a key derived from this workflow file, so a version bump can never serve a stale binary (148s of a 189s job was compiling them). codspeed gains the standard concurrency block and loses a duplicate permissions grant; the Chromium-before-check comment moves onto the step it describes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
The Linux --no-default-features flag derives inside build-target from the target (it was a byte-identical expression + comment at both call sites and a third telling in the recipe); `just workspace-version` owns the Cargo.toml version parse (release tag validation and `just bump` both read it; packaging-build keeps its just-free inline form); the cargo-public-api pin becomes API_PUBLIC_API, asserted at run time by _api-nightly so a divergence between ci-lint's installer and the goldens fails loud instead of churning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
…vocation helper ci-supplemental.yml was deleted in #956; subtracting a name that no longer exists is a no-op a green gate can never surface, so the exemption, its clause, its fixture row, and its test go. The behavior test's seven publisher blocks share run_publisher, varying only the review body and head pair. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
…ck, and honest prose Lens dispositions (3 lenses, all APPROVE-WITH-NITS/REQUEST-CHANGES on in-scope items): - FIXED require-jobs passing vacuously on a missing results input (probe: actionlint accepts the omission; jq exits 0 on empty) — in-composite guard. - FIXED the deny message + test literal still saying "non-advisory" after the advisory class was deleted (paired edit, the message now names what it pins). - FIXED workspace-version stealing build's comment block (the string-anchor class again) and its doc overclaiming "one authority" while packaging-build keeps a deliberate just-free parse (now said in prose at the recipe). - FIXED codspeed losing the workflow-level read floor (the concurrency edit had replaced it; the cited job-scoping precedent is about called workflows). - FIXED the go-tools bin dir being derived in one step and spelled in the cache path (a hit could restore off-PATH); one literal spelling + the WHY. - FIXED _api-nightly → _api-toolchain (it now asserts AND provisions), its absent-tool message parsing in both branches, and the API pin story moving onto API_PUBLIC_API with the echo homes trimmed to references. - FIXED comment rot the diff introduced: lychee comment back on its step, "warm rebuild" → cold reinstall, mutants' DEFAULT-features WHY restored, smoke's ffmpeg comment now references the composite envelope, the publish job keeps only its stranding consequence, the unsupported "drifted once already" history claim dropped, the unquoted-$flags constraint stated. - REFUTED the ALSA guard-home question: the one polymorphic caller is where the guard already lived; macOS no-op is correct (CoreAudio). - SURFACED (PR body): packaging-build's independent version parse, the bare musl-tools install on the tag path, the aggregators' new checkout network dependency, and the tag-time-only surfaces exercised locally instead. plan-miss: the workspace-version insertion point — the known string-anchor trap, caught by two lenses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
d32afcb deleted the middle line of a three-sentence comment, leaving "default features pull" dangling; the rodio -> cpal -> ALSA chain was not relocated anywhere (setup-alsa names only alsa-sys). Revert-shaped: the original meaning returns in full. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
The build and deb jobs rebuild the same aarch64 target with the same flags
into per-job caches, so every tag paid a second cold cross build; both now
share release-<target>. pages.yml and site.yml carried ~20 verbatim lines of
Node/npm/Playwright setup; the setup-site-node composite owns them, exposes
the Node major for withastro, and the ci-obs pin follows the moved step: the
composite must keep the exact pinned install, and each workflow must call it
un-conditioned exactly once (the same protection, one authority).
CodeQL paths-ignore was attempted and REVERTED: main.rego deliberately pins
on.pull_request to exact-null ("any filter lets some PR merge unanalyzed").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
…rity, and the honest cache claim Lens dispositions: - FIXED both site workflows' paths lists omitting the new composite — a composite-only change got zero runtime exercise and no redeploy, falsifying pages.yml's own "every input the build reads" invariant. - FIXED the dangling-step-id class structurally: the Node major is now a composite INPUT (default 26) feeding setup-node and the output — no step id to rename out from under outputs.value (the proposed detection rule became unnecessary; 1,218 published action.yml files use the inputs-in-outputs form). The deploy still deserves one watched pages.yml run — noted in the PR. - FIXED the shared-key comment overclaiming: build and deb start together and tag caches are tag-scoped (GitHub docs, fetched), so a fresh tag pays both cold either way; the honest wins are same-tag re-runs and one cache entry instead of two — the second sentence now guards against a future needs:-build "fix" that would serialize the release. - FIXED the composite's comments: version-neutral npm prose, the chromium ordering stated as the composite's own constraint, the withastro WHY on the output; the rego comment split onto the helper each half constrains; the conditioned-call test uses the constant so a ref rename cannot green it. - SURFACED, not folded: a bootstrap-before-npm-ci ordering rule (a NEW gate — the pre-change policy never pinned ordering either, and fix rounds do not add gates); lighthouse_workflow_path naming (pre-existing, 13 uses). - REFUTED (was SURFACED): CodeQL path-filtering — main.rego pins on.pull_request to exact-null with the WHY; the mechanism decides unless the owner changes the policy itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU
# Conflicts: # .github/workflows/pages.yml
Claude Security ReviewHead: Findings: 0 — No findings This diff only refactors CI workflow/action YAML and OPA policy for the site build pipeline; it touches none of the defined trust boundaries (hook shim, socket/pipe transport, settings/config writes, path/home/process/credential handling, or transcript/hook/JSONL/pack ingestion), so there are no security-relevant changes. Automated read-only review by Claude Code |
Claude ReviewHead: Findings: 0 — No findings Clean CI-only refactor: dedupes the site's Node/npm/Playwright bootstrap from pages.yml and site.yml into a new .github/actions/setup-site-node composite, updates trigger paths, and rewrites the corresponding OPA rego rules and tests to match (github_workspace/pinned_npm_setup_steps cleanly replaced with site_node_action_installs/site_node_call_steps, no dangling references). Verified the composite's step order, working directories, node-version output propagation, and the release.yml rust-cache shared-key change (correctly scoped to the one target — aarch64-unknown-linux-gnu — both build and deb jobs actually share); no architecture-invariant, correctness, or DRY violations found. Automated read-only review by Claude Code |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #968 +/- ##
=======================================
Coverage 95.72% 95.73%
=======================================
Files 197 197
Lines 58303 58303
=======================================
+ Hits 55811 55814 +3
+ Misses 2492 2489 -3
🚀 New features to boost your workflow:
|
Tier B of the CI audit (items 8-11). Was #967, stacked on #966; that PR closed permanently when the merged base branch was deleted, so this is the same branch re-targeted at main (tier-A content arrives via a merge of the squash, auto-resolved).
What
aarch64-unknown-linux-gnu, identical flags since chore(ci): tier A of the CI audit — composites, caches, and one-authority pins #966's target-derived--no-default-features) into per-job caches; both now useshared-key: release-<target>. Honest scope, per review: a fresh tag still pays both cold (the jobs start together; tag caches are tag-scoped) — the wins are same-tag re-runs of a failed deb leg and one cache entry instead of two (cache is currently over the 10 GB ceiling).setup-site-nodecomposite — pages.yml and site.yml shared ~20 verbatim lines of Node/npm/Playwright setup; the composite owns them. The Node major is a composite input (default 26) — one authority feedingsetup-nodeand an output pages.yml forwards towithastro/action(which runs its own Node setup and would otherwise pick a different major). The ci-obs pin follows the moved step: the composite must keep the exact pinned npm install, and each workflow must call the composite un-conditioned exactly once. Both workflows'paths:lists now include the composite (review-caught: a composite-only change previously got zero runtime exercise).Dispositions of the audit's items 9-10
shared-key/save-ifconsolidation) need restore-rate measurement first — most main-branch jobs build with different flag sets, and forcing a shared key across them thrashes. Surfaced with that caveat.main.regopinson.pull_requestto exact-null ("any filter lets some PR merge unanalyzed"); changing that is a security-policy decision, not a cleanup. The ci.yml step-level skip design (~400 runner-min/week) remains available but wants its own design-gated PR: a changes-filter job +if:on expensive steps, inverted default, aggregators and policy untouched. Say the word and it becomes PR 3.Review (two-lens gate)
3 lenses (correctness / design / whole-file comment audit): APPROVE-WITH-NITS ×2, REQUEST-CHANGES ×1 (both its HIGHs fixed — one on the parent branch as #966's round 2, one here). Fold
ec88fdd4. Probe highlights: rust-cacheshared-keysemantics fetched from its README; every policy mutation fires the right deny (install deleted, call deleted,if:added — both levels); zizmor parses and still suppresses inside the composite; the deleted-outputs case is actionlint-caught while the input-shaped authority removes the dangling-id case structurally.Deploy-watch note:
withastro/action+ the output forwarding live only in pages.yml, which never runs on PRs — watch the first main-push pages run's "setup node" step resolve Node 26 before trusting the chain end-to-end.Surfaced: a bootstrap-before-
npm ciordering rule inside the composite (new gate — needs its own small PR if wanted);lighthouse_workflow_pathnaming debt (13 uses, site.yml's check job is 1-of-10 lighthouse).🤖 Generated with Claude Code
https://claude.ai/code/session_01K6LG4b2iq2tRHvJ3AhFXDU