Luigit
repositories / smith

smith

There are many coding harnesses - but this one is fast

owned by admin

smith-harness/src/observer.rs

Raw
//! Interactive observer: worker-owned bounded snapshots, no agent or provider (`SMH-SPEC-SPEC0001`, Observer mode).
use smith::config::Config;
use smith::error::{Result, SmithError};
use smith::id::{EntryId, SessionId};
use smith::tool::CancelHandle;
use smith_alloc::{Scope, enter};
use smith_core::content_codec::{BlockView, EntryContentView};
use smith_core::session::EntryFrame;
use smith_core::store::SessionReader;
use smith_ui::{Observer, ROW_BYTES, ROWS, Row};
use std::path::{Path, PathBuf};
use std::sync::mpsc::{self, SyncSender};
use std::time::Duration;

#[expect(
    clippy::needless_pass_by_value,
    reason = "convert owned errors before discarding them"
)]
fn fault(code: smith::error::SessionCode, message: impl ToString) -> SmithError {
    SmithError::Session {
        code,
        message: message.to_string(),
    }
}

enum Request {
    Fetch {
        generation: u64,
        start: usize,
        follow: bool,
        search: Option<String>,
    },
    Fork(EntryId),
    Export(PathBuf),
    Status,
}
impl Request {
    const fn snapshot(ui: &Observer, generation: u64) -> Self {
        Self::Fetch {
            generation,
            start: ui.start,
            follow: ui.follow,
            search: None,
        }
    }
}

enum Response {
    Snapshot { generation: u64, snapshot: Snapshot },
    Forked(SessionId),
    Exported(PathBuf),
    Status(bool),
}
struct Snapshot {
    total: usize,
    writer_active: bool,
    rows: Vec<Row>,
    found: Option<(usize, EntryId)>,
    visible_tip: Option<EntryId>,
}

/// Local identity of the snapshot requested by the frontend.
/// A response may update visible data only when its generation still matches.
#[derive(Default)]
struct SnapshotState {
    generation: u64,
    published_generation: Option<u64>,
    visible_tip: Option<EntryId>,
}

impl SnapshotState {
    const fn invalidate(&mut self) {
        self.generation = self.generation.wrapping_add(1);
        self.published_generation = None;
        self.visible_tip = None;
    }

    fn publish(&mut self, ui: &mut Observer, generation: u64, snapshot: Snapshot) -> bool {
        if generation != self.generation {
            return false;
        }
        self.published_generation = Some(generation);
        self.visible_tip = snapshot.visible_tip;
        ui.publish(snapshot.total, snapshot.writer_active, snapshot.rows);
        true
    }

    fn refresh_needed(&self) -> bool {
        self.published_generation != Some(self.generation)
    }

    const fn fork_target(&self) -> Option<EntryId> {
        self.visible_tip
    }
}

fn next_snapshot_request(
    ui: &Observer,
    snapshots: &SnapshotState,
    initialized: bool,
    queued: &mut Option<Request>,
) -> Option<Request> {
    queued.take().or_else(|| {
        if ui.follow || !initialized || snapshots.refresh_needed() {
            Some(Request::snapshot(ui, snapshots.generation))
        } else {
            None
        }
    })
}

fn clipped(text: &str, budget: usize) -> String {
    let mut line = String::with_capacity(budget.min(text.len()));
    for character in text.chars() {
        let safe = if character.is_control() {
            ' '
        } else {
            character
        };
        if line.len() + safe.len_utf8() > budget {
            if budget >= 3 {
                while line.len() + 3 > budget {
                    line.pop();
                }
                line.push('…');
            }
            break;
        }
        line.push(safe);
    }
    line
}

fn append_preview(line: &mut String, text: &str) {
    let remaining = ROW_BYTES.saturating_sub(line.len());
    if remaining != 0 {
        line.push_str(&clipped(text, remaining));
    }
}

fn row(entry: &EntryFrame) -> Result<Row> {
    let content = EntryContentView::decode(&entry.content)?;
    let mut text = match &content {
        EntryContentView::Message(message) => format!("{:?}: ", message.role),
        EntryContentView::ToolCall { .. } => "ToolCall: ".into(),
        EntryContentView::ToolResult { .. } => "ToolResult: ".into(),
        EntryContentView::Meta { .. } => "Meta: ".into(),
    };
    match &content {
        EntryContentView::Message(message) => {
            for (index, block) in message.blocks().enumerate() {
                if index != 0 {
                    append_preview(&mut text, " | ");
                }
                append_preview(
                    &mut text,
                    match block {
                        BlockView::Text(text) | BlockView::Thinking(text) => text,
                        BlockView::ToolResult { output, .. } => output,
                        BlockView::ToolUse { name, .. } => name,
                    },
                );
            }
        }
        EntryContentView::ToolCall { name, .. } => append_preview(&mut text, name),
        EntryContentView::ToolResult { output, .. } => append_preview(&mut text, output),
        EntryContentView::Meta { kind, .. } => append_preview(&mut text, kind),
    }
    Ok(Row {
        id: entry.id.to_string(),
        text,
    })
}

fn fetch(
    path: &Path,
    start: usize,
    follow: bool,
    search: Option<&str>,
    cancel: &CancelHandle,
) -> Result<Snapshot> {
    if cancel.is_cancelled() {
        return Err(SmithError::Cancelled);
    }
    let reader = SessionReader::open_cancelled(path, cancel)?;
    let max = Config::default_valid().frame_bytes_max;
    let tip = reader.selected_tip_cancelled(max, cancel)?;
    let mut rows = Vec::with_capacity(ROWS);
    let mut total = 0;
    let mut found = None;
    let mut visible_tip = None;
    if let Some(tip) = tip {
        reader.replay_at_cancelled(tip, max, cancel, |entry| {
            if let Some(term) = search
                && EntryContentView::decode(&entry.content)?.contains(term)
            {
                found = Some((total, entry.id));
            }
            if follow {
                if rows.len() == ROWS {
                    rows.remove(0);
                }
                rows.push(row(&entry)?);
                visible_tip = Some(entry.id);
            } else if total >= start && rows.len() < ROWS {
                rows.push(row(&entry)?);
                visible_tip = Some(entry.id);
            }
            total += 1;
            Ok(())
        })?;
    }
    Ok(Snapshot {
        total,
        writer_active: reader.writer_active(),
        rows,
        found,
        visible_tip,
    })
}

fn export(path: &Path, target: &Path, id: SessionId, cancel: &CancelHandle) -> Result<()> {
    if cancel.is_cancelled() {
        return Err(SmithError::Cancelled);
    }
    let reader = SessionReader::open_cancelled(path, cancel)?;
    let tip = reader.selected_tip_cancelled(Config::default_valid().frame_bytes_max, cancel)?;
    let mut out = std::fs::OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(target)
        .map_err(|error| fault(smith::error::SessionCode::ObserverExport, error))?;
    let result = tip
        .map(|tip| {
            reader.replay_at_cancelled(
                tip,
                Config::default_valid().frame_bytes_max,
                cancel,
                |entry| {
                    let view = EntryContentView::decode(&entry.content)?;
                    crate::inspection::output(&mut out, id, &entry, &view, true, true)
                        .map_err(|error| fault(smith::error::SessionCode::ObserverExport, error))
                },
            )
        })
        .transpose();
    if let Err(error) = result.and_then(|_| {
        out.sync_all()
            .map_err(|error| fault(smith::error::SessionCode::ObserverExport, error))
    }) {
        drop(out);
        // Preserve the export failure; unpublished output removal is best-effort cleanup.
        let _cleanup_result: std::io::Result<()> = std::fs::remove_file(target);
        return Err(error);
    }
    Ok(())
}

fn work(path: &Path, id: SessionId, request: Request, cancel: &CancelHandle) -> Result<Response> {
    match request {
        Request::Fetch {
            generation,
            start,
            follow,
            search,
        } => fetch(path, start, follow, search.as_deref(), cancel).map(|snapshot| {
            Response::Snapshot {
                generation,
                snapshot,
            }
        }),
        Request::Fork(at) => {
            if cancel.is_cancelled() {
                return Err(SmithError::Cancelled);
            }
            let target_id = SessionId::new();
            let target = path.with_file_name(format!("{target_id}.smh"));
            let opened = SessionReader::open_cancelled(path, cancel)?.fork_at_cancelled(
                at,
                &target,
                Config::default_valid(),
                cancel,
            )?;
            drop(opened);
            Ok(Response::Forked(target_id))
        }
        Request::Export(target) => {
            export(path, &target, id, cancel)?;
            Ok(Response::Exported(target))
        }
        Request::Status => smith_core::store::writer_active(path).map(Response::Status),
    }
}

fn serve(
    path: &Path,
    id: SessionId,
    receiver: &mpsc::Receiver<Request>,
    responses: &SyncSender<Result<Response>>,
    cancel: &CancelHandle,
) {
    while let Ok(request) = receiver.recv() {
        let _request = enter(Scope::IoRequest);
        if cancel.is_cancelled() || responses.send(work(path, id, request, cancel)).is_err() {
            break;
        }
    }
}

/// Attach by session identity, reading immutable snapshots on a dedicated worker.
///
/// `export_path` must be explicitly supplied for export; never overwrites a file.
/// Exiting or losing a writer never promotes this observer.
///
/// # Errors
/// Returns terminal or storage faults. The alternate screen is restored on errors.
pub fn run(id: SessionId, path: PathBuf, export_path: Option<&PathBuf>) -> Result<()> {
    let (requests, receiver) = mpsc::sync_channel::<Request>(1);
    let (responses, results) = mpsc::sync_channel::<Result<Response>>(1);
    let cancel = CancelHandle::new();
    let worker_cancel = cancel.clone();
    let thread = std::thread::spawn(move || {
        let _session = enter(Scope::Session);
        serve(&path, id, &receiver, &responses, &worker_cancel);
    });
    let result = interact(id, requests, &results, export_path, &cancel);
    cancel.cancel();
    let joined = thread.join().map_err(|_| {
        fault(
            smith::error::SessionCode::ObserverWorker,
            "storage worker panicked",
        )
    });
    match (result, joined) {
        (Ok(()), Ok(())) => Ok(()),
        (Err(error), Ok(())) | (Ok(()), Err(error)) => Err(error),
        (Err(error), Err(worker)) => Err(fault(
            smith::error::SessionCode::ObserverShutdown,
            format!("{error}; {worker}"),
        )),
    }
}

fn interact(
    id: SessionId,
    requests: SyncSender<Request>,
    results: &mpsc::Receiver<Result<Response>>,
    export_path: Option<&PathBuf>,
    cancel: &CancelHandle,
) -> Result<()> {
    let mut screen = smith_tui::Screen::open()
        .map_err(|e| fault(smith::error::SessionCode::ObserverTerminal, e))?;
    let result = event_loop(id, requests, results, export_path, cancel, &mut screen);
    let cleanup = screen
        .close()
        .map_err(|e| fault(smith::error::SessionCode::ObserverTerminal, e));
    match (result, cleanup) {
        (Ok(()), Ok(())) => Ok(()),
        (Err(error), Ok(())) | (Ok(()), Err(error)) => Err(error),
        (Err(error), Err(cleanup)) => Err(fault(
            smith::error::SessionCode::ObserverShutdown,
            format!("{error}; {cleanup}"),
        )),
    }
}

#[expect(
    clippy::too_many_lines,
    reason = "one terminal event loop owns all frontend transitions"
)]
fn event_loop(
    id: SessionId,
    requests: SyncSender<Request>,
    results: &mpsc::Receiver<Result<Response>>,
    export_path: Option<&PathBuf>,
    cancel: &CancelHandle,
    screen: &mut smith_tui::Screen,
) -> Result<()> {
    let session_label = id.to_string();
    let mut ui = Observer::default();
    let mut input = false;
    let mut pending = false;
    let mut initialized = false;
    let mut snapshots = SnapshotState::default();
    let mut search_request = None;
    let mut last_status = std::time::Instant::now();
    loop {
        if !pending {
            let request = next_snapshot_request(&ui, &snapshots, initialized, &mut search_request)
                .or_else(|| {
                    if last_status.elapsed() >= Duration::from_secs(1) {
                        last_status = std::time::Instant::now();
                        Some(Request::Status)
                    } else {
                        None
                    }
                });
            if let Some(request) = request {
                requests
                    .send(request)
                    .map_err(|e| fault(smith::error::SessionCode::ObserverWorker, e))?;
                pending = true;
            }
        }
        screen
            .draw(&session_label, &ui, input)
            .map_err(|e| fault(smith::error::SessionCode::ObserverTerminal, e))?;
        match results.try_recv() {
            Ok(Ok(Response::Snapshot {
                generation,
                snapshot,
            })) => {
                pending = false;
                if generation != snapshots.generation {
                    continue;
                }
                initialized = true;
                if let Some((index, found_id)) = snapshot.found {
                    ui.found = Some(found_id.to_string());
                    ui.start = index;
                    snapshots.invalidate();
                    search_request = Some(Request::snapshot(&ui, snapshots.generation));
                } else if !ui.search.is_empty() && ui.found.is_none() {
                    ui.notice = "No matching entry".into();
                } else {
                    snapshots.publish(&mut ui, generation, snapshot);
                }
            }
            Ok(Ok(Response::Forked(new_id))) => {
                pending = false;
                ui.notice = format!(
                    "Fork created: {new_id}. Resume with smith eval --session {new_id} <prompt>"
                );
            }
            Ok(Ok(Response::Exported(target))) => {
                pending = false;
                ui.notice = clipped(&format!("Exported to {}", target.display()), ROW_BYTES);
            }
            Ok(Ok(Response::Status(active))) => {
                pending = false;
                ui.status_known = true;
                ui.writer_active = active;
            }
            Ok(Err(SmithError::Cancelled)) => {
                pending = false;
            }
            Ok(Err(e)) => {
                pending = false;
                ui.notice = clipped(&format!("Error: {e}"), ROW_BYTES);
            }
            Err(mpsc::TryRecvError::Disconnected) => {
                return Err(fault(
                    smith::error::SessionCode::ObserverWorker,
                    "storage worker stopped",
                ));
            }
            Err(mpsc::TryRecvError::Empty) => {}
        }
        match smith_tui::next_input(Duration::from_millis(150))
            .map_err(|e| fault(smith::error::SessionCode::ObserverTerminal, e))?
        {
            Some(smith_tui::Input::Key(key)) => {
                use smith_tui::Key;
                if input {
                    match key {
                        Key::Escape | Key::Interrupt => {
                            input = false;
                            ui.search.clear();
                        }
                        Key::Enter => {
                            input = false;
                            ui.follow = false;
                            ui.found = None;
                            snapshots.invalidate();
                            search_request = Some(Request::Fetch {
                                generation: snapshots.generation,
                                start: ui.start,
                                follow: false,
                                search: Some(ui.search.clone()),
                            });
                        }
                        Key::Backspace => {
                            ui.search.pop();
                        }
                        Key::Char(c) if ui.search.len() < 128 => ui.search.push(c),
                        _ => {}
                    }
                } else {
                    match key {
                        Key::Char('q') | Key::Escape | Key::Interrupt => {
                            cancel.cancel();
                            break;
                        }
                        Key::PageUp | Key::Char('b') => {
                            ui.back();
                            snapshots.invalidate();
                            search_request = Some(Request::snapshot(&ui, snapshots.generation));
                        }
                        Key::PageDown | Key::Char('n') => {
                            ui.forward();
                            snapshots.invalidate();
                            search_request = Some(Request::snapshot(&ui, snapshots.generation));
                        }
                        Key::Char('f') => {
                            ui.toggle_follow();
                            snapshots.invalidate();
                            search_request = Some(Request::snapshot(&ui, snapshots.generation));
                        }
                        Key::Char('r') => {
                            snapshots.invalidate();
                            search_request = Some(Request::snapshot(&ui, snapshots.generation));
                        }
                        Key::Char('/') => {
                            ui.search.clear();
                            input = true;
                        }
                        Key::Char('k') => {
                            if let Some(at) = snapshots.fork_target() {
                                search_request = Some(Request::Fork(at));
                            } else {
                                ui.notice = "No visible entry to fork; wait for snapshot".into();
                            }
                        }
                        Key::Char('e') => {
                            if let Some(target) = &export_path {
                                search_request = Some(Request::Export((*target).clone()));
                            } else {
                                ui.notice = "Export requires --export PATH".into();
                            }
                        }
                        Key::Enter | Key::Char(_) => {
                            ui.notice = "READ ONLY: prompt submission disabled".into();
                        }
                        Key::Backspace => {}
                    }
                }
            }
            Some(smith_tui::Input::Resize) | None => {}
        }
    }
    drop(requests);
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use smith_alloc::Scope;
    use std::io::Write;

    const SMALL_ENTRIES: usize = 4;
    const LARGE_ENTRIES: usize = 128;
    const PAYLOAD_BYTES: usize = 32 * 1024;

    fn observed_history(
        path: &Path,
        entries: usize,
        tag: &str,
    ) -> (SessionId, smith_core::store::SessionWriter) {
        use smith::message::{Message, Role};
        use smith_core::frame::Frame;
        use smith_core::session::{EntryContent, Session};
        use smith_core::store::SessionWriter;

        let session = Session::new();
        let mut writer = SessionWriter::open(path, Config::default_valid()).unwrap();
        writer
            .append_frame(&Frame::Header {
                header: session.header(),
            })
            .unwrap();
        let mut tip = None;
        for index in 0..entries {
            let content = if index % 2 == 0 {
                EntryContent::Message(Message::with_text(
                    Role::Assistant,
                    format!("visible needle {tag} {index} {}", "x".repeat(PAYLOAD_BYTES)),
                ))
            } else {
                EntryContent::Meta {
                    kind: "event".into(),
                    detail: smith::StructuredData::from_serializable(&serde_json::json!({
                        "needle": tag,
                        "payload": "x".repeat(PAYLOAD_BYTES),
                        "nested": [{"values": [true, 0, null]}],
                    }))
                    .unwrap(),
                }
            };
            let entry = EntryFrame::new(tip, &content).unwrap();
            tip = Some(entry.id);
            writer.append_frame(&Frame::Known { entry }).unwrap();
        }
        writer.select_entry(tip.unwrap()).unwrap();
        (session.id(), writer)
    }

    fn worker_request(
        path: PathBuf,
        id: SessionId,
        request: Request,
    ) -> (Response, smith_alloc::Stats) {
        let (requests, receiver) = mpsc::sync_channel(1);
        let (responses, results) = mpsc::sync_channel(1);
        let before = smith_alloc::snapshot(Scope::IoRequest);
        let thread = std::thread::spawn(move || {
            let cancel = CancelHandle::new();
            serve(&path, id, &receiver, &responses, &cancel);
        });
        requests.send(request).unwrap();
        drop(requests);
        let response = results.recv_timeout(Duration::from_secs(5)).unwrap();
        thread.join().unwrap();
        let after = smith_alloc::snapshot(Scope::IoRequest);
        (
            response.unwrap(),
            smith_alloc::Stats {
                allocations: after.allocations - before.allocations,
                bytes: after.bytes - before.bytes,
                live: after.live,
                peak: after.peak,
            },
        )
    }

    fn observer_cost(
        path: &Path,
        id: SessionId,
        entries: usize,
        target: &Path,
    ) -> (smith_alloc::Stats, EntryId) {
        let (response, fetch_cost) = worker_request(
            path.to_path_buf(),
            id,
            Request::Fetch {
                generation: 0,
                start: entries.saturating_sub(ROWS),
                follow: false,
                search: Some("needle".into()),
            },
        );
        let Response::Snapshot { snapshot, .. } = response else {
            panic!("expected observer snapshot")
        };
        assert_eq!(snapshot.total, entries);
        assert_eq!(snapshot.rows.len(), entries.min(ROWS));
        assert!(snapshot.found.is_some());
        let fork_at = snapshot.visible_tip.unwrap();
        let retained = fetch_cost.live;
        drop(snapshot);
        let released = smith_alloc::snapshot(Scope::IoRequest).live;
        assert!(
            fetch_cost.allocations > 0 && retained != released,
            "fetch response retention must be visible in IoRequest accounting"
        );
        let (response, export_cost) = worker_request(
            path.to_path_buf(),
            id,
            Request::Export(target.to_path_buf()),
        );
        assert!(matches!(response, Response::Exported(_)));
        assert!(
            fetch_cost.allocations > 0 && export_cost.allocations > 0,
            "production observer fetch and export requests must charge allocations to IoRequest"
        );
        (
            smith_alloc::Stats {
                allocations: fetch_cost.allocations + export_cost.allocations,
                bytes: fetch_cost.bytes + export_cost.bytes,
                live: fetch_cost.live.max(export_cost.live),
                peak: fetch_cost.peak.max(export_cost.peak),
            },
            fork_at,
        )
    }

    fn snapshot(id: EntryId, row: &str) -> Snapshot {
        Snapshot {
            total: 24,
            writer_active: true,
            rows: vec![Row {
                id: id.to_string(),
                text: row.into(),
            }],
            found: None,
            visible_tip: Some(id),
        }
    }

    #[cfg(target_arch = "x86_64")]
    #[test]
    fn snapshot_state_stays_within_one_cache_line() {
        assert_eq!(std::mem::size_of::<SnapshotState>(), 48);
    }

    #[test]
    fn stale_snapshot_after_navigation_cannot_replace_rows_or_fork_target() {
        let initial = EntryId::new();
        let stale = EntryId::new();
        let current = EntryId::new();
        let mut ui = Observer::default();
        let mut state = SnapshotState::default();
        assert!(state.publish(&mut ui, 0, snapshot(initial, "initial")));
        ui.forward();
        state.invalidate();
        let old_generation = state.generation;
        ui.back();
        state.invalidate();
        assert!(!state.publish(&mut ui, old_generation, snapshot(stale, "stale")));
        assert_eq!(ui.start, 0);
        assert_eq!(ui.rows[0].text, "initial");
        assert_eq!(state.fork_target(), None);
        assert!(state.publish(&mut ui, state.generation, snapshot(current, "current")));
        assert_eq!(ui.rows[0].text, "current");
        assert_eq!(state.fork_target(), Some(current));
    }

    #[test]
    fn export_after_navigation_requeues_current_snapshot_before_fork() {
        let old = EntryId::new();
        let current = EntryId::new();
        let mut ui = Observer::default();
        let mut state = SnapshotState::default();
        let mut queued = Some(Request::snapshot(&ui, state.generation));
        let stale_generation = match queued.take().unwrap() {
            Request::Fetch { generation, .. } => generation,
            _ => unreachable!(),
        };
        ui.back();
        state.invalidate();
        queued = Some(Request::snapshot(&ui, state.generation));
        assert!(matches!(queued, Some(Request::Fetch { .. })));
        queued = Some(Request::Export(PathBuf::from("transcript.json")));
        assert!(matches!(queued, Some(Request::Export(_))));
        queued = Some(Request::Export(PathBuf::from("latest-transcript.json")));
        assert!(matches!(queued.take(), Some(Request::Export(_))));
        assert!(!state.publish(&mut ui, stale_generation, snapshot(old, "stale")));
        assert!(state.refresh_needed());
        let Request::Fetch { generation, .. } =
            next_snapshot_request(&ui, &state, true, &mut queued)
                .expect("export completion must requeue the invalidated snapshot")
        else {
            unreachable!()
        };
        assert!(state.publish(&mut ui, generation, snapshot(current, "current")));
        assert_eq!(state.fork_target(), Some(current));
    }

    #[test]
    fn published_empty_snapshot_does_not_request_again_while_browsing() {
        let mut ui = Observer::default();
        let mut state = SnapshotState::default();
        assert!(state.publish(
            &mut ui,
            state.generation,
            Snapshot {
                total: 0,
                writer_active: false,
                rows: Vec::new(),
                found: None,
                visible_tip: None,
            },
        ));
        assert!(!state.refresh_needed());
        let mut queued = None;
        assert!(next_snapshot_request(&ui, &state, true, &mut queued).is_none());
    }

    #[test]
    fn multi_block_message_preview_retains_order_within_row_budget() {
        use smith::message::{ContentBlock, Message, Role};
        use smith_core::session::EntryContent;
        let mut message = Message::with_text(Role::Assistant, "first");
        message.add_block(ContentBlock::thinking("second"));
        message.add_block(ContentBlock::text("third"));
        let entry = EntryFrame::new(None, &EntryContent::Message(message)).unwrap();
        let row = row(&entry).unwrap();
        assert!(row.text.contains("first | second | third"));
        assert!(row.text.len() <= ROW_BYTES);
    }

    #[test]
    fn observer_snapshots_follow_append_and_fork_without_mutating_source() {
        use smith::message::{Message, Role};
        use smith_core::session::{EntryContent, Session};
        use smith_core::store::SessionWriter;
        let dir =
            std::env::temp_dir().join(format!("smith-observer-worker-{}", std::process::id()));
        std::fs::create_dir_all(&dir).unwrap();
        let session = Session::new();
        let path = dir.join(format!("{}.smh", session.id()));
        let mut writer = SessionWriter::open(&path, Config::default_valid()).unwrap();
        writer
            .append_frame(&smith_core::frame::Frame::Header {
                header: session.header(),
            })
            .unwrap();
        let first = EntryFrame::new(
            None,
            &EntryContent::Message(Message::with_text(Role::User, "first")),
        )
        .unwrap();
        writer
            .append_entry(
                &smith_core::session::Entry {
                    id: first.id,
                    parent: first.parent,
                    timestamp_ms: first.timestamp_ms,
                    kind: first.kind,
                    content: smith_core::session::Span { offset: 0, len: 0 },
                },
                &first.content,
            )
            .unwrap();
        let cancel = CancelHandle::new();
        let initial = fetch(&path, 0, false, None, &cancel).unwrap();
        assert!(initial.writer_active);
        assert_eq!(initial.rows.len(), 1);
        let next = EntryFrame::new(
            Some(first.id),
            &EntryContent::Message(Message::with_text(Role::Assistant, "second")),
        )
        .unwrap();
        writer
            .append_entry(
                &smith_core::session::Entry {
                    id: next.id,
                    parent: next.parent,
                    timestamp_ms: next.timestamp_ms,
                    kind: next.kind,
                    content: smith_core::session::Span { offset: 0, len: 0 },
                },
                &next.content,
            )
            .unwrap();
        let live = fetch(&path, 0, true, Some("second"), &cancel).unwrap();
        assert_eq!(
            fetch(&path, 0, false, None, &cancel).unwrap().visible_tip,
            Some(next.id)
        );
        assert_eq!(live.total, 2);
        assert_eq!(live.found, Some((1, next.id)));
        assert!(live.rows.last().unwrap().text.contains("second"));
        let before = std::fs::read(&path).unwrap();
        let Response::Forked(new_id) =
            work(&path, session.id(), Request::Fork(first.id), &cancel).unwrap()
        else {
            panic!("expected fork")
        };
        let fork_path = dir.join(format!("{new_id}.smh"));
        assert_eq!(fetch(&fork_path, 0, true, None, &cancel).unwrap().total, 1);
        assert_eq!(std::fs::read(&path).unwrap(), before);
        drop(writer);
        assert!(!fetch(&path, 0, false, None, &cancel).unwrap().writer_active);
        let Response::Status(active) = work(&path, session.id(), Request::Status, &cancel).unwrap()
        else {
            panic!("expected status")
        };
        assert!(!active);
        assert_eq!(fetch(&fork_path, 0, true, None, &cancel).unwrap().total, 1);
        let _ = std::fs::remove_dir_all(dir);
    }

    #[test]
    fn observer_visible_window_and_export_peak_ignore_history_payload() {
        // SMH-SPEC-SPEC0001: worker consumer paths retain ROWS previews and
        // stream JSONL export; incomplete live tails are excluded.
        let root =
            std::env::temp_dir().join(format!("smith-observer-bounds-{}", std::process::id()));
        let _ = std::fs::remove_dir_all(&root);
        std::fs::create_dir_all(&root).unwrap();
        let small_path = root.join("small.smh");
        let large_path = root.join("large.smh");
        let (small_id, small_writer) = observed_history(&small_path, SMALL_ENTRIES, "small");
        let (large_id, large_writer) = observed_history(&large_path, LARGE_ENTRIES, "large");
        let mut tail = std::fs::OpenOptions::new()
            .append(true)
            .open(&large_path)
            .unwrap();
        tail.write_all(&[4, 0]).unwrap();
        drop(tail);
        let source_before = std::fs::read(&large_path).unwrap();

        let (small, _) = observer_cost(
            &small_path,
            small_id,
            SMALL_ENTRIES,
            &root.join("small.jsonl"),
        );
        let (large, fork_at) = observer_cost(
            &large_path,
            large_id,
            LARGE_ENTRIES,
            &root.join("large.jsonl"),
        );
        assert!(
            large.peak <= small.peak + 64 * 1024,
            "worker fetch/export peak grew from {} to {} bytes",
            small.peak,
            large.peak
        );
        assert!(
            large.peak < 256 * 1024,
            "worker request peak {} bytes for {} bytes of history",
            large.peak,
            std::fs::metadata(&large_path).unwrap().len()
        );
        assert_eq!(std::fs::read(&large_path).unwrap(), source_before);
        assert_eq!(
            std::fs::read_to_string(root.join("large.jsonl"))
                .unwrap()
                .lines()
                .count(),
            LARGE_ENTRIES,
            "incomplete live tail is not exported"
        );
        let before_fork = smith_alloc::snapshot(Scope::IoRequest);
        let (response, fork_cost) = worker_request(large_path, large_id, Request::Fork(fork_at));
        assert!(matches!(response, Response::Forked(_)));
        assert!(
            fork_cost.allocations > 0
                && smith_alloc::snapshot(Scope::IoRequest).allocations > before_fork.allocations,
            "production observer fork requests must charge allocations to IoRequest"
        );
        drop((small_writer, large_writer));
        let _ = std::fs::remove_dir_all(root);
    }

    #[test]
    fn clipping_is_utf8_safe_and_bounded() {
        assert_eq!(clipped("aébc", 4), "a…");
        assert_eq!(clipped("a\nb", 3), "a b");
        assert_eq!(clipped("\u{1b}[31m", 5), " [31m");
        assert!(clipped(&"é".repeat(600), ROW_BYTES).len() <= ROW_BYTES);
    }
}