Sdlc/Structural/InstanceVariableAssumption: treat always-run assignments and guarded reads as safe #1364
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#1364
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Rewritten 2026-10-27 from docs/lint-lessons/analyses/sdlc-structural-instance-variable-assumption.md.
The cop calls an ivar assignment conditional when any
if/case/and/oris above it.@x = m.match(t) or raisealways assigns (false hit). An ivar assigned in every branch ofif/elseorcase/elseis also flagged. Awhile/untilbody is skippable but not flagged (miss). The message prescribes "or guard the read", but the cop flags the guard.Reproduce
n/a: the 5 live hits in plugins/os/lib/handoff/document.rb and the probe table are in the analysis file, step 7.
Approach
Required work:
IvasgnConditionality, call an assignment conditional only when an ancestor holds it in a skippable slot:ifthen/else body,casewhen/else body, rhs ofand/or,while/untilbody (block and modifier forms).InitializeIvars, treat an ivar as unconditional when every branch of oneif/elseorcase-with-elseassigns it.MESSAGE: remove "or guard the read"; prescribe assigning on every path of initialize, or moving the optional part to its own object.defined?(@x),@x&.) as offenses; ticket item 3 (skip guarded reads) is rejected.Acceptance criteria
@x = R.match(t) or raiseand a read in another method, when the cop runs, then it reports no offense.if f; @x = 1; else; @x = 2; end, when the cop runs, then it reports no offense.t && @x = 1or@x = 1 while c.next, when the cop runs, then it reports one offense per read.@x = {} if flagand adefined?(@x)-guarded reader, when the cop runs, then it reports an offense and the message does not contain "guard the read".plugins/on main, when the cop runs, then it reports 0 offenses.Owner sketch
IvasgnConditionalityowns "is this slot skippable";InitializeIvarsowns "assigned on every path";ReadSitesis unchanged.Origin
VERDICT: CREATE
Skeptic DROP (depth-1, 1 hit fixed by #1423): proposed cop for a character offset and a byte operation in one method. Revisit if a second site appears. The real bug is filed as #1423.
Body rewritten 2026-10-27 from the false-positive process; analysis and lint lesson merged to main (docs/lint-lessons/analyses/, plugins/os-sdlc/lint-lessons/).
Work started on branch ticket-1364 (os-sdlc implement).
Resolution
Done: IvasgnConditionality flags an initialize assignment only in a skippable slot (if/case branch body, rhs of and/or, while/until body); InitializeIvars treats an ivar assigned in every branch of if/else or case/else (including elsif chains) as set on every path, via new BranchBodies; MESSAGE drops 'or guard the read' and prescribes assigning on every path or moving the optional part to its own object. Guarded reads stay offenses.
Evidence: main
76313394(commitfab94ec4), pushed. Cop over plugins/: 5 offenses (plugins/os/lib/handoff/document.rb:23,31,37,37,39) -> 0, no new hits. 8 new tests cover AC 1-4; os-sdlc suite 2811 runs, 0 failures, 38 s. Lint clean. Lesson file already matched the new rule; unchanged. Hand-finished: implementation 199 went stale when another unit in the same session opened implementation 200.Follow-ups: Pipeline defect: two implementations in one Claude session collide (capture pending skeptic verdict).
Follow-up filed: #1447 (two implementations in one Claude session collide; this ticket was hand-finished because of it).