v1.5.0-rc.28
Full Changelog: v1.5.0-rc.27...v1.5.0-rc.28
[1.5.0-rc.28] — 2026-05-28
Fixed
- #386 follow-through — a fresh-restart agent whose in-memory store has not yet been re-populated no longer wipes the controller's last-known container state on handshake. A user running drydock in a controller + agent topology reported on rc.27 that their
mlagent still rendered 0 running containers in the controller UI even after the rc.25 watcher-snapshot suppression (d02080ae) and the rc.26 stats-changed broadcast (512c3751). Cause: whenAgentClient._doHandshake(app/agent/AgentClient.ts) reconnects to an agent's SSE stream it handshakes viaGET /api/containers, which serves from the agent's in-memorystoreContainer. If the agent process has just restarted and itswatchatstartcron has not yet finished its first run (the agent's store is non-persistent across restarts), that endpoint legitimately returns[]even though the docker daemon has N running containers._doHandshakethen calledpruneOldContainers([])unconditionally, deleting every controller-side container the agent had previously contributed — even though the agent's firstdd:watcher-snapshotwas about to repopulate the store seconds later. The rc.25 fix inDocker.watch()only suppresses outgoing snapshots from the agent when enumeration fails on the agent itself; it does not cover the controller-side handshake path. The fix makes the handshake's prune step ambiguity-aware:_doHandshakenow skipspruneOldContainerswhenevercontainers.length === 0and emits aHandshake returned 0 containers; preserving last-known state until the first watch cycle completeswarning (only afterhasConnectedOnce, so the first-ever connection of a genuinely empty agent stays silent). Pruning is deferred to the next authoritativedd:watcher-snapshot, which is already gated on!containerEnumerationFailed && enrichmentErrors === 0(app/watchers/providers/docker/Docker.ts:1136) and is therefore unambiguous: a 0-container snapshot means the agent really has 0 running containers. Non-zero handshakes continue to prune normally — the behaviour change is scoped strictly to the 0-container case that exposed the cold-start race.