Skip to content

st2 doctor reports a retired agent as a problem, so any catalog containing one is permanently red #18

Description

@schickling-assistant

Against 46ff6ee1db2cae1b52b7730ae75ba781e0bb6605.

st2 doctor has no retirement filter, so a deliberately-retired agent is reported as a fleet health problem. Two code paths disagree about what a retired agent means:

  • reconcile treats retired as an explicit teardown — src/reconcile.rs:119 returns the live task ids to kill, and tests/reconcile.rs:122 (retired_with_live_sessions_is_torn_down) asserts that as intended behaviour. materialize_catalog skips retired specs outright (src/materialize.rs:704, "materialize every active agent"), and select_target excludes them from shepherd root selection (src/shepherd.rs:189).
  • doctor_cmd (src/main.rs:887) iterates found.specs and filters on resolved_host only (src/main.rs:933). It then asserts every task is in the live-session set (src/main.rs:943) and that presence has not rotted (src/main.rs:961).

So the runner kills a retired agent's tasks by design, and then doctor reports those same tasks as session dead/missing. retired appears in main.rs only at 246 (a doc comment), 1041/1047 (agents rendering) and 1785/1787 (ls rendering) — nowhere in doctor's filtering.

Reproduction

Read-only; no st2 up, nothing launched.

mkdir -p /tmp/scratch/only/h/principal /tmp/scratch/empty
cat > /tmp/scratch/only/h/principal/agent.kdl <<'EOF'
agent "principal" {
  identity "principal"
  host "h"
  type "service"
  retired #true
  pty "agent" { command "exec true" }
}
EOF
st2 doctor /tmp/scratch/empty --host h
st2 doctor /tmp/scratch/only  --host h
st2 doctor — catalog /tmp/scratch/empty, host 'h'
  ✓ `pty` on PATH
  ✗ supervisor (st2 up) running — no live host-lock — run `st2 up`
Error: 1 problem(s) found

st2 doctor — catalog /tmp/scratch/only, host 'h'
  ✓ `pty` on PATH
  ✗ supervisor (st2 up) running — no live host-lock — run `st2 up`
  ✗ h.principal task 'agent' alive — session dead/missing
  ✗ h.principal presence missing — no status file — is its ding refreshing?
Error: 3 problem(s) found

The supervisor line is in both runs because this was run read-only without st2 up; the delta is what matters — the two extra problems are attributable solely to the retired agent. That agent passes st2 validate with 0 errors, so nothing else flags it as malformed.

Of the two, the task-alive check is the structural one: reconcile guarantees those sessions are gone, so it is red for as long as the agent stays retired. The presence check is time-dependent (read_state only derives unknown after staleness), so a freshly-retired agent can still be green there and go red later.

Why it matters for an adopter

doctor is the natural health gate — the thing an operator runs before/after a change, or that a soak test asserts on. A catalog containing any retired agent is permanently red and exits non-zero, so "doctor is green" stops being a usable signal. The practical outcome is that people stop reading doctor at all, which costs you the checks that are genuinely valuable.

Possible directions (not a prescription)

  • Treat a retired agent's stopped tasks as the expected state — skip it in the loop the same way materialize/shepherd do, or invert the check to "retired ⇒ no live sessions".
  • Or keep it visible but out of the verdict: report retired agents in a distinct section that does not count toward problems or affect exit status.

Happy to send a PR if you'd like a particular shape. You may well have this in flight already — the rev I pinned is Gate hook renders and expose retired agents, so you are clearly in this area right now — please close this if it duplicates unpushed work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions