Skip to content

fix(dub): completed tracks always show their tabs + history keeps its language (P0) - #956

Merged
debpalash merged 2 commits into
mainfrom
fix/dub-track-tabs-p0-pr
Jul 4, 2026
Merged

fix(dub): completed tracks always show their tabs + history keeps its language (P0)#956
debpalash merged 2 commits into
mainfrom
fix/dub-track-tabs-p0-pr

Conversation

@debpalash

@debpalash debpalash commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Bug (owner report)

A project with a completed dubbed video doesn't show the video track tabs unless the language is re-selected.

Root cause (verified chain)

  • DubTab.jsx: the visibility gate contained a tautology (dubTracks?.length > 0 || !!dubTracks — always true since the store defaults to []), so tabs were effectively keyed to the language dropdown (dubLangCode !== 'und'), not the persisted tracks.
  • History restore set dubLangCode to 'und' because dub_history.language_code is frozen at "": the save UPSERT never updates language/language_code after the ingest-time insert, even though generation sets them (the values live correctly inside the job_data JSON).

Fixes

  1. Tabs render from the persisted tracks alone: hasDubbedTrack = dubStep === 'done' && dubTracks.length > 0 — the language dropdown only matters for generating new tracks.
  2. Auto-jump preview is membership-guarded (dubTracks.includes(dubLangCode) ? … : dubTracks[0]) — kills a preview-404 class on project restores.
  3. The UPSERT heals language/language_code with the same empty-guarded CASE pattern as content_hash — new saves fix the columns.
  4. Restore falls back to the parsed job_data values — existing rows in users' DBs heal with no migration (backward-compat rule).

Plus P0 polish: track pills get duration/timing tooltips (hydrated lazily from the previously-unused GET /dub/tracks/{job_id}), an accurate now-playing indicator, i18n'd strings.

Tests

9 new (7 frontend across 2 files + 2 backend) — fail-before verified per-fix by stashing. Full frontend suite: 108 files / 855 tests green; typecheck + lint clean; backend save_job consumers 49/49.

🤖 Generated with Claude Code

Summary

  • Fixed dubbed-track tab visibility so completed dubs show tabs based on persisted track data, not the language dropdown state.
  • Hardened preview auto-jump to only select languages that actually exist in dubTracks.
  • Updated dub history persistence/restoration to preserve healed language / language_code values and fall back to job_data for older rows.
  • Added track pill tooltips with duration/timing metadata, more accurate now-playing state, and new i18n strings.
  • Added regression tests for tab visibility, preview behavior, tooltip rendering, and DB upsert healing.

UI sketch

Before:

[Original] [Lang A] [Lang B]   <- tabs could stay hidden unless language was re-selected

After:

[Original] [Lang A] [Lang B]   <- tabs show when persisted tracks exist
   ^ tooltip: duration + timing

Behavior

flowchart TD
  A[Dub job restored / saved] --> B{Has persisted tracks?}
  B -->|No| C[Keep preview on Original / hide tabs]
  B -->|Yes| D[Show dubbed track tabs]
  D --> E{Requested auto-jump lang exists in dubTracks?}
  E -->|Yes| F[Jump to that lang]
  E -->|No| G[Jump to first available track]
  A --> H[Save_job UPSERT]
  H --> I[Heal language fields only when incoming values are non-empty]
  A --> J[Restore from older DB row]
  J --> K[Fallback to job_data values / defaults]
</mermaid>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Loading

mergetest and others added 2 commits July 5, 2026 01:13
… language (P0)

Root cause chain: the track switcher's visibility expression required
dubLangCode !== 'und' and ended in a tautology (dubTracks?.length > 0 ||
!!dubTracks), so it was effectively keyed to the language dropdown, not
the persisted tracks. History restore always handed the frontend 'und'
because the dub_history language/language_code COLUMNS froze at the
ingest-time "" — the save_job UPSERT never updated them after generation
set them on the job dict (only the job_data JSON carried the real value).
Net effect: a restored project with finished tracks showed no track tabs
until the user re-picked a language.

- DubTab: hasDubbedTrack = done && dubTracks.length > 0 (tracks only;
  also stops the tautology from showing a trackless switcher).
- DubTab auto-jump: membership-guarded — the preview only jumps to a
  language that has a track, else tracks[0]. Kills the preview-404 class
  (restores falling back to 'en' with tracks ['bn'] pointed the player
  at /dub/preview-video?lang=en).
- dub_pipeline.save_job UPSERT: language/language_code now update when
  non-empty (same CASE guard as content_hash), so new saves heal the
  frozen columns and empty re-saves can't clobber them back.
- App.restoreDubHistory: falls back to job_data's language/language_code
  so EXISTING rows in users' DBs restore correctly with no migration.
- P0.2 polish: track pills get duration + timing-strategy tooltips,
  hydrated lazily and failure-silently from the existing
  GET /dub/tracks/{job_id} via new api/dub.dubListTracks; all new
  strings through i18n (en.json).

Tests (fail-before/pass-after): DubTab-level visibility + auto-jump
membership-guard tests (3 of 4 fail pre-fix), pill-tooltip hydration
tests, and save_job language heal/no-clobber tests (heal fails pre-fix).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Backend save_job UPSERT logic now conditionally preserves existing dub_history.language/language_code values instead of overwriting them with empty strings. Frontend restores language fields with fallbacks, derives dubbed-track availability from actual tracks, guards preview auto-jump against missing tracks, and adds per-track duration/timing tooltips via a new dubListTracks API. Tests and changelog added.

Changes

Backend language column healing

Layer / File(s) Summary
Conditional UPSERT for language fields
backend/services/dub_pipeline.py
save_job's UPSERT ON CONFLICT clause now uses CASE expressions to preserve existing non-empty language/language_code values when incoming values are empty, with an explanatory doc comment.
Backend healing tests
tests/test_dub_pipeline_state.py
Adds _lang_row helper and tests verifying that empty language columns are healed on a later save and that previously healed values are not clobbered by empty updates.

Frontend dub track visibility, restore, and tooltip UI

Layer / File(s) Summary
History restoration fallback logic
frontend/src/App.jsx
restoreDubHistory now falls back across item and job_data fields for dubLang/dubLangCode, defaulting to Auto/und.
Dubbed-track availability and preview auto-jump
frontend/src/pages/DubTab.jsx
hasDubbedTrack now depends only on dubStep === 'done' and non-empty dubTracks; preview auto-jump effect verifies dubLangCode exists in dubTracks before jumping, else falls back to the first track.
DubTab restore/auto-jump regression tests
frontend/src/test/DubTrackTabsRestore.test.jsx
New suite mocks DubTab dependencies and asserts hasDubbedTrack/previewMode across restore and membership-guard scenarios.
Track metadata API and tooltip rendering
frontend/src/api/dub.ts, frontend/src/components/dub/DubLeftColumn.jsx, frontend/src/i18n/locales/en.json
Adds DubTrackInfo interface and dubListTracks API call; DubLeftColumn fetches track metadata into trackInfo state and renders a trackTooltip combining duration and localized timing-strategy labels on preview pills.
Track pill tooltip tests
frontend/src/test/DubTrackPillTooltip.test.jsx
New suite mocks dubListTracks and verifies tooltip hydration, silent-failure behavior, and no-track rendering without API calls.
Changelog entry
CHANGELOG.md
Adds an Unreleased Fixed entry describing the fixes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • debpalash/OmniVoice-Studio#759: Prior refactor of the same DubTab.jsx and DubLeftColumn.jsx modules that this PR extends with track-availability and tooltip logic.
🚥 Pre-merge checks | ✅ 7 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning Conventional-commit scope is present, but the title lacks the required issue reference in the title or body. Add the issue key (for example, #956 or a JIRA ID) to the title or PR body while keeping the fix(dub): format.
I18n Completeness (21 Locales) ⚠️ Warning DubLeftColumn.jsx:173-185 adds 5 dub.* keys, but only en.json:895-899 has them; the other 20 locale files miss them. Add dub.timing_concise, dub.timing_stretch_video, dub.timing_strict_slot, dub.track_tip_duration, dub.track_tip_timing to ar,de,es,fr,hi,id,it,ja,ko,nl,pl,pt,ru,sv,th,tr,uk,vi,zh-CN,zh-TW.
✅ Passed checks (7 passed)
Check name Status Explanation
Description check ✅ Passed The description is detailed and covers summary, root cause, fixes, and tests, but it does not use the repo template headings or checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cross-Platform Default Parity ✅ Passed Touched logic at backend/services/dub_pipeline.py:187-220, frontend/src/App.jsx:1032-1056, and frontend/src/pages/DubTab.jsx:351-382 is platform-agnostic; no cfg!/process.platform/target_os branche...
Local-First Guarantee ✅ Passed PASS: New fetch is local-only (/dub/tracks/{job_id}_get_job/job.get('dubbed_tracks')), tooltip failure is silent, and touched files add no telemetry/API-key/cloud deps.
Backward Compatibility ✅ Passed PASS: dub_history schema stays unchanged; save_job only guards existing cols (backend/services/dub_pipeline.py), and App.jsx falls back to job_data for legacy rows—no migration, engine rein...
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dub-track-tabs-p0-pr

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes restored dub projects so completed tracks drive the preview tabs and history keeps language data.

  • Dub history UPSERT now heals non-empty language and language_code values.
  • Restore now falls back to language fields stored inside job_data.
  • Track tabs now render from persisted tracks instead of the language dropdown.
  • Preview selection now chooses an existing track on restore.
  • Track pills now fetch local track metadata for duration and timing tooltips.
  • UI shape: Before: [Original only]After: [Original | Bengali].

Confidence Score: 4/5

The restored preview path still has a stale-track state that can request a missing preview video.

  • New localized tooltip strings are present only in English.
  • The preview effect validates against dubTracks but does not rerun when the track set changes.
  • The backend persistence change and restore fallback look sound from the reviewed diff.

frontend/src/pages/DubTab.jsx and frontend/src/i18n/locales/*.json

Important Files Changed

Filename Overview
backend/services/dub_pipeline.py Adds guarded UPSERT updates for dub language columns so non-empty generated values persist without later empty clobbers.
frontend/src/App.jsx Restores dub language fields from job_data when older database columns are empty.
frontend/src/pages/DubTab.jsx Fixes initial tab visibility and restore preview selection, but preview reconciliation still misses track-list changes.
frontend/src/components/dub/DubLeftColumn.jsx Adds local track metadata hydration for pill tooltips without blocking the main track switcher.
frontend/src/api/dub.ts Adds a typed wrapper around the existing /dub/tracks/{job_id} endpoint.
frontend/src/i18n/locales/en.json Adds English tooltip and timing labels, but matching keys are missing from the other locale files.
frontend/src/test/DubTrackPillTooltip.test.jsx Adds tests for tooltip hydration and failure-silent metadata fetch behavior.
frontend/src/test/DubTrackTabsRestore.test.jsx Adds tests for restored completed tracks, misaligned language codes, and empty track sets.
tests/test_dub_pipeline_state.py Adds backend tests for healing language columns and preserving them during later empty saves.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
  participant H as dub_history
  participant A as App restore
  participant S as Store
  participant D as DubTab
  participant V as Preview
  H->>A: columns or job_data language
  A->>S: set language + track keys
  S->>D: done state + tracks
  D->>D: show tabs when tracks exist
  D->>V: preview matching lang or first track
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
  participant H as dub_history
  participant A as App restore
  participant S as Store
  participant D as DubTab
  participant V as Preview
  H->>A: columns or job_data language
  A->>S: set language + track keys
  S->>D: done state + tracks
  D->>D: show tabs when tracks exist
  D->>V: preview matching lang or first track
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "docs(changelog): open [Unreleased] with ..." | Re-trigger Greptile

Comment on lines +895 to +899
"timing_concise": "Concise",
"timing_stretch_video": "Stretch Video",
"timing_strict_slot": "Strict slot",
"track_tip_duration": "Duration {{duration}}",
"track_tip_timing": "Timing {{strategy}}",

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.

P1 Locale Keys Stay English-Only

These new tooltip and timing labels are user-facing, but they were added only to en.json. In any non-English locale, the track-pill tooltip falls back to English text such as Duration and Timing, which creates mixed-language UI and violates the locale coverage rule for new strings.

Context Used: CLAUDE.md (source)

Fix in Claude Code

Comment on lines 376 to 381
useEffect(() => {
if (hasDubbedTrack && previewMode === 'original' && dubLangCode && dubLangCode !== 'und') {
setPreviewMode(dubLangCode);
if (hasDubbedTrack && previewMode === 'original') {
setPreviewMode(dubTracks.includes(dubLangCode) ? dubLangCode : dubTracks[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasDubbedTrack, dubLangCode]);

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.

P1 Track Set Changes Leave Stale Preview

The guard validates previewMode against dubTracks, but the effect does not rerun when dubTracks changes while dubStep stays done and dubLangCode is unchanged. A completed regenerate that replaces ['bn'] with ['es'] can leave previewMode on bn, so the player requests /dub/preview-video/{jobId}?lang=bn even though that track no longer exists.

Suggested change
useEffect(() => {
if (hasDubbedTrack && previewMode === 'original' && dubLangCode && dubLangCode !== 'und') {
setPreviewMode(dubLangCode);
if (hasDubbedTrack && previewMode === 'original') {
setPreviewMode(dubTracks.includes(dubLangCode) ? dubLangCode : dubTracks[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasDubbedTrack, dubLangCode]);
useEffect(() => {
if (hasDubbedTrack && previewMode === 'original') {
setPreviewMode(dubTracks.includes(dubLangCode) ? dubLangCode : dubTracks[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasDubbedTrack, dubLangCode, dubTracks]);

Fix in Claude Code

@debpalash
debpalash merged commit 6b91205 into main Jul 4, 2026
10 of 12 checks passed
@debpalash
debpalash deleted the fix/dub-track-tabs-p0-pr branch July 4, 2026 19:51

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/dub/DubLeftColumn.jsx`:
- Line 21: The dub tooltip strings are only defined in the English locale, so
non-English users will see fallback text. Update the locale resource files for
the other 20 languages to add the new dub keys used by DubLeftColumn
(dub.track_tip_duration and dub.track_tip_timing), matching the existing
translation structure and keeping the key names consistent with en.json.

In `@frontend/src/pages/DubTab.jsx`:
- Around line 369-381: Reset the preview selection whenever the mounted DubTab
is showing a previewMode that is no longer valid for the current dubTracks, not
just when previewMode is original. Update the useEffect in DubTab to resync
previewMode when restoring a different job so videoSrc never requests a stale
language, using the existing hasDubbedTrack, previewMode, dubTracks, and
dubLangCode logic as the anchor. Add a regression test that restores one job and
then another in the same mounted component to verify previewMode is corrected to
a valid track instead of staying on the previous job’s language.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 15c32493-6014-4573-86d6-5bd449d1d69b

📥 Commits

Reviewing files that changed from the base of the PR and between 1dfa032 and f68d860.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • backend/services/dub_pipeline.py
  • frontend/src/App.jsx
  • frontend/src/api/dub.ts
  • frontend/src/components/dub/DubLeftColumn.jsx
  • frontend/src/i18n/locales/en.json
  • frontend/src/pages/DubTab.jsx
  • frontend/src/test/DubTrackPillTooltip.test.jsx
  • frontend/src/test/DubTrackTabsRestore.test.jsx
  • tests/test_dub_pipeline_state.py

import WaveformTimeline from '../WaveformTimeline';
import MultiLangPicker from '../MultiLangPicker';
import { API } from '../../api/client';
import { dubListTracks } from '../../api/dub';

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd . frontend/src/i18n/locales -e json | while read -r f; do
  echo "== $f =="
  jq -e '.dub.track_tip_duration // "MISSING"' "$f"
  jq -e '.dub.track_tip_timing // "MISSING"' "$f"
done

Repository: debpalash/OmniVoice-Studio

Length of output: 1456


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== DubLeftColumn.jsx (relevant lines) =="
sed -n '140,230p' frontend/src/components/dub/DubLeftColumn.jsx | cat -n

echo
echo "== locale keys under dub =="
python3 - <<'PY'
import json, pathlib
for path in sorted(pathlib.Path('frontend/src/i18n/locales').glob('*.json')):
    data = json.loads(path.read_text(encoding='utf-8'))
    dub = data.get('dub', {})
    keys = sorted(k for k in dub.keys() if 'tip' in k or 'timing' in k)
    print(path.name, keys)
PY

Repository: debpalash/OmniVoice-Studio

Length of output: 5387


Add the new dub tooltip keys to the other 20 locale files
frontend/src/components/dub/DubLeftColumn.jsx:34-46 now calls dub.track_tip_duration and dub.track_tip_timing; only frontend/src/i18n/locales/en.json has those entries. Non-English locales will fall back to the English defaults, so the tooltip copy stays untranslated outside English.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/dub/DubLeftColumn.jsx` at line 21, The dub tooltip
strings are only defined in the English locale, so non-English users will see
fallback text. Update the locale resource files for the other 20 languages to
add the new dub keys used by DubLeftColumn (dub.track_tip_duration and
dub.track_tip_timing), matching the existing translation structure and keeping
the key names consistent with en.json.

Source: Path instructions

Comment on lines 369 to 381
// When a dub finishes, jump the preview to the freshly-dubbed language so the
// result plays immediately — the user can tap back to Original any time.
// Membership guard: only jump to a language that actually has a track,
// otherwise fall back to the first track. Restored projects can have
// dubLangCode out of sync with the tracks (e.g. 'en'/'und' with tracks
// ['bn']) and an unguarded jump would point the player at
// /dub/preview-video?lang=en — a guaranteed 404.
useEffect(() => {
if (hasDubbedTrack && previewMode === 'original' && dubLangCode && dubLangCode !== 'und') {
setPreviewMode(dubLangCode);
if (hasDubbedTrack && previewMode === 'original') {
setPreviewMode(dubTracks.includes(dubLangCode) ? dubLangCode : dubTracks[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasDubbedTrack, dubLangCode]);

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== DubTab.jsx around previewMode / effects ==\n'
ast-grep outline frontend/src/pages/DubTab.jsx --view expanded || true
printf '\n-- relevant lines --\n'
sed -n '150,420p' frontend/src/pages/DubTab.jsx | cat -n

printf '\n== Search for previewMode setters/usages ==\n'
rg -n "setPreviewMode|previewMode" frontend/src/pages frontend/src -g '!**/node_modules/**' || true

printf '\n== App.jsx restore/load paths ==\n'
ast-grep outline frontend/src/App.jsx --view expanded || true
printf '\n-- relevant restore/load slices --\n'
rg -n "restoreDubHistory|loadProject|DubTab|dubJobId|dubTracks|dubLangCode" frontend/src/App.jsx frontend/src -g '!**/node_modules/**' || true

printf '\n== DubTrackTabsRestore tests ==\n'
rg -n "renderDone|restore|DubTrackTabsRestore|previewMode|dubLangCode|dubTracks" frontend/src tests -g '!**/node_modules/**' || true

Repository: debpalash/OmniVoice-Studio

Length of output: 50382


Reset the preview selection when restoring a different job

previewMode survives on the mounted DubTab, so the guard at lines 377-381 only covers the “from original” case. Restore job A with 'bn', then restore job B whose dubTracks is ['es'], and previewMode stays 'bn'; videoSrc then requests /dub/preview-video/{jobB}?lang=bn and 404s. Broaden the effect to resync when the current previewMode is no longer in dubTracks, and add a same-mount restore regression.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/DubTab.jsx` around lines 369 - 381, Reset the preview
selection whenever the mounted DubTab is showing a previewMode that is no longer
valid for the current dubTracks, not just when previewMode is original. Update
the useEffect in DubTab to resync previewMode when restoring a different job so
videoSrc never requests a stale language, using the existing hasDubbedTrack,
previewMode, dubTracks, and dubLangCode logic as the anchor. Add a regression
test that restores one job and then another in the same mounted component to
verify previewMode is corrected to a valid track instead of staying on the
previous job’s language.

debpalash pushed a commit that referenced this pull request Jul 4, 2026
#956 merged with a red Tests gate — my merge script ran unconditionally
instead of aborting on the gate value; the failure was oxfmt-only on the
two new test files. Whitespace-only fix, tests re-verified green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant