Before you submit
What happened?
The Cloudflare Pages deploy provider always creates a production deployment served at the public root <project>.pages.dev, even though both DeployConfigResponse.target and DeploymentInfo.target are typed as 'preview'. There is no config or API option to request a non-production (preview) deployment, so a generated artifact is publicly live the instant it's deployed — you can't stage a gated preview URL for review before it goes public.
Steps to reproduce
- Configure the Cloudflare Pages deploy provider (token + account ID).
- Deploy any project artifact (
POST /api/projects/<id>/deploy with providerId: "cloudflare-pages").
- Note the returned
url is the production root <project>.pages.dev and is publicly reachable immediately.
- In the Cloudflare dashboard, open the deployment → Environment = Production (never Preview).
- There is no setting or request field to make this a preview deployment.
Expected behavior
Because the deploy config and every DeploymentInfo are declared target: 'preview', a deploy should be able to produce a Cloudflare Pages preview deployment — a <hash>.<project>.pages.dev URL (deploy branch ≠ production_branch) that can be Access-gated, leaving the production hostname untouched. At minimum, OD should expose an explicit choice between production and preview rather than silently forcing production.
Open Design version
0.10.2 (od --version; reproduced on main @ 2ff2d79)
Platform
macOS (Apple Silicon) — but the defect is in the daemon deploy code and is platform-independent.
Additional context
Root cause (traced to source):
apps/daemon/src/deploy.ts:498 hardcodes form.append('branch', 'main') on the deployment FormData.
apps/daemon/src/deploy.ts:1000 sets production_branch: 'main'. Cloudflare Pages treats branch === production_branch as Production, so every deploy is Production.
target: 'preview' (deploy.ts:168/182/432/543, routes/deploy.ts:125) and the contract literals (packages/contracts/src/api/projects.ts:506,527) are never translated into the Cloudflare deploy branch — the label only feeds internal metadata and DNS (pagesTarget, deploy.ts:628, is derived from the pages.dev hostname, not the branch).
routes/deploy.ts accepts no branch/target override, so no caller can request a non-production deploy.
Suggested minimal direction: derive the deploy branch from an explicit deploy mode (preview → a non-main branch such as preview; publish/approve → main) and thread an optional target through routes/deploy.ts. This also unblocks #2357 (versioned handoff publishing), which presumes a working preview path.
Before you submit
od --version.What happened?
The Cloudflare Pages deploy provider always creates a production deployment served at the public root
<project>.pages.dev, even though bothDeployConfigResponse.targetandDeploymentInfo.targetare typed as'preview'. There is no config or API option to request a non-production (preview) deployment, so a generated artifact is publicly live the instant it's deployed — you can't stage a gated preview URL for review before it goes public.Steps to reproduce
POST /api/projects/<id>/deploywithproviderId: "cloudflare-pages").urlis the production root<project>.pages.devand is publicly reachable immediately.Expected behavior
Because the deploy config and every
DeploymentInfoare declaredtarget: 'preview', a deploy should be able to produce a Cloudflare Pages preview deployment — a<hash>.<project>.pages.devURL (deploy branch ≠production_branch) that can be Access-gated, leaving the production hostname untouched. At minimum, OD should expose an explicit choice between production and preview rather than silently forcing production.Open Design version
0.10.2 (
od --version; reproduced onmain@2ff2d79)Platform
macOS (Apple Silicon) — but the defect is in the daemon deploy code and is platform-independent.
Additional context
Root cause (traced to source):
apps/daemon/src/deploy.ts:498hardcodesform.append('branch', 'main')on the deployment FormData.apps/daemon/src/deploy.ts:1000setsproduction_branch: 'main'. Cloudflare Pages treatsbranch === production_branchas Production, so every deploy is Production.target: 'preview'(deploy.ts:168/182/432/543,routes/deploy.ts:125) and the contract literals (packages/contracts/src/api/projects.ts:506,527) are never translated into the Cloudflare deploy branch — the label only feeds internal metadata and DNS (pagesTarget,deploy.ts:628, is derived from the pages.dev hostname, not the branch).routes/deploy.tsaccepts nobranch/targetoverride, so no caller can request a non-production deploy.Suggested minimal direction: derive the deploy branch from an explicit deploy mode (preview → a non-
mainbranch such aspreview; publish/approve →main) and thread an optionaltargetthroughroutes/deploy.ts. This also unblocks #2357 (versioned handoff publishing), which presumes a working preview path.