yog 0.0.35

yog: the standalone server for litany loops — the world, the balls and the conversations, behind one wire
Documentation
//! The boundary glue a frame's gestures land in (§8.5), driven from where the
//! **engine** stands ([`crate::test_support::engine::act`]) — since bl-1747 the
//! window posts every act over the wire and holds no dispatch of its own, so
//! these read the chokepoint the wire's listener reaches, over a `ui.json`
//! opened fresh per gesture. Shares [`super::world`]'s hermetic fixture; spawns
//! a fake `litany`, so it lives in its own file (the `prepare.rs` discipline).

use super::{model, world};
use crate::boundary::Action;
use crate::boundary::reply::Reply;
use crate::cli_outbound::Cli;
use crate::opslog::{self, DETACHED_EXIT};
use crate::start::Prepared;
use crate::test_support::engine;
use std::path::Path;
use tempfile::tempdir;

/// The door's fire over a wall that is signed in (bl-2291) — these beats are
/// about the mint and the launch, not the wall.
fn signed(deps: crate::boundary::dispatch::Deps) -> crate::boundary::dispatch::Deps {
    crate::boundary::dispatch::Deps {
        world: crate::test_support::signed(&deps.world),
        ..deps
    }
}

/// The conversation the retarget and the fork address. **Id-shaped** (ARCH
/// §2.3's compact stamp): the §8.5 chokepoint resolves the conversation a
/// gesture names (bl-49bc), and an id reads as one on its own.
const AGENT: &str = "20260101T000000Z-c1";

/// An everything-succeeds fake `litany`.
fn fake_litany(dir: &Path) -> Cli {
    let path = dir.join("litany");
    crate::test_support::write_exec(&path, "#!/bin/sh\nexit 0\n");
    Cli::new(path)
}

/// The composer's own hand-off, as the two `Prompt` drives below spend it.
fn prepared(w: &super::World) -> Prepared {
    Prepared {
        workspace: crate::naming::leaf(&w.ws_cobalt),
        binding: Some(w.ws_cobalt.clone()),
        goal: "prefill".into(),
        origin: crate::opslog::Origin::Conversation,
        lineage: None,
    }
}

#[test]
fn the_engines_dispatch_is_the_one_chokepoint_a_posted_act_reaches() {
    let bin = tempdir().unwrap();
    let w = world();
    let (_c, m) = model(&w);
    let litany = fake_litany(bin.path());
    let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
    let action = Action::Scan {
        workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
    };
    let Reply::Outcome(outcome) = engine::act(&m, &deps, "TS", &action).unwrap() else {
        panic!("a verb answers an outcome");
    };
    assert!(outcome.ok());
    let ops = opslog::tail(&w.roots.yog_state, 4);
    assert_eq!(ops.last().map(|e| e.ts.clone()), Some("TS".to_owned()));
}

/// The §9.4 exit rides the same chokepoint (bl-2d19), and what reaches the
/// substrate is the workspace-bound `litany retarget <ws> <agent>` — asserted
/// off the §4.2 trail, which records the argv actually spawned.
#[test]
fn the_retarget_exit_spawns_the_bound_litany_verb() {
    let bin = tempdir().unwrap();
    let w = world();
    let (_c, m) = model(&w);
    let litany = fake_litany(bin.path());
    let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
    let action = Action::Retarget {
        workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
        agent: AGENT.into(),
    };
    let Reply::Outcome(outcome) = engine::act(&m, &deps, "TR", &action).unwrap() else {
        panic!("a verb answers an outcome");
    };
    assert!(outcome.ok());
    let ops = opslog::tail(&w.roots.yog_state, 4);
    let last = ops.last().expect("the verb is on the trail");
    assert_eq!(
        last.argv[1..],
        [
            "retarget".to_owned(),
            w.ws_cobalt.display().to_string(),
            AGENT.to_owned()
        ]
    );
    assert_eq!(last.cwd, w.ws_cobalt.display().to_string());
}

#[test]
fn the_prompt_door_launches_detached_and_mints_off_the_seat_s_own_seed() {
    let bin = tempdir().unwrap();
    let w = world();
    let (_c, m) = model(&w);
    let litany = fake_litany(bin.path());
    let deps = signed(m.boundary_deps(&litany, &Cli::new("/no/bl")));
    let action = Action::Prompt {
        prepared: prepared(&w),
        goal: "go".into(),
        // The §3.3 seed is the firing seat's, carried on the gesture since
        // bl-1747 rather than reached into `Deps` — this is a window's own
        // preview seed crossing with the act it predicted.
        seed: Some(7),
    };
    let Reply::Started { conversation } = engine::act(&m, &deps, "T1", &action).unwrap() else {
        panic!("the prompt door answers the minted name");
    };
    assert!(
        !conversation.is_empty(),
        "the minted conversation name rides back"
    );
    let ops = opslog::tail(&w.roots.yog_state, 4);
    assert_eq!(
        ops.last().map(|e| e.exit),
        Some(DETACHED_EXIT),
        "the handoff's §4.2 sentinel row"
    );

    // The same door refuses when the fork cannot land, error text riding back.
    let dead = signed(m.boundary_deps(&Cli::new("/no/such/litany"), &Cli::new("/no/bl")));
    let err = engine::act(&m, &dead, "T2", &action).unwrap_err();
    assert!(!err.is_empty());
}

/// **A caller that predicted no name still mints one** (bl-1747): `seed: None`
/// is the deposited line and the §4.3 loop, and the door draws off this
/// moment's stamp instead. The default lives at the door, so no intake carries
/// a copy of it.
#[test]
fn a_seedless_prompt_mints_off_the_stamp() {
    let bin = tempdir().unwrap();
    let w = world();
    let (_c, m) = model(&w);
    let litany = fake_litany(bin.path());
    let deps = signed(m.boundary_deps(&litany, &Cli::new("/no/bl")));
    let action = Action::Prompt {
        prepared: prepared(&w),
        goal: "go".into(),
        seed: None,
    };
    let Reply::Started { conversation } = engine::act(&m, &deps, "T9", &action).unwrap() else {
        panic!("the prompt door answers the minted name");
    };
    assert!(!conversation.is_empty(), "a name was minted regardless");
}

/// **S12-T5 three-spellings** (the executor half): one attempt crosses the
/// boundary as the ordinary `litany dispatch --from`, and the whole argv —
/// role, parent, verbatim goal, fork point, skill pin — lands on the §4.2
/// trail. A cohort is this, N times: nothing here knows how many there were.
#[test]
fn an_attempt_dispatches_the_ordinary_fork_and_logs_its_whole_argv() {
    let bin = tempdir().unwrap();
    let w = world();
    let (_c, m) = model(&w);
    let litany = fake_litany(bin.path());
    let deps = m.boundary_deps(&litany, &Cli::new("/no/bl"));
    let action = Action::Fork {
        workspace: crate::naming::leaf(&(w.ws_cobalt.clone())),
        parent: AGENT.into(),
        attempt: crate::fork::Attempt {
            from: "aaaa1111".into(),
            role: "worker".into(),
            skills: vec!["bash".into()],
        },
        goal: "try it the other way".into(),
    };
    let Reply::Outcome(outcome) = engine::act(&m, &deps, "TS", &action).unwrap() else {
        panic!("a verb answers an outcome");
    };
    assert!(outcome.ok());
    let argv = opslog::tail(&w.roots.yog_state, 4)
        .last()
        .map(|e| e.argv.clone())
        .unwrap_or_default();
    assert!(argv.contains(&"dispatch".to_owned()), "{argv:?}");
    assert!(argv.contains(&"worker".to_owned()), "{argv:?}");
    assert!(argv.contains(&AGENT.to_owned()), "{argv:?}");
    assert!(argv.contains(&"--from".to_owned()), "{argv:?}");
    assert!(argv.contains(&"aaaa1111".to_owned()), "{argv:?}");
    assert!(
        argv.contains(&"try it the other way".to_owned()),
        "{argv:?}"
    );
    // The pin's source is the **world's** pool, never an ambient litany's.
    let pin = argv.iter().find(|a| a.starts_with("skills/bash/SKILL.md="));
    let pin = pin.expect("the skill rides as a pin");
    assert!(pin.contains("world/litany/skills/bash/SKILL.md"), "{pin}");
}