Skip to content

Fix live-preview flicker and changing announcer audio during generation - #30

Merged
builtbyrishabh merged 1 commit into
mainfrom
fix/preview-emit-replay-flood
Jul 18, 2026
Merged

builtbyrishabh merged 1 commit into
mainfrom
fix/preview-emit-replay-flood

Conversation

@builtbyrishabh

Copy link
Copy Markdown
Owner

Problem

While a video generates, the live preview page constantly re-refreshed and the announcer audio changed partway through the run.

Root cause — Inngest determinism violation. Inngest re-executes the function body from the top on every step boundary, running any non-step code again. In characterBundle and metaBundle, the announcer/character/meta emits (stateUpdateAndEmit) ran outside step.run, so:

  • every step replay re-emitted the same preview states → the client received a flood of updates → the <Player> re-rendered repeatedly ("video keeps refreshing"), and
  • createCommonPreviewAssets() picks the announcer audio with Math.random(), and running outside a step re-rolled it on each replay → the announcer voice changed mid-preview.

roundBundle and finalisePipeline already avoided this by emitting inside a step and restoring liveState via Object.assign on replay.

Fix

Apply that same, already-established pattern to the two bundles that didn't follow it:

  • characterBundle.ts — announcer + char1 + char2 emits moved into step.run("emit-character-cards", …), then Object.assign(liveState.data, emittedState.data). Each emit now fires once, and the random announcer audio is memoized (rolled once, reused on replay).
  • metaBundle.ts — meta emit moved into step.run("emit-meta", …) with the same restore.
  • livePlayer.tsx — realtime onData now guards setLiveState on data.data.version > prev.data.version, so stale/duplicate/out-of-order deliveries (realtime is at-least-once) can't rewind the preview. Backstop only; the completed-manifest path is unchanged.

roundBundle/finalisePipeline untouched (already correct).

Why Object.assign is required

stateUpdateAndEmit mutates the shared liveState. A memoized step's body doesn't re-run on replay, so without the restore, earlier segments would be dropped from liveState and the final saved manifest. Object.assign re-hydrates the cached snapshot, keeping version monotonic across the stream.

Verification

  • pnpm typecheck — clean
  • pnpm test — 33/33 pass

Not exercised end-to-end here (needs the Inngest dev server + external AI/TTS/R2 calls); recommend a live generation run to confirm the announcer audio stays fixed and the preview stops re-refreshing.

🤖 Generated with Claude Code

Announcer/character/meta preview emits ran outside Inngest steps, so they
re-fired on every step replay and the announcer audio (a Math.random pick)
was re-rolled each replay. The client accepted every emit, causing the
preview to constantly re-refresh and the announcer voice to change mid-run.

Wrap those emits in step.run and restore liveState via Object.assign on
replay (the pattern roundBundle/finalisePipeline already use), so each emit
fires once and the random announcer audio is memoized. Add a monotonic
version guard on the client so stale/duplicate realtime deliveries can't
rewind the preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
anime-room Ready Ready Preview, Comment Jul 18, 2026 6:17am

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Free

Run ID: f4340bc3-8232-40d6-b10e-622da21d8af6

📥 Commits

Reviewing files that changed from the base of the PR and between 0b7897f and e8d2f37.

📒 Files selected for processing (3)
  • src/app/(dashboard)/videos/[jobId]/livePlayer.tsx
  • src/inngest/characterBundle.ts
  • src/inngest/metaBundle.ts

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Live previews now advance in the correct order, preventing stale or duplicate updates from replacing newer content.
    • Character cards and announcer information are updated reliably during replayed workflows.
    • Battle titles, subtitles, and thumbnail information now remain synchronized after processing and replay events.

Walkthrough

LivePlayer now ignores stale or duplicate preview versions. Character and metadata bundle emissions run inside memoized Inngest steps, with emitted state restored after step execution.

Changes

Monotonic preview updates

Layer / File(s) Summary
Preview version guard
src/app/(dashboard)/videos/[jobId]/livePlayer.tsx
previewUpdate events update live state only when their version is newer than the current version.

Replay-safe bundle emissions

Layer / File(s) Summary
Memoized bundle emissions
src/inngest/characterBundle.ts, src/inngest/metaBundle.ts
Character card and metadata emissions run through named step.run calls, and returned state data is copied back onto liveState.

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

Sequence Diagram(s)

sequenceDiagram
  participant characterBundle
  participant stepRun
  participant emitAnnouncer
  participant stateUpdateAndEmit
  characterBundle->>stepRun: run emit-character-cards
  stepRun->>emitAnnouncer: emit when announcer is not ready
  stepRun->>stateUpdateAndEmit: update character1 and character2
  stateUpdateAndEmit-->>stepRun: return updated liveState
  stepRun-->>characterBundle: return cached liveState on replay
  stepRun-->>characterBundle: restore liveState.data
Loading

Poem

A rabbit watched previews hop in line,
While newer versions crossed the sign.
Cards and metadata stepped with care,
Replays found their answers there.
“No stale hops!” the rabbit cheered.


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

This branch was successfully deployed

1 active deployment
Preview — e8d2f370 Deployed Jul 18, 2026 by vercel[bot]
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