Skip to content

Extend auto-refresh to cover manual file edits and missed WebSocket events #740

@JasonBroderick

Description

@JasonBroderick

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:

  1. Manual edits to .automaker/features/*.json files (e.g., fixing corrupted data, debugging)
  2. Server restarts causing missed WebSocket events during downtime
  3. Browser sleep/wake cycles interrupting the WebSocket connection
  4. Network disruptions dropping events

Current System

The existing use-query-invalidation.ts hook listens for WebSocket events:

  • auto_mode_feature_complete
  • pipeline_step_started
  • auto_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

  1. User manually edits .automaker/features/ai-chat/feature.json (fixing corrupted status: "verified""pending")
  2. File changes on disk
  3. UI continues showing old status (feature stuck in wrong column)
  4. No WebSocket event was emitted for the file change
  5. 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

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions