Skip to content

Remove Video Processing State Overlays and Enable Always-Watchable Videos

System Intent

Remove the "processing..." and "failed" status overlay displays from the memory viewer modal. Videos should be playable and viewable immediately upon upload, regardless of their backend processing state. This improves user experience by making memories accessible without UI blocking, while asynchronous enrichment (graph indexing, metadata extraction) continues in the background.

Mermaid Diagram

graph TB
    subgraph MemoryViewer["Memory Viewer Modal"]
        VideoList["Video List<br/>from Search"]
        VideoModal["Video Modal"]
        VideoPlayer["Video Player<br/>(Always Rendered)"]
        Metadata["Metadata Display<br/>(Badges, timestamps)"]
    end

    subgraph Backend["Background Processing"]
        Ingest["Ingest Pipeline<br/>(state: pending)"]
        Enrichment["Graph Enrichment<br/>(state: processing)"]
        Complete["Processing Complete<br/>(state: ready)"]
    end

    User["User"]

    User -->|Select video| VideoModal
    VideoModal -->|Load immediately| VideoPlayer
    VideoModal -->|Render| Metadata

    Metadata -->|Show upload time,<br/>not processing state| Metadata

    Backend -.->|Async enrichment<br/>does NOT block playback| Enrichment
    Enrichment -.-> Complete

    style VideoPlayer fill:#90EE90
    style Ingest fill:#FFB6C6
    style Enrichment fill:#FFD700

Black-Box Input/Output Contracts

Flow: Load and Display Video in Modal

Inputs: - videoId (string): Unique identifier of the video memory - videoUri (string): Playable media URI (uploaded file path or streaming URL) - processingState (enum: pending, processing, ready, failed): Backend enrichment state - metadata (object): Upload timestamp, duration, dimensions

Outputs: - Modal with rendered video player (always playable) - Metadata display (upload time, duration) - No "processing..." overlay - No "failed" state blocking UI

Processing State Mapping:

State Display Behavior Playable Notes
pending Show upload badge Yes Video in queue for enrichment
processing Show enrichment badge (optional) Yes Async background work ongoing
ready Show ready indicator Yes Enrichment complete
failed Show error badge (non-blocking) Yes Enrichment failed but playback allowed
updated Y Field changed in current revision

Success Output:

{
  "videoId": "uuid-1234",
  "uri": "s3://bucket/video.mp4",
  "duration": 45,
  "uploadedAt": "2025-05-10T14:30:00Z",
  "state": "processing",
  "playbackBlocked": false
}

Failure Output (non-blocking):

{
  "videoId": "uuid-1234",
  "uri": "s3://bucket/video.mp4",
  "error": "Enrichment failed: graph indexing timeout",
  "playbackBlocked": false,
  "state": "failed"
}

Test Mapping: - apps/mobile/src/screens/__tests__/memory-viewer.test.ts - apps/mobile/src/components/__tests__/video-player.test.ts

Flow: Remove Status Overlay Components

Inputs: - Processing state from backend - Overlay component registry

Outputs: - Conditional rendering removes "processing..." and "failed" overlay divs - Video player remains in viewport with no modal blocking - Optional: Small non-blocking badge/indicator for state

Test Mapping: - apps/mobile/src/components/__tests__/video-status-overlay.test.ts

Flow: Handle Enrichment Completion During Playback

Inputs: - processingState update (pending → processing → ready or failed) - Video currently playing in modal

Outputs: - UI smoothly updates without interrupting playback - Optional badge refresh if shown

Test Mapping: - apps/mobile/src/screens/__tests__/memory-viewer.integration.test.ts

Acceptance Criteria

Test 1: Video Loads and Plays Immediately

Input: - User selects a video with processingState: pending

Pass Criteria: - Video player renders and accepts play command within 1 second - No "processing..." or overlay blocks the video area - Video plays without interruption - Upload timestamp is displayed

Fail Criteria: - Modal shows "processing..." overlay - Play button is disabled or hidden - Video doesn't load


Test 2: Processing State Badge Updates Without Blocking

Input: - User is playing a video with processingState: processing - Backend enrichment completes, state changes to ready

Pass Criteria: - Video continues playing without stutter or interruption - Optional state badge updates (if shown) without re-rendering player - No modal re-opens or overlay appears

Fail Criteria: - Playback pauses or restarts - Overlay appears momentarily - User interaction required to dismiss notification


Test 3: Failed Enrichment Doesn't Block Playback

Input: - User selects a video with processingState: failed - Graph enrichment error occurred in backend

Pass Criteria: - Video player loads and plays normally - Error badge or indicator shown in non-blocking location (corner/badge, not overlay) - User can watch entire video without errors

Fail Criteria: - "Failed" overlay blocks video - Play button is disabled - Modal requires user action to dismiss error


Test 4: All Video States Are Watchable

Input: - Video exists in states: pending, processing, ready, failed

Pass Criteria: - All four states render playable videos - No overlays block playback in any state - Clear visual differentiation (badges/indicators only, not overlays)

Fail Criteria: - Any state blocks playback with overlay - Video URI is not loaded/playable


Test 5: Multiple Concurrent Videos Can Be Opened

Input: - User opens video modal for video A (processing) - User closes modal, opens video B (ready) - User opens video A again

Pass Criteria: - Each video loads and plays independently - No state leakage between modals - Processing of video A doesn't affect video B

Fail Criteria: - State from one video affects another - Modal fails to re-open same video


Pseudocode (Critical Flow: Modal Load and Display)

FUNCTION loadVideoModal(videoId, processingState, videoUri, metadata):

  // Always render the modal with player
  modal = createModal()

  // Load video player without state-based blocking
  player = createVideoPlayer()
  player.src = videoUri
  player.disabled = false  // Always playable, regardless of state

  modal.appendChild(player)

  // Add metadata (upload time, not processing state)
  metadataDiv = createMetadataDisplay()
  metadataDiv.innerHTML = formatTimestamp(metadata.uploadedAt)
  metadataDiv.innerHTML += formatDuration(metadata.duration)

  // Conditionally add state badge (non-blocking, optional)
  IF processingState != "ready":
    badge = createStateBadge(processingState)
    badge.style.position = "absolute"
    badge.style.top = "10px"
    badge.style.right = "10px"
    badge.style.zIndex = 5  // Below player controls
    modal.appendChild(badge)
  END IF

  // Remove all blocking overlay components
  // DELETE overlay component if processingState == "processing"
  // DELETE overlay component if processingState == "failed"

  modal.appendChild(metadataDiv)
  modal.show()
  RETURN modal

FUNCTION createStateBadge(state):
  badge = createElement("div")
  badge.className = "state-badge state-" + state
  badge.innerText = formatStateLabel(state)
  RETURN badge

FUNCTION removeStatusOverlay():
  overlays = document.querySelectorAll(".video-processing-overlay, .video-failed-overlay")
  FOR EACH overlay IN overlays:
    overlay.remove()
  END FOR

Implementation Notes

  1. Identify current overlay components: Locate React/JSX components that render processing state overlays (likely in apps/mobile/src/components/ or apps/mobile/src/screens/)
  2. Remove conditional rendering: Strip out {processingState === 'processing' && <Overlay />} or similar patterns
  3. Ensure video URI is always loaded: Verify videoUri prop is passed to player component regardless of state
  4. Replace with optional badge: If state visibility is desired for users, use a small non-blocking badge instead
  5. Test all state transitions: Verify playback continues smoothly when state changes during playback
  6. Update modal styling: Remove any CSS that hides/disables player based on processing state

Status

Current: draft Next: Await approval of Mermaid diagram, then move to contract and acceptance criteria approval