1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use clap::{Args, Subcommand};
#[derive(Debug, Args)]
pub(crate) struct TestBenchArgs {
#[command(subcommand)]
pub command: TestBenchCommand,
}
#[derive(Debug, Subcommand)]
pub(crate) enum TestBenchCommand {
/// Execute a .harn script under a hermetic testbench: paused clock,
/// optional LLM fixtures, optional filesystem overlay, optional
/// subprocess tape, and a deny-by-default network policy.
Run(TestBenchRunArgs),
/// Replay a previously recorded subprocess tape against a script
/// and assert the run produces a byte-identical tape.
Replay(TestBenchReplayArgs),
}
#[derive(Debug, Args, Clone)]
pub(crate) struct TestBenchRunArgs {
/// Path to the .harn script to execute.
pub file: String,
/// Pin the unified mock clock to this UNIX-epoch millisecond value
/// before the script runs. Defaults to a fixed deterministic
/// timestamp when `--clock paused` is requested without `--start-at`.
#[arg(long = "start-at", value_name = "UNIX_MS")]
pub start_at_ms: Option<i64>,
/// `paused` (default) or `real`. Selects whether the clock is
/// pinned at all.
#[arg(long = "clock", default_value = "paused", value_name = "MODE")]
pub clock: String,
/// Replay LLM responses from a JSONL fixture (same format as
/// `harn run --llm-mock`).
#[arg(
long = "llm-fixture",
value_name = "PATH",
conflicts_with = "llm_record"
)]
pub llm_fixture: Option<String>,
/// Record executed LLM responses into a JSONL fixture for a future
/// replay.
#[arg(
long = "llm-record",
value_name = "PATH",
conflicts_with = "llm_fixture"
)]
pub llm_record: Option<String>,
/// Mount a copy-on-write filesystem overlay rooted at the given
/// worktree path. Reads pass through; writes stay in memory until
/// the run ends.
#[arg(long = "fs-overlay", value_name = "DIR")]
pub fs_overlay: Option<String>,
/// Replay subprocess invocations from a tape produced by a previous
/// `--process-record` run.
#[arg(
long = "process-replay",
value_name = "PATH",
conflicts_with = "process_record"
)]
pub process_replay: Option<String>,
/// Record subprocess invocations to a tape file. The tape captures
/// (program, args, cwd, stdout, stderr, exit, virtual Δt) tuples.
#[arg(
long = "process-record",
value_name = "PATH",
conflicts_with = "process_replay"
)]
pub process_record: Option<String>,
/// Network policy. `deny` (default) blocks every outbound request
/// unless `--allow-host` matches; `real` reverts to the host's
/// configured policy.
#[arg(long = "network", default_value = "deny", value_name = "MODE")]
pub network: String,
/// Allow outbound traffic to a host or CIDR. Repeatable. Equivalent
/// to a comma-separated `HARN_EGRESS_ALLOW`. Only effective with
/// `--network deny`.
#[arg(long = "allow-host", value_name = "HOST_OR_CIDR")]
pub allow_host: Vec<String>,
/// Emit a unified-style diff of overlay filesystem writes to this
/// path. Requires `--fs-overlay`.
#[arg(long = "emit-diff", value_name = "PATH", requires = "fs_overlay")]
pub emit_diff: Option<String>,
/// Positional script arguments. Pass after `--`:
/// `harn test-bench run script.harn -- a b c`.
#[arg(last = true)]
pub argv: Vec<String>,
}
#[derive(Debug, Args, Clone)]
pub(crate) struct TestBenchReplayArgs {
/// Path to the .harn script to replay.
pub file: String,
/// Subprocess tape produced by a prior `harn test-bench run
/// --process-record` invocation. The script must request the same
/// (program, args, cwd) tuples in the same order.
#[arg(long = "process-tape", value_name = "PATH")]
pub process_tape: String,
/// Pin the unified mock clock to this UNIX-epoch millisecond value
/// before replay. Default matches the testbench-run default.
#[arg(long = "start-at", value_name = "UNIX_MS")]
pub start_at_ms: Option<i64>,
/// LLM JSONL fixture to replay alongside the subprocess tape.
#[arg(long = "llm-fixture", value_name = "PATH")]
pub llm_fixture: Option<String>,
/// Filesystem overlay root for replay (matches the run-side flag).
#[arg(long = "fs-overlay", value_name = "DIR")]
pub fs_overlay: Option<String>,
#[arg(last = true)]
pub argv: Vec<String>,
}