Resolve typed-check globs from the target path or refuse unmatched globs at implementation-open #1443

Closed
opened 2026-10-27 18:53:48 +00:00 by jared · 2 comments
Owner

Problem

A typed required-work check resolves its glob from the project root (ADR-0255). A ticket author who writes a path relative to the target path (for example lib/os_sdlc/dispatch/brief.rb for target plugins/os-sdlc) gets a check that can never pass. Implementation-open accepts the body, so the defect shows only at the suite-check gate, after the red and green rounds. The programmer-repair node cannot change the ticket body, so each repair loop is wasted. The check reads the body snapshot taken at implementation-open, so a correction on the tracker does not help the running implementation.

Example: implementation 195 (ticket #1436) escalated with bound_exhausted:suite-check/fail. The suite-check gate failed 3 times at the required-work step:

os-sdlc-required-work-check 195
glob matched no file

The three checks were check: absent work_rootinlib/os_sdlc/dispatch/brief.rb``, and two checks with paths tests/dispatch/brief_map_name_test.rb and tests/dispatch/brief_drafted_map_test.rb. All three files existed at open time under plugins/os-sdlc/. Evidence: implementation 195 escalation 90; the #1436 body revision history.

Approach

Refuse at implementation-open, not resolve from the target path: ADR-0255 fixes globs to the project root and the os-backlog validator reads the same check vocabulary, so a second, target-relative path rule would be a silent fallback that changes a one-way door, while a refusal fails loudly before the red round and stays inside the ADR.

Which checks need a file at open:

  • absent with a glob that matches no file from the project root: always refuse. Such a check can never pass (ADR-0255: a glob that matches no file fails the check).
  • Any check (present or absent) whose glob matches no file from the project root but matches a file under the selected target path: refuse, and name the root-relative path <target path>/<glob>.
  • present with a glob that matches no file anywhere: accept. The ticket can create that file.

TicketShape#missing already refuses at open for file facts (retired tests not found), so the new refusal joins #missing. Implementation::Open and Implementation::RerouteIntake both raise on #missing, so both get the refusal. They pass the selected target path. An unconfigured project has the target path ., so the target-path rule cannot match there. The suite-check gate (RequiredWorkCheck) is unchanged.

Required work:

  1. TicketShape::RequiredWork::Check returns its open-time problem for a project root and a target path, by the three rules above (proven by AC 1, AC 2).
  2. TicketShape takes a target_path: keyword (default ., the same default as Project::Target) and adds one #missing entry per typed check with a problem (proven by AC 1, AC 2).
  3. Implementation::Open#check_ticket_shape! passes target_path: @project.target.path (proven by AC 2).
  4. Implementation::RerouteIntake#refuse_incomplete_shape! passes the same target path (proven by AC 3).

Acceptance criteria

  1. Given a ticket body under poodr-ticket-implementation with check: absent work_rootinlib/brief.rband no file `lib/brief.rb` under the project root, when implementation-open runs, then it raises `HarnessError` whose message containsabsent check glob matched no file: lib/brief.rb ``, and no implementation row exists.
  2. Given a project whose selected target has path plugins/widget, a file plugins/widget/tests/brief_test.rb, and a body with check: present def test_briefintests/brief_test.rb, when implementation-open runs, then it raises `HarnessError` whose message contains write it from the project root as plugins/widget/tests/brief_test.rb ``, and no implementation row exists.
  3. Given a waiting implementation and a tracker body whose check glob matches only under the target path, when reroute-request runs, then it raises RerouteIntakeRefusedError whose message names the root-relative path <target path>/<glob>.

Owner sketch

Owner Responsibility Change
OsSdlc::TicketShape::RequiredWork::Check (lib/os_sdlc/ticket_shape/required_work/check.rb) Knows its polarity and glob, so it decides whether it can pass from the project root. New #open_problem(root:, target_path:): nil when the glob matches a file from root; "glob `<g>` matches only under the target path; write it from the project root as `<t>/<g>`" when it matches only under root/target_path; "absent check glob matched no file: `<g>`" for absent; nil for present. new method
OsSdlc::TicketShape (lib/os_sdlc/ticket_shape.rb) Lists body defects. New target_path: keyword; #missing adds "Required work check (<problem>): <item text>" per typed item. interface change (new keyword)
OsSdlc::Implementation::Open (lib/os_sdlc/implementation/open.rb) Refuses a body before the red round. Passes target_path: @project.target.path. one argument
OsSdlc::Implementation::RerouteIntake (lib/os_sdlc/implementation/reroute_intake.rb) Refuses a corrected body at reroute by the same rule. Passes the same target path. one argument
OsSdlc::Implementation::RequiredWorkCheck Suite-check judgment from the project root. unchanged

Test doubles that stand in for an object whose interface changes: none. No test stubs TicketShape or Check; the tests below use the real Project, Implementation::Open, and TicketShape. FakeTracker stands in for the tracker, whose interface does not change.

Add both tests to plugins/os-sdlc/tests/implementation/open_ticket_shape_test.rb (class OsSdlc::OpenTicketShapeTest, which already has TICKET_MAP, body_with_item, and implementations_for). A scratch spike at HEAD gave 2 failures, both OsSdlc::HarnessError expected but nothing was raised. In the second test, the project loaded as configured with target path plugins/widget, so the red is for the intended reason: open accepts the body.

    def test_open_raises_naming_the_glob_when_an_absent_check_matches_no_file
      body = body_with_item("1. Drop the old reader.\n   check: absent `work_root` in `lib/brief.rb`")
      work_order = Implementation::WorkOrder.new(session_id: "session-1", ticket: "1443", map_name: TICKET_MAP)

      error = assert_raises(HarnessError) do
        OpenImplementationFixture.call(@dir, work_order, FakeTracker.new(body: body))
      end

      assert_includes error.message, "absent check glob matched no file: `lib/brief.rb`"
      assert_empty implementations_for("session-1")
    end

    def test_open_raises_naming_the_root_relative_path_when_a_check_glob_matches_only_under_the_target_path
      ProjectScenario.new(@dir, name: "fixture").write_multi_target_project_yaml(
        targets: { widget: { path: "plugins/widget", test_path: "plugins/widget/tests", test_command: "true" } }
      )
      FileUtils.mkdir_p(File.join(@dir, "plugins", "widget", "tests"))
      File.write(File.join(@dir, "plugins", "widget", "tests", "brief_test.rb"), "def test_brief\nend\n")
      body = body_with_item("1. Cover the brief.\n   check: present `def test_brief` in `tests/brief_test.rb`")
      work_order = Implementation::WorkOrder.new(session_id: "session-1", ticket: "1443", map_name: TICKET_MAP,
                                                 target: "widget")

      error = assert_raises(HarnessError) do
        OpenImplementationFixture.call(@dir, work_order, FakeTracker.new(body: body))
      end

      assert_includes error.message, "write it from the project root as `plugins/widget/tests/brief_test.rb`"
      assert_empty implementations_for("session-1")
    end

Out of scope

  • Resolving check globs from the target path (rejected above; it would need a superseding ADR for ADR-0255).
  • A present check that names a file the ticket creates with a target-relative path. No file exists at open, so open cannot detect it; it still fails at suite-check.
  • File-existence checks in os-backlog validate-template. It has no project root, the same as for retired tests.
  • Checks that require test-file edits after the test-writer round (#865, #866).

Origin

  • Trigger: os-sdlc-required-work-check 195 during implementation 195 of #1436
  • Chain: wasted repair loops and escalation <- check glob matches no file <- repo-root glob resolution vs target-relative paths (DESIGN: ADR-0255)
  • Root candidate: #865 (covers the test-file shape only); no open ticket covers target-relative globs.
  • Where: os-sdlc required-work check and implementation-open (plugins/os-sdlc)
  • Session: 82e65b81-56fa-4c14-acd0-f225c6f57314
## Problem A typed required-work check resolves its glob from the project root (ADR-0255). A ticket author who writes a path relative to the target path (for example `lib/os_sdlc/dispatch/brief.rb` for target `plugins/os-sdlc`) gets a check that can never pass. Implementation-open accepts the body, so the defect shows only at the suite-check gate, after the red and green rounds. The programmer-repair node cannot change the ticket body, so each repair loop is wasted. The check reads the body snapshot taken at implementation-open, so a correction on the tracker does not help the running implementation. Example: implementation 195 (ticket #1436) escalated with `bound_exhausted:suite-check/fail`. The suite-check gate failed 3 times at the `required-work` step: ``` os-sdlc-required-work-check 195 glob matched no file ``` The three checks were `check: absent `work_root` in `lib/os_sdlc/dispatch/brief.rb``, and two checks with paths `tests/dispatch/brief_map_name_test.rb` and `tests/dispatch/brief_drafted_map_test.rb`. All three files existed at open time under `plugins/os-sdlc/`. Evidence: implementation 195 escalation 90; the #1436 body revision history. ## Approach Refuse at implementation-open, not resolve from the target path: ADR-0255 fixes globs to the project root and the os-backlog validator reads the same check vocabulary, so a second, target-relative path rule would be a silent fallback that changes a one-way door, while a refusal fails loudly before the red round and stays inside the ADR. Which checks need a file at open: - `absent` with a glob that matches no file from the project root: always refuse. Such a check can never pass (ADR-0255: a glob that matches no file fails the check). - Any check (`present` or `absent`) whose glob matches no file from the project root but matches a file under the selected target path: refuse, and name the root-relative path `<target path>/<glob>`. - `present` with a glob that matches no file anywhere: accept. The ticket can create that file. `TicketShape#missing` already refuses at open for file facts (retired tests not found), so the new refusal joins `#missing`. `Implementation::Open` and `Implementation::RerouteIntake` both raise on `#missing`, so both get the refusal. They pass the selected target path. An unconfigured project has the target path `.`, so the target-path rule cannot match there. The suite-check gate (`RequiredWorkCheck`) is unchanged. Required work: 1. `TicketShape::RequiredWork::Check` returns its open-time problem for a project root and a target path, by the three rules above (proven by AC 1, AC 2). 2. `TicketShape` takes a `target_path:` keyword (default `.`, the same default as `Project::Target`) and adds one `#missing` entry per typed check with a problem (proven by AC 1, AC 2). 3. `Implementation::Open#check_ticket_shape!` passes `target_path: @project.target.path` (proven by AC 2). 4. `Implementation::RerouteIntake#refuse_incomplete_shape!` passes the same target path (proven by AC 3). ## Acceptance criteria 1. Given a ticket body under `poodr-ticket-implementation` with `check: absent `work_root` in `lib/brief.rb`` and no file `lib/brief.rb` under the project root, when implementation-open runs, then it raises `HarnessError` whose message contains ``absent check glob matched no file: `lib/brief.rb` ``, and no implementation row exists. 2. Given a project whose selected target has path `plugins/widget`, a file `plugins/widget/tests/brief_test.rb`, and a body with `check: present `def test_brief` in `tests/brief_test.rb``, when implementation-open runs, then it raises `HarnessError` whose message contains ``write it from the project root as `plugins/widget/tests/brief_test.rb` ``, and no implementation row exists. 3. Given a waiting implementation and a tracker body whose check glob matches only under the target path, when reroute-request runs, then it raises `RerouteIntakeRefusedError` whose message names the root-relative path `<target path>/<glob>`. ## Owner sketch | Owner | Responsibility | Change | |---|---|---| | `OsSdlc::TicketShape::RequiredWork::Check` (`lib/os_sdlc/ticket_shape/required_work/check.rb`) | Knows its polarity and glob, so it decides whether it can pass from the project root. New `#open_problem(root:, target_path:)`: `nil` when the glob matches a file from `root`; ``"glob `<g>` matches only under the target path; write it from the project root as `<t>/<g>`"`` when it matches only under `root/target_path`; ``"absent check glob matched no file: `<g>`"`` for `absent`; `nil` for `present`. | new method | | `OsSdlc::TicketShape` (`lib/os_sdlc/ticket_shape.rb`) | Lists body defects. New `target_path:` keyword; `#missing` adds `"Required work check (<problem>): <item text>"` per typed item. | interface change (new keyword) | | `OsSdlc::Implementation::Open` (`lib/os_sdlc/implementation/open.rb`) | Refuses a body before the red round. Passes `target_path: @project.target.path`. | one argument | | `OsSdlc::Implementation::RerouteIntake` (`lib/os_sdlc/implementation/reroute_intake.rb`) | Refuses a corrected body at reroute by the same rule. Passes the same target path. | one argument | | `OsSdlc::Implementation::RequiredWorkCheck` | Suite-check judgment from the project root. | unchanged | Test doubles that stand in for an object whose interface changes: none. No test stubs `TicketShape` or `Check`; the tests below use the real `Project`, `Implementation::Open`, and `TicketShape`. `FakeTracker` stands in for the tracker, whose interface does not change. Add both tests to `plugins/os-sdlc/tests/implementation/open_ticket_shape_test.rb` (class `OsSdlc::OpenTicketShapeTest`, which already has `TICKET_MAP`, `body_with_item`, and `implementations_for`). A scratch spike at HEAD gave 2 failures, both `OsSdlc::HarnessError expected but nothing was raised.` In the second test, the project loaded as configured with target path `plugins/widget`, so the red is for the intended reason: open accepts the body. ```ruby def test_open_raises_naming_the_glob_when_an_absent_check_matches_no_file body = body_with_item("1. Drop the old reader.\n check: absent `work_root` in `lib/brief.rb`") work_order = Implementation::WorkOrder.new(session_id: "session-1", ticket: "1443", map_name: TICKET_MAP) error = assert_raises(HarnessError) do OpenImplementationFixture.call(@dir, work_order, FakeTracker.new(body: body)) end assert_includes error.message, "absent check glob matched no file: `lib/brief.rb`" assert_empty implementations_for("session-1") end def test_open_raises_naming_the_root_relative_path_when_a_check_glob_matches_only_under_the_target_path ProjectScenario.new(@dir, name: "fixture").write_multi_target_project_yaml( targets: { widget: { path: "plugins/widget", test_path: "plugins/widget/tests", test_command: "true" } } ) FileUtils.mkdir_p(File.join(@dir, "plugins", "widget", "tests")) File.write(File.join(@dir, "plugins", "widget", "tests", "brief_test.rb"), "def test_brief\nend\n") body = body_with_item("1. Cover the brief.\n check: present `def test_brief` in `tests/brief_test.rb`") work_order = Implementation::WorkOrder.new(session_id: "session-1", ticket: "1443", map_name: TICKET_MAP, target: "widget") error = assert_raises(HarnessError) do OpenImplementationFixture.call(@dir, work_order, FakeTracker.new(body: body)) end assert_includes error.message, "write it from the project root as `plugins/widget/tests/brief_test.rb`" assert_empty implementations_for("session-1") end ``` ## Out of scope - Resolving check globs from the target path (rejected above; it would need a superseding ADR for ADR-0255). - A `present` check that names a file the ticket creates with a target-relative path. No file exists at open, so open cannot detect it; it still fails at suite-check. - File-existence checks in os-backlog `validate-template`. It has no project root, the same as for retired tests. - Checks that require test-file edits after the test-writer round (#865, #866). ## Origin - Trigger: `os-sdlc-required-work-check 195` during implementation 195 of #1436 - Chain: wasted repair loops and escalation <- check glob matches no file <- repo-root glob resolution vs target-relative paths (DESIGN: ADR-0255) - Root candidate: #865 (covers the test-file shape only); no open ticket covers target-relative globs. - Where: os-sdlc required-work check and implementation-open (plugins/os-sdlc) - Session: 82e65b81-56fa-4c14-acd0-f225c6f57314
Author
Owner

Work started on branch ticket-1443 via /os-sdlc:implement (poodr-ticket-implementation).

Work started on branch ticket-1443 via /os-sdlc:implement (poodr-ticket-implementation).
Author
Owner

Resolution

Done: implementation-open and reroute refuse a typed required-work check that can never pass: an absent check whose glob matches no file, or a glob that matches only under the target path (the message names the root-relative path). A present check that matches nothing is accepted. GlobFiles is the one owner of glob-to-files matching for open and suite-check.

Evidence: main 5ac83946 (merged as 2bceeea7). Tests in open_ticket_shape_test (3 new), reroute_target_path_check_test, required_work_typed_check_test. os-sdlc suite 2800 runs, 0 failures. Rubocop clean. Implementation 197 escalated (test defect: fixture map without ticket_shape) and was hand-finished per the escalation procedure, with an opus design audit (no must-fix; should-fix items fixed).

Follow-ups: Test-file typed checks (only the test-writer may edit tests): already covered by #865 and #866 per the ticket-skeptic. None else.

## Resolution **Done:** implementation-open and reroute refuse a typed required-work check that can never pass: an absent check whose glob matches no file, or a glob that matches only under the target path (the message names the root-relative path). A present check that matches nothing is accepted. GlobFiles is the one owner of glob-to-files matching for open and suite-check. **Evidence:** main 5ac83946 (merged as 2bceeea7). Tests in open_ticket_shape_test (3 new), reroute_target_path_check_test, required_work_typed_check_test. os-sdlc suite 2800 runs, 0 failures. Rubocop clean. Implementation 197 escalated (test defect: fixture map without ticket_shape) and was hand-finished per the escalation procedure, with an opus design audit (no must-fix; should-fix items fixed). **Follow-ups:** Test-file typed checks (only the test-writer may edit tests): already covered by #865 and #866 per the ticket-skeptic. None else.
jared closed this issue 2026-10-27 19:24: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#1443
No description provided.