Port the inward-dependency lint to a rubocop cop #1073
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#1073
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 inward-dependency check judges code: it reports a reference that crosses from an inner layer to an outer layer. Every other code judgment in os-sdlc is a rubocop cop that the gate runs. This one is a separate script,
plugins/os-sdlc/bin/lint-inward-dependencies, called by hand as gate step 3 of the crc-refactor skill. It prints one summary line per file, not an offense on the referencing line. It runs only during a CRC run, so no other Ruby codebase gets the check.Reproduce
n/a: design ticket. The script runs today with
bundle exec bin/lint-inward-dependencies ../../docs/crc/os-sdlc/ledger.tsvfromplugins/os-sdlc.Approach
Port the check to a cop,
Sdlc/Structural/InwardDependency, and delete the script. Decided design:LedgerPath:is configured, the layer is the ledgerrolecolumn for the file path. Otherwise the layer is the first directory underlib/os_sdlc/of the file (model/,presenter/,adapter/, and so on), the same rulebuild_role_mapuses today. The layer table is the existingROLE_LAYERconstant, moved to the cop.a40f736eon 2026-10-17. Keep it.Sdlc/*cop reaches target projects.skills/crc-refactor/SKILL.mdandreferences/parameters.md.lint-lessons/with the cop. Lesson, code shape only: a reader that finds "the constant this file defines" by walking only class and module nodes names the wrong constant forName = Struct.new,Name = Data.define, andName = Class.new. Those are the same definition in a different spelling. Ask the loader for the constant instead of parsing. Test with one file of each spelling and assert the same name for all three..rubocop.ymlenabled, withExclude:entries for the files that carry the 69 edges reported on 2026-10-17, under a comment naming Phase 9 of docs/crc/PLAN.md as the burn-down. The gate must stay green.Required work:
all_expected_cpathsinplugins/os-sdlc/lib/os_sdlc/cops/inward_dependency*.rbSdlc/Structural/InwardDependencyinplugins/os-sdlc/.rubocop.ymllint-inward-dependenciesinplugins/os-sdlc/bin/*all_expected_cpathsinplugins/os-sdlc/lint-lessons/*inward*Orchestrator work: skill edits in item 4; ADR check against 0090, 0082, 0066 before the first edit.
Acceptance criteria
modelthat references a constant in layercommand, when rubocop runs with the cop enabled, then an offense appears on the referencing line and names both layers.Name = Struct.new,Name = Data.define, orclass Name, when rubocop runs, then the file's own layer is the same in all three cases.LedgerPath:in config, when rubocop runs on an A15 plugin, then the layer comes from the file's role directory.bin/lint-inward-dependenciesand the file does not exist.Owner sketch
Non-goals
Ruling on the 69 edges the check reports today. That is a Phase 9 task in
docs/crc/PLAN.md.Surveying
crc-sweepfor a cop port. Follow-up ticket if the survey says yes.Origin
a40f736efix; Jared asked why the check is an executable and not a copWork started on branch ticket-1073 via /os-sdlc:implement.
Resolution
Done: Inward-dependency lint ported to the rubocop cop Sdlc/Structural/InwardDependency; script, lib and test deleted; loader construction extracted to lib/os_sdlc_loader.rb so the cop loads without bundler; LedgerPath set in .rubocop.yml with 39 files Excluded for Phase 9 burn-down; lint lesson shipped; crc-refactor skill text uses INWARD_LEDGER_PATH
Evidence: ticket-1073 commit
7fc5e28b; suite 1774 runs 0 failures 0 errors; whole-plugin rubocop 89 offenses, all pre-existing under eval/ and tests/support; cop alone on lib: no offenses with Excludes, 70 offenses in 39 files without; design audit (contract-auditor) passed, its findings applied; ADR find: no one-way door reversed (0090, 0166, 0082 inform). Hand-finished after Runner escalation 27 (unexpected pass) on implementation 52.Follow-ups: crc_tickets still accepts --inward-lint-command (remove or repoint): captured as Phase 9 note in docs/crc/PLAN.md, no ticket; format-exemplar.md 'inward-lint count' wording stays as a historical example: dropped; burn down the 39 Excluded files: Phase 9 task already in docs/crc/PLAN.md