Collapse os-sdlc slice directories into role autoload roots and drop slice prefixes from constants #737

Closed
opened 2026-09-25 21:13:05 +00:00 by jared · 2 comments
Owner

Problem

ADR-0196 maps lib/os_sdlc/<slice>/<name>.rb to OsSdlc::<Slice>::<Name>. The layout ADR that follows ADR-0221 (number to be filled in by the implementer from docs/adr/README.md, title starts "os-sdlc organizes constants by concept and files by role") replaces that rule. Role directories (model/, query/, presenter/, parser/, command/, adapter/, and the existing lint/, cli/, evidence/, hook/, pipeline/ as decided in the ADR) become Zeitwerk collapsed directories. A file at model/gate.rb defines OsSdlc::Gate; presenter/gate/reply.rb defines OsSdlc::Gate::Reply. Every existing constant loses its slice prefix. Model.for(db) is a registry that needs a new name, since Model stops being a namespace.

Reproduce

n/a: layout change, not a defect.

Approach

One move-map script, the same shape ADR-0196 used, that moves every file and rewrites every constant reference in lib/, tests/, bin/, and .rubocop.yml in one pass. Suite green before merge. Run os-sdlc:blast-radius first; the os plugin and any other repo that names os-sdlc constants are the unknowns. Rewrite the inward-dependency check from constant names to file paths. This ticket lands before any Gate consolidation, so Gate moves once.

Required work:

  1. Run os-sdlc:blast-radius to identify external consumers — check: os-sdlc:blast-radius returns no breaking changes outside this repo or a clear list of repos to update
  2. Write move-map script following ADR-0196 pattern — check: script runs without error on dry-run
  3. Move files from slice directories to role directories — check: no files remain in old slice locations
  4. Rewrite all constant references in lib/, tests/, bin/, and .rubocop.yml — check: grep finds no old slice-prefixed constants in these locations
  5. Rename Model.for(db) registry to new name and update all callers — check: grep finds no references to Model.for
  6. Rewrite inward-dependency check from constant-name-based to file-path-based — check: bin/inward-dependency-check passes
  7. Run full test suite — check: bin/test passes with zero failures
  8. Verify eager-load — check: bin/zeitwerk:check or project equivalent passes
  9. Refresh plugin cache — check: bin/refresh-plugins completes successfully
  10. Live verification from another repo — check: os-sdlc-runner command succeeds with updated os plugin

Acceptance criteria

  1. zeitwerk:check (or the project's equivalent eager-load test) passes with the collapsed directories.
  2. No constant in lib/ carries a slice prefix (Model::, Pipeline::, Lint::, Adapter::, Evidence::, Hook::, Cli::) except where the ADR keeps one by explicit nesting.
  3. The registry formerly reached by Model.for(db) has a new name and every caller uses it.
  4. The inward-dependency rule is enforced by file path and its test is green.
  5. Full suite green; bin/refresh-plugins run; a live os-sdlc-runner command succeeds from another repo.

Owner sketch

class OsSdlc::LayoutMigration
  def initialize(root_path)
  end

  def move_files_to_roles
  end

  def rewrite_constants
  end

  def rename_registry
  end

  def verify_eager_load
  end
end

Origin

  • Session: f7e333c0-cafa-4981-b78c-c5e82b990d45
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-crc-pass-os-sdlc/f7e333c0-cafa-4981-b78c-c5e82b990d45.jsonl
  • Where: plugins/os-sdlc/lib/os_sdlc/ (all slices)
  • Source: docs/crc/os-sdlc/HANDOFF.md, ADR-0221 follow-up layout decision, 2026-09-25
## Problem ADR-0196 maps `lib/os_sdlc/<slice>/<name>.rb` to `OsSdlc::<Slice>::<Name>`. The layout ADR that follows ADR-0221 (number to be filled in by the implementer from docs/adr/README.md, title starts "os-sdlc organizes constants by concept and files by role") replaces that rule. Role directories (`model/`, `query/`, `presenter/`, `parser/`, `command/`, `adapter/`, and the existing `lint/`, `cli/`, `evidence/`, `hook/`, `pipeline/` as decided in the ADR) become Zeitwerk collapsed directories. A file at `model/gate.rb` defines `OsSdlc::Gate`; `presenter/gate/reply.rb` defines `OsSdlc::Gate::Reply`. Every existing constant loses its slice prefix. `Model.for(db)` is a registry that needs a new name, since `Model` stops being a namespace. ## Reproduce n/a: layout change, not a defect. ## Approach One move-map script, the same shape ADR-0196 used, that moves every file and rewrites every constant reference in lib/, tests/, bin/, and .rubocop.yml in one pass. Suite green before merge. Run `os-sdlc:blast-radius` first; the `os` plugin and any other repo that names os-sdlc constants are the unknowns. Rewrite the inward-dependency check from constant names to file paths. This ticket lands before any Gate consolidation, so Gate moves once. Required work: 1. Run `os-sdlc:blast-radius` to identify external consumers — check: `os-sdlc:blast-radius` returns no breaking changes outside this repo or a clear list of repos to update 2. Write move-map script following ADR-0196 pattern — check: script runs without error on dry-run 3. Move files from slice directories to role directories — check: no files remain in old slice locations 4. Rewrite all constant references in lib/, tests/, bin/, and .rubocop.yml — check: grep finds no old slice-prefixed constants in these locations 5. Rename `Model.for(db)` registry to new name and update all callers — check: grep finds no references to `Model.for` 6. Rewrite inward-dependency check from constant-name-based to file-path-based — check: `bin/inward-dependency-check` passes 7. Run full test suite — check: `bin/test` passes with zero failures 8. Verify eager-load — check: `bin/zeitwerk:check` or project equivalent passes 9. Refresh plugin cache — check: `bin/refresh-plugins` completes successfully 10. Live verification from another repo — check: `os-sdlc-runner` command succeeds with updated `os` plugin ## Acceptance criteria 1. `zeitwerk:check` (or the project's equivalent eager-load test) passes with the collapsed directories. 2. No constant in lib/ carries a slice prefix (`Model::`, `Pipeline::`, `Lint::`, `Adapter::`, `Evidence::`, `Hook::`, `Cli::`) except where the ADR keeps one by explicit nesting. 3. The registry formerly reached by `Model.for(db)` has a new name and every caller uses it. 4. The inward-dependency rule is enforced by file path and its test is green. 5. Full suite green; `bin/refresh-plugins` run; a live `os-sdlc-runner` command succeeds from another repo. ## Owner sketch ```ruby class OsSdlc::LayoutMigration def initialize(root_path) end def move_files_to_roles end def rewrite_constants end def rename_registry end def verify_eager_load end end ``` ## Origin - Session: f7e333c0-cafa-4981-b78c-c5e82b990d45 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-crc-pass-os-sdlc/f7e333c0-cafa-4981-b78c-c5e82b990d45.jsonl - Where: plugins/os-sdlc/lib/os_sdlc/ (all slices) - Source: docs/crc/os-sdlc/HANDOFF.md, ADR-0221 follow-up layout decision, 2026-09-25
Author
Owner

Work started on branch crc-pass-os-sdlc (hand-run, not the pipeline: rename with no red test). Blast radius: one sibling gem test (procman procman_kind_contract_test.rb references OsSdlc::LspProbe::ProcmanKind -> OsSdlc::ProcmanKind), .claude/rules/os-sdlc-architecture.md, two SKILL.md path references, two string-pinned constant names in tests. Move map (321 rows, verb-rule roles, four CLI collisions renamed RunnerCLI/EvidenceCLI/LspProbeCLI, Git:: nesting kept) at docs/crc/os-sdlc/move-map-0222.tsv. Registry Model.for(db) becomes Records.for(db).

Work started on branch crc-pass-os-sdlc (hand-run, not the pipeline: rename with no red test). Blast radius: one sibling gem test (procman procman_kind_contract_test.rb references OsSdlc::LspProbe::ProcmanKind -> OsSdlc::ProcmanKind), .claude/rules/os-sdlc-architecture.md, two SKILL.md path references, two string-pinned constant names in tests. Move map (321 rows, verb-rule roles, four CLI collisions renamed RunnerCLI/EvidenceCLI/LspProbeCLI, Git:: nesting kept) at docs/crc/os-sdlc/move-map-0222.tsv. Registry Model.for(db) becomes Records.for(db).
Author
Owner

Resolution

Done: Slice directories collapsed into 11 Zeitwerk role autoload roots (model query presenter parser command adapter lint cli evidence hook pipeline); every constant lost its slice prefix per docs/crc/os-sdlc/move-map-0222.tsv (321 rows); Model.for(db) registry renamed Records; CLI collisions resolved as RunnerCLI, EvidenceCLI, LspProbeCLI; Git:: nesting kept; 148 tests moved to mirror role dirs; inward-dependency rule enforced by file path in tests/inward_dependency_test.rb with a 72-entry recorded baseline; .claude/rules/os-sdlc-architecture.md rewritten to ADR-0222; docs and skills updated.

Evidence: main 27b7b9bb (commits 4d462e1b 0d91cb2b 9bca1068 38cbe22b aebc1ebc 81b16e37 27b7b9bb). Suite: 1428 runs, 3245 assertions, 1 failure (pre-existing fork-guard, #740), 0 errors. zeitwerk_eager_load_test green. bin/refresh-plugins run; from ~/dev/ruby-gems/procman the cached os-sdlc-runner, lsp-probe, and evidence binaries start and eager load resolves OsSdlc::RunnerCLI and OsSdlc::Records. Blast radius run first; hand-run rather than pipeline because a rename has no red test.

Follow-ups: #740 fork-guard allowlist defect (pre-existing from #713); #741 shrink the 72-entry inward-dependency baseline and re-layer IssueSource, Map, Records; jared/procman#5 rename OsSdlc::LspProbe::ProcmanKind in the procman gem test; Gate/Brief consolidation and card rewrites tracked in docs/crc/os-sdlc/HANDOFF.md, not tickets yet.

## Resolution **Done:** Slice directories collapsed into 11 Zeitwerk role autoload roots (model query presenter parser command adapter lint cli evidence hook pipeline); every constant lost its slice prefix per docs/crc/os-sdlc/move-map-0222.tsv (321 rows); Model.for(db) registry renamed Records; CLI collisions resolved as RunnerCLI, EvidenceCLI, LspProbeCLI; Git:: nesting kept; 148 tests moved to mirror role dirs; inward-dependency rule enforced by file path in tests/inward_dependency_test.rb with a 72-entry recorded baseline; .claude/rules/os-sdlc-architecture.md rewritten to ADR-0222; docs and skills updated. **Evidence:** main 27b7b9bb (commits 4d462e1b 0d91cb2b 9bca1068 38cbe22b aebc1ebc 81b16e37 27b7b9bb). Suite: 1428 runs, 3245 assertions, 1 failure (pre-existing fork-guard, #740), 0 errors. zeitwerk_eager_load_test green. bin/refresh-plugins run; from ~/dev/ruby-gems/procman the cached os-sdlc-runner, lsp-probe, and evidence binaries start and eager load resolves OsSdlc::RunnerCLI and OsSdlc::Records. Blast radius run first; hand-run rather than pipeline because a rename has no red test. **Follow-ups:** #740 fork-guard allowlist defect (pre-existing from #713); #741 shrink the 72-entry inward-dependency baseline and re-layer IssueSource, Map, Records; jared/procman#5 rename OsSdlc::LspProbe::ProcmanKind in the procman gem test; Gate/Brief consolidation and card rewrites tracked in docs/crc/os-sdlc/HANDOFF.md, not tickets yet.
jared closed this issue 2026-09-26 12:40:08 +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#737
No description provided.