{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eightarms.net/octopus-workflow/schemas/workflow-routing.schema.json", "title": "Workflow Routing Table", "description": "Schema for workflow-routing.yaml 鈥?type-driven (Kind/*) process selection. Referenced by rules/workflow-routing.md and the auto-approve rule. When this schema and the rules markdown disagree, the YAML (validated by this schema) is authoritative.", "type": "object", "additionalProperties": false, "required": ["version", "default", "routes"], "properties": { "$schema": { "type": "string" }, "version": { "type": "integer", "const": 1 }, "default": { "$ref": "#/$defs/route" }, "routes": { "type": "object", "additionalProperties": { "$ref": "#/$defs/route" }, "description": "Keys are Kind/* label names, e.g. Kind/Bug, Kind/Feature." }, "preflight": { "$ref": "#/$defs/preflightPolicy" }, "dag": { "$ref": "#/$defs/dag" }, "filing": { "$ref": "#/$defs/filing" }, "review": { "$ref": "#/$defs/review" } }, "$defs": { "stage": { "type": "string", "description": "A pipeline stage identifier 鈥?the 5 live gates (post-[org-internal #3072] phase 3, 2026-08-21): review-dag, review-code, verify, audit-process, merge-pr. Production-phase names (requirements, design, roadmap, implement) and the 7 retired stage ids (roadmap-exit, review-roadmap, requirements-exit, design-exit, review-design-space, review-iteration-plan, plan-iterations) are no longer valid anywhere 鈥?the sizing block that consumed the phase names was retired the same ruling.", "enum": ["review-dag", "review-code", "verify", "audit-process", "merge-pr"] }, "entry": { "type": "object", "additionalProperties": false, "properties": { "skill": { "type": ["string", "null"], "enum": ["implement", "review-artifact", "review-code", "verify", "analyze-dag", null], "description": "Skill name to enter, or null for natural-language routing. The legacy roadmap / requirements-elicitation / design / plan-iterations entries were removed when those skills were archived ([org-internal #3072] phase 3, 2026-08-21 - the instance archive)." }, "mode": { "type": ["string", "null"], "enum": ["bugfix", "refactor", "port", null], "description": "Skill mode, or null." } } }, "stageList": { "type": "array", "items": { "$ref": "#/$defs/stage" } }, "route": { "type": "object", "additionalProperties": false, "properties": { "entry": { "$ref": "#/$defs/entry" }, "skip": { "$ref": "#/$defs/stageList" }, "keep_gates": { "$ref": "#/$defs/stageList" }, "preflight": { "type": "array", "items": { "$ref": "#/$defs/preflightItem" }, "description": "Evidence-based producer pre-flight checklist ([org-internal #2599]) 鈥?landed by a human from retrospective PRE-FLIGHT PROPOSAL rows. Absent/empty = no injection. Cap is governed by preflight.max_items (policy), not the schema." }, "notes": { "type": "string" }, "effort": { "type": "string", "enum": ["low", "high", "max"], "description": "Reasoning-effort hint for this route (llm-latency phase 2): maps onto the active model's variant table when it exposes one (GLM-5.2+ low/high/max); fail-open otherwise. Reserve `low` for genuinely lightweight routes (direct-edit, no pipeline) 鈥?reasoning dominates GLM-5.3 generation latency." } } }, "preflightPolicy": { "type": "object", "additionalProperties": false, "description": "Thresholds for the retro 鈫?routes.{Kind}.preflight evidence loop ([org-internal #2599]). Authoritative values live here; the retrospective consults this block, it does not restate the numbers.", "properties": { "max_items": { "type": "integer", "minimum": 1 }, "min_sample": { "type": "integer", "minimum": 0 }, "consecutive_recur": { "type": "integer", "minimum": 1 }, "aging_consecutive_clean": { "type": "integer", "minimum": 1 } } }, "preflightItem": { "type": "object", "additionalProperties": false, "required": ["id", "item", "evidence"], "properties": { "id": { "type": "string", "description": "Stable slug, e.g. cor-unhandled-null." }, "item": { "type": "string", "description": "One checklist line the Producer verifies before implementing." }, "evidence": { "type": "string", "description": "Retro reference justifying the item, e.g. 'retro [org-internal #2599]: COR 脳 unhandled-null, 5/8 first-round FAILs on Kind/Bug'." }, "added_cycle": { "type": "string", "description": "Cycle id when landed, e.g. 2026-08. Drop-oldest beyond preflight.max_items sorts on this." } } }, "filing": { "type": "object", "additionalProperties": false, "description": "Filing policy (绔嬫/鐧昏绛栫暐). sprint-mode ([org-internal #3007]): when true, verify Phase 5.5 promotes registry rows to tickets in sprint mode only. work-ticket-wip-cap ([org-internal #3005] G3): open non-TD work tickets beyond this count require scheduling evidence, else they stay registry rows.", "properties": { "sprint-mode": { "type": "boolean", "description": "Sprint-mode filing downgrade switch ([org-internal #3007])." }, "work-ticket-wip-cap": { "type": "integer", "minimum": 0, "description": "WIP cap on open non-TD work tickets (Kind/* without assignee) before new filings require scheduling evidence ([org-internal #3005] G3)." } } }, "review": { "type": "object", "additionalProperties": false, "description": "Review round budget (process-diet P0b, [org-internal #3567]/TD-564): a tail cut, not the norm 鈥?at budget without convergence, STOP; residual findings flow to the TD registry. High risk = a BLOCKER survived a round or the diff touches a frozen cross-session contract.", "required": ["max_rounds"], "properties": { "max_rounds": { "type": "object", "additionalProperties": false, "required": ["default", "high_risk"], "properties": { "default": { "type": "integer" }, "high_risk": { "type": "integer" } } } } }, "dag": { "type": "object", "additionalProperties": false, "required": ["route", "task_route", "ticket_creation", "verify_milestone", "size_derivation", "review_depth"], "properties": { "route": { "$ref": "#/$defs/dagRoute" }, "task_route": { "$ref": "#/$defs/dagTaskRoute" }, "ticket_creation": { "$ref": "#/$defs/dagTicketCreation" }, "verify_milestone": { "$ref": "#/$defs/dagVerifyMilestone" }, "size_derivation": { "$ref": "#/$defs/dagSizeDerivation" }, "review_depth": { "$ref": "#/$defs/dagReviewDepth" } } }, "dagRoute": { "type": "object", "additionalProperties": false, "required": ["entry", "skip", "keep_gates", "single_gate"], "properties": { "entry": { "$ref": "#/$defs/entry" }, "skip": { "$ref": "#/$defs/stageList" }, "keep_gates": { "$ref": "#/$defs/stageList" }, "single_gate": { "$ref": "#/$defs/dagSingleGate" }, "preflight": { "type": "array", "items": { "$ref": "#/$defs/preflightItem" }, "description": "Evidence-based pre-flight checklist for the DAG route ([org-internal #2905] 鏂规 3) 鈥?same item shape as routes.{Kind}.preflight ([org-internal #2599]). Landed by a human from retrospective PRE-FLIGHT PROPOSAL rows, including the 'REQ 脳 late-discovery' root cause (requirements found only after the DAG froze: DAG oversize signals, demo-period feedback). Consumed by analyze-dag (the route's entry skill) before decomposition. Absent/empty = no injection. Optional 鈥?deliberately NOT in dagRoute.required (spec-02 搂2.8 frozen required array unchanged). Cap governed by preflight.max_items (policy), not the schema." } } }, "dagTaskRoute": { "type": "object", "additionalProperties": false, "required": ["entry", "skip", "keep_gates", "inherit"], "properties": { "entry": { "$ref": "#/$defs/entry" }, "skip": { "$ref": "#/$defs/stageList" }, "keep_gates": { "$ref": "#/$defs/stageList" }, "inherit": { "type": "string", "enum": ["parent_dag"] } } }, "dagSingleGate": { "type": "object", "additionalProperties": false, "required": ["id", "dimensions", "replaces", "depth_from", "never_trim"], "properties": { "id": { "type": "string", "enum": ["review-dag"] }, "dimensions": { "type": "array", "items": { "type": "string", "enum": ["TOPO", "REQMAP", "RELEASE"] }, "uniqueItems": true, "minItems": 3, "maxItems": 3 }, "replaces": { "type": "array", "items": { "type": "string" }, "description": "Historical documentation of which legacy gates the single gate replaced ([org-internal #3072] phase 3 retired them) 鈥?free-form strings, not the live stage vocabulary." }, "depth_from": { "type": "string", "enum": ["size_derivation"] }, "never_trim": { "type": "boolean" } } }, "dagTicketCreation": { "type": "object", "additionalProperties": false, "required": ["per_node", "milestone_no_ticket", "inherit_parent", "parent_aggregator"], "properties": { "per_node": { "type": "boolean" }, "milestone_no_ticket": { "type": "boolean" }, "inherit_parent": { "type": "array", "items": { "type": "string", "enum": ["Kind/Epic", "Kind/Feature"] }, "uniqueItems": true, "minItems": 1, "description": "Ticket kinds whose DAG children reference them as ## 鐖剁骇 / Parent ([org-internal #3061] Phase 2 / TD-388: Kind/Feature added alongside Kind/Epic)." }, "parent_aggregator": { "type": "boolean" } } }, "dagVerifyMilestone": { "type": "object", "additionalProperties": false, "required": ["weld_at_convergence", "milestone_skill", "integration_trigger"], "properties": { "weld_at_convergence": { "type": "boolean" }, "milestone_skill": { "type": "string", "enum": ["verify"] }, "integration_trigger": { "type": "string", "enum": ["all_incoming_done_and_green"] } } }, "dagSizeDerivation": { "type": "object", "additionalProperties": false, "required": ["enabled", "thresholds", "size_labels", "oversize_signals"], "properties": { "enabled": { "type": "boolean" }, "formula": { "type": "string" }, "thresholds": { "type": "object", "additionalProperties": false, "properties": { "node_count": { "type": "object", "additionalProperties": false, "properties": { "d1": { "type": "integer" }, "d2": { "type": "integer" }, "d3": { "type": "integer" } } }, "cross_session_edge_count": { "type": "object", "additionalProperties": false, "properties": { "d1": { "type": "integer" }, "d3": { "type": "integer" } } }, "contract_change_surface": { "type": "object", "additionalProperties": false, "properties": { "none": { "type": "string" }, "additive": { "type": "string" }, "breaking": { "type": "string" } } } } }, "size_labels": { "type": "string" }, "oversize_signals": { "type": "array", "items": { "$ref": "#/$defs/dagOversizeSignal" } } } }, "dagOversizeSignal": { "type": "object", "additionalProperties": false, "required": ["id", "trigger"], "properties": { "id": { "type": "string", "enum": [ "node_split", "new_cross_session_edge", "draft_contract_breaking", "frozen_contract_breaking", "node_scope_drift" ] }, "trigger": { "type": "string" } } }, "dagReviewDepth": { "type": "object", "additionalProperties": false, "required": ["D1", "D2", "D3", "D4"], "properties": { "D1": { "type": "object", "additionalProperties": false, "required": ["reviewers", "rounds", "dim_split"], "properties": { "reviewers": { "type": "integer" }, "rounds": { "type": "integer" }, "dim_split": { "type": "string" } } }, "D2": { "type": "object", "additionalProperties": false, "required": ["reviewers", "rounds", "dim_split"], "properties": { "reviewers": { "type": "integer" }, "rounds": { "type": "integer" }, "dim_split": { "type": "string" } } }, "D3": { "type": "object", "additionalProperties": false, "required": ["reviewers", "rounds", "dim_split"], "properties": { "reviewers": { "type": "integer" }, "rounds": { "type": "integer" }, "dim_split": { "type": "string" } } }, "D4": { "type": "object", "additionalProperties": false, "required": ["reviewers", "rounds", "dim_split"], "properties": { "reviewers": { "type": "integer" }, "rounds": { "type": "integer" }, "dim_split": { "type": "string" } } } } } } }