Repository navigation
ci: the combined CI canon (runner allowlist stage, native-live gate shape, fleet-routed ci/docs, post-merge build-gate, release ARM on the protected runner) - #635
Conversation
…oup mirror does not list The org runner group admits a workflow by its file (`<repo>/.github/workflows/ <file>@refs/heads/main`). Moving jobs onto gke- labels without that entry queued them for eight hours with no runner and nothing in CI noticed. Add a `runner-allowlist` preflight stage. It resolves every job's `runs-on` (scalars, flow and block sequences, matrix rows, env and fromJSON values, files called with workflow_call) with the readers the runner checks already use, and fails when a file with a gke- or gkp- job is missing from the committed mirror `.github/runner-group-allowlist.txt`, or when the mirror is malformed, unsorted, duplicated, for another repository or not on refs/heads/main. A mirror line for a file without such a job is only printed. The stage is in the fast and github-only tiers and in the parallel group. docs/ci.md: the stage list and the workflow-lint paragraph change. The sentence "checks the declarations in `.github/actionlint.yaml`." gains a sentence on adding the mirror line before moving a workflow onto a gke- or gkp- label, and the sentence beginning "all stages and its existing event-aware verifier-class selection." now names the new stage. The page keeps its line count. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The org policy checker allows job-level always() on one proven aggregate per workflow. native-live.yml had two (native-live-native and native-live-gate). The native shard summary now uses the cancellable status override (!cancelled() with authz success), keeps its refusal first step and guards its remaining run step. native-live-gate directly needs every other job including the shard matrix, carries no workflow or job environment (the four build values move into both proof jobs), refuses first, and fails unless every needed result is exactly success. The preflight pins and tests follow, with mutation rows on the real workflow text for a failed, skipped or cancelled shard. docs/ci.md: the native-live paragraph names the non-required override job and the all-results gate; the page keeps its line count. Sentences replaced, named here for the doc-revert check: "The `native-live (native)` aggregate requires all four successful summary proofs;" and "`native-live-gate` requires it and both sanitizer cells, refusing missing or skipped work; the caller's `build` aggregate still requires the reusable". Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…fleet The org policy checker admits no hosted Linux label for this repository, so ci.yml authz and docs.yml authz and build now use the ordered fleet array ["self-hosted","pf-gcp-pr"] (pull_request workflows never get a GKE pod). The label is declared in .github/actionlint.yaml, and the exact runner, canon, metadata and credential checks of the preflight follow, with regression rows on the real files. docs/ci.md replaces, on their existing lines, the sentences and rows beginning: "| ci.yml authz | Hosted authorization context", "Hosted `ubuntu-24.04` runs PR `authz`, admission, `legs` and `result` jobs, and `docs.yml`'s `build`", "Hosted exceptions cover PR light jobs", "| ci.yml | Unfiltered pull_request", "| docs.yml | pull_request, except" and "HOSTED_JOB_RUNNERS pins hosted jobs". The page keeps its line count. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
… jobs Two sentences in docs/ci.md still described ci.yml authz and docs.yml authz and build as hosted light jobs after they moved to the pf-gcp-pr fleet: the closing sentence of the runner paragraph and the fork-pull-request sentence. Both now name the fleet jobs and say the VM-only fork-refusal hook applies to them. Same lines, 2016 lines kept. docs/ci.md replaces the sentences beginning: "These light, secret-free jobs need no VM-only tools, mounts or caches." and "Fork PRs on hosted runners run without our secrets, so the VM-only fork-refusal hook is not needed." Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
scripts/ci_docs_only.py classifies every non-pull_request event as code (a documentation-only push now runs the proofs) and keeps the pull_request output unchanged. ci-post.yml drops its classifier job, keeps the proof jobs, and uses one canonical all-success aggregate, build-gate, with no name field and no workflow or job environment; the four leg gates (build-release-gate, build-debug-gate, kernel-only-gate, sanitizers-gate) become guarded optional override jobs and are not required contexts. The branch ruleset must require build-gate instead of build in the same change as the merge. The preflight pins and release-gate tests follow, with rows that refuse a restored classifier job, a pull_request trigger and every omitted aggregate need. docs/ci.md replaces these sentences, quoted from the page: "The existing docs-only classification still skips proof jobs on a documentation-only PR or main push." "Scheduled and manual runs execute every profile." "A push to `main` follows the same rule, since nothing downstream needs the proof jobs to have run on a merged commit:" "`release.yml` starts only on a manual dispatch and builds and verifies its own tarballs, `promote-baseline.yml` starts on the push to `main`, resolves" "A documentation merge therefore does not rebuild; the `ci.yml` run on its commit is `preflight` and the skip." "That run is `main`'s latest, the one the README badge shows, so after a documentation merge the badge reports the documentation guards, and the last" "Shard jobs and leg aggregates skip together only on classified docs-only changes." It also replaces the sentences beginning: The existing docs-only classification; Both preflight tiers together; Scheduled and manual runs execute; ci.yml retains authorization and draft event handling; Docs-only and GitHub-only changes; Failed, cancelled or unclassified work; The seven ci-post.yml light jobs; The full post call graph expands; A push to main follows; A documentation merge therefore; That run is main's latest; The ci-workflow-contract stage pins; Shard jobs and leg aggregates. The post runner-table fragment Seven light jobs becomes Six light jobs. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The first commit of this change said the branch ruleset must require build-gate instead of build, and docs/ci.md said the ruleset changes with the rename. Both are wrong: the engine's merge ruleset requires only pineforge/verify and pineforge/parity, ci-post.yml runs only on push, schedule and dispatch, and its contexts never appear on a pull request head. Acting on that sentence would block every pull request. docs/ci.md now says so, on the same two lines. No ruleset change is needed or wanted for this change. docs/ci.md replaces the sentences beginning: "The required aggregate context is `build-gate` (formerly `build`); the ruleset changes with that rename." Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
release.yml prebuilt moves its linux-aarch64 row from hosted ubuntu-22.04-arm to the bare protected scalar gkp-8cpu-16gb-arm64 (runner group gke-protected, main-ref workflows only) and runs under the release environment. Both triples, the x86_64 runner, the release needs and tag assertions, and the upload safeguards are unchanged; the Build step now uses the runner's core count instead of -j 4. The preflight pins and regression rows follow. docs/ci.md replaces sentences beginning: "Hosted exceptions cover PR light jobs and the existing hosted release cells", "GKE jobs carry no deployment secrets" and "Release's Linux arm64 artifact cell keeps its hosted". Compatibility note: the protected toolchain image's base and glibc version are not stated in the sources read; the previous Ubuntu 22.04 floor is glibc 2.35. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…and pin its guards
The prebuilt secret scan ran after comment lines were dropped, so a commented
`${{ secrets.NAME }}` inside a run block passed while GitHub still expands the
expression into the step script before the shell discards the comment. The
credential check and the runner policy now also read the raw job text for
`${{ ... }}` expressions. New rows put commented secret expressions (dotted,
indexed, dynamic index, toJSON and a format string containing a closing brace
pair) into the real prebuilt job and expect the finding, keep plain comment
prose and the GITHUB_TOKEN reference clean, change the job permissions in two
more ways than an added id-token, and give the Build step an `if:`, a
continue-on-error and a duplicate step name.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…is a gkp job release.yml prebuilt runs its linux-aarch64 row on the protected scalar gkp-8cpu-16gb-arm64, so the runner-allowlist stage requires the file's line in .github/runner-group-allowlist.txt. The line mirrors the live gke-protected runner group entry (pineforge-engine release.yml at refs/heads/main). Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…mirror line Two RunnerGroupAllowlist rows still described the tree before the combined stack: - test_hosted_and_pf_gcp_workflows_need_no_mirror_entry replaced the literal text "runs-on: ubuntu-24.04" in the authz job, but ci.yml's authz job now runs on the PR fleet, so the replacement text was absent. It now replaces the job's own runs-on line (and asserts that line names pf-gcp-pr) and still tries all four runners. - test_real_tree_mirror_preserves_the_live_group_and_only_two_advisories listed nine mirror entries; the mirror now also lists release.yml, whose ARM row is a gkp job. The expected list gains release.yml; the two advisories are unchanged. No expectation is weakened: each row still fails on a wrong mirror or a wrong runner. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
# Conflicts: # .github/runner-group-allowlist.txt # scripts/test_ci_preflight.py
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.
Not checked: tests were not run; formal verification proved 0 of 12 changed function(s) (4 sampled, not proven, 5 not verified).
Formal verification. 3 change(s) alter behavior, breaking input(s) attached. PR-changed functions: 7/12 verified (0 proven, 4 may-equivalent, 3 distinguished) · 5 not verified (5 vacuous).
Behavior changes: ci\_authz\_only\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which ci\_authz\_only\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"workflow":"'\\\\t\\\\n'"\}, the old code produced \['ci\.yml must retain only the pull\_request trigger', 'ci\.yml must keep its exact unfiltered PR triggers', 'ci\.yml must run on every pull\_request without event filters', 'ci\.yml must retain its… but the new code produces \['ci\.yml must retain only the pull\_request trigger', 'ci\.yml must keep its exact unfiltered PR triggers', 'ci\.yml must run on every pull\_request without event filters', 'ci\.yml must retain its…. Paste that input straight into a regression test.
Behavior changes: native\_workflow\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which native\_workflow\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"native":"' '","curl\_action":"None"\}, the old code produced \['native\-live\.yml must start with the verbatim canon authz job', 'native\-live\.yml must use readable events without pull\_request\_target', 'native\-live\.yml must retain contents: read workflow… but the new code produces \['native\-live\.yml must start with the verbatim canon authz job', 'native\-live\.yml must use readable events without pull\_request\_target', 'native\-live\.yml must retain contents: read workflow…. Paste that input straight into a regression test.
Behavior changes: post\_shard\_workflow\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which post\_shard\_workflow\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"jobs":"\{'n': 0, 's': 'x', 'l': \[1, 2\]\}"\}, the old code produced \['build\-release\-gate must require only its own complete shard matrix and keep its docs\-only scheduling policy', 'build\-debug\-gate must require only its own complete shard matrix and keep its do… but the new code produces \['build\-release\-gate must require only its own complete shard matrix and keep its guarded non\-required override policy', 'build\-debug\-gate must require only its own complete shard matrix and ke… (outputs first differ at character 85). Paste that input straight into a regression test.
Not verified on this run: classify\_paths (vacuous: never exercised), compared (vacuous: never exercised), main (vacuous: never exercised), pipeline\_workflow\_findings (vacuous: never exercised), runner\_findings (vacuous: never exercised).
Graphify review — findings
Removes the docs-only changes classifier from ci-post.yml, so every proof job (build, sanitizers, kernel-only, ARM) now runs on every push with no skip path for documentation-only commits. The per-leg aggregate gates now key on !cancelled() instead of always(), and the shared ccache and release-tag env moves from workflow level onto each job that uses it. Adds the pf-gcp-pr and gkp-8cpu-16gb-arm64 runner labels and the release.yml allowlist entry, and moves the docs and PR workflows onto the self-hosted PR fleet, with the preflight, release-gate and shard-runner tests updated to match.
Worth a look
- Docs authz gate now runs on self-hosted PR fleet before authorization —
.github/workflows/docs.yml:20· Escalate · high- NOT verified (no proof, no reproducing execution) — needs human review
- Authorization gate now runs on the self-hosted PR fleet before authz decides —
.github/workflows/ci.yml:23· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- Docs authz and PR docs build moved onto the self-hosted PR fleet —
.github/workflows/docs.yml:81· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- ARM release runner label likely misspelled ('gkp-' vs 'gke-') —
.github/workflows/release.yml:371· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- Misspelled GKE runner label is allowlisted —
.github/actionlint.yaml:16· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1420 functions depend on the 1411 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
native_workflow_findings()— 15 callers, 12 callees - worse:
gated_workflow_findings()— 6 callers, 10 callees - worse:
runner_findings()— 2 callers, 23 callees - worse:
ci_authz_only_findings()— 2 callers, 8 callees - worse:
pipeline_workflow_findings()— 1 callers, 13 callees - worse:
_holds_credentials()— 3 callers, 4 callees
Verification — 1420 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1420 function(s) in the blast radius were not formally verified this run
Docs that may be stale (advisory)
AGENTS.md§ REQUIRED before claiming any change is done (lines 5-45): references changed symbolspost,workflowAGENTS.md§ Refactor workers (native-engine programme, R4 and later) (lines 105-141): references changed symbolsworkflowAGENTS.md§ Merge gate and parity campaign (lines 142-160): references changed symbolsworkflowsCHANGELOG.md§ CI and release process (lines 280-341): references changed symbolspost,workflowCHANGELOG.md§ 1.6.0 — 2026-10-17 (lines 1338-1503): references changed symbolsworkflowsCLAUDE.md§ Refactor workers (native-engine programme, R4 and later) (lines 108-143): references changed symbolsworkflowCONTRIBUTING.md§ Maintainer: release checklist (lines 346-368): references changed symbolsworkflowsdocs/README.md§ Deployment (Cloudflare Pages) (lines 99-103): references changed symbolsworkflowsdocs/pages/public-contract.md§ Versions (lines 99-124): references changed symbolsworkflow,workflowsdocs/pine-adapter-kernel-notes.md§ 2.2 Same-bar strategy.close batching (lines 749-780): references changed symbolspost
…and 1 more.
Formal verification
Behavior changes: ci\_authz\_only\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which ci\_authz\_only\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"workflow":"'\\\\t\\\\n'"\}, the old code produced \['ci\.yml must retain only the pull\_request trigger', 'ci\.yml must keep its exact unfiltered PR triggers', 'ci\.yml must run on every pull\_request without event filters', 'ci\.yml must retain its… but the new code produces \['ci\.yml must retain only the pull\_request trigger', 'ci\.yml must keep its exact unfiltered PR triggers', 'ci\.yml must run on every pull\_request without event filters', 'ci\.yml must retain its…. Paste that input straight into a regression test.
Behavior changes: native\_workflow\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which native\_workflow\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"native":"' '","curl\_action":"None"\}, the old code produced \['native\-live\.yml must start with the verbatim canon authz job', 'native\-live\.yml must use readable events without pull\_request\_target', 'native\-live\.yml must retain contents: read workflow… but the new code produces \['native\-live\.yml must start with the verbatim canon authz job', 'native\-live\.yml must use readable events without pull\_request\_target', 'native\-live\.yml must retain contents: read workflow…. Paste that input straight into a regression test.
Behavior changes: post\_shard\_workflow\_findings changes behavior, here is the input that shows it.
The verifier found a concrete input on which post\_shard\_workflow\_findings behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.
Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.
Evidence: On input \{"jobs":"\{'n': 0, 's': 'x', 'l': \[1, 2\]\}"\}, the old code produced \['build\-release\-gate must require only its own complete shard matrix and keep its docs\-only scheduling policy', 'build\-debug\-gate must require only its own complete shard matrix and keep its do… but the new code produces \['build\-release\-gate must require only its own complete shard matrix and keep its guarded non\-required override policy', 'build\-debug\-gate must require only its own complete shard matrix and ke… (outputs first differ at character 85). Paste that input straight into a regression test.
Could not verify: Could not verify classify\_paths.
The verifier did not have enough to check classify\_paths, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: non-vacuity: domain too small (only 2 distinct inputs exercised, need 3) — 'no divergence' would be near-vacuous
Could not verify: Could not verify compared.
The verifier did not have enough to check compared, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 18 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly Doubt — names the real obstacle, not a sampling gap)
Could not verify: Could not verify main.
The verifier did not have enough to check main, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 12 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly NameError — names the real obstacle, not a sampling gap)
No difference found (not proven): No behavior difference found in \_authz\_header (not a proof).
The verifier ran both versions of \_authz\_header on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_holds\_credentials (not a proof).
The verifier ran both versions of \_holds\_credentials on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in actionlint\_runner\_label\_findings (not a proof).
The verifier ran both versions of actionlint\_runner\_label\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in authz\_workflow\_findings (not a proof).
The verifier ran both versions of authz\_workflow\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify pipeline\_workflow\_findings.
The verifier did not have enough to check pipeline\_workflow\_findings, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 63 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly TypeError — names the real obstacle, not a sampling gap)
Could not verify: Could not verify runner\_findings.
The verifier did not have enough to check runner\_findings, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: non-vacuity: domain too small (only 2 distinct inputs exercised, need 3) — 'no divergence' would be near-vacuous
· 3 grounded finding(s) anchored inline below; 3 more finding(s) on lines outside this diff (see the check run).
| return expressions | ||
|
|
||
|
|
||
| def _holds_credentials(workflow: str, body: str, *, effective_permissions: bool = False) -> bool: |
There was a problem hiding this comment.
_holds_credentials()
high coupling complexity (Ca·Ce = 12).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| @@ -3347,52 +3363,38 @@ def _native_profile_job_findings(job: str, name: str, *, sharded: bool) -> list[ | |||
|
|
|||
|
|
|||
| def pipeline_workflow_findings(workflow: str, name: str, *, pr: bool) -> list[str]: | |||
There was a problem hiding this comment.
pipeline_workflow_findings()
fans out to 13 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| @@ -3803,7 +3796,7 @@ def docs_workflow_self_test(workflow: str, post: str) -> int: | |||
|
|
|||
|
|
|||
| def ci_authz_only_findings(workflow: str) -> list[str]: | |||
There was a problem hiding this comment.
ci_authz_only_findings()
fans out to 8 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
* ci: route CI Linux x64 jobs through the live ci-spot pool * ci: route corpus parity through the ci-spot build class * ci: route native live profiles through the ci-spot pool * ci: route documentation through the public ci-spot class * ci: route manual baseline promotion through ci-spot * ci: route release Linux x64 jobs through ci-spot * ci: require exact ci-spot routing and job labels in preflight Replace the CR-170 standard-only runner contract with the public and engine-x64-16 fragments, including fork and untrusted-event fallback. Require one matching PF_CI_LABELS string at job scope; pin the Linux-only build and release matrix routing and the unchanged hosted legs. Retain larger-runner, timeout, core-count and reusable-workflow guards. Update mutation and stage tests for missing, duplicate and incorrect PF_CI_LABELS, wrong label lists, unsafe fragment changes, paid labels and hosted exceptions. No tests, builds, linters or verification scripts run locally under the executor no-run rule. * docs: record the live ci-spot pool and hosted fallbacks Supersede the stopgap sentences from 3484a7c, squash-merged as 693fd9e (pineforge-4pass#415, CR-170). Reword the runner-selection and timing assumptions from d093560 (pineforge-4pass#290) and the documentation-only runner sentence from 133f571 (pineforge-4pass#308); preserve the platform limits from 2394ba2 (pineforge-4pass#373). Record the 2026-10-18 live-pool bulletin, exact fragment and environment labels, class allocation, actor allowlist, hosted matrix legs and event fallbacks. Keep historical timings separate from unmeasured pool performance. No local verification run under the executor no-run rule. * ci: restore release and deployment jobs to their original hosted runners Apply the L6 production-credential ruling to Cloudflare docs deployment, baseline promotion and every release job. Restore all three workflow files byte-for-byte from origin/main, including their original hosted labels, and remove pool environment labels. No steps, permissions, timeouts or matrix populations change. No tests, builds, linters, preflight, corpus verification or workflows run locally under the executor no-run rule. Nothing pushed. * ci: adopt the b240f6d7 hosted fallback for pool jobs Match the current pf-ci-spot public and engine-x64-16 fragments from bulletin pineforge-4pass#635. Change the hosted fallback to ubuntu-24.04 for all ten pool job definitions and preserve their matching PF_CI_LABELS, actor checks, fork protection and macOS routing. No tests, builds, linters, preflight, corpus verification or workflows run locally under the executor no-run rule. Nothing pushed. * ci: require hosted runners for credential-bearing jobs Pin the b240f6d7 expressions and original hosted release/deployment routes. Detect non-GITHUB_TOKEN secrets, inherited workflow environment secrets, job or workflow OIDC write permissions and deployment environments. Require hosted routing without PF_CI_LABELS for credentials and current fragments with matching labels for other Linux x64 jobs. Preserve the larger-runner, timeout and core-count guards. Add must-fail credential and old-fallback cases and a must-pass case for the current hosted release workflow. No tests, builds, linters, preflight, corpus verification or workflows run locally under the executor no-run rule. Nothing pushed. * docs: record the L6 hosted credential rule and current pool fallback Reword the pool-allocation, release/deploy routing and fallback sentences introduced by 28fe3466a and carried into f9bee22. Cite pf-ci-spot b240f6d7 and bulletin pineforge-4pass#635, retain the Dependabot and historical policy references, and explain the exact original hosted labels and updated preflight contract. No tests, builds, linters, preflight, corpus verification or workflows run locally under the executor no-run rule. Nothing pushed. * test(ci): anchor pool label mutations to job-level env An unanchored four-space env search matched the tail of step-level env in promotion and release jobs, so the negative fixture never put PF_CI_LABELS in the job environment. Anchor the env and steps keys to complete job-level lines in both label fixture builders. Assert the injected label at job scope and require the exact hosted-job diagnostic. Keep the existing hosted release baseline and the production guard unchanged. No tests, builds, linters or verification scripts run locally under the executor no-run rule. Nothing pushed.
Combines the pending CI changes into one branch, merged with main:
gke-/gkp-label that the runner-group mirror does not list, and listrelease.ymlin that mirror;always()on its single aggregate gate only;build-gateis required;ci.ymlauthorization fleet and therelease.ymlmirror line.Verification: the full 8-step lab gate passed on this exact head (preflight, release, debug, sanitizers, kernel, docs, parity, subset).
🤖 Generated with Claude Code