[pitboss/grind] deferred session-0019 (20260517T044708Z-e058)

This commit is contained in:
pitboss 2026-05-17 06:56:06 -05:00
parent f87ef7f118
commit b5696c99e2

View file

@ -1,6 +1,6 @@
/// Dynamic verification benchmarks (§8.4).
///
/// Tracks six cost anchors:
/// Tracks the per-scan cost anchors:
///
/// 1. `harness_build_cold` — fresh workdir, spec → BuiltHarness (source gen + disk write).
/// 2. `harness_build_warm` — same spec, workdir already staged (file write skipped).
@ -9,6 +9,25 @@
/// 4. `docker_image_build` — cold image pull/build for the python:3-slim base.
/// 5. `docker_exec_warm` — `docker exec` into a running container (no cold start).
/// 6. `docker_payload_cost` — per-payload sandbox cost via docker backend end-to-end.
/// 7. `composite_chain_reverify_dispatch` — `reverify_top_chains` on a
/// synthetic 3-member chain with no member diags. Measures the no-derive
/// dispatch path (chain_step_specs miss, early-exit build/run loops,
/// Inconclusive verdict allocation, severity downgrade).
/// 8. `composite_chain_reverify_stub_confirmed` — same chain shape, stubbed
/// reverifier returning `Confirmed`. Measures the apply-verdict happy path
/// (no severity bucket change).
/// 9. `composite_chain_reverify_top_n_slice` — 5-chain slice with `top_n=3`.
/// Measures the slice traversal cost so a regression that walks the full
/// slice instead of the prefix is visible.
///
/// Wall-clock budget anchors for the composite reverify path (per the
/// Phase 26 acceptance literal): the live process backend stays under
/// 400ms per 3-member chain, the docker backend under 1500ms. Those
/// live-run numbers are covered by the
/// `flask_eval_chain_reverify_populates_dynamic_verdict` integration
/// test in `tests/chain_emission_e2e.rs`; the microbenches here anchor
/// the dispatch + verdict-application overhead so regressions on the
/// API-shape half land in the criterion baseline.
///
/// Baselines committed to `benches/dynamic_bench_baseline.json`.
/// Run: `cargo bench --features dynamic -- dynamic`
@ -386,6 +405,164 @@ fn bench_php_harness_build_cold(c: &mut Criterion) {
});
}
#[cfg(feature = "dynamic")]
fn mk_chain_member(hash: u64, idx: usize) -> nyx_scanner::chain::FindingRef {
use nyx_scanner::surface::SourceLocation;
nyx_scanner::chain::FindingRef {
finding_id: format!("bench-chain-member-{idx}"),
stable_hash: hash,
location: SourceLocation::new("bench/synthetic.py", (idx as u32) + 1, 1),
rule_id: "taint-unsanitised-flow".into(),
cap_bits: 0,
}
}
#[cfg(feature = "dynamic")]
fn mk_synthetic_chain(hash: u64, members: usize) -> nyx_scanner::chain::ChainFinding {
use nyx_scanner::chain::{ChainFinding, ChainSeverity, ChainSink, ImpactCategory};
ChainFinding {
stable_hash: hash,
members: (0..members)
.map(|i| mk_chain_member(hash.wrapping_add(i as u64 + 1), i))
.collect(),
sink: ChainSink {
file: "bench/synthetic.py".into(),
line: 99,
col: 1,
function_name: "sink".into(),
cap_bits: 0,
},
implied_impact: ImpactCategory::Rce,
severity: ChainSeverity::Critical,
score: 100.0,
dynamic_verdict: None,
reverify_reason: None,
}
}
#[cfg(feature = "dynamic")]
struct BenchConfirmedReverifier;
#[cfg(feature = "dynamic")]
impl nyx_scanner::chain::CompositeReverifier for BenchConfirmedReverifier {
fn reverify(
&self,
_chain: &nyx_scanner::chain::ChainFinding,
_member_diags: &[nyx_scanner::commands::scan::Diag],
_surface: &nyx_scanner::surface::SurfaceMap,
_opts: &nyx_scanner::dynamic::verify::VerifyOptions,
) -> nyx_scanner::evidence::VerifyResult {
nyx_scanner::evidence::VerifyResult {
finding_id: "bench".into(),
status: nyx_scanner::evidence::VerifyStatus::Confirmed,
triggered_payload: None,
reason: None,
inconclusive_reason: None,
detail: None,
attempts: vec![],
toolchain_match: None,
differential: None,
replay_stable: None,
wrong: None,
hardening_outcome: None,
}
}
}
/// Phase 26 dispatch-cost anchor: synthetic 3-member chain with no
/// matching member diags. The reverifier walks chain_step_specs (3
/// HashMap misses → 3 NoFlowSteps errors), the build loop sees zero
/// derived specs and exits early, the run loop sees zero built steps
/// and exits early. The composed VerifyResult is allocated and applied
/// via `apply_dynamic_verdict` (Inconclusive → severity downgrade).
///
/// This is the no-toolchain-dep dispatch overhead — a regression here
/// signals a hot-path allocation introduced into the reverify pipeline.
#[cfg(feature = "dynamic")]
fn bench_composite_chain_reverify_dispatch(c: &mut Criterion) {
use nyx_scanner::chain::reverify;
use nyx_scanner::dynamic::verify::VerifyOptions;
use nyx_scanner::surface::SurfaceMap;
let surface = SurfaceMap::new();
let opts = VerifyOptions::default();
c.bench_function("composite_chain_reverify_dispatch", |b| {
b.iter(|| {
let mut chains = [mk_synthetic_chain(0xC1A1, 3)];
let _ = reverify::reverify_top_chains(&mut chains, &[], &surface, &opts, 1);
});
});
}
/// Phase 26 stub-reverifier happy-path anchor: synthetic 3-member
/// chain driven through `reverify_top_chains_with` + a stubbed
/// reverifier returning `Confirmed`. Measures the apply-verdict path
/// when the verdict does NOT trigger a severity downgrade, so the
/// `ChainReverifyResult` allocation + `chain.apply_dynamic_verdict`
/// transition cost is exercised independent of the verdict-side
/// allocation in the dispatch bench.
#[cfg(feature = "dynamic")]
fn bench_composite_chain_reverify_stub_confirmed(c: &mut Criterion) {
use nyx_scanner::chain::reverify;
use nyx_scanner::dynamic::verify::VerifyOptions;
use nyx_scanner::surface::SurfaceMap;
let surface = SurfaceMap::new();
let opts = VerifyOptions::default();
let reverifier = BenchConfirmedReverifier;
c.bench_function("composite_chain_reverify_stub_confirmed", |b| {
b.iter(|| {
let mut chains = [mk_synthetic_chain(0xC2A2, 3)];
let _ = reverify::reverify_top_chains_with(
&mut chains,
&[],
&surface,
&opts,
1,
&reverifier,
);
});
});
}
/// Phase 26 top-N slice anchor: 5-chain slice with `top_n=3`. Asserts
/// (by way of regression) that the reverify pass never walks past the
/// top-N prefix. The fan-in is the per-chain dispatch cost times three;
/// a regression that drops the `bound = top_n.min(chains.len())` cap
/// would show up as a ~5/3 increase in this bench.
#[cfg(feature = "dynamic")]
fn bench_composite_chain_reverify_top_n_slice(c: &mut Criterion) {
use nyx_scanner::chain::reverify;
use nyx_scanner::dynamic::verify::VerifyOptions;
use nyx_scanner::surface::SurfaceMap;
let surface = SurfaceMap::new();
let opts = VerifyOptions::default();
let reverifier = BenchConfirmedReverifier;
c.bench_function("composite_chain_reverify_top_n_slice", |b| {
b.iter(|| {
let mut chains: [nyx_scanner::chain::ChainFinding; 5] = [
mk_synthetic_chain(0xC301, 3),
mk_synthetic_chain(0xC302, 3),
mk_synthetic_chain(0xC303, 3),
mk_synthetic_chain(0xC304, 3),
mk_synthetic_chain(0xC305, 3),
];
let _ = reverify::reverify_top_chains_with(
&mut chains,
&[],
&surface,
&opts,
3,
&reverifier,
);
});
});
}
#[cfg(feature = "dynamic")]
fn bench_noop(_c: &mut Criterion) {}
@ -409,6 +586,9 @@ criterion_group!(
bench_go_harness_build_cold,
bench_java_harness_build_cold,
bench_php_harness_build_cold,
bench_composite_chain_reverify_dispatch,
bench_composite_chain_reverify_stub_confirmed,
bench_composite_chain_reverify_top_n_slice,
);
#[cfg(not(feature = "dynamic"))]