Skip to content

Make Studio ?video= autostart one-shot under Strict Mode and document YouTube workflow - #1812

Merged
groupthinking merged 5 commits into
mainfrom
copilot/make-studio-video-auto-start
Sep 12, 2026
Merged

Make Studio ?video= autostart one-shot under Strict Mode and document YouTube workflow#1812
groupthinking merged 5 commits into
mainfrom
copilot/make-studio-video-auto-start

Conversation

Copilot AI commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Canonical issue

Linked by automation.

Outcome

Studio now treats ?video= handoff as a one-shot trigger even across React Strict Mode remounts, preventing duplicate analysis starts. /docs/api now explicitly describes the Home → Studio → transcript/events → actions/output YouTube workflow.

Scope

  • Included:
    • Auto-start dedupe hardening: applyStudioQueryAutoStart now guards on both caller ref state and a module-level video key so the same handoff video cannot double-start during Strict Mode remount behavior.
    • Regression coverage: added a test that simulates remount with a fresh ref object and asserts second invocation is already with a single start call.
    • Docs update: expanded /docs/api “Try it” section with explicit end-to-end workflow steps and one-shot Studio autostart behavior.
    • Snippet (core change):
      if (
        input.startedKey.current === handoff.videoId ||
        strictModeAutoStartedVideoId === handoff.videoId
      ) {
        return 'already';
      }
  • Explicitly excluded:
    • No changes to pipeline execution semantics, pack payload shape, or API contracts.
    • No UI flow changes outside /studio handoff/autostart and docs copy.

Risk

  • Risk level: low
  • Failure mode: over-deduping could suppress a legitimate rerun for the same video within the same module lifecycle.
  • Rollback: revert apps/web/src/lib/studio-handoff.ts autostart guard and associated regression test.

Verification

List exact automated and manual checks, tied to the current head SHA.

  • Focused tests
  • Required CI
  • Review threads resolved

Production evidence

Not applicable for this PR: behavior and docs-only validation at app/test level; no production config or infrastructure change.

Agent handoff

  • One canonical issue is linked
  • No competing PR implements the same issue
  • Acceptance criteria are satisfied
  • Required checks pass on the current head
  • Human decision is requested only for product, security, irreversible infrastructure, or production approval

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated
v0-uvai Ready Ready Preview, v0 Sep 12, 2026 10:06am UTC

Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
Copilot AI changed the title [WIP] Ensure Studio auto-start from ?video= runs once safely in Strict Mode Make Studio ?video= autostart one-shot under Strict Mode and document YouTube workflow Sep 8, 2026
Copilot AI requested a review from groupthinking September 8, 2026 23:15
Comment thread apps/web/src/lib/studio-handoff.ts
…eset, permanently suppressing auto-start for the last-started video id across remounts within an SPA session.

This commit fixes the issue reported at apps/web/src/lib/studio-handoff.ts:46

## Bug

`apps/web/src/lib/studio-handoff.ts` has a module-level global `strictModeAutoStartedVideoId` used to swallow React's Strict Mode double-mount:

```ts
let strictModeAutoStartedVideoId: string | null = null;
// ...
if (
  input.startedKey.current === handoff.videoId ||
  strictModeAutoStartedVideoId === handoff.videoId
) {
  return 'already';
}
input.startedKey.current = handoff.videoId;
strictModeAutoStartedVideoId = handoff.videoId; // set, but never cleared
```

A grep confirms the global is only ever **set/compared, never reset**. The per-mount `autoStartedKey` `useRef` in `OneLoopStudio.tsx` resets to `null` on a fresh mount — which is what let the previous ref-only guard correctly re-trigger auto-start on a genuine remount. The new global lives for the entire module/page lifetime.

### Concrete failure trigger

1. User pastes video `A` on Home → navigates to `/studio?video=A`.
2. `OneLoopStudio` mounts, the auto-start effect runs, `runAnalysis(A)` fires, and the global is set to `A`.
3. Analysis fails (transient network error) **or** the user leaves Studio and later re-pastes the *same* video `A`.
4. `OneLoopStudio` remounts → `autoStartedKey.current` is a fresh `null`, but `strictModeAutoStartedVideoId` still equals `A`.
5. `applyStudioQueryAutoStart` returns `'already'`, so `start()` / `runAnalysis()` is **never called**. Studio opens but analysis silently never auto-starts.

This is a regression versus the prior ref-only guard, where a fresh mount always re-triggered auto-start for the same video.

## Fix

The guard is only needed to survive React's *synchronous* Strict Mode unmount→remount; it must be released once the component truly leaves the tree.

- Added `resetStudioQueryAutoStart()` to `studio-handoff.ts` that clears the module global.
- Added a dedicated `[]`-deps unmount effect in `OneLoopStudio.tsx` whose cleanup schedules the reset via `window.setTimeout(..., 0)`.

The deferral discriminates the two remount kinds:

- **Strict Mode** (dev): unmount + remount happen synchronously in the same tick, so the remount effect runs *before* the `setTimeout(0)` callback — the guard is still set → correctly returns `'already'`, no double-start. The reset then fires harmlessly.
- **Genuine navigation**: the user leaves Studio and returns later; the timeout has long since cleared the guard, so the fresh mount (with a fresh `null` ref) re-triggers auto-start.

Also added a regression test and an `afterEach(resetStudioQueryAutoStart)` to keep the suite deterministic.

## Rebase note

Rebased onto commit `cb84e8d`. The docs commit only reworded the comment above `StudioSearchParams`; the guard code and the absence of any reset site are unchanged, so the bug and fix stand as-is.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: groupthinking <garveyht@gmail.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 PR Validation

⚠️ PR title should follow conventional commits format

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d5899d1a-8ccf-45d1-9f0b-75fd68335760

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions github-actions Bot added javascript Pull requests that update javascript code tests labels Sep 12, 2026
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 7f7907b.
Ensure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@groupthinking
groupthinking merged commit cfa3034 into main Sep 12, 2026
@groupthinking
groupthinking deleted the copilot/make-studio-video-auto-start branch September 12, 2026 10:05
@github-actions

Copy link
Copy Markdown
Contributor

🔴 E2E Test Results: FAILURE DETECTED

Metric Value
Status 🔴 RED
Total Tests 6
Passed 11
Failed 6
Deployment https://v0-uvai-dvd8p1x53-garv1.vercel.app
Test Output
2m''�[39m�[33m;�[39m
    �[90m190|�[39m       �[34mexpect�[39m(ct)�[33m.�[39m�[34mtoContain�[39m(�[32m'text/event-stream'�[39m)�[33m;�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/6]⎯�[22m�[39m

�[41m�[1m FAIL �[22m�[49m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mSSE Pipeline Stream�[2m > �[22mSSE stream emits at least a pipeline_status:running event
�[31m�[1mAssertionError�[22m: expected 0 to be greater than or equal to 1�[39m
�[36m �[2m❯�[22m tests/e2e/pipeline.test.ts:�[2m208:29�[22m�[39m
    �[90m206|�[39m
    �[90m207|�[39m       �[90m// Must have at least 1 event�[39m
    �[90m208|�[39m       �[34mexpect�[39m(events�[33m.�[39mlength)�[33m.�[39m�[34mtoBeGreaterThanOrEqual�[39m(�[34m1�[39m)�[33m;�[39m
    �[90m   |�[39m                             �[31m^�[39m
    �[90m209|�[39m
    �[90m210|�[39m       �[90m// Must start with pipeline_status:running�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/6]⎯�[22m�[39m

�[41m�[1m FAIL �[22m�[49m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22mmissing URL returns 400, not a hang
�[31m�[1mAssertionError�[22m: expected 401 to be 400 // Object.is equality�[39m

�[32m- Expected�[39m
�[31m+ Received�[39m

�[32m- 400�[39m
�[31m+ 401�[39m

�[36m �[2m❯�[22m tests/e2e/pipeline.test.ts:�[2m358:26�[22m�[39m
    �[90m356|�[39m
    �[90m357|�[39m       �[35mconst�[39m elapsed �[33m=�[39m �[33mDate�[39m�[33m.�[39m�[34mnow�[39m() �[33m-�[39m start�[33m;�[39m
    �[90m358|�[39m       �[34mexpect�[39m(res�[33m.�[39mstatus)�[33m.�[39m�[34mtoBe�[39m(�[34m400�[39m)�[33m;�[39m
    �[90m   |�[39m                          �[31m^�[39m
    �[90m359|�[39m       �[34mexpect�[39m(elapsed)�[33m.�[39m�[34mtoBeLessThan�[39m(�[34m5_000�[39m)�[33m;�[39m �[90m// Should respond instantly�[39m
    �[90m360|�[39m     })�[33m;�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/6]⎯�[22m�[39m

�[41m�[1m FAIL �[22m�[49m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mAPI Health�[2m > �[22mPOST /api/pipeline/stream with no body returns 400
�[31m�[1mAssertionError�[22m: expected [ 400, 500 ] to include 200�[39m
�[36m �[2m❯�[22m tests/e2e/pipeline.test.ts:�[2m441:26�[22m�[39m
    �[90m439|�[39m       )�[33m;�[39m
    �[90m440|�[39m       �[90m// Should handle gracefully — 400 or 500, but respond quickly�[39m
    �[90m441|�[39m       �[34mexpect�[39m([�[34m400�[39m�[33m,�[39m �[34m500�[39m])�[33m.�[39m�[34mtoContain�[39m(res�[33m.�[39mstatus)�[33m;�[39m
    �[90m   |�[39m                          �[31m^�[39m
    �[90m442|�[39m     })�[33m;�[39m
    �[90m443|�[39m   })�[33m;�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/6]⎯�[22m�[39m


�[2m Test Files �[22m �[1m�[31m1 failed�[39m�[22m�[90m (1)�[39m
�[2m      Tests �[22m �[1m�[31m6 failed�[39m�[22m�[2m | �[22m�[1m�[32m11 passed�[39m�[22m�[90m (17)�[39m
�[2m   Start at �[22m 11:07:05
�[2m   Duration �[22m 4.18s�[2m (transform 53ms, setup 0ms, import 67ms, tests 3.99s, environment 0ms)�[22m


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation javascript Pull requests that update javascript code tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make Studio ?video= auto-start one-shot and document YouTube workflow

2 participants