From 05b89fe2f809da4153ef8b1524afcf0f4edf0ae6 Mon Sep 17 00:00:00 2001 From: Vasilev Dmitrii Date: Thu, 3 Sep 2026 19:35:54 +0700 Subject: [PATCH 1/2] fix(tri): price the four remaining thresholds; one guards a hazard, three were not the class Following the 30-line window, the short list from that sweep was read by hand and each constant was priced. quant.rs `depth > 8`, the recursion cap in `size_of`. Instrumented over the live corpus: 2078 calls, maximum depth reached ONE, guard taken ZERO times -- and the census is identical with the cap at 1, 2, 4, 6, 8, 12, 16, 32 or 64. It decides nothing about any published number. It is kept, and now it is PROVEN: removing it stack-overflows on a struct whose field is itself, which #2949 established exists in real code (`BTreeNode** children` inside `BTreeNode`). A guard clause nobody has executed is a comment, so a test executes it -- with a finite-chain counter-example beside it, or the cap would be indistinguishable from "give up on anything nested". red.rs `at_least: n >= 30` against `per_page=30`: two literals that must agree, linked only by a comment. Raising the query alone would have kept printing `+` on streaks that are exact -- a truncation marker that has stopped marking truncation, which is what that command exists to surface. One constant now, and the test reads the page size back OUT of the URL and checks the count at which the marker flips. Not the class, with the reason: prcheck.rs `blips > 5` and `quiet >= 4` are retry budgets that print their own number, and quant.rs `e >= 8` chooses between `2^e` and the literal. Refs #2994 Co-Authored-By: Claude Opus 5 --- cli/tri/src/quant.rs | 51 ++++++++++++++++- cli/tri/src/red.rs | 55 ++++++++++++++++++- ...d-one-guards-a-hazard-three-were-not-th.md | 7 +++ 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 docs/now/2026-09-03-four-thresholds-priced-one-guards-a-hazard-three-were-not-th.md diff --git a/cli/tri/src/quant.rs b/cli/tri/src/quant.rs index 70002ea357..53616f0fa1 100644 --- a/cli/tri/src/quant.rs +++ b/cli/tri/src/quant.rs @@ -132,9 +132,22 @@ fn scan_structs(specs: &[(PathBuf, String)]) -> Structs { Structs { fields, conflicted } } +/// How deep `size_of` will follow a type before calling it unbounded. +const MAX_TYPE_DEPTH: usize = 8; + fn size_of(ty: &str, s: &Structs, depth: usize) -> Size { let ty = ty.trim().trim_end_matches(',').trim(); - if depth > 8 { + // A recursion cap, and it has never fired here. Instrumented over the live + // corpus: 2078 calls to this function, maximum depth reached **1**, guard + // taken **0** times -- and the census is identical with the cap at 1, 2, 4, + // 6, 8, 12, 16, 32 or 64. So it decides nothing about any published number. + // + // It is kept because what it guards is real and simply absent from this + // corpus: a struct that contains itself. #2949 established one in C + // (`BTreeNode** children` inside `BTreeNode`), and a walk of that without a + // cap does not terminate. A guard clause nobody has executed is a comment, + // so `a_self_referential_struct_terminates` executes this one. + if depth > MAX_TYPE_DEPTH { return Size::Unbounded; } if let Some(n) = primitive(ty) { @@ -1623,6 +1636,42 @@ mod tests { } } + /// The recursion cap, executed on purpose. + /// + /// Instrumented over the live corpus: **2078** calls to `size_of`, maximum + /// depth reached **1**, cap taken **0** times -- and the census is identical + /// with it at 1, 2, 4, 6, 8, 12, 16, 32 or 64. Nothing in this repository + /// exercises it, and a guard clause nobody has run is a comment. This runs + /// it: a struct whose field is itself, which #2949 established exists in + /// real code (`BTreeNode** children` inside `BTreeNode`) and which without + /// the cap does not terminate. + #[test] + fn a_self_referential_struct_terminates() { + let mut fields = std::collections::BTreeMap::new(); + fields.insert("Node".to_string(), vec!["Node".to_string()]); + let st = Structs { + fields, + conflicted: Default::default(), + }; + assert_eq!(size_of("Node", &st, 0), Size::Unbounded); + } + + /// And a chain that is deep but FINITE must still be measured, or the cap + /// would be indistinguishable from "give up on anything nested". + #[test] + fn a_chain_shallower_than_the_cap_is_still_measured() { + let mut fields = std::collections::BTreeMap::new(); + fields.insert("L0".to_string(), vec!["Trit".to_string()]); + for i in 1..=3 { + fields.insert(format!("L{i}"), vec![format!("L{}", i - 1)]); + } + let st = Structs { + fields, + conflicted: Default::default(), + }; + assert_eq!(size_of("L3", &st, 0), Size::Finite(3)); + } + #[test] fn a_trit_is_three_and_a_struct_is_the_product() { assert_eq!(size_of("Trit", &s(), 0), Size::Finite(3)); diff --git a/cli/tri/src/red.rs b/cli/tri/src/red.rs index 74fdf4fb64..203fdcedf2 100644 --- a/cli/tri/src/red.rs +++ b/cli/tri/src/red.rs @@ -81,10 +81,29 @@ struct Red { /// How many of the most recent runs, newest first, share the failing verdict. /// A single red is noise; nine in a row is an outage nobody is reading. +/// How many runs one page of the API returns. +/// +/// A constant because TWO places need the same number and only prose linked +/// them: the query asks for a page this size, and a streak that FILLS the page +/// is a lower bound, printed as `30+`. Raising the query alone would have kept +/// printing `+` on streaks that are exact -- a truncation marker that has +/// stopped marking truncation, which is this command's own subject. +const PAGE: usize = 30; + +/// The query, built from `PAGE` so the URL and the marker cannot disagree. +fn runs_url(repo: &str, id: &str, branch: &str) -> String { + format!("repos/{repo}/actions/workflows/{id}/runs?branch={branch}&per_page={PAGE}") +} + +/// Is a streak of `n` a LOWER BOUND rather than an exact count? +fn is_lower_bound(n: usize) -> bool { + n >= PAGE +} + fn streak(repo: &str, id: &str, branch: &str) -> Result<(usize, String)> { let raw = gh(&[ "api", - &format!("repos/{repo}/actions/workflows/{id}/runs?branch={branch}&per_page=30"), + &runs_url(repo, id, branch), "--jq", r#".workflow_runs[]|"\(.conclusion)\t\(.created_at)""#, ])?; @@ -146,7 +165,7 @@ fn now(repos: &[String], include_cancelled: bool) -> Result<()> { name: name.to_string(), since: since.chars().take(16).collect(), consecutive: n, - at_least: n >= 30, + at_least: is_lower_bound(n), }); } } @@ -200,3 +219,35 @@ mod tests { ); } } + +#[cfg(test)] +mod page_tests { + use super::*; + + /// The query and the truncation marker must be the same number. + /// + /// They were two literals, both `30`, linked only by a comment. A raise of + /// the query alone would have kept printing `+` on streaks that are exact + /// -- a truncation marker that has stopped marking truncation, which is + /// what this command exists to surface. + #[test] + fn the_query_and_the_marker_read_one_constant() { + // Read the page size back OUT of the URL the command sends and check + // it against the count at which the marker flips. Two literals cannot + // pass this; one constant does. + let url = runs_url("o/r", "wf.yml", "master"); + let sent: usize = url + .rsplit("per_page=") + .next() + .and_then(|v| v.parse().ok()) + .expect("the query states a page size"); + assert!( + !is_lower_bound(sent - 1), + "one short of a full page is an exact count" + ); + assert!( + is_lower_bound(sent), + "a full page is a lower bound and must print as `{sent}+`" + ); + } +} diff --git a/docs/now/2026-09-03-four-thresholds-priced-one-guards-a-hazard-three-were-not-th.md b/docs/now/2026-09-03-four-thresholds-priced-one-guards-a-hazard-three-were-not-th.md new file mode 100644 index 0000000000..d0f80972b2 --- /dev/null +++ b/docs/now/2026-09-03-four-thresholds-priced-one-guards-a-hazard-three-were-not-th.md @@ -0,0 +1,7 @@ +# NOW -- Four thresholds priced: one guards a hazard, three were not the class (2026-09-03) + +## Four thresholds priced: one guards a hazard, three were not the class (Refs #2994) + +- quant.rs depth>8: instrumented over the live corpus -- 2078 calls, maximum depth reached 1, guard taken 0 times, and the census is identical at 1/2/4/6/8/12/16/32/64. It decides nothing about any published number. +- It is kept because removing it STACK-OVERFLOWS on a struct whose field is itself, which #2949 established exists. A guard nobody had run is now run by a test, plus a finite-chain counter-example so the cap is not 'give up on anything nested'. +- red.rs at_least: n>=30 and per_page=30 were two literals linked only by prose. One constant now, with a test that reads the page size back OUT of the URL and checks the count at which the marker flips. From 401eb14b6353852914ec9dec2c7893ae21586ede Mon Sep 17 00:00:00 2001 From: Vasilev Dmitrii Date: Thu, 3 Sep 2026 19:36:26 +0700 Subject: [PATCH 2/2] docs(skill): 453-455 -- a cap that guards termination, two literals, and a mutation over an unmutated file 453: depth>8 changes no published number at any width but removing it stack-overflows. Two different questions, and only the second tells a dead guard from an unexercised one. 454: per_page=30 and n>=30 were two literals linked by prose. The first test I wrote asserted the constant against itself; the real one reads the page size back out of the URL. 455: three mutants passed because the rewrite aborted before writing the file. The helper now exits non-zero when the anchor is not found. Refs #2994 Co-Authored-By: Claude Opus 5 --- .claude/skills/ci-gates/SKILL.md | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/.claude/skills/ci-gates/SKILL.md b/.claude/skills/ci-gates/SKILL.md index 7fa81e6967..9e9e2fe6ca 100644 --- a/.claude/skills/ci-gates/SKILL.md +++ b/.claude/skills/ci-gates/SKILL.md @@ -11595,3 +11595,91 @@ always -- the number was implausible for the size of the tree. **The finding survives; the tool does not.** One of the fourteen was the 30-line window, and it was found by reading a short list rather than by shipping a check that would cry wolf 50 times. + +## 453. A cap that decides nothing about the number, and everything about termination + +The sweep in §452 produced fourteen candidates and about five that looked like +decisions. Read by hand, priced one at a time: + +**`quant.rs` `depth > 8`** -- the recursion cap in `size_of`, which feeds the +walkable-clause census. Instrumented over the live corpus: + + calls to size_of 2078 + maximum depth reached 1 + guard taken 0 + +and the census reads `119 / 308 / 472` with the cap at **1, 2, 4, 6, 8, 12, 16, +32 or 64**. Flat everywhere. So by the §450 test it is not load-bearing, and by +the §426 rule -- *a guard clause you have not executed is a comment* -- it looks +deletable. + +**It is not.** Remove it and the suite does not fail; it **stack-overflows**, on +a struct whose field is itself. #2949 established one in real code +(`BTreeNode** children` inside `BTreeNode`), and this corpus simply has none +today. + +So the treatment is neither deletion nor silence: **make the unreached branch +reachable.** `a_self_referential_struct_terminates` plants the cycle and asserts +`Unbounded`; `a_chain_shallower_than_the_cap_is_still_measured` plants a +four-deep finite chain and asserts a real size, or the cap would be +indistinguishable from *give up on anything nested*. Both mutations bite. + +**The general shape.** Two questions look alike and are not: + +* *does this constant change a published number?* -- sweep it and read the table; +* *does this constant prevent a failure?* -- remove it and see what happens. + +A constant can answer **no** to the first and **yes** to the second, and only +the second question distinguishes a dead guard from an unexercised one. + +## 454. Two literals that must agree, linked only by prose + +`tri gates red` asks GitHub for `per_page=30` runs and prints a streak that +fills the page as `30+`, because a full page is a lower bound. The marker was +`n >= 30` -- a *second* literal, two hundred lines from the first, with a +comment explaining why they match. + +Raising the query alone would have kept printing `+` on streaks that are exact: +**a truncation marker that has stopped marking truncation**, in the command +whose whole subject is silent truncation. + +One constant now, and the test does not assert the constant against itself -- +which is where the first version went wrong: + +```rust +assert!(PAGE >= PAGE); // a control that cannot fail +assert!(!(PAGE - 1 >= PAGE)); // and its twin +``` + +The real check reads the page size back **out of the URL the command sends** +and compares it to the count at which the marker flips. Hard-coding `100` into +the URL turns it red; moving the marker to `n > PAGE` turns it red. Two +literals cannot pass it; one constant does. + +**Where two numbers must be equal, a comment is not the mechanism.** Give them +one definition, and let the test read one of them from the artefact the other +produces. + +## 455. A mutation run over a file that was never mutated + +Three mutants "passed" in a row, all green, all meaningless: the rewrite that +was supposed to change the source had aborted on a failed anchor assertion +**before writing the file**, so every mutant ran against the original. + +This is §440 wearing different clothes -- there the sample was empty, here the +*treatment* was. Both print a clean table. + +The guard is the same one line, moved: the mutation helper now **exits +non-zero and says so** when the anchor is not found exactly once, instead of +letting the caller read a green. + +```python +if s.count(old) != 1: + print(f"ANCHOR NOT FOUND ({s.count(old)}) -- mutation NOT applied"); sys.exit(9) +``` + +**A harness that cannot tell "the mutant survived" from "the mutant was never +built" is not a harness.** The repository already learned this for mutants the +compiler rejected (§382, three arms: killed, survived, never built); a mutant +the *editor* never wrote is the fourth arm, and it looks exactly like the +second.