lint rule: cross-file structural duplication via flay #200
Labels
No labels
P0
P1
P2
P3
bug
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
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#200
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?
Migrated from jared/os-sdlc#12 (repo retired).
lint rule: cross-file structural duplication via flay
Problem
RuboCop cops (including Sdlc/Dry/DuplicatedStatementSequence) operate on one
file's AST at a time (RuboCop::Cop::Base#on_new_investigation runs per source
file) -- they structurally cannot catch duplicate logic that lives in two
different files. The original example (identical
overlaps?inac_coverage_lint.rb and a since-removed lint/spec_ticket_coverage.rb) no
longer exists verbatim -- that specific pair was consolidated -- but the gap
it illustrated is still real and still generalizable: no current lint step
catches near-identical methods/blocks duplicated across separate files.
Detection
flay(already a project dependency,gem list flay->2.14.4) over lib/; fail if any reported duplicate-mass pair exceeds a
chosen threshold. This is a standalone flay-based check, not a rubocop cop
(out of scope for rubocop's single-file model) -- wire it as its own
script/rake task alongside the existing custom lint/ tools
(ac_coverage_lint.rb is the precedent for a standalone advisory lint in
this plugin).
the two file:method locations and the shared statement text.
Correction
Extract the shared logic into one module/method both call.
Pass/fail examples
chosen threshold between two distinct files.
Scope note
The original namespace/layout complaint (OsSdlc::AcCoverageLint file location
vs OsSdlc::Lint::SpecTicketCoverage) is dropped from this ticket -- it was
tied to a file pairing that no longer exists, and was a one-off convention
gripe rather than a generalizable rule. If a
*Lintnaming/locationconvention is wanted, file that separately once there are enough live
examples to generalize from.
Provenance
Fable finding 2, severity should-fix. Council review of run #5 (ticket #5,
artifact .sdlc/5.md), 2026-07-20. Reassessed and narrowed 2026-08-01 during
os-sdlc sandbox retirement triage.
Implementation plan
Threshold value and wiring (rake task vs CI step vs pipeline lint stage) are
open implementation decisions -- not fully specified.
Recommendation for maintainer: flay defaults to reporting all pairs; add a --minimum (mass) threshold rather than "any duplicate mass". Flay convention treats mass ~20 as noise, ~40+ as worth extracting. Recommend a conservative default of --minimum 40, tunable later via .flay.yml or a rake arg. Wire as rake lint:flay (a lint/flay_lint.rb script alongside ac_coverage_lint.rb) run in the same lint stage as rubocop, not folded into RuboCop itself (cross-file, out of its per-file model). This fully specifies detection + wiring; no open maintainer decision remains.
Implemented via os-sdlc pipeline (2 review rounds, APPROVE). OsSdlc::FlayCheck, threshold 40, findings quote shared source. Merged to main in
4e32fbc. Note: overlaps with the older human-invoked bin/dup-sweep; consolidation left for human review.