mirror of
https://github.com/bdbrown4/peltier.io.git
synced 2026-11-07 10:58:28 +00:00
Bootstrap hotpath from engineering spec v0.1
Commit the spec and scaffold the system it describes:
- SPEC.md: the full v0.1 engineering spec
- crates/: trust-layer Rust workspace, unit-tested
- bench-runner: interleaved ABAB scheduling with discarded warm-ups,
deterministic bootstrap CIs over the ratio of medians,
CI-lower-bound accept rule, env fingerprinting, and a CLI with
compare + A/A self-test modes (A/A verified passing end-to-end)
- diff-test: gate outcome model, sha256 corpus pin verifier that
refuses on mismatch, per-target equivalence policy parser
(byte-identical default, explicit fp-tolerance opt-in)
- ledger: append-only SQLite attempt schema with UPDATE/DELETE
refused by triggers, anti-double-attempt query
- report: cores-saved and dollars/yr ROI math over speedup CIs,
pricing.toml inputs
- playbook/: classes 1-7 with preconditions, procedure, verification
notes, and known failure modes per class
- agent/: Python package skeleton — six-tool contract and prompting
spine, harness IPC deferred to Phase 1
- config/: accept.toml (2% threshold, 30 runs/side), pricing.toml
- targets/, corpora/, results/calibration/: layout and policy docs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EcKPWQ3MQD4NdEHwar96u2
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
//! Equivalence gates (SPEC §3.2) and corpus hash-pinning.
|
||||
//!
|
||||
//! The gate *sequencing* (upstream tests → golden replay → differential
|
||||
//! fuzz → sanitizers) is orchestrated per-target; this crate owns the
|
||||
//! pieces that must be trustworthy regardless of target: the pin
|
||||
//! verifier that refuses to run on a tampered corpus, and the
|
||||
//! per-target equivalence policy parser (byte-identical unless a target
|
||||
//! declares an explicit FP tolerance).
|
||||
|
||||
pub mod pin;
|
||||
pub mod policy;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Outcome of one gate layer. `Skipped` is only legal where the SPEC
|
||||
/// allows it (e.g. TSan when no concurrency primitives changed) and the
|
||||
/// reason is always recorded.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum GateOutcome {
|
||||
Passed,
|
||||
Failed { detail: String },
|
||||
Skipped { reason: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum GateLayer {
|
||||
UpstreamTests,
|
||||
GoldenReplay,
|
||||
DifferentialFuzz,
|
||||
Sanitizers,
|
||||
}
|
||||
|
||||
/// All layers must pass; any failure is an auto-reject (SPEC §8).
|
||||
pub fn all_passed(results: &[(GateLayer, GateOutcome)]) -> bool {
|
||||
results.iter().all(|(_, o)| {
|
||||
matches!(o, GateOutcome::Passed | GateOutcome::Skipped { .. })
|
||||
}) && results
|
||||
.iter()
|
||||
.any(|(_, o)| matches!(o, GateOutcome::Passed))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn any_failure_rejects() {
|
||||
let results = vec![
|
||||
(GateLayer::UpstreamTests, GateOutcome::Passed),
|
||||
(
|
||||
GateLayer::GoldenReplay,
|
||||
GateOutcome::Failed { detail: "stdout diverged".into() },
|
||||
),
|
||||
];
|
||||
assert!(!all_passed(&results));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_skipped_is_not_a_pass() {
|
||||
let results = vec![(
|
||||
GateLayer::Sanitizers,
|
||||
GateOutcome::Skipped { reason: "n/a".into() },
|
||||
)];
|
||||
assert!(!all_passed(&results));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//! Corpus hash-pinning (SPEC §3.2, §10): corpora live outside
|
||||
//! agent-writable paths and are pinned by a SHA-256 manifest. diff-test
|
||||
//! refuses to run if any hash mismatches — a tampered corpus is a
|
||||
//! stop-the-line event, not a warning.
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum PinError {
|
||||
#[error("io error reading {path}: {source}")]
|
||||
Io {
|
||||
path: String,
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("malformed manifest line {line}: {content:?}")]
|
||||
MalformedManifest { line: usize, content: String },
|
||||
#[error("HASH MISMATCH for {path}: manifest {expected}, actual {actual} — refusing to run")]
|
||||
Mismatch {
|
||||
path: String,
|
||||
expected: String,
|
||||
actual: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn sha256_hex(path: &Path) -> Result<String, PinError> {
|
||||
let bytes = std::fs::read(path).map_err(|source| PinError::Io {
|
||||
path: path.display().to_string(),
|
||||
source,
|
||||
})?;
|
||||
Ok(format!("{:x}", Sha256::digest(&bytes)))
|
||||
}
|
||||
|
||||
/// Verify every entry of a `sha256sum`-format manifest
|
||||
/// (`<hex-digest> <relative-path>` per line, paths relative to `root`).
|
||||
/// Returns the number of files verified; errors on the first mismatch.
|
||||
pub fn verify_manifest(manifest: &Path, root: &Path) -> Result<usize, PinError> {
|
||||
let raw = std::fs::read_to_string(manifest).map_err(|source| PinError::Io {
|
||||
path: manifest.display().to_string(),
|
||||
source,
|
||||
})?;
|
||||
let mut verified = 0;
|
||||
for (i, line) in raw.lines().enumerate() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() || line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
let (expected, rel) = line
|
||||
.split_once(" ")
|
||||
.ok_or_else(|| PinError::MalformedManifest {
|
||||
line: i + 1,
|
||||
content: line.to_string(),
|
||||
})?;
|
||||
let path = root.join(rel);
|
||||
let actual = sha256_hex(&path)?;
|
||||
if !actual.eq_ignore_ascii_case(expected) {
|
||||
return Err(PinError::Mismatch {
|
||||
path: path.display().to_string(),
|
||||
expected: expected.to_string(),
|
||||
actual,
|
||||
});
|
||||
}
|
||||
verified += 1;
|
||||
}
|
||||
Ok(verified)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs;
|
||||
|
||||
#[test]
|
||||
fn verifies_and_refuses() {
|
||||
let dir = std::env::temp_dir().join("hotpath-pin-test");
|
||||
fs::create_dir_all(&dir).unwrap();
|
||||
let corpus = dir.join("input.bin");
|
||||
fs::write(&corpus, b"golden input").unwrap();
|
||||
let digest = sha256_hex(&corpus).unwrap();
|
||||
|
||||
let manifest = dir.join("MANIFEST.sha256");
|
||||
fs::write(&manifest, format!("{digest} input.bin\n")).unwrap();
|
||||
assert_eq!(verify_manifest(&manifest, &dir).unwrap(), 1);
|
||||
|
||||
// Tamper: verification must refuse.
|
||||
fs::write(&corpus, b"tampered input").unwrap();
|
||||
let err = verify_manifest(&manifest, &dir).unwrap_err();
|
||||
assert!(matches!(err, PinError::Mismatch { .. }));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//! Per-target equivalence policy (`targets/<name>/equivalence.toml`).
|
||||
//! Absent a policy file, byte-identical is required (SPEC §3.2).
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
#[serde(tag = "mode", rename_all = "kebab-case", deny_unknown_fields)]
|
||||
pub enum EquivalencePolicy {
|
||||
/// Default: stdout, output files, and exit codes must match exactly.
|
||||
ByteIdentical,
|
||||
/// FP-producing targets only: numeric fields may differ within the
|
||||
/// declared tolerance; everything else stays byte-identical. Using
|
||||
/// this tier at all routes the attempt to needs-human-review when
|
||||
/// FP *flags* changed (SPEC §8) — tolerance covers output compare,
|
||||
/// not compiler-flag laxity.
|
||||
FpTolerance {
|
||||
/// Maximum absolute difference per numeric value.
|
||||
abs: f64,
|
||||
/// Maximum relative difference per numeric value.
|
||||
rel: f64,
|
||||
},
|
||||
}
|
||||
|
||||
impl EquivalencePolicy {
|
||||
/// Load the target's policy, defaulting to byte-identical when no
|
||||
/// equivalence.toml exists.
|
||||
pub fn load(target_dir: &Path) -> anyhow::Result<Self> {
|
||||
let path = target_dir.join("equivalence.toml");
|
||||
if !path.exists() {
|
||||
return Ok(Self::ByteIdentical);
|
||||
}
|
||||
let raw = std::fs::read_to_string(&path)?;
|
||||
let policy: Self = toml::from_str(&raw)?;
|
||||
if let Self::FpTolerance { abs, rel } = &policy {
|
||||
anyhow::ensure!(
|
||||
*abs >= 0.0 && *rel >= 0.0,
|
||||
"tolerances must be non-negative"
|
||||
);
|
||||
}
|
||||
Ok(policy)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn absent_policy_means_byte_identical() {
|
||||
let dir = std::env::temp_dir().join("hotpath-policy-none");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
assert_eq!(
|
||||
EquivalencePolicy::load(&dir).unwrap(),
|
||||
EquivalencePolicy::ByteIdentical
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_fp_tolerance() {
|
||||
let dir = std::env::temp_dir().join("hotpath-policy-fp");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
std::fs::write(
|
||||
dir.join("equivalence.toml"),
|
||||
"mode = \"fp-tolerance\"\nabs = 1e-9\nrel = 1e-6\n",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
EquivalencePolicy::load(&dir).unwrap(),
|
||||
EquivalencePolicy::FpTolerance { abs: 1e-9, rel: 1e-6 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user