From 035c53cf91ea5d1bb5a59406e9cdef4a43518a76 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 05:46:50 +0700 Subject: [PATCH] The half the locator was silent on was one wrong assumption `tri unparsed locate` confirmed 37 answers and refuted 37 -- exactly half. That line sat at the bottom of four consecutive reports and I kept picking one of the other options. `split_module` assumed a BRACED module. A file declaring `module NAME;` -- the semicolon form -- has no wrapper, so the scan for "the first line that opens a brace at depth 1" found the first `struct`, and everything after that struct's closing brace became the tail. Every truncated prefix then had a large orphan chunk glued onto it and failed for the chunk's own reasons, so the bisection landed on the first item and causality refuted it. Found with the base rate rather than without it. The hunch -- "the tail is too long" -- was available immediately, and on its own worth nothing: tail > 10 lines tail = 1 line refuted 32 4 confirmed 4 33 A one-line tail is a real braced module's closing brace, and it lands almost entirely in the confirmed column. That is the finding, and it cost one more measurement than the hunch did. located AND causally confirmed 37 -> 60 ... the item ALONE reproduces 60 candidate REFUTED by causality 37 -> 14 The 14 that remain point at lines 5 to 11 -- the FIRST item in the file. Those are specs opening with `algorithm NAME {`, which the parser does not implement, so the first prefix already fails and there is nothing to bisect. Refusing is correct: "unsupported from its first declaration" is a different claim from "this item causes the failure", and only the second is what the command promises. `bootstrap/src/compiler.rs` untouched; FROZEN_HASH does not move. Refs #2864 Co-Authored-By: Claude Opus 5 --- .claude/skills/ci-gates/SKILL.md | 47 +++++++++++++++++++ cli/tri/src/unparsed.rs | 45 ++++++++++++++++++ ...-was-silent-on-was-one-wrong-assumption.md | 8 ++++ 3 files changed, 100 insertions(+) create mode 100644 docs/now/2026-08-30-the-half-the-locator-was-silent-on-was-one-wrong-assumption.md diff --git a/.claude/skills/ci-gates/SKILL.md b/.claude/skills/ci-gates/SKILL.md index 310eca8dd9..226e9cbb39 100644 --- a/.claude/skills/ci-gates/SKILL.md +++ b/.claude/skills/ci-gates/SKILL.md @@ -8846,3 +8846,50 @@ pattern visible in a single glance. **Fix the location before analysing the population.** It costs a line and it converts every later step from guessing to reading. + +## 354. The option you keep not picking + +`tri unparsed locate` confirmed 37 answers and refuted 37 -- exactly half. That +line sat at the bottom of four consecutive iteration reports, and each time I +picked one of the other two options. + +Half is not a plateau, it is a signal. The cause took twenty minutes: a file +declaring `module NAME;` -- the SEMICOLON form -- has no wrapping brace, and +`split_module` looked for "the first line that opens a brace at depth 1" and +found the first `struct`. Everything after that struct's closing brace became +the "tail", so every truncated prefix had a large orphan chunk glued onto it +and failed for the chunk's own reasons. + + confirmed 37 -> 60 refuted 37 -> 14 + +**A number that has been stable across several reports is either finished or +avoided.** Write down which, and if it is avoided, take it next. + +## 355. The base rate is what turned a hunch into a cause + +The hunch -- "the tail is too long" -- was available immediately: 32 of the 37 +refuted cases had a tail over 10 lines. On its own that is worth nothing; long +tails might simply be common. + +``` + tail > 10 lines tail = 1 line + refuted 32 4 + confirmed 4 33 +``` + +A one-line tail is a real braced module's closing brace, and it lands almost +exclusively in the confirmed column. THAT is the finding, and it costs one more +measurement than the hunch did. + +**A distribution over the failing group is a hunch. The same distribution over +the passing group is a cause.** + +## 356. Fourteen refusals that are correct + +The 14 still refuted point at lines 5 to 11 -- the first item in the file. Those +are specs opening with `algorithm NAME {`, a construct the parser does not +implement at all, so the very first prefix fails and there is nothing to bisect. + +The locator says so instead of naming that item, which is right: "the file is +unsupported from its first declaration" is not the same claim as "this item +causes the failure", and only the second one is what the command promises. diff --git a/cli/tri/src/unparsed.rs b/cli/tri/src/unparsed.rs index 36b40ad6df..f5db505ad0 100644 --- a/cli/tri/src/unparsed.rs +++ b/cli/tri/src/unparsed.rs @@ -1075,6 +1075,29 @@ mod tests { assert!(stage_of("Error: parse error at module level near line 2") == Stage::Parse); } + // `module NAME;` wraps nothing, so the body is everything after it. Taking + // the first braced line as a wrapper instead made the rest of the file a + // "tail" that was glued onto every truncated prefix -- 32 of 37 refuted + // answers were that, against 4 of 37 confirmed. + #[test] + fn a_semicolon_module_wraps_nothing() { + let src = [ + "// header", + "module config-load;", + "struct A { x: u32 }", + "fn b() -> u32 { return 1; }", + ]; + let (start, end) = split_module(&src); + assert_eq!(start, 2, "body starts after the `module NAME;` line"); + assert_eq!(end, 4, "and runs to the end -- there is no closing brace"); + } + + #[test] + fn a_braced_module_still_splits_at_its_brace() { + let src = ["module m {", " fn a() { }", "}"]; + assert_eq!(split_module(&src), (1, 2)); + } + // A file with no module wrapper still has a body: the whole file. #[test] fn split_module_handles_a_bare_file() { @@ -1262,6 +1285,28 @@ fn check_text(t27c: &Path, root: &Path, text: &str) -> (bool, Option) { fn split_module(lines: &[&str]) -> (usize, usize) { let d = depths(lines); let c = code_only(lines); + // `module NAME;` -- the SEMICOLON form, which wraps nothing. The scan below + // looks for the first line that opens a brace at depth 1 and calls it the + // module header; in a semicolon-form file that is the first `struct` or + // `fn`, so everything after its closing brace became the "tail" and the + // reconstruction glued a large orphan chunk onto a truncated body. Every + // prefix then failed for the chunk's own reasons. + // + // Measured before the fix, with the base rate that makes it mean something: + // + // tail > 10 lines tail = 1 line + // refuted 32 4 + // confirmed 4 33 + // + // A one-line tail is the closing brace of a real braced module. Anything + // longer was this. + for i in 0..lines.len() { + let t = c[i].trim(); + let t = t.strip_prefix("pub ").unwrap_or(t); + if t.starts_with("module ") && t.ends_with(';') && d[i] == 0 { + return (i + 1, lines.len()); + } + } for i in 0..lines.len() { if d[i] == 1 && c[i].contains('{') { for j in i + 1..lines.len() { diff --git a/docs/now/2026-08-30-the-half-the-locator-was-silent-on-was-one-wrong-assumption.md b/docs/now/2026-08-30-the-half-the-locator-was-silent-on-was-one-wrong-assumption.md new file mode 100644 index 0000000000..d77c596f6a --- /dev/null +++ b/docs/now/2026-08-30-the-half-the-locator-was-silent-on-was-one-wrong-assumption.md @@ -0,0 +1,8 @@ +# NOW -- The half the locator was silent on was one wrong assumption (2026-08-30) + +## The half the locator was silent on was one wrong assumption (Refs #2864) + +- tri unparsed locate confirmed 37 and refuted 37 -- exactly half. Four iterations of options lists carried that line, and I kept picking something else. +- Cause: split_module assumed a BRACED module. Files declaring 'module NAME;' -- the semicolon form -- have no wrapper, so it took the first 'struct X {' as the header and made the rest of the file a tail. Every truncated prefix then had a large orphan chunk glued to it and failed for the chunk's own reasons. +- Found with the base rate, not without it: tail longer than 10 lines appeared in 32 of 37 REFUTED and 4 of 37 CONFIRMED; a one-line tail in 4 refuted and 33 confirmed. A one-line tail is a real module's closing brace. +- confirmed 37 -> 60, refuted 37 -> 14, all 60 still reproduce alone. The 14 that remain point at lines 5-11: their FIRST item is unsupported -- files opening with 'algorithm NAME {' -- so there is nothing to bisect and the refusal is correct.