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

This commit is contained in:
pitboss 2026-05-17 05:35:00 -05:00
parent cfdd2ecfb1
commit e66b35f355

View file

@ -51,6 +51,8 @@
use crate::chain::finding::{ChainFinding, ChainSeverity};
use crate::commands::scan::Diag;
use crate::dynamic::build_sandbox::dispatch_prepare;
use crate::dynamic::harness;
use crate::dynamic::spec::HarnessSpec;
use crate::dynamic::verify::VerifyOptions;
use crate::evidence::{InconclusiveReason, UnsupportedReason, VerifyResult, VerifyStatus};
@ -180,18 +182,29 @@ pub trait CompositeReverifier {
/// Phase 26 default composite reverifier.
///
/// The composite-harness composer walks `chain.members`, derives one
/// [`HarnessSpec`] per member via [`chain_step_specs`], and (in a
/// future session) will call
/// [`crate::dynamic::lang::compose_chain_step`] per step to assemble a
/// per-step harness with `NYX_PREV_OUTPUT` threading.
/// [`HarnessSpec`] per member via [`chain_step_specs`], drives each
/// derived spec through [`harness::build`] + [`dispatch_prepare`] so
/// the per-language build cost is amortised against the on-disk caches
/// before the live sandbox-run pass lands, and (in a future session)
/// will call [`crate::dynamic::lang::compose_chain_step`] per step to
/// assemble a per-step harness with `NYX_PREV_OUTPUT` threading.
///
/// Today the default reverifier surfaces
/// `Inconclusive(BackendInsufficient)` when invoked, but the `detail`
/// field reports how many of `chain.members` produced a derivable
/// [`HarnessSpec`] so operators (and the [`reverify_top_chains`]
/// caller) can see the spec-derivation coverage before the live
/// execution path lands. Callers that need a deterministic outcome
/// (tests, CI) use [`reverify_chain_with`] with a stubbed reverifier.
/// field reports both the spec-derivation coverage AND the per-step
/// build coverage (`derived N/M`, `built B/N`, `cache_hit=H`,
/// `build_ms=T`, `build_errors=E`) so operators (and the
/// [`reverify_top_chains`] caller) can see the build-cost coverage
/// before the live execution path lands. Callers that need a
/// deterministic outcome (tests, CI) use [`reverify_chain_with`] with
/// a stubbed reverifier.
///
/// Workdir lifetime: every per-step build is content-addressed by
/// [`HarnessSpec::spec_hash`] under `/tmp/nyx-harness/{spec_hash}`,
/// and the per-language `prepare_*` caches under the host's
/// `ProjectDirs` cache root are keyed on `(lockfile_hash,
/// toolchain_id, language)`. Repeated calls with the same specs are
/// idempotent — no per-call growth on disk.
pub struct DefaultCompositeReverifier;
impl CompositeReverifier for DefaultCompositeReverifier {
@ -205,9 +218,46 @@ impl CompositeReverifier for DefaultCompositeReverifier {
let finding_id = format!("chain-{:016x}", chain.stable_hash);
let specs = chain_step_specs(chain, member_diags, opts);
let total = specs.len();
let derived = specs.iter().filter(|s| s.result.is_ok()).count();
let derived_specs: Vec<&HarnessSpec> = specs
.iter()
.filter_map(|s| s.result.as_ref().ok())
.collect();
let derived = derived_specs.len();
// Sub-task (b) main of the Phase 26 live-execution split:
// drive each derived spec through the per-language build
// pipeline so the per-step cache state is visible before
// sub-task (c) lands the live sandbox::run chain. Failures
// are counted, not propagated — the outer verdict stays
// `Inconclusive(BackendInsufficient)` until (c) lands.
let profile = opts.sandbox.process_hardening;
let mut built = 0usize;
let mut cache_hits = 0usize;
let mut total_build_ms: u128 = 0;
let mut build_errors = 0usize;
for spec in &derived_specs {
match harness::build(spec) {
Ok(built_harness) => {
match dispatch_prepare(spec, &built_harness.workdir, profile) {
Ok(result) => {
built += 1;
if result.cache_hit {
cache_hits += 1;
}
total_build_ms = total_build_ms
.saturating_add(result.duration.as_millis());
}
Err(_) => build_errors += 1,
}
}
Err(_) => build_errors += 1,
}
}
let detail = format!(
"composite chain re-verification not yet wired for live runs; derived {derived}/{total} harness specs"
"composite chain re-verification not yet wired for live runs; \
derived {derived}/{total} harness specs; \
built {built}/{derived} (cache_hit={cache_hits}, build_ms={total_build_ms}, build_errors={build_errors})"
);
VerifyResult {
finding_id,
@ -517,6 +567,34 @@ mod tests {
);
}
#[test]
fn default_reverifier_detail_reports_build_coverage_with_no_derived_specs() {
// No diags → 0/N derived → 0/0 built. Verifies the build
// segment of the detail string is well-formed even when the
// build pipeline is never invoked.
let mut chain = mk_chain(0xBD, ChainSeverity::Medium, ImpactCategory::InfoDisclosure);
let surface = SurfaceMap::new();
let opts = VerifyOptions::default();
let result = reverify_chain(&mut chain, &[], &surface, &opts);
let detail = result.verdict.detail.as_deref().expect("detail populated");
assert!(
detail.contains("built 0/0"),
"detail must report 0/0 built when no specs derived; got {detail:?}"
);
assert!(
detail.contains("cache_hit=0"),
"detail must zero cache_hit when no builds attempted; got {detail:?}"
);
assert!(
detail.contains("build_ms=0"),
"detail must zero build_ms when no builds attempted; got {detail:?}"
);
assert!(
detail.contains("build_errors=0"),
"detail must zero build_errors when no builds attempted; got {detail:?}"
);
}
#[test]
fn chain_step_specs_reports_no_flow_steps_for_missing_diag() {
let chain = mk_chain(7, ChainSeverity::Medium, ImpactCategory::InfoDisclosure);