The Final Polish: Fixing a Dangling Polling Timer in the vast-manager UI

The subject message is deceptively simple. It reads in its entirety:

[assistant] [edit] /tmp/czk/cmd/vast-manager/ui.html Edit applied successfully.

A single edit confirmation, barely a line of text. Yet this message represents the culmination of a careful debugging session that spanned six incremental fixes, each addressing a different facet of a single user complaint: the cuzk status panel in the vast-manager web UI was "jumpy." The user had attached a screenshot showing the panel working correctly, but noted two specific issues — the "connecting to cuzk" text flickered during page refreshes, and the pipeline state visualization jumped around whenever new data arrived. This message, the sixth and final edit, closed the last gap: the Escape key handler collapsed the expanded instance panel but left the cuzk polling timer running in the background.

The Context: A Live Monitoring Panel

The vast-manager is a web-based dashboard for managing GPU instances running the CuZK zero-knowledge proving engine. Over the preceding messages ([msg 2627] through [msg 2651]), the assistant had built and deployed a live status panel that polled the cuzk daemon's HTTP status API through an SSH tunnel, displaying real-time information about memory usage, synthesis concurrency, pipeline progress, GPU worker states, and buffer allocations. The full chain worked: browser → vast-manager Go backend → SSH tunnel → cuzk daemon → status JSON. The user's screenshot confirmed the panel rendered correctly with live proof data.

But the user noticed a subtle but important quality issue. Every time the main dashboard refreshed (a 10-second countdown cycle), the cuzk panel would briefly show "Connecting to cuzk..." before the next poll filled in the data. And every 1.5 seconds, when the poll returned new data, the entire panel's HTML was replaced via innerHTML, causing a visible layout reflow — the "jumpiness" the user described.

Tracing the Root Cause

The assistant's reasoning, visible in [msg 2640], shows a methodical diagnosis. The core problem was architectural: the refresh() function called renderInstances(), which rebuilt the entire instances table HTML from scratch using string concatenation and innerHTML. This destroyed the cuzk panel's DOM nodes, and the panel would show "Connecting to cuzk..." until the next polling cycle completed up to 1.5 seconds later. The same innerHTML replacement every 1.5 seconds also caused the pipeline visualization to jump as partition state badges, progress bars, and timing information appeared and disappeared.

The assistant considered several approaches: preserving the panel's innerHTML before the rebuild, skipping the cuzk div during replacement, or caching the last successful API response. It chose the caching approach as the cleanest solution, reasoning that it could immediately re-inject the cached data when the DOM was rebuilt, eliminating the "Connecting..." flash entirely.

The Six Edits

The assistant applied six edits to /tmp/czk/cmd/vast-manager/ui.html:

  1. Add a cuzkLastData cache variable and use it during container injection, so the panel always has data to render immediately.
  2. Cache data on successful fetch — every time the poll returns successfully, store the response in the cache.
  3. Use cached data in renderInstances() — when rebuilding the DOM, if cached data exists, render it directly instead of showing "Connecting to cuzk...".
  4. Clear cache when polling stops — when the user collapses the instance panel, clear the cache so a fresh "Connecting..." state appears on re-expand.
  5. Add CSS stability — a min-height on the cuzk panel to prevent layout jumps when pipeline sections appear/disappear, and CSS transitions on partition cells for smoother visual updates.
  6. Fix the Escape key handler — ensure it stops cuzk polling when collapsing the panel.

Why the Escape Key Handler Mattered

The subject message is Edit 6. The assistant had already addressed the visual jumpiness, but while reading the code to understand the full render cycle, it noticed a subtle bug: the keyboard shortcut handler for the Escape key collapsed the expanded instance panel without calling stopCuzkPolling(). This meant the polling timer continued running, firing HTTP requests through the SSH tunnel even though the panel was hidden. The timer would only be cleaned up when the user explicitly clicked the collapse button, which did call stopCuzkPolling().

This was more than a resource leak. If the user collapsed and re-expanded the panel, startCuzkPolling() would create a new timer without clearing the old one, leading to duplicate polling intervals, redundant network requests, and potentially stale data in the re-rendered panel. The fix was straightforward: add stopCuzkPolling() to the Escape key handler's collapse path.

Assumptions and Edge Cases

The assistant made several assumptions in this fix. It assumed that the Escape key handler was the only path where polling could be left dangling — an assumption validated by reading the code and finding that the explicit collapse button and the instance row click handler both called stopCuzkPolling(). It also assumed that caching the last response was sufficient to eliminate the "Connecting..." flash, which held true as long as the cached data was still reasonably fresh when the DOM was rebuilt (the refresh cycle and the poll cycle ran on different schedules, so the cache was typically at most a few seconds old).

One potential oversight: the assistant did not add a max-age check on the cached data. If the dashboard had been idle for an extended period and the refresh cycle rebuilt the DOM, the cached data could be arbitrarily stale, showing partition states that no longer reflected reality. In practice, the 1.5-second polling interval kept the cache fresh enough that this was unlikely to be noticeable.

The Broader Significance

This message, for all its brevity, represents a critical phase in software development: the polish pass. The core functionality — displaying live cuzk status data — was already working. The user could see memory usage, pipeline progress, and GPU worker states. But the experience was marred by visual flickering and a subtle resource leak. The assistant's six edits transformed a functional but rough interface into a smooth, professional one.

The fix also reveals an important lesson about UI architecture in single-page applications. The innerHTML replacement pattern, while simple and effective for initial rendering, creates challenges for real-time updates. Components that manage their own polling or timers need careful lifecycle management — every path that hides or destroys a component must also clean up its resources. The caching pattern the assistant adopted is a pragmatic middle ground: it avoids the complexity of a full virtual DOM library while eliminating the most jarring visual artifact.

In the end, the subject message — "Edit applied successfully" — is the quiet confirmation that the last loose end has been tied. The Escape key now properly stops the polling timer, the panel no longer flickers on refresh, and the pipeline visualization updates smoothly. The user's "jumpy" UI is now stable, and the vast-manager's cuzk status panel is ready for real-world use.