open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-stack/examples/comprehend_demo.rs
Transaction Science f0251c5163 jouleclaw-stack/examples: 6 starter cascades — the on-ramp the audit asked for
Wave-8 close-the-gaps move 3. The five-lens cross-talk audit
(Phillip / Rafie / Bloom / Hyper-Agent / Priscilla) named the same
on-ramp gap from five different vocabularies: *"100 crates, one
end-to-end example."* This commit closes it.

Six runnable starter cascades, each ≤ 120 LOC, one per use case
the audits surfaced. Every example builds with `cargo run -p
jouleclaw-stack --example <name>` and produces a meaningful output
out of the box.

## The six examples

  minimal_cache_only.rs           The smallest cascade walk. Ask the
                                  same question twice, watch the L0
                                  cache serve the repeat at floor
                                  energy. (Phillip: text-is-state.)

  rag_with_retrieval.rs           Seeded local index → retrieve →
                                  enrich → rerank → read pipeline,
                                  with per-stage joule trace. (Bloom:
                                  the verifiable zone in action.)

  comprehend_demo.rs              `Stack::comprehend` against a
                                  seeded corpus, with HeuristicClassifier
                                  installed. Prints passages,
                                  extracted answer, intent verdict,
                                  and the verifiable-zone invariant.
                                  (Priscilla: *understand before you
                                  generate*.)

  agent_with_skill_induction.rs   Register a Skill with a template
                                  matcher + Format procedure, watch
                                  the cascade resolve a whole query
                                  class at L0.5 — nanojoules, no
                                  model invocation. (Phillip:
                                  agent-ready APIs.)

  save_memory_and_promote.rs      Demonstrates Hyper-Agent's three
                                  modes of memory on JouleClaw's
                                  primitives: manual save_memory,
                                  plus an FnPromotionListener
                                  capturing a NotifyPromotedFact
                                  event when a verified compartment
                                  answer is promoted. (Hyper-Agent:
                                  three modes of memory.)

  ledger_breakdown.rs             Constructs a 7-receipt synthetic
                                  workload over jouleclaw-ledger,
                                  prints a CostSummary by tier /
                                  tool / model / intent. The output
                                  reproduces a Priscilla-style 67/2-
                                  ish breakdown on a controlled
                                  fixture. (Rafie: breakdown at the
                                  top.)

## AGENTS.md companion

`examples/AGENTS.md` indexes the six with a one-line "what it shows"
and the audit lens each serves. The doctrine in one line:

  *Inference is the last resort, not the entry point.* (SPEC §1.1)

Discovered automatically by `jouleclaw-agents-md` via the hierarchical
walk; an operator who drops their own AGENTS.md alongside picks up
the starter notes without configuration.

## Test infrastructure

`[dev-dependencies]` in `jouleclaw-stack/Cargo.toml` extended with
`jouleclaw-prov`, `jouleclaw-energy`, `jouleclaw-ledger`,
`jouleclaw-local-index`, `jouleclaw-skill` — needed by examples and
documented as such ("Direct deps the starter examples reach for").
These do not affect the library surface.

All six examples smoke-tested:

  minimal_cache_only        first ask L3 / second ask L0 (cache hit)
  rag_with_retrieval        extracts "Paris" from seeded index
  comprehend_demo           highest tier = L2.5 (invariant), intent
                            tagged as comprehension (80% confidence)
  agent_with_skill_induction  three countries all resolve at L0.5
                              (~40 nanojoules each)
  save_memory_and_promote   manual capture + listener fires once
  ledger_breakdown          7 receipts → 71.4% / 14.3% comprehension /
                            generation (close to Priscilla's 67% / 2%)

Workspace regression: 0 failures.
2026-06-01 02:39:49 -04:00

82 lines
3.1 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! `comprehend_demo` — *understand before you generate.*
//!
//! Drives `JouleClawStack::comprehend` against a seeded corpus. The
//! cascade walks only the L0–L2.5 verifiable zone — never the L3 model
//! — and returns a [`ComprehensionTrace`] with every passage that
//! grounded the answer, per-stage joule attribution, the optional
//! extractive answer from the L1.5 reader, and (when a classifier is
//! installed) the query's intent verdict.
//!
//! This is the Priscilla-from-Sentry surface: the 67%-comprehension
//! workload made operationally visible.
//!
//! Run with:
//! cargo run -p jouleclaw-stack --example comprehend_demo
use jouleclaw_intent::HeuristicClassifier;
use jouleclaw_local_index::{Document, InMemoryIndex, LocalIndexTier};
use jouleclaw_stack::{ComprehensionConfig, JouleClawStack};
fn main() {
// Seed a tiny set of facts.
let mut idx = InMemoryIndex::new();
idx.insert(Document::new("d1", "The capital of France is Paris."));
idx.insert(Document::new("d2", "The capital of Germany is Berlin."));
idx.insert(Document::new("d3", "The capital of Italy is Rome."));
let mut stack = JouleClawStack::with_defaults()
.with_intent_classifier(Box::new(HeuristicClassifier::new()));
stack.local_index = LocalIndexTier::new(idx);
let cfg = ComprehensionConfig {
use_federation: false,
use_graph_enrich: false,
..ComprehensionConfig::default()
};
let trace = stack.comprehend_with("explain what the capital of France is", 100.0, &cfg);
println!("comprehension trace:");
println!(" question {}", trace.question);
println!(
" highest tier touched {} (verifiable-zone invariant)",
trace.highest_tier_touched
);
println!(" joules spent {:.6}", trace.joules_spent);
println!(" budget exhausted {}", trace.budget_exhausted);
if let Some(intent) = &trace.intent {
println!(
" intent {} ({:.0}% confident, classifier={})",
intent.intent.label(),
intent.confidence * 100.0,
intent.classifier_id
);
}
println!();
println!("passages ({} total, in best-first order):", trace.passages.len());
for (i, p) in trace.passages.iter().enumerate() {
let src = p.source.as_deref().unwrap_or("(no source)");
let score = p
.rerank_score
.map(|s| format!("{s:.3}"))
.unwrap_or_else(|| "—".into());
println!(" [{i}] (score={score}) [{src}]");
println!(" {}", p.text);
}
println!();
if let Some(extracted) = trace.extracted_answer {
println!("extracted answer: {extracted}");
println!("confidence: {:.3}", trace.confidence);
} else {
println!("(reader produced no extractive answer)");
}
println!();
println!("per-stage trace:");
for s in &trace.stages {
println!(
" {stage:<26} {joules:>10.6} J {note}",
stage = s.stage,
joules = s.joules,
note = s.note
);
}
}