Appearance
Runtime status
A runtime record's status field (projects/matrix-3/packages/host-service/src/types.ts:85) is one of five values:
| Status | Meaning | Live? |
|---|---|---|
starting | spawn returned, readiness probe in progress | yes |
running | readiness probe passed; supervisor expects this runtime alive | yes |
stopping | matrix down in flight, graceful shutdown sent | yes |
stopped | runtime exited cleanly (exit code 0 or SIGTERM) | no |
failed | runtime crashed or readiness timed out | no |
isLiveRuntimeStatus (matrix-host-service.ts:1211-1213) returns true for starting, running, stopping. The launch-readiness work's liveness checks (see below) use this to decide whether a record is even claiming to be alive.
Transitions
mermaid
stateDiagram-v2
[*] --> starting: matrix up
starting --> running: runtime.ready ok
starting --> failed: readiness timeout / spawn error
running --> stopping: matrix down
running --> stopped: child exit(0) without down
running --> failed: child exit(N) without down / SIGKILL
stopping --> stopped: graceful shutdown ok / SIGTERM clean exit
stopping --> failed: SIGKILL after grace period (rare)
failed --> starting: matrix up (operator action) / auto-start sweep
stopped --> starting: matrix up / auto-start sweepThe Host writes the new record atomically on every transition. updatedAt ticks (ISO8601 string) so callers can detect change. startedAt is written once on the first successful spawn. stoppedAt is written when the status leaves a live state.
Where status can drift
A runtime.json says status: "running" but the real process is dead. Three reasons this happens:
- The Host crashed before it could update the record.
- The pid was recycled by another process after the Host died.
- The pid is still alive but for a different commandline (someone else restarted the package out-of-band).
The Host never trusts a record blindly. Three reconciliation passes:
1. _refreshRuntimeRecordLiveness
Called whenever listRuntimeRecords is invoked (matrix-host-service.ts:234-240). For any record claiming a live status:
- If
pidis missing -> markfailedwith reason"live runtime record has no pid". - If pid is no longer alive -> mark
failed,"recorded runtime pid is no longer alive". - If pid is alive but
runtimeProcessIdentityMismatchReason(matrix-host-service.ts:1107-1131) returns a non-empty reason (commandline / args / cwd diverged) -> markfailed,"recorded runtime pid belongs to a different ...".
2. _refreshRuntimeRecordControlLiveness
Called from listRuntimeRecordsWithControlLiveness (matrix-host-service.ts:269-309). For records still claiming live state, invoke runtime.health over the controlMount with a 1.5s deadline. If the runtime does not respond, or replies with { healthy: false }, mark the record controlHealthStatus: "degraded" plus a controlHealthReason. The status itself stays running; degraded just flags it.
3. _recoverOrphanedAutoRuntimeRecordsBeforeStart
Runs at the very start of MatrixHostService.start() (matrix-host-service.ts:578-622). For any auto-start record claiming live status with a live but unmanaged pid: SIGTERM, then SIGKILL after 2s, then mark stopped with orphanRecoveredAt. If a pid refuses to die, the Host refuses to start and reports the failure list. This prevents accidentally double-running an auto-start runtime when the Host process restarts and the previous runtime survived.
Reading status
bash
# Quick view, all runtimes.
matrix runtimes | jq '.runtimes[] | { id: .runtimeId, status: .status, pid: .pid }'
# Filter to failed only.
matrix runtimes | jq '.runtimes[] | select(.status=="failed")'
# Including degraded (control-mount-unresponsive) records, ask via host-control.
matrix invoke host.control runtime.list '{}' | jq '.runtimes[] | { id: .runtimeId, status, controlHealthStatus: .metadata.controlHealthStatus }'The CLI's status and runtimes commands route through invokeHostControlFromStatus when the Host is live (cli.ts:53-98), and fall back to reading the on-disk records directly if the supervisor is unreachable.