-
Notifications
You must be signed in to change notification settings - Fork 525
Description
Problem Statement
Automaker has an excellent WebSocket-based auto-refresh system (apps/ui/src/hooks/use-query-invalidation.ts) that automatically syncs the UI when agent/auto-mode events occur. However, it doesn't cover several important scenarios where the UI becomes stale:
- Manual edits to
.automaker/features/*.jsonfiles (e.g., fixing corrupted data, debugging) - Server restarts causing missed WebSocket events during downtime
- Browser sleep/wake cycles interrupting the WebSocket connection
- Network disruptions dropping events
Current System
The existing use-query-invalidation.ts hook listens for WebSocket events:
auto_mode_feature_completepipeline_step_startedauto_mode_error- etc.
And automatically invalidates React Query caches, triggering UI refresh. This works perfectly for agent-driven changes.
File: apps/ui/src/hooks/use-query-invalidation.ts
- Lines 30-38:
FEATURE_LIST_INVALIDATION_EVENTS(WebSocket event list) - Lines 164-212: Event subscription and invalidation logic
The Gap
When changes happen outside the WebSocket event stream, the UI doesn't know to refresh:
- Manual file edits don't emit events
- Missed events during server restart are lost
- Browser sleep breaks WebSocket connection
Users must hard-refresh the browser (Ctrl+Shift+R), which is disruptive and clears all client state.
Real-World Example
- User manually edits
.automaker/features/ai-chat/feature.json(fixing corrupted status:"verified"→"pending") - File changes on disk
- UI continues showing old status (feature stuck in wrong column)
- No WebSocket event was emitted for the file change
- User must hard-refresh browser to see correct state
Suggested Solutions
Let developers decide best architectural approach:
Option 1: File System Watcher (Most Comprehensive)
// Add to server
import { watch } from 'fs';
watch('.automaker/features', { recursive: true }, (event, filename) => {
if (filename.endsWith('feature.json')) {
// Emit custom WebSocket event
broadcastEvent({ type: 'feature_file_changed', filename });
}
});Pros:
- Covers manual edits automatically
- Integrates with existing invalidation system
- Real-time updates
Cons:
- Server-side change required
- File watcher overhead (minimal on modern systems)
Option 2: Polling Fallback (Moderate)
// Add to use-query-invalidation.ts
useEffect(() => {
const interval = setInterval(() => {
if (!hasRecentWebSocketActivity()) {
// Poll for changes when WebSocket quiet
queryClient.refetchQueries({ queryKey: queryKeys.features.all() });
}
}, 30000); // Every 30s
return () => clearInterval(interval);
}, []);Pros:
- Client-side only
- Catches missed events, server restarts
- Simple implementation
Cons:
- Polling overhead
- Less real-time than file watcher
Option 3: Manual Refresh Button (Escape Hatch)
Add button to board header that manually refetches all data.
Pros:
- User-controlled fallback
- Covers all edge cases
- Simplest implementation
Cons:
- Requires manual user action
- Doesn't solve root cause
Option 4: Combination Approach (Recommended)
- File watcher for manual edits
- Polling for missed events
- Manual button as final fallback
User Stories
- As a developer debugging issues, when I manually edit feature files, I want the UI to reflect changes automatically
- As a developer, when the server restarts, I want the UI to recover without hard refresh
- As a developer, when my network hiccups, I want a way to resync the UI
Impact
- Improves reliability and developer experience
- Reduces disruptive hard refreshes
- Makes manual debugging/fixes practical
- Provides recovery for network/server issues
Related Issues
- Add board-wide refresh button to sync UI state with server #737 - Proposed manual refresh button (symptom treatment)
- Features stuck in 'in_progress' after server restart - cannot resume #696 - Features stuck after restart (related but different scope)
This issue addresses the root cause by extending the existing auto-refresh architecture to cover gaps.
Environment
- Automaker v0.14.0rc
- Affects all platforms (Docker, Electron, Web)