sprawling-runtime 0.0.10

One run of a sprawling resident, from dispatch to freeze: turns, tools, replay and the sandbox that executes code.
Documentation
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
// Copyright (c) 2026 2youg1 and the sprawling contributors

#![allow(
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::panic,
    clippy::indexing_slicing,
    clippy::as_conversions,
    clippy::arithmetic_side_effects,
    reason = "test code"
)]

use super::*;
use kernel::{ClockStampGranularity, Temporal, TimeMs};
use storage::Cas;

pub(super) fn no_offload(cap: u64) -> PackContext<'static> {
    PackContext {
        cap_bytes: cap,
        stamp: None,
        net_notice: false,
        steer: None,
        reminder: None,
        offload: None,
        sieve: None,
        adviser: None,
    }
}

#[test]
fn small_results_pass_intact_with_zero_envelope_bytes() {
    let out = package(b"{\"ok\":true}", no_offload(4_096)).unwrap();
    assert_eq!(out.content, "{\"ok\":true}");
    assert!(out.events.is_empty(), "A18 spirit: no feature, no bytes");
}

#[test]
fn oversized_but_small_results_truncate_without_storing() {
    let prose = "The first sentence says what this result is about. ".repeat(40);
    let out = package(prose.as_bytes(), no_offload(100)).unwrap();
    assert!(out.content.starts_with("The first sentence"));
    assert!(out.content.contains("[truncated: "));
    assert!(
        out.events.is_empty(),
        "invariant 3: lossy-without-restore stores nothing"
    );
}

#[test]
fn a_log_keeps_the_end_a_reader_needs_rather_than_the_beginning() {
    let mut log = String::new();
    for n in 0..400 {
        log.push_str(&format!(
            "2026-08-22T10:00:00Z line {n}
"
        ));
    }
    let out = package(log.as_bytes(), no_offload(400)).unwrap();
    assert!(
        out.content.contains("line 399"),
        "a log's last line is the one somebody is looking for: {}",
        out.content
    );
    assert!(
        out.content.contains("[truncated:"),
        "and it is never silent"
    );
}

/// A result that cannot be shortened and has nowhere to go is refused,
/// rather than cut on a byte and handed to the model looking whole.
///
/// The byte cut this replaces produced `{"rows":[1,1,1,[truncated: N
/// bytes]`, which parses as nothing and reads as a document.
#[test]
fn structured_content_with_nowhere_to_go_is_refused_rather_than_cut() {
    let json = format!("{{\"rows\":[{}]}}", "1,".repeat(500));
    let Err(refused) = package(json.as_bytes(), no_offload(100)) else {
        panic!("a structured result with nowhere to go is refused");
    };
    assert_eq!(refused.code(), &kernel::AxCode::InvalidArgs);
    assert!(
        refused.recovery().contains("smaller part"),
        "the refusal says what to do instead: {}",
        refused.recovery()
    );
}

/// Binary is material nothing can read the shape of, so it takes the
/// same road as structured data: whole into the store, or refused.
#[test]
fn bytes_that_are_not_text_are_stored_whole_rather_than_cut() {
    let dir = tempfile::tempdir().unwrap();
    let mut cas = Cas::open(&dir.path().join("cas")).unwrap();
    let env = dir.path().join("env");
    std::fs::create_dir_all(&env).unwrap();
    let binary = vec![0xffu8; 9_000];
    let out = package(
        &binary,
        PackContext {
            cap_bytes: 1_024,
            stamp: None,
            net_notice: false,
            steer: None,
            reminder: None,
            offload: Some(OffloadSite {
                cas: &mut cas,
                city_root: &env,
                room: &kernel::Address::parse("room").unwrap(),
                origin: crate::offload::tests::origin(),
            }),
            sieve: None,
            adviser: None,
        },
    )
    .unwrap();
    assert_eq!(out.events.len(), 1, "it left the window whole");
    assert!(package(&binary, no_offload(1_024)).is_err());
}

#[test]
fn large_results_offload_first_and_account_it() {
    let dir = tempfile::tempdir().unwrap();
    let mut cas = Cas::open(&dir.path().join("cas")).unwrap();
    let env = dir.path().join("env");
    std::fs::create_dir_all(&env).unwrap();
    let big = vec![b'z'; 20_000];
    let out = package(
        &big,
        PackContext {
            cap_bytes: 1_024,
            stamp: None,
            net_notice: false,
            steer: None,
            reminder: None,
            offload: Some(OffloadSite {
                cas: &mut cas,
                city_root: &env,
                room: &kernel::Address::parse("room").unwrap(),
                origin: crate::offload::tests::origin(),
            }),
            sieve: None,
            adviser: None,
        },
    )
    .unwrap();
    assert!(out.content.contains("[offloaded: total 20000 bytes"));
    assert_eq!(out.events.len(), 1);
    let event = serde_json::to_value(&out.events[0]).unwrap();
    assert!(event["original"].as_str().unwrap().starts_with("cas:b3-"));
    assert_eq!(event["len"], 20_000);
}

#[test]
fn an_exec_result_is_sieved_before_it_is_packaged() {
    let dir = tempfile::tempdir().unwrap();
    let mut cas = Cas::open(&dir.path().join("cas")).unwrap();
    let env = dir.path().join("env");
    std::fs::create_dir_all(&env).unwrap();
    let table = FilterTable::builtin();
    let mut history = SieveHistory::default();
    let noise = "   Compiling dep v0.1.0\n".repeat(200);
    let out = package(
        noise.as_bytes(),
        PackContext {
            cap_bytes: 16_384,
            stamp: None,
            net_notice: false,
            steer: None,
            reminder: None,
            offload: Some(OffloadSite {
                cas: &mut cas,
                city_root: &env,
                room: &kernel::Address::parse("room").unwrap(),
                origin: crate::offload::tests::origin(),
            }),
            sieve: Some(SieveRequest {
                key: CommandKey::of(&kernel::ExecArm::Program {
                    path: "cargo".to_owned(),
                    args: vec!["check".to_owned()],
                }),
                exit_code: Some(0),
                table: &table,
                history: &mut history,
            }),
            adviser: None,
        },
    )
    .unwrap();
    assert!(
        out.content.starts_with("cargo check: clean, exit 0"),
        "{}",
        out.content
    );
    assert_eq!(out.events.len(), 1, "the tee is accounted");
    let event = serde_json::to_value(&out.events[0]).unwrap();
    assert_eq!(event["filter"], "cargo");
}

#[test]
fn the_three_attachments_ride_in_order_and_off_means_zero_bytes() {
    let mut gate = crate::clock::StampGate::new(ClockStampGranularity::Minute, Vec::new());
    let stamp = gate
        .observe(TimeMs::new(90_000), Temporal::Timestamped)
        .unwrap();
    let out = package(
        b"done",
        PackContext {
            cap_bytes: 4_096,
            stamp,
            net_notice: true,
            steer: Some(("user".to_owned(), "wrap up".to_owned())),
            reminder: None,
            offload: None,
            sieve: None,
            adviser: None,
        },
    )
    .unwrap();
    let lines: Vec<&str> = out.content.lines().collect();
    assert_eq!(lines[0], "done");
    assert_eq!(lines[1], "clock: 1970-01-01T00:01:30Z;");
    assert!(lines[2].starts_with("[net] "));
    assert_eq!(lines[3], "user: wrap up");
    // Off gate: byte-identical to the featureless envelope (A18).
    let mut off = crate::clock::StampGate::new(ClockStampGranularity::Off, Vec::new());
    let none = off
        .observe(TimeMs::new(90_000), Temporal::Timestamped)
        .unwrap();
    let plain = package(
        b"done",
        PackContext {
            cap_bytes: 4_096,
            stamp: none,
            net_notice: false,
            steer: None,
            reminder: None,
            offload: None,
            sieve: None,
            adviser: None,
        },
    )
    .unwrap();
    assert_eq!(plain.content, "done");
}

#[test]
fn an_overlong_attachment_is_cut_at_the_attachment_cap() {
    let noisy = "s".repeat(5_000);
    let out = package(
        b"ok",
        PackContext {
            cap_bytes: 4_096,
            stamp: None,
            net_notice: false,
            steer: Some(("user".to_owned(), noisy)),
            reminder: None,
            offload: None,
            sieve: None,
            adviser: None,
        },
    )
    .unwrap();
    assert!(out.content.len() < 2 + 1 + ENVELOPE_ATTACH_MAX_BYTES + 40);
    assert!(out.content.contains("[truncated: "));
}

/// A sieve pass that later leaves the window through the plain store
/// keeps the seven stage reports instead of being accounted as "never
/// sieved".
#[test]
fn a_sieved_pass_that_leaves_carries_its_stage_account() {
    let dir = tempfile::tempdir().unwrap();
    let mut cas = Cas::open(&dir.path().join("cas")).unwrap();
    let env = dir.path().join("env");
    std::fs::create_dir_all(&env).unwrap();
    let table = FilterTable::builtin();
    let mut history = SieveHistory::default();
    let text: String = (0..200)
        .map(|n| {
            let first = char::from(b'a' + (n % 26) as u8);
            let second = char::from(b'a' + (n / 26) as u8);
            let third = char::from(b'a' + ((n / 676) % 26) as u8);
            format!(
                "record {first}{second}{third} stands alone here {} \n",
                "and keeps going ".repeat(6)
            )
        })
        .collect();
    assert!(
        text.len() > 16_384,
        "the store has to be worth it: {}",
        text.len()
    );
    let out = package(
        text.as_bytes(),
        PackContext {
            cap_bytes: 1_024,
            stamp: None,
            net_notice: false,
            steer: None,
            reminder: None,
            offload: Some(OffloadSite {
                cas: &mut cas,
                city_root: &env,
                room: &kernel::Address::parse("room").unwrap(),
                origin: crate::offload::tests::origin(),
            }),
            sieve: Some(SieveRequest {
                key: CommandKey::of(&kernel::ExecArm::Program {
                    path: "ls".to_owned(),
                    args: Vec::new(),
                }),
                exit_code: Some(0),
                table: &table,
                history: &mut history,
            }),
            adviser: None,
        },
    )
    .unwrap();
    assert_eq!(out.events.len(), 1, "the result left through the store");
    let event = serde_json::to_value(&out.events[0]).unwrap();
    assert_eq!(event["filter"], "generic");
    assert_eq!(
        event["stages"].as_array().map(Vec::len),
        Some(7),
        "a pass accounts every stage it ran: {event}"
    );
}