Skip to content

feat(cf-v2): unified target-driven delivery (Native Dev, smoke modes, migration stage) - #89

Merged
ClaudiaFang merged 36 commits into
mainfrom
claude/cf-workers-cicd-v2-refactor-5167d9
Nov 3, 2026
Merged

ClaudiaFang merged 36 commits into
mainfrom
claude/cf-workers-cicd-v2-refactor-5167d9

Conversation

@ClaudiaFang

@ClaudiaFang ClaudiaFang commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

Refactor Cloudflare Workers v2 CI/CD in place to reduce orchestration duplication while retaining one shared delivery engine, one normal-pipeline D1 Migration job, per-target Smoke/Recovery, deferred verification, and the existing public workflow inputs/outputs.

Current reviewed HEAD: 8ad4d40 (includes the P1 stale-migration fix). Latest PR CI: run 41595263650 — passed. This PR has not been merged; main, the floating @v2 tag, and consumer repositories have not been changed by this PR.

Current DAG

Consumer workflow
  └─ _cf-worker-v2.yml (public)
       ├─ CI → _cf-worker-ci.yml
       │    ├─ Lint ─────────────┐
       │    ├─ Typecheck ────────┤
       │    ├─ Unit ─────────────┤
       │    ├─ Integration ──────┤ parallel
       │    ├─ Build Validation ─┤
       │    └─ E2E (matrix) ─────┘
       │                 ↓
       │           Validation Gate
       ├─ Delivery Plan (enabled targets + one physical D1)
       ├─ Database Migration (ONE job; validate all targets before mutation)
       ├─ Delivery × enabled kind → _cf-worker-delivery.yml
       │    ├─ Production ───────┐
       │    ├─ Native Branch ────┤ Deploy → Smoke → conditional Rollback
       │    ├─ Native Dev ───────┤ (one shared implementation, isolated results)
       │    └─ Persistent Dev ───┘
       └─ Release (main + verified Production only)

Other event paths (not part of the delivery DAG):
  same-repo PR / branch delete → _cf-worker-lifecycle.yml
  approved manual Persistent Dev → _cf-worker-persistent-dev.yml
  pipeline_phase=verify → Plan (restored handoff) → Smoke → optional Rollback

The four Delivery job definitions are conditional; disabled targets do not execute. The normal pipeline has no separate Preflight job/matrix. stage: preflight remains as read-only validation inside the single Migration job.

Key changes

  • Reusable CI: Move six independent checks and their fail-closed Validation Gate into _cf-worker-ci.yml. Same-repo PR does not rerun CI already covered by branch push; fork PRs run credential-free validation.
  • One physical-D1 migration per invocation: The Plan deduplicates shared D1 bindings and rejects two distinct physical D1s before mutation. The Migration job audits enabled target builds and effective Wrangler/D1 bindings first; d1_migrations: false skips Migration without blocking Delivery.
  • One delivery implementation: Four thin target calls reuse _cf-worker-delivery.yml and actions/cf-deploy for Build/Audit/Publish → Smoke → guarded Rollback. Deployment outputs, environment approvals, concurrency and rollback decisions remain target-specific.
  • Event handlers extracted: Preview PR comment/branch deletion and the protected manual Persistent Dev route now live in dedicated small internal workflows. Manual Persistent Dev retains its existing engine and legacy-command options.
  • Self-repository references: Nested workflows/actions use $/..., binding tooling to the called workflow's exact repository commit and removing the redundant .cf-tools checkouts. tools_ref remains accepted but is deprecated, optional and ignored.
  • Public interface: All 60 input names and 20 output names remain available. The opaque phase_state handoff omits a redundant internal d1 map; pass it through unchanged. Check-context names do change due to CI extraction.

Security / P1 resolution (fixed at HEAD 8ad4d40)

The previous resolveMigrationUsed() accepted a Migration result with stale=true without proving that any D1 migration ran. In a potential branch A → B → A force-push race, a later fresh-SHA check would not prove migration completion.

Fixed: the publish-stage Migration Gate now rejects stale (true or "true"), absent/malformed result, failed/skipped Migration, missing or incorrect owner, non-applied result, or mismatched physical D1. The Gate runs before publish-stage build or mutation. d1_migrations=false and deferred pipeline_phase=verify remain supported. Regression coverage includes A → B → A, no unauthorized Publish/Smoke/Rollback/Release.

Additional protections retained: Production/non-production D1 isolation; effective Wrangler config validation; protected Production Environment; stale-SHA guards; Smoke full|basic|skip; target-specific recovery; Release only after verified Production; no automatic schema rollback.

Scope and metrics

Metric Before this extraction Current
Public _cf-worker-v2.yml 1,081 lines 769 lines
_cf-worker-delivery.yml 320 lines 282 lines
Total five pipeline workflows 1,401 lines 1,516 lines (+8%)
Separate Preflight jobs 0 0
Normal-pipeline Migration jobs 1 1
Shared tooling repository checkouts (representative feature push) up to 11 0
Delivery implementations 1 1

The benefit is separation of responsibilities and less duplicated setup, not lower total YAML line count. Available real-runner comparison (n=1 per scenario) shows no established runtime improvement.

Verification evidence

  • Latest reviewed HEAD 8ad4d40: PR CI run 41595263650 — passed. Fast profile, Chain profile (mocked Cloudflare/GitHub), ShellCheck and Actionlint all passed; includes the stale-migration regression tests.
  • Earlier implementation SHA 3bda5fb (before P1 fix): PR CI run 41589279882 — passed; cross-repository disposable scratch-caller evidence confirms $/ resolution, parallel CI and Validation Gate, D1 gating and skip cases, distinct-D1 rejection, deferred verification, manual Persistent Dev and lifecycle. Examples: parallel CI, CI failure blocks delivery, migration disabled, two D1s rejected, legacy manual Dev, PR lifecycle. Several scratch runs intentionally conclude failure because Cloudflare credentials were withheld; their intended gates and observed steps are recorded in the docs.
  • Post-P1-fix cross-repo scratch run pinned to 8ad4d40: done, see Final merge-readiness verification below.
  • Still not demonstrated: live non-production D1 migration / publish / smoke / recovery (BLOCKED, no approved credentials); protected Environment approval; consumer Required Check migrations (unreadable, administrator action); GHES or runners older than 2.336.0.

Final merge-readiness verification (implementation 8ad4d40, 2026-11-03)

Implementation is unchanged since 8ad4d40; a docs-only commit recording the details below (fd6ab85, touching docs/cf-worker-v2-refactor.md, docs/cf-worker-v2-unified-delivery.md and the OpenSpec tasks.md only) is the PR branch tip; the implementation SHA stays 8ad4d40. Nothing was merged; @v2, consumers, branch protection and Cloudflare were not changed.

1. Regression at 8ad4d40. PR CI 41595263650 passed. Local re-run on the exact SHA: test.sh fast and test.sh full PASSED (561 contract + 420 chain checks), ShellCheck 0.11.0 (+ composite-action scripts) clean, actionlint 1.7.12 clean. All nine required assertions have named passing tests (stale true/"true" blocked; missing/malformed fail closed; valid applied Migration with matching owner + physical D1 succeeds; d1_migrations=false does not block; A → B → A rejected before the build; failed Migration never starts publishing; verify never migrates; Smoke/Rollback target-isolated; Release only after verified Production).

2. Real-runner stale gate. cf-v2-scratch-caller run 41598319442 runs the real cli.mjs migration-gate entrypoint from 8ad4d40 on the org linux runner and ubuntu-latest with a validated descriptor and synthetic handoffs: stale (true and "true"), empty, malformed, none, owner mismatch, D1 mismatch and failed-Migration inputs all exit 1; valid and d1_migrations=false controls exit 0; PATH shims show no wrangler/gh/curl/pnpm/npx call (no publish-side action). (The first dispatch, 41598162595, failed on a bug in my test script — bash -e — not in the implementation.) The full A → B → A race is not reproducible on Actions without a live account; its evidence stays the chain regression.

3. Scratch caller pinned to 8ad4d40 (all referenced_workflows and nested $/ actions resolved to the same SHA; org runners 2.338.0; no Cloudflare credentials, so failure conclusions below are the designed fail-closed result and each was checked against its step message):

Scenario Run Result
Parallel CI 41598183911 7 check jobs success → Gate/Plan success → Migration skipped → Deploy preview credentials not provided (expected)
Validation failure 41598188577 Lint fails, others still run, Gate fails; Plan/Migration/Deliveries/Release skipped
Single D1 Migration 41598193186, 41598197646 exactly one Database Migration; failed closed on credentials; Deliveries skipped
Migration disabled 41598201733 Migration skipped; both Deliveries started
Distinct D1s 41598206295 Plan fails naming both D1s, nothing was changed
Deferred verification 41598211512, 41598215678 Migration skipped in both calls; Smoke from the original handoff
Same-repo PR / Branch Delete 41598279417 / 41598501202 lifecycle only (no duplicate CI); ledger retired, Preview kept
Manual Persistent Dev 41598224024, 41598228322 legacy contract success; engine contract failed closed on credentials

4. Consumer compatibility (default branches read 2026-11-03; no other consumer of _cf-worker-v2.yml exists; the real planner was run on every call × push/dispatch/PR/delete):

Repository / App Runner Required Checks D1 Deployment Action
blog yes UNVERIFIED — ADMIN ACCESS REQUIRED yes (prod 45031ada…; branch feb45b04…) yes fix secrets:; update checks
heaven-monorepo / heaven-id yes UNVERIFIED yes (prod 193440aa…; dev ca755ecb…) yes update checks
heaven-monorepo / heaven-checkin yes UNVERIFIED yes (prod 41fa4337…; dev 8e3f8323…) yes update checks
heaven-monorepo / test-client yes UNVERIFIED yes (no D1) yes update checks
innovation-apps / diet-manager yes UNVERIFIED yes (prod e12e2d9e…; preview b9421085…) yes update checks
innovation-apps / notification-hub yes UNVERIFIED yes (prod 311ab3c8…; dev 9a69f8e9…) yes update checks
anas-mcp yes yes — verified: public, no protection, no rulesets yes (no D1) yes none
heaven-www yes UNVERIFIED yes (no D1) yes fix secrets:; update checks
  • Runner: all online org runners report 2.338.0 (nine of ten listed on 2026-11-03; heavenweb-runner-10 absent) (≥ 2.336.0, confirmed by API; scratch jobs ran on heavenweb-runner-3). Node/pnpm/Playwright setup is unchanged from main. Hosted ubuntu-latest also accepted $/ but lacks pnpm.
  • Required Checks: branch protection/rulesets of the four private repos return 403 Upgrade to GitHub Pro although the token has admin rights (org plan free) — plan limit, not proof that none exist. An administrator must confirm none of these is required, or move it: <job> / Lint|Typecheck|Unit Tests|Integration Tests|Build Validation|E2E[ (variant)] → <job> / CI / …; add <job> / CI / Validation Gate; <job> / Migration → <job> / Database Migration; <job> / Deploy|Smoke Tests|Revert on Verify Failure|Shared Dev* → <job> / Delivery (<kind>) / …. <job> is Pipeline (blog, innovation-apps, heaven-www), Heaven ID / Heaven Checkin / Heaven ID Test Client, or cf (anas-mcp).
  • D1: no call plans two distinct physical D1s in any modeled event. Not modeled: the post-build effective-config audit (live only).
  • Environments: no consumer Environment has required reviewers, wait timers or branch policies, so the Production approval described above is not enforced by any consumer today; approval behaviour was not exercised.
  • Deferred verification: no consumer uses pipeline_phase/phase_state/upstream_gate.

5. Live non-production evidence — BLOCKED. The only Cloudflare credentials reachable are the Production org secrets; the scratch repository has none and no disposable, approved account/D1/protected Environment exists. Prerequisites: a scratch Cloudflare account or disposable-scope token, a throw-away D1 with migrations, scratch repo secrets, and a protected Environment with a reviewer (paid plan or public repository). No live evidence is claimed.

Rollout blocker found (not caused by this PR; must be fixed before @v2 moves): blog cicd.yml, blog preview-gc.yml and heaven-www cicd.yml pass CLOUDFLARE_PREVIEW_API_TOKEN / CLOUDFLARE_PREVIEW_ACCOUNT_ID, which neither the current @v2 (def3679) nor 8ad4d40 declares (commit 5def01d on main). GitHub rejects such a caller before any job starts — reproduced as startup_failure in 41599151750 (8ad4d40) and 41600536212 (fd6ab85); the run page reads Invalid secret, CLOUDFLARE_PREVIEW_API_TOKEN is not defined in the referenced workflow. (same for CLOUDFLARE_PREVIEW_ACCOUNT_ID); heaven-www CI/CD (41017574023) and blog Preview GC nightly runs show matching startup_failures (cause inferred, not read from a log). Remedy: drop those two lines from the three callers, or declare them as optional secrets. Fix PRs (open, not merged): blog#461, heaven-www#56; replicas of the fixed callers start against both the v2 tag and this PR (fail closed only on missing scratch credentials). Preconditions, procedure and rollback for the tag move: docs/cf-worker-v2-rollout.md.

Verdict: no merge blocker found in the implementation. Remaining items are @v2-rollout requirements: the secrets fix, administrator Required-Check confirmation/update, and live non-production evidence.

Detailed evidence: architecture/refactor guide · unified delivery + P1 fix · OpenSpec.

Compatibility and rollout requirements

  1. Check-context rename: Required Checks may change from <caller-job> / Lint to <caller-job> / CI / Lint (likewise for other checks). Audit every consumer's branch protection/rulesets before moving @v2; missing admin/ruleset visibility is unverified, not proof that no rule exists.
  2. Runner floor: $/ requires GitHub Actions runner >= 2.336.0. The tested org linux runner is newer; check all consumers' runner choices. $/ is not verified for GHES.
  3. D1 compatibility: One invocation may migrate at most one distinct physical D1. Existing expected consumer configurations appear compatible, but all supported branch/dispatch variants and live bindings must be confirmed before tag promotion. Repository-scoped concurrency does not lock a D1 shared across repositories.
  4. No live claim: Contract and stub tests are not evidence of a successful remote Cloudflare migration, publish, Smoke or Rollback. Use approved disposable non-production resources for a staged end-to-end exercise, then roll out pinned to an immutable SHA.

Review / rollout checklist

  • Single Migration + reusable Delivery architecture implemented; no Preflight jobs or Migration matrix
  • P1 stale-migration authorization fixed with unit, contract and A → B → A chain regressions
  • Fast, Chain, ShellCheck and Actionlint passed on reviewed HEAD 8ad4d40
  • Earlier cross-repository scratch caller exercised reusable-workflow structure without Cloudflare credentials
  • Repeat the critical scratch-caller checks using final 8ad4d40 (including stale Migration fail-closed on a real runner)
  • Audit consumer Required Check names, runner versions and distinct-D1 configurations (Required Checks on 4 private repos remain UNVERIFIED — administrator must confirm)
  • Final human review and approval for merge
  • Merge to main and record the immutable merged SHA only after approval
  • Validate live non-production deployment/smoke/recovery with authorized resources before moving @v2 (BLOCKED: none available)
  • Merge the consumer fixes (blog#461, heaven-www#56) that remove undeclared CLOUDFLARE_PREVIEW_* secrets before moving @v2 (PRs open; merging runs the real Production pipelines)
  • Promote @v2 / migrate consumers in a separately approved rollout

Do not merge, move @v2, or change consumers as part of this PR-description update.

ClaudiaFang and others added 30 commits October 30, 2026 06:50
…pe plan)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…IP workflow follows)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tion/Deploy/Smoke/Rollback, Native Dev, smoke modes)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… (PR #89 review P1-A/P1-B/P2-A/P2-B)

- _cf-worker-delivery.yml: one internal reusable workflow (preflight/migrate/deliver) called once per kind; no matrix, no shared output keys
- public outputs select their source by plan flags; phase_state carries each kind's own results
- canonical Preview URL resolved before the build (Cloudflare preview_url_suffix), asserted after publish; build-env origin checks
- Preflight of every enabled kind precedes any migration; shared D1 migrated once by its owner; engine binds the plan's D1 id
- contract/job/unit tests rewritten for the new topology plus regression scenarios

WIP: test-jobs.py full run and real-runner evidence still pending.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…kipped at job level on policy/gate

- rollback job `if` now also requires production policy automatic and a non-blocked cross-service gate (no no-op green rollback job)
- ghexpr: render() respects quoted `}}`, format() unescapes `{{`/`}}`
- regression scenarios for reversed completion order, per-target failure isolation, shared-D1 dedupe, URL pre-resolution, hand-off isolation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…penspec tasks; real-runner evidence outstanding

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the whole called workflow

GitHub validates the ceiling for every job of a called workflow, including jobs skipped by if:. Found by the real-runner scratch run (startup_failure).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ding and hosted-runner pnpm limitation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…uts.json with one jq

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… PR-scoped validation concurrency

test.sh fast (~10s) / chain / full; run-job-groups.py runs the 7 test-jobs.py sections
as independent processes (379 assertions, same as serial). CI: cancel superseded PR
validation only; checks keep the 'contract' job name; delivery workflow added to paths+actionlint.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rget/environment/D1/owner/group copies

Slice A. delivery.mjs: versioned descriptor (targetDescriptor/validateDescriptor/buildDescriptors/parseDescriptor);
plan emits 'descriptors'; the 12 static calls pass one 'descriptor' instead of 6 fields; delivery workflow and the
engine (descriptor-check at init, also supplies smoke mode) consume it. persistent-dev keeps the legacy shared Dev
concurrency group (pinned by tests). Plan drops d1_*/owner_of_* outputs. Tests: delivery.test.mjs, contract, test-jobs
(4 forged-descriptor refusals).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…to delivery.mjs + engine

Slice B. checkPeerPreflights / resolveMigrationUsed (pure, unit-tested incl. every refusal); engine phase
migration-gate runs right after init for the migrate and publish stages, taking owner/D1 from the validated
descriptor. Delivery workflow loses two inline shell steps. A job that fails its gate now reports published=false
in its hand-off (was {}): two isolation assertions compare != 'true'.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…mal run and the recovery rebuild

Slice C. engine.sh run_build/run_publish replace the duplicated env blocks of build, publish and recover-run; recovery
only supplies its state dir, rebound build env/version and no host re-check. Contract test pins one build.sh and one
publish.sh invocation. Recovery scenarios (rebuild at last-good SHA, exact URL, re-smoke) unchanged and green.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… engine.sh into delivery.mjs

Slice D. verificationOutcome (only content-level verifies), prodRollbackBlock (policy, identity, no D1 schema rollback,
never over a foreign/newer deployment) and rollbackVerdict (restored_verified needs a content-level re-smoke) are pure and
unit-tested for every refusal; the engine gathers facts and performs effects. Shell scenarios unchanged and green.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ries; every group writes its perf report

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… (P1)

phase_state now carries the deploy call's validated descriptor map; the verify plan restores it (restoreDescriptors) and
only moves phase deploy -> verify. Cross-checked against kinds, app, repository, D1 ids and migration owner; wrong/forged
state fails the plan closed; a legacy hand-off is rebuilt only from the deploy call's own inputs. Unit tests + end-to-end
deferred scenarios (skip policy, shared-db lock, tamper cases); mutation check proves the scenarios catch the old bug.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…cks)

validateInit (delivery.mjs, pure, unit-tested for every refusal) replaces ~6 Node spawns + jq in engine.sh init: target/kind/stage/
mode binding, descriptor, strategy/policy, enabled kind, per-target requirements, URL isolation and env data. Credentials stay an
explicit shell check; state files are written only after every check passed. parse-env.mjs entry guard no longer throws when imported.
Measured (one Production chain, system-wide execve): node 17 -> 9, total 567 -> 549; engine init 213 ms -> 59 ms avg.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ewriting

test-jobs.py is now shared fixtures + eight explicit group_* functions registered in GROUPS (--list / --group ID); the
deferred-verification scenarios are their own group. run-job-groups.py is a thin launcher: bounded parallelism (CF_V2_TEST_JOBS or
min(4, CPUs)), a MANIFEST of expected groups with minimum check counts, and it fails on a missing/unexpected/empty/shrunken/skipped
group or a missing perf report. 393 checks = the 379 before + 14 added this session; no assertion removed or weakened.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Removes the 'kind' input beside the descriptor from the 12 calls and the delivery workflow (11 uses): one canonical record, no way for a
call to disagree with its own descriptor. Contract and harness updated accordingly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pinned to 506c101; OpenSpec Phase 1 tasks

Docs and OpenSpec only; code is identical to the validated SHA 506c101.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…1 ownership, fail-fast Full

1. Deferred verify: the top-level concurrency expression now applies the deploy expression to phase_state.inputs (never the caller-supplied
   group string); restoreDescriptors requires phase_state.group to equal runLockGroup(deploy inputs) and the Persistent Dev deploy/rollback
   locks to equal the repository + app + deploy-time d1_lock_scope identity. JS twin (runLockGroup) is contract-tested against the rendered
   YAML expression on 512 scenarios in deploy and verify mode.
2. cli.mjs workflow annotations (::error/::warning/::notice/::add-mask) go to stderr: stdout is only key=value records, so a rejected input
   can no longer add an 'Invalid format' error to $GITHUB_OUTPUT. The job harness now enforces GitHub's output-file format. cli.test.mjs.
3. Legacy phase_state: migration ownership is reconstructed per physical D1 only when every member result proves the same owner on the
   same D1; missing/conflicting evidence fails closed; non-D1 hand-offs unchanged.
4. test.sh full: Chain is not started when Fast failed; tooling pre-check; test-testsh.sh.
404 chain checks (393 + 11), 65 delivery + 7 cli unit tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…al-runner evidence (8ad9f5f); OpenSpec

Docs/OpenSpec only; code identical to the validated SHA 8ad9f5f.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nd four Migration calls

- _cf-worker-v2.yml: the eight reusable-workflow calls (preflight_*, migration_*) become ONE job. Its first steps are the
  read-only pre-mutation checks (stage preflight for each non-owner target: target build, effective-config audit, exact D1
  binding), its last engine step migrates once (stage migrate, which validates the owner the same way before the mutation).
  Environment = the plan's migration owner (<app>/prod on main). Skipped when d1_migrations is off; Delivery proceeds.
- plan: single-DB rule. Identical D1s dedupe, distinct physical D1s fail the plan before any mutation; outputs `migration`
  (owner, environment, d1 id) replaces owns_<kind>.
- _cf-worker-delivery.yml: only deploy / smoke / rollback; stage, kinds, peers, own_/owner_migration_* removed, replaced by
  migration_result / migration_json. A failed Migration skips every dependent Delivery at job level.
- engine: init starts from a clean state (several engine calls per job); migration gate only for publish; peer-preflight
  bookkeeping (checkPeerPreflights) removed.
- tests: contract, job-chain, delivery.mjs, cli.mjs updated in the same slice; migration_status is an always-run status step.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…Migration documentation and measurements

- engine/cf-deploy: the Migration job calls the engine once per validated target; the tooling npm ci and the application Setup run once
  per job (CFV2_DEPS, reserved env name); init only wipes the engine's own default state dir.
- _cf-worker-v2.yml: YAML anchors for the four identical Delivery permissions / secrets blocks and the five identical CI tooling fetches.
- docs / OpenSpec: revised decision (no Preflight stage, one Migration job), single-DB compatibility restriction, measured before/after.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… and persistent Dev as small reusable workflows

- every .cf-tools checkout is gone: shared actions and the delivery/CI/lifecycle/persistent-dev workflows are referenced with $/ (this
  repository at the running workflow's commit); tools_ref stays accepted but is a deprecated no-op
- new _cf-worker-ci.yml (six parallel checks + fail-closed Validation Gate, validation=passed verdict), _cf-worker-lifecycle.yml,
  _cf-worker-persistent-dev.yml; new actions/cf-tools (TOOLS_DIR + npm ci) for the jobs that run the tooling scripts directly
- Plan emits the canonical lock group (runLockGroup); concurrency.group loses its duplicated verify copy; phase_state drops the
  redundant per-kind d1 map and the duplicated group expression
- migration/delivery depend on the plan only (the plan already requires a passed CI)
- contract + chain tests ported (529 contract checks, 413 chain checks green)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… yet

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ClaudiaFang and others added 6 commits November 3, 2026 06:20
…runner-version note; consumer doc

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…decision, concurrency note, real-runner evidence @ 3bda5fb

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
resolveMigrationUsed accepted a result with stale=true without checking migration/owner/D1. A Migration job superseded by a newer push
succeeds as a skip, so after a force-push back to the original commit (A -> B -> A) the Delivery's branch-tip check saw a fresh tip and
published without the required migration. The gate now rejects stale (true or "true") and malformed/missing results; owner and physical
D1 stay mandatory. Tests: unit, executed engine gate, chain A->B->A. Docs + OpenSpec updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ity audit and rollout blockers

Docs and OpenSpec task state only; no implementation, workflow or test change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…re with GitHub's exact message

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…consumer fix PR status

Docs and OpenSpec task state only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ClaudiaFang
ClaudiaFang merged commit 8ff47d3 into main Nov 3, 2026
1 check passed
@ClaudiaFang
ClaudiaFang deleted the claude/cf-workers-cicd-v2-refactor-5167d9 branch November 3, 2026 09:00
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