Route the ticket map waiting node to an in-map map-router node #885

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

Problem

ADR-0259 decision 7 makes map-router an in-map node. A reroutable map (one with entries:) declares a reroute: map-router exit on the waiting node needs-orchestrator and a map-router node with agent: map-router, enrich: [approved_maps], and gates: [reroute], and the validator requires them. Today no map has a map-router node, Brief::Facts::FACT_RESOLVERS (query/brief/facts.rb:6) has no approved_maps, and Map::Validator::CHECKS (model/map/validator.rb:6) has no such rule. check_enrich_facts! refuses an enrich name that is not a fact or an agent type, so the node cannot be added before the fact exists.

Reproduce

n/a: design change, nothing to reproduce.

Approach

  1. approved_maps fact: add "approved_maps" => :approved_maps to FACT_RESOLVERS. It returns the joined text of every *.yaml file in Map::Catalog.default.dir (#868), sorted:
Dir.glob(File.join(maps_dir, "*.yaml")).sort.map do |path|
  "Map: #{File.basename(path, ".yaml")}\n#{File.read(path)}"
end.join("\n----\n")
  1. Validator check_reroute_route! (added to CHECKS): it runs only on a map whose entries is not empty. The map must have a waiting node (#872) with a reroute edge. The edge target must be a node whose agent is map-router, whose verdict source is gate with reroute among its gates, and whose enrich includes approved_maps. Codes: :missing_reroute_route (no waiting node with a reroute edge) and :bad_map_router (the target node breaks a rule; the message names the rule).
  2. Ticket map maps/poodr-ticket-implementation.yaml: the waiting node gets edges: { reroute: map-router }. New node:
map-router:
  agent: map-router
  instructions: >-
    Choose one approved map and its entry node for this run. Run
    `os-sdlc-gate DISPATCH_ID` until it is green, then stop with your handoff.
  enrich: [approved_maps]
  verdict:
    source: gate
    gates: [reroute]
  edges:
    pass: { to: escalate, bound: 3, note: "the reroute landing replaces this edge" }
    fail: { to: escalate, bound: 3 }
    error: error
    escalate: escalate

The bounds keep check_bounded_cycles! valid (needs-orchestrator -> map-router -> escalate -> needs-orchestrator) and match the reroute cap of 3. map-router is not in entries. The reroute gate and its landing come in #873; the CLI that takes the reroute exit comes in the reroute-request ticket. Until both land, nothing routes a run to map-router.

Required work:

  1. Add the approved_maps fact — check: present "approved_maps" in plugins/os-sdlc/lib/os_sdlc/query/brief/facts.rb
  2. Add the reroute-route validator check — check: present check_reroute_route! in plugins/os-sdlc/lib/os_sdlc/model/map/validator.rb
  3. Add the map-router node to the ticket map — check: present agent: map-router in plugins/os-sdlc/maps/poodr-ticket-implementation.yaml
  4. Add the waiting node exit — check: present reroute: map-router in plugins/os-sdlc/maps/poodr-ticket-implementation.yaml

Acceptance criteria

  1. Given a map with entries: whose waiting node has no reroute edge, when it loads, then it fails with missing_reroute_route.
  2. Given a map with entries: whose reroute edge leads to a node without the reroute gate or without approved_maps in enrich, when it loads, then it fails with bad_map_router and names the missing rule.
  3. Given a map with no entries: and no map-router node, when it loads, then it is valid.
  4. Given an implementation positioned at the ticket map's map-router node, when its brief is composed, then approved_maps holds each map in the maps directory under a Map: <name> line, separated by ---- lines.
  5. Given the shipped ticket map, when it loads, then it is valid.

Owner sketch

class OsSdlc::Brief::Facts
  def approved_maps
end

class OsSdlc::Map::Validator
  def check_reroute_route!
end

Origin

  • Trigger: user ruling A3 on the map reroute design, 2026-10-01 (ADR-0259 decision 7)
  • Improvised this session: none
  • Chain: an out-of-map dispatch is misjudged in ~11 places ← map-router was outside every map ← DESIGN (docs/adr/0259)
  • Root candidate: #859
  • Where: plugins/os-sdlc/lib/os_sdlc/model/map/validator.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: #870, #872, #869

## Problem ADR-0259 decision 7 makes map-router an in-map node. A reroutable map (one with `entries:`) declares a `reroute: map-router` exit on the waiting node `needs-orchestrator` and a `map-router` node with `agent: map-router`, `enrich: [approved_maps]`, and `gates: [reroute]`, and the validator requires them. Today no map has a map-router node, `Brief::Facts::FACT_RESOLVERS` (query/brief/facts.rb:6) has no `approved_maps`, and `Map::Validator::CHECKS` (model/map/validator.rb:6) has no such rule. `check_enrich_facts!` refuses an enrich name that is not a fact or an agent type, so the node cannot be added before the fact exists. ## Reproduce n/a: design change, nothing to reproduce. ## Approach 1. `approved_maps` fact: add `"approved_maps" => :approved_maps` to `FACT_RESOLVERS`. It returns the joined text of every `*.yaml` file in `Map::Catalog.default.dir` (#868), sorted: ```ruby Dir.glob(File.join(maps_dir, "*.yaml")).sort.map do |path| "Map: #{File.basename(path, ".yaml")}\n#{File.read(path)}" end.join("\n----\n") ``` 2. Validator `check_reroute_route!` (added to `CHECKS`): it runs only on a map whose `entries` is not empty. The map must have a waiting node (#872) with a `reroute` edge. The edge target must be a node whose agent is `map-router`, whose verdict source is `gate` with `reroute` among its gates, and whose `enrich` includes `approved_maps`. Codes: `:missing_reroute_route` (no waiting node with a `reroute` edge) and `:bad_map_router` (the target node breaks a rule; the message names the rule). 3. Ticket map `maps/poodr-ticket-implementation.yaml`: the waiting node gets `edges: { reroute: map-router }`. New node: ```yaml map-router: agent: map-router instructions: >- Choose one approved map and its entry node for this run. Run `os-sdlc-gate DISPATCH_ID` until it is green, then stop with your handoff. enrich: [approved_maps] verdict: source: gate gates: [reroute] edges: pass: { to: escalate, bound: 3, note: "the reroute landing replaces this edge" } fail: { to: escalate, bound: 3 } error: error escalate: escalate ``` The bounds keep `check_bounded_cycles!` valid (needs-orchestrator -> map-router -> escalate -> needs-orchestrator) and match the reroute cap of 3. map-router is not in `entries`. The `reroute` gate and its landing come in #873; the CLI that takes the `reroute` exit comes in the reroute-request ticket. Until both land, nothing routes a run to map-router. Required work: 1. Add the approved_maps fact — check: present `"approved_maps"` in `plugins/os-sdlc/lib/os_sdlc/query/brief/facts.rb` 2. Add the reroute-route validator check — check: present `check_reroute_route!` in `plugins/os-sdlc/lib/os_sdlc/model/map/validator.rb` 3. Add the map-router node to the ticket map — check: present `agent: map-router` in `plugins/os-sdlc/maps/poodr-ticket-implementation.yaml` 4. Add the waiting node exit — check: present `reroute: map-router` in `plugins/os-sdlc/maps/poodr-ticket-implementation.yaml` ## Acceptance criteria 1. Given a map with `entries:` whose waiting node has no `reroute` edge, when it loads, then it fails with `missing_reroute_route`. 2. Given a map with `entries:` whose `reroute` edge leads to a node without the `reroute` gate or without `approved_maps` in `enrich`, when it loads, then it fails with `bad_map_router` and names the missing rule. 3. Given a map with no `entries:` and no map-router node, when it loads, then it is valid. 4. Given an implementation positioned at the ticket map's map-router node, when its brief is composed, then `approved_maps` holds each map in the maps directory under a `Map: <name>` line, separated by `----` lines. 5. Given the shipped ticket map, when it loads, then it is valid. ## Owner sketch ```ruby class OsSdlc::Brief::Facts def approved_maps end class OsSdlc::Map::Validator def check_reroute_route! end ``` ## Origin - Trigger: user ruling A3 on the map reroute design, 2026-10-01 (ADR-0259 decision 7) - Improvised this session: none - Chain: an out-of-map dispatch is misjudged in ~11 places ← map-router was outside every map ← DESIGN (docs/adr/0259) - Root candidate: #859 - Where: plugins/os-sdlc/lib/os_sdlc/model/map/validator.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: #870, #872, #869
Author
Owner

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

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

Resolution

Done: The ticket map waiting node routes to an in-map map-router node; Node#map_router_gap and Map::Validator::RerouteRoute enforce the map-router node and reroute-route rules; Brief::Facts#approved_maps supplies the approved_maps fact.

Evidence: main b9896f57 (Runner commit, implementation 1 implementation_complete, 12 dispatches, 1 retry; required-work and suite gates green), 34c5b4c2 History row; bin/test on main: 9 suites passed.

Follow-ups: none

## Resolution **Done:** The ticket map waiting node routes to an in-map map-router node; Node#map_router_gap and Map::Validator::RerouteRoute enforce the map-router node and reroute-route rules; Brief::Facts#approved_maps supplies the approved_maps fact. **Evidence:** main b9896f57 (Runner commit, implementation 1 implementation_complete, 12 dispatches, 1 retry; required-work and suite gates green), 34c5b4c2 History row; bin/test on main: 9 suites passed. **Follow-ups:** none
jared closed this issue 2026-10-01 17:51:47 +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#885
No description provided.