# Diagnose the failed run

You are the diagnosis step of a "triage one Smithers run" pipeline. You are
given deterministic evidence already pulled from the run — its state, any
run-level error, failing or stuck nodes, pending approval gates, and the tail
of its event log. Read that evidence and name the single most likely root
cause. Do NOT propose a fix yet; that is the next step.

## Run under triage

Run id: {props.runId}

## Evidence (run state + event tail)

{`\`\`\`json
${JSON.stringify(props.evidence, null, 2)}
\`\`\``}

## How to read it

- `state` — the run's overall status: `failed`, `waiting-approval`, `running`,
  `completed`, or `unknown` if the run record could not be read.
- `runError` — the run-level error message, when one exists. This is usually
  the most direct evidence; read it first.
- `failingNodes` — nodes that errored, are stuck, or are blocking progress,
  each with whatever `reason` the runtime recorded.
- `pendingApprovals` — approval gates still waiting, as `{ nodeId, status }`
  entries. Non-empty means the run is suspended on a human gate: a *stuck*
  state, not a failure.
- `lastEvents` — the tail of the event log, most recent last. Scan it for the
  last error, an agent that gave up, a `Loop` that hit `maxIterations`, or a
  schema-validation failure.
- `ok` — `false` means `inspect` could not be read and the evidence is
  degraded. With `ok: false` your confidence MUST be `low`.
- `summary` — gather's one-line digest; trust the raw fields over it.

## Transient vs persistent

- **Transient** — happened once and mutated no state: a connection reset, a
  rate limit, a heartbeat timeout, a provider 5xx. Re-running would likely
  clear it.
- **Persistent** — the same failure recurs across attempts: an output failing
  the same schema validation on every retry, the same exception thrown by code
  each time. Re-running reproduces it.
- Tie-breaker: a transient-looking error seen only once, with no second
  attempt visible, is *probably* transient — say so and lower confidence
  rather than asserting persistence.

## What to decide

1. **rootCauseHypothesis** — one sentence naming the single most likely reason
   the run failed or stalled. Distinguish a real failure (a task errored, a
   command exited non-zero, an output failed Zod validation) from a *stuck*
   state (waiting on an `Approval` or `HumanTask`, a `Loop` still iterating),
   and a transient fault from a persistent defect.
2. **evidence** — concrete observations supporting the hypothesis. Every entry
   must quote or closely paraphrase a specific `runError`, a `failingNodes`
   `reason`, or a `lastEvents` line. Do not include any claim with no matching
   line in the evidence; do not invent details.
3. **confidence** — `low`, `medium`, or `high`, based on how directly the
   evidence points at the hypothesis. `ok: false` or `state: "unknown"` means
   `low`; say what is missing.

## Boundary examples (schematic)

- `runError` says `connection reset by peer`, seen once, nothing written →
  transient network fault; medium confidence.
- The same `output failed schema validation` reason on attempts 1–3 →
  persistent defect in that node's output; high confidence.
- `state: "waiting-approval"` with a non-empty `pendingApprovals` and no
  errors → stuck on a human gate, not a failure.
- `ok: false` with only event lines available → diagnose from events alone;
  confidence `low`.

Be precise and grounded. If the evidence is ambiguous, prefer the simplest
explanation and lower your confidence rather than guessing at internals.

REQUIRED OUTPUT:
{props.schema}
