Skip to content

Cancel export and media download strategy improvement#1050

Merged
LeviXIII merged 7 commits into
mainfrom
cancel-export-and-media-download-strategy-improvement
Jun 15, 2026
Merged

Cancel export and media download strategy improvement#1050
LeviXIII merged 7 commits into
mainfrom
cancel-export-and-media-download-strategy-improvement

Conversation

@TimRl

@TimRl TimRl commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Cancel export and media download strategy improvement

Frontier: genesis-ai-dev/frontier-authentication#34

Pinned Project: 1050-cancel-export-and-media-download-strategy-improvement

#997

Summary

Adds the ability to cancel an in-progress project export (cleaning up any
partial output), makes whole-project audio export resilient to transient
LFS/network failures, and overhauls how unresolved/missing audio is surfaced
to the user — including a categorized, expandable, clickable issues list, a
targeted "retry failed" action, and clearer real-time progress.

Also tightens the media-download-strategy switch (clear "Calculating…" feedback
and diagnostic logging into why some media is retained).

Changes

Export cancellation

  • Cancel button on the export progress view; threads a CancellationToken
    through every exporter (audio, plaintext, USFM, HTML, VTT/SRT, XLIFF, CSV/TSV,
    rebuild, backtranslations).
  • Aborts in-flight LFS downloads via an AbortSignal bridged from the token.
  • Deletes the partial (unique) export folder on cancel and shows a terminal
    "Cancelled — partial output removed" state with a Close button.
  • Re-entrancy guard prevents starting a second export while one is running;
    closing the export tab aborts the run.

Resilient audio downloads

  • New downloadLfsWithRetry: up to 4 attempts with exponential backoff + jitter.
  • Retries only transient errors (5xx, 429, timeouts, ECONNRESET, fetch failed,
    etc.); fails fast on permanent ones (4xx, corrupt pointer) and never retries a
    user-initiated abort.

Export issues UX

  • "X audio file(s) exported, Y could not be resolved" now expands into a
    categorized, collapsible list with human-readable labels/descriptions and an
    "Expand all / Collapse all" toggle.
  • Each issue row is clickable and deep-links to the exact cell in the editor
    (cell id + codex path threaded through the reporter chain).
  • New "selected take missing but other takes available" warning category
    (recoverable) split out from hard "could not be resolved" errors.
  • "Retry failed" action re-runs only the recoverable failed cells and merges
    recovered audio back into the existing export folder.
  • Unified amber accent across all issue groups.

Pre-flight (Step 1) + real-time stats

  • Cells whose selected take is flagged isMissing are surfaced as "possibly
    missing"; cells whose only remaining takes are all missing are reclassified as
    "without audio" (consistently in pre-flight and export).
  • Audio stat pills update in real time via a debounced .codex file watcher;
    the cell-list popover stays open when navigating to a cell.

Progress display

  • Count shown once (in the title); the secondary line shows the actual item
    (cell label while writing) instead of repeating the .codex filename during
    concurrent downloads.

Media download strategy switch

  • Disabled "Calculating…" state while counting media files before the prompt.
  • Diagnostic tally in replaceFilesWithPointers explaining why each file was
    retained (persisted / unsynced / already-pointer) without changing behavior.

Testing Checklist

Export cancellation

  • Start an audio export, cancel mid-download → run stops, partial folder is deleted, "Cancelled — partial output removed" state shows with a Close button.
  • Close the export tab mid-export → the run aborts.
  • Attempt to start a second export while one is running → blocked.
  • Cancel during a retry backoff → aborts promptly (doesn't wait out the delay) and surfaces as cancellation, not an error.

Resilient audio downloads (retry/backoff)

  • Export against a flaky/500-prone server → transient failures (5xx, 429, timeouts, ECONNRESET, fetch failed) auto-recover via retry.
  • Permanent errors (404/401/403, corrupt pointer) fail fast without retrying.

Export issues UX

  • Trigger unresolved cells → issues list groups them by category with human-readable labels/descriptions.
  • "Expand all / Collapse all" toggle works and stays readable in hover/selected states.
  • Issue rows deep-link to the correct cell in the editor.
  • "Selected take missing but other takes available" appears as a recoverable warning, separate from hard "could not be resolved" errors.
  • "Retry failed" → recovered cells drop off, still-failing ones remain, recovered audio lands in the original export folder.
  • All issue groups share the unified amber accent.

Pre-flight (Step 1) + real-time stats

  • Cells with a selected isMissing take show as "possibly missing".
  • Cells whose only remaining takes are all missing are classified as "without audio" (consistent in pre-flight and export).
  • Edit a cell's audio on Step 1 → stat pills update live; the cell-list popover stays open when navigating to a cell.

Progress display

  • Count shows once (in the title); the secondary line shows the actual item (cell label while writing), not the .codex filename during concurrent downloads.

Media download strategies — audio pointerization (replaceFilesWithPointers)

  • Default stream-only run reverts a synced audio take (pointers/ holds the pointer, files/ holds real bytes) to a pointer.
  • Default stream-only run preserves an unsynced audio take (real bytes in both files/ and pointers/) — bytes untouched.
  • restrictToAudio pointerizes audio only, leaving video untouched.
  • restrictToVideos pointerizes video only, leaving audio untouched.
  • Persisted (user-saved) audio is protected on automatic cleanup; ignorePersisted frees it.
  • Mixed audio + video, default run: both synced files pointerized, both unsynced files preserved (regression for the "always compute videoRefs" refactor).

Media download strategies — countSyncedDeletableAudioFiles

  • Counts synced audio (pointer in pointers/, real bytes in files/).
  • Excludes unsynced audio (no/real-bytes pointer).
  • Excludes persisted (allowlisted) audio.
  • Excludes files that are already pointer stubs.
  • Excludes video files.
  • Counts ambiguous .webm recordings as audio (not referenced by a notebook videoUrl).

Media download strategies — counting & stubs

  • countDownloadedMediaFiles counts real downloaded media, ignores pointer stubs.
  • removeFilesPointerStubs (less-restrictive switch, audio): removes audio pointer stubs so they re-download; preserves real downloaded audio bytes.

Media download strategies — applyMediaStrategy transition matrix

  • auto-download → stream-only (default): synced media freed, unsynced preserved.
  • auto-download → stream-only (keep-video): local videos allowlisted and kept; rest freed.
  • auto-download → stream-only (free-all): everything freed incl. saved videos; video allowlist cleared.
  • auto-download → stream-and-save (granular keepVideo/keepAudio combinations).
  • auto-download → stream-and-save (keepFilesOnStreamAndSave === false): explicit free incl. saved videos.
  • stream-only → auto-download: pointer stubs removed + pending swap downloads processed.
  • stream-only → stream-and-save: preserve-videos behavior.
  • stream-and-save → stream-only / auto-download: restrictive vs less-restrictive outcomes.
  • Same strategy (no change) is a no-op; forceApply re-runs anyway.

Media download strategies — "Calculating…" UX (project.mediaStrategyCalculating)

  • Switch media strategy on a large project → disabled "Calculating…" state shows while counting.
  • Message sent (calculating: true) before counting media files.
  • Cleared (calculating: false) on cancel and before persisting the result.

Frontier-authentication — AbortSignal for LFS downloads

  • Cancel an export while LFS objects are downloading → downloads abort promptly and surface as cancellation, not errors.
  • Two callers request the same OID; one aborts → the other still completes (refcounted abort).
  • All waiters for an OID abort → the shared fetch is actually cancelled (no lingering bandwidth use).
  • An already-aborted signal never joins/starts a shared download.
  • Normal (uncancelled) downloads and the dedup fast-path still work.
  • Aborted requests propagate AbortError untouched (callers can distinguish cancel vs failure).

@TimRl TimRl linked an issue Jun 11, 2026 that may be closed by this pull request
3 tasks
@TimRl

TimRl commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

/build

@github-actions

Copy link
Copy Markdown

@LeviXIII LeviXIII left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well for me. There was one issue that was caught unrelated to the PR but that was made into a separate issue.

@LeviXIII LeviXIII merged commit 6d167bb into main Jun 15, 2026
3 checks passed
@LeviXIII LeviXIII deleted the cancel-export-and-media-download-strategy-improvement branch June 15, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Need a Cancel Button for audio exports

2 participants