Merge pull request #4 from bdbrown4/claude/test-wsk42i

This commit is contained in:
2026-07-06 19:40:43 -04:00
committed by GitHub
9 changed files with 190 additions and 6 deletions
+1
View File
@@ -53,6 +53,7 @@ Built so far (command-level, pre-target-integration):
just build / test / lint # trust-layer workspace: cargo build/test/clippy+fmt just build / test / lint # trust-layer workspace: cargo build/test/clippy+fmt
just aa [cmd] # A/A self-test of bench-runner on a shell command just aa [cmd] # A/A self-test of bench-runner on a shell command
just compare <a> <b> # interleaved A/B of two shell commands, bootstrap CI just compare <a> <b> # interleaved A/B of two shell commands, bootstrap CI
just gates <target> # corpus pin + upstream tests + golden replay
just pin-check <target> # verify corpus MANIFEST.sha256 just pin-check <target> # verify corpus MANIFEST.sha256
just calibrate <cmd> <out> # automated A/A + regression-injection calibration just calibrate <cmd> <out> # automated A/A + regression-injection calibration
``` ```
Generated
+1
View File
@@ -183,6 +183,7 @@ name = "diff-test"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap",
"serde", "serde",
"sha2", "sha2",
"thiserror", "thiserror",
+1
View File
@@ -9,6 +9,7 @@ repository.workspace = true
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
serde.workspace = true serde.workspace = true
clap.workspace = true
sha2.workspace = true sha2.workspace = true
thiserror.workspace = true thiserror.workspace = true
toml.workspace = true toml.workspace = true
+1
View File
@@ -8,6 +8,7 @@
//! declares an explicit FP tolerance). //! declares an explicit FP tolerance).
pub mod pin; pub mod pin;
pub mod target;
pub mod policy; pub mod policy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
+93
View File
@@ -0,0 +1,93 @@
//! Gate orchestration: corpus pin → upstream tests → golden replay.
//! Refuses to run anything if the corpus manifest mismatches (SPEC §3.2).
//! Differential fuzz and sanitizers remain per-attempt manual steps in
//! Phase 1 and are reported as skipped with a reason.
use anyhow::Result;
use clap::Parser;
use diff_test::target::{expected_golden_hash, TargetSpec};
use diff_test::{all_passed, pin, GateLayer, GateOutcome};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::process::{Command, Stdio};
#[derive(Parser)]
#[command(name = "diff-test", about = "hotpath equivalence-gate orchestrator")]
struct Cli {
/// Target name under targets/.
target: String,
/// Repository root (defaults to current directory).
#[arg(long, default_value = ".")]
root: PathBuf,
}
fn sh(root: &PathBuf, cmd: &str) -> Result<std::process::Output> {
Ok(Command::new("sh")
.arg("-c")
.arg(cmd)
.current_dir(root)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()?)
}
fn main() -> Result<()> {
let cli = Cli::parse();
let root = cli.root.canonicalize()?;
let spec = TargetSpec::load(&root, &cli.target)?;
let mut results: Vec<(GateLayer, GateOutcome)> = Vec::new();
// Corpus pin is a precondition, not a gate: mismatch = refuse to run.
let verified = pin::verify_manifest(&root.join(&spec.corpus.manifest), &root.join(&spec.corpus.root))?;
println!("corpus pin: {} files verified against {}", verified, spec.corpus.manifest.display());
print!("upstream tests ... ");
let t = sh(&root, &spec.gates.tests)?;
let tests_outcome = if t.status.success() {
println!("PASS");
GateOutcome::Passed
} else {
println!("FAIL");
GateOutcome::Failed {
detail: String::from_utf8_lossy(&t.stderr).chars().take(2000).collect(),
}
};
results.push((GateLayer::UpstreamTests, tests_outcome));
print!("golden replay ... ");
let golden_cmd = spec.gates.golden.replace("{binary}", &spec.build.binary);
let g = sh(&root, &golden_cmd)?;
let expected = expected_golden_hash(&root.join(&spec.corpus.golden_sha256))?;
let actual = format!("{:x}", Sha256::digest(&g.stdout));
let golden_outcome = if g.status.success() && actual == expected {
println!("PASS (stdout sha256 = pinned golden)");
GateOutcome::Passed
} else {
println!("FAIL");
GateOutcome::Failed {
detail: format!("exit={:?} expected={expected} actual={actual}", g.status.code()),
}
};
results.push((GateLayer::GoldenReplay, golden_outcome));
results.push((
GateLayer::DifferentialFuzz,
GateOutcome::Skipped { reason: "per-attempt manual step in Phase 1 (needs old/new pair)".into() },
));
results.push((
GateLayer::Sanitizers,
GateOutcome::Skipped { reason: "per-attempt manual step in Phase 1 (nightly toolchain)".into() },
));
for (layer, outcome) in &results {
if let GateOutcome::Skipped { reason } = outcome {
println!("{layer:?}: skipped — {reason}");
}
}
if all_passed(&results) {
println!("gates: PASS ({})", cli.target);
Ok(())
} else {
anyhow::bail!("gates: FAIL ({})", cli.target)
}
}
+72
View File
@@ -0,0 +1,72 @@
//! Per-target spec (`targets/<name>/target.toml`). All commands and
//! paths are relative to the repository root; `{binary}` in commands is
//! substituted with the built binary path.
use serde::Deserialize;
use std::path::{Path, PathBuf};
#[derive(Debug, Deserialize)]
pub struct TargetSpec {
pub source: Source,
pub build: Build,
pub gates: Gates,
pub corpus: Corpus,
}
#[derive(Debug, Deserialize)]
pub struct Source {
pub repo: String,
pub commit: String,
pub license: String,
#[serde(default)]
pub submodules: toml::value::Table,
}
#[derive(Debug, Deserialize)]
pub struct Build {
/// Baseline build command, run from repo root.
pub baseline: String,
/// Built binary path, relative to repo root.
pub binary: String,
}
#[derive(Debug, Deserialize)]
pub struct Gates {
/// Upstream test suite command, run from repo root.
pub tests: String,
/// Golden replay command; stdout is hashed. `{binary}` substituted.
pub golden: String,
}
#[derive(Debug, Deserialize)]
pub struct Corpus {
/// sha256sum-format manifest of the corpus inputs.
pub manifest: PathBuf,
/// Directory the manifest's relative paths resolve against.
pub root: PathBuf,
/// File whose last whitespace-delimited-first-field line is the
/// expected sha256 of the golden command's stdout.
pub golden_sha256: PathBuf,
}
impl TargetSpec {
pub fn load(repo_root: &Path, name: &str) -> anyhow::Result<Self> {
let path = repo_root.join("targets").join(name).join("target.toml");
let raw = std::fs::read_to_string(&path)
.map_err(|e| anyhow::anyhow!("cannot read {}: {e}", path.display()))?;
Ok(toml::from_str(&raw)?)
}
}
/// Parse the expected stdout hash out of a GOLDEN.sha256 file
/// (comment lines starting with '#' ignored).
pub fn expected_golden_hash(path: &Path) -> anyhow::Result<String> {
let raw = std::fs::read_to_string(path)?;
raw.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with('#'))
.filter_map(|l| l.split_whitespace().next())
.next_back()
.map(str::to_string)
.ok_or_else(|| anyhow::anyhow!("no hash entry in {}", path.display()))
}
+5
View File
@@ -33,3 +33,8 @@ pin-check target:
calibrate cmd out sessions="20": calibrate cmd out sessions="20":
cargo run -p bench-runner -- --config config/accept.toml calibrate \ cargo run -p bench-runner -- --config config/accept.toml calibrate \
--cmd "{{cmd}}" --sessions {{sessions}} --out "{{out}}" --cmd "{{cmd}}" --sessions {{sessions}} --out "{{out}}"
# Equivalence gates for a target: corpus pin (refuses on mismatch) ->
# upstream tests -> golden replay. Fuzz/sanitizers stay per-attempt.
gates target:
cargo run -p diff-test -- {{target}}
+8 -3
View File
@@ -18,8 +18,8 @@ license = "BSD-2-Clause"
# git clone <submodule repo> workspace/vendor/progit && git -C ... checkout <commit> # git clone <submodule repo> workspace/vendor/progit && git -C ... checkout <commit>
[build] [build]
baseline = "cargo build --release --manifest-path workspace/Cargo.toml" baseline = "cargo build --release --manifest-path targets/comrak/workspace/Cargo.toml"
binary = "workspace/target/release/comrak" binary = "targets/comrak/workspace/target/release/comrak"
[bench] [bench]
# Upstream workload (benches/bench.sh): full Pro Git book through the # Upstream workload (benches/bench.sh): full Pro Git book through the
@@ -28,6 +28,11 @@ command = "cat corpora/comrak/progit.md | {binary} > /dev/null"
workload = "Pro Git book, all translations, 11.0 MB concatenated markdown, single stream" workload = "Pro Git book, all translations, 11.0 MB concatenated markdown, single stream"
[gates] [gates]
tests = "cargo test --release --manifest-path workspace/Cargo.toml" tests = "cargo test --release --manifest-path targets/comrak/workspace/Cargo.toml"
# Golden replay: corpus through the binary, stdout must be byte-identical. # Golden replay: corpus through the binary, stdout must be byte-identical.
golden = "cat corpora/comrak/progit.md | {binary}" golden = "cat corpora/comrak/progit.md | {binary}"
[corpus]
manifest = "corpora/comrak/MANIFEST.sha256"
root = "corpora/comrak"
golden_sha256 = "corpora/comrak/GOLDEN.sha256"
+8 -3
View File
@@ -9,8 +9,8 @@ commit = "fa44e5194060305576514d59b850353643afbfc8" # v14.0.0
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[build] [build]
baseline = "cargo build --release --manifest-path workspace/Cargo.toml" baseline = "cargo build --release --manifest-path targets/tokei/workspace/Cargo.toml"
binary = "workspace/target/release/tokei" binary = "targets/tokei/workspace/target/release/tokei"
[bench] [bench]
# Single rayon thread: measurement first (SPEC conventions); the # Single rayon thread: measurement first (SPEC conventions); the
@@ -19,5 +19,10 @@ command = "RAYON_NUM_THREADS=1 {binary} --sort code corpora/tokei/input > /dev/n
workload = "8 replicas of pinned progit + comrak/src trees, 221 MB, 4360 files, single rayon thread" workload = "8 replicas of pinned progit + comrak/src trees, 221 MB, 4360 files, single rayon thread"
[gates] [gates]
tests = "cargo test --release --manifest-path workspace/Cargo.toml" tests = "cargo test --release --manifest-path targets/tokei/workspace/Cargo.toml"
golden = "RAYON_NUM_THREADS=1 {binary} --sort code corpora/tokei/input" golden = "RAYON_NUM_THREADS=1 {binary} --sort code corpora/tokei/input"
[corpus]
manifest = "corpora/tokei/MANIFEST.sha256"
root = "corpora/tokei/input/copy1"
golden_sha256 = "corpora/tokei/GOLDEN.sha256"