Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
370d285
fix(present-yaml): 34 example tests read a path nothing has lived at …
noahgift Sep 14, 2026
8098cee
fix(cgp): six wall-clock assertions, three of them in the REQUIRED check
noahgift Sep 14, 2026
f18e257
fix(distribute): tokio behind an optional feature, used unconditional…
noahgift Sep 14, 2026
39dc1da
Merge branch 'main' into PMAT-1098-cgp-timing-gate
noahgift Sep 14, 2026
14c1b5b
fix(zram): the cuda feature says why it cannot build, instead of a ca…
noahgift Sep 14, 2026
9cab1fc
fix(guard): the roadmap guard counted agy lane scratch as a second co…
noahgift Sep 14, 2026
b31a2c2
fix(nightly): guards-nightly has been RED naming a step that runs eve…
noahgift Sep 14, 2026
cb06a6c
fix(examples): an example built WITHOUT its feature is not a broken e…
noahgift Sep 14, 2026
359d0c5
fix(silicon): a vanished dep-info file was reported as a SIMD failure…
noahgift Sep 14, 2026
0ffce33
Merge remote-tracking branch 'origin/main' into PMAT-3235-needs-feature
noahgift Sep 14, 2026
dd9948a
fix(zram): a same-process ratio is load-immune but NOT instrumentatio…
noahgift Sep 14, 2026
5b313d6
fix(roadmap): collapse my insertion's stray blank line (roadmap_trim.py)
noahgift Sep 14, 2026
106194c
fix(roadmap): collapse my insertion's stray blank line (roadmap_trim.py)
noahgift Sep 14, 2026
534c6fc
fix(roadmap): collapse my insertion's stray blank line (roadmap_trim.py)
noahgift Sep 14, 2026
215c286
Merge remote-tracking branch 'origin/main' into PMAT-3234-nightly-man…
noahgift Sep 14, 2026
fcfe0ed
Merge remote-tracking branch 'origin/main' into PMAT-3236-silicon-env…
noahgift Sep 14, 2026
2997888
batch: #3250 (PMAT-1098-present-yaml-example-paths)
noahgift Sep 15, 2026
b36942c
batch: #3253 (PMAT-1098-cgp-timing-gate)
noahgift Sep 15, 2026
de99339
batch: #3257 (PMAT-1098-distribute-no-default-features)
noahgift Sep 15, 2026
c7135fa
batch: #3267 (PMAT-1098-zram-cuda)
noahgift Sep 15, 2026
f99c772
batch: #3272 (PMAT-3226-lane-scratch-universe)
noahgift Sep 15, 2026
c66b297
batch: #3285 (PMAT-3234-nightly-manifest)
noahgift Sep 15, 2026
e463578
batch: #3288 (PMAT-3235-needs-feature)
noahgift Sep 15, 2026
4dd2088
batch: #3289 (PMAT-3236-silicon-env-claim)
noahgift Sep 15, 2026
bc883bd
batch: #3290 (PMAT-3237-zram-timing)
noahgift Sep 15, 2026
87703a8
batch-1: collapse the 9-way roadmap re-serialisation (roadmap_trim.py)
noahgift Sep 15, 2026
92bc80e
batch-1: PMAT-3226 to its sorted slot — a textual merge cannot insert…
noahgift Sep 15, 2026
3239492
Merge remote-tracking branch 'origin/main' into PMAT-3231-batch-1-ci-…
noahgift Sep 15, 2026
1a8e27f
Merge branch 'main' into PMAT-3231-batch-1-ci-guards
noahgift Sep 15, 2026
735347b
Merge remote-tracking branch 'origin/main' into PMAT-3231-batch-1-ci-…
noahgift Sep 15, 2026
6a6205b
Merge branch 'main' into PMAT-3231-batch-1-ci-guards
noahgift Sep 15, 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
32 changes: 15 additions & 17 deletions .github/workflows/guards-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,22 @@ jobs:
# names a step; each must appear VERBATIM as a `- name:` in this file.
# Fail-closed: an empty manifest, a missing file or an unreadable line is
# a failure, never a pass.
# EXTRACTED to scripts/check_guards_nightly_manifest.sh (PMAT-3234). The
# inline version matched `grep -Fq -- "- name: $name"` — the BARE spelling —
# while a step name containing a colon-space must be QUOTED in YAML, and one
# of them is. So the matcher looked for `- name: Test-tier...` and the file
# said `- name: "Test-tier...`, and this lane went RED naming a step that
# runs on every nightly as one the workflow does not run.
#
# Logic that lives in a `run:` block cannot be unit-tested and cannot carry a
# case table; that is why the defect survived. The script matches on the
# PARSED name, so all three YAML quotings of one string are one step, and it
# ships 7 rows in both directions (a genuinely absent step still fails, and a
# manifest that parsed almost nothing is refused rather than passed).
- name: Manifest-vs-workflow case table (PMAT-3234, both directions)
run: bash scripts/check_guards_nightly_manifest.sh --self-test
- name: Every step the manifest says moved here must exist here
run: |
set -euo pipefail
manifest=scripts/guards_nightly_manifest.txt
[ -s "$manifest" ] || { echo "FAIL: $manifest missing or empty"; exit 1; }
n=0; bad=0
while IFS=$'\t' read -r secs name; do
case "${secs:-}" in ''|'#'*) continue ;; esac
[ -n "${name:-}" ] || { echo "FAIL: manifest line has no step name: $secs"; bad=1; continue; }
n=$((n + 1))
if ! grep -Fq -- "- name: $name" .github/workflows/guards-nightly.yml; then
echo "FAIL: manifest names a step this workflow does not run: $name"
bad=1
fi
done < <(grep -vE '^[[:space:]]*(#|$)' "$manifest")
[ "$n" -ge 5 ] || { echo "FAIL (vacuity): only $n manifest entries parsed"; exit 1; }
[ "$bad" -eq 0 ] || exit 1
echo "ok $n manifest entries, every one a step in this workflow"
run: bash scripts/check_guards_nightly_manifest.sh
# THE COMPARAND, FETCHED ONCE, BEFORE ANY GUARD THAT NEEDS IT -- the
# SATD step below measures its ceiling on origin/main with the HEAD-built
# suite, and a depth-1 checkout has no such ref until this runs.
Expand Down
16 changes: 12 additions & 4 deletions .github/workflows/silicon-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ jobs:
timeout-minutes: 90
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: cargo_step.sh falsifier (ENV-vs-CODE instrument)
run: bash scripts/cargo_step.sh --self-test
- name: Put the runner's Rust toolchain on PATH
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# THE ARCH-SENSITIVE SUBSET, not the whole suite. Five legs of a full
Expand All @@ -109,7 +111,8 @@ jobs:
- name: SIMD and numeric paths (x86_64, widest vectors)
run: |
set -euo pipefail
nice -n 19 cargo test -p aprender-compute --release --lib
bash scripts/cargo_step.sh 'x86_64 SIMD: aprender-compute' -- \
nice -n 19 cargo test -p aprender-compute --release --lib
# `aprender-primitives` does not exist and never has. It was invented by
# this file (#2772) and killed BOTH legs with `package ID specification
# ... did not match any packages`, exit 101, every night since
Expand All @@ -118,7 +121,8 @@ jobs:
# (10 files with target_arch/target_feature, after aprender-compute's
# 110). scripts/check_workflow_cargo_packages.sh makes the class
# unrepeatable. YOGA-NIGHTLY-001 R-8.
nice -n 19 cargo test -p aprender-core --release --lib
bash scripts/cargo_step.sh 'x86_64 SIMD: aprender-core' -- \
nice -n 19 cargo test -p aprender-core --release --lib

aarch64-cuda-sm121:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.axis == 'all' || inputs.axis == 'aarch64-cuda-sm121' }}
Expand All @@ -138,6 +142,8 @@ jobs:
timeout-minutes: 90
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: cargo_step.sh falsifier (ENV-vs-CODE instrument)
run: bash scripts/cargo_step.sh --self-test
- name: Put the runner's Rust toolchain on PATH
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# ASK THE BOX, NEVER THE LABEL. A label says what we intended; nvidia-smi
Expand All @@ -163,7 +169,8 @@ jobs:
- name: NEON and numeric paths (aarch64)
run: |
set -euo pipefail
nice -n 19 cargo test -p aprender-compute --release --lib
bash scripts/cargo_step.sh 'aarch64 SIMD: aprender-compute' -- \
nice -n 19 cargo test -p aprender-compute --release --lib
# `aprender-primitives` does not exist and never has. It was invented by
# this file (#2772) and killed BOTH legs with `package ID specification
# ... did not match any packages`, exit 101, every night since
Expand All @@ -172,7 +179,8 @@ jobs:
# (10 files with target_arch/target_feature, after aprender-compute's
# 110). scripts/check_workflow_cargo_packages.sh makes the class
# unrepeatable. YOGA-NIGHTLY-001 R-8.
nice -n 19 cargo test -p aprender-core --release --lib
bash scripts/cargo_step.sh 'aarch64 SIMD: aprender-core' -- \
nice -n 19 cargo test -p aprender-core --release --lib

# AN AXIS NAMED `cuda` MUST INVOKE CUDA (YOGA-NIGHTLY-001 R-6).
#
Expand Down
24 changes: 24 additions & 0 deletions crates/aprender-cgp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ trueno-gpu = { path = "../aprender-gpu", version = "0.67.0", features = ["cuda"]
[features]
default = []
cuda = ["dep:trueno-gpu"]
# A DURATION ASSERTION IS NOT A CORRECTNESS ASSERTION (#3239, and this repo has
# paid for it eleven times — see scripts/check_no_timing_in_required.sh, whose
# registry exists because "policy is what failed the other eleven times").
#
# tests/falsify.rs carries two: FALSIFY-CGP-061 (`cgp doctor` < 2 s) and
# FALSIFY-CGP-060 (`cgp profile compare` < 30 s). Both are real product limits
# and neither can be asserted on a shared CI box. Measured 2026-09-14 during a
# full --lib --tests sweep of the workspace:
#
# FALSIFY-CGP-061 FAILED: doctor took 2665ms (limit 2500, over by 6.6%)
#
# The box was running 98,621 tests in parallel. That number measures the LOAD,
# not `cgp doctor`. Raising the limit is the "clever ratio rewrite" that once
# blocked all nine open PRs; the fix is to stop asserting duration where
# duration cannot be measured.
#
# check_no_timing_in_required.sh keeps exactly this rule for shell guards, with
# a declared registry so "adding a timing gate without deciding its placement is
# impossible". This feature is that registry for Rust targets: nothing enables
# it, so a timing row cannot reach a required check by accident.
#
# Arm it where duration IS measurable -- a dedicated, unloaded runner (perf-solo),
# at release time. Not in CI's default set, and not in the nightly full surface.
timing-gate = []

[dev-dependencies]
proptest = "1.9"
Expand Down
4 changes: 4 additions & 0 deletions crates/aprender-cgp/src/analysis/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,14 @@ mod tests {
}
let elapsed = start.elapsed();
// 100 diffs should take << 100ms
// DURATION ONLY UNDER `timing-gate` (#3239) — see this crate's Cargo.toml.
#[cfg(feature = "timing-gate")]
assert!(
elapsed.as_millis() < 100,
"100 diffs took {}ms",
elapsed.as_millis()
);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;
}
}
5 changes: 5 additions & 0 deletions crates/aprender-cgp/src/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,11 @@ mod tests {
let _ = detect_gpu();
let _ = check_binary("nonexistent", &[], parse_generic_version);
let elapsed = start.elapsed();
// DURATION ONLY UNDER `timing-gate` (#3239). A shared, saturated runner
// cannot measure elapsed time; see this crate's Cargo.toml.
#[cfg(feature = "timing-gate")]
assert!(elapsed.as_secs() < 2, "doctor checks took {:?}", elapsed);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;
}
}
4 changes: 4 additions & 0 deletions crates/aprender-cgp/src/metrics/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ mod tests {
let _ = load_json(&path).unwrap();
let _ = load_json(&path).unwrap();
let elapsed = start.elapsed();
// DURATION ONLY UNDER `timing-gate` (#3239) — see this crate's Cargo.toml.
#[cfg(feature = "timing-gate")]
assert!(
elapsed.as_millis() < 100,
"Loading two JSONs took {}ms (should be <100ms)",
elapsed.as_millis()
);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;
}
}
43 changes: 39 additions & 4 deletions crates/aprender-cgp/tests/falsify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,16 +447,45 @@ fn falsify_cgp_061_doctor_speed_real() {
let elapsed = start.elapsed();

assert!(output.status.success());
// Allow 500ms subprocess overhead on top of the 2s spec limit

// DURATION ONLY UNDER `timing-gate`. Measured 2026-09-14 on a box running
// 98,621 tests in parallel: 2665 ms against this 2500 ms limit -- a 6.6%
// miss that says nothing about `cgp doctor` and everything about the load.
// See this crate's Cargo.toml for why the feature exists.
#[cfg(feature = "timing-gate")]
assert!(
elapsed.as_millis() < 2500,
"FALSIFY-CGP-061 FAILED: doctor took {}ms",
elapsed.as_millis()
);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;

let stdout = String::from_utf8_lossy(&output.stdout);
// Verify it detected the GPU
assert!(stdout.contains("RTX 4090") || stdout.contains("GPU"));
// THE STATUS MUST BE DECIDED -- not that this box has a 4090.
// `contains("RTX 4090") || contains("GPU")` asserts the RUNNER's hardware,
// the class fixed in #3210 across four sibling rows. It passes here only
// because this box happens to have one. What CGP-061 actually owes is that
// `doctor` reached a verdict about the device and printed it.
assert!(
!stdout.trim().is_empty(),
"FALSIFY-CGP-061 FAILED: doctor printed nothing -- no verdict at all"
);
let decided = [
"GPU",
"CUDA",
"device",
"Device",
"no GPU",
"not available",
"unavailable",
]
.iter()
.any(|k| stdout.contains(k));
assert!(
decided,
"FALSIFY-CGP-061 FAILED: doctor reached no decision about the device.\nstdout: {stdout}"
);
}

// ══════════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -545,12 +574,18 @@ fn falsify_cgp_060_profile_speed() {
let elapsed = start.elapsed();

assert!(output.status.success());
// 30s spec limit + 500ms subprocess overhead

// DURATION ONLY UNDER `timing-gate`, for the same reason as CGP-061 above.
// 30 s is a real product limit and a shared runner cannot measure it; this
// row has simply not been unlucky yet, which is not the same as correct.
#[cfg(feature = "timing-gate")]
assert!(
elapsed.as_secs() < 31,
"FALSIFY-CGP-060 FAILED: profile took {}s (limit: 30s)",
elapsed.as_secs()
);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;
}

// ══════════════════════════════════════════════════════════════════════
Expand Down
4 changes: 4 additions & 0 deletions crates/aprender-cgp/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ fn test_doctor_completes() {
assert!(stdout.contains("cgp System Check"), "Missing header");
assert!(stdout.contains("CPU"), "Missing CPU detection");
// Doctor should complete in <2s (FALSIFY-CGP-061), allow 30s for compilation
// DURATION ONLY UNDER `timing-gate` (#3239) — see this crate's Cargo.toml.
#[cfg(feature = "timing-gate")]
assert!(
elapsed.as_secs() < 30,
"cgp doctor took too long: {:?}",
elapsed
);
#[cfg(not(feature = "timing-gate"))]
let _ = elapsed;
}

/// cgp roofline --target cuda must show RTX 4090 data.
Expand Down
4 changes: 4 additions & 0 deletions crates/aprender-distribute/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
//! This module defines the `Executor` trait and provides implementations
//! for different backends (CPU, GPU, Remote).

// `cpu` is the only executor module that was NOT feature-gated, and it is the
// one that needs tokio (`tokio::process::Command`, `AsyncReadExt`, `timeout`).
// Its five siblings below are all gated; this makes it consistent. #3176.
#[cfg(feature = "tokio")]
pub mod cpu;

#[cfg(feature = "gpu")]
Expand Down
32 changes: 32 additions & 0 deletions crates/aprender-distribute/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,19 @@ mod generated_contracts;
pub mod checkpoint;
pub mod error;
pub mod executor;
// TOKIO, NOT `cpu`. #3176 proposed `#[cfg(feature = "cpu")]` and the intent is
// right — gate the modules, do NOT make tokio a hard dependency — but `cpu` is
// only one of SIX features that pull tokio in: `cpu`, `remote`, `checkpoint`,
// `tui`, `serverless`, `microvm`. Gating on `cpu` would leave
// `--no-default-features --features remote` with tokio present and the modules
// that need it compiled out, which trades one broken configuration for another.
//
// Cargo creates an implicit `tokio` feature for the optional dependency, and it
// is true exactly when some feature brought tokio in. That is the predicate the
// code actually depends on.
#[cfg(feature = "tokio")]
pub mod messaging;
#[cfg(feature = "tokio")]
pub mod scheduler;
#[cfg(feature = "serverless")]
pub mod serverless;
Expand All @@ -90,16 +102,33 @@ pub mod task;
pub mod tensor;
// tui module removed — was ratatui-only

// Only the Pool API uses these, and the Pool API is tokio-gated below.
#[cfg(feature = "tokio")]
use error::{RepartirError, Result};
// `Pool` is the crate's high-level API and it is async to its core --
// tokio::sync::RwLock, tokio::task::JoinSet, tokio::time::sleep, and a
// CpuExecutor that spawns processes through tokio. There is no meaningful
// tokio-free Pool to preserve, so the whole API surface is gated with the
// runtime it requires rather than half-gated into something that compiles and
// cannot run. #3176.
#[cfg(feature = "tokio")]
use executor::cpu::CpuExecutor;
#[cfg(feature = "tokio")]
use executor::Executor;
#[cfg(feature = "tokio")]
use scheduler::Scheduler;
#[cfg(feature = "tokio")]
use std::sync::Arc;
#[cfg(feature = "tokio")]
use task::{ExecutionResult, Task};
#[cfg(feature = "tokio")]
use tokio::sync::RwLock;
#[cfg(feature = "tokio")]
use tokio::task::JoinSet;
#[cfg(feature = "tokio")]
use tracing::{debug, info};

#[cfg(feature = "tokio")]
/// High-level API for distributed task execution.
///
/// The `Pool` manages executors, schedules tasks, and coordinates results.
Expand Down Expand Up @@ -131,6 +160,7 @@ pub struct Pool {
workers: Arc<RwLock<JoinSet<()>>>,
}

#[cfg(feature = "tokio")]
impl Pool {
/// Creates a new pool builder.
#[must_use]
Expand Down Expand Up @@ -182,13 +212,15 @@ impl Pool {
}
}

#[cfg(feature = "tokio")]
/// Builder for `Pool`.
#[derive(Default)]
pub struct PoolBuilder {
cpu_workers: Option<usize>,
max_queue_size: Option<usize>,
}

#[cfg(feature = "tokio")]
impl PoolBuilder {
/// Sets the number of CPU workers.
#[must_use]
Expand Down
Loading
Loading