diff --git a/.claude/board/AGENT_LOG.md b/.claude/board/AGENT_LOG.md index 0859876a..988c071e 100644 --- a/.claude/board/AGENT_LOG.md +++ b/.claude/board/AGENT_LOG.md @@ -1,3 +1,6 @@ +## 2026-06-23 (cont.³⁷) — sealed the capstone OUT/IN-leg public surface + end-to-end mixed-trigger test + +**Main thread (Opus), self-directed ("what do you want").** Disk reality: ~11 GB free vs ~14-18 GB for the lance/datafusion build (ENOSPC'd twice) → S3-live is **disk-walled in this env**, not permission-gated; its home is the symbiont golden-image harness (already pulls lance-7). So took the feasible completion: made the shipped OUT/IN-leg drivers an actual crate surface. `lance-graph-supervisor/lib.rs` now re-exports `deliver_kanban_step`, `drive_mul_advance`, `drive_scheduled_tick`, `drive_version_tick`, `run_to_absorbing`, `KanbanRouteError` (were module-path-only; only `KanbanActor`/`KanbanMsg` were public) — the surface the live S3 consumer will `use` when it lands. **+1 test (15 total green):** `mixed_triggers_compose_on_one_owner_s2_gate_then_s3_ticks` — the capstone integration: the S2 MUL gate takes the first Rubicon step (Flow qualia → Planning→CognitiveWork) and S3 version ticks (`run_to_absorbing`) carry the rest to Commit, proving the two DIFFERENT triggers compose on ONE mailbox-as-owner (no panic, no spurious rejection, lands absorbing). clippy + fmt clean; light build. The actor-side capstone is now a sealed, consumable surface; only the disk-gated live wiring (S3 `versions()` source, S2 shader-driver loop) remains, to be done where the heavy build fits. Rides a PR on jirak. ## 2026-06-21 (cont.³⁶) — run-NaN COGNITIVE half PROVEN green (#580 handoff) + fixed the ogar_codebook drift that blocked it **Main thread (Opus), cognitive-compilation session.** Picked up the cognitive diff --git a/crates/lance-graph-supervisor/src/kanban_actor.rs b/crates/lance-graph-supervisor/src/kanban_actor.rs index b715822b..2757cd98 100644 --- a/crates/lance-graph-supervisor/src/kanban_actor.rs +++ b/crates/lance-graph-supervisor/src/kanban_actor.rs @@ -824,4 +824,47 @@ mod tests { actor.stop(None); handle.await.expect("actor join"); } + + #[tokio::test] + async fn mixed_triggers_compose_on_one_owner_s2_gate_then_s3_ticks() { + // The capstone integration: the S2 MUL gate and the S3 version tick are + // DIFFERENT triggers driving the SAME owner. Here the first Rubicon step + // is taken by a MUL gate (Flow qualia → Planning→CognitiveWork) and the + // rest by version ticks (run_to_absorbing → …→Commit). Both compose + // cleanly on one mailbox-as-owner: no panic, no spurious rejection, lands + // absorbing. + let (actor, handle) = Actor::spawn( + None, + KanbanActor::::default(), + board(KanbanColumn::Planning), + ) + .await + .expect("spawn"); + + // S2: the MUL gate takes the first step (Flow qualia + mantissa>0). + let flow_q = QualiaI4_16D(0).with(3, 4).with(14, 3).with(9, 4).with(1, 2); + let gated = drive_mul_advance(&actor, flow_q, 4) + .await + .expect("gate driver ok") + .expect("Flow advances"); + assert_eq!(gated.from, KanbanColumn::Planning); + assert_eq!(gated.to, KanbanColumn::CognitiveWork); + + // S3: version ticks carry the rest of the arc to the absorbing column. + let tail = run_to_absorbing(&actor, 16) + .await + .expect("ticks reach absorbing"); + let arc: Vec<_> = tail.iter().map(|m| m.to).collect(); + assert_eq!( + arc, + vec![KanbanColumn::Evaluation, KanbanColumn::Commit], + "S3 ticks resume from where the S2 gate left the owner" + ); + + let phase = ractor::call!(actor, |reply| KanbanMsg::Phase { reply }).expect("rpc"); + assert_eq!(phase, KanbanColumn::Commit); + + actor.stop(None); + handle.await.expect("actor join"); + } } diff --git a/crates/lance-graph-supervisor/src/lib.rs b/crates/lance-graph-supervisor/src/lib.rs index b18a3152..43871306 100644 --- a/crates/lance-graph-supervisor/src/lib.rs +++ b/crates/lance-graph-supervisor/src/lib.rs @@ -64,7 +64,10 @@ pub mod actors; pub mod kanban_actor; #[cfg(feature = "supervisor")] -pub use kanban_actor::{KanbanActor, KanbanMsg}; +pub use kanban_actor::{ + deliver_kanban_step, drive_mul_advance, drive_scheduled_tick, drive_version_tick, + run_to_absorbing, KanbanActor, KanbanMsg, KanbanRouteError, +}; #[cfg(feature = "supervisor")] pub use supervisor::{