Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
76ad6c8
feat(ci): tier=reuse for a PR with a verified signed receipt (Refs #5…
noahgift Oct 21, 2026
589a09d
ci(mg-reuse): merge_group skips workspace-test-shard on an identical-…
noahgift Oct 21, 2026
fe1d367
merge origin/main into ci/mg-reuse-shards: draft-skip (f0d48dc9c0) an…
noahgift Oct 21, 2026
5247a32
fix(mg-reuse): wt=1 needs >=1 workspace-test-shard job, all success; …
noahgift Oct 21, 2026
1b7f02c
fix(mg-reuse): shard job names are 'workspace-test-shard (N, M)'; the…
noahgift Oct 21, 2026
197ee71
fix(mg-reuse): wt=1 needs every shard of the matrix present (nsh==M) …
noahgift Oct 21, 2026
cb92a52
Merge origin/main into recut/5798-sq (port --receipt-ok into scripts/…
Oct 21, 2026
fd4b55a
ci(#5797): shard if keeps success() on workspace-test-arch; drop unus…
Oct 22, 2026
5ce1079
Revert "ci: drop X64 from arch-neutral runs-on, pin the FULL tier's s…
Oct 22, 2026
da08180
merge origin/main into ci/mg-reuse-shards: shard needs both workspace…
Oct 22, 2026
f84b26e
ci(shard): !cancelled() must not hide a failed workspace-test-arch (R…
Oct 22, 2026
aa6fd1f
ci(mg-reuse): refuse wt=1 unless the cited PR run really ran tests (r…
Oct 22, 2026
e8bc5fe
ci(mg-reuse): once receipt-judge exists the test-ran marker must need…
Oct 22, 2026
1e90d3c
Merge #5907 revert head 5ce1079ffa into recut/5798-sq (staged; re-por…
Oct 22, 2026
46cccaf
Merge #5907 revert head 5ce1079ffa into ci/mg-reuse-shards (staged; n…
Oct 22, 2026
7dcf4f1
Merge origin/main into recut/5798-sq-pace
Oct 22, 2026
f4a5da0
Merge origin/main into ci/mg-reuse-shards
Oct 22, 2026
efcf95f
Merge remote-tracking branch 'origin/main' into ci/mg-reuse-shards
Oct 22, 2026
78721f7
Merge remote-tracking branch 'origin/main' into HEAD
Oct 22, 2026
1c80989
fix(ci): regenerate roadmap aggregate after merge; rewrite shards() j…
Oct 22, 2026
f6014e7
ci(receipt-gate): judge_ok pins shard fallback, trust dir, ok=0 guard…
Oct 22, 2026
a12b829
fix(ci): #5885 re-seat findings — non-vacuous mg-reuse rows, no trans…
Oct 22, 2026
aa8b4ba
test(ci): guard #5885 fixes 3 and 4 — mgshape rules + 3 mutants shown…
Oct 22, 2026
c753ff1
ci(receipt-gate): judge_ok pins whole lines, shard comment-stripped; …
Oct 22, 2026
93e1dd9
ci(receipt-gate): judge_ok pins the GITHUB_OUTPUT line; W20k E5 mutan…
Oct 22, 2026
82a12c3
ci(receipt-gate): hash-pin the whole judge job, ok=0 init pin, behavi…
Oct 22, 2026
7e3e72c
ci(receipt-gate): hash-pin the tier consumer chain, refuse BASH_ENV/d…
Oct 22, 2026
1f19d49
ci(receipt-gate): sha256-pin the shard job, its sections.yml block, f…
Oct 22, 2026
004c210
ci(receipt-gate): spelling-proof structure pins (top-level keys, job …
Oct 22, 2026
1df6517
ci(receipt-gate): fat_driver drops RECEIPT_OK from GITHUB_ENV; pin th…
Oct 22, 2026
52f6d50
ci(receipt-gate): tier-step helpers run with scratch GITHUB_OUTPUT/EN…
Oct 22, 2026
59f9eda
gate(#5850): byte-pin the six tier-step helpers + ci_mg_reuse.sh; W41…
Oct 22, 2026
577bda7
gate(#5850): tier step pins RUSTUP_TOOLCHAIN so a PR rust-toolchain.t…
Oct 22, 2026
f608ff4
Merge remote-tracking branch 'origin/main' into w5018/p5885
Oct 22, 2026
ea4fea2
test(ci): D1 CANON lists mg-reuse-wt, workspace-test-ran and the shar…
Oct 22, 2026
6caee74
Merge remote-tracking branch 'origin/main' into HEAD
Oct 22, 2026
10f4f79
gate(#5850): ci_mg_reuse.sh pin follows #5801 (03b3bdf6...)
Oct 22, 2026
3c67b42
gate(#5850): merge #5885 (workspace-test-ran), D1 CANON receipt-judge…
Oct 22, 2026
9d8bb4c
Merge remote-tracking branch 'origin/main' into HEAD
Oct 22, 2026
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
1 change: 1 addition & 0 deletions .flow009/batcher.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINna9SBgvdA0Te1LhyTa6jXbDu8SgJmiDDPhHkLmljw7 flow009-batcher
63 changes: 58 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -512,21 +512,73 @@ jobs:
# The workspace tests, one shard per job (nextest hash partition N/12 plus the
# explicit runner's round-robin N/12), in parallel on the X64 clean-room pool.
# The section body is ci/sections.yml `workspace-test-shard`, unchanged.
# #5798: the receipt judge. A PR cannot forge a receipt: this job checks out the BASE only
# and fetches the PR merge commit as data (a --no-checkout worktree that is read, never
# executed), on a dedicated self-hosted ephemeral runner (label receipt-judge) that no PR-code job ever shares, and runs the
# verifier under `env -i` with absolute tools. What it does NOT cover: a PR that edits the CI
# files or the judge itself. merge_group ignores --receipt-ok but runs only the QUICK tier
# (full only on tag/release, scripts/ci_test_tier.sh merge_group case), from the PR's own
# CI files, so it does not re-judge such an edit with a trusted copy; CI-edit review is the
# only backstop. scripts/check_receipt_gate.sh (W16-W32) turns RED if
# this job gains a step that runs PR-tree code or checks the PR out as code.
# Fail closed: the job runs only once the repo variable RECEIPT_JUDGE_RUNNER_READY is 'true' (set
# after the label has a runner). Until then it is skipped, the shard gets ok=0 and the PR runs the
# tier its diff selects, so a judge with no runner never queues and never blocks a PR.
# It always exits 0; the shard job reads `ok` as 1 only on a literal 1.
receipt-judge:
if: github.event_name == 'pull_request' && vars.RECEIPT_JUDGE_RUNNER_READY == 'true'
runs-on: [self-hosted, Linux, X64, receipt-judge]
timeout-minutes: 10
permissions:
contents: read
outputs:
ok: ${{ steps.judge.outputs.ok }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.base_ref }}
persist-credentials: false
- name: Judge the receipt in the PR body
id: judge
env:
GH_TOKEN: ${{ github.token }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
export GIT_NO_REPLACE_OBJECTS=1
ok=0
printf '%s' "${PR_BODY:-}" > "$RUNNER_TEMP/pr-body.md"
export GIT_TERMINAL_PROMPT=0 GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.https://github.com/.extraheader
GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')"
export GIT_CONFIG_VALUE_0
if git fetch -q --no-tags --depth=1 origin "refs/pull/${PR_NUMBER}/merge" &&
[ "$(git rev-parse FETCH_HEAD)" = "${GITHUB_SHA}" ] &&
unset GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0 GH_TOKEN &&
git -c core.hooksPath=/dev/null worktree add -q --no-checkout --detach "$RUNNER_TEMP/prtree" FETCH_HEAD &&
git show HEAD:scripts/ci/receipt_ok_arg.sh > "$RUNNER_TEMP/rok.sh"; then
# --no-checkout: the PR tree has no files, so no PR executable can sit in the verifier's
# cwd, and no filter or hook runs. The wrapper is read from the base object database.
ok="$(cd "$RUNNER_TEMP/prtree" && env -i HOME="$HOME" PATH=/usr/local/bin:/usr/bin:/bin /usr/bin/bash "$RUNNER_TEMP/rok.sh" "$RUNNER_TEMP/pr-body.md" "$GITHUB_WORKSPACE" "${GITHUB_SHA}")" || ok=0
fi
[ "$ok" = 1 ] || ok=0
printf 'ok=%s\n' "$ok" >> "$GITHUB_OUTPUT"

# mg-reuse-wt may cite a PR run only if that run really tested the tree. A receipt-reuse run (#5850, tier=reuse)
# runs no test step, so its shards are green over zero tests. This marker needs the shards and runs only after
# they SUCCEEDED, so a run whose shards were skipped or failed never has it; ci_mg_reuse.sh refuses wt=1 unless it
# succeeded (R:k6-wt-ran). Once #5850's receipt-judge job exists, ci_mg_reuse.sh --self-test
# (mgshape) is RED until this job needs it and keys its if on receipt-judge.outputs.ok.
# succeeded (R:k6-wt-ran). With #5850's receipt-judge job present, ci_mg_reuse.sh --self-test (mgshape) needs this
# job to need the judge and key its if on receipt-judge.outputs.ok: a judged receipt-reuse run never owns the marker.
workspace-test-ran:
needs: [workspace-test-shard]
if: ${{ !cancelled() && needs.workspace-test-shard.result == 'success' && github.event_name == 'pull_request' && github.event.pull_request.draft != true }}
needs: [workspace-test-shard, receipt-judge]
if: ${{ !cancelled() && needs.workspace-test-shard.result == 'success' && needs.receipt-judge.outputs.ok != '1' && github.event_name == 'pull_request' && github.event.pull_request.draft != true }}
runs-on: [self-hosted, Linux, clean-room]
timeout-minutes: 5
steps:
- run: echo "this run owes and runs the test suite"
workspace-test-shard:
# T43b: a merge_group entry whose tree equals a green PR run's skips the shards (mg-reuse-wt); anything else runs them
needs: [mg-reuse-wt]
# #5850: the judge is skipped off a pull_request and fails closed: !cancelled() runs the shard whatever the judge did, and RECEIPT_OK is 1 only on the judge's literal 1.
needs: [receipt-judge, mg-reuse-wt]
if: ${{ !cancelled() && needs.mg-reuse-wt.outputs.wt != '1' && github.event.pull_request.draft != true }}
# same lanes as x86-main: clean-room for pull_request/push, mq for a merge_group entry
runs-on: ${{ github.event_name == 'merge_group' && fromJSON('["self-hosted","Linux","X64","mq"]') || fromJSON('["self-hosted","Linux","X64","clean-room"]') }}
Expand All @@ -539,6 +591,7 @@ jobs:
outputs:
results: ${{ steps.run.outputs.results }}
env:
RECEIPT_OK: ${{ needs.receipt-judge.outputs.ok || '0' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FAT_VARS_JSON: ${{ toJSON(vars) }}
steps:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/guards-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ jobs:
# ─────────────────────────────────────────────────────────────────────
- name: "Test-tier decision case table (BSE-17): quick/full/reuse, drift is ENV"
run: bash scripts/ci_test_tier.sh --self-test
- name: Receipt gate case table and mutants (#5797, LAB)
run: setsid --wait bash scripts/check_receipt_gate.sh
- name: Fleet-cells gate case table and mutants (#5064, LAB)
run: setsid --wait bash scripts/release/fleet_cells_gate.sh --self-test
- name: compute row zero-tests case table and mutants (#5048, LAB)
Expand Down
21 changes: 19 additions & 2 deletions ci/sections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,26 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
MG_BASE_SHA: ${{ github.event.merge_group.base_sha }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
set -euo pipefail
# #5850: every helper below runs with a SCRATCH GITHUB_OUTPUT/GITHUB_ENV; only the last line of this step writes
# the real file, so no helper can plant tier=/cite= lines or a heredoc in front of ours.
real_out="$GITHUB_OUTPUT"
GITHUB_OUTPUT="$(mktemp)"; GITHUB_ENV="$(mktemp)"; export GITHUB_OUTPUT GITHUB_ENV
# #5850: a PR rust-toolchain.toml `path=` would make `cargo metadata` (gate_touched_crates.sh) run PR code before the final write; the env var outranks the file.
RUSTUP_TOOLCHAIN=1.93.0; export RUSTUP_TOOLCHAIN
args=(--event "${GITHUB_EVENT_NAME}")
# #5797: a signed batch receipt in the PR body (signature, tree hash == this
# merge tree, toolchain hash) lets the PR run check/fmt/clippy instead of the
# suite. The verdict is NOT computed here: the `receipt-judge` job in ci.yml
# computes it in a job that never checks out or runs the PR tree (it checks out
# the base, reads the PR merge commit as data), and the shard job hands it in as
# RECEIPT_OK. Anything but a literal 1 -- unset, 0, a skipped or failed judge -- is
# 0, and 0 leaves the tier exactly as it was. Only a pull_request can carry one.
rok=0
if [ "${GITHUB_EVENT_NAME}" = pull_request ] && [ "${RECEIPT_OK:-0}" = 1 ]; then rok=1; fi
args+=(--receipt-ok "${rok:-0}")
# PMAT-1098 67-E2: the queue and a push to main re-derive their own
# diff from HEAD's FIRST PARENT (HEAD^1..HEAD is the PR's diff on the
# new base). actions/checkout is shallow, so that parent is not in the
Expand Down Expand Up @@ -439,7 +456,7 @@ jobs:
;;
esac
bash scripts/ci_test_tier.sh "${args[@]}" | tee "$RUNNER_TEMP/tier.txt"
grep -E '^(tier|crates|targets|check_workspace|reason|cite)=' "$RUNNER_TEMP/tier.txt" >> "$GITHUB_OUTPUT"
grep -E '^(tier|crates|targets|check_workspace|reason|cite)=' "$RUNNER_TEMP/tier.txt" >> "$real_out"
# #4502 row 2: lint_passes_on_real_contracts (aprender-contracts) requires the
# refinement gate to RUN whenever CI is set, and that gate compares HEAD with
# merge-base(HEAD, origin/main), else the origin/main tip. This section clones at
Expand Down Expand Up @@ -1075,7 +1092,7 @@ jobs:
python3 scripts/ci/sigma_executed.py nextest --kind "quick tree readers" --junit "$sig/quick-tree.junit.xml" --list-json "$sig/quick-tree.list.json" || rc=1
exit "$rc"
- name: "Quick tier: cargo check --workspace (over-the-cap integration, BSE-17 rule (i))"
if: steps.tier.outputs.tier == 'quick' && steps.tier.outputs.check_workspace == '1' && matrix.shard == matrix.shards
if: ((steps.tier.outputs.tier == 'quick' && steps.tier.outputs.check_workspace == '1') || (steps.tier.outputs.tier == 'reuse' && steps.tier.outputs.cite == 'receipt')) && matrix.shard == matrix.shards
timeout-minutes: 20
env:
REASON: ${{ steps.tier.outputs.reason }}
Expand Down
3 changes: 2 additions & 1 deletion crates/aprender-core/tests/monorepo_invariants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,9 @@ fn draft_gate_canon() -> Vec<(&'static str, String)> {
("determinism", "${{ !cancelled() && needs.mg-reuse.outputs.det != '1' && github.event_name != 'pull_request' }}".into()),
// merge_group-only: a draft never reaches the queue, so there is nothing to skip.
("mg-reuse-wt", "github.event_name == 'merge_group'".into()),
("receipt-judge", "github.event_name == 'pull_request' && vars.RECEIPT_JUDGE_RUNNER_READY == 'true'".into()),
("workspace-test-shard", format!("${{{{ !cancelled() && needs.mg-reuse-wt.outputs.wt != '1' && {DF} }}}}")),
("workspace-test-ran", format!("${{{{ !cancelled() && needs.workspace-test-shard.result == 'success' && github.event_name == 'pull_request' && {DF} }}}}")),
("workspace-test-ran", format!("${{{{ !cancelled() && needs.workspace-test-shard.result == 'success' && needs.receipt-judge.outputs.ok != '1' && github.event_name == 'pull_request' && {DF} }}}}")),
("workspace-test", "always()".into()),
("ci-gate", "always()".into()),
("gate", "always()".into()),
Expand Down
18 changes: 18 additions & 0 deletions docs/roadmaps/entries/PMAT-5797.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
- id: PMAT-5797
github_issue: 5797
item_type: task
title: 'PR gate: signed batch receipt verify (sig, tree, toolchain) as tier=reuse extension'
status: planned
priority: high
assigned_to: null
created: 2026-10-20T14:55:28Z
updated: 2026-10-20T14:55:28Z
spec: null
acceptance_criteria: []
phases: []
subtasks: []
estimated_effort: null
labels:
- kind:code
notes: null
epic: 5510
18 changes: 18 additions & 0 deletions docs/roadmaps/roadmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25340,6 +25340,24 @@ Not done, pending the ruling: moving the 31 fixture files to an obviously synthe
- kind:code
notes: null
epic: 5510
- id: PMAT-5797
github_issue: 5797
item_type: task
title: 'PR gate: signed batch receipt verify (sig, tree, toolchain) as tier=reuse extension'
status: planned
priority: high
assigned_to: null
created: 2026-10-20T14:55:28Z
updated: 2026-10-20T14:55:28Z
spec: null
acceptance_criteria: []
phases: []
subtasks: []
estimated_effort: null
labels:
- kind:code
notes: null
epic: 5510
- id: PMAT-5792
github_issue: 5792
item_type: task
Expand Down
Loading
Loading