Skip to content

fix: terminalize studio.deploy so Attempting deploy cannot hang - #1893

Merged
kk-agent merged 2 commits into
mainfrom
cursor/studio-deploy-terminal-gate-c9f1
Sep 12, 2026
Merged

kk-agent merged 2 commits into
mainfrom
cursor/studio-deploy-terminal-gate-c9f1

Conversation

@groupthinking

@groupthinking groupthinking commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Canonical issue

Follow-on to #1891. AXIOM dogfood on READY prod dpl_GfaxC4wivWYZqzGFrKvMcYn8fsdD (d7ac9058) / XYMcBrFSJ4c:

  1. First click started wrun_01M2B768A7AVDRR5YQTNVJDZJ8 then UI briefly showed stale fix: read studio.deploy workflow run instead of Request-parse HOLD #1853 receipt wrun_01M2ABB1NJ5TFZ153CTRNTPNW9 → UNVERIFIED (not FAIL).
  2. Second clean click (CoS GO, same dpl_): NO TERMINAL — UI stayed Attempting deploy… ~5 minutes. No new receipt. No live URL. Explicitly not the stale fix: read studio.deploy workflow run instead of Request-parse HOLD #1853 receipt.

Outcome

Anon Studio Attempt Deploy / G.A.T.E. studio.deploy with ready-transcript reuse reaches a terminal decision within a bounded kickoff budget: G.A.T.E. PASS + backend-supplied https live URL + receipt bound to the new run, or a precise HOLD (STUDIO_ORIGIN_KICKOFF_NO_JOB_HOLD). Attempting deploy cannot stick indefinitely without a gate decision/receipt.

Root cause

Verified in tree on d7ac9058 (#1891):

  1. KICKOFF_RETRIES = 6 × kickoffStep (AbortSignal.timeout(45s) plus an inner abort retry) × sleep('10s') keeps the WDK run running for ~5–11 minutes when origin never returns a job_id.
  2. GET /api/workflows/studio-deploy/:runId only attaches result when completed/failed. While kickoff is retrying there is no job id, no receipt, and deployBusy stays true (Attempting deploy…).
  3. Client poll window is 210 × 2s ≈ 7 minutes — longer than the AXIOM wait — so the UI never flipped to a HOLD.
  4. gateReceipt was not cleared on a new attempt, so the first click could flash the fix: read studio.deploy workflow run instead of Request-parse HOLD #1853 receipt.

This is not a missing VERCEL_TOKEN / invented hostname. Prefer terminal signaling over inventing a live URL.

What changed

  • Bound KICKOFF_RETRIES to 1 (initial + one durable retry), not six silent 45s steps.
  • After retries, a failed kickoff returns handoff with the kickoff-no-job message (terminal WDK status) instead of staying running until FatalError.
  • Exhausted client polls with no job id HOLD STUDIO_ORIGIN_KICKOFF_NO_JOB_HOLD (not “still running after N polls”).
  • Studio clears the stale gateReceipt on click and binds an in-flight receipt to the new runId before pollStudioDeploy.
  • Shared STUDIO_ORIGIN_KICKOFF_NO_JOB_HOLD on the client-safe pipeline-status module.

What was NOT done

  • No invented live URL.
  • No invented VERCEL_TOKEN / EVENTRELAY_API_KEY / Hayden secrets.
  • No LLM in Origin wasm. No self-hosted models.
  • Did not bounce to forge, slingshot, reach, uvai-skills, ClipToAction, or Origin tmp project uvai.
  • Did not shorten the 6-minute job-id poll window (WDK 36 × 10s still covered when kickoff actually returns a job).
  • Did not merge.

Hayden stop (not taken)

Hang/terminal gap was EventRelay-side: kickoff retries left the run non-terminal and the UI uncleared. Did not invent deploy credentials. If a later AXIOM job error proves a missing credential only Hayden has, that is the Loop→CoS ask — not guessed here.

Scope

  • Included: kickoff retry bound, handoff terminalization, no-result HOLD, stale-receipt clear + new-run bind, tests
  • Explicitly excluded: Origin invent, CRM, YouTube cookies, inventing secrets, merge

How cleared residuals stay cleared

Reuse / origin-no-live / timeout-abort raw string / HTTP 524 / bot / UNKNOWN / workflow-run / return-value / BACKEND_URL / hostname-finished tests still assert those strings are absent. New HOLD for wrun_01M2B768A7AVDRR5YQTNVJDZJ8 is kickoff-no-job bound to that run, not wrun_01M2ABB1NJ5TFZ153CTRNTPNW9.

Risk

Verification

Head: 5f0c66bf1e89b41f3eec954d72abf279b83a93b6

  • Focused Vitest: 5 files / 109 passed (pipeline-async-job, gate-transition, studio-pipeline-status, studio-workflow, studio-deploy)
  • Studio-deploy route Vitest: 9 passed (6 + 3)
  • Pytest: N/A — no Python touched
  • Required CI (Loop merges when core-green)
  • Review threads resolved

Production evidence

Cannot signed-in dogfood AXIOM here. Target residual: dpl_GfaxC4wivWYZqzGFrKvMcYn8fsdD / first-click wrun_01M2B768A7AVDRR5YQTNVJDZJ8 / second-click no receipt. Proof used: tree on d7ac9058 (KICKOFF_RETRIES = 6, result only on completed/failed, gateReceipt uncleared).

Agent handoff

  • Sole writer on this envelope
  • Acceptance criteria covered in tests
  • Required checks pass on the current head
  • Human decision: production AXIOM / G.A.T.E. PASS on uvai.io only
Open in Web Open in Cursor 

Bound kickoff retries and complete a no-job kickoff as a handoff HOLD.
Clear stale G.A.T.E. receipts and bind the new runId before poll.

Co-authored-by: Hayden <groupthinking@users.noreply.github.com>
@vercel

vercel Bot commented Sep 12, 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 5:01pm UTC

@github-actions github-actions Bot added documentation Improvements or additions to documentation javascript Pull requests that update javascript code tests labels Sep 12, 2026
Co-authored-by: Hayden <groupthinking@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d7d29e50-89c9-4e73-b09a-88507a36cca7


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

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-he3ksn52b-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 17:02:14
�[2m   Duration �[22m 3.76s�[2m (transform 52ms, setup 0ms, import 66ms, tests 3.57s, environment 0ms)�[22m


@github-actions

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 5f0c66b.
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

@kk-agent
kk-agent merged commit 6dd8fe2 into main Sep 12, 2026
40 of 42 checks passed
@kk-agent
kk-agent deleted the cursor/studio-deploy-terminal-gate-c9f1 branch September 12, 2026 17:07
@linear-code

linear-code Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

GRV-540

kk-agent pushed a commit that referenced this pull request Sep 12, 2026
* fix: studio.deploy HOLD only after poll, not attempt-started

#1893 bound a G.A.T.E. HOLD on kickoff with waiting copy. AXIOM
treated that as terminal while Origin/job could still be pollable.

Co-authored-by: Hayden <groupthinking@users.noreply.github.com>

* docs: record studio.deploy precise-HOLD PR #1895

Co-authored-by: Hayden <groupthinking@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Hayden <groupthinking@users.noreply.github.com>
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.

3 participants