Sdlc/Sequel/RowIndexOnModel: match receiver origin, not name regex or test-path globs #1383

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

Problem

Sdlc/Sequel/RowIndexOnModel flags x[:sym] by receiver name (row, record, ...). When the receiver is a Hash, the prescribed fix row.number raises NoMethodError. The cop also skips test paths by glob (DEFAULT_ALLOWED_PATHS, row_index_on_model.rb:16) instead of by shape.

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

Observed

Counterexample 1: plugins/os-backlog/bin/wakeup-poll:37-38. The row is a Hash, because open_issues returns Hashes (plugins/os-backlog/lib/backlog/forgejo_backend.rb:38).

Counterexample 2: a naked-dataset row is a Hash.

class Store
  def titles(db)
    db[:handoffs].all.map { |row| row[:title] }
  end
end

Reproduce

n/a: run rubocop --only Sdlc/Sequel/RowIndexOnModel on the snippet above.

Approach

Fix by shape. Put the carve-out in the cop matcher, never in a config Exclude list or a test-path exclusion.

Required work:

  1. Flag only when the receiver comes from a Sequel model source: a model class query, an association reader, or a Model#... call. Do not match by name.
  2. Remove the DEFAULT_ALLOWED_PATHS test globs.

Acceptance criteria

  1. Given db[:handoffs].all.map { |row| row[:title] }, when the cop runs, then it reports no offense.
  2. Given Handoff.where(x: 1).map { |row| row[:title] }, when the cop runs, then it reports an offense.

Origin

  • Trigger: the #1325 zero-false-positive audit of the Sdlc cops (docs/plans/class-length-family/sdlc-cop-audit.md)
  • Improvised this session: none
  • Chain: false positive ← matcher keys on the receiver name ← DESIGN (plugins/os-sdlc/lib/os_sdlc/cops/row_index_on_model.rb:14,23)
  • Root candidate: none found; searched RowIndexOnModel, row index, row_index_on_model, DEFAULT_ALLOWED_PATHS
  • Where: plugins/os-sdlc/lib/os_sdlc/cops/row_index_on_model.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

VERDICT: CREATE

## Problem `Sdlc/Sequel/RowIndexOnModel` flags `x[:sym]` by receiver name (`row`, `record`, ...). When the receiver is a Hash, the prescribed fix `row.number` raises `NoMethodError`. The cop also skips test paths by glob (`DEFAULT_ALLOWED_PATHS`, row_index_on_model.rb:16) instead of by shape. Found by the #1325 zero-false-positive audit (docs/plans/class-length-family/sdlc-cop-audit.md). ## Observed Counterexample 1: `plugins/os-backlog/bin/wakeup-poll:37-38`. The `row` is a Hash, because `open_issues` returns Hashes (plugins/os-backlog/lib/backlog/forgejo_backend.rb:38). Counterexample 2: a naked-dataset row is a Hash. ```ruby class Store def titles(db) db[:handoffs].all.map { |row| row[:title] } end end ``` ## Reproduce n/a: run `rubocop --only Sdlc/Sequel/RowIndexOnModel` on the snippet above. ## Approach Fix by shape. Put the carve-out in the cop matcher, never in a config Exclude list or a test-path exclusion. Required work: 1. Flag only when the receiver comes from a Sequel model source: a model class query, an association reader, or a `Model#...` call. Do not match by name. 2. Remove the `DEFAULT_ALLOWED_PATHS` test globs. ## Acceptance criteria 1. Given `db[:handoffs].all.map { |row| row[:title] }`, when the cop runs, then it reports no offense. 2. Given `Handoff.where(x: 1).map { |row| row[:title] }`, when the cop runs, then it reports an offense. ## Origin - Trigger: the #1325 zero-false-positive audit of the Sdlc cops (docs/plans/class-length-family/sdlc-cop-audit.md) - Improvised this session: none - Chain: false positive ← matcher keys on the receiver name ← DESIGN (plugins/os-sdlc/lib/os_sdlc/cops/row_index_on_model.rb:14,23) - Root candidate: none found; searched RowIndexOnModel, row index, row_index_on_model, DEFAULT_ALLOWED_PATHS - Where: plugins/os-sdlc/lib/os_sdlc/cops/row_index_on_model.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 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#1383
No description provided.