//! `wave50_coding_stream` — streaming coding session demo. //! //! Simulates a typed-coding session: the user types, the agent //! suggests, the user accepts / rejects, diagnostics update. The //! whole session streams through the wave-47 substrate one //! 200 ms window at a time. The wave-50 `CodingOpMaterializer` //! collects accepted suggestions and seals them into a Joule-Code //! coding-op cargo when the session window closes. Each window //! mints a JCR-1 `coding-window/1` receipt; the materialized op //! id correlates the receipt with the joule-code cargo. //! //! Run: //! cargo run -p jouleclaw-stack --example wave50_coding_stream use jouleclaw_coding_stream::{ CODING_STREAM_MIME, CodingAnchor, CodingEvent, CodingOpMaterializer, CodingWindow, }; use jouleclaw_jcr1::{CodingActivitySummary, CodingWindowReceipt}; use jouleclaw_stream::{ ChannelDirection, ChannelSpec, StreamSpec, StreamWindow, Tick, TickKind, WindowId, }; const STEWARD: &str = "did:keri:EJ9testStewardAID000000000000000"; const STREAM_ID: &str = "session-001"; const AUTHOR: &str = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"; const CLOSED_BASE: &str = "2026-06-05T00:00"; fn coding_spec() -> StreamSpec { StreamSpec { tick_window_ms: 200, max_chunk_bytes: 64 * 1024, max_ticks_per_window: 64, channels: vec![ChannelSpec { id: "coding".into(), direction: ChannelDirection::Bidi, kind_tag: "text".into(), mime: CODING_STREAM_MIME.into(), }], } } fn tick_of(spec: &StreamSpec, w: u64, ev: CodingEvent, ts: u64) -> Tick { let bytes = ev.to_tick_bytes().expect("event serialises"); let t = Tick { window_id: WindowId(w), channel_id: "coding".into(), kind: TickKind::Text, bytes, ts_ns: ts, }; spec.validate_tick(&t).expect("valid"); t } fn build_window(spec: &StreamSpec, w: u64, events: Vec) -> StreamWindow { let mut sw = StreamWindow::new(WindowId(w)); for (i, ev) in events.into_iter().enumerate() { sw.push(spec, tick_of(spec, w, ev, (i as u64) * 1000)) .expect("push"); } sw } fn summarise(cw: &CodingWindow) -> CodingActivitySummary { let mut diag_delta = 0i32; for ev in &cw.events { if let CodingEvent::DiagnosticDelta { added, cleared, .. } = ev { diag_delta += *added as i32 - *cleared as i32; } } CodingActivitySummary { typed_bytes: cw.typed_bytes() as u64, suggestions_appeared: cw.count_by_tag("suggestion_appeared") as u32, suggestions_accepted: cw.accepted_count() as u32, suggestions_rejected: cw.rejected_count() as u32, cursor_moves: cw.count_by_tag("cursor_moved") as u32, diagnostic_delta_net: diag_delta, } } fn main() { println!("== wave-50 streaming coding session demo ==\n"); let spec = coding_spec(); // Scripted session: 5 windows. // w0: user types "fn ad" // w1: user types "d()"; suggestion appears (full signature) // w2: user types more; rejects suggestion s1 // w3: new suggestion s2 appears; accepted // w4: diagnostics clear; cursor moves; END — materialize op let session: Vec<(u64, Vec)> = vec![ ( 0, vec![CodingEvent::TypedChar { path: "src/lib.rs".into(), bytes: "fn ad".into(), }], ), ( 1, vec![ CodingEvent::TypedChar { path: "src/lib.rs".into(), bytes: "d()".into(), }, CodingEvent::SuggestionAppeared { suggestion_id: "b3:s1-full-signature-0001".into(), path: "src/lib.rs".into(), anchor: CodingAnchor::ByteRange { start: 0, end: 8 }, replacement: "pub fn add(a: i64, b: i64) -> i64 { a + b }".into(), }, ], ), ( 2, vec![ CodingEvent::TypedChar { path: "src/lib.rs".into(), bytes: "{}".into(), }, CodingEvent::SuggestionRejected { suggestion_id: "b3:s1-full-signature-0001".into(), }, ], ), ( 3, vec![ CodingEvent::SuggestionAppeared { suggestion_id: "b3:s2-simple-add-0002".into(), path: "src/lib.rs".into(), anchor: CodingAnchor::ByteRange { start: 8, end: 10 }, replacement: " { a + b }".into(), }, CodingEvent::SuggestionAccepted { suggestion_id: "b3:s2-simple-add-0002".into(), }, ], ), ( 4, vec![ CodingEvent::DiagnosticDelta { path: "src/lib.rs".into(), added: 0, cleared: 2, }, CodingEvent::CursorMoved { path: "src/lib.rs".into(), offset: 18, }, ], ), ]; // The materializer is owned by the session. let mut materializer = CodingOpMaterializer::new( "b3:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", AUTHOR, "L3", ); let mut total_typed = 0u64; let mut total_accepted = 0u32; let mut total_rejected = 0u32; let mut materialized_at: Option = None; for (wid, events) in &session { let sw = build_window(&spec, *wid, events.clone()); let cw = CodingWindow::from_window(&sw); materializer.observe_window(&cw); let activity = summarise(&cw); total_typed += activity.typed_bytes; total_accepted += activity.suggestions_accepted; total_rejected += activity.suggestions_rejected; // Materialize at the LAST window of the session. let (materialized_op_id, author_for_receipt) = if *wid == session.last().unwrap().0 { match materializer.materialize("add(a:i64,b:i64)->i64") { Ok(op) => { materialized_at = Some(*wid); (op.op_id, AUTHOR.to_string()) } Err(_) => (String::new(), String::new()), } } else { (String::new(), String::new()) }; let receipt = CodingWindowReceipt::build( format!("{STREAM_ID}:cw:{:04}", wid), format!("{CLOSED_BASE}:{:02}Z", wid), STEWARD, STREAM_ID, *wid, activity.clone(), materialized_op_id.clone(), author_for_receipt, ); let receipt_hash = receipt.receipt_hash().expect("hash"); let tag = if !materialized_op_id.is_empty() { "SEAL " } else if activity.suggestions_accepted > 0 { "ACPT " } else if activity.suggestions_rejected > 0 { "REJT " } else if activity.typed_bytes > 0 { "TYPE " } else { "IDLE " }; println!( " w{:02} {} typed={:>3}B appeared={} accepted={} rejected={} diag={:+} receipt={}", wid, tag, activity.typed_bytes, activity.suggestions_appeared, activity.suggestions_accepted, activity.suggestions_rejected, activity.diagnostic_delta_net, &receipt_hash[..16] ); if !materialized_op_id.is_empty() { println!( " ↳ materialized op_id={} (correlates with joule-code cargo)", &materialized_op_id[..20] ); } } println!(); println!("== summary =="); println!( " windows={} typed={}B accepted={} rejected={} materialized={}", session.len(), total_typed, total_accepted, total_rejected, materialized_at.map(|w| format!("w{w:02}")).unwrap_or_else(|| "none".into()) ); println!(); println!("✓ Streaming coding session works end-to-end:"); println!( " CodingEvent → tick (under {CODING_STREAM_MIME})" ); println!( " → StreamWindow → CodingWindow → materializer (accumulates accepts across windows)" ); println!( " → MaterializedCodingOp (joule-code-cargo wire shape)" ); println!( " → JCR-1 coding-window/1 receipt per window (op_id correlates with joule-code cargo;" ); println!(" stream_id + window_id correlate with wave-47 stream-window/1 receipt)"); }