Skip to content

refactor(cf-v2): manual persistent-dev dispatch uses the standard pipeline (remove the manual job) - #93

Draft
ClaudiaFang wants to merge 4 commits into
mainfrom
claude/unify-manual-auto-delivery-4e2cc1
Draft

ClaudiaFang wants to merge 4 commits into
mainfrom
claude/unify-manual-auto-delivery-4e2cc1

Conversation

@ClaudiaFang

@ClaudiaFang ClaudiaFang commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Summary

A manual workflow_dispatch of Persistent Dev no longer has its own implementation, and no caller can bring its own publish step. Exactly four delivery kinds (production, native-branch, native-dev, persistent-dev) share one audited engine and one DAG; the trigger decides when, the kind decides where.

1. Before / after DAG

Before (manual): workflow_dispatch -> persistent-dev / manual (build -> audit -> migrate -> publish by a caller command -> smoke); CI, Plan, Migrate and Revert skipped.
After (manual and automatic identical): Push / Dispatch -> CI + Validation Gate -> Plan -> Migrate (only if needed) -> Delivery(kind): Deploy -> Smoke -> Conditional Revert -> Release (verified Production only).

2. Removed

  • The manual job, its input and routing; engine mode; the CI bypass for a dispatch.
  • Custom Dev publishing: dev_deploy_cmd execution, PUBLISH_CMD, and (after an intermediate revision) the whole guard layer built to police it - wrangler-guard.sh, wranglerPublishBlock, devPublishCmdBlock, the wrangler-guard / publish-cmd-check CLIs, the shim installation and their tests. None of that exists in the final diff.
  • The engine is the only publisher: build (dev_build_cmd or build_cmd) -> audit the effective Wrangler config and D1/Worker identity -> wrangler deploy --config <audited> (plus --env <dev env> only for an audited source config; flattened configs never take an env) -> Smoke. Config SHA, artifact digest, stale-SHA guards, D1 identity and "never migrate inside Deploy" are unchanged.
  • dev_deploy_cmd stays declared but retired: a non-empty value fails the Plan before anything is built, migrated or published, with an explicit message (a stale caller gets that instead of a workflow-syntax error). All other public inputs and outputs are unchanged.

3. Final modified files (23 vs main; why each remains)

Workflows: _cf-worker-v2.yml (Plan if, CI target env, retired input, concurrency/routing), _cf-worker-delivery.yml (manual job removed), _cf-worker-ci.yml + actions/cf-ci-check/action.yml (CI env input). Engine: delivery.mjs (target resolution, D1 recovery rule, ciTargetEnv), cli.mjs (plan rejection, recovery-guard), engine.sh (recovery guard, mode removal), publish.sh (reverted to the single publisher), actions/cf-deploy/action.yml. Docs/openspec (5 files + 2) updated to the final architecture. Tests: delivery.test.mjs, test-jobs.py, jobrunner.py, ghexpr.py (startsWith), run-job-groups.py, test-deploy.sh, test-workflow-contract.py.
Net size: this PR vs main: 23 files, +609 / -309. The final cleanup commit alone vs the previous PR head: 18 files, +104 / -312 (the guard layer and its tests removed).

4. CI target environment

Scenario CI env (VITE_APP_ENV, imported build env)
push main prod
Native Branch only preview
Native Dev only preview (existing contract)
Persistent Dev only, automatic push dev
Persistent Dev, manual dispatch (approved ref or main) dev (same build_env_dev, same VITE_APP_ENV as the automatic run)
dispatch of main without target prod
several kinds at once preview (existing shared-validation policy; each kind's own build + audit still validates its actual config downstream)
pull request preview
Resolved by an expression on the existing CI call (JS twin ciTargetEnv), exactly one build env imported, ci_env applied after it, no Cloudflare credentials in CI, no extra job, no dependency on the Plan. The contract test compares the expression with the twin on 960 scenarios and checks dev <=> the run's only target (per resolveDeliveryTargets) is persistent-dev; executed cf-ci-check tests assert the actual values the CI commands receive.

5. Preserved safety fixes

dispatch_target fails closed (valid only for workflow_dispatch, only persistent-dev, tag/PR/push/delete with a target ends red via the Plan if:); non-Production recovery D1 guard (nonProdRecoveryBlock, same rule as Production; missing/mismatched/destructive/unattested -> blocked, D1 never reverted); one dedicated Migrate job; manual and automatic Dev share one concurrency group; Release only after a verified Production delivery (never from a dispatch).

6. Consumers (public summary; detail kept out of this PR)

Every branch of every consumer workflow was searched for dev_deploy_cmd. Exactly two hits: (a) one consumer app on its default branch (legacy persistent Dev command), whose open draft PR moves it to Native Dev and removes the input - that PR must be merged and its Native Dev deployment verified before the shared v2 tag moves; (b) a legacy-contract fixture inside the scratch-caller repo (test workflow; it will fail the Plan by design, retire or update it). All other consumers set no dev_deploy_cmd (Dev users already set dev_build_cmd) and are unaffected. v2 stays unchanged. Merging this PR does not affect consumers by itself; only promoting v2 does. No consumer repo was modified.

7. Tests (actually run, HEAD of this PR)

scripts/cf-preview/test.sh full: workflow contract, node unit + cli, deploy, migrate, smoke, parse-env, probe, gh, testsh, gc unit, delivery chain groups (108s) all ok -> PASSED (full). Explicit regressions: Dev build -> audited config -> engine publish -> content Smoke -> verified; failed publish -> Deploy red, smoke_status=none, no recovery, no verified result, no Release; retired dev_deploy_cmd -> Plan fails with nothing built/migrated/published.
Not run: actionlint and shellcheck - not installed here and installing them was refused by the environment, so no result is claimed. The earlier reviewer actionlint run covers an older revision.

8. Scratch-caller validation: not performed (blocker)

No authorized, isolated non-Production environment or credentials were available to this session, so none of the 8 live cases (automatic Dev push, approved / unauthorized / main dispatch, invalid target, successful Smoke, failed Smoke with recovery, failed Smoke after a destructive migration) was executed on GitHub Actions. All of them are covered only by the stub-based executed-chain tests. Needed: a run of the scratch caller pinned to this PR's SHA with an isolated scratch Worker + D1.

9. Known risks

  • No live evidence yet (see 8): dispatch run-level group, Plan if:, Dev CI env and the recovery guard are verified against stubs only.
  • dev_deploy_cmd is a breaking change for any caller that sets it; the transition is an explicit Plan error, and only promoting v2 exposes callers.
  • Recovery of Dev/Preview with pending migrations is blocked unless d1_rollback_compat: expand-contract and the scan is additive (intended).
  • A tag dispatch with a target now fails red; without a target it is still skipped.
  • Engine mode removal: no mode in the Shared Dev ledger payload, no cf-deploy mode: input, no "(manual|auto)" in the summary.

10. Recommendation

Ready for review; merge after approval. v2: No-Go until (1) the consumer Native Dev PR is merged and verified, (2) the scratch-caller run on this SHA, (3) actionlint + shellcheck. No tag moved, nothing merged, no Production deploy.

🤖 Generated with Claude Code

ClaudiaFang and others added 4 commits November 6, 2026 03:17
…eline (remove the manual delivery job and mode)

A workflow_dispatch with dispatch_target=persistent-dev now only selects the persistent-dev kind in the Plan; CI, Plan, Migrate,
Deploy, Smoke and conditional Rollback are the same as for an automatic Shared Dev push. The delivery workflow has only
deploy / smoke / rollback; the manual job, input, legacy two-command contract and the engine mode input are removed.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…add manual-dispatch failure tests

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…target, non-production D1 recovery guard, publish-only dev_deploy_cmd guard

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…cmd and the Wrangler guard); Dev CI env for automatic Persistent Dev

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
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.

1 participant