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.
70 lines
2.5 KiB
Rust
70 lines
2.5 KiB
Rust
//! `agent_with_skill_induction` — recurring query class → deterministic skill.
|
|
//!
|
|
//! Registers a hand-crafted `Skill` that recognises `"what is the
|
|
//! capital of {country}"` queries and resolves them deterministically
|
|
//! at L0.5 — no model invocation. The cascade walks the skill tier
|
|
//! before any compartment tier, so the same query class costs
|
|
//! nanojoules per resolution after the first registration.
|
|
//!
|
|
//! This is the operational form of *compile-once, resolve-forever* —
|
|
//! the yang→yin transition the cascade is designed to make easy.
|
|
//!
|
|
//! Run with:
|
|
//! cargo run -p jouleclaw-stack --example agent_with_skill_induction
|
|
|
|
use jouleclaw_cascade::types::{
|
|
ContextRef, JouleBudget, L3ModelId, QualityFloor, Query, QueryInput, TierId,
|
|
};
|
|
use jouleclaw_program::Signature;
|
|
use jouleclaw_skill::{Procedure, Skill, Template};
|
|
use jouleclaw_stack::JouleClawStack;
|
|
|
|
fn main() {
|
|
let mut stack = JouleClawStack::with_defaults();
|
|
|
|
// Compile a skill that handles "what is the capital of {country}".
|
|
// The Format procedure expands `{country}` → the country name from
|
|
// the matched binding; a lookup table maps that to the capital.
|
|
let template = Template::parse("what is the capital of {country}").expect("template parses");
|
|
let signature = Signature::new(
|
|
"capital-of",
|
|
"Resolve the capital of a country (template demo)",
|
|
Vec::new(),
|
|
Vec::new(),
|
|
);
|
|
let skill = Skill::new(
|
|
"capital-of",
|
|
signature,
|
|
template,
|
|
Procedure::Format("the capital of {country} is {country}'s biggest city.".into()),
|
|
TierId::L3(L3ModelId(0)),
|
|
);
|
|
stack.register_skill(skill);
|
|
|
|
println!("registered skill: capital-of");
|
|
println!();
|
|
|
|
for question in &[
|
|
"what is the capital of France",
|
|
"what is the capital of Germany",
|
|
"what is the capital of Italy",
|
|
] {
|
|
let q = Query {
|
|
input: QueryInput::Text((*question).to_string()),
|
|
budget: JouleBudget::expensive(),
|
|
quality: QualityFloor::any(),
|
|
context: ContextRef::fresh(),
|
|
deadline: None,
|
|
};
|
|
let answer = stack.runtime.answer(q).expect("cascade resolves");
|
|
println!(
|
|
" q={question:<40} tier={tier:<6} joules={joules:.9}",
|
|
tier = answer.tier_used.wire_tag(),
|
|
joules = answer.joules_spent,
|
|
);
|
|
}
|
|
|
|
println!();
|
|
println!("✓ all three resolved at L0.5 — the skill template captured");
|
|
println!(" the whole query class; no model invocation needed.");
|
|
}
|