yog 0.0.2

yog: a balls-oriented session manager for lernie loops (egui frontend)
Documentation
//! The conversation identity (§3.3): the per-workspace mint, the composer's
//! name prediction, and the **legacy** stamp parse — the read-only survivors of
//! the retired `You are <name>.` compose (bl-6920). What the goal says about
//! the *work* — prefills, the ball header, the driver cwd — is [`super::goal`]'s.

use crate::start::identity::mint_conversation;
use crate::start::{identity_preview, parse_identity_stamp, strip_identity_stamp};

/// The preview predicts the **name** and claims nothing about the payload
/// (bl-6920): it is not a line of the goal — nothing is prepended at fire — so
/// its wording must not read as one, and it still instructs nothing (§16.7 W9).
#[test]
fn the_preview_predicts_the_name_and_is_not_a_goal_line() {
    let line = identity_preview(&[], &mut super::rng());
    let name = line.strip_prefix("will be named ").expect("the prediction");
    assert!(!name.is_empty() && !name.contains(char::is_whitespace));
    assert!(
        parse_identity_stamp(&line).is_none(),
        "the preview no longer wears the retired stamp's shape"
    );
    assert!(!line.contains("--as"));
    assert!(!line.contains("workspace"));
}

/// The **legacy** parse reads the line the retired compose used to write
/// (`You are <x>.`, pre-0.0.4 roots only) — the fallback rung of the §3.3
/// display ladder and nothing else. No live path composes this shape, so the
/// fixture is the literal legacy bytes.
#[test]
fn parse_identity_stamp_reads_the_legacy_line_only() {
    let goal = "You are cobalt-gecko.\n\nfree prose";
    assert_eq!(parse_identity_stamp(goal).as_deref(), Some("cobalt-gecko"));
    // Line one only: the retired compose put the stamp there, so a `You are`
    // sentence further down the operator's own payload is prose, not a name.
    assert_eq!(parse_identity_stamp("hi\n\nYou are late."), None);
    // A post-bl-6920, hand-typed, or foreign root carries no stamp at all.
    assert_eq!(parse_identity_stamp("just do the thing"), None);
    // A real name is one token and the line ends in the period the compose emitted.
    assert_eq!(parse_identity_stamp("You are two words."), None);
    assert_eq!(parse_identity_stamp("You are ."), None);
    assert_eq!(parse_identity_stamp("You are cobalt-gecko"), None);
}

/// The legacy stamp's other inverse (§3.3): what the payload was before the
/// pre-bl-6920 harness stamped it — the string the display ladder's second rung
/// is drawn from, which is why rungs one and two can never be the same line.
/// A goal with no stamp — every new root — is its own payload, verbatim.
#[test]
fn strip_identity_stamp_gives_back_the_payload_the_stamp_was_prepended_to() {
    let goal = "You are cobalt-gecko.\n\nBall bl-1: fix\n\nbody";
    assert_eq!(strip_identity_stamp(goal), "Ball bl-1: fix\n\nbody");
    // No stamp (post-bl-6920 / foreign / hand-typed): the goal verbatim.
    assert_eq!(
        strip_identity_stamp("just do the thing"),
        "just do the thing"
    );
    assert_eq!(
        strip_identity_stamp("hi\n\nYou are late."),
        "hi\n\nYou are late."
    );
    // A stamp and nothing else: an empty payload, not a stray identity line.
    assert_eq!(strip_identity_stamp("You are cobalt-gecko."), "");
}

/// The conversation mint scans past the names its workspace's living agents
/// wear (§3.3) — the occupied set is per-workspace, and nothing wider.
#[test]
fn mint_conversation_skips_the_workspaces_occupied_names() {
    let first = mint_conversation(&[], &mut super::rng()).unwrap();
    assert!(!first.contains('-'), "one word, no compound (bl-d12f)");
    let second = mint_conversation(std::slice::from_ref(&first), &mut super::rng()).unwrap();
    assert_ne!(second, first, "an occupied name is scanned past");
}