open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-stack/examples/rag_with_retrieval.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

49 lines
1.8 KiB
Rust

//! `rag_with_retrieval` — RAG over a seeded local corpus.
//!
//! Seeds a tiny in-memory index, drives the `retrieve → enrich →
//! rerank → read` pipeline at `JouleClawStack::rag`, and prints the
//! extractive answer + per-stage joule trace. No model is invoked;
//! the L1.5 reader extracts directly from passages — the *Apply*
//! corner of Bloom's verifiable zone.
//!
//! Run with:
//! cargo run -p jouleclaw-stack --example rag_with_retrieval
use jouleclaw_local_index::{Document, InMemoryIndex, LocalIndexTier};
use jouleclaw_stack::{JouleClawStack, RagConfig};
fn main() {
// Seed three short facts in the local index.
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();
stack.local_index = LocalIndexTier::new(idx);
// Local-only retrieval — federation's mock provider would add noise.
let cfg = RagConfig {
use_federation: false,
use_graph_enrich: false,
..RagConfig::default()
};
let outcome = stack.rag_with("What is the capital of France?", 100.0, &cfg);
println!("RAG run:");
println!(" answer {:?}", outcome.answer);
println!(" confidence {:.3}", outcome.confidence);
println!(" total joules {:.6}", outcome.joules_spent);
println!(" candidates {}", outcome.candidates);
println!(" read {} passage(s)", outcome.passages_read);
println!();
println!("per-stage trace:");
for s in &outcome.stages {
println!(
" {stage:<24} {joules:>10.6} J {note}",
stage = s.stage,
joules = s.joules,
note = s.note
);
}
}