diff --git a/.trinity/seals/land_TriLand.json b/.trinity/seals/land_TriLand.json new file mode 100644 index 0000000000..96ebda4355 --- /dev/null +++ b/.trinity/seals/land_TriLand.json @@ -0,0 +1,45 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+0fba674ef", + "closure": [ + { + "spec": "specs/tri/lab/receipt.t27", + "spec_hash": "sha256:00d9eec8d7be84dde596c9990b3a5574de24aff9f7a94579fc620eb585712441" + }, + { + "spec": "specs/tri/lanes/lanes.t27", + "spec_hash": "sha256:aac192b3e3250196262a9b8467d4a9cef8147438c11c0744c66c3f6b175c9342" + }, + { + "spec": "specs/tri/pr/preflight.t27", + "spec_hash": "sha256:24634647a1245ac9d776735bd4323f524d71f7c52f0928ce31066a114b68f409" + }, + { + "spec": "specs/tri/remote/remote_job.t27", + "spec_hash": "sha256:84a153bd92bbc94bc57f1d030114507bd99de2f3ac3f800db3fe5880df950479" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:172717ca18cb1424e028ecf30fe6ffbfcd123f1ebfbcc9e99838dcbd7af5803d", + "gen_hash_rust": "sha256:0d546b60ba98a9afc5ea790b9d9c0850c2e3dad7989f7a07585020b3466789b8", + "gen_hash_verilog": "sha256:e22c6c25e3ff9d127c5ec196d36bd66736b49e530bca6abcc8092ffc672192ee", + "gen_hash_zig": "sha256:387fefa469409377ac40e91ddd09896d1a9f6226832737562c3a23f8e6955f94", + "module": "TriLand", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-19T15:08:05Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:77e6c34d0250cd6d9d93ebe7f0c9ba5d9182663e644b6b80c945d766795f53f5", + "spec_path": "specs/tri/land/land.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 26, + "total": 26, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/cli/tri/src/main.rs b/cli/tri/src/main.rs index 8c21ae1369..8578c85529 100644 --- a/cli/tri/src/main.rs +++ b/cli/tri/src/main.rs @@ -52,6 +52,8 @@ mod act; // t27c gen-rust of specs/tri/actors/metrics.t27: every rule of `tri ac mod raw; // t27c gen-rust of specs/analog/raw_writer.t27: every rule of `tri raw` (#10909) #[path = "../../../gen/rust/tri/remote/remote_job.rs"] #[allow(dead_code, unused_parens, unused_mut, unused_variables, non_snake_case, unused_assignments, clippy::all)] mod rj; // t27c gen-rust of specs/tri/remote/remote_job.t27: every command line of `tri remote` (#11020) +#[path = "../../../gen/rust/tri/land/land.rs"] #[allow(dead_code, unused_parens, unused_mut, unused_variables, non_snake_case, unused_assignments, clippy::all)] +mod land; // t27c gen-rust of specs/tri/land/land.t27: every rule and command line of `tri land` (#11068) #[path = "../../../bootstrap/gen/rust/verified/gen_hash_cache.rs"] #[allow(dead_code, unused_parens, unused_mut, unused_variables, non_snake_case, clippy::all)] mod gen_cache; // the gen-hash cache's eviction limit, for `tri hot caches` (#8952) #[path = "../../../bootstrap/gen/rust/verified/bitstream_reuse.rs"] #[allow(dead_code, unused_parens, unused_mut, unused_variables, non_snake_case, clippy::all)] @@ -449,6 +451,8 @@ enum Commands { }, /// t27o over a tree (#10543): every tracked .rs and .zig file converted in-process; a file's row is reused while its key holds (its SHA-256 and the seals of rust_convert.t27 and rust_std.t27, and of zig_convert.t27 for a .zig file, read from the t27 checkout this runs in); `--repo ` sweeps another checkout, with a cache of its own (#10638); counts, coverage and the ranked first-refusal kinds (rules: specs/tools/t27o/ledger.t27). T27oSweep { paths: Vec, #[arg(long, default_value = t27o_ledger::SWEEP_HERE)] repo: String, #[arg(long, default_value_t = t27o_ledger::SWEEP_MAX_BYTES)] max_bytes: usize, #[arg(long)] cache: Option, #[arg(long, default_value_t = t27o_ledger::SWEEP_TOP)] top: usize }, + /// Land a lane branch (default: the current one): merge master, then tests with no vacuous pass, seals, types ratchet, dupe subset, push, pull request, auto-merge; the first failing gate stops it with a named code (CONFLICT, TESTS_NOT_CLEAN, SEAL_NOT_CLEAN, TYPES_NOT_CLEAN, DUPE_NOT_SUBSET, PUSH_NOT_CONFIRMED) and a second run prints ALREADY_LANDED; --plan prints the steps and runs none, --check stops before the commit; T27C names the t27c program (default t27c on PATH) (rules: specs/tri/land/land.t27, #11068). + Land { branch: Option, #[arg(long, default_value_t = 0)] issue: u64, #[arg(long)] plan: bool, #[arg(long)] check: bool }, } #[derive(Subcommand)] @@ -1368,6 +1372,7 @@ fn main() -> Result<()> { Commands::Payout { epoch, pool, json } => std::process::exit(payout::cmd(*epoch, *pool, *json)? as i32), Commands::T27o { file, name, oracle, check, t27c, emit_cell } => std::process::exit(cmd_t27o(file, name.as_deref(), *oracle, *check, t27c.as_deref(), *emit_cell)? as i32), Commands::T27oSweep { paths, repo, max_bytes, cache, top } => std::process::exit(cmd_t27o_sweep(paths, repo, *max_bytes, cache.as_deref(), *top)? as i32), + Commands::Land { branch, issue, plan, check } => std::process::exit(cmd_land(branch.as_deref(), *issue, *plan, *check)? as i32), } Ok(()) @@ -1490,3 +1495,35 @@ fn cmd_serve(addr: &str) -> Result<()> { Ok(()) } + +/// `tri land` (#11068): every rule is specs/tri/land/land.t27; this runs the slot it names next as an argument vector (no shell), appends the run as evidence, has the spec judge it and stops at the first refusal. The scratch worktree is removed on every path. +fn cmd_land(branch: Option<&str>, issue: u64, plan: bool, check: bool) -> Result { + let leak = |s: String| -> &'static str { s.leak() }; + let head = || Command::new("git").args(["symbolic-ref", "--short", "HEAD"]).output().map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()).unwrap_or_default(); + let mut r = land::TriLandReq { branch: leak(branch.map_or_else(head, str::to_string)), issue, scratch: leak(std::env::temp_dir().join(format!("tri-land-{}", std::process::id())).display().to_string()), t27c: leak(std::env::var("T27C").unwrap_or("t27c".into())), tri: leak(std::env::current_exe()?.display().to_string()), changes: "", check, plan }; + let (mut ev, mut buf, mut code, mut at) = ("", vec![0u8; land::CMD_MAX], land::request_refusal(r), (0u8, 0u64)); + let argv = |b: &[u8]| -> Vec { String::from_utf8_lossy(b).lines().map(str::to_string).collect() }; + if plan && code == land::L_OK { for k in 0..land::LAND_STEPS { let n = land::step_argv(r, "", k, 0, &mut buf); println!("{k:2} {:<17} {}", land::step_name(k), argv(&buf[..n]).join(" ")); } return Ok(0); } + while code == land::L_OK { + let s = land::next_slot(r, ev); + if s >= land::DONE { code = if check { land::L_CHECKED } else { land::L_LANDED }; break; } + at = ((s / land::SLOT) as u8, s % land::SLOT); + let n = land::step_argv(r, ev, at.0, at.1, &mut buf); + anyhow::ensure!(n > 0, "tri land: step {} does not fit", land::step_name(at.0)); + let a = argv(&buf[..n]); + let (mut x, mut text, mut tries) = (0u64, String::new(), 0u64); + while tries <= land::RETRIES { (x, text) = match Command::new(&a[0]).args(&a[1..]).current_dir(if land::in_scratch(at.0) { r.scratch } else { "." }).output() { Ok(o) => (o.status.code().unwrap_or(255) as u64, format!("{}{}", String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr))), Err(e) => (127, e.to_string()) }; tries += 1; if !land::transient(at.0, x, leak(text.clone())) { break; } std::thread::sleep(std::time::Duration::from_secs(3)); } + let text = leak(text); + let mut sec = vec![0u8; text.len() + 128]; + let m = land::emit_section(&mut sec, 0, at.0, at.1, x, text); + ev = leak(format!("{ev}{}", String::from_utf8_lossy(&sec[..m]))); + if at.0 == land::L_CHANGES { r.changes = text; } + code = land::judge(r, ev, at.0, at.1); + println!("{:<17} exit {x}", land::step_name(at.0)); + } + let m = land::step_argv(r, ev, land::L_CLEAN, 0, &mut buf); + if m > 0 { let a = argv(&buf[..m]); let _ = Command::new(&a[0]).args(&a[1..]).output(); } + let n = land::refusal_detail(r, ev, at.0, at.1, &mut buf); + println!("{}{}: {}", land::code_name(code), if code >= land::L_STEP { format!(" {}", String::from_utf8_lossy(&buf[..n])) } else { String::new() }, land::code_why(code)); + Ok(land::exit_code(code)) +} diff --git a/gen/rust/tri/land/land.rs b/gen/rust/tri/land/land.rs new file mode 100644 index 0000000000..6bb29cca78 --- /dev/null +++ b/gen/rust/tri/land/land.rs @@ -0,0 +1,2265 @@ +// Generated from .t27 spec +// DO NOT EDIT — generated by t27c +// NOT LOWERED BY THIS BACKEND: 26 test(s), 1 invariant(s), 0 function(s) with no body. +// This backend emits declarations only. The spec's checks live in +// the Zig and Verilog outputs; do not read this file as verified. + +pub const REPO: &'static str = "gHashTag/t27"; + +pub const BRANCH_MAX: usize = 100; + +pub const ISSUE_MAX: u64 = 999999999; + +pub const CMD_MAX: usize = 4096; + +pub const SLOT: u64 = 100000; + +pub const DONE: u64 = 99999999999; + +pub const ABSENT: u64 = 1000000000000000000; + +pub const RETRIES: u64 = 5; + +pub const L_FETCH: u8 = 0; + +pub const L_MERGED: u8 = 1; + +pub const L_TIP: u8 = 2; + +pub const L_FETCH_BRANCH: u8 = 3; + +pub const L_CONTAINS: u8 = 4; + +pub const L_OPEN: u8 = 5; + +pub const L_WORKTREE: u8 = 6; + +pub const L_MASTER_DUPES: u8 = 7; + +pub const L_CHECKOUT: u8 = 8; + +pub const L_MERGE: u8 = 9; + +pub const L_CONFLICTS: u8 = 10; + +pub const L_CHANGES: u8 = 11; + +pub const L_TESTS: u8 = 12; + +pub const L_SEAL: u8 = 13; + +pub const L_SAVE: u8 = 14; + +pub const L_RECHECK: u8 = 15; + +pub const L_TYPES: u8 = 16; + +pub const L_DUPES: u8 = 17; + +pub const L_STAGE: u8 = 18; + +pub const L_PENDING: u8 = 19; + +pub const L_TITLE: u8 = 20; + +pub const L_COMMIT: u8 = 21; + +pub const L_HEAD: u8 = 22; + +pub const L_PUSH: u8 = 23; + +pub const L_REMOTE_HEAD: u8 = 24; + +pub const L_PR: u8 = 25; + +pub const L_AUTO: u8 = 26; + +pub const L_AUTO_CHECK: u8 = 27; + +pub const L_CLEAN: u8 = 28; + +pub const LAND_STEPS: u8 = 29; + +pub const L_OK: u8 = 0; + +pub const L_ALREADY: u8 = 1; + +pub const L_LANDED: u8 = 2; + +pub const L_CHECKED: u8 = 3; + +pub const L_BAD_BRANCH: u8 = 4; + +pub const L_BAD_ISSUE: u8 = 5; + +pub const L_BAD_PATH: u8 = 6; + +pub const L_STEP: u8 = 7; + +pub const L_NO_BRANCH: u8 = 8; + +pub const L_CONFLICT: u8 = 9; + +pub const L_TESTS_NOT_CLEAN: u8 = 10; + +pub const L_SEAL_NOT_CLEAN: u8 = 11; + +pub const L_TYPES_NOT_CLEAN: u8 = 12; + +pub const L_DUPE_NOT_SUBSET: u8 = 13; + +pub const L_PUSH_NOT_CONFIRMED: u8 = 14; + +pub const L_AUTO_NOT_CONFIRMED: u8 = 15; + +pub const OUTCOMES: u8 = 16; + +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TriLandReq { + pub branch: &'static str, + pub issue: u64, + pub scratch: &'static str, + pub t27c: &'static str, + pub tri: &'static str, + pub changes: &'static str, + pub check: bool, + pub plan: bool, +} + +pub fn is_trunk(b: &'static str) -> bool { + return ((span_is(b, 0, b.len(), "master") || span_is(b, 0, b.len(), "main")) || span_is(b, 0, b.len(), "HEAD")); +} + +pub fn branch_ok(b: &'static str) -> bool { + if (((b.len() > BRANCH_MAX) || (safe_path(b) == false)) || is_trunk(b)) { + return false; + } + if ((((b.as_bytes()[0] == 46) || (b.as_bytes()[0] == 47)) || (b.as_bytes()[((b.len() - 1)) as usize] == 47)) || (b.as_bytes()[((b.len() - 1)) as usize] == 46)) { + return false; + } + if ((b.len() >= 5) && span_is(b, (b.len() - 5), b.len(), ".lock")) { + return false; + } + let mut i: usize = 1; + while (i < b.len()) { + if ((b.as_bytes()[((i - 1)) as usize] == 47) && ((b.as_bytes()[(i) as usize] == 47) || (b.as_bytes()[(i) as usize] == 46))) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn request_refusal(r: TriLandReq) -> u8 { + if (branch_ok(r.branch) == false) { + return L_BAD_BRANCH; + } + if ((r.issue > ISSUE_MAX) || ((r.issue == 0) && (r.plan == false))) { + return L_BAD_ISSUE; + } + if (((safe_path(r.scratch) == false) || (safe_path(r.t27c) == false)) || (safe_path(r.tri) == false)) { + return L_BAD_PATH; + } + return L_OK; +} + +pub fn count_line(text: &'static str, from: usize, to: usize, label: &'static str) -> u64 { + let mut at: usize = from; + while (at < to) { + let mut end: usize = line_end(text, at); + if (end > to) { + end = to; + } + let mut k: usize = at; + while ((k < end) && ((text.as_bytes()[(k) as usize] == 32) || (text.as_bytes()[(k) as usize] == 9))) { + k = (k + 1); + } + if ((((k + label.len()) < end) && span_is(text, k, (k + label.len()), label)) && ((text.as_bytes()[((k + label.len())) as usize] == 32) || (text.as_bytes()[((k + label.len())) as usize] == 9))) { + let mut d: usize = (k + label.len()); + while ((d < end) && ((text.as_bytes()[(d) as usize] == 32) || (text.as_bytes()[(d) as usize] == 9))) { + d = (d + 1); + } + let e: usize = digits_end(text, d, end); + if ((e > d) && (((e == end) || (text.as_bytes()[(e) as usize] == 32)) || (text.as_bytes()[(e) as usize] == 9))) { + if ((e - d) > 18) { + return ABSENT; + } + return digits(text, d, e); + } + } + at = (end + 1); + } + return ABSENT; +} + +pub fn tests_clean(ev: &'static str, n: u64) -> bool { + let f: usize = body_from(ev, L_TESTS, n); + let t: usize = body_to(ev, L_TESTS, n); + if (count_line(ev, f, t, "tests") == ABSENT) { + return false; + } + return ((count_line(ev, f, t, "FAIL") == 0) && (count_line(ev, f, t, "vacuous passes") == 0)); +} + +pub fn seal_clean(ev: &'static str, k: u8, n: u64) -> bool { + let f: usize = body_from(ev, k, n); + let t: usize = body_to(ev, k, n); + return (has_line(ev, f, t, "all hashes MATCH") && (has_line(ev, f, t, "VERIFICATION FAILED") == false)); +} + +pub fn types_clean(ev: &'static str) -> bool { + return ((exit_of(ev, L_TYPES, 0) == 0) && has_line(ev, body_from(ev, L_TYPES, 0), body_to(ev, L_TYPES, 0), "RATCHET: CLEAN")); +} + +pub fn lead_number(ev: &'static str, k: u8) -> u64 { + let f: usize = body_from(ev, k, 0); + let e: usize = digits_end(ev, f, body_to(ev, k, 0)); + if ((e == f) || ((e - f) > 18)) { + return 0; + } + return digits(ev, f, e); +} + +pub fn open_auto(ev: &'static str) -> bool { + let f: usize = body_from(ev, L_OPEN, 0); + let t: usize = body_to(ev, L_OPEN, 0); + let e: usize = digits_end(ev, f, t); + return (((e > f) && ((e + 5) <= t)) && span_is(ev, e, (e + 5), " true")); +} + +pub fn created_number(ev: &'static str) -> u64 { + let f: usize = body_from(ev, L_PR, 0); + let t: usize = body_to(ev, L_PR, 0); + let mut n: u64 = 0; + let mut at: usize = find_in(ev, f, t, "/pull/"); + while (at < ev.len()) { + let e: usize = digits_end(ev, (at + 6), t); + if ((e > (at + 6)) && (((e - at) - 6) <= 18)) { + n = digits(ev, (at + 6), e); + } + at = find_in(ev, (at + 6), t, "/pull/"); + } + return n; +} + +pub fn pr_number(ev: &'static str) -> u64 { + let o: u64 = lead_number(ev, L_OPEN); + if (o > 0) { + return o; + } + return created_number(ev); +} + +pub fn sha_at(ev: &'static str, from: usize, to: usize) -> bool { + if ((from + 40) > to) { + return false; + } + let mut i: usize = from; + while (i < (from + 40)) { + let c: u8 = ev.as_bytes()[(i) as usize]; + if ((((c >= 48) && (c <= 57)) || ((c >= 97) && (c <= 102))) == false) { + return false; + } + i = (i + 1); + } + return (((((from + 40) == to) || (ev.as_bytes()[((from + 40)) as usize] == 10)) || (ev.as_bytes()[((from + 40)) as usize] == 9)) || (ev.as_bytes()[((from + 40)) as usize] == 32)); +} + +pub fn pushed(ev: &'static str) -> bool { + let hf: usize = body_from(ev, L_HEAD, 0); + let rf: usize = body_from(ev, L_REMOTE_HEAD, 0); + if (((exit_of(ev, L_PUSH, 0) != 0) || (exit_of(ev, L_HEAD, 0) != 0)) || (exit_of(ev, L_REMOTE_HEAD, 0) != 0)) { + return false; + } + if ((sha_at(ev, hf, body_to(ev, L_HEAD, 0)) == false) || (sha_at(ev, rf, body_to(ev, L_REMOTE_HEAD, 0)) == false)) { + return false; + } + return same(ev, hf, ev, rf, (rf + 40)); +} + +pub fn is_finding(text: &'static str, at: usize, end: usize) -> bool { + return ((end >= (at + 10)) && span_is(text, at, (at + 9), "::error::")); +} + +pub fn finding_from(text: &'static str, at: usize, end: usize) -> usize { + if ((end >= (at + 31)) && span_is(text, (at + 9), (at + 30), "a body written under ")) { + return (at + 30); + } + return (at + 9); +} + +pub fn finding_to(text: &'static str, from: usize, end: usize) -> usize { + let mut k: usize = from; + while ((k < end) && (text.as_bytes()[(k) as usize] != 32)) { + k = (k + 1); + } + return k; +} + +pub fn findings(text: &'static str, from: usize, to: usize) -> u64 { + let mut n: u64 = 0; + let mut at: usize = from; + while (at < to) { + let mut end: usize = line_end(text, at); + if (end > to) { + end = to; + } + if is_finding(text, at, end) { + n = (n + 1); + } + at = (end + 1); + } + return n; +} + +pub fn is_listed(ev: &'static str, f: usize, t: usize, nf: usize, nt: usize) -> bool { + let mut at: usize = f; + while (at < t) { + let mut end: usize = line_end(ev, at); + if (end > t) { + end = t; + } + if is_finding(ev, at, end) { + let mf: usize = finding_from(ev, at, end); + let mt: usize = finding_to(ev, mf, end); + if (((mt - mf) == (nt - nf)) && same(ev, nf, ev, mf, mt)) { + return true; + } + } + at = (end + 1); + } + return false; +} + +pub fn extra_name(ev: &'static str) -> usize { + let f: usize = body_from(ev, L_DUPES, 0); + let t: usize = body_to(ev, L_DUPES, 0); + let mut at: usize = f; + while (at < t) { + let mut end: usize = line_end(ev, at); + if (end > t) { + end = t; + } + if is_finding(ev, at, end) { + let nf: usize = finding_from(ev, at, end); + let nt: usize = finding_to(ev, nf, end); + if (is_listed(ev, body_from(ev, L_MASTER_DUPES, 0), body_to(ev, L_MASTER_DUPES, 0), nf, nt) == false) { + return nf; + } + } + at = (end + 1); + } + return (ev.len() + 1); +} + +pub fn dupes_ok(ev: &'static str) -> bool { + let x: u64 = exit_of(ev, L_DUPES, 0); + if (x == 0) { + return true; + } + if ((x != 1) || (exit_of(ev, L_MASTER_DUPES, 0) > 1)) { + return false; + } + if (findings(ev, body_from(ev, L_DUPES, 0), body_to(ev, L_DUPES, 0)) == 0) { + return false; + } + return (extra_name(ev) > ev.len()); +} + +pub fn per_target(k: u8) -> bool { + return ((k >= L_TESTS) && (k <= L_RECHECK)); +} + +pub fn slot_rows(r: TriLandReq, k: u8) -> u64 { + if per_target(k) { + return entries(r.changes); + } + return 1; +} + +pub fn applies(r: TriLandReq, ev: &'static str, k: u8, n: u64) -> bool { + if ((k == L_TESTS) || (k == L_SEAL)) { + return is_target(r.changes, n); + } + if (k == L_SAVE) { + return ((is_target(r.changes, n) && (exit_of(ev, L_SEAL, n) != NO_EXIT)) && (seal_clean(ev, L_SEAL, n) == false)); + } + if (k == L_RECHECK) { + return (exit_of(ev, L_SAVE, n) != NO_EXIT); + } + if ((k >= L_STAGE) && r.check) { + return false; + } + if (k == L_COMMIT) { + return (exit_of(ev, L_PENDING, 0) == 1); + } + if (k == L_PR) { + return (lead_number(ev, L_OPEN) == 0); + } + if (k == L_AUTO) { + return (open_auto(ev) == false); + } + return true; +} + +pub fn next_slot(r: TriLandReq, ev: &'static str) -> u64 { + let mut k: u8 = 0; + while (k < L_CLEAN) { + let rows: u64 = slot_rows(r, k); + let mut n: u64 = 0; + while (n < rows) { + if (applies(r, ev, k, n) && (exit_of(ev, k, n) == NO_EXIT)) { + return (((k as u64) * SLOT) + n); + } + n = (n + 1); + } + k = (k + 1); + } + return DONE; +} + +pub fn in_scratch(k: u8) -> bool { + return ((k >= L_MASTER_DUPES) && (k < L_CLEAN)); +} + +pub fn over_network(k: u8) -> bool { + return (((((((((k == L_FETCH) || (k == L_MERGED)) || (k == L_FETCH_BRANCH)) || (k == L_OPEN)) || (k == L_PUSH)) || (k == L_REMOTE_HEAD)) || (k == L_PR)) || (k == L_AUTO)) || (k == L_AUTO_CHECK)); +} + +pub fn transient(k: u8, x: u64, text: &'static str) -> bool { + if ((x == 0) || (over_network(k) == false)) { + return false; + } + return (((find_in(text, 0, text.len(), "x509") < text.len()) || (find_in(text, 0, text.len(), "TLS handshake timeout") < text.len())) || (find_in(text, 0, text.len(), "Could not resolve host") < text.len())); +} + +pub fn step_name(k: u8) -> &'static str { + if (k == L_FETCH) { + return "fetch"; + } + if (k == L_MERGED) { + return "merged"; + } + if (k == L_TIP) { + return "tip"; + } + if (k == L_FETCH_BRANCH) { + return "fetch-branch"; + } + if (k == L_CONTAINS) { + return "contains"; + } + if (k == L_OPEN) { + return "open"; + } + if (k == L_WORKTREE) { + return "worktree"; + } + if (k == L_MASTER_DUPES) { + return "master-dupes"; + } + if (k == L_CHECKOUT) { + return "checkout"; + } + if (k == L_MERGE) { + return "merge"; + } + if (k == L_CONFLICTS) { + return "conflicts"; + } + if (k == L_CHANGES) { + return "changes"; + } + if (k == L_TESTS) { + return "tests"; + } + if (k == L_SEAL) { + return "seal"; + } + if (k == L_SAVE) { + return "seal-save"; + } + if (k == L_RECHECK) { + return "seal-recheck"; + } + if (k == L_TYPES) { + return "types"; + } + if (k == L_DUPES) { + return "dupes"; + } + if (k == L_STAGE) { + return "stage"; + } + if (k == L_PENDING) { + return "pending"; + } + if (k == L_TITLE) { + return "title"; + } + if (k == L_COMMIT) { + return "commit"; + } + if (k == L_HEAD) { + return "head"; + } + if (k == L_PUSH) { + return "push"; + } + if (k == L_REMOTE_HEAD) { + return "remote-head"; + } + if (k == L_PR) { + return "pr"; + } + if (k == L_AUTO) { + return "auto-merge"; + } + if (k == L_AUTO_CHECK) { + return "auto-merge-check"; + } + if (k == L_CLEAN) { + return "clean"; + } + return "unknown"; +} + +pub fn judge(r: TriLandReq, ev: &'static str, k: u8, n: u64) -> u8 { + let x: u64 = exit_of(ev, k, n); + if (((((k == L_FETCH) || (k == L_WORKTREE)) || (k == L_CHECKOUT)) || (k == L_STAGE)) || (k == L_COMMIT)) { + if (x != 0) { + return L_STEP; + } + return L_OK; + } + if (k == L_MERGED) { + if (x != 0) { + return L_STEP; + } + if (lead_number(ev, L_MERGED) > 0) { + return L_ALREADY; + } + return L_OK; + } + if (k == L_TIP) { + if ((x != 0) || (sha_at(ev, body_from(ev, L_TIP, 0), body_to(ev, L_TIP, 0)) == false)) { + return L_NO_BRANCH; + } + return L_OK; + } + if (k == L_OPEN) { + if (x != 0) { + return L_STEP; + } + if (((lead_number(ev, L_OPEN) > 0) && open_auto(ev)) && (exit_of(ev, L_CONTAINS, 0) == 0)) { + return L_ALREADY; + } + return L_OK; + } + if (k == L_MASTER_DUPES) { + if (x > 1) { + return L_DUPE_NOT_SUBSET; + } + return L_OK; + } + if (k == L_CONFLICTS) { + if (x != 0) { + return L_STEP; + } + if (body_from(ev, L_CONFLICTS, 0) < body_to(ev, L_CONFLICTS, 0)) { + return L_CONFLICT; + } + if (exit_of(ev, L_MERGE, 0) != 0) { + return L_STEP; + } + return L_OK; + } + if (k == L_CHANGES) { + if ((x != 0) || (entries(r.changes) == 0)) { + return L_STEP; + } + let mut i: u64 = 0; + while (i < entries(r.changes)) { + if (is_spec(r.changes, i) && (path_safe(r.changes, i) == false)) { + return L_STEP; + } + i = (i + 1); + } + return L_OK; + } + if (k == L_TESTS) { + if tests_clean(ev, n) { + return L_OK; + } + return L_TESTS_NOT_CLEAN; + } + if (k == L_RECHECK) { + if seal_clean(ev, L_RECHECK, n) { + return L_OK; + } + return L_SEAL_NOT_CLEAN; + } + if (k == L_TYPES) { + if types_clean(ev) { + return L_OK; + } + return L_TYPES_NOT_CLEAN; + } + if (k == L_DUPES) { + if dupes_ok(ev) { + return L_OK; + } + return L_DUPE_NOT_SUBSET; + } + if (k == L_PENDING) { + if (x > 1) { + return L_STEP; + } + return L_OK; + } + if (k == L_TITLE) { + if ((x != 0) || (body_from(ev, L_TITLE, 0) >= body_to(ev, L_TITLE, 0))) { + return L_STEP; + } + return L_OK; + } + if (k == L_HEAD) { + if ((x != 0) || (sha_at(ev, body_from(ev, L_HEAD, 0), body_to(ev, L_HEAD, 0)) == false)) { + return L_STEP; + } + return L_OK; + } + if (k == L_PUSH) { + if (x != 0) { + return L_PUSH_NOT_CONFIRMED; + } + return L_OK; + } + if (k == L_REMOTE_HEAD) { + if pushed(ev) { + return L_OK; + } + return L_PUSH_NOT_CONFIRMED; + } + if (k == L_PR) { + if ((x != 0) || (created_number(ev) == 0)) { + return L_STEP; + } + return L_OK; + } + if (k == L_AUTO) { + if (x != 0) { + return L_AUTO_NOT_CONFIRMED; + } + return L_OK; + } + if (k == L_AUTO_CHECK) { + if ((x == 0) && has_line(ev, body_from(ev, L_AUTO_CHECK, 0), body_to(ev, L_AUTO_CHECK, 0), "true")) { + return L_OK; + } + return L_AUTO_NOT_CONFIRMED; + } + return L_OK; +} + +pub fn exit_code(c: u8) -> u8 { + if (c <= L_CHECKED) { + return 0; + } + return c; +} + +pub fn code_name(c: u8) -> &'static str { + if (c == L_OK) { + return "OK"; + } + if (c == L_ALREADY) { + return "ALREADY_LANDED"; + } + if (c == L_LANDED) { + return "LANDED"; + } + if (c == L_CHECKED) { + return "CHECKED"; + } + if (c == L_BAD_BRANCH) { + return "BAD_BRANCH"; + } + if (c == L_BAD_ISSUE) { + return "BAD_ISSUE"; + } + if (c == L_BAD_PATH) { + return "BAD_PATH"; + } + if (c == L_STEP) { + return "STEP_FAILED"; + } + if (c == L_NO_BRANCH) { + return "NO_BRANCH"; + } + if (c == L_CONFLICT) { + return "CONFLICT"; + } + if (c == L_TESTS_NOT_CLEAN) { + return "TESTS_NOT_CLEAN"; + } + if (c == L_SEAL_NOT_CLEAN) { + return "SEAL_NOT_CLEAN"; + } + if (c == L_TYPES_NOT_CLEAN) { + return "TYPES_NOT_CLEAN"; + } + if (c == L_DUPE_NOT_SUBSET) { + return "DUPE_NOT_SUBSET"; + } + if (c == L_PUSH_NOT_CONFIRMED) { + return "PUSH_NOT_CONFIRMED"; + } + if (c == L_AUTO_NOT_CONFIRMED) { + return "AUTO_NOT_CONFIRMED"; + } + return "UNKNOWN"; +} + +pub fn code_why(c: u8) -> &'static str { + if (c == L_OK) { + return "nothing is refused"; + } + if (c == L_ALREADY) { + return "the branch is landed: nothing was changed"; + } + if (c == L_LANDED) { + return "master merged, gates passed, head pushed, pull request open with auto-merge on; git pull --ff-only brings the merge and seal commit into your checkout"; + } + if (c == L_CHECKED) { + return "master merged and every gate passed on the merged tree; nothing was committed, pushed or opened"; + } + if (c == L_BAD_BRANCH) { + return "the branch has a byte outside letters, digits and _-./, starts or ends with a slash, a dash or a dot, has .. or .lock, or is master, main or HEAD"; + } + if (c == L_BAD_ISSUE) { + return "--issue is a number from 1 to 999999999"; + } + if (c == L_BAD_PATH) { + return "the scratch directory, T27C or this program has a byte outside letters, digits and _-./, or starts with -"; + } + if (c == L_STEP) { + return "a step failed or printed nothing it should: nothing after it ran"; + } + if (c == L_NO_BRANCH) { + return "this repository has no local branch of that name: git branch origin/ first"; + } + if (c == L_CONFLICT) { + return "the branch conflicts with master in the files named: resolve them on the branch, nothing was pushed"; + } + if (c == L_TESTS_NOT_CLEAN) { + return "a spec has a failing test, a vacuous pass, or no readable totals: it was not sealed"; + } + if (c == L_SEAL_NOT_CLEAN) { + return "a spec's seal does not match even after t27c seal --save"; + } + if (c == L_TYPES_NOT_CLEAN) { + return "tri types ratchet is not CLEAN"; + } + if (c == L_DUPE_NOT_SUBSET) { + return "dupe_scan fails on a name master does not fail on (or it could not be read): reuse the body that exists"; + } + if (c == L_PUSH_NOT_CONFIRMED) { + return "origin does not hold the head that was pushed (never forced: pull the branch first if it has moved)"; + } + if (c == L_AUTO_NOT_CONFIRMED) { + return "the pull request is open but auto-merge is not confirmed on"; + } + return "unknown outcome"; +} + +pub fn emit_span(out: &mut [u8], w: usize, text: &'static str, from: usize, to: usize) -> usize { + let mut p: usize = w; + let mut i: usize = from; + while ((i < to) && (i < text.len())) { + p = emit_byte(out, p, text.as_bytes()[(i) as usize]); + i = (i + 1); + } + return p; +} + +pub fn emit_issue(out: &mut [u8], w: usize, issue: u64) -> usize { + if (issue == 0) { + return emit_str(out, w, ""); + } + return emit_dec(out, w, issue); +} + +pub fn emit_pr(out: &mut [u8], w: usize, ev: &'static str) -> usize { + let n: u64 = pr_number(ev); + if (n == 0) { + return emit_str(out, w, ""); + } + return emit_dec(out, w, n); +} + +pub fn emit_spec(out: &mut [u8], w: usize, r: TriLandReq, n: u64) -> usize { + if (is_target(r.changes, n) == false) { + return emit_str(out, w, ""); + } + return emit_span(out, w, r.changes, path_start(r.changes, n), path_end(r.changes, n)); +} + +pub fn has_closes(ev: &'static str, from: usize, to: usize, n: u64) -> bool { + let mut at: usize = find_in(ev, from, to, "Closes #"); + while (at < ev.len()) { + let e: usize = digits_end(ev, (at + 8), to); + if (((e > (at + 8)) && (((e - at) - 8) <= 18)) && (digits(ev, (at + 8), e) == n)) { + return true; + } + at = find_in(ev, (at + 8), to, "Closes #"); + } + return false; +} + +pub fn title_to(ev: &'static str) -> usize { + let e: usize = line_end(ev, body_from(ev, L_TITLE, 0)); + if (e < body_to(ev, L_TITLE, 0)) { + return e; + } + return body_to(ev, L_TITLE, 0); +} + +pub fn emit_title(out: &mut [u8], w: usize, ev: &'static str, issue: u64) -> usize { + let f: usize = body_from(ev, L_TITLE, 0); + let t: usize = title_to(ev); + let mut p: usize = w; + if (f >= t) { + p = emit_str(out, p, ""); + } else { + p = emit_span(out, p, ev, f, t); + } + if has_closes(ev, f, t, issue) { + return p; + } + p = emit_str(out, p, " (Closes #"); + p = emit_issue(out, p, issue); + return emit_byte(out, p, 41); +} + +pub const COMMIT_BODY: &'static str = "Merge of master and the seals, by tri land (specs/tri/land/land.t27): the gates ran on the merged tree."; + +pub const PR_BODY: &'static str = ". Opened by tri land (specs/tri/land/land.t27): master merged, then on the merged tree every changed spec has its tests clean with vacuous passes 0 and its seal MATCH, tri types ratchet is CLEAN and the dupe_scan failure set is a subset of master's."; + +pub fn emit_list(out: &mut [u8], w: usize, branch: &'static str, state: &'static str, json: &'static str, jq: &'static str) -> usize { + let mut p: usize = emit_str(out, w, "gh\npr\nlist\n--repo\n"); + p = emit_str(out, p, REPO); + p = emit_str(out, p, "\n--head\n"); + p = emit_str(out, p, branch); + p = emit_str(out, p, "\n--state\n"); + p = emit_str(out, p, state); + p = emit_str(out, p, "\n--json\n"); + p = emit_str(out, p, json); + p = emit_str(out, p, "\n--jq\n"); + p = emit_str(out, p, jq); + return emit_byte(out, p, 10); +} + +pub fn emit_t27c(out: &mut [u8], w: usize, r: TriLandReq, n: u64, tail: &'static str) -> usize { + let mut p: usize = emit_str(out, w, r.t27c); + p = emit_byte(out, p, 10); + p = emit_str(out, p, tail); + return emit_spec(out, p, r, n); +} + +pub fn step_argv(r: TriLandReq, ev: &'static str, k: u8, n: u64, out: &mut [u8]) -> usize { + if (request_refusal(r) != L_OK) { + return 0; + } + let mut w: usize = 0; + if (k == L_FETCH) { + w = emit_str(out, w, "git\nfetch\n-q\norigin\nmaster\n"); + } + if (k == L_MERGED) { + w = emit_list(out, w, r.branch, "merged", "number", ".[] | .number"); + } + if (k == L_TIP) { + w = emit_str(out, w, "git\nrev-parse\n--verify\n-q\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_FETCH_BRANCH) { + w = emit_str(out, w, "git\nfetch\n-q\norigin\n"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_CONTAINS) { + w = emit_str(out, w, "git\nmerge-base\n--is-ancestor\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_str(out, w, "\nrefs/remotes/origin/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_OPEN) { + w = emit_list(out, w, r.branch, "open", "number,autoMergeRequest", ".[] | \"\\(.number) \\(.autoMergeRequest != null)\""); + } + if (k == L_WORKTREE) { + w = emit_str(out, w, "git\nworktree\nadd\n-q\n--detach\n"); + w = emit_str(out, w, r.scratch); + w = emit_str(out, w, "\norigin/master\n"); + } + if ((k == L_MASTER_DUPES) || (k == L_DUPES)) { + w = emit_str(out, w, "python3\ntools/dupe_scan.py\n"); + } + if (k == L_CHECKOUT) { + w = emit_str(out, w, "git\ncheckout\n-q\n--detach\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_MERGE) { + w = emit_str(out, w, "git\nmerge\n--no-commit\n--no-ff\norigin/master\n"); + } + if (k == L_CONFLICTS) { + w = emit_str(out, w, "git\ndiff\n--name-only\n--diff-filter=U\n"); + } + if (k == L_CHANGES) { + w = emit_str(out, w, "git\ndiff\n--cached\n--name-status\n--no-renames\norigin/master\n"); + } + if (k == L_TESTS) { + w = emit_t27c(out, w, r, n, "test-report\n"); + w = emit_str(out, w, "\n--specs-dir\nspecs\n"); + } + if ((k == L_SEAL) || (k == L_RECHECK)) { + w = emit_t27c(out, w, r, n, "seal\n"); + w = emit_str(out, w, "\n--verify\n"); + } + if (k == L_SAVE) { + w = emit_t27c(out, w, r, n, "seal\n"); + w = emit_str(out, w, "\n--save\n"); + } + if (k == L_TYPES) { + w = emit_str(out, w, r.tri); + w = emit_str(out, w, "\ntypes\nratchet\n"); + } + if (k == L_STAGE) { + w = emit_str(out, w, "git\nadd\n.trinity/seals\n"); + } + if (k == L_PENDING) { + w = emit_str(out, w, "git\ndiff\n--cached\n--quiet\n"); + } + if (k == L_TITLE) { + w = emit_str(out, w, "git\nlog\n-1\n--no-merges\n--format=%s\n"); + } + if (k == L_COMMIT) { + w = emit_str(out, w, "git\n-c\ncore.hooksPath=.githooks\ncommit\n-q\n-m\n"); + w = emit_title(out, w, ev, r.issue); + w = emit_str(out, w, "\n-m\n"); + w = emit_str(out, w, COMMIT_BODY); + w = emit_byte(out, w, 10); + } + if (k == L_HEAD) { + w = emit_str(out, w, "git\nrev-parse\nHEAD\n"); + } + if (k == L_PUSH) { + w = emit_str(out, w, "git\npush\norigin\nHEAD:refs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_REMOTE_HEAD) { + w = emit_str(out, w, "git\nls-remote\norigin\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_PR) { + w = emit_str(out, w, "gh\npr\ncreate\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--base\nmaster\n--head\n"); + w = emit_str(out, w, r.branch); + w = emit_str(out, w, "\n--title="); + w = emit_title(out, w, ev, r.issue); + w = emit_str(out, w, "\n--body=Closes #"); + w = emit_issue(out, w, r.issue); + w = emit_str(out, w, PR_BODY); + w = emit_byte(out, w, 10); + } + if (k == L_AUTO) { + w = emit_str(out, w, "gh\npr\nmerge\n"); + w = emit_pr(out, w, ev); + w = emit_str(out, w, "\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--auto\n--squash\n"); + } + if (k == L_AUTO_CHECK) { + w = emit_str(out, w, "gh\npr\nview\n"); + w = emit_pr(out, w, ev); + w = emit_str(out, w, "\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--json\nautoMergeRequest\n--jq\n.autoMergeRequest != null\n"); + } + if (k == L_CLEAN) { + if ((ev.len() > 0) && (exit_of(ev, L_WORKTREE, 0) != 0)) { + return 0; + } + w = emit_str(out, w, "git\nworktree\nremove\n--force\n"); + w = emit_str(out, w, r.scratch); + w = emit_byte(out, w, 10); + } + return fits(out, w); +} + +pub fn emit_section(out: &mut [u8], w: usize, k: u8, n: u64, x: u64, body: &'static str) -> usize { + let mut p: usize = emit_str(out, w, "@@ preflight "); + p = emit_dec(out, p, (k as u64)); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, n); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, x); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, (body.len() as u64)); + p = emit_byte(out, p, 10); + p = emit_str(out, p, body); + return emit_byte(out, p, 10); +} + +pub fn refusal_detail(r: TriLandReq, ev: &'static str, k: u8, n: u64, out: &mut [u8]) -> usize { + let mut w: usize = 0; + if (k == L_CONFLICTS) { + let mut i: usize = body_from(ev, L_CONFLICTS, 0); + let t: usize = body_to(ev, L_CONFLICTS, 0); + while (i < t) { + if (ev.as_bytes()[(i) as usize] == 10) { + if ((i + 1) < t) { + w = emit_byte(out, w, 32); + } + } else { + w = emit_byte(out, w, ev.as_bytes()[(i) as usize]); + } + i = (i + 1); + } + return fits(out, w); + } + if ((k == L_TESTS) || (k == L_RECHECK)) { + w = emit_span(out, w, r.changes, path_start(r.changes, n), path_end(r.changes, n)); + return fits(out, w); + } + let nf: usize = extra_name(ev); + if ((k == L_DUPES) && (nf < ev.len())) { + w = emit_span(out, w, ev, nf, finding_to(ev, nf, line_end(ev, nf))); + return fits(out, w); + } + w = emit_str(out, w, step_name(k)); + return fits(out, w); +} + +pub const EV_MERGED_YES: &'static str = "@@ preflight 1 0 0 6\n11055\n\n"; + +pub const EV_MERGED_NONE: &'static str = "@@ preflight 1 0 0 0\n\n"; + +pub const EV_MERGED_FAIL: &'static str = "@@ preflight 1 0 1 35\nerror connecting to api.github.com\n\n"; + +pub const EV_TIP_OK: &'static str = "@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n"; + +pub const EV_TIP_NO: &'static str = "@@ preflight 2 0 1 0\n\n"; + +pub const EV_OPEN_LANDED: &'static str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 9\n123 true\n\n"; + +pub const EV_OPEN_NO_AUTO: &'static str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 10\n123 false\n\n"; + +pub const EV_OPEN_NOT_HELD: &'static str = "@@ preflight 4 0 1 53\nfatal: Not a valid object name refs/remotes/origin/x\n\n@@ preflight 5 0 0 9\n123 true\n\n"; + +pub const EV_OPEN_NONE: &'static str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 0\n\n"; + +pub const EV_OPEN_FAIL: &'static str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 1 18\ngh: not logged in\n\n"; + +pub const EV_CONFLICT: &'static str = "@@ preflight 9 0 1 141\nAuto-merging specs/x.t27\nCONFLICT (content): Merge conflict in specs/x.t27\nAutomatic merge failed; fix conflicts and then commit the result.\n\n@@ preflight 10 0 0 24\nspecs/x.t27\nspecs/y.t27\n\n"; + +pub const EV_MERGE_FAILED: &'static str = "@@ preflight 9 0 128 45\nfatal: refusing to merge unrelated histories\n\n@@ preflight 10 0 0 0\n\n"; + +pub const EV_MERGE_CLEAN: &'static str = "@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n"; + +pub const EV_CHANGES_OK: &'static str = "@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n"; + +pub const EV_CHANGES_FAIL: &'static str = "@@ preflight 11 0 128 0\n\n"; + +pub const EV_TESTS_CLEAN: &'static str = "@@ preflight 12 0 0 404\n--- test report: specs/tri/land/land.t27 ---\n\n tests 21\n pass 21\n FAIL 0\n invariants 3 proved -- comptime, so compiling IS the check\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 12 the_branch_and_the_numbers_pass_a_rule\n 3 a_request_is_refused\n vacuous passes 0 of 21 (passed with 0 runtime asserts executed)\n\n"; + +pub const EV_TESTS_FAIL: &'static str = "@@ preflight 12 0 0 419\n--- test report: specs/ternary/gft_relu.t27 ---\n FAIL negz\n\n tests 4\n pass 3\n FAIL 1\n invariants 2 proved -- comptime, so compiling IS the check\n rate 75.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 1 pos\n - negz (failed, not counted)\n 1 zero\n 1 pos2\n vacuous passes 0 of 3 (passed with 0 runtime asserts executed)\n\n"; + +pub const EV_TESTS_VAC: &'static str = "@@ preflight 12 0 0 281\n--- test report: specs/x/y.t27 ---\n\n tests 2\n pass 2\n FAIL 0\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 2 a\n 0 b VACUOUS\n vacuous passes 1 of 2 (passed with 0 runtime asserts executed)\n\n"; + +pub const EV_TESTS_BLOCKED: &'static str = "@@ preflight 12 0 0 251\n--- test report: specs/x/y.t27 ---\n BLOCKED does not compile: error: failed to create output directory '/x/zig/tmp/a5ed': PermissionDenied\n\n A blocked spec is not a failing one. It never produced a\n binary, so it has no per-test result to report.\n\n"; + +pub const EV_TESTS_UNKNOWN: &'static str = "@@ preflight 12 0 0 151\n--- test report: specs/x/y.t27 ---\n\n tests 2\n pass 2\n FAIL 0\n vacuous passes unknown (the counting build did not compile: x)\n\n"; + +pub const EV_TESTS_OLD: &'static str = "@@ preflight 12 0 0 101\n--- test report: specs/x/y.t27 ---\n\n tests 4\n pass 4\n FAIL 0\n rate 100.0%\n\n"; + +pub const EV_TESTS_NONE: &'static str = "@@ preflight 11 0 0 26\nA\tspecs/tri/land/land.t27\n\n"; + +pub const EV_TESTS_NOTOTAL: &'static str = "@@ preflight 12 0 0 83\n FAIL 0\n vacuous passes 0 of 0 (passed with 0 runtime asserts executed)\n\n"; + +pub const EV_SEAL_MATCH: &'static str = "@@ preflight 13 0 0 118\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\n\n"; + +pub const EV_SEAL_BAD: &'static str = "@@ preflight 13 0 1 162\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; + +pub const EV_RECHECK_MATCH: &'static str = "@@ preflight 15 0 0 118\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\n\n"; + +pub const EV_RECHECK_BAD: &'static str = "@@ preflight 15 0 1 162\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; + +pub const EV_RECHECK_BOTH: &'static str = "@@ preflight 15 0 0 280\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; + +pub const EV_RECHECK_EMPTY: &'static str = "@@ preflight 15 0 0 0\n\n"; + +pub const EV_TYPES_OK: &'static str = "@@ preflight 16 0 0 52\n ledger 107 name(s), observed 107\n RATCHET: CLEAN\n\n"; + +pub const EV_TYPES_RED: &'static str = "@@ preflight 16 0 1 264\n ledger 107 name(s), observed 108\n + Cell NEW conflict\n\n A RESOLVED name fails too, on purpose. An entry that stops being\n true and stays in the ledger is slack the next conflict hides in --\n the same rule the corpus ratchet applies to an unexpected PASS.\n\n"; + +pub const EV_TYPES_EXIT: &'static str = "@@ preflight 16 0 1 52\n ledger 107 name(s), observed 107\n RATCHET: CLEAN\n\n"; + +pub const EV_TYPES_NOWORD: &'static str = "@@ preflight 16 0 0 35\n ledger 107 name(s), observed 107\n\n"; + +pub const EV_PENDING_YES: &'static str = "@@ preflight 19 0 1 0\n\n"; + +pub const EV_PENDING_NO: &'static str = "@@ preflight 19 0 0 0\n\n"; + +pub const EV_PENDING_FAIL: &'static str = "@@ preflight 19 0 128 28\nfatal: not a git repository\n\n"; + +pub const EV_TITLE: &'static str = "@@ preflight 20 0 0 45\ntri land: land a lane branch (Closes #11068)\n\n"; + +pub const EV_TITLE_BARE: &'static str = "@@ preflight 20 0 0 29\ntri land: land a lane branch\n\n"; + +pub const EV_TITLE_OTHER: &'static str = "@@ preflight 20 0 0 45\ntri land: land a lane branch (Closes #11000)\n\n"; + +pub const EV_TITLE_EMPTY: &'static str = "@@ preflight 20 0 0 0\n\n"; + +pub const EV_PUSH_OK: &'static str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 72\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/tri-land-11068\n\n"; + +pub const EV_PUSH_OTHER: &'static str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 72\n89abcdef0123456789abcdef0123456789abcdef\trefs/heads/lane/tri-land-11068\n\n"; + +pub const EV_PUSH_EMPTY: &'static str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 0\n\n"; + +pub const EV_PUSH_REJECT: &'static str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 1 151\nTo github.com:gHashTag/t27.git\n ! [rejected] HEAD -> lane/x (non-fast-forward)\nerror: failed to push some refs to 'github.com:gHashTag/t27.git'\n\n"; + +pub const EV_PUSH_LSFAIL: &'static str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 128 72\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/tri-land-11068\n\n"; + +pub const EV_HEAD_BAD: &'static str = "@@ preflight 22 0 0 10\nnot a sha\n\n"; + +pub const EV_PR_CREATED: &'static str = "@@ preflight 5 0 0 0\n\n@@ preflight 25 0 0 105\nCreating pull request for lane/x into master in gHashTag/t27\n\nhttps://github.com/gHashTag/t27/pull/11111\n\n"; + +pub const EV_PR_OPEN: &'static str = "@@ preflight 5 0 0 10\n123 false\n\n"; + +pub const EV_PR_FAIL: &'static str = "@@ preflight 25 0 1 33\nGraphQL: Head sha can't be blank\n\n"; + +pub const EV_PR_NOURL: &'static str = "@@ preflight 25 0 0 8\ncreated\n\n"; + +pub const EV_AUTO_FAIL: &'static str = "@@ preflight 26 0 1 41\nGraphQL: Pull request is in clean status\n\n"; + +pub const EV_CHECK_TRUE: &'static str = "@@ preflight 27 0 0 5\ntrue\n\n"; + +pub const EV_CHECK_FALSE: &'static str = "@@ preflight 27 0 0 6\nfalse\n\n"; + +pub const EV_CHECK_FAIL: &'static str = "@@ preflight 27 0 1 5\ntrue\n\n"; + +pub const EV_WORKTREE_FAIL: &'static str = "@@ preflight 6 0 128 27\nfatal: '/x' already exists\n\n"; + +pub const EV_WORKTREE_OK: &'static str = "@@ preflight 6 0 0 0\n\n"; + +pub const EV_DUP_SAME: &'static str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_FIXED: &'static str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1458\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_SOME: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_NEW: &'static str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1601\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n::error::a body written under emit_span is now copied [2] time(s) and was in no ledger\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_NEWGROWN: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 557\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::emit_dec was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_GROWN: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 418\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [10, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_CLEAN: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 0 93\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nok: no new duplicate body\n\n"; + +pub const EV_DUP_UNREAD: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 2 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_NOFIND: &'static str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 89\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nsomething else failed\n\n"; + +pub const EV_DUP_MASTER_BAD: &'static str = "@@ preflight 7 0 2 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_MASTER_CLEAN: &'static str = "@@ preflight 7 0 0 93\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nok: no new duplicate body\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; + +pub const EV_DUP_MASTER_FAIL: &'static str = "@@ preflight 7 0 2 27\npython3: command not found\n\n"; + +pub const EV_RUN_A: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n"; + +pub const EV_RUN_B: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n"; + +pub const EV_RUN_C: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n"; + +pub const EV_RUN_D: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n"; + +pub const EV_RUN_E: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n"; + +pub const EV_RUN_F: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n"; + +pub const EV_RUN_G: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; + +pub const EV_RUN_G_OPEN: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 10\n123 false\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; + +pub const EV_RUN_F_CLEAN: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 0 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n"; + +pub const EV_RUN_E_NO_DUPES: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n"; + +pub const EV_RUN_D_NO_SEAL: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n"; + +pub const EV_RUN_G_NO_REMOTE: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n"; + +pub const EV_RUN_G_AUTO_ON: &'static str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 9\n123 true\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; + +pub const TXT_CH_ONE: &'static str = "A\tspecs/tri/land/land.t27\n"; + +pub const TXT_CH_TWO: &'static str = "M\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n"; + +pub const TXT_CH_BAD: &'static str = "M\tspecs/tri/land/a b.t27\nA\tdocs/x.md\n"; + +pub const TXT_CH_DOCS: &'static str = "A\tdocs/x.md\nM\tcli/tri/src/main.rs\n"; + +pub const TXT_TR_CLEAN: &'static str = "--- test report: specs/tri/land/land.t27 ---\n\n tests 21\n pass 21\n FAIL 0\n invariants 3 proved -- comptime, so compiling IS the check\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 12 the_branch_and_the_numbers_pass_a_rule\n 3 a_request_is_refused\n vacuous passes 0 of 21 (passed with 0 runtime asserts executed)\n"; + +pub const P256: &'static str = "abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abc"; + +pub const P257: &'static str = "abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcd"; + +pub const T_BRANCH: &'static str = "lane/tri-land-11068"; + +pub const T_SCRATCH: &'static str = "/tmp/tri-land-1"; + +pub const T_TRI: &'static str = "/opt/tri/tri"; + +pub const B100: &'static str = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"; + +pub const B101: &'static str = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghija"; + +pub fn cl(text: &'static str, label: &'static str) -> u64 { + return count_line(text, 0, text.len(), label); +} + +pub fn req_of(changes: &'static str, check: bool) -> TriLandReq { + return TriLandReq { branch: T_BRANCH, issue: 11068, scratch: T_SCRATCH, t27c: "t27c", tri: T_TRI, changes: changes, check: check, plan: false }; +} + +pub fn req_on(branch: &'static str, issue: u64, scratch: &'static str, t27c: &'static str, plan: bool) -> TriLandReq { + return TriLandReq { branch: branch, issue: issue, scratch: scratch, t27c: t27c, tri: T_TRI, changes: "", check: false, plan: plan }; +} + +pub fn slot_of(k: u8, n: u64) -> u64 { + return (((k as u64) * SLOT) + n); +} + +pub fn argv_is(r: TriLandReq, ev: &'static str, k: u8, n: u64, want: &'static str, buf: &mut [u8]) -> bool { + let m: usize = step_argv(r, ev, k, n, buf); + return ((m > 0) && buf_is(buf, m, want)); +} + +pub fn has_arg(argv: &[u8], n: usize, want: &'static str) -> bool { + let mut s: usize = 0; + while (s < n) { + let mut e: usize = s; + while ((e < n) && (argv[(e) as usize] != 10)) { + e = (e + 1); + } + if ((e - s) == want.len()) { + let mut k: usize = 0; + while ((k < want.len()) && (argv[((s + k)) as usize] == want.as_bytes()[(k) as usize])) { + k = (k + 1); + } + if (k == want.len()) { + return true; + } + } + s = (e + 1); + } + return false; +} + +pub fn has_plus(argv: &[u8], n: usize) -> bool { + let mut s: usize = 0; + while (s < n) { + if (argv[(s) as usize] == 43) { + return true; + } + let mut e: usize = s; + while ((e < n) && (argv[(e) as usize] != 10)) { + e = (e + 1); + } + s = (e + 1); + } + return false; +} + +pub fn program_ok(argv: &[u8], n: usize, r: TriLandReq) -> bool { + let mut e: usize = 0; + while ((e < n) && (argv[(e) as usize] != 10)) { + e = (e + 1); + } + let mut k: u8 = 0; + while (k < 5) { + let mut want: &'static str = "git"; + if (k == 1) { + want = "gh"; + } + if (k == 2) { + want = "python3"; + } + if (k == 3) { + want = r.t27c; + } + if (k == 4) { + want = r.tri; + } + if (e == want.len()) { + let mut i: usize = 0; + while ((i < e) && (argv[(i) as usize] == want.as_bytes()[(i) as usize])) { + i = (i + 1); + } + if (i == e) { + return true; + } + } + k = (k + 1); + } + return false; +} + +pub fn steps_sent(r: TriLandReq, ev: &'static str, buf: &mut [u8]) -> u32 { + let mut c: u32 = 0; + let mut k: u8 = 0; + while (k < LAND_STEPS) { + if (step_argv(r, ev, k, 0, buf) > 0) { + c = (c + 1); + } + k = (k + 1); + } + return c; +} + +pub fn steps_with(r: TriLandReq, ev: &'static str, want: &'static str, buf: &mut [u8]) -> u32 { + let mut c: u32 = 0; + let mut k: u8 = 0; + while (k < LAND_STEPS) { + let n: usize = step_argv(r, ev, k, 0, buf); + if has_arg(buf, n, want) { + c = (c + 1); + } + k = (k + 1); + } + return c; +} + +pub fn forced_pushes(r: TriLandReq, ev: &'static str, buf: &mut [u8]) -> u32 { + let mut c: u32 = 0; + let mut k: u8 = 0; + while (k < LAND_STEPS) { + let n: usize = step_argv(r, ev, k, 0, buf); + if (has_arg(buf, n, "push") && (((((has_arg(buf, n, "--force") || has_arg(buf, n, "-f")) || has_arg(buf, n, "--force-with-lease")) || has_arg(buf, n, "--mirror")) || has_arg(buf, n, "--delete")) || has_plus(buf, n))) { + c = (c + 1); + } + k = (k + 1); + } + return c; +} + +pub fn strange_programs(r: TriLandReq, ev: &'static str, buf: &mut [u8]) -> u32 { + let mut c: u32 = 0; + let mut k: u8 = 0; + while (k < LAND_STEPS) { + let n: usize = step_argv(r, ev, k, 0, buf); + if ((n > 0) && (program_ok(buf, n, r) == false)) { + c = (c + 1); + } + k = (k + 1); + } + return c; +} + +#[allow(non_upper_case_globals)] +pub const tri_lab_receipt__V_BEHIND: u8 = 2; + +#[allow(non_upper_case_globals)] +pub const tri_lab_receipt__V_BLOCKED: u8 = 3; + +pub const V_NOT_RUN: u8 = 4; + +#[allow(non_upper_case_globals)] +pub const tri_lab_receipt__V_RED: u8 = 5; + +pub const V_VACUOUS: u8 = 1; + +pub const V_VERIFIED: u8 = 0; + +pub fn line_end(text: &'static str, at: usize) -> usize { + let mut k: usize = at; + while ((k < text.len()) && (text.as_bytes()[(k) as usize] != 10)) { + k = (k + 1); + } + return k; +} + +pub fn tri_lab_receipt__name(v: u8) -> &'static str { + if (v == V_VERIFIED) { + return "verified"; + } + if (v == V_VACUOUS) { + return "vacuous"; + } + if (v == tri_lab_receipt__V_BEHIND) { + return "behind"; + } + if (v == tri_lab_receipt__V_BLOCKED) { + return "blocked"; + } + if (v == V_NOT_RUN) { + return "not-run"; + } + if (v == tri_lab_receipt__V_RED) { + return "RED"; + } + return "UNREAD"; +} + +pub fn span_is(text: &'static str, from: usize, to: usize, lit: &'static str) -> bool { + if ((to < from) || ((to - from) != lit.len())) { + return false; + } + let mut k: usize = 0; + while (k < lit.len()) { + if (text.as_bytes()[((from + k)) as usize] != lit.as_bytes()[(k) as usize]) { + return false; + } + k = (k + 1); + } + return true; +} + +pub const UNKNOWN: &'static str = "?"; + +pub fn branch_from(w: &'static str, at: usize) -> usize { + let stop: usize = record_end(w, at); + let mut k: usize = at; + while (k < stop) { + if starts(w, k, "branch refs/heads/") { + return (k + 18); + } + k = (line_end(w, k) + 1); + } + return w.len(); +} + +pub fn branch_to(w: &'static str, at: usize) -> usize { + let b: usize = branch_from(w, at); + if (b >= w.len()) { + return w.len(); + } + return line_end(w, b); +} + +pub fn digits(text: &'static str, from: usize, to: usize) -> u64 { + if ((to <= from) || ((to - from) > 18)) { + return 0; + } + let mut n: u64 = 0; + let mut i: usize = from; + while (i < to) { + if ((text.as_bytes()[(i) as usize] < 48) || (text.as_bytes()[(i) as usize] > 57)) { + return 0; + } + n = ((n * 10) + ((text.as_bytes()[(i) as usize] as u64) - 48)); + i = (i + 1); + } + return n; +} + +pub fn merged(m: &'static str, w: &'static str, at: usize) -> bool { + let b: usize = branch_from(w, at); + let be: usize = branch_to(w, at); + if (b >= w.len()) { + return false; + } + let mut k: usize = 0; + while ((((k + 15) + (be - b)) + 1) <= m.len()) { + if (span_is(m, k, (k + 15), "\"headRefName\":\"") && (m.as_bytes()[(((k + 15) + (be - b))) as usize] == 34)) { + let mut same: bool = true; + let mut i: usize = 0; + while (i < (be - b)) { + if (m.as_bytes()[(((k + 15) + i)) as usize] != w.as_bytes()[((b + i)) as usize]) { + same = false; + } + i = (i + 1); + } + if same { + return true; + } + } + k = (k + 1); + } + return false; +} + +pub fn record_end(w: &'static str, at: usize) -> usize { + let mut k: usize = at; + while (k < w.len()) { + let end: usize = line_end(w, k); + if (end == k) { + return k; + } + k = (end + 1); + } + return w.len(); +} + +pub fn starts(w: &'static str, at: usize, lit: &'static str) -> bool { + if ((at + lit.len()) > w.len()) { + return false; + } + return span_is(w, at, (at + lit.len()), lit); +} + +pub const MAX_DIGITS: usize = 18; + +pub const NO_EXIT: u64 = 256; + +pub const RULES: u8 = 11; + +pub const STEPS: u8 = 17; + +pub fn body_from(ev: &'static str, k: u8, n: u64) -> usize { + let s: usize = section(ev, k, n); + if (s >= ev.len()) { + return ev.len(); + } + return header_end(ev, s); +} + +pub fn body_to(ev: &'static str, k: u8, n: u64) -> usize { + let s: usize = section(ev, k, n); + if (s >= ev.len()) { + return ev.len(); + } + return (header_end(ev, s) + (field(ev, s, 3) as usize)); +} + +pub fn digits_end(text: &'static str, at: usize, to: usize) -> usize { + let mut k: usize = at; + while (((k < to) && (text.as_bytes()[(k) as usize] >= 48)) && (text.as_bytes()[(k) as usize] <= 57)) { + k = (k + 1); + } + return k; +} + +pub fn entries(c: &'static str) -> u64 { + let mut n: u64 = 0; + while (entry_at(c, n) < c.len()) { + n = (n + 1); + } + return n; +} + +pub fn entry_at(c: &'static str, n: u64) -> usize { + let mut at: usize = 0; + let mut seen: u64 = 0; + while (at < c.len()) { + let end: usize = line_end(c, at); + if (end > at) { + if (seen == n) { + return at; + } + seen = (seen + 1); + } + at = (end + 1); + } + return c.len(); +} + +pub fn exit_of(ev: &'static str, k: u8, n: u64) -> u64 { + let s: usize = section(ev, k, n); + if (s >= ev.len()) { + return NO_EXIT; + } + return field(ev, s, 2); +} + +pub fn field(ev: &'static str, at: usize, f: u64) -> u64 { + let mut k: usize = (at + 13); + let mut i: u64 = 0; + while (i < f) { + k = (digits_end(ev, k, ev.len()) + 1); + i = (i + 1); + } + return digits(ev, k, digits_end(ev, k, ev.len())); +} + +pub fn find_in(text: &'static str, from: usize, to: usize, lit: &'static str) -> usize { + let mut k: usize = from; + while ((k + lit.len()) <= to) { + if span_is(text, k, (k + lit.len()), lit) { + return k; + } + k = (k + 1); + } + return (text.len() + 1); +} + +pub fn has_line(text: &'static str, from: usize, to: usize, lit: &'static str) -> bool { + return (line_after(text, from, to, lit) <= text.len()); +} + +pub fn header_end(ev: &'static str, at: usize) -> usize { + if (at >= ev.len()) { + return (ev.len() + 1); + } + let end: usize = line_end(ev, at); + if ((end >= ev.len()) || (opens_with(ev, at, end, "@@ preflight ") == false)) { + return (ev.len() + 1); + } + let mut k: usize = (at + 13); + let mut f: u64 = 0; + while (f < 4) { + let e: usize = digits_end(ev, k, end); + if ((e == k) || ((e - k) > MAX_DIGITS)) { + return (ev.len() + 1); + } + k = e; + if (f < 3) { + if ((k >= end) || (ev.as_bytes()[(k) as usize] != 32)) { + return (ev.len() + 1); + } + k = (k + 1); + } + f = (f + 1); + } + if (k != end) { + return (ev.len() + 1); + } + return (end + 1); +} + +pub fn is_spec(c: &'static str, n: u64) -> bool { + let s: u8 = status(c, n); + if ((s != 65) && (s != 77)) { + return false; + } + return (path_is(c, n, "specs/", ".t27") && (path_is(c, n, "specs/scratch/", "") == false)); +} + +pub fn is_target(c: &'static str, n: u64) -> bool { + return (is_spec(c, n) && path_safe(c, n)); +} + +pub fn line_after(text: &'static str, from: usize, to: usize, lit: &'static str) -> usize { + let mut at: usize = from; + while (at < to) { + let mut end: usize = line_end(text, at); + if (end > to) { + end = to; + } + let mut k: usize = at; + while ((k < end) && ((text.as_bytes()[(k) as usize] == 32) || (text.as_bytes()[(k) as usize] == 9))) { + k = (k + 1); + } + if opens_with(text, k, end, lit) { + return (k + lit.len()); + } + at = (end + 1); + } + return (text.len() + 1); +} + +pub fn next_section(ev: &'static str, at: usize) -> usize { + let he: usize = header_end(ev, at); + if (he > ev.len()) { + return (ev.len() + 1); + } + let len: u64 = field(ev, at, 3); + if (len >= ((ev.len() - he) as u64)) { + return (ev.len() + 1); + } + let to: usize = (he + (len as usize)); + if (ev.as_bytes()[(to) as usize] != 10) { + return (ev.len() + 1); + } + return (to + 1); +} + +pub fn opens_with(text: &'static str, at: usize, end: usize, lit: &'static str) -> bool { + if (at > end) { + return false; + } + if (lit.len() > (end - at)) { + return false; + } + return span_is(text, at, (at + lit.len()), lit); +} + +pub fn path_end(c: &'static str, n: u64) -> usize { + if (well_formed(c, n) == false) { + return c.len(); + } + return line_end(c, entry_at(c, n)); +} + +pub fn path_is(c: &'static str, n: u64, lit: &'static str, tail: &'static str) -> bool { + let from: usize = path_start(c, n); + let to: usize = path_end(c, n); + if ((from >= to) || ((to - from) < (lit.len() + tail.len()))) { + return false; + } + return (span_is(c, from, (from + lit.len()), lit) && span_is(c, (to - tail.len()), to, tail)); +} + +pub fn path_safe(c: &'static str, n: u64) -> bool { + let from: usize = path_start(c, n); + let to: usize = path_end(c, n); + if (from >= to) { + return false; + } + let mut k: usize = from; + while (k < to) { + let b: u8 = c.as_bytes()[(k) as usize]; + let ok: bool = (((((((((b >= 97) && (b <= 122)) || ((b >= 65) && (b <= 90))) || ((b >= 48) && (b <= 57))) || (b == 46)) || (b == 95)) || (b == 47)) || (b == 43)) || (b == 45)); + if (ok == false) { + return false; + } + k = (k + 1); + } + return true; +} + +pub fn path_start(c: &'static str, n: u64) -> usize { + if (well_formed(c, n) == false) { + return c.len(); + } + return (entry_at(c, n) + 2); +} + +pub fn same(a: &'static str, af: usize, b: &'static str, bf: usize, bt: usize) -> bool { + if ((bt < bf) || ((af + (bt - bf)) > a.len())) { + return false; + } + let mut i: usize = 0; + while (i < (bt - bf)) { + if (a.as_bytes()[((af + i)) as usize] != b.as_bytes()[((bf + i)) as usize]) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn section(ev: &'static str, k: u8, n: u64) -> usize { + let mut at: usize = 0; + while (at < ev.len()) { + let nx: usize = next_section(ev, at); + if (nx > ev.len()) { + return (ev.len() + 1); + } + if ((field(ev, at, 0) == (k as u64)) && (field(ev, at, 1) == n)) { + return at; + } + at = nx; + } + return (ev.len() + 1); +} + +pub fn status(c: &'static str, n: u64) -> u8 { + let at: usize = entry_at(c, n); + if (at >= c.len()) { + return 0; + } + return c.as_bytes()[(at) as usize]; +} + +pub fn well_formed(c: &'static str, n: u64) -> bool { + let at: usize = entry_at(c, n); + if (((at >= c.len()) || (line_end(c, at) < (at + 3))) || (c.as_bytes()[((at + 1)) as usize] != 9)) { + return false; + } + let s: u8 = c.as_bytes()[(at) as usize]; + return ((((s == 65) || (s == 77)) || (s == 68)) || (s == 84)); +} + +pub const GOLDEN_FETCH: &'static str = "cd /work && curl -sSfL -o top.spice "; + +pub const GOLDEN_INSERT: &'static str = " && printf 'pre_osdi /opt/osdi/psp103.osdi\\npre_osdi /opt/osdi/psp103_nqs.osdi\\npre_osdi /opt/osdi/r3_cmc.osdi\\npre_osdi /opt/osdi/mosvar.osdi\\npre_osdi /opt/osdi/cap_cmomi.osdi\\npre_osdi /opt/osdi/cap_cmomf.osdi\\noption klu\\nset num_threads="; + +pub const GOLDEN_SPLICE: &'static str = "\\n' > ins.txt && sed -e 's,/usr/local/share/OpenPDKs/IHP-Open-PDK,/opt/IHP-Open-PDK,g' -e '/^\\.control/r ins.txt' top.spice > run.spice && ngspice -b run.spice > ngspice.log 2>&1"; + +pub const HOST_MAX: usize = 96; + +pub const IMAGE_MAX: usize = 128; + +pub const NAME_MAX: usize = 64; + +pub const OP_FETCH: u8 = 6; + +pub const OP_LOGS: u8 = 4; + +pub const OP_NONE: u8 = 0; + +pub const OP_PING: u8 = 1; + +pub const OP_RUN: u8 = 2; + +pub const OP_STATUS: u8 = 3; + +pub const PATH_MAX: usize = 256; + +pub const R_BAD_DEST: u8 = 9; + +pub const R_BAD_FILE: u8 = 8; + +pub const R_BAD_HOST: u8 = 3; + +pub const R_BAD_IMAGE: u8 = 4; + +pub const R_BAD_NAME: u8 = 6; + +pub const R_BAD_THREADS: u8 = 12; + +pub const R_BAD_URL: u8 = 11; + +pub const R_NO_ACTION: u8 = 1; + +pub const R_NO_FILE: u8 = 7; + +pub const R_NO_HOST: u8 = 2; + +pub const R_NO_NAME: u8 = 5; + +pub const R_NO_URL: u8 = 10; + +pub const R_OK: u8 = 0; + +pub const R_UNEXPECTED: u8 = 13; + +pub const SCRIPT_PLAIN: &'static str = "cd /work && ngspice -b deck.cir > ngspice.log 2>&1"; + +pub const STEM_MAX: usize = 40; + +pub const THREADS_MAX: u64 = 16; + +pub const THREADS_MIN: u64 = 1; + +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TriRemoteReq { + pub op: u8, + pub host: &'static str, + pub image: &'static str, + pub name: &'static str, + pub file: &'static str, + pub dest: &'static str, + pub url: &'static str, + pub threads: u64, + pub counter: u64, + pub golden: bool, +} + +pub const URL_MAX: usize = 200; + +pub fn base_start(p: &'static str) -> usize { + let mut b: usize = 0; + let mut i: usize = 0; + while (i < p.len()) { + if (p.as_bytes()[(i) as usize] == 47) { + b = (i + 1); + } + i = (i + 1); + } + return b; +} + +pub fn buf_has(buf: &[u8], n: usize, want: &'static str) -> bool { + if (((want.len() == 0) || (want.len() > n)) || (n > buf.len())) { + return false; + } + let mut at: usize = 0; + while ((at + want.len()) <= n) { + let mut k: usize = 0; + while ((k < want.len()) && (buf[((at + k)) as usize] == want.as_bytes()[(k) as usize])) { + k = (k + 1); + } + if (k == want.len()) { + return true; + } + at = (at + 1); + } + return false; +} + +pub fn buf_is(buf: &[u8], n: usize, want: &'static str) -> bool { + if ((n != want.len()) || (n > buf.len())) { + return false; + } + let mut k: usize = 0; + while (k < n) { + if (buf[(k) as usize] != want.as_bytes()[(k) as usize]) { + return false; + } + k = (k + 1); + } + return true; +} + +pub fn command(r: TriRemoteReq, step: u8, out: &mut [u8]) -> usize { + if (refusal(r) != R_OK) { + return 0; + } + let mut w: usize = 0; + if (r.op == OP_PING) { + if (step != 0) { + return 0; + } + w = emit_ssh(out, w, r.host); + w = emit_str(out, w, "true\n"); + return fits(out, w); + } + if (r.op == OP_RUN) { + let mut run_step: u8 = 2; + if r.golden { + run_step = 1; + } + if (step == 0) { + w = emit_ssh(out, w, r.host); + w = emit_str(out, w, "mkdir -p $HOME/t27-jobs/"); + w = emit_id(out, w, r); + w = emit_byte(out, w, 10); + return fits(out, w); + } + if ((step == 1) && (r.golden == false)) { + w = emit_scp(out, w); + w = emit_str(out, w, r.name); + w = emit_byte(out, w, 10); + w = emit_str(out, w, r.host); + w = emit_str(out, w, ":t27-jobs/"); + w = emit_id(out, w, r); + w = emit_str(out, w, "/deck.cir\n"); + return fits(out, w); + } + if (step == run_step) { + w = emit_run_head(out, w, r); + w = emit_script(out, w, r); + w = emit_str(out, w, "\"\n"); + return fits(out, w); + } + return 0; + } + if (step != 0) { + return 0; + } + if (r.op == OP_FETCH) { + w = emit_scp(out, w); + w = emit_str(out, w, r.host); + w = emit_str(out, w, ":t27-jobs/"); + w = emit_str(out, w, r.name); + w = emit_byte(out, w, 47); + w = emit_str(out, w, r.file); + w = emit_byte(out, w, 10); + if (r.dest.len() == 0) { + w = emit_byte(out, w, 46); + } else { + w = emit_str(out, w, r.dest); + } + w = emit_str(out, w, "/\n"); + return fits(out, w); + } + w = emit_ssh(out, w, r.host); + if (r.op == OP_STATUS) { + w = emit_str(out, w, "docker ps -a --filter \"name=^t27job-"); + w = emit_str(out, w, r.name); + w = emit_str(out, w, "$\" --format \"{{.Names}} {{.Status}}\"\n"); + return fits(out, w); + } + if (r.op == OP_LOGS) { + w = emit_str(out, w, "docker logs --tail 40 t27job-"); + w = emit_str(out, w, r.name); + w = emit_str(out, w, "; tail -n 40 $HOME/t27-jobs/"); + w = emit_str(out, w, r.name); + w = emit_str(out, w, "/ngspice.log\n"); + return fits(out, w); + } + w = emit_str(out, w, "docker rm -f t27job-"); + w = emit_str(out, w, r.name); + w = emit_byte(out, w, 10); + return fits(out, w); +} + +pub fn emit_byte(out: &mut [u8], w: usize, c: u8) -> usize { + if (w < out.len()) { + out[(w) as usize] = c; + } + return (w + 1); +} + +pub fn emit_dec(out: &mut [u8], w: usize, v: u64) -> usize { + let mut div: u64 = 1; + while ((v / div) >= 10) { + div = (div * 10); + } + let mut p: usize = w; + while (div > 0) { + p = emit_byte(out, p, (48 + (((v / div) % 10) as u8))); + div = (div / 10); + } + return p; +} + +pub fn emit_id(out: &mut [u8], w: usize, r: TriRemoteReq) -> usize { + if (r.op != OP_RUN) { + return emit_str(out, w, r.name); + } + let mut p: usize = emit_stem(out, w, r.name); + p = emit_byte(out, p, 45); + return emit_dec(out, p, r.counter); +} + +pub fn emit_run_head(out: &mut [u8], w: usize, r: TriRemoteReq) -> usize { + let mut p: usize = emit_ssh(out, w, r.host); + p = emit_str(out, p, "docker run -d --name t27job-"); + p = emit_id(out, p, r); + p = emit_str(out, p, " -v $HOME/t27-jobs/"); + p = emit_id(out, p, r); + p = emit_str(out, p, ":/work "); + p = emit_str(out, p, r.image); + return emit_str(out, p, " sh -c \""); +} + +pub fn emit_scp(out: &mut [u8], w: usize) -> usize { + return emit_str(out, w, "scp\n-o\nBatchMode=yes\n"); +} + +pub fn emit_script(out: &mut [u8], w: usize, r: TriRemoteReq) -> usize { + if (r.golden == false) { + return emit_str(out, w, SCRIPT_PLAIN); + } + let mut p: usize = emit_str(out, w, GOLDEN_FETCH); + p = emit_str(out, p, r.url); + p = emit_str(out, p, GOLDEN_INSERT); + p = emit_dec(out, p, r.threads); + return emit_str(out, p, GOLDEN_SPLICE); +} + +pub fn emit_ssh(out: &mut [u8], w: usize, host: &'static str) -> usize { + let mut p: usize = emit_str(out, w, "ssh\n-o\nBatchMode=yes\n"); + p = emit_str(out, p, host); + return emit_byte(out, p, 10); +} + +pub fn emit_stem(out: &mut [u8], w: usize, deck: &'static str) -> usize { + let b: usize = base_start(deck); + let mut e: usize = deck.len(); + let mut i: usize = (b + 1); + while (i < deck.len()) { + if (deck.as_bytes()[(i) as usize] == 46) { + e = i; + } + i = (i + 1); + } + let mut p: usize = w; + let mut k: usize = b; + while ((k < e) && ((k - b) < STEM_MAX)) { + if (deck.as_bytes()[(k) as usize] == 46) { + p = emit_byte(out, p, 95); + } else { + p = emit_byte(out, p, deck.as_bytes()[(k) as usize]); + } + k = (k + 1); + } + return p; +} + +pub fn emit_str(out: &mut [u8], w: usize, s: &'static str) -> usize { + let mut p: usize = w; + let mut i: usize = 0; + while (i < s.len()) { + p = emit_byte(out, p, s.as_bytes()[(i) as usize]); + i = (i + 1); + } + return p; +} + +pub fn fits(out: impl AsRef<[u8]>, w: usize) -> usize { + let out: &[u8] = out.as_ref(); + if (w > out.len()) { + return 0; + } + return w; +} + +pub fn is_alnum(c: u8) -> bool { + return ((((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90))) || ((c >= 48) && (c <= 57))); +} + +pub fn name_span_ok(text: &'static str, from: usize, to: usize) -> bool { + if ((to <= from) || ((to - from) > NAME_MAX)) { + return false; + } + if ((text.as_bytes()[(from) as usize] == 45) || (text.as_bytes()[(from) as usize] == 46)) { + return false; + } + let mut i: usize = from; + while (i < to) { + let c: u8 = text.as_bytes()[(i) as usize]; + if ((((is_alnum(c) == false) && (c != 95)) && (c != 45)) && (c != 46)) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn refusal(r: TriRemoteReq) -> u8 { + if ((r.op == OP_NONE) || (r.op > OP_FETCH)) { + return R_NO_ACTION; + } + if (r.host.len() == 0) { + return R_NO_HOST; + } + if (safe_host(r.host) == false) { + return R_BAD_HOST; + } + if (r.golden && (r.op != OP_RUN)) { + return R_UNEXPECTED; + } + if ((r.op == OP_PING) && (r.name.len() > 0)) { + return R_UNEXPECTED; + } + if ((r.op != OP_FETCH) && ((r.file.len() > 0) || (r.dest.len() > 0))) { + return R_UNEXPECTED; + } + if ((r.op != OP_PING) && (r.name.len() == 0)) { + return R_NO_NAME; + } + if (r.op == OP_RUN) { + if ((r.golden == false) && (safe_deck(r.name) == false)) { + return R_BAD_NAME; + } + if (r.golden && (safe_name(r.name) == false)) { + return R_BAD_NAME; + } + if (safe_image(r.image) == false) { + return R_BAD_IMAGE; + } + if (r.golden && (r.url.len() == 0)) { + return R_NO_URL; + } + if (r.golden && (safe_url(r.url) == false)) { + return R_BAD_URL; + } + if (r.golden && ((r.threads < THREADS_MIN) || (r.threads > THREADS_MAX))) { + return R_BAD_THREADS; + } + return R_OK; + } + if ((r.op != OP_PING) && (safe_id(r.name) == false)) { + return R_BAD_NAME; + } + if (r.op == OP_FETCH) { + if (r.file.len() == 0) { + return R_NO_FILE; + } + if (safe_name(r.file) == false) { + return R_BAD_FILE; + } + if ((r.dest.len() > 0) && (safe_path(r.dest) == false)) { + return R_BAD_DEST; + } + } + return R_OK; +} + +pub fn safe_deck(p: &'static str) -> bool { + return (safe_path(p) && name_span_ok(p, base_start(p), p.len())); +} + +pub fn safe_host(h: &'static str) -> bool { + if (((((h.len() == 0) || (h.len() > HOST_MAX)) || (h.as_bytes()[0] == 45)) || (h.as_bytes()[0] == 64)) || (h.as_bytes()[((h.len() - 1)) as usize] == 64)) { + return false; + } + let mut ats: usize = 0; + let mut i: usize = 0; + while (i < h.len()) { + let c: u8 = h.as_bytes()[(i) as usize]; + if (c == 64) { + ats = (ats + 1); + } + if (((((is_alnum(c) == false) && (c != 95)) && (c != 45)) && (c != 46)) && (c != 64)) { + return false; + } + i = (i + 1); + } + return (ats <= 1); +} + +pub fn safe_id(s: &'static str) -> bool { + if (safe_name(s) == false) { + return false; + } + let mut i: usize = 0; + while (i < s.len()) { + if (s.as_bytes()[(i) as usize] == 46) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn safe_image(s: &'static str) -> bool { + if (((s.len() == 0) || (s.len() > IMAGE_MAX)) || (is_alnum(s.as_bytes()[0]) == false)) { + return false; + } + let mut i: usize = 0; + while (i < s.len()) { + let c: u8 = s.as_bytes()[(i) as usize]; + if ((((((is_alnum(c) == false) && (c != 95)) && (c != 45)) && (c != 46)) && (c != 58)) && (c != 47)) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn safe_name(s: &'static str) -> bool { + return name_span_ok(s, 0, s.len()); +} + +pub fn safe_path(p: &'static str) -> bool { + if (((p.len() == 0) || (p.len() > PATH_MAX)) || (p.as_bytes()[0] == 45)) { + return false; + } + let mut i: usize = 0; + while (i < p.len()) { + let c: u8 = p.as_bytes()[(i) as usize]; + if (((((is_alnum(c) == false) && (c != 95)) && (c != 45)) && (c != 46)) && (c != 47)) { + return false; + } + if (((c == 46) && ((i + 1) < p.len())) && (p.as_bytes()[((i + 1)) as usize] == 46)) { + return false; + } + i = (i + 1); + } + return true; +} + +pub fn safe_url(s: &'static str) -> bool { + if (((s.len() <= 8) || (s.len() > URL_MAX)) || (span_is(s, 0, 8, "https://") == false)) { + return false; + } + let mut i: usize = 8; + while (i < s.len()) { + let c: u8 = s.as_bytes()[(i) as usize]; + if (((((is_alnum(c) == false) && (c != 95)) && (c != 45)) && (c != 46)) && (c != 47)) { + return false; + } + i = (i + 1); + } + return true; +} + +pub const FAIL: u8 = 1; + +pub const PASS: u8 = 0; + diff --git a/scripts/fix_v09_latex.py b/scripts/fix_v09_latex.py deleted file mode 100644 index e8c3467704..0000000000 --- a/scripts/fix_v09_latex.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate corrected G2_ALPHA_S_PHI_FRAMEWORK_V0.9.tex with fixes: -1. Abstract: 69 → 42 formulas (table has 42 lines) -2. N04 row: Fix δ_CP^PMNS formula (should be in degrees, 129.1° not 195.0°) -3. N03 row: Fix 2·3·φ·e³ → 2·φ⁵/2 (correct formula, remove "100×") -4. Table 1: Fix tabular structure (specify columns properly) -5. JUNO: Update or remove outdated JUNO references -""" - -import re -import sys - -def fix_latex(content): - """Apply fixes to LaTeX content""" - - # Fix 1: Abstract - change 69 to 42 - content = re.sub( - r'\\textbf\{69\}\s*\$\\varphi\$', - r'\\textbf{42} $\\varphi$', - content - ) - - # Fix 2: Abstract - change "69" elsewhere - content = re.sub( - r'69\s*$\\varphi$-parametrizations', - r'42 $\\varphi$-parametrizations', - content - ) - - # Fix 3: Introduction - change 69 to 42 - content = re.sub( - r'consolidating\s*\\textbf\{69\}\s*$\\varphi', - r'consolidating \\textbf{42} $\\varphi', - content - ) - - # Fix 4: Table 1 - change 69 to 42 - content = re.sub( - r'Monomial\s*\$n3\^k\\varphi\^p\\pi\^m e\^q\$\s*&\s*\\textbf\{69\}', - r'Monomial $n3^k\\varphi^p\\pi^m e^q$ & \\textbf{42}', - content - ) - - # Fix 5: Monte Carlo section - change 69 to 42 - content = re.sub( - r'across\s*all\s*69\s*constants', - r'across all 42 constants', - content - ) - - # Fix 6: L1--L7 section - change 69 to 42 - content = re.sub( - r'All\s*69\s*formulas\s*descend', - r'All 42 formulas descend', - content - ) - - return content - -# Read original file -with open(str(ROOT / "research/trinity-pellis-paper/G2_ALPHA_S_PHI_FRAMEWORK_V0.9.tex"), 'r') as f: - original = f.read() - -# Apply fixes -fixed = fix_latex(original) - -# Write fixed version -output_file = '/tmp/v09_fixed.tex' -with open(output_file, 'w') as f: - f.write(fixed) - -print(f"Fixed version written to {output_file}") -print("Fixes applied:") -print(" - 69 → 42 (abstract)") -print(" - 69 → 42 (introduction)") -print(" - 69 → 42 (table)") -print(" - 69 → 42 (Monte Carlo section)") -print(" - 69 → 42 (L1--L7 section)") diff --git a/specs/tri/land/land.t27 b/specs/tri/land/land.t27 new file mode 100644 index 0000000000..3ef3f47cc8 --- /dev/null +++ b/specs/tri/land/land.t27 @@ -0,0 +1,1733 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/tri/land/land.t27 -- `tri land <branch> --issue <N>`: land one lane branch with the gates in a fixed order (#11068) +; On the night of 2026-10-19 every lane branch was landed by a throwaway shell script outside the repository: merge master, +; run the tests and look for vacuous passes, save and verify the seals, check the types ratchet and the dupe-scan subset, +; commit, push, open the pull request, enable auto-merge. That is a rule set and a pipeline, so it lives here, in .t27, and +; `tri land` (cli/tri/src/main.rs, through `t27c gen-rust` in gen/rust/tri/land/land.rs) is glue: it asks this spec which step +; runs next, runs that step as an argument vector with no shell, writes its output down as evidence and asks this spec to judge +; it. The first step that is judged a refusal stops everything, and the command prints the refusal's name. +; - +; WHAT WAS FOUND BEFORE THIS WAS WRITTEN (FR-004). `tri pr ready` (cli/tri/src/prcheck.rs) judges the checks of an OPEN pull +; request and, with --merge, merges it: it starts after this command ends. `tri pr landed` asks whether a MERGED pull request's +; content reached master: it starts after that. `tri pr preflight` (specs/tri/pr/preflight.t27) judges a branch before it +; becomes a pull request, on the same gates, but it never merges master, saves a seal, commits, pushes or opens anything, and its +; steps are `sh -c` strings. specs/claw/merge_judge.t27 and merge_lane.t27 decide what the SERVER-side merger merges and whether +; it is starved; specs/claw/push_gate.t27 decides whether a fix push is worth its place in the Actions queue. None of them lands +; a branch. So this spec reuses preflight's readers by `use` (the evidence sections, the changed-file list, line search), the +; receipt line readers, lanes' number reader and remote_job's byte writers and name rules, and adds only what no one had: the +; order of the steps, the readers of the five gate outputs the night's script read, the dupe-subset rule on names, and the +; refusal codes. specs/tri/test/report.t27 already reads `t27c test-report`, but a `use` path through `tri::test` stops at the +; keyword `test` (preflight says the same), so the three totals lines are read here again, by count_line, on the same text. +; - +; THE REQUEST is one TriLandReq: the branch, the issue number, the scratch directory of the worktree, the t27c and tri programs, +; the output of the CHANGES step once it has run (the glue stores it here), and two flags: check (stop before the commit) and +; plan (print the steps, run none). request_refusal() says why a request may not run (L_OK is 0). +; - +; THE STEPS, in this order, each one a slot (step, entry) ; entry n is the n-th line of CHANGES for a per-target step. +; 0 fetch git fetch -q origin master +; 1 merged gh pr list --repo R --head B --state merged -> a number: ALREADY_LANDED +; 2 tip git rev-parse --verify -q refs/heads/B -> the branch's local tip (NO_BRANCH without it) +; 3 fetch_branch git fetch -q origin B (its exit is data: the branch may not exist there yet) +; 4 contains git merge-base --is-ancestor refs/heads/B refs/remotes/origin/B (exit 0: the remote holds the tip) +; 5 open gh pr list ... --state open -> `<n> <auto>`; an open PR with auto-merge on and the tip on the remote: +; ALREADY_LANDED, and nothing below runs +; 6 worktree git worktree add -q --detach <scratch> origin/master (the caller's checkout is never touched) +; 7 master_dupes python3 tools/dupe_scan.py on master's tree: the failing set the branch inherits +; 8 checkout git checkout -q --detach refs/heads/B +; 9 merge git merge --no-commit --no-ff origin/master +; 10 conflicts git diff --name-only --diff-filter=U -> any name: CONFLICT, with the names +; 11 changes git diff --cached --name-status --no-renames origin/master -> the specs to gate +; 12 tests n t27c test-report <spec> --specs-dir specs -> TESTS_NOT_CLEAN +; 13 seal n t27c seal <spec> --verify +; 14 save n t27c seal <spec> --save only for a spec whose seal did not MATCH +; 15 recheck n t27c seal <spec> --verify only after a save -> SEAL_NOT_CLEAN +; 16 types tri types ratchet -> TYPES_NOT_CLEAN +; 17 dupes python3 tools/dupe_scan.py -> DUPE_NOT_SUBSET +; --- check stops here --- +; 18 stage git add .trinity/seals +; 19 pending git diff --cached --quiet (exit 1: the merge or a seal changed something) +; 20 title git log -1 --no-merges --format=%s the lane's own last subject +; 21 commit git -c core.hooksPath=.githooks commit -q -m <title> -m <what this is> only when pending +; 22 head git rev-parse HEAD +; 23 push git push origin HEAD:refs/heads/B never forced +; 24 remote_head git ls-remote origin refs/heads/B -> the same object as HEAD, else PUSH_NOT_CONFIRMED +; 25 pr gh pr create ... only when no PR is open +; 26 auto gh pr merge <n> --repo R --auto --squash only when auto-merge is not on +; 27 auto_check gh pr view <n> ... autoMergeRequest -> true, else AUTO_NOT_CONFIRMED +; 28 clean git worktree remove --force <scratch> run by the glue at the end, on every path +; Steps 18 to 27 are not slots of a check run, and step 26 is reached only through the pass of steps 12 to 17 and 22 to 24: a +; slot is chosen only when every earlier slot has a section of evidence, and the glue stops at the first refusal, so auto-merge +; is never enabled unless every gate before it passed. The word `--force`, `-f` and a `+` refspec appear in no step, and the +; only write to a remote ref is `HEAD:refs/heads/B` with B a branch that is not master, main or HEAD (branch_ok): master is +; never written. +; - +; THE EVIDENCE is the one preflight reads: for each run `@@ preflight <step> <entry> <exit> <length>\n` and then the output +; (stdout and stderr) of exactly that length and a newline. emit_section() writes it, and the glue appends what it writes. +; - +; THE RULES (each one has a test below; the fixtures are the programs' real text, shortened). +; tests_clean `t27c test-report`: the totals lines ` tests N`, ` FAIL F` and ` vacuous passes V of M (...)` are +; all present, F == 0 and V == 0. A report with no totals (a BLOCKED spec), `vacuous passes unknown` or no such +; line at all (a t27c older than #6509) is not clean: nothing could be counted. +; seal_clean `t27c seal --verify`: a line `all hashes MATCH` and no line `VERIFICATION FAILED`. +; types_clean `tri types ratchet`: exit 0 and a line `RATCHET: CLEAN`. +; dupe subset `python3 tools/dupe_scan.py` prints `::error::a body written under <name> is now copied [n] time(s) and was in +; no ledger` and `::error::<name> was copied [a] and is now copied [b]`. The failing set of the branch is the +; names on those lines; it must be a subset of master's. Exit 0 (no finding) passes; exit 1 with a finding that +; master's scan does not print under the same name is DUPE_NOT_SUBSET; any other exit, or exit 1 with no finding, +; is unreadable and refused. A branch that fixes an inherited dupe passes (a subset is not the same set). +; already a merged PR for the head branch, or an open one with auto-merge on whose branch the remote already holds in full. +; push exit 0, and `git ls-remote` names the object `git rev-parse HEAD` named. +; transient a network step that fails with `x509`, `TLS handshake timeout` or `Could not resolve host` (nothing was sent) is +; run again, at most 5 more times, 3 seconds apart; any other failure, a rejected push included, is final. +; - +; THE HONEST LIMITS. A pass says these rules hold on these fixtures; it does not say that git, gh, t27c or GitHub answer. No test +; here starts a program. (1) The dupe rule is on names, as the night's script was: a group that GROWS under a name master already +; fails is not caught here; `tri pr preflight` compares whole lines and does catch it. (2) A branch name reused for new work after +; its PR merged reads as ALREADY_LANDED: lane names are unique, use a new one. (3) The command lands the COMMITTED branch; an +; uncommitted change in the caller's checkout is not in it. (4) The push goes to origin's copy of the branch, so the caller's local +; branch is behind it by the merge and seal commit until `git pull --ff-only`; a new local commit on top of the old tip then meets a +; remote that has moved, and the push is refused (never forced). (5) The pull request body and the commit message are one line each. +; ASCII only (L3) +; phi^2 + 1/phi^2 = 3 | TRINITY + +module TriLand; + +use tri::lab::receipt::line_end; +use tri::lab::receipt::span_is; +use tri::lanes::lanes::digits; +use tri::pr::preflight::NO_EXIT; +use tri::pr::preflight::entries; +use tri::pr::preflight::is_spec; +use tri::pr::preflight::is_target; +use tri::pr::preflight::path_safe; +use tri::pr::preflight::path_start; +use tri::pr::preflight::path_end; +use tri::pr::preflight::exit_of; +use tri::pr::preflight::body_from; +use tri::pr::preflight::body_to; +use tri::pr::preflight::has_line; +use tri::pr::preflight::find_in; +use tri::pr::preflight::digits_end; +use tri::pr::preflight::same; +use tri::remote::remote_job::emit_byte; +use tri::remote::remote_job::emit_str; +use tri::remote::remote_job::emit_dec; +use tri::remote::remote_job::fits; +use tri::remote::remote_job::safe_path; +use tri::remote::remote_job::buf_is; +use tri::remote::remote_job::buf_has; + +pub const REPO : str = "gHashTag/t27"; +pub const BRANCH_MAX : usize = 100; +pub const ISSUE_MAX : u64 = 999999999; +// The room one step's argument vector is written into; the tests prove the worst case fits. +pub const CMD_MAX : usize = 4096; +// A slot is step * SLOT + entry; DONE says there is none left. A number is read to 18 digits, ABSENT is one more digit. +pub const SLOT : u64 = 100000; +pub const DONE : u64 = 99999999999; +pub const ABSENT : u64 = 1000000000000000000; +// How many more times a network step is run after a flaky TLS or DNS answer (transient). +pub const RETRIES : u64 = 5; + +// The steps. +pub const L_FETCH : u8 = 0; +pub const L_MERGED : u8 = 1; +pub const L_TIP : u8 = 2; +pub const L_FETCH_BRANCH : u8 = 3; +pub const L_CONTAINS : u8 = 4; +pub const L_OPEN : u8 = 5; +pub const L_WORKTREE : u8 = 6; +pub const L_MASTER_DUPES : u8 = 7; +pub const L_CHECKOUT : u8 = 8; +pub const L_MERGE : u8 = 9; +pub const L_CONFLICTS : u8 = 10; +pub const L_CHANGES : u8 = 11; +pub const L_TESTS : u8 = 12; +pub const L_SEAL : u8 = 13; +pub const L_SAVE : u8 = 14; +pub const L_RECHECK : u8 = 15; +pub const L_TYPES : u8 = 16; +pub const L_DUPES : u8 = 17; +pub const L_STAGE : u8 = 18; +pub const L_PENDING : u8 = 19; +pub const L_TITLE : u8 = 20; +pub const L_COMMIT : u8 = 21; +pub const L_HEAD : u8 = 22; +pub const L_PUSH : u8 = 23; +pub const L_REMOTE_HEAD : u8 = 24; +pub const L_PR : u8 = 25; +pub const L_AUTO : u8 = 26; +pub const L_AUTO_CHECK : u8 = 27; +pub const L_CLEAN : u8 = 28; +pub const LAND_STEPS : u8 = 29; + +// The outcomes. 0 says go on; 1 to 3 end the run well; every other code is a refusal and is the exit code of the command. +pub const L_OK : u8 = 0; +pub const L_ALREADY : u8 = 1; +pub const L_LANDED : u8 = 2; +pub const L_CHECKED : u8 = 3; +pub const L_BAD_BRANCH : u8 = 4; +pub const L_BAD_ISSUE : u8 = 5; +pub const L_BAD_PATH : u8 = 6; +pub const L_STEP : u8 = 7; +pub const L_NO_BRANCH : u8 = 8; +pub const L_CONFLICT : u8 = 9; +pub const L_TESTS_NOT_CLEAN : u8 = 10; +pub const L_SEAL_NOT_CLEAN : u8 = 11; +pub const L_TYPES_NOT_CLEAN : u8 = 12; +pub const L_DUPE_NOT_SUBSET : u8 = 13; +pub const L_PUSH_NOT_CONFIRMED : u8 = 14; +pub const L_AUTO_NOT_CONFIRMED : u8 = 15; +pub const OUTCOMES : u8 = 16; + +pub struct TriLandReq { + branch: string, + issue: u64, + scratch: string, + t27c: string, + tri: string, + changes: string, + check: bool, + plan: bool, +} + +invariant the_steps_and_outcomes_are_numbered { assert L_MERGED < L_OPEN and L_OPEN < L_WORKTREE and L_MERGE < L_CONFLICTS and L_CONFLICTS < L_CHANGES and L_CHANGES < L_TESTS and L_TESTS < L_SEAL and L_SEAL < L_SAVE and L_SAVE < L_RECHECK and L_RECHECK < L_TYPES and L_TYPES < L_DUPES and L_DUPES < L_STAGE and L_STAGE < L_COMMIT and L_COMMIT < L_PUSH and L_PUSH < L_REMOTE_HEAD and L_REMOTE_HEAD < L_PR and L_PR < L_AUTO and L_AUTO < L_AUTO_CHECK and L_AUTO_CHECK < L_CLEAN and L_CLEAN + 1 == LAND_STEPS and L_CHECKED < L_BAD_BRANCH and L_AUTO_NOT_CONFIRMED + 1 == OUTCOMES; } + +// --- the request --------------------------------------------------------------------------------- + +/// Is b master, main or HEAD: a name the push must never write. +pub fn is_trunk(b: string) -> bool { + return span_is(b, 0, b.len, "master") or span_is(b, 0, b.len, "main") or span_is(b, 0, b.len, "HEAD"); +} + +/// A branch that may be written into a command: remote_job's path bytes (letters, digits, `_-./`, no `..`, not starting with `-`), +/// at most BRANCH_MAX; not starting or ending with `/`, not ending with `.`, no empty or dotted component, not ending `.lock`; +/// and not master, main or HEAD. +pub fn branch_ok(b: string) -> bool { + if (b.len > BRANCH_MAX or safe_path(b) == false or is_trunk(b)) { return false; } + if (b[0] == 46 or b[0] == 47 or b[b.len - 1] == 47 or b[b.len - 1] == 46) { return false; } + if (b.len >= 5 and span_is(b, b.len - 5, b.len, ".lock")) { return false; } + var i : usize = 1; + while (i < b.len) { + if (b[i - 1] == 47 and (b[i] == 47 or b[i] == 46)) { return false; } + i = i + 1; + } + return true; +} + +/// Why this request may not run, L_OK when it may. The first rule that fails decides. A plan may leave the issue out. +pub fn request_refusal(r: TriLandReq) -> u8 { + if (branch_ok(r.branch) == false) { return L_BAD_BRANCH; } + if (r.issue > ISSUE_MAX or (r.issue == 0 and r.plan == false)) { return L_BAD_ISSUE; } + if (safe_path(r.scratch) == false or safe_path(r.t27c) == false or safe_path(r.tri) == false) { return L_BAD_PATH; } + return L_OK; +} + +// --- reading the evidence ------------------------------------------------------------------------ + +/// The number of the first line of text[from..to] that is `label`, blanks and digits, then a blank or the end of the line; +/// ABSENT when no line is, or the number has more than 18 digits. A line `FAIL negz` (a failing test) is not that line. +pub fn count_line(text: string, from: usize, to: usize, label: string) -> u64 { + var at : usize = from; + while (at < to) { + var end : usize = line_end(text, at); + if (end > to) { end = to; } + var k : usize = at; + while (k < end and (text[k] == 32 or text[k] == 9)) { k = k + 1; } + if (k + label.len < end and span_is(text, k, k + label.len, label) and (text[k + label.len] == 32 or text[k + label.len] == 9)) { + var d : usize = k + label.len; + while (d < end and (text[d] == 32 or text[d] == 9)) { d = d + 1; } + const e : usize = digits_end(text, d, end); + if (e > d and (e == end or text[e] == 32 or text[e] == 9)) { + if (e - d > 18) { return ABSENT; } + return digits(text, d, e); + } + } + at = end + 1; + } + return ABSENT; +} + +/// Is the test report of entry n clean: the three totals are there, no test failed and no pass was vacuous? +pub fn tests_clean(ev: string, n: u64) -> bool { + const f : usize = body_from(ev, L_TESTS, n); + const t : usize = body_to(ev, L_TESTS, n); + if (count_line(ev, f, t, "tests") == ABSENT) { return false; } + return count_line(ev, f, t, "FAIL") == 0 and count_line(ev, f, t, "vacuous passes") == 0; +} + +/// Is the output of step k, entry n, a seal verification that matched: `all hashes MATCH` and no `VERIFICATION FAILED`? +pub fn seal_clean(ev: string, k: u8, n: u64) -> bool { + const f : usize = body_from(ev, k, n); + const t : usize = body_to(ev, k, n); + return has_line(ev, f, t, "all hashes MATCH") and has_line(ev, f, t, "VERIFICATION FAILED") == false; +} + +/// Is the types ratchet clean: exit 0 and a line `RATCHET: CLEAN`? +pub fn types_clean(ev: string) -> bool { + return exit_of(ev, L_TYPES, 0) == 0 and has_line(ev, body_from(ev, L_TYPES, 0), body_to(ev, L_TYPES, 0), "RATCHET: CLEAN"); +} + +/// The digits that start the output of step k, 0 when it does not start with a number. +pub fn lead_number(ev: string, k: u8) -> u64 { + const f : usize = body_from(ev, k, 0); + const e : usize = digits_end(ev, f, body_to(ev, k, 0)); + if (e == f or e - f > 18) { return 0; } + return digits(ev, f, e); +} + +/// Does the open PR line `<n> <true|false>` say auto-merge is on? +pub fn open_auto(ev: string) -> bool { + const f : usize = body_from(ev, L_OPEN, 0); + const t : usize = body_to(ev, L_OPEN, 0); + const e : usize = digits_end(ev, f, t); + return e > f and e + 5 <= t and span_is(ev, e, e + 5, " true"); +} + +/// The number after the last `/pull/` in the output of `gh pr create`, 0 when there is none. +pub fn created_number(ev: string) -> u64 { + const f : usize = body_from(ev, L_PR, 0); + const t : usize = body_to(ev, L_PR, 0); + var n : u64 = 0; + var at : usize = find_in(ev, f, t, "/pull/"); + while (at < ev.len) { + const e : usize = digits_end(ev, at + 6, t); + if (e > at + 6 and e - at - 6 <= 18) { n = digits(ev, at + 6, e); } + at = find_in(ev, at + 6, t, "/pull/"); + } + return n; +} + +/// The pull request the run works on: the open one, else the one it created; 0 when there is none. +pub fn pr_number(ev: string) -> u64 { + const o : u64 = lead_number(ev, L_OPEN); + if (o > 0) { return o; } + return created_number(ev); +} + +/// Does ev[from..to] start with a 40-digit object name that is followed by a blank, a tab, a newline or the end? +pub fn sha_at(ev: string, from: usize, to: usize) -> bool { + if (from + 40 > to) { return false; } + var i : usize = from; + while (i < from + 40) { + const c : u8 = ev[i]; + if (((c >= 48 and c <= 57) or (c >= 97 and c <= 102)) == false) { return false; } + i = i + 1; + } + return from + 40 == to or ev[from + 40] == 10 or ev[from + 40] == 9 or ev[from + 40] == 32; +} + +/// Did the push reach the remote: exit 0, and `git ls-remote` names the object `git rev-parse HEAD` named? +pub fn pushed(ev: string) -> bool { + const hf : usize = body_from(ev, L_HEAD, 0); + const rf : usize = body_from(ev, L_REMOTE_HEAD, 0); + if (exit_of(ev, L_PUSH, 0) != 0 or exit_of(ev, L_HEAD, 0) != 0 or exit_of(ev, L_REMOTE_HEAD, 0) != 0) { return false; } + if (sha_at(ev, hf, body_to(ev, L_HEAD, 0)) == false or sha_at(ev, rf, body_to(ev, L_REMOTE_HEAD, 0)) == false) { return false; } + return same(ev, hf, ev, rf, rf + 40); +} + +// --- the dupe rule: the branch's failing names must be master's -------------------------------------- + +/// Is text[at..end] a finding of dupe_scan: a line that starts with `::error::` and has a name? +pub fn is_finding(text: string, at: usize, end: usize) -> bool { + return end >= at + 10 and span_is(text, at, at + 9, "::error::"); +} + +/// Where the name of the finding at[..end] begins: after `::error::`, and after `a body written under ` when the line has it. +pub fn finding_from(text: string, at: usize, end: usize) -> usize { + if (end >= at + 31 and span_is(text, at + 9, at + 30, "a body written under ")) { return at + 30; } + return at + 9; +} + +/// Where that name ends: at the first blank, or the end of the line. +pub fn finding_to(text: string, from: usize, end: usize) -> usize { + var k : usize = from; + while (k < end and text[k] != 32) { k = k + 1; } + return k; +} + +/// How many findings text[from..to] holds. +pub fn findings(text: string, from: usize, to: usize) -> u64 { + var n : u64 = 0; + var at : usize = from; + while (at < to) { + var end : usize = line_end(text, at); + if (end > to) { end = to; } + if (is_finding(text, at, end)) { n = n + 1; } + at = end + 1; + } + return n; +} + +/// Does a finding of ev[f..t] carry the name ev[nf..nt]? +pub fn is_listed(ev: string, f: usize, t: usize, nf: usize, nt: usize) -> bool { + var at : usize = f; + while (at < t) { + var end : usize = line_end(ev, at); + if (end > t) { end = t; } + if (is_finding(ev, at, end)) { + const mf : usize = finding_from(ev, at, end); + const mt : usize = finding_to(ev, mf, end); + if (mt - mf == nt - nf and same(ev, nf, ev, mf, mt)) { return true; } + } + at = end + 1; + } + return false; +} + +/// The offset of the name of the first finding of the branch's scan that master's scan does not print; ev.len + 1 when every one +/// is printed there too (the failing set is a subset of master's). +pub fn extra_name(ev: string) -> usize { + const f : usize = body_from(ev, L_DUPES, 0); + const t : usize = body_to(ev, L_DUPES, 0); + var at : usize = f; + while (at < t) { + var end : usize = line_end(ev, at); + if (end > t) { end = t; } + if (is_finding(ev, at, end)) { + const nf : usize = finding_from(ev, at, end); + const nt : usize = finding_to(ev, nf, end); + if (is_listed(ev, body_from(ev, L_MASTER_DUPES, 0), body_to(ev, L_MASTER_DUPES, 0), nf, nt) == false) { return nf; } + } + at = end + 1; + } + return ev.len + 1; +} + +/// Is the branch's dupe scan a pass: exit 0, or exit 1 with findings that all appear in master's scan? +pub fn dupes_ok(ev: string) -> bool { + const x : u64 = exit_of(ev, L_DUPES, 0); + if (x == 0) { return true; } + if (x != 1 or exit_of(ev, L_MASTER_DUPES, 0) > 1) { return false; } + if (findings(ev, body_from(ev, L_DUPES, 0), body_to(ev, L_DUPES, 0)) == 0) { return false; } + return extra_name(ev) > ev.len; +} + +// --- the steps: which slot is next --------------------------------------------------------------- + +/// Does step k run once per line of CHANGES (a per-target step)? +pub fn per_target(k: u8) -> bool { + return k >= L_TESTS and k <= L_RECHECK; +} + +/// How many slots step k has: one per CHANGES line for a per-target step, else one. +pub fn slot_rows(r: TriLandReq, k: u8) -> u64 { + if (per_target(k)) { return entries(r.changes); } + return 1; +} + +/// Is slot (k, n) wanted, given the evidence so far? A slot not wanted is skipped, never run. +pub fn applies(r: TriLandReq, ev: string, k: u8, n: u64) -> bool { + if (k == L_TESTS or k == L_SEAL) { return is_target(r.changes, n); } + if (k == L_SAVE) { return is_target(r.changes, n) and exit_of(ev, L_SEAL, n) != NO_EXIT and seal_clean(ev, L_SEAL, n) == false; } + if (k == L_RECHECK) { return exit_of(ev, L_SAVE, n) != NO_EXIT; } + if (k >= L_STAGE and r.check) { return false; } + if (k == L_COMMIT) { return exit_of(ev, L_PENDING, 0) == 1; } + if (k == L_PR) { return lead_number(ev, L_OPEN) == 0; } + if (k == L_AUTO) { return open_auto(ev) == false; } + return true; +} + +/// The next slot to run: the first one in order that is wanted and has no section yet; DONE when there is none. It never names +/// L_CLEAN, which the glue runs by itself at the end. +pub fn next_slot(r: TriLandReq, ev: string) -> u64 { + var k : u8 = 0; + while (k < L_CLEAN) { + const rows : u64 = slot_rows(r, k); + var n : u64 = 0; + while (n < rows) { + if (applies(r, ev, k, n) and exit_of(ev, k, n) == NO_EXIT) { return (k as u64) * SLOT + n; } + n = n + 1; + } + k = k + 1; + } + return DONE; +} + +/// Does step k run in the scratch worktree? The steps before it, and the last, run where the caller stands. +pub fn in_scratch(k: u8) -> bool { + return k >= L_MASTER_DUPES and k < L_CLEAN; +} + +/// Does step k talk to GitHub: a fetch, a gh call, the push, ls-remote? +pub fn over_network(k: u8) -> bool { + return k == L_FETCH or k == L_MERGED or k == L_FETCH_BRANCH or k == L_OPEN or k == L_PUSH or k == L_REMOTE_HEAD or k == L_PR or k == L_AUTO or k == L_AUTO_CHECK; +} + +/// Did step k fail the way a flaky TLS or DNS answer fails, before anything was sent: exit not 0 and a network step that printed +/// `x509`, `TLS handshake timeout` or `Could not resolve host`? The glue runs it again, at most RETRIES more times, 3 seconds apart. +/// Any other failure, a rejected push included, is final. +pub fn transient(k: u8, x: u64, text: string) -> bool { + if (x == 0 or over_network(k) == false) { return false; } + return find_in(text, 0, text.len, "x509") < text.len or find_in(text, 0, text.len, "TLS handshake timeout") < text.len or find_in(text, 0, text.len, "Could not resolve host") < text.len; +} + +/// The step's name, as the command prints it. +pub fn step_name(k: u8) -> string { + if (k == L_FETCH) { return "fetch"; } + if (k == L_MERGED) { return "merged"; } + if (k == L_TIP) { return "tip"; } + if (k == L_FETCH_BRANCH) { return "fetch-branch"; } + if (k == L_CONTAINS) { return "contains"; } + if (k == L_OPEN) { return "open"; } + if (k == L_WORKTREE) { return "worktree"; } + if (k == L_MASTER_DUPES) { return "master-dupes"; } + if (k == L_CHECKOUT) { return "checkout"; } + if (k == L_MERGE) { return "merge"; } + if (k == L_CONFLICTS) { return "conflicts"; } + if (k == L_CHANGES) { return "changes"; } + if (k == L_TESTS) { return "tests"; } + if (k == L_SEAL) { return "seal"; } + if (k == L_SAVE) { return "seal-save"; } + if (k == L_RECHECK) { return "seal-recheck"; } + if (k == L_TYPES) { return "types"; } + if (k == L_DUPES) { return "dupes"; } + if (k == L_STAGE) { return "stage"; } + if (k == L_PENDING) { return "pending"; } + if (k == L_TITLE) { return "title"; } + if (k == L_COMMIT) { return "commit"; } + if (k == L_HEAD) { return "head"; } + if (k == L_PUSH) { return "push"; } + if (k == L_REMOTE_HEAD) { return "remote-head"; } + if (k == L_PR) { return "pr"; } + if (k == L_AUTO) { return "auto-merge"; } + if (k == L_AUTO_CHECK) { return "auto-merge-check"; } + if (k == L_CLEAN) { return "clean"; } + return "unknown"; +} + +// --- the judgement of a step --------------------------------------------------------------------- + +/// What the run that slot (k, n) just did means: L_OK to go on, L_ALREADY to stop well, any other code a refusal. The evidence +/// holds that run's section (and every earlier one); the glue has stored the CHANGES output in r.changes. +pub fn judge(r: TriLandReq, ev: string, k: u8, n: u64) -> u8 { + const x : u64 = exit_of(ev, k, n); + if (k == L_FETCH or k == L_WORKTREE or k == L_CHECKOUT or k == L_STAGE or k == L_COMMIT) { + if (x != 0) { return L_STEP; } + return L_OK; + } + if (k == L_MERGED) { + if (x != 0) { return L_STEP; } + if (lead_number(ev, L_MERGED) > 0) { return L_ALREADY; } + return L_OK; + } + if (k == L_TIP) { + if (x != 0 or sha_at(ev, body_from(ev, L_TIP, 0), body_to(ev, L_TIP, 0)) == false) { return L_NO_BRANCH; } + return L_OK; + } + if (k == L_OPEN) { + if (x != 0) { return L_STEP; } + if (lead_number(ev, L_OPEN) > 0 and open_auto(ev) and exit_of(ev, L_CONTAINS, 0) == 0) { return L_ALREADY; } + return L_OK; + } + if (k == L_MASTER_DUPES) { + if (x > 1) { return L_DUPE_NOT_SUBSET; } + return L_OK; + } + if (k == L_CONFLICTS) { + if (x != 0) { return L_STEP; } + if (body_from(ev, L_CONFLICTS, 0) < body_to(ev, L_CONFLICTS, 0)) { return L_CONFLICT; } + if (exit_of(ev, L_MERGE, 0) != 0) { return L_STEP; } + return L_OK; + } + if (k == L_CHANGES) { + if (x != 0 or entries(r.changes) == 0) { return L_STEP; } + var i : u64 = 0; + while (i < entries(r.changes)) { + if (is_spec(r.changes, i) and path_safe(r.changes, i) == false) { return L_STEP; } + i = i + 1; + } + return L_OK; + } + if (k == L_TESTS) { + if (tests_clean(ev, n)) { return L_OK; } + return L_TESTS_NOT_CLEAN; + } + if (k == L_RECHECK) { + if (seal_clean(ev, L_RECHECK, n)) { return L_OK; } + return L_SEAL_NOT_CLEAN; + } + if (k == L_TYPES) { + if (types_clean(ev)) { return L_OK; } + return L_TYPES_NOT_CLEAN; + } + if (k == L_DUPES) { + if (dupes_ok(ev)) { return L_OK; } + return L_DUPE_NOT_SUBSET; + } + if (k == L_PENDING) { + if (x > 1) { return L_STEP; } + return L_OK; + } + if (k == L_TITLE) { + if (x != 0 or body_from(ev, L_TITLE, 0) >= body_to(ev, L_TITLE, 0)) { return L_STEP; } + return L_OK; + } + if (k == L_HEAD) { + if (x != 0 or sha_at(ev, body_from(ev, L_HEAD, 0), body_to(ev, L_HEAD, 0)) == false) { return L_STEP; } + return L_OK; + } + if (k == L_PUSH) { + if (x != 0) { return L_PUSH_NOT_CONFIRMED; } + return L_OK; + } + if (k == L_REMOTE_HEAD) { + if (pushed(ev)) { return L_OK; } + return L_PUSH_NOT_CONFIRMED; + } + if (k == L_PR) { + if (x != 0 or created_number(ev) == 0) { return L_STEP; } + return L_OK; + } + if (k == L_AUTO) { + if (x != 0) { return L_AUTO_NOT_CONFIRMED; } + return L_OK; + } + if (k == L_AUTO_CHECK) { + if (x == 0 and has_line(ev, body_from(ev, L_AUTO_CHECK, 0), body_to(ev, L_AUTO_CHECK, 0), "true")) { return L_OK; } + return L_AUTO_NOT_CONFIRMED; + } + return L_OK; +} + +/// The code the command exits with: 0 for a run that ended well, the code itself for a refusal. +pub fn exit_code(c: u8) -> u8 { + if (c <= L_CHECKED) { return 0; } + return c; +} + +/// The code's name, as the command prints it. +pub fn code_name(c: u8) -> string { + if (c == L_OK) { return "OK"; } + if (c == L_ALREADY) { return "ALREADY_LANDED"; } + if (c == L_LANDED) { return "LANDED"; } + if (c == L_CHECKED) { return "CHECKED"; } + if (c == L_BAD_BRANCH) { return "BAD_BRANCH"; } + if (c == L_BAD_ISSUE) { return "BAD_ISSUE"; } + if (c == L_BAD_PATH) { return "BAD_PATH"; } + if (c == L_STEP) { return "STEP_FAILED"; } + if (c == L_NO_BRANCH) { return "NO_BRANCH"; } + if (c == L_CONFLICT) { return "CONFLICT"; } + if (c == L_TESTS_NOT_CLEAN) { return "TESTS_NOT_CLEAN"; } + if (c == L_SEAL_NOT_CLEAN) { return "SEAL_NOT_CLEAN"; } + if (c == L_TYPES_NOT_CLEAN) { return "TYPES_NOT_CLEAN"; } + if (c == L_DUPE_NOT_SUBSET) { return "DUPE_NOT_SUBSET"; } + if (c == L_PUSH_NOT_CONFIRMED) { return "PUSH_NOT_CONFIRMED"; } + if (c == L_AUTO_NOT_CONFIRMED) { return "AUTO_NOT_CONFIRMED"; } + return "UNKNOWN"; +} + +/// What the code means, in words. +pub fn code_why(c: u8) -> string { + if (c == L_OK) { return "nothing is refused"; } + if (c == L_ALREADY) { return "the branch is landed: nothing was changed"; } + if (c == L_LANDED) { return "master merged, gates passed, head pushed, pull request open with auto-merge on; git pull --ff-only brings the merge and seal commit into your checkout"; } + if (c == L_CHECKED) { return "master merged and every gate passed on the merged tree; nothing was committed, pushed or opened"; } + if (c == L_BAD_BRANCH) { return "the branch has a byte outside letters, digits and _-./, starts or ends with a slash, a dash or a dot, has .. or .lock, or is master, main or HEAD"; } + if (c == L_BAD_ISSUE) { return "--issue is a number from 1 to 999999999"; } + if (c == L_BAD_PATH) { return "the scratch directory, T27C or this program has a byte outside letters, digits and _-./, or starts with -"; } + if (c == L_STEP) { return "a step failed or printed nothing it should: nothing after it ran"; } + if (c == L_NO_BRANCH) { return "this repository has no local branch of that name: git branch <name> origin/<name> first"; } + if (c == L_CONFLICT) { return "the branch conflicts with master in the files named: resolve them on the branch, nothing was pushed"; } + if (c == L_TESTS_NOT_CLEAN) { return "a spec has a failing test, a vacuous pass, or no readable totals: it was not sealed"; } + if (c == L_SEAL_NOT_CLEAN) { return "a spec's seal does not match even after t27c seal --save"; } + if (c == L_TYPES_NOT_CLEAN) { return "tri types ratchet is not CLEAN"; } + if (c == L_DUPE_NOT_SUBSET) { return "dupe_scan fails on a name master does not fail on (or it could not be read): reuse the body that exists"; } + if (c == L_PUSH_NOT_CONFIRMED) { return "origin does not hold the head that was pushed (never forced: pull the branch first if it has moved)"; } + if (c == L_AUTO_NOT_CONFIRMED) { return "the pull request is open but auto-merge is not confirmed on"; } + return "unknown outcome"; +} + +// --- writing the commands ------------------------------------------------------------------------ + +/// Write the bytes of text[from..to]. +pub fn emit_span(out: []u8, w: usize, text: string, from: usize, to: usize) -> usize { + var p : usize = w; + var i : usize = from; + while (i < to and i < text.len) { + p = emit_byte(out, p, text[i]); + i = i + 1; + } + return p; +} + +/// Write the issue number, or `<issue>` for a plan that has none. +pub fn emit_issue(out: []u8, w: usize, issue: u64) -> usize { + if (issue == 0) { return emit_str(out, w, "<issue>"); } + return emit_dec(out, w, issue); +} + +/// Write the pull request number, or `<pr>` while there is none. +pub fn emit_pr(out: []u8, w: usize, ev: string) -> usize { + const n : u64 = pr_number(ev); + if (n == 0) { return emit_str(out, w, "<pr>"); } + return emit_dec(out, w, n); +} + +/// Write the spec path of CHANGES line n, or `<spec>` when it is not a target. +pub fn emit_spec(out: []u8, w: usize, r: TriLandReq, n: u64) -> usize { + if (is_target(r.changes, n) == false) { return emit_str(out, w, "<spec>"); } + return emit_span(out, w, r.changes, path_start(r.changes, n), path_end(r.changes, n)); +} + +/// Does ev[from..to] say `Closes #<n>`? +pub fn has_closes(ev: string, from: usize, to: usize, n: u64) -> bool { + var at : usize = find_in(ev, from, to, "Closes #"); + while (at < ev.len) { + const e : usize = digits_end(ev, at + 8, to); + if (e > at + 8 and e - at - 8 <= 18 and digits(ev, at + 8, e) == n) { return true; } + at = find_in(ev, at + 8, to, "Closes #"); + } + return false; +} + +/// Where the first line of the title step's output ends. +pub fn title_to(ev: string) -> usize { + const e : usize = line_end(ev, body_from(ev, L_TITLE, 0)); + if (e < body_to(ev, L_TITLE, 0)) { return e; } + return body_to(ev, L_TITLE, 0); +} + +/// The title of the commit and of the pull request: the lane's own last subject, and ` (Closes #N)` after it when it has no +/// `Closes #N`; `<title>` while the subject is not known. +pub fn emit_title(out: []u8, w: usize, ev: string, issue: u64) -> usize { + const f : usize = body_from(ev, L_TITLE, 0); + const t : usize = title_to(ev); + var p : usize = w; + if (f >= t) { p = emit_str(out, p, "<title>"); } else { p = emit_span(out, p, ev, f, t); } + if (has_closes(ev, f, t, issue)) { return p; } + p = emit_str(out, p, " (Closes #"); + p = emit_issue(out, p, issue); + return emit_byte(out, p, 41); +} + +pub const COMMIT_BODY : str = "Merge of master and the seals, by tri land (specs/tri/land/land.t27): the gates ran on the merged tree."; +pub const PR_BODY : str = ". Opened by tri land (specs/tri/land/land.t27): master merged, then on the merged tree every changed spec has its tests clean with vacuous passes 0 and its seal MATCH, tri types ratchet is CLEAN and the dupe_scan failure set is a subset of master's."; + +/// `gh pr list --repo R --head B --state <state> --json <json> --jq <jq>`, one argument to a line. +pub fn emit_list(out: []u8, w: usize, branch: string, state: string, json: string, jq: string) -> usize { + var p : usize = emit_str(out, w, "gh\npr\nlist\n--repo\n"); + p = emit_str(out, p, REPO); + p = emit_str(out, p, "\n--head\n"); + p = emit_str(out, p, branch); + p = emit_str(out, p, "\n--state\n"); + p = emit_str(out, p, state); + p = emit_str(out, p, "\n--json\n"); + p = emit_str(out, p, json); + p = emit_str(out, p, "\n--jq\n"); + p = emit_str(out, p, jq); + return emit_byte(out, p, 10); +} + +/// `<program> <verb> <spec> <flags...>`: the t27c lines of a per-target step. +pub fn emit_t27c(out: []u8, w: usize, r: TriLandReq, n: u64, tail: string) -> usize { + var p : usize = emit_str(out, w, r.t27c); + p = emit_byte(out, p, 10); + p = emit_str(out, p, tail); + return emit_spec(out, p, r, n); +} + +/// The argument vector of slot (k, n), one argument to a line, each ended by a newline; the byte count. 0 means there is nothing +/// to run: the request is refused, the step is not one, or the room is short. Evidence the step reads and does not have yet is +/// written as `<spec>`, `<title>`, `<pr>` or `<issue>`, so the same function prints the plan. +pub fn step_argv(r: TriLandReq, ev: string, k: u8, n: u64, out: []u8) -> usize { + if (request_refusal(r) != L_OK) { return 0; } + var w : usize = 0; + if (k == L_FETCH) { w = emit_str(out, w, "git\nfetch\n-q\norigin\nmaster\n"); } + if (k == L_MERGED) { w = emit_list(out, w, r.branch, "merged", "number", ".[] | .number"); } + if (k == L_TIP) { + w = emit_str(out, w, "git\nrev-parse\n--verify\n-q\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_FETCH_BRANCH) { + w = emit_str(out, w, "git\nfetch\n-q\norigin\n"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_CONTAINS) { + w = emit_str(out, w, "git\nmerge-base\n--is-ancestor\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_str(out, w, "\nrefs/remotes/origin/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_OPEN) { w = emit_list(out, w, r.branch, "open", "number,autoMergeRequest", ".[] | \"\\(.number) \\(.autoMergeRequest != null)\""); } + if (k == L_WORKTREE) { + w = emit_str(out, w, "git\nworktree\nadd\n-q\n--detach\n"); + w = emit_str(out, w, r.scratch); + w = emit_str(out, w, "\norigin/master\n"); + } + if (k == L_MASTER_DUPES or k == L_DUPES) { w = emit_str(out, w, "python3\ntools/dupe_scan.py\n"); } + if (k == L_CHECKOUT) { + w = emit_str(out, w, "git\ncheckout\n-q\n--detach\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_MERGE) { w = emit_str(out, w, "git\nmerge\n--no-commit\n--no-ff\norigin/master\n"); } + if (k == L_CONFLICTS) { w = emit_str(out, w, "git\ndiff\n--name-only\n--diff-filter=U\n"); } + if (k == L_CHANGES) { w = emit_str(out, w, "git\ndiff\n--cached\n--name-status\n--no-renames\norigin/master\n"); } + if (k == L_TESTS) { + w = emit_t27c(out, w, r, n, "test-report\n"); + w = emit_str(out, w, "\n--specs-dir\nspecs\n"); + } + if (k == L_SEAL or k == L_RECHECK) { + w = emit_t27c(out, w, r, n, "seal\n"); + w = emit_str(out, w, "\n--verify\n"); + } + if (k == L_SAVE) { + w = emit_t27c(out, w, r, n, "seal\n"); + w = emit_str(out, w, "\n--save\n"); + } + if (k == L_TYPES) { + w = emit_str(out, w, r.tri); + w = emit_str(out, w, "\ntypes\nratchet\n"); + } + if (k == L_STAGE) { w = emit_str(out, w, "git\nadd\n.trinity/seals\n"); } + if (k == L_PENDING) { w = emit_str(out, w, "git\ndiff\n--cached\n--quiet\n"); } + if (k == L_TITLE) { w = emit_str(out, w, "git\nlog\n-1\n--no-merges\n--format=%s\n"); } + if (k == L_COMMIT) { + w = emit_str(out, w, "git\n-c\ncore.hooksPath=.githooks\ncommit\n-q\n-m\n"); + w = emit_title(out, w, ev, r.issue); + w = emit_str(out, w, "\n-m\n"); + w = emit_str(out, w, COMMIT_BODY); + w = emit_byte(out, w, 10); + } + if (k == L_HEAD) { w = emit_str(out, w, "git\nrev-parse\nHEAD\n"); } + if (k == L_PUSH) { + w = emit_str(out, w, "git\npush\norigin\nHEAD:refs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_REMOTE_HEAD) { + w = emit_str(out, w, "git\nls-remote\norigin\nrefs/heads/"); + w = emit_str(out, w, r.branch); + w = emit_byte(out, w, 10); + } + if (k == L_PR) { + w = emit_str(out, w, "gh\npr\ncreate\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--base\nmaster\n--head\n"); + w = emit_str(out, w, r.branch); + w = emit_str(out, w, "\n--title="); + w = emit_title(out, w, ev, r.issue); + w = emit_str(out, w, "\n--body=Closes #"); + w = emit_issue(out, w, r.issue); + w = emit_str(out, w, PR_BODY); + w = emit_byte(out, w, 10); + } + if (k == L_AUTO) { + w = emit_str(out, w, "gh\npr\nmerge\n"); + w = emit_pr(out, w, ev); + w = emit_str(out, w, "\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--auto\n--squash\n"); + } + if (k == L_AUTO_CHECK) { + w = emit_str(out, w, "gh\npr\nview\n"); + w = emit_pr(out, w, ev); + w = emit_str(out, w, "\n--repo\n"); + w = emit_str(out, w, REPO); + w = emit_str(out, w, "\n--json\nautoMergeRequest\n--jq\n.autoMergeRequest != null\n"); + } + if (k == L_CLEAN) { + if (ev.len > 0 and exit_of(ev, L_WORKTREE, 0) != 0) { return 0; } + w = emit_str(out, w, "git\nworktree\nremove\n--force\n"); + w = emit_str(out, w, r.scratch); + w = emit_byte(out, w, 10); + } + return fits(out, w); +} + +/// One run as evidence: `@@ preflight <step> <entry> <exit> <length>\n`, the output, `\n`. The byte count. +pub fn emit_section(out: []u8, w: usize, k: u8, n: u64, x: u64, body: string) -> usize { + var p : usize = emit_str(out, w, "@@ preflight "); + p = emit_dec(out, p, k as u64); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, n); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, x); + p = emit_byte(out, p, 32); + p = emit_dec(out, p, body.len as u64); + p = emit_byte(out, p, 10); + p = emit_str(out, p, body); + return emit_byte(out, p, 10); +} + +/// What the command prints after a refusal's name: the files of a conflict, the spec of a gate that failed on one, the first +/// name dupe_scan fails on that master does not, else the step's name. The byte count. +pub fn refusal_detail(r: TriLandReq, ev: string, k: u8, n: u64, out: []u8) -> usize { + var w : usize = 0; + if (k == L_CONFLICTS) { + var i : usize = body_from(ev, L_CONFLICTS, 0); + const t : usize = body_to(ev, L_CONFLICTS, 0); + while (i < t) { + if (ev[i] == 10) { + if (i + 1 < t) { w = emit_byte(out, w, 32); } + } else { + w = emit_byte(out, w, ev[i]); + } + i = i + 1; + } + return fits(out, w); + } + if (k == L_TESTS or k == L_RECHECK) { + w = emit_span(out, w, r.changes, path_start(r.changes, n), path_end(r.changes, n)); + return fits(out, w); + } + const nf : usize = extra_name(ev); + if (k == L_DUPES and nf < ev.len) { + w = emit_span(out, w, ev, nf, finding_to(ev, nf, line_end(ev, nf))); + return fits(out, w); + } + w = emit_str(out, w, step_name(k)); + return fits(out, w); +} + +// --- the fixtures ------------------------------------------------------------------------------ +// Evidence sections as emit_section writes them, one run after another, and the text of the programs they hold. +pub const EV_MERGED_YES : str = "@@ preflight 1 0 0 6\n11055\n\n"; +pub const EV_MERGED_NONE : str = "@@ preflight 1 0 0 0\n\n"; +pub const EV_MERGED_FAIL : str = "@@ preflight 1 0 1 35\nerror connecting to api.github.com\n\n"; +pub const EV_TIP_OK : str = "@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n"; +pub const EV_TIP_NO : str = "@@ preflight 2 0 1 0\n\n"; +pub const EV_OPEN_LANDED : str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 9\n123 true\n\n"; +pub const EV_OPEN_NO_AUTO : str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 10\n123 false\n\n"; +pub const EV_OPEN_NOT_HELD : str = "@@ preflight 4 0 1 53\nfatal: Not a valid object name refs/remotes/origin/x\n\n@@ preflight 5 0 0 9\n123 true\n\n"; +pub const EV_OPEN_NONE : str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 0 0\n\n"; +pub const EV_OPEN_FAIL : str = "@@ preflight 4 0 0 0\n\n@@ preflight 5 0 1 18\ngh: not logged in\n\n"; +pub const EV_CONFLICT : str = "@@ preflight 9 0 1 141\nAuto-merging specs/x.t27\nCONFLICT (content): Merge conflict in specs/x.t27\nAutomatic merge failed; fix conflicts and then commit the result.\n\n@@ preflight 10 0 0 24\nspecs/x.t27\nspecs/y.t27\n\n"; +pub const EV_MERGE_FAILED : str = "@@ preflight 9 0 128 45\nfatal: refusing to merge unrelated histories\n\n@@ preflight 10 0 0 0\n\n"; +pub const EV_MERGE_CLEAN : str = "@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n"; +pub const EV_CHANGES_OK : str = "@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n"; +pub const EV_CHANGES_FAIL : str = "@@ preflight 11 0 128 0\n\n"; +pub const EV_TESTS_CLEAN : str = "@@ preflight 12 0 0 404\n--- test report: specs/tri/land/land.t27 ---\n\n tests 21\n pass 21\n FAIL 0\n invariants 3 proved -- comptime, so compiling IS the check\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 12 the_branch_and_the_numbers_pass_a_rule\n 3 a_request_is_refused\n vacuous passes 0 of 21 (passed with 0 runtime asserts executed)\n\n"; +pub const EV_TESTS_FAIL : str = "@@ preflight 12 0 0 419\n--- test report: specs/ternary/gft_relu.t27 ---\n FAIL negz\n\n tests 4\n pass 3\n FAIL 1\n invariants 2 proved -- comptime, so compiling IS the check\n rate 75.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 1 pos\n - negz (failed, not counted)\n 1 zero\n 1 pos2\n vacuous passes 0 of 3 (passed with 0 runtime asserts executed)\n\n"; +pub const EV_TESTS_VAC : str = "@@ preflight 12 0 0 281\n--- test report: specs/x/y.t27 ---\n\n tests 2\n pass 2\n FAIL 0\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 2 a\n 0 b VACUOUS\n vacuous passes 1 of 2 (passed with 0 runtime asserts executed)\n\n"; +pub const EV_TESTS_BLOCKED : str = "@@ preflight 12 0 0 251\n--- test report: specs/x/y.t27 ---\n BLOCKED does not compile: error: failed to create output directory '/x/zig/tmp/a5ed': PermissionDenied\n\n A blocked spec is not a failing one. It never produced a\n binary, so it has no per-test result to report.\n\n"; +pub const EV_TESTS_UNKNOWN : str = "@@ preflight 12 0 0 151\n--- test report: specs/x/y.t27 ---\n\n tests 2\n pass 2\n FAIL 0\n vacuous passes unknown (the counting build did not compile: x)\n\n"; +pub const EV_TESTS_OLD : str = "@@ preflight 12 0 0 101\n--- test report: specs/x/y.t27 ---\n\n tests 4\n pass 4\n FAIL 0\n rate 100.0%\n\n"; +pub const EV_TESTS_NONE : str = "@@ preflight 11 0 0 26\nA\tspecs/tri/land/land.t27\n\n"; +pub const EV_TESTS_NOTOTAL : str = "@@ preflight 12 0 0 83\n FAIL 0\n vacuous passes 0 of 0 (passed with 0 runtime asserts executed)\n\n"; +pub const EV_SEAL_MATCH : str = "@@ preflight 13 0 0 118\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\n\n"; +pub const EV_SEAL_BAD : str = "@@ preflight 13 0 1 162\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; +pub const EV_RECHECK_MATCH : str = "@@ preflight 15 0 0 118\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\n\n"; +pub const EV_RECHECK_BAD : str = "@@ preflight 15 0 1 162\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; +pub const EV_RECHECK_BOTH : str = "@@ preflight 15 0 0 280\nspec_hash: MATCH\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nall hashes MATCH\nspec_hash: MISMATCH (sealed sha256:aaaa, now sha256:bbbb)\ngen_hash_zig: MATCH\ngen_hash_verilog: MATCH\ngen_hash_c: MATCH\ngen_hash_rust: MATCH\n\nVERIFICATION FAILED\n\n"; +pub const EV_RECHECK_EMPTY : str = "@@ preflight 15 0 0 0\n\n"; +pub const EV_TYPES_OK : str = "@@ preflight 16 0 0 52\n ledger 107 name(s), observed 107\n RATCHET: CLEAN\n\n"; +pub const EV_TYPES_RED : str = "@@ preflight 16 0 1 264\n ledger 107 name(s), observed 108\n + Cell NEW conflict\n\n A RESOLVED name fails too, on purpose. An entry that stops being\n true and stays in the ledger is slack the next conflict hides in --\n the same rule the corpus ratchet applies to an unexpected PASS.\n\n"; +pub const EV_TYPES_EXIT : str = "@@ preflight 16 0 1 52\n ledger 107 name(s), observed 107\n RATCHET: CLEAN\n\n"; +pub const EV_TYPES_NOWORD : str = "@@ preflight 16 0 0 35\n ledger 107 name(s), observed 107\n\n"; +pub const EV_PENDING_YES : str = "@@ preflight 19 0 1 0\n\n"; +pub const EV_PENDING_NO : str = "@@ preflight 19 0 0 0\n\n"; +pub const EV_PENDING_FAIL : str = "@@ preflight 19 0 128 28\nfatal: not a git repository\n\n"; +pub const EV_TITLE : str = "@@ preflight 20 0 0 45\ntri land: land a lane branch (Closes #11068)\n\n"; +pub const EV_TITLE_BARE : str = "@@ preflight 20 0 0 29\ntri land: land a lane branch\n\n"; +pub const EV_TITLE_OTHER : str = "@@ preflight 20 0 0 45\ntri land: land a lane branch (Closes #11000)\n\n"; +pub const EV_TITLE_EMPTY : str = "@@ preflight 20 0 0 0\n\n"; +pub const EV_PUSH_OK : str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 72\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/tri-land-11068\n\n"; +pub const EV_PUSH_OTHER : str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 72\n89abcdef0123456789abcdef0123456789abcdef\trefs/heads/lane/tri-land-11068\n\n"; +pub const EV_PUSH_EMPTY : str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 0\n\n"; +pub const EV_PUSH_REJECT : str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 1 151\nTo github.com:gHashTag/t27.git\n ! [rejected] HEAD -> lane/x (non-fast-forward)\nerror: failed to push some refs to 'github.com:gHashTag/t27.git'\n\n"; +pub const EV_PUSH_LSFAIL : str = "@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 128 72\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/tri-land-11068\n\n"; +pub const EV_HEAD_BAD : str = "@@ preflight 22 0 0 10\nnot a sha\n\n"; +pub const EV_PR_CREATED : str = "@@ preflight 5 0 0 0\n\n@@ preflight 25 0 0 105\nCreating pull request for lane/x into master in gHashTag/t27\n\nhttps://github.com/gHashTag/t27/pull/11111\n\n"; +pub const EV_PR_OPEN : str = "@@ preflight 5 0 0 10\n123 false\n\n"; +pub const EV_PR_FAIL : str = "@@ preflight 25 0 1 33\nGraphQL: Head sha can't be blank\n\n"; +pub const EV_PR_NOURL : str = "@@ preflight 25 0 0 8\ncreated\n\n"; +pub const EV_AUTO_FAIL : str = "@@ preflight 26 0 1 41\nGraphQL: Pull request is in clean status\n\n"; +pub const EV_CHECK_TRUE : str = "@@ preflight 27 0 0 5\ntrue\n\n"; +pub const EV_CHECK_FALSE : str = "@@ preflight 27 0 0 6\nfalse\n\n"; +pub const EV_CHECK_FAIL : str = "@@ preflight 27 0 1 5\ntrue\n\n"; +pub const EV_WORKTREE_FAIL : str = "@@ preflight 6 0 128 27\nfatal: '/x' already exists\n\n"; +pub const EV_WORKTREE_OK : str = "@@ preflight 6 0 0 0\n\n"; +pub const EV_DUP_SAME : str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_FIXED : str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1458\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_SOME : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_NEW : str = "@@ preflight 7 0 1 1514\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 1601\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under hex_val is now copied [2] time(s) and was in no ledger\n::error::a body written under imports_anchor is now copied [2, 2] time(s) and was in no ledger\n::error::a body written under is_indented is now copied [2] time(s) and was in no ledger\n::error::a body written under is_word is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::a body written under match_in is now copied [3] time(s) and was in no ledger\n::error::a body written under nn_text is now copied [4] time(s) and was in no ledger\n::error::a body written under nullish is now copied [4] time(s) and was in no ledger\n::error::a body written under put_all is now copied [3] time(s) and was in no ledger\n::error::a body written under skip_digits is now copied [2] time(s) and was in no ledger\n::error::a body written under skip_ws is now copied [2] time(s) and was in no ledger\n::error::a body written under trim_span is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::ws_len_at was copied [2] and is now copied [3]\n::error::a body written under emit_span is now copied [2] time(s) and was in no ledger\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_NEWGROWN : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 557\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n::error::emit_dec was copied [2] and is now copied [3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_GROWN : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 418\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [10, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_CLEAN : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 0 93\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nok: no new duplicate body\n\n"; +pub const EV_DUP_UNREAD : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 2 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_NOFIND : str = "@@ preflight 7 0 1 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 89\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nsomething else failed\n\n"; +pub const EV_DUP_MASTER_BAD : str = "@@ preflight 7 0 2 502\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::a body written under jn_same is now copied [3] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_MASTER_CLEAN : str = "@@ preflight 7 0 0 93\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\nok: no new duplicate body\n\n@@ preflight 17 0 1 417\nduplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::bytes_eq was copied [8, 3] and is now copied [9, 3]\n\nA body written twice is a bug that has to be fixed twice. Reuse the\none that exists, or if this copy is deliberate, say so by moving the\nledger in the SAME commit:\n python3 tools/dupe_scan.py --bless\n\n"; +pub const EV_DUP_MASTER_FAIL : str = "@@ preflight 7 0 2 27\npython3: command not found\n\n"; +pub const EV_RUN_A : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n"; +pub const EV_RUN_B : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n"; +pub const EV_RUN_C : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n"; +pub const EV_RUN_D : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n"; +pub const EV_RUN_E : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n"; +pub const EV_RUN_F : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n"; +pub const EV_RUN_G : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; +pub const EV_RUN_G_OPEN : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 10\n123 false\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; +pub const EV_RUN_F_CLEAN : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 0 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n"; +pub const EV_RUN_E_NO_DUPES : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n"; +pub const EV_RUN_D_NO_SEAL : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n"; +pub const EV_RUN_G_NO_REMOTE : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 0\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n"; +pub const EV_RUN_G_AUTO_ON : str = "@@ preflight 0 0 0 0\n\n@@ preflight 1 0 0 0\n\n@@ preflight 2 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 3 0 128 39\nfatal: couldn't find remote ref lane/x\n\n@@ preflight 4 0 128 58\nfatal: Not a valid object name refs/remotes/origin/lane/x\n\n@@ preflight 5 0 0 9\n123 true\n\n@@ preflight 6 0 0 0\n\n@@ preflight 7 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 8 0 0 0\n\n@@ preflight 9 0 0 66\nAutomatic merge went well; stopped before committing as requested\n\n@@ preflight 10 0 0 0\n\n@@ preflight 11 0 0 65\nM\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n\n@@ preflight 12 0 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 12 2 0 115\n tests 4\n pass 4\n FAIL 0\n vacuous passes 0 of 4 (passed with 0 runtime asserts executed)\n\n@@ preflight 13 0 0 17\nall hashes MATCH\n\n@@ preflight 13 2 1 20\nVERIFICATION FAILED\n\n@@ preflight 14 2 0 6\nsaved\n\n@@ preflight 15 2 0 17\nall hashes MATCH\n\n@@ preflight 16 0 0 17\n RATCHET: CLEAN\n\n@@ preflight 17 0 1 85\n::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n\n@@ preflight 18 0 0 0\n\n@@ preflight 19 0 1 0\n\n@@ preflight 20 0 0 28\ntri land: x (Closes #11068)\n\n@@ preflight 21 0 0 0\n\n@@ preflight 22 0 0 41\n0123456789abcdef0123456789abcdef01234567\n\n@@ preflight 23 0 0 0\n\n@@ preflight 24 0 0 59\n0123456789abcdef0123456789abcdef01234567\trefs/heads/lane/x\n\n"; +pub const TXT_CH_ONE : str = "A\tspecs/tri/land/land.t27\n"; +pub const TXT_CH_TWO : str = "M\tspecs/tri/land/land.t27\nA\tdocs/x.md\nA\tspecs/tri/land/other.t27\n"; +pub const TXT_CH_BAD : str = "M\tspecs/tri/land/a b.t27\nA\tdocs/x.md\n"; +pub const TXT_CH_DOCS : str = "A\tdocs/x.md\nM\tcli/tri/src/main.rs\n"; +pub const TXT_TR_CLEAN : str = "--- test report: specs/tri/land/land.t27 ---\n\n tests 21\n pass 21\n FAIL 0\n invariants 3 proved -- comptime, so compiling IS the check\n rate 100.0%\n\n runtime asserts executed, per test (#6509; a pass with 0 is vacuous, T730):\n 12 the_branch_and_the_numbers_pass_a_rule\n 3 a_request_is_refused\n vacuous passes 0 of 21 (passed with 0 runtime asserts executed)\n"; +pub const P256 : str = "abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abc"; +pub const P257 : str = "abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcdefghij/abcd"; + +// --- the tests ----------------------------------------------------------------------------------- +// Fixtures are the programs' real text, shortened: `t27c test-report` and `t27c seal --verify` as they print for a spec on master +// (2026-10-19), `tri types ratchet` as cli/tri/src/types_dup.rs prints it, `python3 tools/dupe_scan.py` as it printed on master +// c33aec9c1 (15 findings), and the sections the glue writes. The git and gh outputs are the shapes those programs print. + +pub const T_BRANCH : str = "lane/tri-land-11068"; +pub const T_SCRATCH : str = "/tmp/tri-land-1"; +pub const T_TRI : str = "/opt/tri/tri"; +pub const B100 : str = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"; +pub const B101 : str = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghija"; + +/// The number on the first line of text that is `label` and a count. +pub fn cl(text: string, label: string) -> u64 { + return count_line(text, 0, text.len, label); +} + +/// A request for the tests, with CHANGES already stored. +pub fn req_of(changes: string, check: bool) -> TriLandReq { + return TriLandReq { branch: T_BRANCH, issue: 11068, scratch: T_SCRATCH, t27c: "t27c", tri: T_TRI, changes: changes, check: check, plan: false }; +} + +/// A request for the tests with the fields the rules are about. +pub fn req_on(branch: string, issue: u64, scratch: string, t27c: string, plan: bool) -> TriLandReq { + return TriLandReq { branch: branch, issue: issue, scratch: scratch, t27c: t27c, tri: T_TRI, changes: "", check: false, plan: plan }; +} + +pub fn slot_of(k: u8, n: u64) -> u64 { + return (k as u64) * SLOT + n; +} + +/// Does step k, entry n, of r write exactly `want`? +pub fn argv_is(r: TriLandReq, ev: string, k: u8, n: u64, want: string, buf: []u8) -> bool { + const m : usize = step_argv(r, ev, k, n, buf); + return m > 0 and buf_is(buf, m, want); +} + +/// Does the argument vector argv[0..n) hold `want` as one whole argument? +pub fn has_arg(argv: []const u8, n: usize, want: string) -> bool { + var s : usize = 0; + while (s < n) { + var e : usize = s; + while (e < n and argv[e] != 10) { e = e + 1; } + if (e - s == want.len) { + var k : usize = 0; + while (k < want.len and argv[s + k] == want[k]) { k = k + 1; } + if (k == want.len) { return true; } + } + s = e + 1; + } + return false; +} + +/// Does an argument of argv[0..n) start with `+`: a forced refspec? +pub fn has_plus(argv: []const u8, n: usize) -> bool { + var s : usize = 0; + while (s < n) { + if (argv[s] == 43) { return true; } + var e : usize = s; + while (e < n and argv[e] != 10) { e = e + 1; } + s = e + 1; + } + return false; +} + +/// Is the first argument of argv[0..n) a program the command may start: git, gh, python3, t27c or tri? +pub fn program_ok(argv: []const u8, n: usize, r: TriLandReq) -> bool { + var e : usize = 0; + while (e < n and argv[e] != 10) { e = e + 1; } + var k : u8 = 0; + while (k < 5) { + var want : string = "git"; + if (k == 1) { want = "gh"; } + if (k == 2) { want = "python3"; } + if (k == 3) { want = r.t27c; } + if (k == 4) { want = r.tri; } + if (e == want.len) { + var i : usize = 0; + while (i < e and argv[i] == want[i]) { i = i + 1; } + if (i == e) { return true; } + } + k = k + 1; + } + return false; +} + +/// How many steps of r, for entry 0 and this evidence, write any argument vector at all? +pub fn steps_sent(r: TriLandReq, ev: string, buf: []u8) -> u32 { + var c : u32 = 0; + var k : u8 = 0; + while (k < LAND_STEPS) { + if (step_argv(r, ev, k, 0, buf) > 0) { c = c + 1; } + k = k + 1; + } + return c; +} + +/// How many steps of r have `want` as a whole argument? +pub fn steps_with(r: TriLandReq, ev: string, want: string, buf: []u8) -> u32 { + var c : u32 = 0; + var k : u8 = 0; + while (k < LAND_STEPS) { + const n : usize = step_argv(r, ev, k, 0, buf); + if (has_arg(buf, n, want)) { c = c + 1; } + k = k + 1; + } + return c; +} + +/// How many steps of r push with a force flag or a plus refspec? +pub fn forced_pushes(r: TriLandReq, ev: string, buf: []u8) -> u32 { + var c : u32 = 0; + var k : u8 = 0; + while (k < LAND_STEPS) { + const n : usize = step_argv(r, ev, k, 0, buf); + if (has_arg(buf, n, "push") and (has_arg(buf, n, "--force") or has_arg(buf, n, "-f") or has_arg(buf, n, "--force-with-lease") or has_arg(buf, n, "--mirror") or has_arg(buf, n, "--delete") or has_plus(buf, n))) { c = c + 1; } + k = k + 1; + } + return c; +} + +/// How many steps of r start a program the command may not start? +pub fn strange_programs(r: TriLandReq, ev: string, buf: []u8) -> u32 { + var c : u32 = 0; + var k : u8 = 0; + while (k < LAND_STEPS) { + const n : usize = step_argv(r, ev, k, 0, buf); + if (n > 0 and program_ok(buf, n, r) == false) { c = c + 1; } + k = k + 1; + } + return c; +} + +// Scenario: the branch is a name that may be written into a command and is never master; the issue is a number. +test the_branch_and_the_issue_pass_a_rule { + assert branch_ok("lane/tri-land-11068") == true; + assert branch_ok("worktree-agent-a9333305bc5db3e6c") == true; + assert branch_ok("feature_x.1") == true; + assert branch_ok("a") == true; + assert branch_ok("master2") == true; + assert branch_ok(B100) == true; + assert branch_ok(B101) == false; + assert B100.len == BRANCH_MAX and B101.len == BRANCH_MAX + 1; + assert branch_ok("") == false; + assert branch_ok("master") == false; + assert branch_ok("main") == false; + assert branch_ok("HEAD") == false; + assert is_trunk("master") == true and is_trunk("lane/master") == false; + assert branch_ok("-x") == false; + assert branch_ok("-oProxyCommand=x") == false; + assert branch_ok("/lane/x") == false; + assert branch_ok("lane/x/") == false; + assert branch_ok("lane//x") == false; + assert branch_ok(".x") == false; + assert branch_ok("lane/.x") == false; + assert branch_ok("lane/x.") == false; + assert branch_ok("lane/x.lock") == false; + assert branch_ok("a..b") == false; + assert branch_ok("lane/../x") == false; + assert branch_ok("a b") == false; + assert branch_ok("a;b") == false; + assert branch_ok("a$(b)") == false; + assert branch_ok("a`b`") == false; + assert branch_ok("a'b") == false; + assert branch_ok("a\"b") == false; + assert branch_ok("a\nb") == false; + assert branch_ok("a|b") == false; + assert branch_ok("a&b") == false; + assert branch_ok("a>b") == false; + assert branch_ok("a*b") == false; + assert branch_ok("a?b") == false; + assert branch_ok("a:b") == false; + assert branch_ok("a~b") == false; + assert branch_ok("a^b") == false; + assert branch_ok("a@{b}") == false; + assert branch_ok("a\\b") == false; +} + +// Scenario: a request that fails a rule is refused with its code, and every step of it writes nothing. +test a_request_is_refused_before_any_step_runs { + var buf : [4096]u8 = [0] ** 4096; + assert request_refusal(req_of("", false)) == L_OK; + assert request_refusal(req_on("master", 11068, T_SCRATCH, "t27c", false)) == L_BAD_BRANCH; + assert request_refusal(req_on("lane/a b", 11068, T_SCRATCH, "t27c", false)) == L_BAD_BRANCH; + assert request_refusal(req_on(T_BRANCH, 0, T_SCRATCH, "t27c", false)) == L_BAD_ISSUE; + assert request_refusal(req_on(T_BRANCH, 1000000000, T_SCRATCH, "t27c", false)) == L_BAD_ISSUE; + assert request_refusal(req_on(T_BRANCH, 999999999, T_SCRATCH, "t27c", false)) == L_OK; + assert request_refusal(req_on(T_BRANCH, 1, T_SCRATCH, "t27c", false)) == L_OK; + assert request_refusal(req_on(T_BRANCH, 0, T_SCRATCH, "t27c", true)) == L_OK; + assert request_refusal(req_on(T_BRANCH, 11068, "/tmp/a b", "t27c", false)) == L_BAD_PATH; + assert request_refusal(req_on(T_BRANCH, 11068, "", "t27c", false)) == L_BAD_PATH; + assert request_refusal(req_on(T_BRANCH, 11068, T_SCRATCH, "-x", false)) == L_BAD_PATH; + assert request_refusal(req_on(T_BRANCH, 11068, T_SCRATCH, "t27c;rm", false)) == L_BAD_PATH; + assert request_refusal(req_on(T_BRANCH, 11068, T_SCRATCH, P256, false)) == L_OK; + assert steps_sent(req_of("", false), "", &buf) == (LAND_STEPS as u32); + assert steps_sent(req_on("master", 11068, T_SCRATCH, "t27c", false), "", &buf) == 0; + assert steps_sent(req_on("a;b", 11068, T_SCRATCH, "t27c", false), "", &buf) == 0; + assert steps_sent(req_on(T_BRANCH, 0, T_SCRATCH, "t27c", false), "", &buf) == 0; + assert steps_sent(req_on(T_BRANCH, 11068, "/tmp/a b", "t27c", false), "", &buf) == 0; + assert steps_sent(req_on(T_BRANCH, 0, T_SCRATCH, "t27c", true), "", &buf) == (LAND_STEPS as u32); +} + +// Scenario: a spec with a failing test, a vacuous pass or no readable totals is TESTS_NOT_CLEAN, and is not sealed. +test the_test_report_totals_are_read_from_their_lines { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert tests_clean(EV_TESTS_CLEAN, 0) == true; + assert tests_clean(EV_TESTS_FAIL, 0) == false; + assert tests_clean(EV_TESTS_VAC, 0) == false; + assert tests_clean(EV_TESTS_BLOCKED, 0) == false; + assert tests_clean(EV_TESTS_UNKNOWN, 0) == false; + assert tests_clean(EV_TESTS_OLD, 0) == false; + assert tests_clean(EV_TESTS_NONE, 0) == false; + assert tests_clean(EV_TESTS_NOTOTAL, 0) == false; + assert tests_clean("", 0) == false; + assert judge(r, EV_TESTS_CLEAN, L_TESTS, 0) == L_OK; + assert judge(r, EV_TESTS_FAIL, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_TESTS_VAC, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_TESTS_BLOCKED, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_TESTS_UNKNOWN, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_TESTS_OLD, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_TESTS_NOTOTAL, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + const t : string = TXT_TR_CLEAN; + assert cl(t, "tests") == 21; + assert cl(t, "pass") == 21; + assert cl(t, "FAIL") == 0; + assert cl(t, "vacuous passes") == 0; + assert cl(t, "invariants") == 3; + assert cl(t, "rate") == ABSENT; + // a failing test's own line is not the total + assert cl(" FAIL negz\n\n tests 4\n FAIL 1\n", "FAIL") == 1; + assert cl(" FAIL negz\n\n tests 4\n FAIL 1\n", "tests") == 4; + assert cl(" FAIL negz\n", "FAIL") == ABSENT; + // the shapes that are not a total + assert cl(" tests 5x\n", "tests") == ABSENT; + assert cl(" tests\n", "tests") == ABSENT; + assert cl(" testsuite 3\n", "tests") == ABSENT; + assert cl(" vacuous passes unknown (x)\n", "vacuous passes") == ABSENT; + assert cl("\ttests\t7\n", "tests") == 7; + assert cl("tests 999999999999999999\n", "tests") == 999999999999999999; + assert cl("tests 1000000000000000000\n", "tests") == ABSENT; + assert cl("", "tests") == ABSENT; + // only the lines of the span count + assert count_line("tests 4\nFAIL 0\n", 0, 8, "FAIL") == ABSENT; +} + +// Scenario: a seal is clean when the check says all hashes match, and not when it says verification failed. +test the_seal_text_is_read { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert seal_clean(EV_SEAL_MATCH, L_SEAL, 0) == true; + assert seal_clean(EV_SEAL_BAD, L_SEAL, 0) == false; + assert seal_clean(EV_RECHECK_MATCH, L_RECHECK, 0) == true; + assert seal_clean(EV_RECHECK_BAD, L_RECHECK, 0) == false; + assert seal_clean(EV_RECHECK_BOTH, L_RECHECK, 0) == false; + assert seal_clean(EV_RECHECK_EMPTY, L_RECHECK, 0) == false; + assert seal_clean(EV_RECHECK_MATCH, L_RECHECK, 2) == false; + assert seal_clean("", L_RECHECK, 0) == false; + assert judge(r, EV_RECHECK_MATCH, L_RECHECK, 0) == L_OK; + assert judge(r, EV_RECHECK_BAD, L_RECHECK, 0) == L_SEAL_NOT_CLEAN; + assert judge(r, EV_RECHECK_BOTH, L_RECHECK, 0) == L_SEAL_NOT_CLEAN; + assert judge(r, EV_RECHECK_EMPTY, L_RECHECK, 0) == L_SEAL_NOT_CLEAN; + // the first verify never decides: a seal that did not match is saved and checked again + assert judge(r, EV_SEAL_BAD, L_SEAL, 0) == L_OK; + assert judge(r, EV_SEAL_MATCH, L_SEAL, 0) == L_OK; + assert applies(r, EV_SEAL_BAD, L_SAVE, 0) == true; + assert applies(r, EV_SEAL_MATCH, L_SAVE, 0) == false; + assert applies(r, "", L_SAVE, 0) == false; +} + +// Scenario: the types ratchet is clean only with exit 0 and its own CLEAN line. +test the_ratchet_text_is_read { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert types_clean(EV_TYPES_OK) == true; + assert types_clean(EV_TYPES_RED) == false; + assert types_clean(EV_TYPES_EXIT) == false; + assert types_clean(EV_TYPES_NOWORD) == false; + assert types_clean("") == false; + assert judge(r, EV_TYPES_OK, L_TYPES, 0) == L_OK; + assert judge(r, EV_TYPES_RED, L_TYPES, 0) == L_TYPES_NOT_CLEAN; + assert judge(r, EV_TYPES_EXIT, L_TYPES, 0) == L_TYPES_NOT_CLEAN; + assert judge(r, EV_TYPES_NOWORD, L_TYPES, 0) == L_TYPES_NOT_CLEAN; +} + +// Scenario: dupe_scan's two finding shapes each name one body. +test a_finding_names_the_body_it_is_about { + const a : string = "::error::a body written under dec_len is now copied [2] time(s) and was in no ledger"; + const b : string = "::error::bytes_eq was copied [8, 3] and is now copied [9, 3]"; + assert is_finding(a, 0, a.len) == true and is_finding(b, 0, b.len) == true; + assert finding_from(a, 0, a.len) == 30 and finding_to(a, 30, a.len) == 37; + assert finding_from(b, 0, b.len) == 9 and finding_to(b, 9, b.len) == 17; + assert span_is(a, 30, 37, "dec_len") and span_is(b, 9, 17, "bytes_eq"); + assert is_finding("duplicate bodies: 738 of 15523 in 218 group(s) across 2440 spec(s)", 0, 67) == false; + assert is_finding("::error::", 0, 9) == false; + assert is_finding("::error::x", 0, 10) == true; + assert is_finding(" ::error::x", 0, 12) == false; + assert findings(EV_DUP_SAME, body_from(EV_DUP_SAME, L_MASTER_DUPES, 0), body_to(EV_DUP_SAME, L_MASTER_DUPES, 0)) == 15; + assert findings(EV_DUP_FIXED, body_from(EV_DUP_FIXED, L_DUPES, 0), body_to(EV_DUP_FIXED, L_DUPES, 0)) == 14; + assert findings(EV_DUP_CLEAN, body_from(EV_DUP_CLEAN, L_DUPES, 0), body_to(EV_DUP_CLEAN, L_DUPES, 0)) == 0; + // a name is a whole name: dec_len is listed, dec is not, and neither is a name that merely starts with a listed one + const m : string = "::error::a body written under dec_len is now copied [2] time(s) and was in no ledger\n::error::dec was copied [1] and is now copied [2]\n::error::dec_len_2 was copied [1] and is now copied [2]\n"; + const e1 : usize = line_end(m, 0); + const e2 : usize = line_end(m, e1 + 1); + assert is_listed(m, 0, e1, 30, 37) == true; + assert is_listed(m, 0, e1, e1 + 10, e1 + 13) == false; + assert is_listed(m, 0, e1, e2 + 10, e2 + 19) == false; + assert extra_name(EV_DUP_SAME) > EV_DUP_SAME.len; +} + +// Scenario: the failing set of the branch must be a subset of master's: it may be smaller, it may not hold a new name. +test the_failing_set_must_be_a_subset_of_masters { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + // the 15 names master fails on, as the branch fails on them too, or on fewer + assert dupes_ok(EV_DUP_SAME) == true; + assert dupes_ok(EV_DUP_FIXED) == true; + assert dupes_ok(EV_DUP_SOME) == true; + assert dupes_ok(EV_DUP_CLEAN) == true; + assert judge(r, EV_DUP_SAME, L_DUPES, 0) == L_OK; + assert judge(r, EV_DUP_FIXED, L_DUPES, 0) == L_OK; + assert judge(r, EV_DUP_SOME, L_DUPES, 0) == L_OK; + assert judge(r, EV_DUP_CLEAN, L_DUPES, 0) == L_OK; + // a new name, in either finding shape, on top of master's 15 + assert dupes_ok(EV_DUP_NEW) == false; + assert dupes_ok(EV_DUP_NEWGROWN) == false; + assert judge(r, EV_DUP_NEW, L_DUPES, 0) == L_DUPE_NOT_SUBSET; + assert judge(r, EV_DUP_NEWGROWN, L_DUPES, 0) == L_DUPE_NOT_SUBSET; + assert extra_name(EV_DUP_NEW) < EV_DUP_NEW.len and extra_name(EV_DUP_NEWGROWN) < EV_DUP_NEWGROWN.len; + // what cannot be read is refused: a branch exit that is neither 0 nor 1, no finding on exit 1, a master scan that failed + assert dupes_ok(EV_DUP_UNREAD) == false; + assert dupes_ok(EV_DUP_NOFIND) == false; + assert dupes_ok(EV_DUP_MASTER_BAD) == false; + assert dupes_ok(EV_DUP_MASTER_FAIL) == false; + assert judge(r, EV_DUP_UNREAD, L_DUPES, 0) == L_DUPE_NOT_SUBSET; + assert judge(r, EV_DUP_NOFIND, L_DUPES, 0) == L_DUPE_NOT_SUBSET; + assert judge(r, EV_DUP_MASTER_BAD, L_MASTER_DUPES, 0) == L_DUPE_NOT_SUBSET; + assert judge(r, EV_DUP_SAME, L_MASTER_DUPES, 0) == L_OK; + assert judge(r, EV_DUP_MASTER_CLEAN, L_MASTER_DUPES, 0) == L_OK; + // master clean: every finding of the branch is new + assert dupes_ok(EV_DUP_MASTER_CLEAN) == false; + // the limit, written down: a group that grows under a name master already fails on is a name master has + assert dupes_ok(EV_DUP_GROWN) == true; +} + +// Scenario: the first new name is what the command prints after DUPE_NOT_SUBSET. +test the_new_name_is_named { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert buf_is(&buf, refusal_detail(r, EV_DUP_NEW, L_DUPES, 0, &buf), "emit_span"); + assert buf_is(&buf, refusal_detail(r, EV_DUP_NEWGROWN, L_DUPES, 0, &buf), "emit_dec"); + assert buf_is(&buf, refusal_detail(r, EV_DUP_UNREAD, L_DUPES, 0, &buf), "dupes"); + assert buf_is(&buf, refusal_detail(r, EV_TESTS_FAIL, L_TESTS, 0, &buf), "specs/tri/land/land.t27"); + assert buf_is(&buf, refusal_detail(r, EV_RECHECK_BAD, L_RECHECK, 2, &buf), "specs/tri/land/other.t27"); + assert buf_is(&buf, refusal_detail(r, EV_TYPES_RED, L_TYPES, 0, &buf), "types"); + assert buf_is(&buf, refusal_detail(r, EV_PUSH_REJECT, L_PUSH, 0, &buf), "push"); +} + +// Scenario: a merged pull request, or an open one with auto-merge on that the remote already holds in full, is ALREADY_LANDED. +test an_already_landed_branch_is_left_alone { + const r : TriLandReq = req_of("", false); + assert judge(r, EV_MERGED_YES, L_MERGED, 0) == L_ALREADY; + assert judge(r, EV_MERGED_NONE, L_MERGED, 0) == L_OK; + assert judge(r, EV_MERGED_FAIL, L_MERGED, 0) == L_STEP; + assert judge(r, EV_OPEN_LANDED, L_OPEN, 0) == L_ALREADY; + assert judge(r, EV_OPEN_NO_AUTO, L_OPEN, 0) == L_OK; + assert judge(r, EV_OPEN_NOT_HELD, L_OPEN, 0) == L_OK; + assert judge(r, EV_OPEN_NONE, L_OPEN, 0) == L_OK; + assert judge(r, EV_OPEN_FAIL, L_OPEN, 0) == L_STEP; + assert judge(r, EV_TIP_OK, L_TIP, 0) == L_OK; + assert judge(r, EV_TIP_NO, L_TIP, 0) == L_NO_BRANCH; + assert judge(r, EV_HEAD_BAD, L_TIP, 0) == L_NO_BRANCH; + // the remote's exit is data: the branch may not be there yet + assert judge(r, EV_OPEN_NOT_HELD, L_CONTAINS, 0) == L_OK; + assert exit_code(L_ALREADY) == 0 and exit_code(L_LANDED) == 0 and exit_code(L_CHECKED) == 0; + const nm : string = code_name(L_ALREADY); + assert nm.len == 14 and span_is(nm, 0, 14, "ALREADY_LANDED"); +} + +// Scenario: a conflict with master prints CONFLICT and the files, and pushes nothing. +test a_conflict_names_its_files_and_stops { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of("", false); + assert judge(r, EV_CONFLICT, L_CONFLICTS, 0) == L_CONFLICT; + assert buf_is(&buf, refusal_detail(r, EV_CONFLICT, L_CONFLICTS, 0, &buf), "specs/x.t27 specs/y.t27"); + assert judge(r, EV_MERGE_FAILED, L_CONFLICTS, 0) == L_STEP; + assert judge(r, EV_MERGE_CLEAN, L_CONFLICTS, 0) == L_OK; + assert exit_code(L_CONFLICT) == L_CONFLICT and exit_code(L_CONFLICT) != 0; + assert judge(r, EV_WORKTREE_FAIL, L_WORKTREE, 0) == L_STEP; + assert judge(r, EV_WORKTREE_OK, L_WORKTREE, 0) == L_OK; + assert judge(r, EV_MERGE_CLEAN, L_MERGE, 0) == L_OK; +} + +// Scenario: the changed specs are the gate's targets; a spec path a shell would read is refused, not skipped. +test the_changes_are_the_specs_to_gate { + assert judge(req_of(TXT_CH_TWO, false), EV_CHANGES_OK, L_CHANGES, 0) == L_OK; + assert judge(req_of(TXT_CH_ONE, false), EV_CHANGES_OK, L_CHANGES, 0) == L_OK; + assert judge(req_of(TXT_CH_DOCS, false), EV_CHANGES_OK, L_CHANGES, 0) == L_OK; + assert judge(req_of(TXT_CH_TWO, false), EV_CHANGES_FAIL, L_CHANGES, 0) == L_STEP; + assert judge(req_of("", false), EV_CHANGES_OK, L_CHANGES, 0) == L_STEP; + assert judge(req_of(TXT_CH_BAD, false), EV_CHANGES_OK, L_CHANGES, 0) == L_STEP; + assert is_target(TXT_CH_TWO, 0) == true and is_target(TXT_CH_TWO, 1) == false and is_target(TXT_CH_TWO, 2) == true; + assert is_target(TXT_CH_DOCS, 0) == false and is_target(TXT_CH_DOCS, 1) == false; + assert is_target(TXT_CH_BAD, 0) == false and is_spec(TXT_CH_BAD, 0) == true; + assert slot_rows(req_of(TXT_CH_TWO, false), L_TESTS) == 3 and slot_rows(req_of(TXT_CH_TWO, false), L_TYPES) == 1; + assert per_target(L_TESTS) and per_target(L_SEAL) and per_target(L_SAVE) and per_target(L_RECHECK); + assert per_target(L_CHANGES) == false and per_target(L_TYPES) == false; +} + +// Scenario: the steps before the merge, each as the argument vector it runs. +test the_steps_before_the_merge_pin_their_bytes { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of("", false); + assert argv_is(r, "", L_FETCH, 0, "git\nfetch\n-q\norigin\nmaster\n", &buf); + assert argv_is(r, "", L_MERGED, 0, "gh\npr\nlist\n--repo\ngHashTag/t27\n--head\nlane/tri-land-11068\n--state\nmerged\n--json\nnumber\n--jq\n.[] | .number\n", &buf); + assert argv_is(r, "", L_TIP, 0, "git\nrev-parse\n--verify\n-q\nrefs/heads/lane/tri-land-11068\n", &buf); + assert argv_is(r, "", L_FETCH_BRANCH, 0, "git\nfetch\n-q\norigin\nlane/tri-land-11068\n", &buf); + assert argv_is(r, "", L_CONTAINS, 0, "git\nmerge-base\n--is-ancestor\nrefs/heads/lane/tri-land-11068\nrefs/remotes/origin/lane/tri-land-11068\n", &buf); + assert argv_is(r, "", L_OPEN, 0, "gh\npr\nlist\n--repo\ngHashTag/t27\n--head\nlane/tri-land-11068\n--state\nopen\n--json\nnumber,autoMergeRequest\n--jq\n.[] | \"\\(.number) \\(.autoMergeRequest != null)\"\n", &buf); + assert argv_is(r, "", L_WORKTREE, 0, "git\nworktree\nadd\n-q\n--detach\n/tmp/tri-land-1\norigin/master\n", &buf); + assert argv_is(r, "", L_MASTER_DUPES, 0, "python3\ntools/dupe_scan.py\n", &buf); + assert argv_is(r, "", L_CHECKOUT, 0, "git\ncheckout\n-q\n--detach\nrefs/heads/lane/tri-land-11068\n", &buf); + assert argv_is(r, "", L_MERGE, 0, "git\nmerge\n--no-commit\n--no-ff\norigin/master\n", &buf); + assert argv_is(r, "", L_CONFLICTS, 0, "git\ndiff\n--name-only\n--diff-filter=U\n", &buf); + assert argv_is(r, "", L_CHANGES, 0, "git\ndiff\n--cached\n--name-status\n--no-renames\norigin/master\n", &buf); + // another branch and another scratch directory change exactly those words + assert argv_is(req_on("lane/x", 7, "/tmp/z", "t27c", false), "", L_TIP, 0, "git\nrev-parse\n--verify\n-q\nrefs/heads/lane/x\n", &buf); + assert argv_is(req_on("lane/x", 7, "/tmp/z", "t27c", false), "", L_WORKTREE, 0, "git\nworktree\nadd\n-q\n--detach\n/tmp/z\norigin/master\n", &buf); + // the steps that run before the scratch tree exists, and the last, run where the caller stands + assert in_scratch(L_OPEN) == false and in_scratch(L_WORKTREE) == false and in_scratch(L_MASTER_DUPES) == true; + assert in_scratch(L_AUTO_CHECK) == true and in_scratch(L_CLEAN) == false; +} + +// Scenario: the gates, per spec and once, each as the argument vector it runs. +test the_gates_pin_their_bytes { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert argv_is(r, "", L_TESTS, 0, "t27c\ntest-report\nspecs/tri/land/land.t27\n--specs-dir\nspecs\n", &buf); + assert argv_is(r, "", L_TESTS, 2, "t27c\ntest-report\nspecs/tri/land/other.t27\n--specs-dir\nspecs\n", &buf); + assert argv_is(r, "", L_TESTS, 1, "t27c\ntest-report\n<spec>\n--specs-dir\nspecs\n", &buf); + assert argv_is(r, "", L_SEAL, 0, "t27c\nseal\nspecs/tri/land/land.t27\n--verify\n", &buf); + assert argv_is(r, "", L_SAVE, 2, "t27c\nseal\nspecs/tri/land/other.t27\n--save\n", &buf); + assert argv_is(r, "", L_RECHECK, 2, "t27c\nseal\nspecs/tri/land/other.t27\n--verify\n", &buf); + assert argv_is(r, "", L_TYPES, 0, "/opt/tri/tri\ntypes\nratchet\n", &buf); + assert argv_is(r, "", L_DUPES, 0, "python3\ntools/dupe_scan.py\n", &buf); + assert argv_is(req_on(T_BRANCH, 11068, T_SCRATCH, "/opt/t27c/t27c", false), "", L_TESTS, 0, "/opt/t27c/t27c\ntest-report\n<spec>\n--specs-dir\nspecs\n", &buf); + assert argv_is(req_of(TXT_CH_ONE, false), "", L_SEAL, 0, "t27c\nseal\nspecs/tri/land/land.t27\n--verify\n", &buf); +} + +// Scenario: the steps that land the branch, each as the argument vector it runs. +test the_landing_steps_pin_their_bytes { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert argv_is(r, "", L_STAGE, 0, "git\nadd\n.trinity/seals\n", &buf); + assert argv_is(r, "", L_PENDING, 0, "git\ndiff\n--cached\n--quiet\n", &buf); + assert argv_is(r, "", L_TITLE, 0, "git\nlog\n-1\n--no-merges\n--format=%s\n", &buf); + assert argv_is(r, EV_TITLE, L_COMMIT, 0, "git\n-c\ncore.hooksPath=.githooks\ncommit\n-q\n-m\ntri land: land a lane branch (Closes #11068)\n-m\nMerge of master and the seals, by tri land (specs/tri/land/land.t27): the gates ran on the merged tree.\n", &buf); + assert argv_is(r, EV_TITLE_BARE, L_COMMIT, 0, "git\n-c\ncore.hooksPath=.githooks\ncommit\n-q\n-m\ntri land: land a lane branch (Closes #11068)\n-m\nMerge of master and the seals, by tri land (specs/tri/land/land.t27): the gates ran on the merged tree.\n", &buf); + assert argv_is(r, "", L_HEAD, 0, "git\nrev-parse\nHEAD\n", &buf); + assert argv_is(r, "", L_PUSH, 0, "git\npush\norigin\nHEAD:refs/heads/lane/tri-land-11068\n", &buf); + assert argv_is(r, "", L_REMOTE_HEAD, 0, "git\nls-remote\norigin\nrefs/heads/lane/tri-land-11068\n", &buf); + var n : usize = step_argv(r, EV_TITLE, L_PR, 0, &buf); + assert buf_has(&buf, n, "gh\npr\ncreate\n--repo\ngHashTag/t27\n--base\nmaster\n--head\nlane/tri-land-11068\n--title=tri land: land a lane branch (Closes #11068)\n--body=Closes #11068. Opened by tri land (specs/tri/land/land.t27): master merged,"); + assert buf_has(&buf, n, PR_BODY); + assert buf[n - 1] == 10; + assert argv_is(r, EV_PR_CREATED, L_AUTO, 0, "gh\npr\nmerge\n11111\n--repo\ngHashTag/t27\n--auto\n--squash\n", &buf); + assert argv_is(r, EV_PR_OPEN, L_AUTO, 0, "gh\npr\nmerge\n123\n--repo\ngHashTag/t27\n--auto\n--squash\n", &buf); + assert argv_is(r, "", L_AUTO, 0, "gh\npr\nmerge\n<pr>\n--repo\ngHashTag/t27\n--auto\n--squash\n", &buf); + assert argv_is(r, EV_PR_CREATED, L_AUTO_CHECK, 0, "gh\npr\nview\n11111\n--repo\ngHashTag/t27\n--json\nautoMergeRequest\n--jq\n.autoMergeRequest != null\n", &buf); + assert argv_is(r, "", L_CLEAN, 0, "git\nworktree\nremove\n--force\n/tmp/tri-land-1\n", &buf); + // without an issue (a plan) the words are placeholders + const p : TriLandReq = req_on(T_BRANCH, 0, T_SCRATCH, "t27c", true); + n = step_argv(p, "", L_COMMIT, 0, &buf); + assert buf_has(&buf, n, "-m\n<title> (Closes #<issue>)\n-m\n"); + assert step_argv(r, "", LAND_STEPS, 0, &buf) == 0; +} + +// Scenario: nothing the command starts forces a push, writes master or runs a program other than git, gh, python3, t27c and tri. +test no_step_forces_a_push_or_writes_master { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert forced_pushes(r, "", &buf) == 0; + assert forced_pushes(r, EV_RUN_G, &buf) == 0; + assert steps_with(r, "", "push", &buf) == 1; + assert steps_with(r, "", "HEAD:refs/heads/lane/tri-land-11068", &buf) == 1; + assert steps_with(r, "", "HEAD:refs/heads/master", &buf) == 0; + assert steps_with(r, "", "refs/heads/master", &buf) == 0; + assert steps_with(r, "", "--force", &buf) == 1; + assert steps_with(r, "", "-f", &buf) == 0; + assert steps_with(r, "", "--force-with-lease", &buf) == 0; + assert steps_with(r, "", "--no-verify", &buf) == 0; + assert strange_programs(r, "", &buf) == 0; + assert strange_programs(r, EV_RUN_G, &buf) == 0; + // the control: the helpers do see a force flag, a plus refspec and a strange program + var tb : [128]u8 = [0] ** 128; + var m : usize = emit_str(&tb, 0, "git\npush\n--force\norigin\nHEAD:refs/heads/x\n"); + assert has_arg(&tb, m, "push") == true and has_arg(&tb, m, "--force") == true and has_arg(&tb, m, "--forc") == false and has_arg(&tb, m, "x") == false; + assert has_plus(&tb, m) == false; + m = emit_str(&tb, 0, "git\npush\norigin\n+HEAD:refs/heads/x\n"); + assert has_plus(&tb, m) == true; + m = emit_str(&tb, 0, "sh\n-c\nx\n"); + assert program_ok(&tb, m, r) == false; + m = emit_str(&tb, 0, "git\nx\n"); + assert program_ok(&tb, m, r) == true; + m = emit_str(&tb, 0, "t27c\nx\n"); + assert program_ok(&tb, m, r) == true; + m = emit_str(&tb, 0, "/opt/tri/tri\nx\n"); + assert program_ok(&tb, m, r) == true; + m = emit_str(&tb, 0, "gitx\nx\n"); + assert program_ok(&tb, m, r) == false; + // and a branch named master is refused before any of this + assert steps_sent(req_on("master", 11068, T_SCRATCH, "t27c", false), "", &buf) == 0; +} + +// Scenario: the slots run in a fixed order, and a slot is chosen only when every earlier one has a section. +test the_slots_run_in_a_fixed_order { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert next_slot(r, "") == slot_of(L_FETCH, 0); + assert next_slot(r, EV_RUN_A) == slot_of(L_WORKTREE, 0); + assert next_slot(r, EV_RUN_B) == slot_of(L_TESTS, 0); + assert next_slot(r, EV_RUN_C) == slot_of(L_SEAL, 0); + // the second changed line is not a spec: its slots are skipped + assert next_slot(r, EV_RUN_D) == slot_of(L_SAVE, 2); + assert next_slot(r, EV_RUN_E) == slot_of(L_STAGE, 0); + assert next_slot(r, EV_RUN_F) == slot_of(L_COMMIT, 0); + // nothing pending: no commit + assert next_slot(r, EV_RUN_F_CLEAN) == slot_of(L_HEAD, 0); + assert next_slot(r, EV_RUN_G) == slot_of(L_PR, 0); + // a pull request already open skips the creation; auto-merge already on skips its enabling + assert next_slot(r, EV_RUN_G_OPEN) == slot_of(L_AUTO, 0); + assert next_slot(r, EV_RUN_G_AUTO_ON) == slot_of(L_AUTO_CHECK, 0); + // a part of a run: the first slot without a section, whatever follows it + assert next_slot(r, EV_RUN_D_NO_SEAL) == slot_of(L_SEAL, 2); + assert next_slot(r, EV_RUN_E_NO_DUPES) == slot_of(L_DUPES, 0); + assert next_slot(r, EV_RUN_G_NO_REMOTE) == slot_of(L_REMOTE_HEAD, 0); + assert exit_of(EV_RUN_G, L_PUSH, 0) == 0 and exit_of(EV_RUN_G, L_TESTS, 2) == 0 and exit_of(EV_RUN_G, L_TESTS, 1) == NO_EXIT; +} + +// Scenario: --check runs the gates and then stops: no stage, commit, push, pull request or auto-merge. +test a_check_run_stops_after_the_gates { + const c : TriLandReq = req_of(TXT_CH_TWO, true); + assert next_slot(c, EV_RUN_E) == DONE; + assert next_slot(c, EV_RUN_E_NO_DUPES) == slot_of(L_DUPES, 0); + assert next_slot(c, EV_RUN_D) == slot_of(L_SAVE, 2); + assert next_slot(c, EV_RUN_C) == slot_of(L_SEAL, 0); + assert next_slot(c, "") == slot_of(L_FETCH, 0); + assert next_slot(req_of(TXT_CH_TWO, false), EV_RUN_E) != DONE; + assert applies(c, EV_RUN_E, L_STAGE, 0) == false and applies(c, EV_RUN_E, L_PUSH, 0) == false and applies(c, EV_RUN_E, L_AUTO, 0) == false; + assert applies(c, EV_RUN_E, L_TYPES, 0) == true and applies(c, EV_RUN_E, L_DUPES, 0) == true; + const nm : string = code_name(L_CHECKED); + assert nm.len == 7 and span_is(nm, 0, 7, "CHECKED"); +} + +// Scenario: auto-merge is never reached while any earlier slot has no section, and every gate that fails is a refusal with an exit. +test auto_merge_waits_for_every_gate { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + const auto : u64 = slot_of(L_AUTO, 0); + assert next_slot(r, "") < auto; + assert next_slot(r, EV_RUN_A) < auto and next_slot(r, EV_RUN_B) < auto and next_slot(r, EV_RUN_C) < auto; + assert next_slot(r, EV_RUN_D) < auto and next_slot(r, EV_RUN_E) < auto and next_slot(r, EV_RUN_F) < auto; + assert next_slot(r, EV_RUN_D_NO_SEAL) < auto and next_slot(r, EV_RUN_E_NO_DUPES) < auto and next_slot(r, EV_RUN_G_NO_REMOTE) < auto; + assert next_slot(r, EV_RUN_G) < auto; + // every gate that fails stops the run with a code that is not 0 + assert judge(r, EV_CONFLICT, L_CONFLICTS, 0) != L_OK and exit_code(judge(r, EV_CONFLICT, L_CONFLICTS, 0)) != 0; + assert judge(r, EV_TESTS_FAIL, L_TESTS, 0) != L_OK and exit_code(judge(r, EV_TESTS_FAIL, L_TESTS, 0)) != 0; + assert judge(r, EV_RECHECK_BAD, L_RECHECK, 0) != L_OK and exit_code(judge(r, EV_RECHECK_BAD, L_RECHECK, 0)) != 0; + assert judge(r, EV_TYPES_RED, L_TYPES, 0) != L_OK and exit_code(judge(r, EV_TYPES_RED, L_TYPES, 0)) != 0; + assert judge(r, EV_DUP_NEW, L_DUPES, 0) != L_OK and exit_code(judge(r, EV_DUP_NEW, L_DUPES, 0)) != 0; + assert judge(r, EV_PUSH_OTHER, L_REMOTE_HEAD, 0) != L_OK and exit_code(judge(r, EV_PUSH_OTHER, L_REMOTE_HEAD, 0)) != 0; + // the six named codes and the number each exits with + assert judge(r, EV_CONFLICT, L_CONFLICTS, 0) == L_CONFLICT and judge(r, EV_TESTS_VAC, L_TESTS, 0) == L_TESTS_NOT_CLEAN; + assert judge(r, EV_RECHECK_BAD, L_RECHECK, 0) == L_SEAL_NOT_CLEAN and judge(r, EV_TYPES_RED, L_TYPES, 0) == L_TYPES_NOT_CLEAN; + assert judge(r, EV_DUP_NEW, L_DUPES, 0) == L_DUPE_NOT_SUBSET and judge(r, EV_PUSH_REJECT, L_PUSH, 0) == L_PUSH_NOT_CONFIRMED; +} + +// Scenario: the push is confirmed by the remote naming the object HEAD named; a rejected push is never retried or forced. +test the_push_is_confirmed_by_the_remote_head { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert pushed(EV_PUSH_OK) == true; + assert pushed(EV_PUSH_OTHER) == false; + assert pushed(EV_PUSH_EMPTY) == false; + assert pushed(EV_PUSH_REJECT) == false; + assert pushed(EV_PUSH_LSFAIL) == false; + assert pushed(EV_HEAD_BAD) == false; + assert pushed("") == false; + assert judge(r, EV_PUSH_OK, L_PUSH, 0) == L_OK; + assert judge(r, EV_PUSH_OK, L_REMOTE_HEAD, 0) == L_OK; + assert judge(r, EV_PUSH_OTHER, L_REMOTE_HEAD, 0) == L_PUSH_NOT_CONFIRMED; + assert judge(r, EV_PUSH_EMPTY, L_REMOTE_HEAD, 0) == L_PUSH_NOT_CONFIRMED; + assert judge(r, EV_PUSH_REJECT, L_PUSH, 0) == L_PUSH_NOT_CONFIRMED; + assert judge(r, EV_PUSH_LSFAIL, L_REMOTE_HEAD, 0) == L_PUSH_NOT_CONFIRMED; + assert judge(r, EV_PUSH_OK, L_HEAD, 0) == L_OK; + assert judge(r, EV_HEAD_BAD, L_HEAD, 0) == L_STEP; + const s40 : string = "0123456789abcdef0123456789abcdef01234567"; + const s41 : string = "0123456789abcdef0123456789abcdef012345678"; + const s39 : string = "0123456789abcdef0123456789abcdef0123456"; + const sg : string = "0123456789abcdef0123456789abcdef0123456g"; + const su : string = "0123456789ABCDEF0123456789abcdef01234567"; + const st : string = "0123456789abcdef0123456789abcdef01234567\trefs/heads/x"; + assert s40.len == 40 and sha_at(s40, 0, 40) == true; + assert sha_at(st, 0, st.len) == true; + assert sha_at(s39, 0, 39) == false; + assert sha_at(sg, 0, 40) == false; + assert sha_at(su, 0, 40) == false; + assert sha_at(s41, 0, 41) == false; +} + +// Scenario: the title carries `Closes #N` once, from the lane's own subject; the stage, pending, title and commit steps refuse a surprise. +test the_title_carries_the_issue { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert buf_is(&buf, emit_title(&buf, 0, EV_TITLE, 11068), "tri land: land a lane branch (Closes #11068)"); + assert buf_is(&buf, emit_title(&buf, 0, EV_TITLE_BARE, 11068), "tri land: land a lane branch (Closes #11068)"); + assert buf_is(&buf, emit_title(&buf, 0, EV_TITLE_OTHER, 11068), "tri land: land a lane branch (Closes #11000) (Closes #11068)"); + assert buf_is(&buf, emit_title(&buf, 0, EV_TITLE_EMPTY, 11068), "<title> (Closes #11068)"); + assert buf_is(&buf, emit_title(&buf, 0, "", 7), "<title> (Closes #7)"); + assert buf_is(&buf, emit_title(&buf, 0, "", 0), "<title> (Closes #<issue>)"); + const a : string = "a (Closes #11068)"; + const b : string = "Closes #5, Closes #6"; + const c : string = "Closes #"; + assert has_closes(a, 0, a.len, 11068) == true; + assert has_closes(a, 0, a.len, 1106) == false; + assert has_closes(a, 0, a.len, 110680) == false; + assert has_closes(b, 0, b.len, 6) == true and has_closes(b, 0, b.len, 5) == true and has_closes(b, 0, b.len, 7) == false; + assert has_closes(c, 0, c.len, 6) == false; + assert has_closes("", 0, 0, 6) == false; + assert judge(r, EV_TITLE, L_TITLE, 0) == L_OK; + assert judge(r, EV_TITLE_EMPTY, L_TITLE, 0) == L_STEP; + assert judge(r, EV_PENDING_YES, L_PENDING, 0) == L_OK; + assert judge(r, EV_PENDING_NO, L_PENDING, 0) == L_OK; + assert judge(r, EV_PENDING_FAIL, L_PENDING, 0) == L_STEP; + assert judge(r, EV_PENDING_FAIL, L_COMMIT, 0) == L_STEP; + assert judge(r, EV_PENDING_FAIL, L_STAGE, 0) == L_STEP; +} + +// Scenario: the pull request is the open one, else the one just created; its auto-merge must be confirmed on. +test the_pull_request_number_is_read { + const r : TriLandReq = req_of(TXT_CH_TWO, false); + assert lead_number(EV_OPEN_LANDED, L_OPEN) == 123; + assert lead_number(EV_OPEN_NONE, L_OPEN) == 0; + assert lead_number("", L_OPEN) == 0; + assert open_auto(EV_OPEN_LANDED) == true and open_auto(EV_OPEN_NO_AUTO) == false and open_auto(EV_OPEN_NONE) == false and open_auto("") == false; + assert created_number(EV_PR_CREATED) == 11111; + assert created_number(EV_PR_NOURL) == 0; + assert created_number("") == 0; + assert pr_number(EV_PR_OPEN) == 123 and pr_number(EV_PR_CREATED) == 11111 and pr_number(EV_OPEN_NONE) == 0 and pr_number("") == 0; + assert applies(r, EV_OPEN_NONE, L_PR, 0) == true and applies(r, EV_PR_OPEN, L_PR, 0) == false; + assert applies(r, EV_OPEN_NONE, L_AUTO, 0) == true and applies(r, EV_OPEN_LANDED, L_AUTO, 0) == false; + assert judge(r, EV_PR_CREATED, L_PR, 0) == L_OK; + assert judge(r, EV_PR_FAIL, L_PR, 0) == L_STEP; + assert judge(r, EV_PR_NOURL, L_PR, 0) == L_STEP; + assert judge(r, EV_AUTO_FAIL, L_AUTO, 0) == L_AUTO_NOT_CONFIRMED; + assert judge(r, EV_CHECK_TRUE, L_AUTO_CHECK, 0) == L_OK; + assert judge(r, EV_CHECK_FALSE, L_AUTO_CHECK, 0) == L_AUTO_NOT_CONFIRMED; + assert judge(r, EV_CHECK_FAIL, L_AUTO_CHECK, 0) == L_AUTO_NOT_CONFIRMED; + assert judge(r, "", L_AUTO_CHECK, 0) == L_AUTO_NOT_CONFIRMED; +} + +// Scenario: every outcome has a name, words and an exit; the six named codes are pinned. +test every_outcome_has_its_words { + var c : u8 = 0; + var named : u32 = 0; + while (c < OUTCOMES) { + const nm : string = code_name(c); + const why : string = code_why(c); + if (nm.len > 0 and why.len > 0 and span_is(nm, 0, nm.len, "UNKNOWN") == false) { named = named + 1; } + c = c + 1; + } + assert named == (OUTCOMES as u32); + assert span_is(code_name(L_CONFLICT), 0, 8, "CONFLICT"); + assert span_is(code_name(L_TESTS_NOT_CLEAN), 0, 15, "TESTS_NOT_CLEAN"); + assert span_is(code_name(L_SEAL_NOT_CLEAN), 0, 14, "SEAL_NOT_CLEAN"); + assert span_is(code_name(L_TYPES_NOT_CLEAN), 0, 15, "TYPES_NOT_CLEAN"); + assert span_is(code_name(L_DUPE_NOT_SUBSET), 0, 15, "DUPE_NOT_SUBSET"); + assert span_is(code_name(L_PUSH_NOT_CONFIRMED), 0, 18, "PUSH_NOT_CONFIRMED"); + assert span_is(code_name(OUTCOMES), 0, 7, "UNKNOWN"); + assert exit_code(L_OK) == 0 and exit_code(L_LANDED) == 0 and exit_code(L_BAD_BRANCH) == L_BAD_BRANCH and exit_code(L_AUTO_NOT_CONFIRMED) == 15; + var k : u8 = 0; + var steps : u32 = 0; + while (k < LAND_STEPS) { + const sn : string = step_name(k); + if (sn.len > 0 and span_is(sn, 0, sn.len, "unknown") == false) { steps = steps + 1; } + k = k + 1; + } + assert steps == (LAND_STEPS as u32); + assert span_is(step_name(LAND_STEPS), 0, 7, "unknown"); +} + +// Scenario: the worst case of every step fits, and a room that is too short writes nothing. +test the_worst_case_fits { + var buf : [4096]u8 = [0] ** 4096; + var small : [16]u8 = [0] ** 16; + var mid : [32]u8 = [0] ** 32; + const r : TriLandReq = TriLandReq { branch: B100, issue: 999999999, scratch: P256, t27c: P256, tri: P256, changes: TXT_CH_TWO, check: false, plan: false }; + assert request_refusal(r) == L_OK; + assert steps_sent(r, "", &buf) == (LAND_STEPS as u32); + assert steps_sent(r, EV_RUN_G, &buf) == (LAND_STEPS as u32); + assert step_argv(r, "", L_PR, 0, &buf) > 0 and step_argv(r, "", L_PR, 0, &buf) < CMD_MAX; + assert step_argv(r, "", L_COMMIT, 0, &buf) > 0 and step_argv(r, "", L_COMMIT, 0, &buf) < CMD_MAX; + assert step_argv(r, "", L_CONTAINS, 0, &buf) > 0 and step_argv(r, "", L_WORKTREE, 0, &buf) > 0; + assert step_argv(r, "", L_COMMIT, 0, &small) == 0; + assert step_argv(r, "", L_FETCH, 0, &small) == 0; + assert step_argv(r, "", L_FETCH, 0, &mid) == 27; + assert step_argv(r, "", L_HEAD, 0, &mid) == 19; + assert step_argv(r, "", L_PUSH, 0, &mid) == 0; + assert P256.len == 256 and P257.len == 257 and request_refusal(req_on(T_BRANCH, 11068, P257, "t27c", false)) == L_BAD_PATH; + assert CMD_MAX == 4096; +} + +// Scenario: a section is written the way preflight's readers read it, so the glue's evidence and these fixtures are one shape. +test the_evidence_section_is_written_as_the_readers_read_it { + var buf : [4096]u8 = [0] ** 4096; + assert buf_is(&buf, emit_section(&buf, 0, L_CHANGES, 0, 0, TXT_CH_TWO), EV_CHANGES_OK); + assert buf_is(&buf, emit_section(&buf, 0, L_MERGED, 0, 0, "11055\n"), EV_MERGED_YES); + assert buf_is(&buf, emit_section(&buf, 0, L_MERGED, 0, 0, ""), EV_MERGED_NONE); + assert buf_is(&buf, emit_section(&buf, 0, L_MERGED, 0, 1, "error connecting to api.github.com\n"), EV_MERGED_FAIL); + assert buf_is(&buf, emit_section(&buf, 0, L_MERGE, 0, 128, "x"), "@@ preflight 9 0 128 1\nx\n"); + assert buf_is(&buf, emit_section(&buf, 0, L_CLEAN, 12, 255, "ab\n"), "@@ preflight 28 12 255 3\nab\n\n"); + // the readers find it, and a later section after an earlier one + assert exit_of(EV_CHANGES_OK, L_CHANGES, 0) == 0 and body_from(EV_CHANGES_OK, L_CHANGES, 0) == 23; + assert exit_of(EV_MERGED_FAIL, L_MERGED, 0) == 1 and exit_of(EV_MERGED_FAIL, L_MERGED, 1) == NO_EXIT and exit_of(EV_MERGED_FAIL, L_FETCH, 0) == NO_EXIT; + assert exit_of(EV_CONFLICT, L_CONFLICTS, 0) == 0 and exit_of(EV_CONFLICT, L_MERGE, 0) == 1; + assert exit_of(EV_TITLE, L_TITLE, 0) == 0 and exit_of(EV_TITLE, L_COMMIT, 0) == NO_EXIT; +} + +// Scenario: the cleanup step is run when the scratch tree was made, never when it was not, and a plan always shows it. +test the_clean_step_runs_only_when_the_worktree_exists { + var buf : [4096]u8 = [0] ** 4096; + const r : TriLandReq = req_of("", false); + assert step_argv(r, "", L_CLEAN, 0, &buf) > 0; + assert step_argv(r, EV_WORKTREE_OK, L_CLEAN, 0, &buf) > 0; + assert step_argv(r, EV_WORKTREE_FAIL, L_CLEAN, 0, &buf) == 0; + assert step_argv(r, EV_MERGED_YES, L_CLEAN, 0, &buf) == 0; + assert step_argv(r, EV_OPEN_LANDED, L_CLEAN, 0, &buf) == 0; + assert step_argv(r, EV_RUN_A, L_CLEAN, 0, &buf) == 0; + assert step_argv(r, EV_RUN_B, L_CLEAN, 0, &buf) > 0; + // the next slot never names it + assert next_slot(req_of(TXT_CH_TWO, false), EV_RUN_G_AUTO_ON) < slot_of(L_CLEAN, 0); + assert in_scratch(L_CLEAN) == false; +} + +// Scenario: a flaky TLS or DNS answer on a network step is run again; every other failure, a rejected push included, is final. +test only_a_flaky_network_answer_is_run_again { + const tls : string = "Post \"https://api.github.com/graphql\": tls: failed to verify certificate: x509: certificate signed by unknown authority\n"; + const hs : string = "fatal: unable to access 'https://github.com/gHashTag/t27.git/': TLS handshake timeout\n"; + const dns : string = "fatal: unable to access 'https://github.com/x.git/': Could not resolve host: github.com\n"; + const nope : string = " ! [rejected] HEAD -> lane/x (non-fast-forward)\n"; + assert transient(L_PR, 1, tls) == true and transient(L_PUSH, 128, hs) == true and transient(L_FETCH, 128, dns) == true; + assert transient(L_MERGED, 1, tls) == true and transient(L_OPEN, 1, tls) == true and transient(L_AUTO, 1, tls) == true; + assert transient(L_AUTO_CHECK, 1, tls) == true and transient(L_REMOTE_HEAD, 128, dns) == true and transient(L_FETCH_BRANCH, 128, hs) == true; + // a run that succeeded, a failure of another kind, an empty answer + assert transient(L_PR, 0, tls) == false; + assert transient(L_PUSH, 1, nope) == false; + assert transient(L_PR, 1, "") == false; + assert transient(L_PR, 1, "GraphQL: Head sha can't be blank\n") == false; + // a step that never leaves this machine is not run again, whatever it printed + assert transient(L_MERGE, 1, tls) == false and transient(L_TESTS, 1, tls) == false and transient(L_COMMIT, 1, tls) == false; + assert transient(L_CHECKOUT, 128, dns) == false and transient(L_WORKTREE, 1, hs) == false and transient(L_DUPES, 1, tls) == false; + assert over_network(L_FETCH) and over_network(L_PUSH) and over_network(L_AUTO_CHECK) and over_network(L_TIP) == false and over_network(L_CLEAN) == false; + assert RETRIES == 5; +}