Add os-sdlc-reroute-request to move a waiting run to map-router #886

Closed
opened 2026-10-01 15:26:55 +00:00 by jared · 2 comments
Owner

Problem

ADR-0259 decisions 8 and 10 let the orchestrator move a waiting run to map-router: os-sdlc-reroute-request IMPL --situation .. --misfit .. writes a handoff that targets map-router and takes the waiting node's reroute exit. No such CLI exists. Verdict::ALL (model/verdict.rb:9) has no reroute. HandoffContent::VALID_VERDICTS (parser/handoff_content.rb) is pass fail error and does not require situation or misfit. Implementation::Transition#call (command/implementation/transition.rb) needs a dispatch, and the orchestrator request has none.

Reproduce

n/a: design change, nothing to reproduce.

Approach

  1. Add REROUTE = "reroute" to Verdict::ALL with reroute?.
  2. HandoffContent: accept verdict reroute; when the verdict is reroute, require situation and misfit (Malformed codes :situation, :misfit). Slice 3 reuses this contract for the change-auditor.
  3. bin/os-sdlc-reroute-request IMPLEMENTATION_ID --situation TEXT --misfit TEXT, Boot command reroute-request, same shape as bin/os-sdlc-required-work-check. Both flags are required.
  4. It refuses, naming the state and position, unless the implementation is active and its position is a waiting node (#872).
  5. It refuses, naming dispatch_cap:<cap>, when the dispatch budget is spent: Routing#spent would route escalate, and the waiting node has no escalate edge. ADR-0152 counts all dispatches of the implementation.
  6. It writes a handoff through HandoffContent.parse!: implementation.add_handoff(created_by: nil, target_agent_type: "map-router", content:) with content summary, verdict: reroute, situation, misfit. created_by nil marks the orchestrator.
  7. It applies the reroute edge through Implementation::Transition (ADR-0168; ADR-0259 corrections). Transition accepts a request with no dispatch: it skips the AlreadyRouted check, mark_routed!, and the handoff target stamp. The run is then positioned at map-router.
  8. It prints the NextStep dispatch payload for map-router. The map-router brief carries the handoff content through Brief#handoff_json.

Required work:

  1. Add the reroute verdict — check: present REROUTE = "reroute" in plugins/os-sdlc/lib/os_sdlc/model/verdict.rb
  2. Require situation and misfit on a reroute handoff — check: present misfit in plugins/os-sdlc/lib/os_sdlc/parser/handoff_content.rb
  3. Add the CLI — check: present reroute-request in plugins/os-sdlc/bin/os-sdlc-reroute-request

Acceptance criteria

  1. Given a run waiting at needs-orchestrator, when os-sdlc-reroute-request runs with a situation and a misfit, then the run is positioned at map-router, a handoff targeted at map-router with no creator holds the situation and misfit, and the output is a dispatch payload for agent map-router.
  2. Given that payload, when the map-router brief is composed, then its handoff content holds the situation and the misfit.
  3. Given a run positioned at an agent node, when os-sdlc-reroute-request runs, then it refuses, names the position, and writes no handoff.
  4. Given a waiting run, when os-sdlc-reroute-request runs without --misfit, then it refuses and names the missing flag.
  5. Given handoff content with verdict reroute and no situation, when it is parsed, then it fails with situation.
  6. Given a waiting run whose dispatch budget is spent, when os-sdlc-reroute-request runs, then it refuses, names dispatch_cap, and writes no handoff.

Owner sketch

class OsSdlc::RerouteRequest
  def initialize(root:, implementation_id:, situation:, misfit:)
  def call
end

class OsSdlc::Implementation::Transition
  def call(dispatch, verdict, root: nil)   # dispatch may be nil for the orchestrator request
end

Origin

  • Trigger: user ruling A3 on the map reroute design, 2026-10-01 (ADR-0259 decisions 8, 10)
  • Improvised this session: none
  • Chain: the orchestrator hand-finishes misfit runs ← no command moves a waiting run to map-router ← DESIGN (docs/adr/0258, docs/adr/0259)
  • Root candidate: #859
  • Where: plugins/os-sdlc/lib/os_sdlc/command/implementation/transition.rb
  • Session: 55a56279-83ee-47d5-a21e-ee67f9e28abd
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/55a56279-83ee-47d5-a21e-ee67f9e28abd.jsonl

Parent: #859
Blocked by: #885

## Problem ADR-0259 decisions 8 and 10 let the orchestrator move a waiting run to map-router: `os-sdlc-reroute-request IMPL --situation .. --misfit ..` writes a handoff that targets map-router and takes the waiting node's `reroute` exit. No such CLI exists. `Verdict::ALL` (model/verdict.rb:9) has no `reroute`. `HandoffContent::VALID_VERDICTS` (parser/handoff_content.rb) is `pass fail error` and does not require `situation` or `misfit`. `Implementation::Transition#call` (command/implementation/transition.rb) needs a dispatch, and the orchestrator request has none. ## Reproduce n/a: design change, nothing to reproduce. ## Approach 1. Add `REROUTE = "reroute"` to `Verdict::ALL` with `reroute?`. 2. `HandoffContent`: accept verdict `reroute`; when the verdict is `reroute`, require `situation` and `misfit` (`Malformed` codes `:situation`, `:misfit`). Slice 3 reuses this contract for the change-auditor. 3. `bin/os-sdlc-reroute-request IMPLEMENTATION_ID --situation TEXT --misfit TEXT`, Boot command `reroute-request`, same shape as `bin/os-sdlc-required-work-check`. Both flags are required. 4. It refuses, naming the state and position, unless the implementation is active and its position is a waiting node (#872). 5. It refuses, naming `dispatch_cap:<cap>`, when the dispatch budget is spent: `Routing#spent` would route `escalate`, and the waiting node has no escalate edge. ADR-0152 counts all dispatches of the implementation. 6. It writes a handoff through `HandoffContent.parse!`: `implementation.add_handoff(created_by: nil, target_agent_type: "map-router", content:)` with content `summary`, `verdict: reroute`, `situation`, `misfit`. `created_by` nil marks the orchestrator. 7. It applies the `reroute` edge through `Implementation::Transition` (ADR-0168; ADR-0259 corrections). Transition accepts a request with no dispatch: it skips the AlreadyRouted check, `mark_routed!`, and the handoff target stamp. The run is then positioned at map-router. 8. It prints the NextStep dispatch payload for map-router. The map-router brief carries the handoff content through `Brief#handoff_json`. Required work: 1. Add the reroute verdict — check: present `REROUTE = "reroute"` in `plugins/os-sdlc/lib/os_sdlc/model/verdict.rb` 2. Require situation and misfit on a reroute handoff — check: present `misfit` in `plugins/os-sdlc/lib/os_sdlc/parser/handoff_content.rb` 3. Add the CLI — check: present `reroute-request` in `plugins/os-sdlc/bin/os-sdlc-reroute-request` ## Acceptance criteria 1. Given a run waiting at needs-orchestrator, when `os-sdlc-reroute-request` runs with a situation and a misfit, then the run is positioned at map-router, a handoff targeted at map-router with no creator holds the situation and misfit, and the output is a dispatch payload for agent `map-router`. 2. Given that payload, when the map-router brief is composed, then its handoff content holds the situation and the misfit. 3. Given a run positioned at an agent node, when `os-sdlc-reroute-request` runs, then it refuses, names the position, and writes no handoff. 4. Given a waiting run, when `os-sdlc-reroute-request` runs without `--misfit`, then it refuses and names the missing flag. 5. Given handoff content with verdict `reroute` and no `situation`, when it is parsed, then it fails with `situation`. 6. Given a waiting run whose dispatch budget is spent, when `os-sdlc-reroute-request` runs, then it refuses, names `dispatch_cap`, and writes no handoff. ## Owner sketch ```ruby class OsSdlc::RerouteRequest def initialize(root:, implementation_id:, situation:, misfit:) def call end class OsSdlc::Implementation::Transition def call(dispatch, verdict, root: nil) # dispatch may be nil for the orchestrator request end ``` ## Origin - Trigger: user ruling A3 on the map reroute design, 2026-10-01 (ADR-0259 decisions 8, 10) - Improvised this session: none - Chain: the orchestrator hand-finishes misfit runs ← no command moves a waiting run to map-router ← DESIGN (docs/adr/0258, docs/adr/0259) - Root candidate: #859 - Where: plugins/os-sdlc/lib/os_sdlc/command/implementation/transition.rb - Session: 55a56279-83ee-47d5-a21e-ee67f9e28abd - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/55a56279-83ee-47d5-a21e-ee67f9e28abd.jsonl Parent: #859 Blocked by: #885
Author
Owner

Work started on branch ticket-886 (os-sdlc pipeline, map poodr-ticket-implementation).

Work started on branch ticket-886 (os-sdlc pipeline, map poodr-ticket-implementation).
Author
Owner

Resolution

Done: os-sdlc-reroute-request moves a run waiting at needs-orchestrator to the map-router node; it refuses with a reason when the run is not waiting or the dispatch cap is spent; HandoffContent and Verdict accept reroute. Deviation: the Runner commit left the refactorer's nested Implementation::RerouteRequest, its Refused value, routing.rb and dispatch_budget.rb in dirty_paths; committed by hand as 6f02d0b2 (the suite had run with them).

Evidence: main 4dd5a54a (Runner commit, implementation 2 implementation_complete, 14 dispatches, 2 retries), 6f02d0b2, 3b74a794 History row; bin/test on main: 9 suites passed; the reroute command is in the refreshed plugin cache.

Follow-ups: none

## Resolution **Done:** os-sdlc-reroute-request moves a run waiting at needs-orchestrator to the map-router node; it refuses with a reason when the run is not waiting or the dispatch cap is spent; HandoffContent and Verdict accept reroute. Deviation: the Runner commit left the refactorer's nested Implementation::RerouteRequest, its Refused value, routing.rb and dispatch_budget.rb in dirty_paths; committed by hand as 6f02d0b2 (the suite had run with them). **Evidence:** main 4dd5a54a (Runner commit, implementation 2 implementation_complete, 14 dispatches, 2 retries), 6f02d0b2, 3b74a794 History row; bin/test on main: 9 suites passed; the reroute command is in the refreshed plugin cache. **Follow-ups:** none
jared closed this issue 2026-10-01 18:07:44 +00:00
jared referenced this issue from a commit 2026-10-01 18:24:32 +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.

Reference
jared/cc-os#886
No description provided.