prose, unparsed: two commands write a reason for every undecided case and discard it - #3233
Conversation
Both carry a hand-written reason on their "nothing decided" variant and drop it at the only place that reads it. `Outcome::Other` has eight construction sites, each with a distinct reason, and the sole reader bound it to a wildcard and counted -- with `Outcome::Prose(0)` folded into the same number. `Located::None` is the same, six sites, and its own doc comment says "Nothing claimed, and why". Three prose reasons -- unreadable, cannot write probe, compiler did not run -- say the TOOL failed. A reader of "NOT DECIDED" could not tell them from "cap reached", which is an ordinary result: a failed instrument reported as a finding. Both now tally by reason and print the breakdown, marking the instrument-failure reasons. `Outcome::Other` changes from String to &'static str: every site already passed a literal, and the type now says the set is fixed, which is what lets BROKEN_INSTRUMENT name members of it. Tests read the CALL SITE, since the defect is a discarding pattern there and a test of any counting helper would pass. Both verified by mutation: restoring the wildcard fails them by name. The BROKEN_INSTRUMENT assertion is separately mutation-verified -- renaming a member to one no site constructs fails it. `tri prose report` shells out to t27c and exits "no compiler" in this tree, so this is verified by the suite and by both warnings disappearing, not by its output. Refs #3232 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Refs #3232 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…the subject
Both tests take the production text as everything before the FIRST
`#[cfg(test)]`. That is a truncation, not a filter: 13 of the crate's 46 files
carrying a test module have production items after it, and gates.rs has 83
across 38 test modules.
Both tests happen to work today because their subjects sit above the file's
first test module -- position, not construction. Move a test module up, or the
subject down, and `contains` goes false and the negative assertion passes
because it is looking at nothing.
Each now asserts its subject is present in the slice before asserting anything
about it. Control: planting `#[cfg(test)] mod planted { .. }` above the subject
in prose.rs fails the test with "the production slice no longer reaches the
subject -- this test would pass vacuously", where before it would have passed.
`gates::test_module_lines` does NOT have this flaw -- it is a state machine
that toggles in and out of every test module -- so `mutate`'s site filtering is
unaffected. The defect is only in the split-and-take-first shape.
Refs #3232
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR DashboardGenerated at: 2026-09-05 02:53:58 UTC
Summary
Seal Status
|
The previous commit's numbers were produced by a regex that counted column-0 items after the first `#[cfg(test)]` without excluding the ones inside later test modules. Recounted with `gates::test_module_lines`, which is a state machine that toggles in and out of every test module and is the instrument `mutate` already trusts: 46 .rs files contain a test module 10 of them have production items after their FIRST one 130 such items in total; gates.rs holds 79 of them across 38 test modules Two files the wrong count named -- types_dup.rs and prose.rs -- have ZERO, so prose.rs's slice is whole today and its anchor is defence rather than a live repair. The comment now says so. unparsed.rs really does truncate: six items sit after its test module, and the subject only happens to be above the cut. Refs #3232 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…/t27 into w106b-reasons-discarded
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 03:00:35 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 03:04:26 UTC
Summary
Seal Status
|
PR DashboardGenerated at: 2026-09-05 03:07:47 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 03:44:43 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 04:04:50 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 05:36:46 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 05:58:45 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-09-05 07:12:52 UTC
Summary
Seal Status
|
Both commands carry a hand-written reason on their "nothing decided" variant and
throw it away at the only place that reads it.
tri prose reportOutcome::Otheris constructed at eight sites, each with a distinct reason:unreadablecannot write probecompiler did not rundeclarations changed -- refusedno line in the errorline out of rangestops on a commentcap reachedThe sole reader bound it to a wildcard and counted, with a ninth case
(
Outcome::Prose(0)) folded into the same number. The output line:Three of those reasons say the tool failed. A reader of "NOT DECIDED"
cannot tell
compiler did not runfromcap reached, which is an ordinaryresult — a failed instrument reported as a finding.
tri unparsed locateIdentical shape.
Located::None(&'static str), six construction sites, and itsown doc comment reads "Nothing claimed, and why". The why went into
Located::None(_) => silent += 1.After
Outcome::Otheralso moves fromStringto&'static str. Every site alreadypassed a literal; the type now says the set is fixed and enumerable, which is
what lets
BROKEN_INSTRUMENTname members of it and be checked against them.Verification
cargo test -p tri --bin trithe reason is discarded at the match arm againBROKEN_INSTRUMENTnames a reason no site constructswhich no site constructsfield 0 is never readwarnings for both filesTests read the call site: the defect is a discarding pattern there, so a
test of any counting helper would have passed.
tri prose reportshells out tot27c, which is not built in this tree, andexits with "no compiler". This change is verified by the suite and by the two
warnings disappearing — not by running the command's output.
How these were found, including what went wrong
tri gates warnings(#3230) classified both asfield 0 is never read. Atriage fan-out over the 16 dead-code warnings returned
8 UNWIRED / 7 TEST_ONLY / 1 INTENTIONAL.
The adversarial stage was capped at the first 6 of the 8 UNWIRED claims, and
these two are exactly the ones the cap dropped. They came back as "not
surviving" when they had never been checked at all. Both were confirmed by hand
instead. A cap that does not say what it dropped reads as coverage.
Refs #3232