Fix ParameterThreadedThroughPrivateMethods crash on destructured parameters #1102

Open
opened 2026-10-18 14:53:37 +00:00 by jared · 4 comments
Owner

Problem

The cop Sdlc/Structural/ParameterThreadedThroughPrivateMethods crashes on a destructured parameter.
A crash hides all other offenses of this cop in the file, and RuboCop still prints "no offenses detected".
(The ticket first named two cops. BooleanControlParameter no longer crashes; see the comment "Correction 2026-11-12".)

Observed

Run in plugins/os-sdlc on main on 2026-11-12:

bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb
An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting .../lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10.

With -d, the cause is undefined method 'name' for an instance of RuboCop::AST::MlhsNode at lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35 (def_node.arguments.each { |arg| tally[arg.name.to_s] << def_node }).
The trigger is def locate(scope, (segment, *rest)) at lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:35.

Reproduce

cd plugins/os-sdlc && bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb

Approach

Make the cop skip or handle mlhs parameters.

Required work:

  1. Handle mlhs parameters in Sdlc/Structural/ParameterThreadedThroughPrivateMethods.

Acceptance criteria

  1. Given a private method with a destructured parameter, when rubocop runs the cop, then the cop does not raise.

Earlier false-positive shapes of BooleanControlParameter (not re-checked)

These came from the #1325 audit. Not re-checked on 2026-11-12.
The cited site plugins/os-adr/lib/adr/record/matches.rb reports no offense of this cop now.

  1. A data-driven filter flag used only in an iteration condition (for example all_statuses). A split moves the branch to the caller.
  2. The message suggests _without_ for a false default; m_with_<param> fits.

Origin

  • Trigger: Follow-up from #1094 (implementation 63, hand-finish commit 17d4c688), session 6f78b932-f117-4bd7-bbed-524776dbb719.
  • Improvised this session: none
  • Chain: cop crash <- cop assumes every arg node responds to name <- mlhs arg node has no such method
  • Where: plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb
  • Session: 6f78b932-f117-4bd7-bbed-524776dbb719
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/6f78b932-f117-4bd7-bbed-524776dbb719.jsonl
## Problem The cop `Sdlc/Structural/ParameterThreadedThroughPrivateMethods` crashes on a destructured parameter. A crash hides all other offenses of this cop in the file, and RuboCop still prints "no offenses detected". (The ticket first named two cops. `BooleanControlParameter` no longer crashes; see the comment "Correction 2026-11-12".) ## Observed Run in `plugins/os-sdlc` on `main` on 2026-11-12: ``` bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb ``` ``` An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting .../lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10. ``` With `-d`, the cause is `undefined method 'name' for an instance of RuboCop::AST::MlhsNode` at `lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35` (`def_node.arguments.each { |arg| tally[arg.name.to_s] << def_node }`). The trigger is `def locate(scope, (segment, *rest))` at `lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:35`. ## Reproduce ``` cd plugins/os-sdlc && bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb ``` ## Approach Make the cop skip or handle `mlhs` parameters. Required work: 1. Handle `mlhs` parameters in `Sdlc/Structural/ParameterThreadedThroughPrivateMethods`. ## Acceptance criteria 1. Given a private method with a destructured parameter, when rubocop runs the cop, then the cop does not raise. ## Earlier false-positive shapes of `BooleanControlParameter` (not re-checked) These came from the #1325 audit. Not re-checked on 2026-11-12. The cited site `plugins/os-adr/lib/adr/record/matches.rb` reports no offense of this cop now. 1. A data-driven filter flag used only in an iteration condition (for example `all_statuses`). A split moves the branch to the caller. 2. The message suggests `_without_` for a false default; `m_with_<param>` fits. ## Origin - Trigger: Follow-up from #1094 (implementation 63, hand-finish commit 17d4c688), session 6f78b932-f117-4bd7-bbed-524776dbb719. - Improvised this session: none - Chain: cop crash <- cop assumes every arg node responds to name <- mlhs arg node has no such method - Where: plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb - Session: 6f78b932-f117-4bd7-bbed-524776dbb719 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/6f78b932-f117-4bd7-bbed-524776dbb719.jsonl
Author
Owner

Occurrence: Make two Sdlc cops handle destructured parameters instead of crashing
Seen: plugins/os-sdlc/lib/os_sdlc/cops/boolean_control_parameter/def_site.rb:29 (MlhsNode has no default_value), on collaborator_pass/subcommand.rb 7:4 and 46:6
Run: Session acb1c3d0-87bc-425e-ac2b-413f0a7b6f32, after merging #1118 and #1119 (main 5890a574)
Adds: Still present on main 5890a574. rubocop exits 0 with 'no offenses detected' despite both crashes, so the lint gate passes and hides any offense of these cops in the file.

Occurrence: Make two Sdlc cops handle destructured parameters instead of crashing Seen: plugins/os-sdlc/lib/os_sdlc/cops/boolean_control_parameter/def_site.rb:29 (MlhsNode has no default_value), on collaborator_pass/subcommand.rb 7:4 and 46:6 Run: Session acb1c3d0-87bc-425e-ac2b-413f0a7b6f32, after merging #1118 and #1119 (main 5890a574) Adds: Still present on main 5890a574. rubocop exits 0 with 'no offenses detected' despite both crashes, so the lint gate passes and hides any offense of these cops in the file.
Author
Owner

Occurrence: Sdlc/Structural/BooleanControlParameter: fix mlhs crash; carve out data-driven filter flags; correct split name
Seen: plugins/os-sdlc/lib/os_sdlc/cops/boolean_control_parameter/def_site.rb (NoMethodError on MlhsNode at plugins/os-sdlc/lib/os_sdlc/collaborator_pass/subcommand.rb:46)
Run: eb98cdcd-6783-46a0-b7df-cf18a8fe2a56 (#1325 zero-false-positive audit, docs/plans/class-length-family/sdlc-cop-audit.md)
Adds: two more false-positive shapes: a data-driven filter flag used only in an iteration condition (plugins/os-adr/lib/adr/record/matches.rb:13 all_statuses, fed from plugins/os-adr/bin/adr-find:26), where a split moves the branch to the caller; and the message suggests without for a false default, where m_with_ fits. Carve-outs belong in the cop matcher, not config Exclude lists.

Occurrence: Sdlc/Structural/BooleanControlParameter: fix mlhs crash; carve out data-driven filter flags; correct split name Seen: plugins/os-sdlc/lib/os_sdlc/cops/boolean_control_parameter/def_site.rb (NoMethodError on MlhsNode at plugins/os-sdlc/lib/os_sdlc/collaborator_pass/subcommand.rb:46) Run: eb98cdcd-6783-46a0-b7df-cf18a8fe2a56 (#1325 zero-false-positive audit, docs/plans/class-length-family/sdlc-cop-audit.md) Adds: two more false-positive shapes: a data-driven filter flag used only in an iteration condition (plugins/os-adr/lib/adr/record/matches.rb:13 all_statuses, fed from plugins/os-adr/bin/adr-find:26), where a split moves the branch to the caller; and the message suggests _without_ for a false default, where m_with_<param> fits. Carve-outs belong in the cop matcher, not config Exclude lists.
Author
Owner

Occurrence: Fix ParameterThreadedThroughPrivateMethods crash on destructured parameter
Seen: plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35
Run: Session a48658d5-b566-40ce-8257-ebeabf56f7e1
Adds: a second trigger file: plugins/os-sdlc/lib/os_sdlc/simulated_polymorphism/owned_type.rb, def locate(scope, (segment, *rest)). Detail follows.

Observed

Run in plugins/os-sdlc on main (commit 031244657):

bundle exec rubocop lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods
An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10.

With -d, the cause is:

lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35:in 'block (2 levels) in RuboCop::Cop::Sdlc::Structural::ParameterThreadedThroughPrivateMethods#build_tally': undefined method 'name' for an instance of RuboCop::AST::MlhsNode

The line is def_node.arguments.each { |arg| tally[arg.name.to_s] << def_node }.
The trigger is the private method def locate(scope, (segment, *rest)) in owned_type.rb (a destructured parameter).
RuboCop prints "1 file inspected, no offenses detected" after the error, so the file looks clean.
The session path lib/os_sdlc/simulated_polymorphism/owned_type.rb does not exist; the file is under lib/os_sdlc/cops/structural/simulated_polymorphism/.

Reproduce

cd plugins/os-sdlc && bundle exec rubocop lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods

Approach

In build_tally, skip an MlhsNode argument, or tally the names inside it.
Add a test with a private method that takes a destructured parameter in plugins/os-sdlc/test/cops/parameter_threaded_through_private_methods_test.rb.
Merge this into #1102 if its fix covers def parameters of the same cop.

Required work:

  1. Handle mlhs arguments in build_tally — check: present mlhs in plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb

Acceptance criteria

  1. Given a class with a private method def locate(scope, (segment, *rest)), when the cop runs, then it raises no error.
  2. Given a file that has both a destructured parameter and a parameter threaded through three private methods, when the cop runs, then it reports the threaded parameter.

Owner sketch

class RuboCop::Cop::Sdlc::Structural::ParameterThreadedThroughPrivateMethods
  def build_tally(private_defs)
end
Occurrence: Fix ParameterThreadedThroughPrivateMethods crash on destructured parameter Seen: plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35 Run: Session a48658d5-b566-40ce-8257-ebeabf56f7e1 Adds: a second trigger file: `plugins/os-sdlc/lib/os_sdlc/simulated_polymorphism/owned_type.rb`, `def locate(scope, (segment, *rest))`. Detail follows. ## Observed Run in `plugins/os-sdlc` on `main` (commit `031244657`): ``` bundle exec rubocop lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods ``` ``` An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10. ``` With `-d`, the cause is: ``` lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35:in 'block (2 levels) in RuboCop::Cop::Sdlc::Structural::ParameterThreadedThroughPrivateMethods#build_tally': undefined method 'name' for an instance of RuboCop::AST::MlhsNode ``` The line is `def_node.arguments.each { |arg| tally[arg.name.to_s] << def_node }`. The trigger is the private method `def locate(scope, (segment, *rest))` in `owned_type.rb` (a destructured parameter). RuboCop prints "1 file inspected, no offenses detected" after the error, so the file looks clean. The session path `lib/os_sdlc/simulated_polymorphism/owned_type.rb` does not exist; the file is under `lib/os_sdlc/cops/structural/simulated_polymorphism/`. ## Reproduce ``` cd plugins/os-sdlc && bundle exec rubocop lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods ``` ## Approach In `build_tally`, skip an `MlhsNode` argument, or tally the names inside it. Add a test with a private method that takes a destructured parameter in `plugins/os-sdlc/test/cops/parameter_threaded_through_private_methods_test.rb`. Merge this into #1102 if its fix covers `def` parameters of the same cop. Required work: 1. Handle `mlhs` arguments in `build_tally` — check: present `mlhs` in `plugins/os-sdlc/lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb` ## Acceptance criteria 1. Given a class with a private method `def locate(scope, (segment, *rest))`, when the cop runs, then it raises no error. 2. Given a file that has both a destructured parameter and a parameter threaded through three private methods, when the cop runs, then it reports the threaded parameter. ## Owner sketch ```ruby class RuboCop::Cop::Sdlc::Structural::ParameterThreadedThroughPrivateMethods def build_tally(private_defs) end ```
jared changed title from Fix two Sdlc cops crashing on destructured parameters to Fix ParameterThreadedThroughPrivateMethods crash on destructured parameters 2026-11-12 17:51:58 +00:00
Author
Owner

Correction 2026-11-12

Facts checked on main on 2026-11-12:

  • BooleanControlParameter no longer crashes on a destructured parameter. Commit 055bb6166 fixed it. The test test/cops/boolean_control_parameter_test.rb:31 pins it.
  • lib/os_sdlc/collaborator_pass/subcommand.rb no longer exists.
  • Sdlc/Structural/ParameterThreadedThroughPrivateMethods still crashes on a destructured parameter. The cause is lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35. The trigger is lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:35.
  • Reproduce: bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb in plugins/os-sdlc. The error line is An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting .../lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10.

This ticket now concerns that one cop. I rewrote the title and body to match.

Correction 2026-11-12 Facts checked on `main` on 2026-11-12: - `BooleanControlParameter` no longer crashes on a destructured parameter. Commit 055bb6166 fixed it. The test `test/cops/boolean_control_parameter_test.rb:31` pins it. - `lib/os_sdlc/collaborator_pass/subcommand.rb` no longer exists. - `Sdlc/Structural/ParameterThreadedThroughPrivateMethods` still crashes on a destructured parameter. The cause is `lib/os_sdlc/cops/structural/parameter_threaded_through_private_methods.rb:35`. The trigger is `lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:35`. - Reproduce: `bundle exec rubocop --only Sdlc/Structural/ParameterThreadedThroughPrivateMethods lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb` in `plugins/os-sdlc`. The error line is `An error occurred while Sdlc/Structural/ParameterThreadedThroughPrivateMethods cop was inspecting .../lib/os_sdlc/cops/structural/simulated_polymorphism/owned_type.rb:8:10.` This ticket now concerns that one cop. I rewrote the title and body to match.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1102
No description provided.