Make escalation a waiting position at needs-orchestrator #872
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Reference
jared/cc-os#872
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
ADR-0259 decisions 1, 3, 4 and 5 make escalation a waiting position, not a closing stamp. Today
LifecycleStamps::ALL(model/lifecycle_stamps.rb:5) listsescalated_at: :escalated, so an escalated run is closed and no reroute can continue it.Landing#land!(command/implementation/landing.rb:15) terminates the run when the route reaches a terminal with outcomeescalation.Map::Validator::TERMINAL_OUTCOMES(model/map/validator.rb:11) acceptsescalation, andNodeCheck#check_escalate_route!requires every agent node to reach a terminal with that outcome.NextStep(pipeline/next_step.rb) emits the escalation as a terminal payload throughTerminalPayload.Reproduce
n/a: design change, nothing to reproduce.
Approach
escalated_atfromLifecycleStamps::ALLand from theimplementationstable (adapter/db.rb:315); bumpSCHEMA_VERSION(ADR-0129/0155; do not bump while a run is live). RemoveLifecycle#escalate!and#escalated?. The closing stamps arecompleted_at,abandoned_at,failed_at;failed_reasonmeans failure only. UpdateTERMINAL_STAMPSintests/adapter/db_migration_test.rb.Map::NodeSpecreadswaiting: true;Map::Node#waiting?. A waiting node has no agent and no verdict. Its edges may be empty (the reroute exit comes in #885).TERMINAL_OUTCOMESbecomesimplementation_complete implementation_failed.NodeGuardChecksexempts a waiting node from the single-default-edge rule.check_dead_pocket!skips waiting nodes.check_escalate_route!requires the escalate edge of every agent node to reach a waiting node (through routing nodes); code:missing_escalate_route.TransitWalk#dispatchable?stops at a waiting node.Landing#land!: when the decision node is a waiting node, it adds the Escalation row (#884) and callsadvance!(position:). It does not terminate the run.NextStep: when the run is active and its position is a waiting node, it returnsImplementation::EscalationPayload:type: "escalation",node,reasonandescalation_idfromcurrent_escalation,state_dump,on_failure, plusIdentityandsummary. This applies after the transition and on every later poll; no dispatch opens.TerminalPayloadloses its escalation branch.maps/poodr-ticket-implementation.yaml,needs-orchestratorleavesterminals:and becomes the nodeneeds-orchestrator: { agent: null, waiting: true, edges: {} }. Convert the fixture maps undertests/fixtures/maps/that useneeds-orchestrator: escalationthe same way; keep one fixture with outcomeescalationfor AC 4.The readers that refuse closed runs stay unchanged (ADR-0259):
start_subagent.rb:55,completion_intake/lookup.rb:76,Transition#refuse_unroutable!,Dispatch#derived_state_from_owner.abandon_unfinished!now abandons a waiting run; ADR-0259 accepts this.Required work:
escalated_atinplugins/os-sdlc/lib/os_sdlc/model/lifecycle_stamps.rbescalated_atinplugins/os-sdlc/lib/os_sdlc/adapter/db.rbimplementation_failed escalationinplugins/os-sdlc/lib/os_sdlc/model/map/validator.rbwaitinginplugins/os-sdlc/lib/os_sdlc/model/map/node_spec.rbneeds-orchestrator: escalationinplugins/os-sdlc/maps/*.yamlclass EscalationPayloadinplugins/os-sdlc/lib/os_sdlc/presenter/**/*.rbescalationinplugins/os-sdlc/lib/os_sdlc/presenter/implementation/terminal_payload.rbAcceptance criteria
needs-orchestrator, one escalations row exists, and the payload hastype: escalation,node: needs-orchestrator, the row reason, the row id asescalation_id, and astate_dump.needs-orchestrator, when NextStep runs again, then it returns the escalation payload and opens no dispatch.needs-orchestrator, when implementation-open runs for the same session, then the waiting run is abandoned.escalation, when it loads, then it fails withunknown_terminal_outcome.missing_escalate_route.needs-orchestratoris a waiting node.Owner sketch
Origin
Parent: #859
Blocked by: #883, #884
jared referenced this issue2026-10-01 14:26:18 +00:00
Derive escalated state so a reroute row reactivates the runto Make escalation a waiting position at needs-orchestratorWork started on branch ticket-872 (os-sdlc pipeline, map poodr-ticket-implementation).
Implementation 1 stopped at the test-writer: diff-test fails with LoadError because DiffTestPlan requires the changed YAML fixture maps (gate defect, not this ticket). Captured #888; implementing it first. The test-writer work is kept as WIP commit 58f1eb3f on branch ticket-872; #872 re-opens after #888 merges.
Resolution
Done: Escalation is a waiting position at needs-orchestrator (Node#waiting?); the landing records the Escalation row and advances; NextStep renders EscalationPayload; escalated_at removed, failed_reason is failure only; fixture maps converted; SCHEMA_VERSION 29. Deviations: implementation 1 stopped at the test-writer because diff-test required YAML fixtures (gate defect) -> captured and implemented #888 first, kept the test work (WIP 58f1eb3f), re-opened; in run 2 the orchestrator hand-fixed tests/support/repeated_next_row_check.rb (asserted the removed failed_reason; now checks the escalations row) after programmer-repair reported it needed a test edit; the Runner commit left 27 test/fixture paths in dirty_paths, committed by hand as
8425ff91.Evidence: main
a3701b71(Runner commit, implementation 1 implementation_complete, 12 dispatches, 1 retry; required-work and suite gates green),8425ff91, History row; bin/test on main: 9 suites passed.Follow-ups: #888 captured and closed. Dropped: programmer note that check_dead_pocket! also accepts a node that reaches a waiting node - consistent with ADR-0259 waiting nodes; the verifying design session can judge.