Four measured ceilings and the dead code they found - #147
Merged
Conversation
…ose that outlived them `BeanEngine.in_scope_now` and the `BeanCore.in_scope` behind it were recorded as unused when the connections page moved its row highlight onto the stored `scoped` record; the removal that entry promised never happened. `ScrollableFrame.yview_fraction`, `.set_yview_fraction` and `PortTable.age` have no caller anywhere in the repository and no mention in any document. Two comments claimed the row highlight asks the engine live whether a port is in the target set. It has read the stored per-flow record for two releases - which is exactly why the live call went unused - so both now describe `_tag_of` as it is. Ahead of the dead-code guard, so the guard is pinned to a tree that is already clean rather than to a number with a ten-minute shelf life. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…chet already had `max-complexity` watches one function: the most branching one in the tree. It is blind to the drift the size ratchet grew a second knob for on 2026-08-06 - the runners-up climbing together, none of them a record. At a ceiling of 29, `cli._run_session` could reach 29 from 27 with every gate green the whole way. COMPLEX_NEAR_CEILING is today's count in the same 70% band: three functions reach 21 or more, and the next one sits at 20, so the band can fire rather than being a number set where nothing can ever reach it. Both halves live in one test because each reading costs a ruff subprocess over the whole tree; `check` still gives each half its own wording. Measured repo-wide, like the ceiling it is a percentage of. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… - argument count PLR0913 is the only rule on ruff's pylint-refactor list that is not a second number on an axis this repository already watches. PLR0912 scores `core.decide` at 30 where C90 scores the same function 29; PLR0915 is FUNCTION_CEILING measured worse, because the ratchet counts logic lines and leaves comments free; PLR0911 needs a branch per return, which C90 has already counted. Complexity and length are both blind to a wide signature: fifteen arguments can be four lines of straight-line assignment. Pinned to the widest signature that exists (14, sortable_tree.__init__), not to ruff's default of 5, which would be red on 25 signatures before catching anything. The two rule lists are now held to each other. `--select` on the workflow command line replaces the list in pyproject.toml, so a rule could be configured, visible to `ruff check` locally, and absent from the only run that can block a merge. Both lists are recorded in the suite, and a third check refuses a rule that is neither blocking nor reported. Both READMEs and CONTRIBUTING describe the gate as it is now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…it did not measure Length, branch count and indent depth are three different questions. Nothing else here can answer the third: ruff has no depth rule (SIM102 and SIM117 collapse joinable statements rather than measuring depth), the size ceiling is blind to it, and max-complexity scores a flat chain of eight elif exactly like eight nested if. The ceiling is 5 - a supersampling rasteriser that earns every level - with eleven functions at 4 and 860 of 942 at 2 or less. The band is absolute rather than a percentage: 70% of 5 lands on the same line today, but at a ceiling of 4 it would mean "3 or more" and the count would jump from 12 to 82. The metric was wrong when it was written and its own test is what caught it: an if body was walked without the level it sits at, so four nested blocks measured three. The three metric tests went in before the constants were filled in for exactly that reason, and they live in PROVEN_BY_HAND because any patch to the metric reddens the ratchet tests pinned to it as well - measured, three at once - and a registry entry names one test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…oint
A dead caller keeps its callee looking alive: BeanCore.in_scope had exactly one
caller in the tree and that caller was BeanEngine.in_scope_now, which nothing
called either. One pass sees a name mentioned twice and calls it used, so the scan
iterates - a mention counts as life only when it comes from somewhere alive.
The scan reads an allow-list of trees and never walks the repository root, so it
cannot reach directories that exist on a maintainer machine and in no checkout; one
that did would call a name used locally and dead in CI.
Two measured decisions are recorded in the file. It counts every word, comments and
strings included, because counting only code tokens finds six more names and five
are alive - four called from inside run_gui("""...""") blocks, one through getattr.
And it excludes its own file, because the exception list lives there and a name
written into it was a mention of itself, which disarmed the guard in the act of
recording an exception.
Both halves proven able to fail through the registry.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>…ctually fail Three guards in tests/test_code_shape.py read a threshold out of pyproject.toml and ask ruff whether anything crosses it. The mutation job installed the runtime and dev requirements but not the lint ones, so those tests found no ruff, skipped, and the runner reported SURVIVED for mutations that are caught anywhere ruff is installed. Two entries came back that way on this branch with no defect behind either. The skip is now a visible pytest skip rather than a quiet return. A guard that measured nothing has to look different from a guard that passed - which is the whole point of the registry that surfaced this. One anchor had to move: the entry proving that no workflow upgrades pip from the index pointed at the bare lint-requirements install, unique only while one job installed the linter. It matches twice now, so it is re-anchored on a command that names two requirement files, which is unique for a reason unrelated to what the entry guards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
Four ceilings and one clean-up, all measured on this tree rather than taken from a
textbook. Every number pinned here is today's maximum, so the whole set is green
from the first run and only fires when something grows past what already exists.
This started as a question about adopting an external complexity analyser. The
measurement said no: five of the six things that tool takes are taken here already,
often better, and its duplicate detector finds nothing in this tree - 168 files
scanned, zero logic clones, nine cross-file groups that are all data tables. Its
Python reader also counts
and/or, which scoresdriver.doctorat 27 whereruff scores the same function 6 - a ranking inversion on a flat table of ternaries.
A second, disagreeing number on an axis that already has one is two ceilings over
one head. So the gaps it did point at were closed with what is already installed.
The five commits
Remove five definitions nothing calls.
BeanEngine.in_scope_nowand theBeanCore.in_scopebehind it were recorded as unused when the connections pagemoved its row highlight onto the stored
scopedrecord; the follow-up the entrypromised never came.
ScrollableFrame.yview_fraction,.set_yview_fractionandPortTable.agehave no caller anywhere and no mention in any document. Two commentsthat described the deleted path were corrected - they claimed the highlight asks the
engine live, which it has not done for two releases.
A complexity crowd count.
max-complexitywatches one function and is blind tothe drift the size ratchet grew a second knob for: the runners-up climbing together,
none of them a record. At a ceiling of 29,
cli._run_sessioncould reach 29 from 27with every gate green the whole way. Three functions are in the 70% band today and
the next one sits one branch below it.
PLR0913, and both rule lists held to each other. Argument count is the one
measurement on ruff's pylint-refactor list that nothing here already takes -
PLR0912 is C90 on the same function, PLR0915 is FUNCTION_CEILING measured worse
because the ratchet counts logic lines and leaves comments free, PLR0911 needs a
branch per return. Pinned to the widest signature that exists (14), not to ruff's
default of 5, which would be red on 25 signatures before catching anything.
--selecton the workflow command line replaces the list inpyproject.toml, so arule could be configured, visible to
ruff checklocally, and absent from the onlyrun that can block a merge. Both lists are recorded in the suite now, and a third
check refuses a rule that is neither blocking nor reported.
A nesting-depth ceiling. The axis
test_code_shape.pysaid out loud it did notmeasure. Nothing else can see it: ruff has no depth rule, the size ceiling is blind
to it, and complexity scores a flat chain of eight
elifexactly like eight nestedif. The band is absolute rather than a percentage - 70% of 5 lands on the sameline today, but at a ceiling of 4 it would mean "3 or more" and the count would jump
from 12 to 82.
A dead-code guard, resolved to a fixed point. A dead caller keeps its callee
looking alive, which is exactly how
BeanCore.in_scopestayed invisible. The scanreads an allow-list of trees and never walks the repository root, so it cannot reach
directories that exist on a maintainer machine and in no checkout - one that did
would call a name used locally and dead in CI.
Two things were wrong on the first attempt
Both were caught by measurement rather than review, and both are written down where
the next reader will hit them.
The depth metric walked an
ifbody without adding the level that body sits at, sofour nested blocks measured three. Its own test found it - which is why the three
metric tests went in before any constant was filled in. The first pinned band (3)
was the wrong measurement and became 12 once the metric was fixed.
The dead-code guard scanned its own file, where the exception list lives, so writing
a name into that list was a mention of itself and the scan reported it as used. The
guard disarmed itself in the act of recording an exception, and the two entries on
that list were exactly the names it would have stopped watching.
Two measured decisions worth knowing about
The dead-code scan counts every word, comments and strings included. Counting only
code tokens finds six more names and five of them are alive: four are called from
inside
run_gui("""...""")blocks - the GUI tests are Python source in a string, runin a subprocess, and the suite holds 204 of those calls - and one is reached through
getattr. A guard that accuses living code is a guard people switch off. The priceis named in the file: a definition whose name is an ordinary English word survives on
prose alone, which is how
PortTable.agehad to be found by hand.The three depth-metric tests are in
PROVEN_BY_HAND, notMUTATIONS. Any patch tothe metric moves the measurement of the whole package, so it reddens the two ratchet
tests pinned to it as well - measured, three tests red at once - and a registry entry
names one test.
Verification
ruff check --select F,B,C90,PLR0913 .clean,mypyclean over 66 modules.conventions, README, release, packaging): 97 passed.
smoke_gui.pyOK.tools/mutate.py --changedfor this branch: 29 entries, 29 caught, none survived.Six of those entries are new and each was run on its own as well.
it by name, and the file was restored byte for byte.
The full suite, the real-Tk render check, semgrep, diff-cover and the executable
build were deliberately left to this pull request - they need the platforms CI has.