Maintain a module-level containerRowCache (Map<name, {el, fingerprint}>)
that preserves <li> elements across renderContainers calls. Each row's
fingerprint encodes everything that affects its rendered output:
container running/login/update/reminder state, derived pending/opRunning
labels, tree position (depth, isLast, ancestorIsLast), selection, agent
question counts, and link-base context.
When the fingerprint is unchanged the existing DOM node is reused:
- no replaceChildren wipe for stable rows
- the async dashboard-state fetch (nav strip, ctx badge, status text)
is skipped — previously-fetched data stays in place
- DOM order is reconciled via insertBefore with zero layout work for
in-place nodes
Before this change every SSE event (container_changed, rebuild_queue_
changed, transient_set/cleared, question_added/resolved) caused a full
wipe + rebuild of the entire container list, triggering N concurrent
/api/dashboard-state fetches where N is the number of running agents.
After this change only the rows whose state actually changed are
rebuilt; the rest survive intact across re-renders.