Problem
A Ding sidecar that never armed still refreshes its target's status. When the provider process dies, Ding keeps writing liveness, so the agent reads available indefinitely — for a process that no longer exists.
This makes status unsafe to trust as a liveness signal, which is the one job it has.
Why this matters
For an always-on supervised role (a Chief of Staff, an orchestrator), the failure is silent and permanent:
- the provider crashes
- Ding keeps the status fresh, so every consumer reads the agent as healthy
- nothing alerts, nothing restarts
The agent is dead and the bus says it is fine. An operator has no signal until they notice the work stopped. This is worse than a missing feature, because the system actively reports the opposite of the truth during the exact failure the signal exists to expose.
It also breaks the intended contract that a sidecar keeps liveness fresh and lets status decay honestly when the session is no longer running. Only the first half currently holds.
Evidence
Observed on a Linux host, convoy 0.2.0-ts.0, running a managed session with two limbs — provider <host>.w1 and sidecar <host>.w1.ding — in an isolated network.
1. Status advanced while the provider was dead. After killing the provider process, status mtime kept moving forward and both st agents and convoy ls --tree reported available.
2. Ding was the writer. Killing Ding froze the mtime permanently.
3. Observer effect ruled out. With both limbs dead, running st agents and convoy ls repeatedly left the mtime untouched. So the refresh was not a side effect of reading — Ding was actively writing.
4. Ding never armed. Its entire event log for the session is 206 bytes containing a single session_start record. The log shows:
target session "<host>.w1" not yet registered
despite the target being registered at that point. Ding never armed, never delivered a message — and still wrote liveness for the whole session.
So the status write is not gated on the sidecar having successfully attached to its target.
Proposed direction
The invariant I would suggest: a sidecar must not write liveness it has not earned. Concretely, one of:
- (a) Arm-or-exit. If Ding cannot register against its target, it exits non-zero rather than running in a degraded state that still writes status. Simplest, and makes the failure loud.
- (b) Gate the write on armed state. Ding keeps running but writes
status only while it holds a verified attachment to a live target.
- (c) Liveness derives from the provider, not the sidecar. Ding reports what it observes rather than being the source of truth.
(a) is the smallest change and would have surfaced this immediately. (c) is the most principled but the largest.
What I would like consensus on
- Is Ding intended to be the writer of
status at all, or is that an accident of it being the long-lived limb?
- Should an unarmed sidecar be a hard failure, or a degraded-but-running state? If degraded is intentional, what should it be allowed to write?
- Does
status mean "this identity has a live session" or "something is tending this folder"? The two readings diverge exactly here, and consumers currently assume the first.
Happy to put up a PR once there is agreement on which of (a)/(b)/(c) is wanted — the fix differs a lot depending on the answer to Q3.
Related
Problem
A Ding sidecar that never armed still refreshes its target's
status. When the provider process dies, Ding keeps writing liveness, so the agent readsavailableindefinitely — for a process that no longer exists.This makes
statusunsafe to trust as a liveness signal, which is the one job it has.Why this matters
For an always-on supervised role (a Chief of Staff, an orchestrator), the failure is silent and permanent:
The agent is dead and the bus says it is fine. An operator has no signal until they notice the work stopped. This is worse than a missing feature, because the system actively reports the opposite of the truth during the exact failure the signal exists to expose.
It also breaks the intended contract that a sidecar keeps liveness fresh and lets status decay honestly when the session is no longer running. Only the first half currently holds.
Evidence
Observed on a Linux host, convoy
0.2.0-ts.0, running a managed session with two limbs — provider<host>.w1and sidecar<host>.w1.ding— in an isolated network.1. Status advanced while the provider was dead. After killing the provider process,
statusmtime kept moving forward and bothst agentsandconvoy ls --treereportedavailable.2. Ding was the writer. Killing Ding froze the mtime permanently.
3. Observer effect ruled out. With both limbs dead, running
st agentsandconvoy lsrepeatedly left the mtime untouched. So the refresh was not a side effect of reading — Ding was actively writing.4. Ding never armed. Its entire event log for the session is 206 bytes containing a single
session_startrecord. The log shows:despite the target being registered at that point. Ding never armed, never delivered a message — and still wrote liveness for the whole session.
So the status write is not gated on the sidecar having successfully attached to its target.
Proposed direction
The invariant I would suggest: a sidecar must not write liveness it has not earned. Concretely, one of:
statusonly while it holds a verified attachment to a live target.(a) is the smallest change and would have surfaced this immediately. (c) is the most principled but the largest.
What I would like consensus on
statusat all, or is that an accident of it being the long-lived limb?statusmean "this identity has a live session" or "something is tending this folder"? The two readings diverge exactly here, and consumers currently assume the first.Happy to put up a PR once there is agreement on which of (a)/(b)/(c) is wanted — the fix differs a lot depending on the answer to Q3.
Related
coord mcp does not assert
availableon connect/resume — supervised sessions come back alive butoffline#12 is the inverse symptom (failing to assertavailableon connect/resume). Both point atstatusnot having a single owner with a clear contract.Supervisor detects provider death but never replays the manifest — no recovery convoy#82 — the supervisor does not restart the dead provider. Together with this issue, a crashed session stays dead and reads healthy.