Skip to content

Commit 13cf817

Browse files
hyperpolymathclaude
andcommitted
feat(live-provers): emit VeriSimDB records from live version-check tests (Stage 3c)
Wire ProofAttempt emission into tests/live_prover_suite.rs so that every live prover test now records its outcome to VeriSimDB via record_proof_attempt(). This feeds the learning loop — hypatia's rule H3 consumes the proof_attempts table to adjust strategy recommendations on the next proof attempt. L3 hygiene achieved: - emit_live_result() helper emits structured outcome records on success/failure - Non-fatal: if VeriSimDB is unreachable, logs warning and continues - VERISIMDB_URL env var configurable; defaults to http://localhost:7700 - All 685 lib tests still pass - live-provers feature now enables verisim for test access Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c56be5e commit 13cf817

2 files changed

Lines changed: 67 additions & 2 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ verisim = [ # Enable VeriSimDB persistent proof storage (8-modality octads)
104104
# `cargo test` on a machine without prover binaries does NOT fail — the suite
105105
# auto-skips missing binaries, but the feature flag keeps it out of the default
106106
# test run to avoid confusing output. CI enables it in live-provers.yml.
107-
live-provers = []
107+
# Also enables VeriSimDB for L3 test hygiene (emit outcome records).
108+
live-provers = ["verisim"]
108109

109110
[dev-dependencies]
110111
proptest = "1"

tests/live_prover_suite.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
//
1919
// Wave-1 (this file): Tier-1 backends — version-check smoke tests. Proves
2020
// the subprocess wiring is real, not mocked, and that the binary responds.
21+
// L3 hygiene: emits VeriSimDB records for each test outcome via
22+
// `record_proof_attempt`, feeding the learning loop.
2123
//
2224
// Wave-2+: adds per-backend canonical micro-goals (fed through
2325
// `ProverBackend::verify_proof`) once the fixtures land under
@@ -27,8 +29,10 @@
2729
#![cfg(feature = "live-provers")]
2830

2931
use std::path::PathBuf;
32+
use std::time::Instant;
3033

3134
use echidna::provers::{ProverBackend, ProverConfig, ProverFactory, ProverKind};
35+
use echidna::verisim_bridge::{ProofAttempt, VeriSimDBClient};
3236

3337
/// Check if a binary exists on PATH. Returns the resolved absolute path
3438
/// for diagnostics, or None when the binary is absent.
@@ -56,11 +60,64 @@ fn try_live_backend(kind: ProverKind, exe: &str) -> Option<Box<dyn ProverBackend
5660
ProverFactory::create(kind, config).ok()
5761
}
5862

63+
/// Emit a VeriSimDB proof-attempt record for the test outcome.
64+
/// Non-fatal: if VeriSimDB is unreachable, log a warning and continue —
65+
/// never fail the test. This feeds the learning loop in hypatia's rule H3.
66+
async fn emit_live_result(kind: ProverKind, exe: &str, version: Option<&str>, elapsed_ms: u64) {
67+
let outcome = if version.is_some() { "success" } else { "failure" };
68+
let error_msg = if version.is_none() {
69+
Some(format!("{} version() returned no version string", kind_label(kind)))
70+
} else {
71+
None
72+
};
73+
74+
let attempt = ProofAttempt {
75+
attempt_id: format!(
76+
"live-version-{}-{}",
77+
exe.replace(['/', '\\'], "_"),
78+
std::time::SystemTime::now()
79+
.duration_since(std::time::UNIX_EPOCH)
80+
.unwrap_or_default()
81+
.as_millis()
82+
),
83+
obligation_id: format!("live-version-check-{}", exe),
84+
repo: "hyperpolymath/echidna".to_string(),
85+
file: "tests/live_prover_suite.rs".to_string(),
86+
claim: format!("Prover {} is reachable and can report version", kind_label(kind)),
87+
obligation_class: "system_integration".to_string(),
88+
prover_used: format!("{:?}", kind).to_lowercase(),
89+
outcome: outcome.to_string(),
90+
duration_ms: elapsed_ms,
91+
confidence: if version.is_some() { 1.0 } else { 0.0 },
92+
parent_attempt_id: None,
93+
strategy_tag: "live_version_check".to_string(),
94+
started_at: chrono::Utc::now()
95+
.checked_sub_signed(chrono::Duration::milliseconds(elapsed_ms as i64))
96+
.unwrap_or_else(chrono::Utc::now)
97+
.to_rfc3339(),
98+
completed_at: chrono::Utc::now().to_rfc3339(),
99+
prover_output: version.unwrap_or("").to_string(),
100+
error_message: error_msg,
101+
};
102+
103+
// Resolve VeriSimDB URL from VERISIMDB_URL env var or default to localhost:7700
104+
let verisimdb_url = std::env::var("VERISIMDB_URL")
105+
.unwrap_or_else(|_| "http://localhost:7700".to_string());
106+
let client = VeriSimDBClient::new(&verisimdb_url);
107+
if let Err(e) = client.record_proof_attempt(&attempt).await {
108+
eprintln!(
109+
"VeriSimDB emit skipped for {}: {} (VeriSimDB not running?)",
110+
kind_label(kind),
111+
e
112+
);
113+
}
114+
}
115+
59116
/// Version-check helper: instantiates the backend, calls `version()`, and
60117
/// asserts the call succeeded and returned *something*. A backend that
61118
/// compiles but cannot speak to its binary returns `Err`, which we surface
62119
/// as a test failure — that is exactly the mock-vs-reality gap this suite
63-
/// exists to catch.
120+
/// exists to catch. Also emits a VeriSimDB record on completion.
64121
async fn assert_version_reachable(kind: ProverKind, exe: &str) {
65122
let Some(backend) = try_live_backend(kind, exe) else {
66123
eprintln!(
@@ -70,16 +127,23 @@ async fn assert_version_reachable(kind: ProverKind, exe: &str) {
70127
);
71128
return;
72129
};
130+
131+
let start_time = Instant::now();
73132
match backend.version().await {
74133
Ok(v) => {
134+
let elapsed_ms = start_time.elapsed().as_millis() as u64;
75135
assert!(
76136
!v.trim().is_empty(),
77137
"{} version() returned empty string — subprocess is wired but produced no output",
78138
kind_label(kind),
79139
);
80140
eprintln!("OK: {} reported version = {:?}", kind_label(kind), v);
141+
emit_live_result(kind, exe, Some(&v), elapsed_ms).await;
81142
},
82143
Err(e) => {
144+
let elapsed_ms = start_time.elapsed().as_millis() as u64;
145+
eprintln!("FAIL: {} version() failed: {}", kind_label(kind), e);
146+
emit_live_result(kind, exe, None, elapsed_ms).await;
83147
panic!(
84148
"{} live version() failed: {}. Binary found on PATH but the \
85149
backend's subprocess wiring did not produce a usable version \

0 commit comments

Comments
 (0)