use std::{collections::BTreeMap, path::Path, time::Duration};
use claude_scriptorium::{
gloss,
gloss::GlossKind,
render,
render::{Colophon, Delivery, Fonts, Labour, Scribe},
transcript::{Content, Folio, Panel, PanelKind, Role, Side},
};
use comrak::plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder};
use jiff::{Timestamp, tz::TimeZone};
fn fixture() -> Folio {
Folio::read(Path::new("tests/fixtures/session.jsonl")).expect("fixture parses")
}
fn highlighter() -> SyntectAdapter {
SyntectAdapterBuilder::new()
.css_with_class_prefix("ink-")
.build()
}
fn render(folio: &Folio, highlighter: &SyntectAdapter) -> String {
set(folio, highlighter, Fonts::Fitted, Delivery::Static).0
}
fn set(
folio: &Folio,
highlighter: &SyntectAdapter,
fonts: Fonts,
delivery: Delivery,
) -> (String, BTreeMap<char, usize>) {
let scribe = Scribe::new(highlighter, TimeZone::UTC, fonts, delivery);
let colophon = Colophon {
generated: "2026-03-12T09:15:00Z".parse::<Timestamp>().unwrap(),
tool: "claude-scriptorium",
version: "0.1.0",
home: "https://example.invalid/scriptorium",
};
let labour = Labour {
took: Duration::from_millis(412),
bytes: 2_947_312,
};
let (markup, reached) = scribe.folio(folio, &colophon);
(render::inscribe(markup.into_string(), &labour), reached)
}
#[test]
fn bookkeeping_lines_are_not_turns() {
let folio = fixture();
assert_eq!(folio.turns().count(), 5);
}
#[test]
fn turn_roles_come_from_the_entry_tag() {
let folio = fixture();
let roles: Vec<Role> = folio.turns().map(|turn| turn.role).collect();
assert_eq!(
roles,
[
Role::User,
Role::Assistant,
Role::User,
Role::User,
Role::Assistant
]
);
}
#[test]
fn string_content_is_kept_whole() {
let folio = fixture();
let first = folio.turns().next().expect("the fixture opens with a turn");
let Content::Text(text) = &first.content else {
panic!("expected the opening turn to carry plain string content");
};
assert_eq!(text, "Explain the **quire** layout, please.");
}
#[test]
fn subagent_turns_are_marked() {
let folio = fixture();
let sidechains: Vec<bool> = folio.turns().map(|turn| turn.is_sidechain).collect();
assert_eq!(sidechains, [false, false, false, true, false]);
}
#[test]
fn session_id_comes_from_the_file_name() {
assert_eq!(fixture().session_id(), "session");
}
#[test]
fn the_effort_level_refines_the_model_name() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(
r#"<span class="turn__model">claude-opus-4-8 <span class="turn__effort">(high)</span></span>"#
));
assert!(html.contains(r#"<span class="turn__model">claude-opus-4-8</span>"#));
}
fn metered() -> Folio {
Folio::read(Path::new("tests/fixtures/usage.jsonl")).expect("fixture parses")
}
#[test]
fn a_response_written_as_several_lines_is_counted_once() {
let folio = metered();
let counted: Vec<u64> = folio
.turns()
.filter_map(|turn| turn.usage)
.map(|usage| usage.output_tokens)
.collect();
assert_eq!(counted, [214, 31]);
}
#[test]
fn a_session_totals_its_output_but_takes_its_largest_input() {
let folio = metered();
assert_eq!(folio.output(), Some(245));
assert_eq!(folio.largest_input(), Some(48_207));
}
#[test]
fn a_session_without_usage_reports_none() {
assert!(fixture().output().is_none());
assert!(fixture().largest_input().is_none());
}
#[test]
fn a_turn_shows_the_input_it_added_and_the_output_it_drew() {
let html = render(&metered(), &highlighter());
assert!(html.contains(
r#"<span class="turn__usage" title="32,403 input this turn · 214 output this turn">↑ 32.4k ↓ 214</span>"#
));
}
#[test]
fn the_plaque_shows_the_largest_input_and_the_total_output() {
let html = render(&metered(), &highlighter());
assert!(html.contains(
r#"<dd title="48,207 input at its largest · 245 output in all">↑ 48.2k ↓ 245</dd>"#
));
}
#[test]
fn unrecognized_block_types_render_as_json_instead_of_failing() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("block--unknown"));
assert!(html.contains("<summary>illumination</summary>"));
assert!(html.contains("lapis lazuli"));
}
#[test]
fn unrecognized_blocks_nested_in_tool_results_survive_too() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("<summary>tool_reference</summary>"));
assert!(html.contains("Scriptorium"));
}
#[test]
fn markdown_becomes_html() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("<strong>quire</strong>"));
}
#[test]
fn fenced_code_is_highlighted_into_classed_spans() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"class="ink-source ink-rust""#));
}
#[test]
fn tool_calls_carry_a_gist_of_their_subject() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__tool">Read</span>"#));
assert!(html.contains("/scriptorium/quire.rs"));
}
fn tools() -> Folio {
Folio::read(Path::new("tests/fixtures/tools.jsonl")).expect("fixture parses")
}
#[test]
fn bash_calls_show_their_description_and_highlighted_command() {
let html = render(&tools(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">Scaffold the crate</span>"#));
assert!(html.contains("ink-shell"));
assert!(html.contains("cargo"));
}
#[test]
fn write_calls_highlight_content_by_file_extension() {
let html = render(&tools(), &highlighter());
assert!(html.contains("ink-rust"));
assert!(html.contains("scriptorium"));
}
#[test]
fn edit_calls_render_before_and_after_as_a_diff() {
let html = render(&tools(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__note">replace all</span>"#));
assert!(html.contains("ink-deleted"));
assert!(html.contains("ink-inserted"));
}
#[test]
fn todo_writes_render_as_a_status_marked_checklist() {
let html = render(&tools(), &highlighter());
assert!(
html.contains(r#"<li class="tool__todo" data-status="completed">Scaffold the crate</li>"#)
);
assert!(html.contains(r#"data-status="in_progress">Wire the CLI</li>"#));
assert!(html.contains(r#"data-status="pending">Add coverage</li>"#));
}
fn playground() -> Folio {
Folio::read(Path::new("tests/fixtures/playground.jsonl")).expect("fixture parses")
}
#[test]
fn a_call_its_summary_states_in_full_has_no_fold_to_open() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<div class="marginalia marginalia--use marginalia--flat">"#));
assert!(html.contains(r#"<span class="marginalia__note">lines 105–108</span>"#));
}
#[test]
fn a_reads_result_is_set_as_the_language_of_the_file_it_read() {
let html = render(&playground(), &highlighter());
assert!(!html.contains("1\t//! Parsing of Claude Code"));
assert!(html.contains(r#"class="ink-source ink-rust""#));
}
#[test]
fn a_plan_is_set_as_the_markdown_document_it_is() {
let html = render(&playground(), &highlighter());
assert!(
html.contains(r#"<span class="marginalia__gist">Pretty-print every built-in tool</span>"#)
);
assert!(html.contains("<h1>Pretty-print every built-in tool</h1>"));
assert!(html.contains(r#"<li class="tool__prompt">"#));
}
#[test]
fn a_question_shows_every_option_it_offered() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<span class="tool__header">Read result</span>"#));
assert!(html.contains(r#"<span class="tool__label">Highlight by extension</span>"#));
assert!(html.contains("Keep the numbers"));
assert_eq!(
html.matches(r#"<section class="tool__question">"#).count(),
2
);
assert!(html.contains(r#"<span class="tool__header">Scope</span>"#));
}
#[test]
fn a_web_search_sets_the_links_it_found_as_links() {
let html = render(&playground(), &highlighter());
assert!(
html.contains(r#"<a href="https://openfontlicense.org/">SIL Open Font License 1.1</a>"#)
);
}
#[test]
fn a_tool_searchs_result_previews_the_tools_it_found() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">WebSearch, WebFetch</span>"#));
assert!(html.contains(r#"<li class="tool__reference">WebSearch</li>"#));
}
#[test]
fn a_background_tasks_answer_splits_into_its_facts_and_its_output() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<dl class="tool tool--facts">"#));
assert!(html.contains("<dt>status</dt><dd>completed</dd>"));
assert!(html.contains("<li>164 sessions</li>"));
}
fn answers() -> Folio {
Folio::read(Path::new("tests/fixtures/answers.jsonl")).expect("fixture parses")
}
#[test]
fn an_answer_is_recovered_from_the_sentence_the_harness_buries_it_in() {
let html = render(&answers(), &highlighter());
assert!(html.contains(r#"<p class="tool__chosen">All projects, two-stage</p>"#));
assert!(html.contains(r#"<p class="tool__chosen">Time + first prompt</p>"#));
assert!(!html.contains("Your questions have been answered"));
assert!(!html.contains("You can now continue with these answers in mind"));
}
#[test]
fn a_question_quoting_code_does_not_break_the_pairs_apart() {
let html = render(&answers(), &highlighter());
assert!(html.contains(r#"<p class="tool__chosen">Leave it</p>"#));
}
#[test]
fn a_chosen_options_preview_is_shown_against_the_option_not_the_answer() {
let html = render(&answers(), &highlighter());
assert!(html.contains(r#"<p class="tool__chosen">In the meta line</p>"#));
assert!(!html.contains("selected preview"));
assert_eq!(html.matches("┌───────────────┐").count(), 1);
}
#[test]
fn several_selections_arrive_as_the_one_answer_they_were_given_as() {
let html = render(&answers(), &highlighter());
assert!(html.contains(
r#"<p class="tool__chosen">Default policy by role, Valid-optional vs malformed, Derive, don't restate</p>"#
));
}
#[test]
fn an_answer_the_reader_typed_is_kept_whole() {
let html = render(&answers(), &highlighter());
assert!(html.contains(
r#"<p class="tool__chosen" data-typed>I want copy buttons, jump, and fancy collapse."#
));
assert!(!html.contains("The user answered:"));
assert!(!html.contains("no option selected"));
assert!(html.contains("it keeps matching items instead of dropping them"));
}
#[test]
fn a_question_that_was_never_answered_stands_as_the_note_it_is() {
let html = render(&answers(), &highlighter());
assert!(html.contains("No response after 60s"));
}
#[test]
fn a_result_that_only_says_the_call_worked_is_dropped() {
let html = render(&playground(), &highlighter());
assert!(!html.contains("src/render.rs has been updated successfully"));
assert!(!html.contains("File created successfully at"));
assert!(!html.contains("Todos have been modified"));
assert!(!html.contains("Launching skill"));
assert!(html.contains(r#"<span class="marginalia__tool">EnterPlanMode</span>"#));
assert!(!html.contains("Entered plan mode"));
}
#[test]
fn a_result_written_down_as_text_blocks_is_weighed_like_a_plain_one() {
let html = render(&playground(), &highlighter());
assert!(!html.contains("Async agent launched successfully"));
assert!(html.contains("Survey the drollery bestiary"));
}
#[test]
fn a_result_that_warns_alongside_the_acknowledgement_is_kept() {
let html = render(&playground(), &highlighter());
assert!(html.contains("the file had been modified on disk"));
}
#[test]
fn a_terminals_colour_survives_into_the_folio() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<span class="ansi ansi--green">ok</span>"#));
assert!(html.contains(r#"<span class="ansi ansi--red ansi--bold">FAILED</span>"#));
assert!(html.contains(r#"<span class="ansi ansi--bright-black">"#));
assert!(!html.contains('\u{1b}'));
}
#[test]
fn a_colour_a_tool_states_outright_is_carried_as_its_own_value() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"style="color:#ff8700""#));
assert!(html.contains(r#"style="color:#785ac8""#));
}
#[test]
fn a_bodys_trailing_newline_is_not_set_as_a_line() {
let html = render(&playground(), &highlighter());
assert!(!html.contains("\n</code></pre>"));
}
#[test]
fn a_failure_sheds_the_tag_the_harness_wraps_it_in() {
let html = render(&playground(), &highlighter());
assert!(html.contains("String to replace not found in file."));
assert!(!html.contains("tool_use_error"));
}
#[test]
fn an_answer_that_is_json_is_pretty_printed() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"class="ink-source ink-json""#));
}
#[test]
fn a_tool_search_lists_the_tools_it_found() {
let html = render(&playground(), &highlighter());
assert!(html.contains(r#"<li class="tool__reference">WebSearch</li>"#));
assert!(html.contains(r#"<li class="tool__reference">WebFetch</li>"#));
}
#[test]
fn a_tool_with_no_view_of_its_own_falls_back_to_json() {
let html = render(&playground(), &highlighter());
assert!(
html.contains(r#"<span class="marginalia__tool">mcp__scriptorium__list_quires</span>"#)
);
assert!(html.contains("newest_first"));
}
#[test]
fn failed_tool_results_are_flagged() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("data-error"));
assert!(html.contains("vellum not found"));
}
#[test]
fn images_are_inlined_as_data_urls() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"src="data:image/png;base64,iVBORw0KGgo=""#));
}
#[test]
fn transcript_html_is_escaped_rather_than_executed() {
let folio = Folio::read(Path::new("tests/fixtures/injection.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains("<script>"));
assert!(!html.contains("<script>alert"));
}
#[test]
fn the_folio_carries_its_trusted_app_script() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("<script>"));
assert!(html.contains("scriptorium-theme"));
}
#[test]
fn the_folio_carries_a_search_widget() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"class="search""#));
assert!(html.contains(r#"class="search__input""#));
assert!(html.contains(r#"data-search-nav="next""#));
}
#[test]
fn the_lights_a_folio_is_read_by_are_the_control_that_chooses_them() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<div class="luminaries" role="group""#));
assert!(html.contains(r#"data-theme-choice="light""#));
assert!(html.contains(r#"data-theme-choice="dark""#));
assert!(html.contains(r#"class="theme-reset" type="button" data-theme-choice="system""#));
}
#[test]
fn each_light_carries_the_name_its_figure_cannot_say() {
let html = render(&fixture(), &highlighter());
for (choice, label) in [
("light", "read by daylight"),
("dark", "read by candlelight"),
("system", "follow the system"),
] {
let button = html
.split(&format!(r#"data-theme-choice="{choice}""#))
.nth(1)
.and_then(|rest| rest.split("</button>").next())
.unwrap_or_else(|| panic!("the {choice} control is in the corner"));
assert!(
button.contains(&format!(r#"aria-label="{label}""#)),
"the {choice} control has no name, and its figure cannot supply one"
);
}
}
#[test]
fn every_folio_carries_both_lights_and_lets_the_scheme_choose() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"class="luminary__sun""#));
assert!(html.contains(r#"class="luminary__moon""#));
assert!(html.contains(r#"class="luminary__flame""#));
assert!(html.contains(r#"class="luminary__smoke""#));
assert!(html.contains("--flame: light-dark(transparent,"));
assert!(html.contains("--smoke: light-dark(#9c9384, transparent)"));
assert!(html.contains("--sun-disc: light-dark(#c98a1c, transparent)"));
assert!(html.contains("--moon: light-dark(transparent, #cfc6ac)"));
assert!(
html.contains(r#"<svg class="luminary__figure" viewBox="0 0 40 56" aria-hidden="true""#)
);
assert!(html.contains(r#"<span class="luminary__radiance luminary__radiance--day"></span>"#));
assert!(html.contains(r#"<span class="luminary__radiance luminary__radiance--night"></span>"#));
}
#[test]
fn the_reset_is_offered_only_once_a_light_has_been_chosen() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(
r#".theme-reset {
display: none;"#
));
assert!(html.contains(
r#":root[data-theme] .theme-reset {
display: grid;
}"#
));
}
#[test]
fn only_a_served_folio_offers_to_follow_the_session() {
let highlighter = highlighter();
let (statik, _) = set(&fixture(), &highlighter, Fonts::Fitted, Delivery::Static);
let (served, _) = set(&fixture(), &highlighter, Fonts::Fitted, Delivery::Served);
const TAIL: &str = r#"<button class="dock__btn dock__btn--tail""#;
assert!(!statik.contains(TAIL));
assert!(served.contains(TAIL));
assert!(statik.contains(r#"data-nav="end""#));
assert!(served.contains(r#"data-nav="end""#));
}
#[test]
fn the_body_names_the_session_so_stored_state_is_scoped_to_this_folio() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<body data-folio="session">"#));
}
#[test]
fn a_turns_role_is_one_class_attribute_not_two() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"class="turn turn--assistant""#));
assert!(!html.contains(r#"class="turn" class="#));
}
#[test]
fn thinking_blocks_render_their_markdown() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<section class="block block--thinking">"#));
assert!(html.contains("The gathering is four folded sheets."));
}
#[test]
fn redacted_thinking_blocks_are_marked_not_shown_as_an_empty_box() {
let folio =
Folio::read(Path::new("tests/fixtures/redacted_thinking.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(!html.contains(r#"<section class="block block--thinking">"#));
assert!(html.contains("block--redacted"));
assert!(html.contains("The reasoning was redacted."));
}
#[test]
fn tool_result_turns_fold_into_the_assistant_panel() {
let html = render(&fixture(), &highlighter());
assert_eq!(html.matches("<article").count(), 3);
assert_eq!(html.matches(r#"turn__role">user"#).count(), 1);
assert!(html.contains("Quire"));
assert!(html.contains("ink-storage"));
}
#[test]
fn panels_are_labelled_by_their_content_kind() {
let folio = Folio::read(Path::new("tests/fixtures/kinds.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains(r#"turn__role">tool<"#));
assert!(html.contains(r#"turn__role">thinking<"#));
assert!(html.contains(r#"turn__role">assistant<"#));
}
#[test]
fn only_speech_panels_open_with_a_versal() {
let folio = Folio::read(Path::new("tests/fixtures/kinds.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert_eq!(html.matches("data-versal>").count(), 1);
assert!(html.contains(r#"<div class="block block--text" data-versal>"#));
}
#[test]
fn a_versal_marks_only_the_opening_paragraph_of_a_panel() {
let html = render(&fixture(), &highlighter());
assert_eq!(html.matches("data-versal>").count(), 2);
}
#[test]
fn the_caveat_opens_the_reading_column() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<main class="folio"><aside class="caveat">"#));
assert!(html.contains("Caveat lector."));
}
#[test]
fn the_caveat_is_nothing_the_folio_can_navigate() {
let html = render(&fixture(), &highlighter());
let opened = html
.find(r#"<aside class="caveat">"#)
.expect("the caveat is set");
let closed = html[opened..].find("</aside>").expect("the caveat closes");
let caveat = &html[opened..opened + closed];
assert!(!caveat.contains(r#"class="turn"#));
assert!(!caveat.contains("data-turn"));
assert!(!caveat.contains("data-kind"));
assert!(!caveat.contains("data-side"));
}
#[test]
fn each_panel_is_numbered_by_its_leading_turn() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r##"href="#turn-1">#1</a>"##));
assert!(html.contains(r##"href="#turn-2">#2</a>"##));
assert!(html.contains(r##"href="#turn-5">#5</a>"##));
assert!(!html.contains(r##"href="#turn-3">#3</a>"##));
}
#[test]
fn each_panel_is_a_deep_link_target_its_number_points_to() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"<article id="turn-1""#));
assert!(html.contains(r#"<article id="turn-2""#));
assert!(html.contains(r##"<a class="turn__index" href="#turn-1">#1</a>"##));
}
#[test]
fn a_skill_the_harness_injected_is_set_as_a_gloss_rather_than_a_user_turn() {
let folio = Folio::read(Path::new("tests/fixtures/meta.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains(r#"class="turn turn--gloss" data-kind="skill""#));
assert!(html.contains(r#"<span class="marginalia__gist">review-config</span>"#));
assert!(!html.contains("Base directory for this skill"));
assert!(!html.contains("data-meta"));
}
#[test]
fn clear_command_turns_are_dropped() {
let folio = Folio::read(Path::new("tests/fixtures/clear.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(!html.contains("command-name"));
assert!(!html.contains("command-message"));
assert!(html.contains("Explain the quire layout."));
assert_eq!(html.matches("<article").count(), 1);
}
#[test]
fn a_message_queued_mid_response_becomes_a_user_turn() {
let folio = Folio::read(Path::new("tests/fixtures/queued.jsonl")).expect("fixture parses");
let queued = folio
.turns()
.find(|turn| {
turn.role == Role::User
&& matches!(&turn.content, Content::Text(text) if text.contains("above and below"))
})
.expect("the queued message is lifted into a user turn");
assert!(!queued.is_meta);
assert!(!queued.is_sidechain);
}
#[test]
fn a_queued_message_renders_as_its_own_user_panel() {
let folio = Folio::read(Path::new("tests/fixtures/queued.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains("put the drolleries above and below the vine"));
assert_eq!(html.matches(r#"turn__role">user"#).count(), 2);
}
#[test]
fn non_queued_attachments_stay_dropped() {
let folio = Folio::read(Path::new("tests/fixtures/queued.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(!html.contains("You have not used the task tools"));
}
#[test]
fn the_key_offers_a_chip_for_every_kind_of_panel() {
let html = render(&fixture(), &highlighter());
for kind in PanelKind::EVERY {
assert!(
html.contains(&format!(
r#"data-scope="{}" data-side="{}" aria-pressed="true""#,
kind.label(),
kind.side().label()
)),
"{} has no chip in the key, or is not grouped by its side",
kind.label()
);
}
}
#[test]
fn the_key_is_its_own_panel_rather_than_the_searchs_control() {
let html = render(&fixture(), &highlighter());
let rail = html
.split(r#"<div class="rail">"#)
.nth(1)
.expect("the rail holds the panels that answer to the key");
let search = rail
.split(r#"<div class="search""#)
.nth(1)
.and_then(|rest| rest.split(r#"<div class="key""#).next())
.expect("the search sits in the rail");
assert!(
!search.contains("key__chip"),
"the key is nested inside the search panel it is supposed to govern"
);
assert!(html.contains(r#"<div class="key" role="group""#));
}
#[test]
fn panels_carry_their_turn_number_for_stable_fold_memory() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"data-turn="1""#));
assert!(html.contains(r#"data-turn="2""#));
}
#[test]
fn the_dock_steps_along_the_sides_of_the_exchange() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"data-nav="prev" data-side="entered""#));
assert!(html.contains(r#"data-nav="next" data-side="model""#));
assert!(html.contains(r#"class="dock__btn dock__btn--entered""#));
assert!(html.contains(r#"class="dock__btn dock__btn--model""#));
}
#[test]
fn every_panel_carries_the_side_of_the_exchange_it_is_on() {
let html = render(&glossed(), &highlighter());
for kind in PanelKind::EVERY {
let marked = format!(
r#"data-kind="{}" data-side="{}""#,
kind.label(),
kind.side().label()
);
let present = html.contains(&format!(r#"data-kind="{}""#, kind.label()));
assert!(
!present || html.contains(&marked),
"{} panels reach the page without the side the code gives them",
kind.label()
);
}
for side in ["entered", "model", "aside"] {
assert!(
html.contains(&format!(r#"data-side="{side}""#)),
"the swatch has no {side} panel to weigh"
);
}
}
#[test]
fn the_dock_leaps_to_either_end_of_the_folio() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(r#"data-nav="top" aria-label="jump to top""#));
assert!(html.contains(r#"data-nav="end" aria-label="jump to end""#));
}
#[test]
fn the_minimap_is_the_last_card_in_the_rail() {
let html = render(&fixture(), &highlighter());
let rail = html
.split(r#"<div class="rail">"#)
.nth(1)
.expect("the rail holds the cards that answer to the key");
let dock = rail
.find("<nav class=\"dock\"")
.expect("the dock is in the rail");
let minimap = rail
.find(r#"<div class="minimap""#)
.expect("the minimap is in the rail");
assert!(
dock < minimap,
"the minimap is above the dock it sits under"
);
assert!(html.contains(r#"<div class="minimap__view"></div>"#));
assert!(html.contains(r#"title="drag to scrub, scroll to zoom""#));
}
#[test]
fn every_kind_of_panel_is_pigmented_wherever_it_is_stood_for() {
let html = render(&fixture(), &highlighter());
for kind in PanelKind::EVERY {
let label = kind.label();
if label == "note" {
continue;
}
assert!(
html.contains(&format!(
r#".key__chip[data-scope="{label}"],
.minimap__band[data-kind="{label}"] {{"#
)),
"{label} has no pigment of its own in the key or the minimap"
);
}
}
#[test]
fn the_stylesheet_is_inlined_not_linked() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("<style>"));
assert!(html.contains(".ink-keyword"));
assert!(!html.contains("<link"));
}
#[test]
fn the_scroll_thumb_yields_to_the_user_agent_under_forced_colours() {
let html = render(&fixture(), &highlighter());
let rules: String = html
.split("/*")
.map(|c| c.split_once("*/").map_or(c, |(_, r)| r))
.collect();
let guard = rules
.find("@media not (forced-colors: active)")
.expect("the scroll is drawn inside a forced-colours guard");
assert!(rules.contains("::-webkit-scrollbar-thumb"));
assert!(
rules
.match_indices("::-webkit-scrollbar")
.all(|(at, _)| at > guard),
"every scrollbar pseudo-element rule sits after the guard opens"
);
assert!(rules.contains("@supports not selector(::-webkit-scrollbar)"));
assert!(rules.contains("scrollbar-color:"));
assert!(!rules.contains("scrollbar-width:"));
}
#[test]
fn fonts_are_embedded_not_linked() {
let html = render(&fixture(), &highlighter());
assert_eq!(html.matches("data:font/woff2;base64,").count(), 4);
assert!(html.contains(r#"font-family:"Junicode""#));
assert!(html.contains(r#"font-family:"UnifrakturCook""#));
assert!(html.contains(r#"font-family:"Fira Code""#));
assert!(!html.contains("fonts.googleapis.com"));
assert!(!html.contains("fonts.gstatic.com"));
}
#[test]
fn embedded_fonts_carry_their_open_font_license_notice() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("Copyright 2010 j. 'mach' wust"));
assert!(html.contains("SIL Open Font License"));
}
#[test]
fn the_colophon_stamps_the_run() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("claude-scriptorium"));
assert!(html.contains("2026-03-12 09:15:00 UTC"));
}
#[test]
fn the_colophon_states_what_the_render_cost() {
let html = render(&fixture(), &highlighter());
assert!(html.contains("taking 412 ms to set 2.9 MB."));
}
#[test]
fn an_inscribed_folio_keeps_no_placeholder() {
let html = render(&fixture(), &highlighter());
assert!(
!html.contains("<!--folio:"),
"a placeholder outlived inscription"
);
}
#[test]
fn the_colophon_links_the_tool_to_its_home() {
let html = render(&fixture(), &highlighter());
assert!(html.contains(
r#"Written by <a href="https://example.invalid/scriptorium">claude-scriptorium</a> 0.1.0"#
));
}
fn embedded_font_bytes(html: &str) -> usize {
html.match_indices("data:font/woff2;base64,")
.map(|(start, marker)| {
let rest = &html[start + marker.len()..];
rest.find(')').expect("a data URI closes")
})
.sum()
}
#[test]
fn a_folio_inside_the_cut_faces_carries_only_them() {
let (html, reached) = set(&fixture(), &highlighter(), Fonts::Fitted, Delivery::Static);
assert!(reached.is_empty(), "nothing in the fixture is dropped");
assert!(
embedded_font_bytes(&html) < 700_000,
"the cut faces are a fifth the whole ones, so a folio that needs \
nothing more should be far under this"
);
}
#[test]
fn asking_for_the_whole_faces_embeds_them_whatever_the_folio_sets() {
let highlighter = highlighter();
let (cut, _) = set(&fixture(), &highlighter, Fonts::Fitted, Delivery::Static);
let (whole, reached) = set(&fixture(), &highlighter, Fonts::Whole, Delivery::Static);
assert!(reached.is_empty(), "the folio itself still needs nothing");
assert!(embedded_font_bytes(&whole) > embedded_font_bytes(&cut) * 3);
}
fn beyond_cut() -> Folio {
Folio::read(Path::new("tests/fixtures/beyond_cut.jsonl")).expect("fixture parses")
}
#[test]
fn a_character_the_cut_faces_dropped_pulls_in_the_whole_ones() {
let highlighter = highlighter();
let (html, reached) = set(&beyond_cut(), &highlighter, Fonts::Fitted, Delivery::Static);
let (whole, _) = set(&beyond_cut(), &highlighter, Fonts::Whole, Delivery::Static);
assert_eq!(reached.get(&'ч'), Some(&1));
assert_eq!(
embedded_font_bytes(&html),
embedded_font_bytes(&whole),
"a folio that reaches past the cut faces carries the whole ones"
);
}
#[test]
fn a_character_no_face_ever_carried_is_not_a_reason_to_grow() {
let (_, reached) = set(
&beyond_cut(),
&highlighter(),
Fonts::Fitted,
Delivery::Static,
);
for character in ['日', '本', '語', '🎉'] {
assert!(
!reached.contains_key(&character),
"{character} was never in any face, so it is not a regression"
);
}
}
#[test]
fn the_symbols_real_sessions_write_stay_inside_the_cut() {
for character in ['⟨', '⟩', '⬆'] {
assert!(
render::beyond_cut(&character.to_string()).is_empty(),
"{character} is written by real sessions and must stay in the cut"
);
}
}
#[test]
fn nothing_below_the_ascii_boundary_is_ever_dropped() {
let ascii: String = (0..0x80u8).map(char::from).collect();
assert!(render::beyond_cut(&ascii).is_empty());
}
#[test]
fn the_folios_own_chrome_stays_inside_the_cut_faces() {
for (name, source) in [
("illumination.css", include_str!("../src/illumination.css")),
(
"illumination.core.js",
include_str!("../src/illumination.core.js"),
),
(
"illumination.shell.js",
include_str!("../src/illumination.shell.js"),
),
] {
let reached = render::beyond_cut(source);
assert!(
reached.is_empty(),
"{name} sets {reached:?}, which the cut faces drop: widen KEEP in \
scripts/subset_fonts.py and re-run `just fonts`"
);
}
}
fn glossed() -> Folio {
Folio::read(Path::new("tests/fixtures/glosses.jsonl")).expect("fixture parses")
}
#[test]
fn what_the_harness_wrote_into_the_session_is_set_as_its_own_panel() {
let html = render(&glossed(), &highlighter());
for kind in ["hook", "rule", "skill", "command", "plan"] {
assert!(
html.contains(&format!(r#"class="turn turn--gloss" data-kind="{kind}""#)),
"no {kind} gloss was set"
);
}
assert!(html.contains("No journal yet for branch"));
assert!(html.contains("Derive aggressively rather than implementing by hand"));
assert!(html.contains("The objective is to"));
}
#[test]
fn the_gloss_fixture_carries_every_kind_of_panel_to_compare() {
let html = render(&glossed(), &highlighter());
for kind in ["user", "assistant", "tool", "thinking"] {
assert!(
html.contains(&format!(r#"data-kind="{kind}""#)),
"the swatch is missing a {kind} panel to compare the glosses against"
);
}
}
#[test]
fn a_built_in_skill_is_named_by_the_command_that_ran_it() {
let html = render(&glossed(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">review</span>"#));
assert!(html.contains("Gather this target's diff with"));
let skills = html
.matches(r#"class="turn turn--gloss" data-kind="skill""#)
.count();
assert_eq!(skills, 2, "a built-in skill is not set as a skill");
}
#[test]
fn a_hook_keeps_the_line_breaks_it_printed() {
let html = render(&glossed(), &highlighter());
assert!(html.contains("M rustfmt.toml<br />\nM src/gloss.rs"));
assert!(!html.contains("M rustfmt.toml\nM src/gloss.rs</p>"));
assert!(html.contains("<p>You made these changes this session:</p>"));
}
#[test]
fn output_that_redrew_itself_keeps_only_what_the_terminal_was_left_showing() {
let html = render(&glossed(), &highlighter());
assert!(html.contains("⠹ Generating mutants"));
assert!(!html.contains("⠋ Generating mutants"));
assert!(!html.contains("⠙ Generating mutants"));
assert!(html.contains("Checking rustfmt"));
assert!(html.contains("Diff in src/main.rs at line 12"));
}
#[test]
fn inline_code_breaks_rather_than_running_out_of_the_fold_that_holds_it() {
let html = render(&glossed(), &highlighter());
assert!(html.contains(
".folio :not(pre) > code {\n padding: 0.1em 0.35em;\n background: var(--leaf-sunk);"
));
let inline = html
.split(".folio :not(pre) > code {")
.nth(1)
.and_then(|rest| rest.split('}').next())
.expect("the inline-code rule is in the stylesheet");
assert!(
inline.contains("overflow-wrap: break-word"),
"inline code can overflow whatever holds it"
);
let block = html
.split(".folio pre > code {")
.nth(1)
.and_then(|rest| rest.split('}').next())
.expect("the code-block rule is in the stylesheet");
assert!(block.contains("overflow-x: auto"));
assert!(!block.contains("overflow-wrap"));
}
#[test]
fn a_command_takes_the_speakers_pigment_rather_than_the_skills() {
let html = render(&glossed(), &highlighter());
assert!(html.contains("--command-edge: color-mix(in srgb, var(--user-edge)"));
assert!(html.contains(
r#".turn--gloss[data-kind="command"] {
--gloss-edge: var(--command-edge);"#
));
}
#[test]
fn a_slash_command_is_set_as_a_command_rather_than_its_wrapper() {
let html = render(&glossed(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">/debug-gha</span>"#));
assert!(html.contains(r#"<span class="marginalia__note">run 4812</span>"#));
assert!(!html.contains("command-name"));
assert!(!html.contains("command-args"));
assert!(!html.contains("Caveat: The messages below"));
assert!(!html.contains("/copy"));
assert!(!html.contains("Copied to clipboard"));
}
#[test]
fn one_firing_of_a_hook_is_one_panel_however_many_lines_it_wrote() {
let folio = glossed();
let html = render(&folio, &highlighter());
let stop = folio
.panels()
.into_iter()
.find_map(|panel| match panel {
Panel::Gloss(gloss)
if gloss.gloss.gist.as_deref()
== Some("[claude-stop-finish] finishing pass triggered") =>
{
Some(gloss.gloss)
}
_ => None,
})
.expect("the hook's decision labels a panel");
assert_eq!(stop.notes, ["Stop", "added context", "claude-stop"]);
assert!(matches!(
stop.body.as_slice(),
[gloss::Body::Printed(_), gloss::Body::Plain(_)]
));
assert!(html.contains("You made these changes this session"));
assert!(html.contains("claude-stop: 2 files staged"));
}
#[test]
fn a_results_line_previews_what_came_back_rather_than_repeating_the_call() {
let folio = Folio::read(Path::new("tests/fixtures/playground.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(
html.contains(r#"<span class="marginalia__gist">running 41 tests</span>"#),
"a successful result's line is not its hint alone"
);
assert!(!html.contains(r#"<span class="marginalia__outcome">result</span>"#));
assert!(html.contains(concat!(
r#"<span class="marginalia__outcome">error</span>"#,
r#"<span class="marginalia__gist">Exit code 127</span>"#
)));
assert!(!html.contains(r#"<span class="marginalia__note">/home/scribe"#));
}
#[test]
fn a_reads_hint_sheds_the_line_numbering_the_way_its_fold_does() {
let folio = Folio::read(Path::new("tests/fixtures/playground.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">//! Parsing of Claude Code"#));
assert!(!html.contains("<span class=\"marginalia__gist\">1\t"));
}
#[test]
fn a_results_hint_is_its_first_line_with_the_terminals_colour_taken_out() {
let folio = Folio::read(Path::new("tests/fixtures/playground.jsonl")).expect("fixture parses");
let html = render(&folio, &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">running 3 tests</span>"#));
assert!(
!html.contains('\u{1b}'),
"an escape reached the folio as a byte rather than a class"
);
}
#[test]
fn plan_mode_states_both_boundaries_and_whether_a_plan_was_written() {
let html = render(&glossed(), &highlighter());
assert!(html.contains(r#"<span class="marginalia__gist">entered plan mode</span>"#));
assert!(html.contains(r#"<span class="marginalia__note">left, plan written</span>"#));
assert_eq!(html.matches(">entered plan mode<").count(), 1);
}
#[test]
fn scaffolding_and_duplicated_hook_output_stay_out_of_the_folio() {
let folio = glossed();
let panels = folio.panels();
let html = render(&folio, &highlighter());
assert!(!html.contains("distil the branch's working memory"));
assert!(!html.contains("hookSpecificOutput"));
assert!(!html.contains("15086"));
for panel in &panels {
if let Panel::Gloss(gloss) = panel {
assert!(
gloss.gloss.gist.is_some() || !gloss.gloss.body.is_empty(),
"a gloss with nothing to say reached the folio: {gloss:?}"
);
}
}
}
#[test]
fn only_the_kinds_off_the_axis_are_skipped_by_the_navigation_dock() {
let html = render(&glossed(), &highlighter());
for kind in PanelKind::EVERY {
let stepped = kind.side() != Side::Aside;
let expected = match kind.side() {
Side::Entered => "entered",
Side::Model => "model",
Side::Aside => "aside",
};
assert_eq!(
stepped,
expected != "aside",
"{} is classified inconsistently",
kind.label()
);
}
assert_eq!(PanelKind::Gloss(GlossKind::Rule).side(), Side::Entered);
assert_eq!(PanelKind::Gloss(GlossKind::Plan).side(), Side::Model);
assert_eq!(PanelKind::Gloss(GlossKind::Note).side(), Side::Aside);
assert!(html.contains(r#"data-kind="plan" data-side="model""#));
assert!(html.contains(r#"data-kind="rule" data-side="entered""#));
assert!(html.contains(r#"data-kind="hook" data-side="entered""#));
}
#[test]
fn hooks_sharing_one_event_stay_their_own_panels() {
let folio = glossed();
let commands: Vec<String> = folio
.panels()
.into_iter()
.filter_map(|panel| match panel {
Panel::Gloss(gloss) if gloss.gloss.gist.as_deref() == Some("SessionStart:clear") => {
Some(gloss.gloss.notes.join(", "))
}
_ => None,
})
.collect();
assert_eq!(commands, ["claude-branch-journal", "claude-git-status"]);
}
#[test]
fn each_result_joins_the_panel_holding_the_call_it_answers() {
let folio = glossed();
let paired: Vec<(usize, usize)> = folio
.panels()
.iter()
.filter_map(|panel| match panel {
Panel::Speech(speech) if speech.kind() == PanelKind::Tool => Some((
speech.blocks.iter().filter(|b| b.is_call()).count(),
speech.blocks.iter().filter(|b| b.is_result()).count(),
)),
_ => None,
})
.collect();
assert_eq!(paired, [(1, 1), (1, 1)], "each call keeps its own result");
}