bench: cache+branch-sim profiles, hypothesis-granular ledger memory, long-poll read_verdict

- Profiles regenerated with callgrind --cache-sim --branch-sim for both
  targets: per-function D1/LL miss and branch-mispredict columns unlock
  playbook class-4 preconditions (comrak: syntect write_highlighted owns
  31% of D1 read misses; tokei: parse_lines owns 56% of Ir).
- tokei workspace: accepted Phase 0 wins banked as a local commit so
  stash-based baseline rebuilds attribute only the marginal patch to new
  attempts (false-accept trap closed before grinding).
- read_ledger now returns per-attempt history (class, hotspot,
  hypothesis, verdict): a class may be re-entered with a materially new
  hypothesis, never a duplicate one. Task prompt updated to match.
- read_verdict long-polls the ledger up to 45s server-side (under the
  60s MCP cap), cutting the agent's polling turn burn ~15x.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EcKPWQ3MQD4NdEHwar96u2
This commit is contained in:
Claude
2026-07-10 04:49:19 +00:00
parent e0c5018008
commit 017491010b
7 changed files with 52055 additions and 66 deletions
+38 -7
View File
@@ -84,7 +84,21 @@ fn serve_socket(root: &Path, sock: &Path) -> Result<()> {
}
fn respond(root: &Path, line: &str) -> Value {
let _guard = HANDLE_LOCK.lock().unwrap_or_else(|p| p.into_inner());
// read_verdict long-polls the ledger (read-only) and must not hold
// the lock that serializes mutating ops while it sleeps.
let is_read_verdict = serde_json::from_str::<Value>(line)
.ok()
.and_then(|v| {
v.get("op")
.and_then(Value::as_str)
.map(|o| o == "read_verdict")
})
.unwrap_or(false);
let _guard = if is_read_verdict {
None
} else {
Some(HANDLE_LOCK.lock().unwrap_or_else(|p| p.into_inner()))
};
match handle(root, line) {
Ok(v) => json!({"ok": true, "result": v}),
Err(e) => json!({"ok": false, "error": e.to_string()}),
@@ -143,7 +157,14 @@ fn handle(root: &Path, line: &str) -> Result<Value> {
// Read-only surface over the append-only DB.
let ledger = ledger::Ledger::open(&root.join("results/ledger.sqlite"))?;
let classes = ledger.attempted_classes(t)?;
Ok(json!({"attempted_playbook_classes": classes, "total_attempts": ledger.count()?}))
let history = ledger.attempt_history(t)?;
Ok(json!({
"attempted_playbook_classes": classes,
"attempts": history,
"total_attempts": ledger.count()?,
"note": "a class may be re-entered with a materially NEW hypothesis; \
never duplicate a (hotspot, class, hypothesis) that has a verdict",
}))
}
"read_playbook" => {
let class = match req.get("class") {
@@ -303,11 +324,21 @@ fn handle(root: &Path, line: &str) -> Result<Value> {
}
"read_verdict" => {
let run_id = field(&req, "run_id")?;
let ledger = ledger::Ledger::open(&root.join("results/ledger.sqlite"))?;
match ledger.verdict_summary(run_id)? {
Some(v) => Ok(v),
None => Ok(json!({"status": "running",
"note": "no ledger row yet; the pipeline is still building/benching"})),
// Long-poll: the pipeline runs for minutes and the MCP transport
// caps a tool call at 60s. Waiting ~45s server-side per poll cuts
// the agent's turn burn ~15x versus instant "running" replies.
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(45);
loop {
let ledger = ledger::Ledger::open(&root.join("results/ledger.sqlite"))?;
if let Some(v) = ledger.verdict_summary(run_id)? {
return Ok(v);
}
drop(ledger);
if std::time::Instant::now() >= deadline {
return Ok(json!({"status": "running",
"note": "no ledger row yet; the pipeline is still building/benching — poll again"}));
}
std::thread::sleep(std::time::Duration::from_secs(3));
}
}
other => Err(anyhow!(