11"""Clear, actionable diagnosis of API and task failures.
22
33The goal is simple: tell the user *what went wrong and what to do next*. The
4- upstream API already carries the signal for that — ``ErrorCategory`` on cluster
5- errors, ``ComponentFailureInfo`` ( with log tails) on failed deployment tasks,
6- ``HTTPValidationError`` on bad input, ``error_type`` on task results — but a bare
4+ upstream API already carries the signal for that ( ``ErrorCategory`` on cluster
5+ errors, ``ComponentFailureInfo`` with log tails on failed deployment tasks,
6+ ``HTTPValidationError`` on bad input, ``error_type`` on task results), but a bare
77``HTTP 500`` / ``Task failed`` string throws it away.
88
99This module turns those raw signals into a :class:`Diagnosis`: a plain-language
@@ -39,15 +39,15 @@ class Fault(StrEnum):
3939 UNKNOWN = "Unknown" # not enough signal to attribute honestly
4040
4141
42- # Neutral, source-labelled phrasing (no blame — just where the fault lives).
42+ # Neutral, source-labelled phrasing (no blame, just where the fault lives).
4343FAULT_SOURCE : dict [Fault , str ] = {
4444 Fault .USER_INPUT : "your request" ,
4545 Fault .USER_APP : "your application (cluster runtime)" ,
4646 Fault .USER_CONFIG : "your configuration / git" ,
4747 Fault .AUTH : "your credentials / permissions" ,
4848 Fault .PLATFORM : "ZAD platform" ,
4949 Fault .NETWORK : "network / connectivity" ,
50- Fault .UNKNOWN : "unknown — see logs" ,
50+ Fault .UNKNOWN : "unknown ( see logs) " ,
5151}
5252
5353# Rich color: user-fixable = yellow, escalate/investigate = red, auth = magenta.
@@ -61,15 +61,17 @@ class Fault(StrEnum):
6161 Fault .UNKNOWN : "red" ,
6262}
6363
64- # CI/CD exit codes: 1 = your fault (fix it), 2 = platform/transient (safe to retry).
64+ # CI/CD exit codes: 1 = your fault (fix it), 2 = platform/transient (safe to retry),
65+ # 3 = unattributable. UNKNOWN gets its own code rather than claiming "your fault"
66+ # (1) or "safe to retry" (2) when the API gave us no signal to attribute the failure.
6567FAULT_EXIT_CODE : dict [Fault , int ] = {
6668 Fault .USER_INPUT : 1 ,
6769 Fault .USER_APP : 1 ,
6870 Fault .USER_CONFIG : 1 ,
6971 Fault .AUTH : 1 ,
7072 Fault .PLATFORM : 2 ,
7173 Fault .NETWORK : 2 ,
72- Fault .UNKNOWN : 1 ,
74+ Fault .UNKNOWN : 3 ,
7375}
7476
7577# Which fault each cluster ErrorCategory implies. Keyed by ErrorCategory so the
@@ -272,22 +274,22 @@ def _http_headline(status_code: int, fault: Fault) -> tuple[str, list[str]]:
272274 )
273275 if status_code == 404 :
274276 return (
275- "Not found (HTTP 404) — the resource you referenced doesn't exist." ,
277+ "Not found (HTTP 404): the resource you referenced doesn't exist." ,
276278 ["Check the name/spelling and that it exists (e.g. `zad deployment list`)." ],
277279 )
278280 if status_code == 409 :
279281 return (
280- "Conflict (HTTP 409) — the resource is in a state that blocks this action." ,
282+ "Conflict (HTTP 409): the resource is in a state that blocks this action." ,
281283 ["Check its current state, then retry once it settles." ],
282284 )
283285 if status_code == 422 :
284286 return (
285- "Invalid request (HTTP 422) — the values you sent didn't pass validation." ,
287+ "Invalid request (HTTP 422): the values you sent didn't pass validation." ,
286288 ["Fix the field(s) listed above and retry." ],
287289 )
288290 if fault is Fault .PLATFORM :
289291 return (
290- f"ZAD platform error (HTTP { status_code } ) — usually transient." ,
292+ f"ZAD platform error (HTTP { status_code } ), usually transient." ,
291293 ["Retry shortly (exit code 2 = transient). If it persists, report it with the time of the call." ],
292294 )
293295 return (f"Request rejected (HTTP { status_code } )." , [])
@@ -370,7 +372,7 @@ def degraded_diagnoses(result: object) -> list[Diagnosis]:
370372 fault = Fault .USER_CONFIG ,
371373 headline = "The operation succeeded with warnings." ,
372374 details = [str (w ) for w in warnings ],
373- next_steps = ["Review the warnings above — they usually point at your configuration." ],
375+ next_steps = ["Review the warnings above; they usually point at your configuration." ],
374376 )
375377 )
376378
0 commit comments