Skip to content

feat(app-studio): report edge provisioning instead of a broken preview#419

Merged
mjudeikis merged 1 commit into
mainfrom
feat/preview-edge-provisioning-signal
Jul 11, 2026
Merged

feat(app-studio): report edge provisioning instead of a broken preview#419
mjudeikis merged 1 commit into
mainfrom
feat/preview-edge-provisioning-signal

Conversation

@mjudeikis

Copy link
Copy Markdown
Contributor

Problem

In production the preview URL is served through the Gateway edge (cfgate / Cloudflare Tunnel), which takes a minute or more to program DNS and provision the hostname's TLS certificate. The preview path declared Ready as soon as the instance had a status.url — i.e. as soon as the HTTPRoute existed — so the portal iframed a URL whose TLS handshake still fails, and the user stared at a broken preview with no explanation of "we're provisioning, please wait".

Fix

Gate preview readiness on the edge actually serving the URL:

  • templateDevelopmentPreview now probes status.url before answering Ready. Until the probe succeeds it keeps returning ready: false, reason: edge_provisioning with a human message: "Preview is getting ready. The public URL is being provisioned at the edge (DNS + TLS certificate) — this usually takes a minute or two."
  • The probe is a real HTTPS request with certificate verification on — an unprovisioned certificate failing the handshake is the signal. Cloudflare's 52x range (origin/tunnel not wired) counts as not-provisioned; any app-level status (200/302/404/503) counts as served — app readiness stays owned by the dev-runtime data plane.
  • Per-URL successes are cached for the process lifetime (certificates persist once provisioned), so steady-state preview calls pay zero probe latency; failures are re-probed on every portal poll (bounded at 4s per attempt).
  • Probe is injectable (SetPreviewEdgeProbe) for tests.

No frontend change needed: the portal already polls and renders the not-ready message ("Synced project files. "), and the assistant's preview tool passes the same payload through — both now say what's happening instead of handing out a dead URL.

Verification

New unit tests pin the gate + cache semantics and the probe classification (app-level 404 = served, 522 = provisioning, transport error = provisioning). Full app-studio go test ./..., build, vet pass.

🤖 Generated with Claude Code

In production the preview URL is served through the Gateway edge
(cfgate / Cloudflare Tunnel), which takes a minute or more to program
DNS and provision the hostname's TLS certificate. The preview path
declared Ready as soon as the instance had a status.url — i.e. as soon
as the HTTPRoute existed — so the portal iframed a URL whose TLS
handshake still fails and the user stared at a broken preview with no
explanation.

Gate readiness on the edge actually serving the URL: the preview path
probes it (real HTTPS request, certificate verification on — an
unprovisioned certificate failing the handshake IS the signal;
Cloudflare's 52x range counts as not-provisioned, any app-level status
counts as served) and keeps answering Ready=false with
reason=edge_provisioning and a human message — "being provisioned at
the edge (DNS + TLS certificate), usually a minute or two" — until the
probe succeeds. The portal already renders the not-ready message and
polls, so no frontend change is needed; the assistant's preview tool
picks up the same message.

Successes are cached per URL for the process lifetime (certificates
persist once provisioned), so the probe adds no steady-state latency;
failures are re-probed on every poll. The probe is injectable for
tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 11, 2026 15:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves App Studio’s development preview UX by preventing the portal (and assistant tooling) from presenting a “Ready” preview URL until the external edge (DNS + TLS via the Gateway/Cloudflare Tunnel) is actually serving it, avoiding broken iframes during certificate provisioning.

Changes:

  • Gate templateDevelopmentPreview readiness on a real, bounded HTTPS probe of status.url, returning reason=edge_provisioning with a user-facing message until the edge serves.
  • Add a per-URL, process-lifetime cache so successful edge readiness probes don’t add steady-state latency.
  • Add unit tests for probe gating/caching and HTTP status classification.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
providers/app-studio/api/server.go Adds server fields to support an injectable edge probe and a readiness cache.
providers/app-studio/api/project_template.go Gates preview “Ready” on edge-served URL instead of status.url presence alone.
providers/app-studio/api/preview_edge.go Implements edge probing, caching, and provisioning reason/message constants.
providers/app-studio/api/preview_edge_test.go Adds unit tests for readiness gating/caching and probe classification.

Comment on lines +108 to +110
if resp.StatusCode >= 520 && resp.StatusCode <= 530 {
return fmt.Errorf("edge answered %d (origin/tunnel not provisioned)", resp.StatusCode)
}
Comment on lines +87 to +92
dead := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
deadURL := dead.URL
dead.Close() // connection refused from here on
if err := defaultPreviewEdgeProbe(context.Background(), deadURL); err == nil {
t.Fatal("transport error must count as not provisioned")
}
@mjudeikis mjudeikis merged commit 30e79b8 into main Jul 11, 2026
22 checks passed
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.

2 participants