Batch 3 defects: lint_config single resolver, keep save_tracker result, Config refuses nil name #578

Closed
opened 2026-09-14 17:25:54 +00:00 by jared · 3 comments
Owner

Summary

Batch 3 on project.rb, ticket 1 of 4 (defects that move no ownership). Audit run 15: .sdlc/tmp/responsibility-audit/run-15/analysis.yaml.

Three defect rows from the audit, each a sender that bypasses an owner the code already has.

Tasks

  • LintWorklistRubocopConfig stops resolving lint_config itself. It receives the already-resolved absolute path from Project#resolved_lint_config (the sole resolver, ADR-0179) and only inherits or refuses it. Today lint_worklist_rubocop_config.rb:42 tests the raw value with File.exist? against the process cwd and :51 re-resolves against @project_root.
  • IssueSource::TrackerResolver keeps the Project that Project#save_tracker returns (issue_source.rb:47 discards it), so the project handed onward carries the tracker it just persisted.
  • Project::Config#project refuses a blob that has no name with a HarnessError naming the missing key (project/config.rb:24 accepts nil; Project.from_data uses fetch("name")). Empty and nil blobs still return nil (ADR-0176).

Acceptance criteria

  • Given a project.yaml with lint_config: .rubocop.yml (relative) and the process cwd elsewhere, the generated rubocop config inherits <project root>/.rubocop.yml.
  • Given a configured lint_config whose file is missing, LintWorklistRubocopConfig raises HarnessError no matter the process cwd.
  • Given a project with no tracker and a .cc-os/config tracker line, after IssueSource.for(project) the resolver's project responds to tracker with that value.
  • Given a project_config blob {"root": "/x"} with no name, Project::Config.new(blob).project raises HarnessError whose message names name.
  • Given a nil or "{}" blob, Project::Config#project returns nil (unchanged).

Structural follow-through

Applied by the orchestrator after implementation_complete, before commit:

  • Delete Project.sdlc_dir (project.rb:103); Project::Yaml#path (yaml.rb:28) calls Project::ArtifactDir.new(root).path directly. Grep after: rg "Project.sdlc_dir" plugins/os-sdlc returns nothing.
  • Grep after: rg "File.exist\?\(@lint_config\)|LintConfig.new" plugins/os-sdlc/lib/os_sdlc/lint_worklist_rubocop_config.rb returns nothing.
  • Test files that reference touched names: tests/lint_worklist_rubocop_config_test.rb:46, tests/cops/query_method_reaches_write_test.rb:20 (fixture string only), tests/project_test.rb:129-151.

ADR case

Completes ADR-0056 (tracker persisted back through save_tracker), ADR-0091 and ADR-0179 (single lint-config resolver). Amends ADR-0176 (a present blob without name is a refusal, not an empty state); create the amending ADR when the ticket lands.

Order

Position 1 of 4. Follows nothing. Next: ticket 2 (RootSearch owns the not-found message).

Origin

  • Filed by: agent, on user approval via /os-sdlc:responsibility-refactor
  • Source: responsibility-audit run 15, analysis .sdlc/tmp/responsibility-audit/run-15/analysis.yaml
  • Where: plugins/os-sdlc/lib/os_sdlc/project.rb
  • Session: 932cc3fb-b634-45ac-a990-737178341a12
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/932cc3fb-b634-45ac-a990-737178341a12.jsonl
  • Skeptic: not run (user-approved batch)
## Summary Batch 3 on project.rb, ticket 1 of 4 (defects that move no ownership). Audit run 15: `.sdlc/tmp/responsibility-audit/run-15/analysis.yaml`. Three defect rows from the audit, each a sender that bypasses an owner the code already has. ## Tasks - [ ] `LintWorklistRubocopConfig` stops resolving `lint_config` itself. It receives the already-resolved absolute path from `Project#resolved_lint_config` (the sole resolver, ADR-0179) and only inherits or refuses it. Today `lint_worklist_rubocop_config.rb:42` tests the raw value with `File.exist?` against the process cwd and `:51` re-resolves against `@project_root`. - [ ] `IssueSource::TrackerResolver` keeps the `Project` that `Project#save_tracker` returns (`issue_source.rb:47` discards it), so the project handed onward carries the tracker it just persisted. - [ ] `Project::Config#project` refuses a blob that has no `name` with a `HarnessError` naming the missing key (`project/config.rb:24` accepts nil; `Project.from_data` uses `fetch("name")`). Empty and nil blobs still return nil (ADR-0176). ## Acceptance criteria - Given a project.yaml with `lint_config: .rubocop.yml` (relative) and the process cwd elsewhere, the generated rubocop config inherits `<project root>/.rubocop.yml`. - Given a configured `lint_config` whose file is missing, `LintWorklistRubocopConfig` raises `HarnessError` no matter the process cwd. - Given a project with no tracker and a `.cc-os/config` tracker line, after `IssueSource.for(project)` the resolver's project responds to `tracker` with that value. - Given a project_config blob `{"root": "/x"}` with no name, `Project::Config.new(blob).project` raises `HarnessError` whose message names `name`. - Given a nil or `"{}"` blob, `Project::Config#project` returns nil (unchanged). ## Structural follow-through Applied by the orchestrator after `implementation_complete`, before commit: - Delete `Project.sdlc_dir` (project.rb:103); `Project::Yaml#path` (yaml.rb:28) calls `Project::ArtifactDir.new(root).path` directly. Grep after: `rg "Project.sdlc_dir" plugins/os-sdlc` returns nothing. - Grep after: `rg "File.exist\?\(@lint_config\)|LintConfig.new" plugins/os-sdlc/lib/os_sdlc/lint_worklist_rubocop_config.rb` returns nothing. - Test files that reference touched names: `tests/lint_worklist_rubocop_config_test.rb:46`, `tests/cops/query_method_reaches_write_test.rb:20` (fixture string only), `tests/project_test.rb:129-151`. ## ADR case Completes ADR-0056 (tracker persisted back through `save_tracker`), ADR-0091 and ADR-0179 (single lint-config resolver). Amends ADR-0176 (a present blob without `name` is a refusal, not an empty state); create the amending ADR when the ticket lands. ## Order Position 1 of 4. Follows nothing. Next: ticket 2 (RootSearch owns the not-found message). ## Origin - Filed by: agent, on user approval via /os-sdlc:responsibility-refactor - Source: responsibility-audit run 15, analysis `.sdlc/tmp/responsibility-audit/run-15/analysis.yaml` - Where: plugins/os-sdlc/lib/os_sdlc/project.rb - Session: 932cc3fb-b634-45ac-a990-737178341a12 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/932cc3fb-b634-45ac-a990-737178341a12.jsonl - Skeptic: not run (user-approved batch)
Author
Owner

Map: #582

Map: #582
Author
Owner

Work started via /os-sdlc:responsibility-refactor batch 3 (map #582). Branch: ticket-578, map poodr-ticket-implementation.yaml, target os-sdlc.

Work started via /os-sdlc:responsibility-refactor batch 3 (map #582). Branch: ticket-578, map poodr-ticket-implementation.yaml, target os-sdlc.
Author
Owner

Resolution

Done: Config refuses a non-empty blob without name; LintWorklistRubocopConfig resolves lint_config through Project::LintConfig#path; TrackerResolver keeps the Project save_tracker returns; Project.sdlc_dir deleted (Yaml#path uses ArtifactDir). Structural follow-through applied by hand.

Evidence: main 313b230, ADR-0183 (amends 0176/0091/0056), suite 1164 runs 0 failures, rubocop clean on changed files. Pipeline: 14 dispatches, 2 suite-check retries. Deviations: (1) existing fixture tests/runner/implementation_empty_project_config_test.rb built a blob without name; hand-fixed to carry one. (2) One behavior-verifier launch from the plugins/os-sdlc subdirectory produced no dispatch row (start hook found no implementation); relaunched from the worktree root. (3) LintWorklistRubocopConfig resolves via LintConfig#path against @project_root rather than receiving the resolved path from Project#resolved_lint_config; contract-auditor passed it.

Follow-ups: none

## Resolution **Done:** Config refuses a non-empty blob without name; LintWorklistRubocopConfig resolves lint_config through Project::LintConfig#path; TrackerResolver keeps the Project save_tracker returns; Project.sdlc_dir deleted (Yaml#path uses ArtifactDir). Structural follow-through applied by hand. **Evidence:** main 313b230, ADR-0183 (amends 0176/0091/0056), suite 1164 runs 0 failures, rubocop clean on changed files. Pipeline: 14 dispatches, 2 suite-check retries. Deviations: (1) existing fixture tests/runner/implementation_empty_project_config_test.rb built a blob without name; hand-fixed to carry one. (2) One behavior-verifier launch from the plugins/os-sdlc subdirectory produced no dispatch row (start hook found no implementation); relaunched from the worktree root. (3) LintWorklistRubocopConfig resolves via LintConfig#path against @project_root rather than receiving the resolved path from Project#resolved_lint_config; contract-auditor passed it. **Follow-ups:** none
jared closed this issue 2026-09-14 17:54:14 +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#578
No description provided.