Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
- name: Sections (the determinism raster returns first; the rest keep running)
run: >-
python3 scripts/ci/fat_driver.py run
--sections 'sov.*,guard-tree,guard-cargo,vendored-schemas,pr-review-shadow,pr-review-sign,mutants,determinism[X64]'
--sections 'sov.*,changes,guard-tree,guard-cargo,vendored-schemas,pr-review-shadow,pr-review-sign,mutants,determinism[X64]'
--external-job workspace-test
--results "$RUNNER_TEMP/fat/results.json"
--background-until 'determinism[X64]'
Expand Down Expand Up @@ -443,14 +443,38 @@ jobs:
# cuda-unit were never in the gate; they still are not.
# workspace-test is its own job now (three shard jobs + the Σ fan-in).
[ "$WT" = success ] || { echo "workspace-test failed: $WT"; exit 1; }
for pair in X86:guard-tree X86:guard-cargo X86:sov.gate DET:determinism-compare; do
# guard-cargo and determinism-compare are read below under the docs-only rule (#3668).
for pair in X86:guard-tree X86:sov.gate; do
job="${pair%%:*}" sec="${pair#*:}"
r=$(res "${!job}" "$sec")
if [ "$r" != success ]; then
echo "$sec failed: $r"
exit 1
fi
done
# guard-cargo is the cargo half of the same guard universe (BSE-01), and
# determinism-compare is APEX-001 EV-2a's two-architecture comparison. A
# required check that `gate` does not read is not a required check, so both
# are read here -- and each may be `skipped` ONLY on a docs-only PR (#3668).
DOCS=$(printf '%s' "${X86:-null}" | jq -r '(. // {}).changes.outputs.docs_only // ""')
CHG=$(res "$X86" changes)
GC=$(res "$X86" guard-cargo)
DC=$(res "$DET" determinism-compare)
# --- GATE-DOCS-ONLY-RULE-BEGIN (#3668; scripts/check_ci_gate_docs_only_rule.sh runs this block) ---
# A skip is the docs-only skip only when the `changes` section SUCCEEDED and
# said docs_only=true. Any other skip -- changes skipped, failed, missing or
# said false -- means a section that should have run did not: a failure.
skip_ok=0
if [ "$CHG" = success ] && [ "$DOCS" = true ]; then skip_ok=1; fi
for pair in "guard-cargo=$GC" "determinism-compare=$DC"; do
job=${pair%%=*}; res=${pair#*=}
case "$res:$skip_ok" in
success:*) echo "$job: success" ;;
skipped:1) echo "$job: skipped -- docs-only PR (changes: docs_only=true, #3668)" ;;
*) echo "$job failed: $res (changes=$CHG docs_only='$DOCS'; a skip passes only on a docs-only PR)"; exit 1 ;;
esac
done
# --- GATE-DOCS-ONLY-RULE-END ---
MUT=$(res "$X86" mutants)
# --- GATE-MUTANTS-RULE-BEGIN (#3676; scripts/check_ci_gate_mutants_rule.sh runs this block) ---
# `skipped` is a pass ONLY when the skip is the job's own filter:
Expand Down
146 changes: 103 additions & 43 deletions ci/sections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,43 @@ jobs:
# discriminating runner label, so a bare [self-hosted, X64, Linux] selector
# can never again silently land a job on a GPU/dev runner without the
# sovereign-ci registry. Pure text check; runs on the clean-room pool.
# #3668: ONE docs-only decision for the run. A roadmap-only PR paid ~26 min of
# guard-cargo and ~6 of determinism for a diff neither reads. This job asks
# scripts/ci_docs_only.sh (which asks ci_test_tier.sh's #3658 definition:
# every path under docs/roadmaps/ or docs/audits/ and present at HEAD) and
# publishes docs_only. The consumers are written FAIL-CLOSED: they read
# `!cancelled() && needs.changes.outputs.docs_only != 'true'`, so this job
# being skipped (every non-PR event), failing, or printing anything but
# `true` runs everything. `gate` accepts their `skipped` only when this job
# SUCCEEDED and said true (GATE-DOCS-ONLY-RULE,
# scripts/check_ci_gate_docs_only_rule.sh).
changes:
runs-on: [self-hosted, Linux, clean-room] # arch-neutral: intel, yoga or gx10 (#3100)
timeout-minutes: 10 # shallow checkout + one git diff + one script
if: github.event_name == 'pull_request'
outputs:
docs_only: ${{ steps.decide.outputs.docs_only }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
- name: Is this PR docs-only? (#3668)
id: decide
run: |
set -euo pipefail
git fetch --no-tags --depth=1 origin \
"+refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}"
# --no-renames (#3664): a source moved into docs/ must list BOTH paths.
git diff --no-renames --name-only "origin/${GITHUB_BASE_REF}" HEAD > "$RUNNER_TEMP/touched.txt"
printf 'touched (tip vs tip): %s path(s)\n' "$(wc -l < "$RUNNER_TEMP/touched.txt" | tr -d ' ')"
bash scripts/ci_docs_only.sh --event "${GITHUB_EVENT_NAME}" --diff-from "$RUNNER_TEMP/touched.txt" \
> "$RUNNER_TEMP/docs_only.txt"
cat "$RUNNER_TEMP/docs_only.txt"
grep -E '^docs_only=(true|false)$' "$RUNNER_TEMP/docs_only.txt" >> "$GITHUB_OUTPUT"
- name: The docs-only decision can still go RED (case table)
run: bash scripts/ci_docs_only.sh --self-test

guard-tree:
runs-on: [self-hosted, Linux, clean-room] # arch-neutral: intel, yoga or gx10 (#3100)
# 20: the operator's hard PR budget (rule E, 2026-09-10), and it OVERRIDES
Expand Down Expand Up @@ -1126,6 +1163,63 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: bash scripts/guard_tree.sh --no-cargo
# #3668: these three ran in guard-cargo, but none of them invokes cargo --
# guard_tree.sh --no-cargo files them as cargo guards only because their
# SOURCE says `cargo doc` / `cargo install` in a comment or a pattern. They
# are the guard-cargo steps whose reads include docs/roadmaps/ or docs/audits/
# (docs/**/*.md, a `git ls-files | grep dogfood.sh$`), so they live here:
# guard-cargo is skipped on a docs-only PR (the `changes` job) and guard-tree
# never is, so a docs-only diff is still judged by every guard that reads it.
# One runner, one prose, and the user-scope copy stays a <=70-line shim
# that fails CLOSED. The cap lives here, in the repo on protected main;
# the file it caps lives at user scope, where it could otherwise raise its
# own ceiling.
- name: One dogfood runner, and the user-scope copy is a gated shim
run: setsid --wait bash scripts/check_dogfood_shim.sh
# §4.1 names BOTH of these in the merge-phase blocking set, alongside the
# fabricated-baseline guard above. They shipped unwired, which is why the
# five `2.93x Ollama` claims in book/ and the four deleted harnesses were
# each caught by a person rather than by CI.
#
# Neither is baselined as an exemption, deliberately. The tip commit of
# this epic says PERF-009 is "enforced by a shrink-only guard"; a guard
# named by no workflow enforces nothing, and recording that in a baseline
# file would make the claim true only in the sense that the gap is
# written down.
#
# This step is ALSO the I-12 `[X]`-figure gate, which v2.2 §5 listed as
# "not written" against this file. It was right: the comparator pattern
# required the competitor's name to sit immediately after the ratio, in
# ASCII, so of the six shapes §0.1 names it caught one. PERF-010 admits
# the connector ("36.9x over FasterTransformer") and U+00D7, and adds
# placeholders bound to a unit ("XX tok/s"). Twelve pre-existing sites
# surfaced and are baselined shrink-only; one was a LIVE comparator claim
# in book/ and is deleted.
- name: No claim literals on user-facing surfaces
run: setsid --wait bash scripts/check_no_claim_literals.sh
- name: No claim-literal guard regression (case table)
run: setsid --wait bash scripts/check_no_claim_literals.sh --selftest
# PERF-010, the receipt rule's namesake check. The guard above is the
# NEGATIVE half -- a comparator ratio may not appear at all. This is the
# POSITIVE half over the class that is allowed to stay: a speed comparison
# naming no competitor is legal iff it cites the evidence/ receipt that
# produced it (v2.2 section 3.2). Text-only and deterministic, so it
# belongs in the merge phase (section 4.1) rather than at release.
#
# It found 146 uncited speed comparisons across 30 files and ZERO citing a
# receipt -- a 0% citation rate on the very number class this epic is
# named for. Baselined shrink-only; the count is the finding.
- name: Performance claims cite their receipts (PERF-010)
run: setsid --wait bash scripts/check_perf_claims_cite_receipts.sh
- name: Claims-cite-receipts guard can still go RED (case table)
run: setsid --wait bash scripts/check_perf_claims_cite_receipts.sh --selftest
# The gate's docs-only skip rule, executed from ci.yml's own marker block.
# It reads only ci.yml and invokes no build tool, so it runs here -- the job
# that runs on every PR, including the one that edits the gate (#3668).
- name: gate accepts a skipped guard-cargo/determinism only on a docs-only PR (#3668)
run: setsid --wait bash scripts/check_ci_gate_docs_only_rule.sh
- name: gate docs-only rule can still go RED (#3668)
run: setsid --wait bash scripts/check_ci_gate_docs_only_rule.sh --self-test
# scripts/tests/guard_tree_test.sh is guard_tree.sh's OWN case table
# (BSE-01, PMAT-1062) -- it proves guard_tree.sh's no-fail-fast
# behaviour against a fixture, proves a fail-fast MUTANT of it goes RED
Expand Down Expand Up @@ -1542,6 +1636,11 @@ jobs:
# minutes onto every green run for no ordering that anything requires.
guard-cargo:
runs-on: [self-hosted, Linux, clean-room] # arch-neutral: intel, yoga or gx10 (#3100)
# #3668: skipped on a docs-only PR -- no step here reads docs/roadmaps/ or
# docs/audits/ (the three that did moved to guard-tree). Fail-closed: a
# skipped/failed `changes` job leaves docs_only empty, and this runs.
needs: [changes]
if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }}
# 20: the operator's hard PR budget (rule E, 2026-09-10), and it OVERRIDES
# the BSE-05 formula rather than being derived from it.
#
Expand Down Expand Up @@ -1712,12 +1811,6 @@ jobs:
# It found `pmat analyze reachability` bare in BOTH copies on its first run.
- name: The release runner must not resolve a verifier through PATH
run: setsid --wait bash scripts/check_verifier_pinning.sh
# One runner, one prose, and the user-scope copy stays a <=70-line shim
# that fails CLOSED. The cap lives here, in the repo on protected main;
# the file it caps lives at user scope, where it could otherwise raise its
# own ceiling.
- name: One dogfood runner, and the user-scope copy is a gated shim
run: setsid --wait bash scripts/check_dogfood_shim.sh
# deny.toml is 7.2 KB of licence / banned-crate / source-allowlist policy
# that ran in NO workflow -- only `make deny`, which is not a prerequisite
# of any tier, so nothing but a human typing it ever invoked it. Meanwhile
Expand Down Expand Up @@ -2048,43 +2141,6 @@ jobs:
# ollama never invoked (#2679).
- name: No fabricated comparator baselines
run: setsid --wait bash scripts/check_no_fabricated_baselines.sh
# §4.1 names BOTH of these in the merge-phase blocking set, alongside the
# fabricated-baseline guard above. They shipped unwired, which is why the
# five `2.93x Ollama` claims in book/ and the four deleted harnesses were
# each caught by a person rather than by CI.
#
# Neither is baselined as an exemption, deliberately. The tip commit of
# this epic says PERF-009 is "enforced by a shrink-only guard"; a guard
# named by no workflow enforces nothing, and recording that in a baseline
# file would make the claim true only in the sense that the gap is
# written down.
#
# This step is ALSO the I-12 `[X]`-figure gate, which v2.2 §5 listed as
# "not written" against this file. It was right: the comparator pattern
# required the competitor's name to sit immediately after the ratio, in
# ASCII, so of the six shapes §0.1 names it caught one. PERF-010 admits
# the connector ("36.9x over FasterTransformer") and U+00D7, and adds
# placeholders bound to a unit ("XX tok/s"). Twelve pre-existing sites
# surfaced and are baselined shrink-only; one was a LIVE comparator claim
# in book/ and is deleted.
- name: No claim literals on user-facing surfaces
run: setsid --wait bash scripts/check_no_claim_literals.sh
- name: No claim-literal guard regression (case table)
run: setsid --wait bash scripts/check_no_claim_literals.sh --selftest
# PERF-010, the receipt rule's namesake check. The guard above is the
# NEGATIVE half -- a comparator ratio may not appear at all. This is the
# POSITIVE half over the class that is allowed to stay: a speed comparison
# naming no competitor is legal iff it cites the evidence/ receipt that
# produced it (v2.2 section 3.2). Text-only and deterministic, so it
# belongs in the merge phase (section 4.1) rather than at release.
#
# It found 146 uncited speed comparisons across 30 files and ZERO citing a
# receipt -- a 0% citation rate on the very number class this epic is
# named for. Baselined shrink-only; the count is the finding.
- name: Performance claims cite their receipts (PERF-010)
run: setsid --wait bash scripts/check_perf_claims_cite_receipts.sh
- name: Claims-cite-receipts guard can still go RED (case table)
run: setsid --wait bash scripts/check_perf_claims_cite_receipts.sh --selftest
# The single source of truth needs a truth check. An authorless policy
# number, a `inherited_from` pointing at a document with no history in any
# ref, a compute_class no build in this tree reaches, and a cell exception
Expand Down Expand Up @@ -3155,6 +3211,10 @@ jobs:
# font, a locale or a cached artefact from a previous job and quietly agree for the wrong reason.
determinism:
name: determinism (${{ matrix.arch }})
# #3668 does NOT skip this section under #4433's fat jobs: its raster is uploaded
# by the fat job's own step with if-no-files-found: error (x86-main for X64, the
# determinism job for ARM64), so an unrendered raster would fail the fat job on
# every docs-only PR. It always runs; gate's docs-only rule then reads success.
strategy:
fail-fast: false # if one arch fails we still want the other's receipt to compare against
matrix:
Expand Down
22 changes: 22 additions & 0 deletions docs/roadmaps/entries/PMAT-3668.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
- id: PMAT-3668
github_issue: 3668
item_type: task
title: 'Docs-only PRs still spend ~45 min in guard-cargo and guard-tree: gate them on a single docs_only decision so a roadmap PR''s CI is < 10 min'
status: inprogress
priority: critical
assigned_to: aprender-a2
created: 2026-09-21T07:19:59Z
updated: 2026-09-24T19:00:00Z
spec: null
acceptance_criteria:
- scripts/ci_docs_only.sh prints docs_only=true only when every touched path is under docs/roadmaps/ or docs/audits/ and present at HEAD (ci_test_tier.sh docs-only, #3658); every other event, diff or error gives false. The 13-row --self-test has discriminator rows
- guard-cargo and determinism are skipped when needs.changes.outputs.docs_only == 'true' and run otherwise, including when changes is skipped or fails
- gate's GATE-DOCS-ONLY-RULE accepts a skip only when changes succeeded with docs_only=true. check_ci_gate_docs_only_rule.sh runs 14 rows over the block, and 3 planted wrong rules go RED
- the guard-cargo steps that read docs/** run in guard-tree unconditionally
- a real docs-only PR run finishes in under 10 min (observed after landing)
phases: []
subtasks: []
estimated_effort: null
labels:
- kind:code
notes: null
22 changes: 22 additions & 0 deletions docs/roadmaps/roadmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20212,6 +20212,28 @@ roadmap:
labels:
- kind:code
notes: null
- id: PMAT-3668
github_issue: 3668
item_type: task
title: 'Docs-only PRs still spend ~45 min in guard-cargo and guard-tree: gate them on a single docs_only decision so a roadmap PR''s CI is < 10 min'
status: inprogress
priority: critical
assigned_to: aprender-a2
created: 2026-09-21T07:19:59Z
updated: 2026-09-24T19:00:00Z
spec: null
acceptance_criteria:
- scripts/ci_docs_only.sh prints docs_only=true only when every touched path is under docs/roadmaps/ or docs/audits/ and present at HEAD (ci_test_tier.sh docs-only, #3658); every other event, diff or error gives false. The 13-row --self-test has discriminator rows
- guard-cargo and determinism are skipped when needs.changes.outputs.docs_only == 'true' and run otherwise, including when changes is skipped or fails
- gate's GATE-DOCS-ONLY-RULE accepts a skip only when changes succeeded with docs_only=true. check_ci_gate_docs_only_rule.sh runs 14 rows over the block, and 3 planted wrong rules go RED
- the guard-cargo steps that read docs/** run in guard-tree unconditionally
- a real docs-only PR run finishes in under 10 min (observed after landing)
phases: []
subtasks: []
estimated_effort: null
labels:
- kind:code
notes: null
- id: PMAT-3670
github_issue: 3670
item_type: task
Expand Down
Loading
Loading