Project::RootSearch owns the not-found message #579

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

Summary

Batch 3 on project.rb, ticket 2 of 4. Capability: root-search failure message. Audit run 15: .sdlc/tmp/responsibility-audit/run-15/analysis.yaml, finding 3.

Project.raise_missing_root! (project.rb:38) describes the search bound as "the nearest repo/home boundary". Project::RootSearch#boundary? (root_search.rb:26) is the code that decides it. Two objects state one rule; only one can enforce it.

Proposed owner (from the report, verbatim)

class Project::RootSearch
  def root! = root || raise(HarnessError, not_found_message)

  private

  def not_found_message
    "no .sdlc/project.yaml found between #{@dir} and the nearest repo/home boundary -- ..."
  end
end

Keep the message text byte-identical to the current one at project.rb:36-40 so tests/project_test.rb:32-48 keep passing.

Callers that delegate

  • Project.load (project.rb:22-23), through Project::Yaml.containing, which gains a bang form or Project.load calls RootSearch.new(dir).root!.

Tasks

  • Project::RootSearch#root! returns the root or raises HarnessError with the not-found message.
  • Project.load on a directory with no project.yaml raises through RootSearch, same message as today.

Acceptance criteria

  • Given a directory tree with no .sdlc/project.yaml up to .git, Project::RootSearch.new(dir).root! raises HarnessError whose message contains the start dir and nearest repo/home boundary.
  • Given the same tree, Project.load(dir, target: nil) raises HarnessError with that same message.

Structural follow-through

  • Delete Project.raise_missing_root! (project.rb:35-41). Grep after: rg "raise_missing_root" plugins/os-sdlc returns nothing.
  • Test file to check by hand: tests/project_test.rb:32,41,48 (message assertions); tests/project/root_search_test.rb gains the raise case.

ADR case

Amends ADR-0177 (RootSearch owns the walk and its failure text). Create the amending ADR when the ticket lands.

Order

Position 2 of 4. Follows ticket 1 (defects). Next: ticket 3 (Project::Setup).

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 2 of 4. Capability: root-search failure message. Audit run 15: `.sdlc/tmp/responsibility-audit/run-15/analysis.yaml`, finding 3. `Project.raise_missing_root!` (project.rb:38) describes the search bound as "the nearest repo/home boundary". `Project::RootSearch#boundary?` (root_search.rb:26) is the code that decides it. Two objects state one rule; only one can enforce it. ## Proposed owner (from the report, verbatim) ```ruby class Project::RootSearch def root! = root || raise(HarnessError, not_found_message) private def not_found_message "no .sdlc/project.yaml found between #{@dir} and the nearest repo/home boundary -- ..." end end ``` Keep the message text byte-identical to the current one at project.rb:36-40 so `tests/project_test.rb:32-48` keep passing. ## Callers that delegate - `Project.load` (project.rb:22-23), through `Project::Yaml.containing`, which gains a bang form or `Project.load` calls `RootSearch.new(dir).root!`. ## Tasks - [ ] `Project::RootSearch#root!` returns the root or raises `HarnessError` with the not-found message. - [ ] `Project.load` on a directory with no project.yaml raises through `RootSearch`, same message as today. ## Acceptance criteria - Given a directory tree with no `.sdlc/project.yaml` up to `.git`, `Project::RootSearch.new(dir).root!` raises `HarnessError` whose message contains the start dir and `nearest repo/home boundary`. - Given the same tree, `Project.load(dir, target: nil)` raises `HarnessError` with that same message. ## Structural follow-through - Delete `Project.raise_missing_root!` (project.rb:35-41). Grep after: `rg "raise_missing_root" plugins/os-sdlc` returns nothing. - Test file to check by hand: `tests/project_test.rb:32,41,48` (message assertions); `tests/project/root_search_test.rb` gains the raise case. ## ADR case Amends ADR-0177 (RootSearch owns the walk and its failure text). Create the amending ADR when the ticket lands. ## Order Position 2 of 4. Follows ticket 1 (defects). Next: ticket 3 (Project::Setup). ## 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-579, map poodr-ticket-implementation.yaml, target os-sdlc.

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

Resolution

Done: Project::RootSearch#root! owns the not-found message; Project.raise_missing_root! and Project::Yaml.containing deleted; Project.load goes RootSearch then Yaml.new(root). Structural follow-through was completed by the pipeline's refactor rounds.

Evidence: main d2e3c3e, ADR-0184 (amends 0177), suite 1166 runs 0 failures, rubocop clean. Pipeline: 14 dispatches, 2 contract-auditor fail/refactorer rounds. Deviations: test-writer and programmer each relayed the previous node's dispatch id and the Runner answered await_completion; orchestrator ran the gate and hand-settled rows 135 and 137. One hand settlement was mis-sent to the already-closed row 134 (recorded as a second pass, no effect on routing).

Follow-ups: none

## Resolution **Done:** Project::RootSearch#root! owns the not-found message; Project.raise_missing_root! and Project::Yaml.containing deleted; Project.load goes RootSearch then Yaml.new(root). Structural follow-through was completed by the pipeline's refactor rounds. **Evidence:** main d2e3c3e, ADR-0184 (amends 0177), suite 1166 runs 0 failures, rubocop clean. Pipeline: 14 dispatches, 2 contract-auditor fail/refactorer rounds. Deviations: test-writer and programmer each relayed the previous node's dispatch id and the Runner answered await_completion; orchestrator ran the gate and hand-settled rows 135 and 137. One hand settlement was mis-sent to the already-closed row 134 (recorded as a second pass, no effect on routing). **Follow-ups:** none
jared closed this issue 2026-09-14 18:15:29 +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#579
No description provided.