Sdlc/Structural/MutableCollectionLeakViaAttrReader: restrict to dup-safe flat collections #1373

Open
opened 2026-10-25 21:23:25 +00:00 by jared · 0 comments
Owner

Problem

Sdlc/Structural/MutableCollectionLeakViaAttrReader accepts any Const.new(...) as a collection, and its dup prescription fails for non-collections and for nested collections.
Shape: a public attr whose ivar is assigned [], {} or any Const.new and receives a mutating send in a def.

Observed

12 hits, all test fakes or eval checkers.
Sample code that fires:

class Producer
  attr_reader :queue

  def initialize
    @queue = Queue.new
  end

  def produce(job)
    @queue << job
  end
end

class Grouper
  attr_reader :groups

  def initialize
    @groups = {}
  end

  def add(key, value)
    (@groups[key] ||= []).push(value)
    @groups[key] = @groups[key]
  end
end

Queue#dup raises NoMethodError, and the shared reference is the API.
Shallow dup of a hash of arrays still leaks the inner arrays.

Reproduce

Run the cop on the sample above.

Approach

Required work:

  1. Accept only [], {}, Array.new, Hash.new, Set.new as collection values, not any Const.new (collection_value.rb:11).
  2. For ivars whose elements are themselves mutated collections (@h[k] << v, (@h[k] ||= []).push), prescribe a deep copy or an owner method, not dup.

Carve-outs go in the cop matcher. Do not add config Exclude lists or test-path exclusions.

Found by the #1325 zero-false-positive audit (docs/plans/class-length-family/sdlc-cop-audit.md)

Origin

  • Trigger: #1325 zero-false-positive audit of the Sdlc cops
  • Improvised this session: none
  • Chain: false positive on valid code ← cop matcher tests a proxy shape, not the real condition ← DESIGN (cop source named in Where:)
  • Root candidate: none found; searched the cop name, its mechanism terms, and false positive
  • Where: plugins/os-sdlc/lib/os_sdlc/cops/mutable_collection_leak_via_attr_reader.rb:16-18, :49-52 (collection_value.rb:11, ivar_mutation.rb:34-38)
  • Session: eb98cdcd-6783-46a0-b7df-cf18a8fe2a56
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-1325/eb98cdcd-6783-46a0-b7df-cf18a8fe2a56.jsonl

VERDICT: CREATE

## Problem Sdlc/Structural/MutableCollectionLeakViaAttrReader accepts any `Const.new(...)` as a collection, and its `dup` prescription fails for non-collections and for nested collections. Shape: a public attr whose ivar is assigned `[]`, `{}` or any `Const.new` and receives a mutating send in a def. ## Observed 12 hits, all test fakes or eval checkers. Sample code that fires: ```ruby class Producer attr_reader :queue def initialize @queue = Queue.new end def produce(job) @queue << job end end class Grouper attr_reader :groups def initialize @groups = {} end def add(key, value) (@groups[key] ||= []).push(value) @groups[key] = @groups[key] end end ``` `Queue#dup` raises NoMethodError, and the shared reference is the API. Shallow `dup` of a hash of arrays still leaks the inner arrays. ## Reproduce Run the cop on the sample above. ## Approach Required work: 1. Accept only `[]`, `{}`, `Array.new`, `Hash.new`, `Set.new` as collection values, not any `Const.new` (collection_value.rb:11). 2. For ivars whose elements are themselves mutated collections (`@h[k] << v`, `(@h[k] ||= []).push`), prescribe a deep copy or an owner method, not `dup`. Carve-outs go in the cop matcher. Do not add config Exclude lists or test-path exclusions. Found by the #1325 zero-false-positive audit (docs/plans/class-length-family/sdlc-cop-audit.md) ## Origin - Trigger: #1325 zero-false-positive audit of the Sdlc cops - Improvised this session: none - Chain: false positive on valid code ← cop matcher tests a proxy shape, not the real condition ← DESIGN (cop source named in Where:) - Root candidate: none found; searched the cop name, its mechanism terms, and false positive - Where: plugins/os-sdlc/lib/os_sdlc/cops/mutable_collection_leak_via_attr_reader.rb:16-18, :49-52 (collection_value.rb:11, ivar_mutation.rb:34-38) - Session: eb98cdcd-6783-46a0-b7df-cf18a8fe2a56 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-1325/eb98cdcd-6783-46a0-b7df-cf18a8fe2a56.jsonl VERDICT: CREATE
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#1373
No description provided.