Add related lessons and backstop hit to the ClassLength lesson #1324
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#1324
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
The ClassLength lesson cannot point to other cops that explain the same file. Lesson::Relay (plugins/os-sdlc/lib/os_sdlc/lesson/relay.rb) renders one lesson per fired cop key. It has no support for related lessons. A file that Metrics/ClassLength flags, and that no family cop explains, gets no signal that the shape is new.
Reproduce
n/a: missing feature.
Approach
Add a
related:key to the lesson schema. Lesson::Relay renders the signal line of each related lesson.The ClassLength lesson lists the family: the repeated-method-skeleton cop (
Sdlc/Dry/RepeatedRescueClause, #1321), the repeated-collaborator-construction cop (Sdlc/Dry/RepeatedCollaboratorConstruction, #1322), Sdlc/Structural/ModuleOwnsInstanceState, and Sdlc/Structural/ParameterThreadedThroughPrivateMethods.The ClassLength lesson's
related:list is the only family list. The backstop check reads it; it does not keep a second list.The gate reports a "backstop hit" when Metrics/ClassLength fires in a file where no family cop fires. The lesson then tells the agent to run /os-sdlc:smell-analysis and capture a ticket for the uncovered shape.
This ticket is blocked by #1323 (the lessons it relates to).
"The gate" is the implement gate reply:
OsSdlc::Gate::Reply#lint_output(plugins/os-sdlc/lib/os_sdlc/gate/reply.rb) renders the lint step output and callsOffenseDirective#guidancewith the cop names. Find the backstop from the same rubocop JSON, per file, asGate::LintOutput.cop_namesdoes.Lesson schema today:
OsSdlc::Lesson(plugins/os-sdlc/lib/os_sdlc/lesson.rb) isData.define(:key, :signal, :sign_of, :why, :decision, :correction, :example), andLesson.fromraises HarnessError for any missing member.related:and the backstop text must be optional members, so the 32 existing lesson files stay valid.Metrics/ClassLength excludes test paths in plugins/os-sdlc/.rubocop.yml until #1317, so a backstop hit cannot occur in a test file. A target whose lint runs without Sdlc cops reports every ClassLength hit as a backstop hit; #1319 (earlier in the approved order) layers the os-sdlc config onto every target.
Required work:
related:key to the lesson schema and its validation — check: presentrelatedinplugins/os-sdlc/lib/os_sdlc/lesson.rbrelatedinplugins/os-sdlc/lib/os_sdlc/lesson/relay.rbrelated:list to the ClassLength lesson — check: presentrelated:inplugins/os-sdlc/lint-lessons/metrics-class-length.ymlbackstop_pathsinplugins/os-sdlc/lib/os_sdlc/gate/lint_output.rbsmell-analysisinplugins/os-sdlc/lint-lessons/metrics-class-length.ymlAcceptance criteria
related:key, when Lesson::Relay renders it, then the output has the signal line of each related lesson.related:key and no backstop text, when Lesson.from loads it, then it loads with no error.Owner sketch
OsSdlc::Lesson(lib/os_sdlc/lesson.rb): optionalrelated(list of cop keys) andbackstop(text).fromdefaults them when absent.OsSdlc::Lesson::Relay#render(lib/os_sdlc/lesson/relay.rb): after a lesson's text, renders thesignalof each related lesson that the catalog has.OsSdlc::Gate::LintOutput.backstop_paths(lib/os_sdlc/gate/lint_output.rb): from the rubocop JSON, the paths where Metrics/ClassLength fires and no cop infamilyfires.OsSdlc::Gate::Reply#lint_output(lib/os_sdlc/gate/reply.rb): when backstop_paths is not empty, adds abackstop hit: <path>line per path and the ClassLength lesson'sbackstoptext.related:andbackstop:.Origin
VERDICT: CREATE
Blocked by #1323: the ClassLength lesson rewrite must exist before it gets related: keys.
Work started on branch ticket-1324 through /os-sdlc:implement.
Resolution
Done: Lessons take optional related: and backstop: fields. Lesson::Relay renders the signal of each related lesson. The ClassLength lesson lists the four family cops and carries backstop text that names /os-sdlc:smell-analysis and a ticket capture. The gate reply adds a backstop hit line per file where Metrics/ClassLength fires and no family cop fires.
Evidence: Commits
cb4674b6(Runner commit, implementation 164: implementation_complete, 10 dispatches, no escalation, suite-check pass) and7dd2dcd2(History row). Tests in plugins/os-sdlc/tests/gate/class_length_backstop_test.rb cover the five acceptance criteria. Orchestrator read the production diff.Follow-ups: Captured #1391 (skeptic CREATE): the backstop check reads the new-offense-filtered lint JSON, so a family cop offense already on base is filtered out and the file gets a false backstop hit.