Widen DiscardedErrorCode to a code only interpolated into the message #1451

Closed
opened 2026-10-27 21:57:25 +00:00 by jared · 2 comments
Owner

Problem

Ruling needed: does a subprocess exit status (exit #{status.exitstatus} in a raise message) count as a discarded error code? All about 7 candidates today are this shape.

The cop Sdlc/Structural/DiscardedErrorCode counts a code interpolated into a message as carried.
A caller must then parse the message text to get the code.

Observed

Analysis: docs/lint-lessons/analyses/sdlc-structural-discarded-error-code.md, option B.
Shape: raise Error, "bad: #{code}". The cop needs a rule for "code appears only under a dstr".
Candidates (about 7): lint/run/result.rb, report/merged_diff.rb, git/repo.rb, crc/filing/backlog_client.rb, two in eval/.../case_preparer.rb, and judge_pairs.rb (all os-sdlc).

Reproduce

n/a: this is a widening of a cop; the matcher is under plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/.

Approach

Blocked by #1353 (false-positive carve-out on the same cop). Land #1353 first, and get the ruling above.
If the ruling says a subprocess exit status counts, flag a raise whose code appears only inside the message string.
If the ruling says no, narrow the rule so these candidates do not fire.
Rule from Jared: every new hit must be a true positive, and no Exclude lists. Carve-outs go in the matcher.

Required work:

  1. Add the interpolated-code rule to the cop — check: present dstr in plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/raise_site.rb

Acceptance criteria

  1. Given raise Error, "bad: #{code}" where code is an error code, when the cop runs, then it reports an offense.
  2. Given a raise that also passes the code as an argument or attribute, when the cop runs, then it reports no offense.
  3. Given plugins/, when the cop runs, then every new hit is a true positive under the ruling.

Owner sketch

class Sdlc::Structural::DiscardedErrorCode::RaiseSite
  def discarded?(node)
end

Origin

  • Trigger: Jared ruled "B for four cops" on the inc 7 widenings of the lint-cops track (handoff .cc-os/os/handoffs/2026-10-27-1542-lint-cops-track.md).
  • Improvised this session: none
  • Chain: cop misses a code carried only in message text ← cop counts an interpolated code as carried ← DESIGN (docs/lint-lessons/analyses/sdlc-structural-discarded-error-code.md)
  • Root candidate: none found; searched DiscardedErrorCode, discarded_error_code, discarded error code
  • Where: plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/raise_site.rb
  • Session: 9f415790-a6bd-4850-8d70-3dd45004ce2b
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/9f415790-a6bd-4850-8d70-3dd45004ce2b.jsonl
    VERDICT: CREATE
## Problem Ruling needed: does a subprocess exit status (`exit #{status.exitstatus}` in a raise message) count as a discarded error code? All about 7 candidates today are this shape. The cop `Sdlc/Structural/DiscardedErrorCode` counts a code interpolated into a message as carried. A caller must then parse the message text to get the code. ## Observed Analysis: `docs/lint-lessons/analyses/sdlc-structural-discarded-error-code.md`, option B. Shape: `raise Error, "bad: #{code}"`. The cop needs a rule for "code appears only under a dstr". Candidates (about 7): `lint/run/result.rb`, `report/merged_diff.rb`, `git/repo.rb`, `crc/filing/backlog_client.rb`, two in `eval/.../case_preparer.rb`, and `judge_pairs.rb` (all os-sdlc). ## Reproduce n/a: this is a widening of a cop; the matcher is under `plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/`. ## Approach Blocked by #1353 (false-positive carve-out on the same cop). Land #1353 first, and get the ruling above. If the ruling says a subprocess exit status counts, flag a raise whose code appears only inside the message string. If the ruling says no, narrow the rule so these candidates do not fire. Rule from Jared: every new hit must be a true positive, and no Exclude lists. Carve-outs go in the matcher. Required work: 1. Add the interpolated-code rule to the cop — check: present `dstr` in `plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/raise_site.rb` ## Acceptance criteria 1. Given `raise Error, "bad: #{code}"` where `code` is an error code, when the cop runs, then it reports an offense. 2. Given a raise that also passes the code as an argument or attribute, when the cop runs, then it reports no offense. 3. Given `plugins/`, when the cop runs, then every new hit is a true positive under the ruling. ## Owner sketch ```ruby class Sdlc::Structural::DiscardedErrorCode::RaiseSite def discarded?(node) end ``` ## Origin - Trigger: Jared ruled "B for four cops" on the inc 7 widenings of the lint-cops track (handoff `.cc-os/os/handoffs/2026-10-27-1542-lint-cops-track.md`). - Improvised this session: none - Chain: cop misses a code carried only in message text ← cop counts an interpolated code as carried ← DESIGN (docs/lint-lessons/analyses/sdlc-structural-discarded-error-code.md) - Root candidate: none found; searched DiscardedErrorCode, discarded_error_code, discarded error code - Where: plugins/os-sdlc/lib/os_sdlc/cops/discarded_error_code/raise_site.rb - Session: 9f415790-a6bd-4850-8d70-3dd45004ce2b - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/9f415790-a6bd-4850-8d70-3dd45004ce2b.jsonl VERDICT: CREATE
Author
Owner

Waiting on Jared's ruling (question at the top of the body) and on #1353.

Waiting on Jared's ruling (question at the top of the body) and on #1353.
Author
Owner

Resolution

Done: Ruled 2026-10-28 (Jared): do not widen. An exit status interpolated into a raise message describes a failed subprocess for a human; no caller branches on it, so every new hit would be a false positive.

Evidence: raise_site.rb carries? counts any argument subtree naming the discriminator, so a status interpolated in the message already passes; rubocop --only Sdlc/Structural/DiscardedErrorCode reports no offenses on git/repo.rb:15, lint/run/result.rb:8, report/merged_diff.rb:13, crc/filing/backlog_client.rb:36; all rescues (lint/remediation.rb:13, lint/sweeping.rb:13, fast_gate/new_offense_report.rb:10, crc/filing.rb:44) print e.message and exit 3.

Follow-ups: none

## Resolution **Done:** Ruled 2026-10-28 (Jared): do not widen. An exit status interpolated into a raise message describes a failed subprocess for a human; no caller branches on it, so every new hit would be a false positive. **Evidence:** raise_site.rb carries? counts any argument subtree naming the discriminator, so a status interpolated in the message already passes; rubocop --only Sdlc/Structural/DiscardedErrorCode reports no offenses on git/repo.rb:15, lint/run/result.rb:8, report/merged_diff.rb:13, crc/filing/backlog_client.rb:36; all rescues (lint/remediation.rb:13, lint/sweeping.rb:13, fast_gate/new_offense_report.rb:10, crc/filing.rb:44) print e.message and exit 3. **Follow-ups:** none
jared closed this issue 2026-10-28 15:37:50 +00:00
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#1451
No description provided.