7Versioned escalation contract for round-close failures.
11Render a stable, machine-readable escalation document (OI-218, OI-316)
12whenever a round-close step stops and needs operator attention.
16- Enumerate the stable error-code set for round-close stops.
17- Carry a ``resume_command`` except where recovery is rollback-only.
18- Serialize deterministically for logs and operator prompts.
24 L2 - escalation raised
25 L3 - code and resume-command details
30- ``STAGING_BRANCH_DIVERGED`` always renders an empty ``resume_command``.
31- The schema is versioned; consumers branch on ``schema_version``.
35- oc_diagnostics (structured debug logging via _dbg)
36- dataclasses (the frozen Escalation record)
37- enum (the EscalationCode enum)
39from __future__
import annotations
41from dataclasses
import dataclass, field
43from typing
import Mapping
45from oc_diagnostics
import _dbg
48_dbg(
"OC_CHAT.MAIN",
"module",
"loaded", 4)
50ESCALATION_SCHEMA_VERSION =
"1.0"
54 """Stable round-close escalation codes."""
56 STAGING_BRANCH_DIVERGED =
"STAGING_BRANCH_DIVERGED"
57 MERGE_CONFLICT =
"MERGE_CONFLICT"
58 MANUAL_MERGE_REQUIRED =
"MANUAL_MERGE_REQUIRED"
59 TEST_FAILED =
"TEST_FAILED"
60 LINT_FAILED =
"LINT_FAILED"
61 PREFLIGHT_FAILED =
"PREFLIGHT_FAILED"
62 LOCK_HELD =
"LOCK_HELD"
63 ROUND_STATE =
"ROUND_STATE"
64 CLEANUP_FAILED =
"CLEANUP_FAILED"
65 ROADMAP_BUMP_FAILED =
"ROADMAP_BUMP_FAILED"
66 ROADMAP_UNTRACKED_EDIT =
"E_ROADMAP_UNTRACKED_EDIT"
71NON_RESUMABLE_CODES = frozenset({EscalationCode.STAGING_BRANCH_DIVERGED})
74@dataclass(frozen=True)
76 """A versioned, serializable round-close escalation document."""
82 resume_command: str |
None =
None
83 details: Mapping[str, object] = field(default_factory=dict)
84 schema_version: str = ESCALATION_SCHEMA_VERSION
87 """Return a deterministic, JSON-serializable mapping."""
90 resume =
"" if self.code
in NON_RESUMABLE_CODES
else (self.
resume_command or "")
91 _dbg(
"OC_CHAT.MAIN", func, f
"render {self.code.value}", 4)
94 "kind":
"round_close_escalation",
95 "code": self.code.value,
99 "resume_command": resume,
105 """Carries an :class:`Escalation` payload up to the orchestrator surface."""
107 def __init__(self, escalation: Escalation) ->
None:
109 super().
__init__(f
"{escalation.code.value}: {escalation.message}")
113 code: EscalationCode,
118 resume_command: str |
None =
None,
119 details: Mapping[str, object] |
None =
None,
121 """Build an :class:`Escalation`, enforcing the non-resumable policy."""
123 func =
"make_escalation"
124 effective_resume =
None if code
in NON_RESUMABLE_CODES
else resume_command
125 _dbg(
"OC_CHAT.MAIN", func, f
"build {code.value} round={round_no}", 2)
131 resume_command=effective_resume,
132 details=dict(details
or {}),
137 """Return the canonical resume command string for a round."""
139 func =
"resume_command_for"
140 _dbg(
"OC_CHAT.MAIN", func, f
"resume cmd round={round_no}", 4)
141 base = f
"oct agent round resume {round_no}"
142 return base
if slot
is None else f
"{base} --as {slot}"
dict[str, object] to_dict(self)
None __init__(self, Escalation escalation)
Escalation make_escalation(EscalationCode code, *, int round_no, str phase, str message, str|None resume_command=None, Mapping[str, object]|None details=None)
str resume_command_for(int round_no, *, str|None slot=None)