ci(fleet): workspace-test runs on any clean-room box — gx10 measured 3–4× faster than intel; four aarch64-only reds fixed; tree-reader step builds 20 packages, not 686 binaries (PMAT-3138) - #3139
Conversation
…3-4x faster than intel; four aarch64-only reds fixed; tree-reader step builds 20 packages, not 686 binaries (PMAT-3138) Measured on gx10 (GB10, 20 cores) with ci.yml's own image and env, train #3127 tree a6148ab, --no-fail-fast (issue #3138 has the table): the quick tier's step 1 took 10.6 min against intel's 34.5, step 2 6.7 against 27.4, the over-the-cap cargo check 84 s. Test execution alone is 3-4x faster. gx10 read 0 % busy all morning because every long job pinned X64. aarch64-only reds, classified and fixed here: - crates/aprender-serve/examples/bench_simd_dot.rs: #[target_feature(avx2, fma)] unguarded -> cargo check --all-targets RED. x86 assumption: the kernels live in a target_arch = "x86_64" module; other targets get a main that says so (G3.EX still runs it, rc 0 on gx10). - blis::parallel::gemm_blis_parallel_shared_b: CODE DEFECT. The AVX-512 guard existed only under cfg(x86_64) and the microkernel call in the tile loop is cfg(x86_64) inside an if with no other arm, so on aarch64 every full 8x32 tile was silently skipped and only edge tiles were computed: max diff 39.2 against the reference at 256^3 (100x96 passed only under the 8M-flop small-path cut). Non-x86 now takes the plain BLIS path like a no-AVX-512 x86 box, and the tile loop's scalar arm covers a full tile wherever the microkernel is absent. Not on any inference path (only the blis_benchmark example calls it). The 175-line function is decomposed (path guard, thread count, SharedBBlock::{run_slice,run_panels,tile, scalar_tile}) -- the complexity gate blocks any edit to it otherwise; 304/304 blis tests on an AVX-512 box, 4/4 on gx10. - falsification_tests A-013 (NEON >= 2x scalar): a wall-clock ratio, live only on aarch64 and 0.87x there because LLVM autovectorises the "scalar" baseline. Placement, not a threshold: behind a new bench-gates feature (never in a required check, check_no_timing_in_required.sh). - fma_correctness_f017 F022: tolerance 1e-5 encoded >= 8 accumulators. Bound derived from the accumulation model, n*eps/(2k) with k = 4 (NEON f32x4) = 7.5e-5 -> 1e-4; a scalar sequential sum (~3e-4) still fails. Pareto, both arches: the tree-reader step ran --workspace --lib --tests and so linked 686 test binaries to run 41 (run 34680214617 attempt 1: 421 crates compiled after step 1's 703, 27.4 min for 17 min of tests). It now builds only the packages the targets name: 102 targets -> 20 -p. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r aarch64 classifications, RED→GREEN per fix (PMAT-3138)
|
§13.11 rung 1 — quorum shadow verdict Shadow mode: this records a verdict and merges nothing. A refusal |
|
CI run 34685512513 cancelled on purpose: its |
… comparison cites them (PERF-010, check_perf_claims_cite_receipts)
…s the bottleneck, gx10 is 2.3x faster and half idle One append-only JSON per (sha, host, job) from the Actions REST API: queue_wait_s (created->started), exec_s, total_s, host, conclusion. peak_rss_mb and free_disk_gb are null with an explicit "[U]" in unmeasured[]: the REST API does not expose them, and an absent measurement must never read as a zero. What the 182 records say (p50 / p95 exec_s, this repo, 2026-09-12): workspace-test intel 1790 / 4148 s gx10 790 / 790 s yoga 259 / 3167 s guard-cargo intel 1201 / 1820 s gx10 422 / 516 s yoga 830 / 1046 s guard-tree intel 604 / 879 s gx10 192 / 213 s yoga 379 / 379 s queue wait p95 intel 2995 s gx10 233 s yoga 1654 s Per-run required-check wall clock, grouped by which boxes the run touched: gx10 only n=4 mean 9.4 min gx10 + yoga n=4 mean 11.3 min gx10 + intel n=10 mean 42.6 min gx10 + intel + yoga n=11 mean 31.6 min Every run that touched intel cost 32-43 min; no run that avoided it cost more than 11.3. intel took 15 of the 22 workspace-test records because that job is pinned to X64 -- and it is the job whose p95 is 69 minutes. #3139 unpins it. §1 coupling, no longer [U]: p95 gate = 72.3 min, so max PRs per train = 72h / 72.3 min = 59.7. §8's "stop cutting trains below 10" does not fire. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Dequeued from the 0.67.0 merge queue, moved to 0.68.0. Why. This PR's merge-group CI was RED on The remedy is in the guard's own header, and it is mechanical: git fetch origin main && git rebase origin/main # or merge
python3 scripts/roadmap_trim.py # or: roadmap_diff.py trim
bash scripts/check_roadmap_diff_additive.sh # must exit 0 before re-arming
A second finding, worth its own ticket. Not a judgement on the change itself. APR-RELEASE-001 §4: scope is assigned to a train after the fact — 0.67.0 contains whatever merged before its cut. This is on the post-tag re-arm list; nothing else is required of it beyond the trim above. |
…t in 0.67.0 Verified every `#NNNN` in the 0.67.0 section against `git log v0.66.0..origin/main` and against each PR's state. Four rows were false: #3068 OPEN — dequeued from the merge queue; guard-tree RED on check_roadmap_diff_additive.sh. Moved to 0.68.0. #3139 OPEN — same guard, same cause. Moved to 0.68.0. #3064 MERGED 2026-09-09T22:20Z — its merge commit is an ANCESTOR OF v0.66.0. It shipped in the previous release; listing it here bills it twice. #3065 MERGED 2026-09-09T18:00Z — likewise an ancestor of v0.66.0. The last two are the more interesting defect: "merged after the last CHANGELOG entry" is not the same predicate as "merged after the last tag", and only the second one is true of a release. `git merge-base --is-ancestor <merge-sha> v0.66.0` answers it and is what was run here. A release note that lists work the release does not contain is a false record, and it is the kind that survives because nobody re-derives it. The scope rule is APR-RELEASE-001 §4: a train contains whatever merged before its cut, by definition -- so the fix is to shrink the list, never to hold the train for it. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Measured from the 0.67.0 train session (2026-09-12, no SSH):
|
… GPU hosts, cuda-nightly standing-RED since the v0.66.0 sha, why gx10 idles (X64 pin, #3139 795 s, ENOSPC), §6 triage to untriaged=0, one-at-a-time drain [skip ci] Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Two updates from the train session:
|
…d, which made every merge-group build of this PR red by construction `check_roadmap_diff_additive.sh` failed on this PR's group with `deleted: 2 base id(s) missing at head: PMAT-1090, PMAT-3186`. Both landed on main after this branch forked, and each plain update of the branch resolved `docs/roadmaps/roadmap.yaml` by taking one side whole instead of the union, so the PR that lifts the `workspace-test` X64 pin could not get through the queue — the single change that lets the 60-minute job run on gx10 (795 s there against 1,000-6,000 s on intel). Resolution: `docs/roadmaps/roadmap.yaml` is main's file plus this branch's own new entry, PMAT-3138, inserted after PMAT-3124 exactly where it sits in the branch. No other file conflicted. Guards, all re-run after the resolve: check_roadmap_sorted.sh PASS 848 ids, sorted within each prefix, no dups check_roadmap_ids_unique.sh PASS 848 ids, all unique check_roadmap_diff_additive.sh PASS added=3 lifecycle=0 reserialised=0 deleted=0 Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Pushed a merge of Its merge-group builds were failing on one guard: Both ids landed on main after this branch forked, and every plain branch update resolved The resolve is main's roadmap plus this branch's own new entry,
Why this one matters more than its diff suggests: it lifts the Auto-merge is armed. |
check_roadmap_diff_additive.sh reported base id(s) missing at head: this branch forked before they landed on main, and a plain update takes one side of the 847-entry file whole. Resolved as main's roadmap plus this branch's own new entries. The other three roadmap guards pass on the result. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* release: 0.67.0 bump-version.sh 0.67.0 (every workspace, facades included; --check green) and the CHANGELOG [0.67.0] section, per docs/specifications/06x-release-schedule.md §4.2. After this merges, rel-067-autopilot runs §4.3-4.8: pre-publish dogfood, tag, release, the sixteen assets by command, cascade, host receipts, close. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): 0.67.0 CHANGELOG — paiml#3046 left the merge queue (guard-tree: roadmap diff not additive on its group) and cannot precede the cut; it ships in 0.68 Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(release): the 0.67.0 CHANGELOG claimed four changes that are not in 0.67.0 Verified every `#NNNN` in the 0.67.0 section against `git log v0.66.0..origin/main` and against each PR's state. Four rows were false: paiml#3068 OPEN — dequeued from the merge queue; guard-tree RED on check_roadmap_diff_additive.sh. Moved to 0.68.0. paiml#3139 OPEN — same guard, same cause. Moved to 0.68.0. paiml#3064 MERGED 2026-09-09T22:20Z — its merge commit is an ANCESTOR OF v0.66.0. It shipped in the previous release; listing it here bills it twice. paiml#3065 MERGED 2026-09-09T18:00Z — likewise an ancestor of v0.66.0. The last two are the more interesting defect: "merged after the last CHANGELOG entry" is not the same predicate as "merged after the last tag", and only the second one is true of a release. `git merge-base --is-ancestor <merge-sha> v0.66.0` answers it and is what was run here. A release note that lists work the release does not contain is a false record, and it is the kind that survives because nobody re-derives it. The scope rule is APR-RELEASE-001 §4: a train contains whatever merged before its cut, by definition -- so the fix is to shrink the list, never to hold the train for it. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): drop the 0.67.0 "### Added" heading left empty by the four false rows A section heading with no rows under it reads as "nothing was added" only if you notice the heading is empty; more often it reads as a rendering bug. Removing the heading says the same thing without the ambiguity. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): revert the CHANGELOG heading sweep — it deleted 31 headings across eight years of history The previous commit removed every "### " heading with no "- " bullet under it. Thirty of the thirty-one it matched were historical sections whose content is PROSE, not bullets: "### Migration Guide", "### Quality Metrics", "### TOP 10 Algorithms - Complete List". A heading with no bullets is not an empty heading. This reverts it and removes exactly one heading: the 0.67.0 "### Added", which is followed immediately by the next heading with nothing at all between them. The predicate is now "nothing before the next heading", not "no bullets", and it is scoped to the 0.67.0 section. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(release): the 0.67.0 CHANGELOG missed four PRs merged after the v0.66.0 tag — the CUDA-asset rebuild rows (paiml#3072, paiml#3074, paiml#3086) and the PMAT-1096 receipt (paiml#3085) T-0 rule: CHANGELOG from merged PR titles since the last tag. Predicate: `git log v0.66.0..origin/main` titles minus CHANGELOG rows = 4 → now 0. Each merge commit is NOT an ancestor of v0.66.0 (`git merge-base --is-ancestor` rc=1 for 2c584a1 43b8d8e 58c3dda a4b27f3). Rows appended to ### Changed; narrative gains one sentence on the glibc 2.31 floor. Headings 224 → 224; 0.67.0 rows 27 → 31. release_notes.md carries the same four rows. Pmat-Ticket: PMAT-1098 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o of every three queue builds were RED by construction (paiml#3186) (paiml#3187) GitHub builds queue entry N as a squash on top of entry N-1's squash, so at position >= 2 the head has ONE parent that is not the origin/main tip and, at fetch-depth 1, is not fetched. Every rule in resolve_base refused that shape (exit 2 -> guard-tree FAIL), so with max_entries_to_build=3 the second and third entries of every stacked build were RED on this resolver alone: runs 34704287677 (paiml#3139) and 34704288441 (paiml#3046), 2026-09-12, each after passing 82,085 workspace tests on gx10. Four PRs were dequeued today on it. Under GITHUB_EVENT_NAME=merge_group the resolver now deepens the shallow checkout by one commit (git fetch --deepen=1 origin, else fetch the parent by sha) and names that parent as the base — exactly this entry's own diff. A push-shape depth-1 head stays refused (never the tree against itself); ROADMAP_DIFF_NO_DEEPEN=1 is the mutation. Case table (check_roadmap_diff_additive.sh --self-test): rows 19-20 added — a self-contained repo c1 -> c2 -> c3 with origin/main := c1 fetched by name into a depth-1 clone (a shallow clone cannot update-ref to an object it lacks; the fixture fetches the tip the way the job does). Row 19 resolves to c2 under merge_group; row 20 is refused by name with deepening disabled. Mutation measured: with origin/main's resolver restored, row 19 goes RED. 20/20 rows; bashrs 0 errors on both files (guard: 0 -> 0, lib: 0 -> 0). Every consumer of the lib benefits: check_hardcoded_paths.sh (its ratchet also read "origin/main tip" as the base for stacked entries), check_no_fabricated_baselines.sh, check_dogfood_coverage.sh, check_row_pr_write_set.sh. Refs paiml#3186, paiml#3177, APR-RELEASE-001 §3.4/§5 P0·Pack (packing rule, operator 2026-09-12). Pmat-Ticket: PMAT-3186 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Closes #3138 (PMAT-3138). Follow-up to train #3127 (#3104 made seven jobs arch-neutral; this makes the long pole one of them).
Why gx10 sat at 0 %
Every long job pinned
X64. gx10's threeclean-roompools took ~5 arch-neutral jobs × 5 min per PR run and idled for the remaining hour while intel queued.Measured (gx10, GB10 20 cores,
localhost:5000/sovereign-ci:stable, ci.yml's env,--no-fail-fast)cargo check --workspace --all-targets --locked--lib(82,085 tests) + GPU crates per-package + compute libTest execution is 3–4× faster on the idle box; the intel figure is the 16-runners-on-32-cores contention the fleet is provisioned for.
The four aarch64-only reds, classified
aprender-serve/examples/bench_simd_dot.rs—#[target_feature(enable = "avx2", enable = "fma")]unguardedtarget_arch = "x86_64"module; other targets get amainthat says so (G3.EX still runs it, rc 0 on gx10)blis::tests::validate_and_parallel::test_gemm_parallel_shared_b_256— max diff 39.2cfg(x86_64)-only and the microkernel call sits in acfg(x86_64)ifwith no other arm, so every full 8×32 tile was silently skipped on aarch64. Non-x86 takes the plain BLIS path; the tile loop's scalar arm now covers a full tile wherever the microkernel is absent. Decomposed under the complexity gate (SharedBBlock). Not on any inference path. 304/304 blis tests on an AVX-512 box, 4/4 on gx10falsification_tests::section_a::test_a013_neon_speedup— 0.87×bench-gatesfeature (never a required check)fma_correctness_f017::f022_fma_dot_product_accuracy— 1.9e-5 > 1e-5n·eps/(2k), k = 4 → 1e-4; a scalar sequential sum (~3e-4) still failsPareto, both arches
The tree-reader step ran
--workspace --lib --testsand linked 686 test binaries to run 41 (421 crates compiled after step 1's 703; 27.4 min for 17 min of tests). It now builds only the packages the targets name: 102 targets → 20-p.Routing
workspace-test→[self-hosted, Linux, clean-room].pr-review-receiptkeepsX64(#3132). Guards:check_runner_labels.sh,check_no_timing_in_required.shgreen.🤖 Generated with Claude Code