QUAYZ

telling a crash loop from an OOMKill, and naming the failure that no single field finds.

A crash loop and a container the kernel killed for memory are the same thing in `kubectl get pods`, and the remedy for one is not the remedy for the other. Five failures are produced against a cluster the test run creates and destroys, each read with six instruments, and the resulting matrix is what the taxonomy is checked against: three of its entries were wrong until they were joined to it, every one in the direction that flattered the repository.

Tests
135
Python
3.11 to 3.13
Release
v0.1.0
Licence
MIT

The demo, as it really ran

$ uv run python examples/tell_them_apart.py

Six instruments, five states, one cluster. Measured, not asserted.

                          phase  restarts           waiting  terminated  exit  ready
------------------------------------------------------------------------------------
healthy                 Running        no              none        none  none      2
image cannot be pulled  Pending        no  ImagePullBackOff        none  none      0
crash loop              Running       yes  CrashLoopBackOff       Error     1      0
killed for memory       Running       yes  CrashLoopBackOff   OOMKilled   137      0
alive but never ready   Running        no              none        none  none      0

A crash loop and an OOMKill agree on 4 of these 6 columns (phase, restarts, waiting, ready).
They differ on 2: terminated, exit.
  crash loop        Error with exit 1
  killed for memory OOMKilled with exit 137
And they present identically: 'killed for memory' shares its symptom.

What each instrument can do with that:
  restart count                                separates nothing
  container logs                               separates crash loop
  pod phase                                    separates image cannot be pulled
  lastState.terminated.reason with exitCode    separates crash loop, killed for memory
  state.waiting.reason                         separates image cannot be pulled
  EndpointSlice readiness                      separates nothing
  every instrument at once, read together      separates image cannot be pulled, crash loop, killed for memory, alive but never ready
  terraform plan over a helm_release           separates nothing
  the declared objects against the live ones   separates changed by hand afterwards

The pod that is alive and never ready differs from a HEALTHY pod in 1 column (ready),
and that column reads the same for every failure above. No single field finds it.

Output captured on 2026-08-28. It is committed to the repository and a test fails when it stops matching a live run, so this page cannot quietly drift from the code it describes.

Read it

The rest of the toolset