Something went wrong. Try again.
HEXWORK - A Lantern in the Deep: 3D ASCII terminal roguelike RPG in Rust.
Entirely designed and built by Muse Spark 1.3 to evaluate if I like the model.
Something went wrong. Try again.
26 kB · 687 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688//! AC12 actual-process Story/Classic transfer lifecycle evidence.//!//! Every gameplay mutation below comes from normal commands parsed by the//! production binary. Decoding is used only to inspect durable results and to//! label a replay from that durable history; no State, HP, position, item, or//! event field is injected into a positive gameplay path.
#![cfg(any(target_os = "linux", target_os = "macos"))]
pub mod support;
use hexwork_core::action::CommittedAction;use hexwork_core::runtime::ActorRole;use hexwork_save::artifact::MAX_EPITAPH_BYTES;use hexwork_save::{ decode_replay, decode_run, decode_vault, encode_replay, read_file_bounded, ProductionReplay, RunId, SessionEvent, SessionEventKind, MAX_COMPRESSED_BYTES, MAX_MARKER_BYTES, MAX_VAULT_BYTES,};use hexwork_worldgen::{Cell, ConnectorPlan, FloorPlan, PlanDestination, VoxelWrite, WorldPlan};use std::collections::BTreeSet;use std::fs;use std::path::{Path, PathBuf};use std::process::{Command, Output};
use support::{grate_mother_death_script, Harness};
const SEED: u64 = 223;const SMALL_EVIDENCE_CAP: usize = 64 * 1024;const CONFLICTING_REPLAY: &[u8] = b"ac12 deterministic regular replay collision\n";const TRANSFER_CYCLE: &str = "input inventory\ninput drop\ninput confirm\ninput inventory\ninput pickup\ninput confirm\n";const POST_CHECKPOINT_DROP: &str = "input inventory\ninput drop\ninput confirm\ninput inventory\nsave\nquit\n";
fn field<'a>(record: &'a serde_json::Value, name: &str) -> &'a serde_json::Value { record .get(name) .unwrap_or_else(|| panic!("missing {name}: {record}"))}
fn bounded(path: impl AsRef<Path>, cap: usize) -> Vec<u8> { let path = path.as_ref(); read_file_bounded(path, cap) .unwrap_or_else(|error| panic!("bounded read {}: {error}", path.display()))}
fn assert_success(output: &Output, stage: &str) { assert!( output.status.success(), "{stage}: stdout={} stderr={}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) );}
fn assert_exit(output: &Output, expected: i32, code: &str) { assert_eq!( output.status.code(), Some(expected), "expected exit {expected} ({code}); stdout={} stderr={}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); assert!( String::from_utf8_lossy(&output.stderr).contains(code), "missing {code}: {}", String::from_utf8_lossy(&output.stderr) );}
fn allocation_run_id(output: &Output) -> String { Harness::records(output) .iter() .find(|record| field(record, "code") == "allocation-durable") .and_then(|record| field(record, "run_id").as_str()) .expect("allocation milestone run ID") .to_owned()}
fn run_path(harness: &Harness, run_id: &str) -> PathBuf { harness.data.join("runs").join(run_id).join("run.save")}
fn decode_saved( harness: &Harness, pack: &hexwork_content::RuntimePack, run_id: &str,) -> hexwork_save::DecodedRun { decode_run( &bounded(run_path(harness, run_id), MAX_COMPRESSED_BYTES), pack.hash(), ) .expect("decode actual managed save")}
fn player_id(run: &hexwork_save::DecodedRun) -> u64 { run.current .actors .iter() .find(|actor| { run.current .identity(actor.id) .is_some_and(|identity| identity.role == ActorRole::Player) }) .expect("one authoritative Player") .id}
fn transfer_cycle_item(events: &[SessionEvent]) -> u64 { let drop_id = match events.first().map(|event| &event.kind) { Some(SessionEventKind::Action(CommittedAction::Drop { item_id })) => *item_id, other => panic!("first durable action was not starter drop: {other:?}"), }; let pickup_id = match events.get(1).map(|event| &event.kind) { Some(SessionEventKind::Action(CommittedAction::Pickup { item_id })) => *item_id, other => panic!("second durable action was not matching pickup: {other:?}"), }; assert_eq!(pickup_id, drop_id); assert_eq!(events[0].post_tick - events[0].pre_tick, 10); assert_eq!(events[1].post_tick - events[1].pre_tick, 10); drop_id}
fn new_command(harness: &Harness, script: &Path, story: bool) -> Command { let mut command = harness.managed(script); command .arg("--seed") .arg(SEED.to_string()) .arg("--ancestry") .arg("1") .arg("--calling") .arg("1"); if story { command.arg("--story"); } command}
fn load_command(harness: &Harness, script: &Path, run_id: &str, story: bool) -> Command { let mut command = harness.managed(script); command.arg("--load").arg(run_id); if story { command.arg("--story"); } command}
fn recover_command(harness: &Harness) -> Command { let mut command = harness.command(); command .arg("--data-dir") .arg(&harness.data) .arg("--content-root") .arg(&harness.content) .arg("--recover"); command}
fn replay_command(harness: &Harness, replay_path: &Path) -> Command { let mut command = harness.command(); command .arg("--content-root") .arg(&harness.content) .arg("--replay") .arg(replay_path); command}
fn assert_actual_replay(harness: &Harness, replay_path: &Path, expected_hash: u64) { let output = Harness::run(replay_command(harness, replay_path)); assert_success(&output, "actual --replay"); let stdout = String::from_utf8(output.stdout).expect("replay stdout UTF-8"); assert!(stdout.contains("verified event-text replay"), "{stdout}"); assert!( stdout.contains(&format!("hash {expected_hash:#x}")), "{stdout}" );}
fn append_route( output: &mut String, writes: &[VoxelWrite], start: Cell, goal: Cell, blockers: BTreeSet<Cell>,) { support::sampled_route::append_route(output, writes, start, goal, &blockers);}
fn voxel_at(writes: &[VoxelWrite], cell: Cell) -> hexwork_core::voxel::Voxel { writes .binary_search_by_key(&(cell[2], cell[1], cell[0]), |write| { (write.cell[2], write.cell[1], write.cell[0]) }) .ok() .map(|index| writes[index].voxel) .unwrap_or_default()}
fn passable(writes: &[VoxelWrite], cell: Cell) -> bool { let body = voxel_at(writes, cell); let head = voxel_at(writes, [cell[0], cell[1], cell[2] + 1]); let below = voxel_at(writes, [cell[0], cell[1], cell[2] - 1]); body.occ == 0 && head.occ == 0 && below.occ != 0 && body.fluid_amt <= 2}
fn world_blockers(plan: &WorldPlan) -> BTreeSet<Cell> { support::sampled_route::world_blockers(plan)}
fn floor_blockers(plan: &FloorPlan) -> BTreeSet<Cell> { support::sampled_route::floor_blockers(plan)}
fn paired<'a>(connectors: &'a [ConnectorPlan], source: &ConnectorPlan) -> &'a ConnectorPlan { connectors .iter() .find(|connector| connector.transition_id == source.paired_transition_id) .expect("paired connector")}
fn adjacent_access(writes: &[VoxelWrite], target: Cell, blockers: &BTreeSet<Cell>) -> Cell { [(0, 1), (-1, 0), (1, 0), (0, -1)] .into_iter() .map(|(dx, dy)| [target[0] + dx, target[1] + dy, target[2]]) .find(|cell| passable(writes, *cell) && !blockers.contains(cell)) .expect("Grate Mother has accessible adjacent cell")}
fn genuine_story_checkpoint_route(seed: u64) -> (String, Cell, u64) { let town = hexwork_worldgen::milthollow(seed); let floor1 = &hexwork_worldgen::playable_deep(seed)[0]; let down = town .connectors .iter() .find(|connector| connector.destination == PlanDestination::Deep { depth: 1 }) .expect("Town to Deep-1 connector"); let up = paired(&floor1.connectors, down); let mut commands = String::new(); append_route( &mut commands, &town.writes, town.start, down.access, world_blockers(&town), ); commands.push_str("input confirm\ninput confirm\n"); (commands, down.access, up.transition_id)}
fn grate_mother_death_script_from(seed: u64, town_start: Cell) -> String { let town = hexwork_worldgen::milthollow(seed); let floors = hexwork_worldgen::playable_deep(seed); let floor1 = &floors[0]; let floor2 = &floors[1]; let down = town .connectors .iter() .find(|connector| connector.destination == PlanDestination::Deep { depth: 1 }) .expect("Town to Deep-1 connector"); let floor1_up = paired(&floor1.connectors, down); let floor1_down = floor1 .connectors .iter() .find(|connector| connector.destination == PlanDestination::Deep { depth: 2 }) .expect("Deep-1 to Deep-2 connector"); let floor2_up = paired(&floor2.connectors, floor1_down); let mother = floor2 .actors .iter() .find(|actor| actor.template_id == "grate_mother") .expect("generated Grate Mother"); let blockers = floor_blockers(floor2); let access = adjacent_access(&floor2.writes, mother.position, &blockers);
let mut commands = String::new(); append_route( &mut commands, &town.writes, town_start, down.access, world_blockers(&town), ); commands.push_str("input confirm\n"); append_route( &mut commands, &floor1.writes, floor1_up.access, floor1_down.access, floor_blockers(floor1), ); commands.push_str("input confirm\n"); append_route( &mut commands, &floor2.writes, floor2_up.access, access, blockers, ); commands.push_str("input confirm\ninput confirm\ninput confirm\ninput confirm\n"); commands}
fn milestone_positions(records: &[serde_json::Value], wanted: &[&str]) -> Vec<usize> { let codes = records .iter() .filter_map(|record| field(record, "code").as_str()) .collect::<Vec<_>>(); wanted .iter() .map(|wanted| { codes .iter() .position(|code| code == wanted) .unwrap_or_else(|| panic!("missing {wanted}: {codes:?}")) }) .collect()}
#[test]fn binary_story_transfer_checkpoint_rollback_and_replay() { let harness = Harness::new("ac12-story-transfer-lifecycle"); let pack = hexwork_content::RuntimePack::load(&harness.content).unwrap(); let (checkpoint_route, return_cell, return_transition_id) = genuine_story_checkpoint_route(SEED);
let mut checkpoint_body = String::from(TRANSFER_CYCLE); checkpoint_body.push_str(&checkpoint_route); checkpoint_body.push_str("observe state\nsave\nquit\n"); let checkpoint_script = harness.script("story-checkpoint.commands", &checkpoint_body); let checkpoint_output = Harness::run(new_command(&harness, &checkpoint_script, true)); assert_success(&checkpoint_output, "Story checkpoint process"); let run_id = allocation_run_id(&checkpoint_output); let checkpoint_saved = decode_saved(&harness, &pack, &run_id); assert_eq!(checkpoint_saved.identity.seed, SEED); assert_eq!( checkpoint_saved.identity.ancestry, hexwork_core::character::Ancestry::Mudborn ); assert_eq!( checkpoint_saved.identity.calling, hexwork_core::character::Calling::Ratcatcher ); let selected_id = transfer_cycle_item(&checkpoint_saved.events); let player = player_id(&checkpoint_saved); let checkpoint = checkpoint_saved .story_checkpoint .as_ref() .expect("genuine Story checkpoint"); let checkpoint_prefix = usize::try_from(checkpoint.after_event_count).unwrap(); assert!( checkpoint_prefix > 2, "checkpoint prefix must be nonzero and post-route" ); assert_eq!(checkpoint_prefix, checkpoint_saved.events.len()); assert!(matches!( checkpoint_saved.events[checkpoint_prefix - 1].kind, SessionEventKind::Action(CommittedAction::UseTransition { transition_id }) if transition_id == return_transition_id )); let checkpoint_actor = checkpoint .state .image .actors .iter() .find(|actor| actor.id == player) .expect("checkpoint Player"); assert_eq!(checkpoint_actor.position.cell(), return_cell); assert_ne!(return_cell, hexwork_worldgen::milthollow(SEED).start); let checkpoint_instance = checkpoint.state.image.packs[&player].items[&selected_id].clone(); assert!(!checkpoint.state.image.items.contains_key(&selected_id)); assert!(!checkpoint .state .image .ground_items .contains_key(&selected_id));
let post_drop_script = harness.script("story-post-checkpoint-drop.commands", POST_CHECKPOINT_DROP); let post_drop_output = Harness::run(load_command(&harness, &post_drop_script, &run_id, true)); assert_success(&post_drop_output, "Story post-checkpoint drop process"); let post_drop = decode_saved(&harness, &pack, &run_id); let post_drop_image = post_drop.current.to_image().unwrap(); assert_eq!(post_drop.events.len(), checkpoint_prefix + 1); assert!(matches!( post_drop.events[checkpoint_prefix].kind, SessionEventKind::Action(CommittedAction::Drop { item_id }) if item_id == selected_id )); assert_eq!(post_drop_image.items[&selected_id], checkpoint_instance); assert_eq!( post_drop_image.ground_items[&selected_id], return_cell.into() ); assert!(!post_drop_image.packs[&player] .items .contains_key(&selected_id));
let mut lethal_body = grate_mother_death_script_from(SEED, return_cell); lethal_body.push_str("observe state\nsave\nquit\n"); let lethal_script = harness.script("story-recorded-lethal.commands", &lethal_body); let lethal_output = Harness::run(load_command(&harness, &lethal_script, &run_id, true)); assert_success(&lethal_output, "Story recorded lethal/resurrection process"); let restored = decode_saved(&harness, &pack, &run_id); let restored_image = restored.current.to_image().unwrap(); let active_checkpoint = restored.story_checkpoint.as_ref().unwrap(); assert_eq!( active_checkpoint.after_event_count as usize, checkpoint_prefix ); assert_eq!(active_checkpoint.state.hash, checkpoint.state.hash); assert_eq!(restored_image.packs, checkpoint.state.image.packs); assert_eq!(restored_image.items, checkpoint.state.image.items); assert_eq!( restored_image.ground_items, checkpoint.state.image.ground_items ); assert_eq!( restored_image.packs[&player].items[&selected_id], checkpoint_instance ); assert!(!restored_image.items.contains_key(&selected_id)); assert!(!restored_image.ground_items.contains_key(&selected_id)); assert!(restored_image.chapel_debts.contains_key(&player));
assert_eq!( &restored.events[..checkpoint_prefix], &checkpoint_saved.events[..checkpoint_prefix], "resurrection must retain the genuine checkpoint prefix" ); assert!(matches!( restored.events[checkpoint_prefix].kind, SessionEventKind::Action(CommittedAction::Drop { item_id }) if item_id == selected_id )); let attack_count = restored.events[checkpoint_prefix + 1..] .iter() .filter(|event| { matches!( event.kind, SessionEventKind::Action(CommittedAction::ResolveAttack { .. }) ) }) .count(); assert_eq!( attack_count, 4, "seed-223 route must record four combat exchanges" ); let restored_hash = restored.current.try_hash_state().unwrap(); let resurrection = restored .events .iter() .find_map(|event| match event.kind { SessionEventKind::StoryResurrect { checkpoint_after_event_count, checkpoint_hash, dead_state_hash, restored_state_hash, } => Some(( checkpoint_after_event_count, checkpoint_hash, dead_state_hash, restored_state_hash, )), _ => None, }) .expect("recorded Story resurrection event"); assert_eq!(resurrection.0 as usize, checkpoint_prefix); assert_eq!(resurrection.1, checkpoint.state.hash); assert_ne!(resurrection.2, checkpoint.state.hash); assert_eq!(resurrection.3, restored_hash);
let replay = ProductionReplay { identity: restored.identity.clone(), events: restored.events.clone(), expected_final_tick: restored.current.tick, expected_final_hash: restored_hash, }; let replay_path = harness.root.join("story-transfer-history.hexdemo"); fs::write(&replay_path, encode_replay(&replay).unwrap()).unwrap(); let decoded_replay = decode_replay(&bounded(&replay_path, MAX_COMPRESSED_BYTES), pack.hash()) .expect("decode replay labeled from durable Story history"); assert_eq!(decoded_replay.events, restored.events); assert_actual_replay(&harness, &replay_path, restored_hash);}
#[test]fn binary_classic_transfer_death_recovery_and_replay() { let harness = Harness::new("ac12-classic-transfer-lifecycle"); let pack = hexwork_content::RuntimePack::load(&harness.content).unwrap(); let initial_script = harness.script( "classic-transfer-cycle.commands", &format!("{TRANSFER_CYCLE}save\nquit\n"), ); let initial_output = Harness::run(new_command(&harness, &initial_script, false)); assert_success(&initial_output, "Classic transfer cycle process"); let run_id = allocation_run_id(&initial_output); let parsed_run_id = run_id.parse::<RunId>().unwrap(); let run_dir = harness.data.join("runs").join(&run_id); let initial = decode_saved(&harness, &pack, &run_id); assert_eq!(initial.identity.seed, SEED); assert_eq!( initial.identity.ancestry, hexwork_core::character::Ancestry::Mudborn ); assert_eq!( initial.identity.calling, hexwork_core::character::Calling::Ratcatcher ); let selected_id = transfer_cycle_item(&initial.events); let player = player_id(&initial); let selected_instance = initial.current.to_image().unwrap().packs[&player].items[&selected_id].clone();
let replay_path = run_dir.join("replay.hexdemo"); let pending_path = run_dir.join("death.pending"); let committed_path = run_dir.join("death.committed"); let epitaph_path = run_dir.join("epitaph.txt"); let managed_run_path = run_dir.join("run.save"); let vault_path = harness.data.join("lineage-vault.json"); let living_vault = bounded(&vault_path, MAX_VAULT_BYTES); fs::write(&replay_path, CONFLICTING_REPLAY).expect("install regular replay-file conflict");
let lethal_script = harness.script( "classic-recorded-lethal.commands", &grate_mother_death_script(SEED), ); let failed = Harness::run(load_command(&harness, &lethal_script, &run_id, false)); assert_exit(&failed, 3, "immutable-artifact-mismatch"); let failed_records = Harness::records(&failed); let failed_positions = milestone_positions( &failed_records, &["terminal-snapshot-durable", "pending-death-durable"], ); assert!(failed_positions[0] < failed_positions[1]); let failed_codes = failed_records .iter() .filter_map(|record| field(record, "code").as_str()) .collect::<Vec<_>>(); for forbidden in [ "replay-durable", "epitaph-durable", "vault-death-durable", "committed-death-durable", "run-retired-durable", "pending-retired-durable", ] { assert!(!failed_codes.contains(&forbidden), "unexpected {forbidden}"); } assert!(managed_run_path.is_file()); assert!(pending_path.is_file()); assert!(!committed_path.exists()); assert!(!epitaph_path.exists()); assert_eq!( bounded(&replay_path, SMALL_EVIDENCE_CAP), CONFLICTING_REPLAY ); assert_eq!(bounded(&vault_path, MAX_VAULT_BYTES), living_vault);
let terminal = decode_saved(&harness, &pack, &run_id); assert_eq!( &terminal.events[..initial.events.len()], initial.events.as_slice() ); assert_eq!(transfer_cycle_item(&terminal.events), selected_id); assert_eq!( terminal .events .iter() .filter(|event| matches!( event.kind, SessionEventKind::Action(CommittedAction::ResolveAttack { .. }) )) .count(), 4 ); let terminal_image = terminal.current.to_image().unwrap(); let terminal_player = terminal_image .actors .iter() .find(|actor| actor.id == player) .expect("terminal Player"); assert!(!terminal_player.alive && terminal_player.hp <= 0); assert_eq!( terminal_image.packs[&player].items[&selected_id], selected_instance ); let terminal_hash = terminal.current.try_hash_state().unwrap(); let terminal_bytes = bounded(&managed_run_path, MAX_COMPRESSED_BYTES); let pending_bytes = bounded(&pending_path, MAX_MARKER_BYTES);
let retained = || { ( bounded(&managed_run_path, MAX_COMPRESSED_BYTES), bounded(&pending_path, MAX_MARKER_BYTES), bounded(&replay_path, SMALL_EVIDENCE_CAP), bounded(&vault_path, MAX_VAULT_BYTES), ) }; let retained_before = ( terminal_bytes, pending_bytes, CONFLICTING_REPLAY.to_vec(), living_vault, ); let blocked_recover = Harness::run(recover_command(&harness)); assert_exit(&blocked_recover, 3, "immutable-artifact-mismatch"); assert_eq!(retained(), retained_before);
fs::remove_file(&replay_path).expect("remove only regular replay obstacle"); let recovered = Harness::run(recover_command(&harness)); assert_success(&recovered, "independent Classic recovery"); let recovered_records = Harness::records(&recovered); let recovery_positions = milestone_positions( &recovered_records, &[ "replay-durable", "epitaph-durable", "vault-death-durable", "committed-death-durable", "run-retired-durable", "pending-retired-durable", ], ); assert!(recovery_positions.windows(2).all(|pair| pair[0] < pair[1])); assert!(!managed_run_path.exists()); assert!(!pending_path.exists()); assert!(committed_path.is_file()); assert!(epitaph_path.is_file());
let replay_bytes = bounded(&replay_path, MAX_COMPRESSED_BYTES); let replay = decode_replay(&replay_bytes, pack.hash()).expect("death-produced replay"); assert_eq!(replay.identity.run_id, parsed_run_id); assert_eq!(replay.events, terminal.events); assert_eq!(transfer_cycle_item(&replay.events), selected_id); assert_eq!(replay.expected_final_tick, terminal.current.tick); assert_eq!(replay.expected_final_hash, terminal_hash); assert_actual_replay(&harness, &replay_path, terminal_hash);
let vault = decode_vault(&bounded(&vault_path, MAX_VAULT_BYTES)).unwrap(); let receipt = vault .applied_deaths .get(&parsed_run_id) .expect("death receipt for actual run"); assert_eq!(receipt.terminal_core_hash, terminal_hash); let selected_lot = vault .current .auction_lots .iter() .find(|lot| lot.origin_run_id == parsed_run_id && lot.origin_item_id == selected_id) .expect("selected transferred instance has death provenance"); assert_eq!(selected_lot.template_id, selected_instance.template); assert_eq!(selected_lot.material, selected_instance.material); assert_eq!(selected_lot.identified, selected_instance.identified); assert_eq!(selected_lot.cursed, selected_instance.cursed); assert_eq!(selected_lot.blessed, selected_instance.blessed); assert_eq!(selected_lot.condition, selected_instance.condition); assert_eq!(selected_lot.silvered, selected_instance.silvered); assert_eq!(selected_lot.illegal, selected_instance.illegal); assert_eq!(selected_lot.tags, selected_instance.tags); assert_eq!(selected_lot.fuel, selected_instance.fuel); assert_eq!(selected_lot.wet_ticks, selected_instance.wet_ticks);
let stable_completed = || { ( bounded(&vault_path, MAX_VAULT_BYTES), bounded(&replay_path, MAX_COMPRESSED_BYTES), bounded(&epitaph_path, MAX_EPITAPH_BYTES), bounded(&committed_path, MAX_MARKER_BYTES), ) }; let completed = stable_completed(); let repeated = Harness::run(recover_command(&harness)); assert_success(&repeated, "idempotent repeated recovery"); let repeated_codes = Harness::records(&repeated) .iter() .filter_map(|record| field(record, "code").as_str().map(str::to_owned)) .collect::<Vec<_>>(); assert!(repeated_codes.iter().all(|code| ![ "replay-durable", "epitaph-durable", "vault-death-durable", "committed-death-durable", "run-retired-durable", "pending-retired-durable", ] .contains(&code.as_str()))); assert_eq!(stable_completed(), completed);}