Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions .trinity/seals/tri_tool_tri_worktrees.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
{
"built_by": "t27c-bootstrap@0.5.2+5d5d2cdef",
"built_by": "t27c-bootstrap@0.5.2+ea35d9b72",
"closure": [],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:b533e7d02cfcf8702f0816fc836513ef038e4cf8c2a947bb320433f20063ed57",
"gen_hash_rust": "sha256:96b37b3ce707b4f1437288c62e69caa8b3a0a387f11d1ff826e6e485f324d915",
"gen_hash_verilog": "sha256:95e02975fbe3862a319fca8098e35fb80e3d424042e82f83e0cae86430c6f8c4",
"gen_hash_zig": "sha256:a4e673ba1c8066518db133b13acbc7c0f8440262f7a5f540881435a56ef18ed1",
"gen_hash_c": "sha256:3730bc66d153d4e749ac0760d26c72e9dbd4ea8f5e0660f3efcecdc713c67869",
"gen_hash_rust": "sha256:5e6c679216c3e25f1065236b2dbdad7f610a520d04a8930ae59e697feeb6cb31",
"gen_hash_verilog": "sha256:cc44189cebda1719fc034c942a6fad895f65515b1dee20a33f219b8d338c1675",
"gen_hash_zig": "sha256:2bf37ef5bc6ec7f82534dd30e20dfc06d4001fffc022c1e5ad71dd4cb0737803",
"module": "tool_tri_worktrees",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-09T14:56:31Z",
"sealed_at": "2026-10-19T03:52:00Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:4427c5e349eccd291f547ab064220d6c52e5c4a954f74f6bc73b36cbb6fe722b",
"spec_hash": "sha256:a1192fdda1ff3eadeb5de28ae9d662ee7505545c70e62ca1d2d24d1d32b6d1cf",
"spec_path": "specs/tools/tri/worktrees.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 4,
"total": 4
"total": 4,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d",
"test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10",
"zig": "0.16.0"
}
}
37 changes: 37 additions & 0 deletions .trinity/seals/worktrees_TriWorktreeReap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"built_by": "t27c-bootstrap@0.5.2+ea35d9b72",
"closure": [
{
"spec": "specs/tri/lab/receipt.t27",
"spec_hash": "sha256:00d9eec8d7be84dde596c9990b3a5574de24aff9f7a94579fc620eb585712441"
},
{
"spec": "specs/tri/lanes/lanes.t27",
"spec_hash": "sha256:aac192b3e3250196262a9b8467d4a9cef8147438c11c0744c66c3f6b175c9342"
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:8d09198aa53a8bdc23093d3cffb3512bc8380d7489f2246d662f60e96ab45a1d",
"gen_hash_rust": "sha256:a2b4fae679bfa41d9985a8c72810452a1748b7a490f224082d1d07b617ba9bd5",
"gen_hash_verilog": "sha256:716b12e948192e930b1e51c9f46cf0a674355d58e9e87d00137b27cbdadab708",
"gen_hash_zig": "sha256:624311ddde0ac3622b5eeb5ef74a1e74b6ec59bd944d2ff8157f828947de373e",
"module": "TriWorktreeReap",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T03:51:32Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:b01a0e09684d6e3c6c055a8a6f9efb69215f2f0ac4ffeff1a5df33fa403748fd",
"spec_path": "specs/tri/worktrees/reap.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 13,
"total": 13,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10",
"zig": "0.16.0"
}
}
2 changes: 0 additions & 2 deletions bootstrap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ mod host;
mod tt_debug;
mod tt_manifest;
mod tt_profile;
// mod runtime_minimal;
// mod runtime_minimal_test;

use anyhow::Context;
use clap::{Parser, Subcommand};
Expand Down
19 changes: 0 additions & 19 deletions bootstrap/src/runtime_minimal.rs

This file was deleted.

18 changes: 0 additions & 18 deletions bootstrap/src/runtime_minimal_test.rs

This file was deleted.

2 changes: 1 addition & 1 deletion cli/tri/src/payout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pub mod pay; // t27c gen-rust of specs/tri/network/payout.t27
use {anyhow::Result, sha2::{Digest, Sha256}, std::collections::{BTreeMap, BTreeSet, HashMap}, std::io::Write, std::process::{Command, Stdio}};
/// Run `c` with `input` on its stdin; its stdout, leaked, since the generated rules read `&'static str`.
fn sh(c: &str, a: &[&str], input: &str) -> &'static str { let mut p = Command::new(c).args(a).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::null()).spawn().expect(c); let _ = p.stdin.take().map(|mut i| i.write_all(input.as_bytes())); String::from_utf8_lossy(&p.wait_with_output().map(|o| o.stdout).unwrap_or_default()).into_owned().leak() }
pub(crate) fn sh(c: &str, a: &[&str], input: &str) -> &'static str { let mut p = Command::new(c).args(a).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::null()).spawn().expect(c); let _ = p.stdin.take().map(|mut i| i.write_all(input.as_bytes())); String::from_utf8_lossy(&p.wait_with_output().map(|o| o.stdout).unwrap_or_default()).into_owned().leak() }
/// GitHub's answer `name`: the memo, else the GH_CACHE file `ok` reads, else curl with `auth` on stdin (kept once `ok` reads it). `join` adds one author (pay::author_join).
fn get(memo: &mut HashMap<String, &'static str>, dir: &std::path::Path, auth: &str, name: String, ok: &dyn Fn(&'static str) -> bool, args: &[&str]) -> &'static str { if let Some(t) = memo.get(&name) { return t; } let t = std::fs::read_to_string(dir.join(&name)).ok().map(|s| &*s.leak()).filter(|s| ok(s)).unwrap_or_else(|| { let t = sh("curl", &[&["-fsSL", "--max-time", "60", "-H", "@-"], args].concat(), auth); if ok(t) { let _ = std::fs::write(dir.join(&name), t); } t }); memo.insert(name, t); t }
fn join(v: &mut Vec<(u64, u8, &'static str)>, id: u64, f: u8, own: bool, x: &'static str) { match v.iter().position(|a| a.0 == id) { Some(j) => v[j].1 = pay::author_join(v[j].1, f, own), None => v.push((id, f, x)) } }
Expand Down
42 changes: 39 additions & 3 deletions cli/tri/src/trees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use anyhow::{Context, Result};
use clap::Args;
use std::process::Command;
#[path = "../../../gen/rust/tri/worktrees/reap.rs"] #[allow(dead_code, unused_parens)]
mod reap; // t27c gen-rust of specs/tri/worktrees/reap.t27: every rule of `--reap-plan`

/// One checkout, as `git worktree list --porcelain` describes it.
#[derive(Debug, PartialEq, Eq, Default)]
Expand All @@ -32,7 +34,7 @@ pub struct Tree {
pub branch: Option<String>,
pub detached: bool,
pub bare: bool,
pub locked: bool,
pub locked: Option<String>,
pub prunable: bool,
}

Expand Down Expand Up @@ -137,7 +139,7 @@ pub fn parse_porcelain(text: &str) -> Vec<Tree> {
"branch" => cur.branch = Some(rest.trim_start_matches("refs/heads/").to_string()),
"detached" => cur.detached = true,
"bare" => cur.bare = true,
"locked" => cur.locked = true,
"locked" => cur.locked = Some(rest.to_string()),
"prunable" => cur.prunable = true,
_ => {}
}
Expand Down Expand Up @@ -248,6 +250,39 @@ pub struct Worktrees {
/// Print every tree, not only those holding work or unreadable.
#[arg(long)]
all: bool,
/// Print the `git worktree remove` line of every checkout that is REMOVABLE (rules: specs/tri/worktrees/reap.t27): its PR is merged or closed (asked of GitHub once per branch), it holds nothing but the untracked target link, and no live pid holds its lock. Still deletes nothing.
#[arg(long)]
reap_plan: bool,
}

/// The `--reap-plan` section: each checkout judged by `reap`, and the line that removes each REMOVABLE one. GitHub is asked only about a tree a merged PR would make removable.
fn reap_plan(trees: &[Tree], all: bool) {
let token = std::env::var("GITHUB_TOKEN").ok().or_else(|| Command::new("gh").args(["auth", "token"]).output().ok().map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()));
let auth = token.filter(|t| !t.is_empty()).map(|t| format!("Authorization: Bearer {t}\n")).unwrap_or_default();
let (main, mut counts) = (trees.first().map_or("", |t| t.path.as_str()), [0usize; reap::VERDICTS as usize]);
println!();
for (i, t) in trees.iter().enumerate() {
let (path, branch): (&'static str, &'static str) = (t.path.clone().leak(), t.branch.clone().unwrap_or_default().leak());
let dirty = !git_in(path, &["status", "--porcelain"]).map_or(false, |s| reap::only_target(s.leak()));
let pid = reap::lock_pid(t.locked.clone().unwrap_or_default().leak());
let gone = pid != 0 && Command::new("kill").args(["-0", &pid.to_string()]).output().map_or(false, |o| String::from_utf8_lossy(&o.stderr).contains("No such process"));
let lock = reap::lock_state(t.locked.is_some(), pid, !gone);
let judge = |pr| reap::verdict(i == 0, dirty, lock, pr, reap::plain(path));
let mut v = judge(reap::PR_MERGED);
if v == reap::V_REMOVABLE {
let url = format!("{}{branch}", reap::PULLS_URL);
let pulls = if reap::plain(branch) { crate::payout::sh("curl", &["-fsSL", "--max-time", "30", "-H", "@-", &url], &auth) } else { "" };
v = judge(reap::pr_state(serde_json::from_str::<serde_json::Value>(pulls).ok().and_then(|j| serde_json::to_string_pretty(&j).ok()).unwrap_or_default().leak()));
}
counts[v as usize] += 1;
if v == reap::V_REMOVABLE || all {
println!(" {:14} {:28.28} {branch:34.34} {}", reap::verdict_name(v), path.rsplit('/').next().unwrap_or(path), reap::why(v));
}
if v == reap::V_REMOVABLE {
println!(" {}{main}{}{} {path}", reap::REMOVE_HEAD, reap::REMOVE_MID, reap::remove_flags(lock));
}
}
println!(" reap plan: {}", (0..reap::VERDICTS).map(|v| format!("{} {}", counts[v as usize], reap::verdict_name(v))).collect::<Vec<_>>().join(", "));
}

pub fn run(a: &Worktrees) -> Result<()> {
Expand Down Expand Up @@ -355,6 +390,7 @@ pub fn run(a: &Worktrees) -> Result<()> {
gib(keep_kb)
);
}
if a.reap_plan { reap_plan(&trees, a.all); }
println!(" Nothing was deleted. A clean tree is not a tree you own.");
Ok(())
}
Expand Down Expand Up @@ -398,7 +434,7 @@ mod porcelain_tests {
fn locked_bare_and_prunable_are_read() {
let t = parse_porcelain("worktree /r\nbare\n\nworktree /l\nHEAD a\nlocked\n\nworktree /p\nHEAD b\nprunable gitdir file points to non-existent location\n");
assert!(t[0].bare);
assert!(t[1].locked);
assert!(t[1].locked.is_some());
assert!(t[2].prunable);
}

Expand Down
4 changes: 2 additions & 2 deletions docs/reports/orphan_modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"_what": "Per-crate ceiling on .rs files under src/ that no `mod` declaration reaches from the crate root. Measured by `tri mods orphan --gate`.",
"_why": "#2427, a Zig-lexer PR, removed `mod elab;` from cli/tri/src/main.rs in the same hunk as two other lines and left the 319-line file. cargo build cannot error on a file it does not compile, the suite fell 358 -> 354, and no gate reads the test count. Nothing printed a word for six days (#2900).",
"_rule": "Exact match, not an upper bound. A count BELOW its ceiling fails too, so the next orphan cannot hide in the slack -- lower the number in the commit that connects a file.",
"_bootstrap_6": "Pre-existing, not repaired here: _enrich/mod.rs, neural/attention.rs, neural/hslm.rs, runtime_minimal.rs, runtime_minimal_test.rs. tooling.rs (7 unconnected gate bodies, #2905) was deleted by #10165 and math_pslq.rs by #10404, each to pay the foreign-line budget; the rest are unexamined. Connecting any of them is a decision about what goes red, not a repair.",
"_bootstrap_3": "Pre-existing, not repaired here: _enrich/mod.rs, neural/attention.rs, neural/hslm.rs. tooling.rs (7 unconnected gate bodies, #2905) was deleted by #10165, math_pslq.rs by #10404, and runtime_minimal.rs and runtime_minimal_test.rs (two scratch stubs, their `mod` lines already commented out of main.rs) by #10805, each to pay the foreign-line budget; the rest are unexamined. Connecting any of them is a decision about what goes red, not a repair.",
"ceilings": {
"bootstrap": 5,
"bootstrap": 3,
"cli/tri": 0,
"cli/trios-bridge": 0,
"cli/flash-spi": 0,
Expand Down
Loading
Loading