Files

329 lines
14 KiB
JSON
Raw Permalink Normal View History

{
"$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" }
}
}
}
}
}
}