feat(rune_profiler): literal-100% residue — dichotomy wave
Port the last audit-missing fn name-preserving: main, as the CLI-front
bin (memory_scoring/rune_spine bin law) — the oracle main's
measurement loop is host-side (Python callables / Ollama HTTP; FFI
cannot receive callables), so the bin fronts the portable law the
kernel owns: {op: profile_stats, arg} on stdin -> the same doc
envelope the FFI returns. Smoke-verified: function shape (p95/p99),
model_call shape, empty-times ValueError envelope, unknown-op error;
bin output byte-matches the FFI for identical inputs.
FIX-FIRST WITH PROOF (pre-existing master break): pyjson's Float wire
variant (decimal-point law) made the rp_profile_stats FFI and the
battery filter Json::Num only — every float elapsed-ms was dropped,
so ALL delegated calls raised 'min() iterable argument is empty' and
the facade silently fell back to Python; battery 1/3 on master. Both
extractions now accept Num|Float. FFI verified live with float times
(mean/median/percentiles correct); battery 3/3 green; parity 815/815
(frozen 9 fuzz 800 live 6); clippy -D warnings clean; adjacent pytest
22/22 BOTH pins. Fn coverage 2/3 -> 3/3.
This commit is contained in:
1 parent
eefa4dd03a
commit
1168dcdf87
3 files changed
+110
-3
No files matched your search
@@ -81,7 +81,10 @@ fn replay_profile_function() {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Num(n) => Some(*n),
|
||||
// measurement values are Python floats — the wire law
|
||||
// carries them as Json::Float (json floats keep their
|
||||
// decimal point); accept the int form too (Num)
|
||||
Json::Num(n) | Json::Float(n) => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
@@ -110,7 +113,7 @@ fn replay_profile_model_call() {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Num(n) => Some(*n),
|
||||
Json::Num(n) | Json::Float(n) => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -134,7 +134,10 @@ ffi!(rp_profile_stats, |raw: &str| -> Result<Json, (String, String)> {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Num(n) => Some(*n),
|
||||
// elapsed-ms values are Python floats — json.dumps emits
|
||||
// them with a decimal point, which pyjson parses as
|
||||
// Json::Float; the int form (Num) rides for int inputs
|
||||
Json::Num(n) | Json::Float(n) => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
//! main.rs — CLI front for the rune_profiler core (runner/debug use).
|
||||
//!
|
||||
//! The oracle's main() drives the measurement loop (perf_counter_ns
|
||||
//! around Python callables / the Ollama HTTP call) — host-side by
|
||||
//! nature, FFI cannot receive Python callables — so the CLI front is
|
||||
//! the doc-envelope dispatch over the PORTABLE law the kernel owns:
|
||||
//! the stats computation over measured elapsed times (memory_scoring /
|
||||
//! rune_spine bin law).
|
||||
//!
|
||||
//! stdin: {"op": "profile_stats", "arg": {"times": [ms...],
|
||||
//! "iterations": N, "model_call": bool?}}
|
||||
//! stdout: the same {ok, value|err} envelope the FFI returns.
|
||||
|
||||
use evidence_provenance::pyjson::{self, Json};
|
||||
use rune_profiler::{profile_stats, StatsShape};
|
||||
use std::io::Read;
|
||||
|
||||
fn get<'a>(v: &'a Json, key: &str) -> Option<&'a Json> {
|
||||
match v {
|
||||
Json::Obj(pairs) => pairs.iter().find(|(k, _)| k == key).map(|(_, v)| v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_str<'a>(v: &'a Json, key: &str) -> Option<&'a str> {
|
||||
match get(v, key) {
|
||||
Some(Json::Str(s)) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
if std::io::stdin().read_to_string(&mut input).is_err() {
|
||||
emit(Err(("failed to read stdin".to_string(), "OSError".to_string())));
|
||||
return;
|
||||
}
|
||||
let parsed = match pyjson::parse(&input) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
emit(Err((format!("stdin JSON parse failed: {e}"), "ValueError".to_string())));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let op = get_str(&parsed, "op").unwrap_or("").to_string();
|
||||
let arg = get(&parsed, "arg").cloned().unwrap_or(Json::Null);
|
||||
let result = dispatch(&op, &arg);
|
||||
emit(result);
|
||||
}
|
||||
|
||||
fn dispatch(op: &str, arg: &Json) -> Result<Json, (String, String)> {
|
||||
match op {
|
||||
"profile_stats" => {
|
||||
let times: Vec<f64> = match get(arg, "times") {
|
||||
Some(Json::Arr(items)) => items
|
||||
.iter()
|
||||
.filter_map(|x| match x {
|
||||
Json::Num(n) | Json::Float(n) => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
_ => {
|
||||
return Err((
|
||||
"arg.times must be a list of elapsed-ms numbers".to_string(),
|
||||
"TypeError".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let iterations = match get(arg, "iterations") {
|
||||
Some(Json::Num(n)) => *n as usize,
|
||||
_ => 0,
|
||||
};
|
||||
let shape = match get(arg, "model_call") {
|
||||
Some(Json::Bool(true)) => StatsShape::ModelCall,
|
||||
_ => StatsShape::Function,
|
||||
};
|
||||
profile_stats(×, iterations, shape)
|
||||
}
|
||||
other => Err((
|
||||
format!("unknown op: {other:?} (choices: ['profile_stats'])"),
|
||||
"ValueError".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit(result: Result<Json, (String, String)>) {
|
||||
let ok = result.is_ok();
|
||||
let body = match result {
|
||||
Ok(value) => Json::Obj(vec![
|
||||
("ok".to_string(), Json::Bool(true)),
|
||||
("value".to_string(), value),
|
||||
]),
|
||||
Err((err, ty)) => Json::Obj(vec![
|
||||
("ok".to_string(), Json::Bool(false)),
|
||||
("err".to_string(), Json::Str(err)),
|
||||
("type".to_string(), Json::Str(ty)),
|
||||
]),
|
||||
};
|
||||
println!("{}", pyjson::dumps(&body));
|
||||
std::process::exit(if ok { 0 } else { 1 });
|
||||
}
|
||||
Reference in new issue
Block a user