Sdlc/Structural/UnreadInstanceVariable: skip base-class ivars that subclasses read and fix the prescription #1377

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

Problem

Sdlc/Structural/UnreadInstanceVariable flags an ivar in a base class that a subclass reads. The existing subclass skip (:18) does not cover the superclass. The message also prescribes "delete the assignment and its parameter", which breaks code when something else reads the parameter.

Observed

Shape: a RecordingCop subclass (unread_instance_variable.rb:14) whose message prescribes a fix. For a class without a superclass, or a module, whose body assigns an ivar that no read, attr_reader, or delegator names (unread_assignments.rb). Registered at .rubocop.yml:385. It reports 9 hits.

Counterexamples:

  • Base class whose subclass reads the ivar: plugins/os-me/lib/os_me/lever_check.rb:10 (read in lever_check/source.rb:12).
  • plugins/os-vault/eval/bin/check:298 (read at :312).
  • Wrong fix: plugins/os-aidd-lint/lib/aidd_lint/tier2/judge.rb:15. @config is unread, but the parameter config is read at :17, so deleting the parameter breaks the method.

Sample code:

class Base
  def initialize(client)
    @client = client
  end
end

class Child < Base
  def call = @client.ask
end

Reproduce

bundle exec rubocop --only Sdlc/Structural/UnreadInstanceVariable plugins/os-me/lib/os_me/lever_check.rb

Approach

Fix by shape, in the cop matcher. Skip a class with no superclass when the codebase has a subclass that reads the ivar, or record without a fix. Change the message to "delete the parameter only if nothing else reads it". Do not add a config Exclude list or a test-path exclusion.

Required work:

  1. Reword the message to "delete the parameter only if nothing else reads it" — check: present only if nothing else reads it in plugins/os-sdlc/lib/os_sdlc/cops/unread_instance_variable.rb

Acceptance criteria

  1. Given a base class that assigns @client and a subclass in the same file that reads @client, when the cop runs, then it reports no offense.
  2. Given a class that assigns an ivar that nothing reads, when the cop runs, then it still reports an offense.
  3. Given an offense, when the message prints, then it tells the author to delete the parameter only if nothing else reads it.

Owner sketch

class OsSdlc::Cops::UnreadInstanceVariable
end

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

VERDICT: CREATE

Origin

  • Trigger: #1325 zero-false-positive audit of every Sdlc cop.
  • Improvised this session: none
  • Chain: false positive on base-class ivars and an unsafe fix message ← subclass skip covers subclasses only ← DESIGN (unread_instance_variable.rb:18)
  • Root candidate: none found; searched UnreadInstanceVariable, unread_instance_variable, unread, ivar, instance variable
  • Where: plugins/os-sdlc/lib/os_sdlc/cops/unread_instance_variable.rb
  • 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
## Problem `Sdlc/Structural/UnreadInstanceVariable` flags an ivar in a base class that a subclass reads. The existing subclass skip (`:18`) does not cover the superclass. The message also prescribes "delete the assignment and its parameter", which breaks code when something else reads the parameter. ## Observed Shape: a RecordingCop subclass (`unread_instance_variable.rb:14`) whose message prescribes a fix. For a class without a superclass, or a module, whose body assigns an ivar that no read, `attr_reader`, or delegator names (`unread_assignments.rb`). Registered at `.rubocop.yml:385`. It reports 9 hits. Counterexamples: - Base class whose subclass reads the ivar: `plugins/os-me/lib/os_me/lever_check.rb:10` (read in `lever_check/source.rb:12`). - `plugins/os-vault/eval/bin/check:298` (read at `:312`). - Wrong fix: `plugins/os-aidd-lint/lib/aidd_lint/tier2/judge.rb:15`. `@config` is unread, but the parameter `config` is read at `:17`, so deleting the parameter breaks the method. Sample code: ```ruby class Base def initialize(client) @client = client end end class Child < Base def call = @client.ask end ``` ## Reproduce ``` bundle exec rubocop --only Sdlc/Structural/UnreadInstanceVariable plugins/os-me/lib/os_me/lever_check.rb ``` ## Approach Fix by shape, in the cop matcher. Skip a class with no superclass when the codebase has a subclass that reads the ivar, or record without a fix. Change the message to "delete the parameter only if nothing else reads it". Do not add a config Exclude list or a test-path exclusion. Required work: 1. Reword the message to "delete the parameter only if nothing else reads it" — check: present `only if nothing else reads it` in `plugins/os-sdlc/lib/os_sdlc/cops/unread_instance_variable.rb` ## Acceptance criteria 1. Given a base class that assigns `@client` and a subclass in the same file that reads `@client`, when the cop runs, then it reports no offense. 2. Given a class that assigns an ivar that nothing reads, when the cop runs, then it still reports an offense. 3. Given an offense, when the message prints, then it tells the author to delete the parameter only if nothing else reads it. ## Owner sketch ```ruby class OsSdlc::Cops::UnreadInstanceVariable end ``` Found by the #1325 zero-false-positive audit (docs/plans/class-length-family/sdlc-cop-audit.md). VERDICT: CREATE ## Origin - Trigger: #1325 zero-false-positive audit of every Sdlc cop. - Improvised this session: none - Chain: false positive on base-class ivars and an unsafe fix message ← subclass skip covers subclasses only ← DESIGN (`unread_instance_variable.rb:18`) - Root candidate: none found; searched UnreadInstanceVariable, unread_instance_variable, unread, ivar, instance variable - Where: plugins/os-sdlc/lib/os_sdlc/cops/unread_instance_variable.rb - 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
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#1377
No description provided.