Skip to content

fix: studio.deploy HOLD only after poll, not attempt-started - #1895

Merged
kk-agent merged 2 commits into
mainfrom
cursor/studio-deploy-precise-hold-b051
Sep 12, 2026
Merged

fix: studio.deploy HOLD only after poll, not attempt-started#1895
kk-agent merged 2 commits into
mainfrom
cursor/studio-deploy-precise-hold-b051

Conversation

@groupthinking

@groupthinking groupthinking commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Canonical issue

Follow-on to #1893. AXIOM dogfood on READY prod dpl_HheLD9BJr8jts34NDQgMGcta2Fnb (6dd8fe23) / XYMcBrFSJ4c:

Outcome

studio.deploy / G.A.T.E. either PASSes with a backend-supplied https live URL + receipt, or HOLDs with a residual that means Origin/deploy truly finished without a hostname — not a premature “waiting” HOLD while a job is still obtainable / pollable.

Root cause

Verified in tree on 6dd8fe23 (#1893):

  1. OneLoopStudio evaluates G.A.T.E. before pollStudioDeploy with STUDIO_DEPLOY_ATTEMPT_STARTED_HOLD. That HOLD + er:gate:v1:{runId} is the AXIOM terminal residual.
  2. GET /api/workflows/studio-deploy/:runId only attaches result when completed/failed. A still-running WDK job is invisible to the client, so exhausted polls claimed kickoff-no-job even when a job may still be pollable.
  3. Client window was 210×2s = 420s. WDK kickoff retry (45s+10s+45s) + 36×10s job reads is ≥460s, so the client can stop while Origin is still running.
  4. Client getStudioDeployStatus only read top-level result.live_url, so a nested deployment.urls.vercel was dropped.

This is not an invented hostname and not a guessed Hayden secret.

What changed

  • G.A.T.E. runs after poll only. Stale gateReceipt still clears; new runId still binds. No in-flight waiting HOLD.
  • studioDeployPollResidual classifies: live URL → null; still-running (no visible job / still pollable) → STUDIO_ORIGIN_STILL_POLLABLE_HOLD; terminal + no job → kickoff-no-job; terminal + job + no URL → hostname-finished.
  • Client poll window covers kickoff retry + 36×10s (280×2s).
  • Shared extractBackendLiveUrl on the client GET so nested vercel hosts pass through.

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 merge.
  • Did not production-dogfood AXIOM here (no signed-in uvai.io / Origin job from this agent).

Hayden stop (not taken)

No job error in this tree proves a missing credential only Hayden has. If a later AXIOM job error proves that, that is the Loop→CoS ask — not guessed here.

Scope

  • Included: drop in-flight HOLD, residual classifier, poll budget, nested live_url extract, 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 / kickoff-no-job / Attempting-deploy hang / stale #1853 receipt tests still assert those strings are absent from the wrong path. New residual for a still-running wrun_01M2B9NW5JA5JQNBTWDRRSHXD6 is still-pollable, not attempt-started.

Risk

  • Risk level: low
  • Failure mode: a still-running WDK run now HOLDs still-pollable instead of a fake waiting/finished residual; true finished-without-hostname stays hostname-finished
  • Rollback: revert this PR; fix: terminalize studio.deploy so Attempting deploy cannot hang #1893 terminalization (no Attempting-deploy hang, stale receipt clear) remains

Verification

Head: 7a11ac2c1eb76b7ed828d18a195f47a70d0dd6de

  • Focused Vitest: 7 files / 121 passed (studio-workflow, gate-transition, studio-pipeline-status, pipeline-async-job, studio-deploy, studio-deploy route + [runId] route)
  • 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_HheLD9BJr8jts34NDQgMGcta2Fnb / wrun_01M2B9NW5JA5JQNBTWDRRSHXD6 / Deploy attempt started. Waiting for a verified https live URL. Proof used: tree on 6dd8fe23 (in-flight G.A.T.E. HOLD, GET result only on completed/failed, 420s client window, top-level live_url only).

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 

#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>
@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: cdb48245-f085-4c92-9d6a-f6f354bd796f


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.

@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:30pm 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>
@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-p3wn5ua1j-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:30:57
�[2m   Duration �[22m 3.25s�[2m (transform 44ms, setup 0ms, import 53ms, tests 3.10s, 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 7a11ac2.
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 9f407b4 into main Sep 12, 2026
40 of 42 checks passed
@kk-agent
kk-agent deleted the cursor/studio-deploy-precise-hold-b051 branch September 12, 2026 17:37
@linear-code

linear-code Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

GRV-541

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