Skip to content

ADR-0046 Architecture decision record

A converge failure carries its diagnosis ​

The failure that produced ADR-0045 surfaced as error: timed out waiting for the condition — kubectl's verdict and nothing else. The cause (exec format error in a CrashLoopBackOff pod) was found only by hand-running kubectl get pods and kubectl logs. The repo already holds the precedent for what should have happened: oneShotFailure() (kube.ts) rethrows a one-shot probe's failure with the pod's own output in front of kubectl's verdict, because the line that says WHY is exactly what the verdict drops. The rollout wait is the same failure one layer up, and jr2 up runs three of them (operator, Orchestrator, Instance Harness), all equally blind.

Decision ​

  • On rollout failure, the error carries the evidence: for the deployment's pods — phase, container waiting reasons, the last events, and a container log tail — gathered after the timeout and rethrown in front of kubectl's verdict. One rolloutFailure() beside oneShotFailure(), used by all three rollout waits, so every layer gets the same eyes.
  • Named diagnoses annotate the evidence, never replace it. A small pattern table layered on top names the cause and the way back when it matches: exec format error → "image platform X, node platform Y" plus platforms/--force (belt-and-braces under ADR-0045, and the only trace left for pre-0045 images and registry-ref Sandbox Images jr2 never built); ImagePullBackOff/ErrImagePull → the ref and the registry it resolved to (the docker.io/library/ normalization trap); CrashLoopBackOff → lead with the log tail, which IS the diagnosis; CreateContainerConfigError → name the missing object (already preflighted for envFrom Secrets — this catches what slips past). The hard rule that keeps the table honest: a named diagnosis may only interpret evidence that is also printed raw beneath it — a table that swallows evidence turns a wrong match into a lie; one that annotates it costs nothing when wrong.
  • Scope: the rollout wait only. A converge that never reaches a rollout (config error, build error, apply error) keeps its existing errors — no general "dump the namespace on any error" reflex. Those failures already name themselves; the rollout timeout was the one that did not.

Considered options ​

  • Evidence-only (no pattern table). Rejected: the user still translates exec format error into "platform mismatch" themselves, which is the folklore step this ADR exists to delete. The table is small, bounded, and each entry is a failure someone actually hit.
  • Diagnosis as a separate command (jr2 doctor-style, run after the failure). Rejected: the moment of failure is when the evidence is fresh and the user is looking; a second command is the by-hand loop with a jr2 badge on it.

The docs of Kit version 0.5.1. Each page is also at its .md URL.