Sdlc/RequireInsideCode: rename RequireInMethod, flag any require outside the top run, guard autocorrect #1367
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#1367
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
Sdlc/RequireInMethodhas three defects.require. When the require shares a line with other code, the correction deletes that code. A one-line method is deleted completely:def. Its intent is "a require anywhere except the top of the file". It misses requires in blocks, conditions,begin, class bodies, and top-level requires after other code.Move require ...for arequire_relativecall.Found by the #1325 zero-false-positive audit. Redesigned with Jared on 2026-10-26 (session fe2e7204, decision B).
Approach
Rename the cop to
Sdlc/RequireInsideCodeand replace its matcher with the value rule indocs/plans/class-length-family/smell-require-inside-code.md(commit0d602cf1). Fix by shape in the matcher. Never use a config Exclude list or a test-path exclusion.Value rule: a
require/require_relativecall is an offense when it is not in the file's top run. The top run is the top-level statements, from the start of the file, up to the first statement that is not a require.Carve-outs by shape (none by path):
ENV[...] =/||=,$LOAD_PATH/$:,$VERBOSE =, or a call whose receiver chain starts atWarning.Dir[...].each { |f| require f }, or a constant argument) is not an offense.begin ... rescue LoadError(an optional gem) is not an offense.Autocorrect only a stdlib
requirewith a string-literal argument that is alone on its line (stripped line text equals the node source). Move it into the top run once. For every other shape, report the offense and do not correct.The lint lesson exists at
plugins/os-sdlc/lint-lessons/sdlc-require-inside-code.yml(commit0d602cf1). Do not change it in this ticket.Required work:
.rubocop.ymlentry fromRequireInMethodtoRequireInsideCode. Update every reference in code and tests, including the tests that pin the old name by path:tests/**/fast_gate_sdlc_offense_test.rb:16,commands_sdlc_lint_base_commit_test.rb:20,relay_lesson_files_test.rb:10. Leave the TSV fixtures undertests/fixtures/crc_shares/run2/unchanged: they are historical ledger records of an earlier run.check: absent
RequireInMethodinplugins/os-sdlc/**/*.rb_test.rbfiles, so thatSdlc/Minitest/RequireInTestMethoddoes not report the same node.def x; require "y"; ...; end, a require in a block,require "x" if cond, a class-body require, a top-level require afterX = 1, a require between two top-level modules. Add must-pass fixtures: the top run, anENV[...] ||=line beforerequire "bundler/setup", a$LOAD_PATH.unshiftline before a require,Warning.singleton_class.prepend(...)beforerequire "rubocop",Dir[...].each { |f| require f }, a top-levelbegin require "x" rescue LoadError end.plugins/os-backlog/lib/backlog/shell_runner.rb:6plugins/os-me/hooks/cli_appender.rb:10,:16plugins/os-me/hooks/prediction_recorder.rb:51plugins/os-me/hooks/record_prediction.rb:12plugins/os-me/lib/os_me.rb:24plugins/os-sdlc/tests/all.rb:13Lint::Worklist::CopPhase(plugins/os-sdlc/lib/os_sdlc/lint/worklist/cop_phase.rb) to the iterative phase (ITERATIVE_EXTRA_COPS), because most of its offenses need judgment, so that/os-sdlc:fix-lintsreaches it with its lesson.check: present
Sdlc/RequireInsideCodeinplugins/os-sdlc/lib/os_sdlc/lint/worklist/cop_phase.rbOwner sketch
RuboCop::Cop::Sdlc::RequireInsideCode(the renamed cop) iterates the file's require calls, asks each whether it is an offense, reports it, and autocorrects only when the call allows it.RequireInsideCode::TopRun(new) owns the file-level fact: which top-level statements form the top run, including the rule that a load-time-state statement (ENV,$LOAD_PATH/$:,$VERBOSE, aWarningcall) does not end the run for the requires after it.RequireInsideCode::Call(the existingRequireInMethod::Call, renamed) owns the per-call facts: the method name for the message, a literal or non-literal argument, stdlib or not, inside a top-levelbegin ... rescue LoadError, and alone on its source line.Acceptance criteria
defwhose body holds a stdlibrequire, when the cop autocorrects, then the method still exists and the source is unchanged.requirealone on its line inside a method, when the cop autocorrects, then the call moves to the top run and the method body keeps its other lines.require_relativeoutside the top run, when the cop reports it, then the message namesrequire_relative.rubocop -c plugins/os-sdlc/.rubocop.yml --only Sdlc/RequireInsideCode plugins/ bin/runs, then it reports 0 offenses. The cop stays enabled only through the os-sdlc config, as today.Sdlc/RequireInsideCode, whenLint::Worklist::CopPhasecomputes its phase, then it returns:iterative, andLesson::Catalogfinds the lessonsdlc-require-inside-code.ymlfor that key.Sdlc/RequireInMethod: autocorrect deletes one-line methods; skip LoadError probes; name require_relativeto Sdlc/RequireInsideCode: rename RequireInMethod, flag any require outside the top run, guard autocorrectWork started on branch ticket-1367 via /os-sdlc:implement (map poodr-ticket-implementation).
Resolution
Done: Renamed Sdlc/RequireInMethod to Sdlc/RequireInsideCode. It flags any require outside the file's top run, exempts non-literal arguments and top-level rescue LoadError probes, keeps requires after ENV/$LOAD_PATH/$VERBOSE/Warning setup in the top run, autocorrects only a stdlib require alone on its line, names require_relative in its message, and is routed to the iterative fix-lints phase. Lesson lint-lessons/sdlc-require-inside-code.yml and smell analysis committed. Fixed the 7 repo hits.
Evidence: Implementation 167 complete (12 dispatches, 1 reroute after a ticket-defect escalation); commits
0d602cf1,0a934307,5de58339on main. Suite gate green; os-me 392 runs and os-backlog 327 runs green; rubocop --only Sdlc/RequireInsideCode over plugins/ and bin/: 2536 files, no offenses.Follow-ups: #1393 (Zeitwerk loader for cops/, captured with skeptic verdict CREATE). Dropped: os_me.rb requiring a hooks/ file is a placement note, not a defect.
jared referenced this issue2026-10-26 15:08:34 +00:00