os-sdlc: move Metrics/ClassLength and Metrics/ModuleLength to the sweep tier with zero Excludes, drain, promote #1317
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#1317
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
plugins/os-sdlc/.rubocop.ymlexcludes every test directory fromMetrics/ClassLengthand does not enableMetrics/ModuleLength. The exclusion is a file list, and a file list is a baseline: it hides new offenses in test classes and rots as files move. The missing module cop leaves open the cheapest wrong fix for a long class: move the method bodies into a module that only that class includes. Session 345203e9 took that path in os-backlog, and the gate passed. The rulings "code is code; no test-file Exclude without shown degradation" and "no cop Exclude lists" both apply.Observed
A probe on 2026-10-25 ran rubocop over
plugins/os-sdlcwithMetrics/ClassLength: Exclude: []andMetrics/ModuleLength: Max: 100.53
Metrics/ClassLengthhits, all in test classes, none in lib. The six largest test classes count 536, 504, 364, 353, 331, and 324 lines.4
Metrics/ModuleLengthhits, all in lib:Reproduce
Approach
Register both cops in the sweep tier with zero Excludes, drain the hits in batches through the fast path, then promote both cops to the gate and delete the Exclude list. The lesson
plugins/os-sdlc/lint-lessons/metrics-class-length.yml(commita830d451) gives the correction for the four modules: count a single-includer module with its class, build each repeated collaborator once, give the repeated shape one owner. The test classes follow theMetrics/AbcSizelesson shape: one helper that returns the result, one test per outcome, and a split by fixture family when one class still holds two subjects.Required work:
Metrics/ClassLengthwithExclude: []andMetrics/ModuleLengthwithMax: 100registered in the sweep config — check: presentMetrics/ModuleLengthinplugins/os-sdlc/.rubocop-sweep.ymlMetrics/ModuleLengthat 100 through/os-sdlc:fast-batch, one finding each.Metrics/ClassLengthat 100, in fast-batch rounds of about eight files, largest first.Exclude:list removed — check: absent../*/tests/**/*inplugins/os-sdlc/.rubocop.ymlMetrics/ModuleLengthenabled inplugins/os-sdlc/templates/rubocop-base.ymlat the sameMaxasMetrics/ClassLengththere — check: presentMetrics/ModuleLengthinplugins/os-sdlc/templates/rubocop-base.ymlOrchestrator work: open one fast-batch per round; record each round in the "What runs measured" table of
docs/sdlc-fast-path.md.Rejected: keep the test Exclude because tests are long by nature — rejected by the 2026-10-15 ruling; a long test class is an Eager Test or two subjects in one file, and both corrections make the test better.
Rejected: a custom cop that sums a class with its single-includer modules — not needed until the stock module cop fails to catch a case.
Acceptance criteria
bin/lint-sweepruns, then it reportsMetrics/ClassLengthandMetrics/ModuleLengthcounts with no Exclude entries.plugins/os-sdlc, when rubocop runs with the gate config, thenMetrics/ClassLengthandMetrics/ModuleLengthboth report zero offenses in lib and tests.plugins/os-sdlc/.rubocop.yml, when read, thenMetrics/ClassLengthhas noExclude:key.Non-goals
The os-backlog side:
cli_command_wiring.rbandforgejo_backend.rbare in fast-batch-14, andplugins/os-backlog/.rubocop.ymlalready enablesMetrics/ModuleLength(commita830d451). The two long os-backlog test classes (tests/checkout_test.rb145,tests/close_protocol_test.rb161) are not covered by this ticket; os-backlog has no sweep tier.Origin
/os-sdlc:smell-analysis Metrics/ClassLengthafter session 345203e9 hit the cop onplugins/os-backlog/lib/backlog/cli.rb[108/100] with no lessoncli_command_wiring.rbto pass the class copMetrics/ModuleLengthnot enabled,DisabledByDefault: trueinplugins/os-backlog/.rubocop.yml(source: the file) ← os-sdlc's own config excludes tests from ClassLength and has no ModuleLength (source:plugins/os-sdlc/.rubocop.yml:70-79) ← DESIGN: no ADR covers the metrics cops;/os-adr:findon 2026-10-25 found ADR-0082 (layered config, informs only) and ADR-0066 (base plus delta, informs only)plugins/os-sdlc/.rubocop.ymlMetrics/ClassLengthExclude:list, lines 70-79Sweep-tier counts for the five plugins that never ran under the Sdlc cops (HANDOFF.md:47, after #1319). Main SHA swept:
9c348bb3(full9c348bb3e2). No autocorrect.Command, run from the repo root, once per plugin path:
.sdlc/project.yamlnames these targetsos-backlog,os,os-adr,os-aidd-lint,os-me; each haspath: plugins/<name>. Onlyos-backlogsetslint_config; the other four have nolint_configtarget key, so the root.rubocop.ymlapplies. The path was passed directly.Cop names are
Sdlc/Structural/*exceptSdlc/Dry/RepeatedPathLiteral.Metrics/ClassLength: 0 in all five (not measured). Metrics/ModuleLength: 0 in all five (not measured).
lint-sweepruns only the cops listed inplugins/os-sdlc/.rubocop-sweep.yml, and that file has no Metrics entry yet (required work item 1 of this ticket). So the stock-cop column is 0 by construction, not by a clean result. After item 1 lands, re-run to get real Metrics counts.Sweep-tier recount after #1367 (RequireInMethod renamed to RequireInsideCode). Counted at main
63bc2ae83b(63bc2ae8). It is5de58339(includes #1367) plus one docs/lesson commit (#1367 lesson wording, 3 files). No autocorrect.Command, from the repo root, once per plugin path (same as the 2026-10-25 count):
Counts come from the emacs-style offense lines in the output, grouped by cop; files are distinct paths per cop. The sweep tier is the 8 cops in
plugins/os-sdlc/.rubocop-sweep.yml.Total: 277 offenses in 662 files (192 + 60 + 68 + 131 + 211). Same as the earlier 277; per-cop counts also match (163 / 81 / 31 / 1 / 1).
Cops in the sweep tier with zero offenses: Sdlc/Structural/InwardDependency (FP #1366), Sdlc/Structural/UnlayeredConstant (FP #1359), Sdlc/Structural/EffectInModel (FP #1351).
Notes:
Sdlc/RequireInsideCodeis not in the sweep config, so it is not counted (its ticket is #1367, closed).Metrics/ClassLengthandMetrics/ModuleLengthare still not in the sweep config (required work item 1), so they are not measured.