From a6e16ac75c9c2f52a7d209931ccad267b5bae634 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 19 Aug 2026 10:44:26 +0000 Subject: [PATCH 1/2] Export a PackageServiceInstance stub so production can drop the binding. Cloudflare error 10064 blocks a runtime deploy that stops exporting the transferred class while objects still exist. Keep the stub exported and the binding omitted; delete the class in a follow-up after this binding-only deploy. Co-authored-by: me --- .../runtime-worker-migration-runbook.md | 17 ++++++++++------- .../0025-no-package-services-primitive.md | 15 ++++++++------- packages/runtime-worker/wrangler.jsonc | 12 +++++++----- .../worker/src/package-service-instance-stub.ts | 9 +++++++++ packages/worker/src/runtime-worker.ts | 2 ++ 5 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 packages/worker/src/package-service-instance-stub.ts diff --git a/docs/contributing/architecture/runtime-worker-migration-runbook.md b/docs/contributing/architecture/runtime-worker-migration-runbook.md index 941415e885..077f8a001a 100644 --- a/docs/contributing/architecture/runtime-worker-migration-runbook.md +++ b/docs/contributing/architecture/runtime-worker-migration-runbook.md @@ -171,15 +171,18 @@ npm run deploy -- --config packages/worker/wrangler-production.generated.json A class that arrived on `kody-runtime` through `transferred_classes` keeps a remote binding until a deploy publishes config without that binding. Cloudflare rejects a same-deploy `deleted_classes` migration while that binding still -exists (error 10061). Drop the binding first, then add the `deleted_classes` -migration and its `tools/ci/do-deletion-allowlist.json` entry on a later deploy. +exists (error 10061). Existing objects also require the script to keep exporting +the class until `deleted_classes` runs (error 10064). Export a stub, drop the +binding, then add the `deleted_classes` migration and its +`tools/ci/do-deletion-allowlist.json` entry on a later deploy. `PackageServiceInstance` is in that window on production: the transferred -binding is still present, so top-level runtime-worker tag `v2` is deferred until -after the binding-only deploy. Preview keeps `v2` and the matching -`tools/ci/do-deletion-allowlist.json` entry because a fresh worker applies `v1` -`new_sqlite_classes` and cannot create an unexported class (error 10070). The -follow-up reuses that allowlist entry when it restores top-level `v2`. +objects still exist, so the runtime worker exports a stub and top-level tag `v2` +is deferred until after the binding-only deploy. Preview keeps `v2` and the +matching `tools/ci/do-deletion-allowlist.json` entry because a fresh worker +applies `v1` `new_sqlite_classes` and cannot create an unexported class (error +10070). The follow-up reuses that allowlist entry when it restores top-level +`v2` and removes the stub. ## Rollback diff --git a/docs/contributing/decisions/0025-no-package-services-primitive.md b/docs/contributing/decisions/0025-no-package-services-primitive.md index 7a6c8d897e..da5601b7e1 100644 --- a/docs/contributing/decisions/0025-no-package-services-primitive.md +++ b/docs/contributing/decisions/0025-no-package-services-primitive.md @@ -37,10 +37,11 @@ discovering those storage ids until that purge succeeds. Deleting `PackageServiceInstance` on production `kody-runtime` is two deploys. The class arrived through a `transferred_classes` migration, so Cloudflare still -has a remote binding after the source binding is gone. A same-deploy -`deleted_classes` migration fails with error 10061. Drop the remote binding -first, then apply top-level runtime-worker tag `v2` `deleted_classes`. The -`tools/ci/do-deletion-allowlist.json` entry for that tag stays for preview `v2` -and is the same contract the follow-up reuses. Preview keeps `v2` because a -fresh worker applies `v1` `new_sqlite_classes` and cannot create an unexported -class (error 10070). +has a remote binding and existing objects after the source binding is gone. A +same-deploy `deleted_classes` migration fails with error 10061. Dropping the +binding without exporting the class fails with error 10064. Export a stub, drop +the remote binding, then apply top-level runtime-worker tag `v2` +`deleted_classes` and remove the stub. The `tools/ci/do-deletion-allowlist.json` +entry for that tag stays for preview `v2` and is the same contract the follow-up +reuses. Preview keeps `v2` because a fresh worker applies `v1` +`new_sqlite_classes` and cannot create an unexported class (error 10070). diff --git a/packages/runtime-worker/wrangler.jsonc b/packages/runtime-worker/wrangler.jsonc index 66a9fc6ccd..03d26c0944 100644 --- a/packages/runtime-worker/wrangler.jsonc +++ b/packages/runtime-worker/wrangler.jsonc @@ -74,11 +74,13 @@ }, ], }, - // Production still has the transferred PackageServiceInstance - // binding (error 10061). Do not add deleted_classes here until - // after this binding-only deploy lands. Preview keeps tag v2 - // because a fresh worker applies v1 new_sqlite_classes and - // cannot create an unexported class (error 10070). + // Production still has transferred PackageServiceInstance + // objects. deleted_classes while the remote binding exists is + // error 10061; dropping the binding without exporting the class + // is error 10064. Export the stub, drop the binding here, then + // add tag v2 after this deploy. Preview keeps v2 because a + // fresh worker applies v1 new_sqlite_classes (error 10070 + // without the delete). ], "observability": { "enabled": true, diff --git a/packages/worker/src/package-service-instance-stub.ts b/packages/worker/src/package-service-instance-stub.ts new file mode 100644 index 0000000000..86e0027f36 --- /dev/null +++ b/packages/worker/src/package-service-instance-stub.ts @@ -0,0 +1,9 @@ +import { DurableObject } from 'cloudflare:workers' + +/** + * Temporary export so production `kody-runtime` can drop the transferred + * `PackageServiceInstance` binding. Existing Durable Objects still require + * the class to be exported (Cloudflare error 10064). Remove this module when + * top-level runtime-worker tag `v2` `deleted_classes` lands. + */ +export class PackageServiceInstance extends DurableObject {} diff --git a/packages/worker/src/runtime-worker.ts b/packages/worker/src/runtime-worker.ts index d73e9b814c..30be1e0cb0 100644 --- a/packages/worker/src/runtime-worker.ts +++ b/packages/worker/src/runtime-worker.ts @@ -5,6 +5,7 @@ import { } from '@kody-internal/shared/runtime-worker.ts' import { StorageRunner } from './storage-runner.ts' import { RunLog } from './run-records/run-log-do.ts' +import { PackageServiceInstance } from './package-service-instance-stub.ts' import { PackageRealtimeSession } from '#worker/package-runtime/realtime-session.ts' import { DynamicCallableWorkflow } from '#worker/package-runtime/package-workflows.ts' import { PackageAppRuntimeBridge } from '#worker/package-runtime/package-app.ts' @@ -41,6 +42,7 @@ export { StorageRunner, RunLog, PackageRealtimeSession, + PackageServiceInstance, DynamicCallableWorkflow, PackageAppRuntimeBridge, KodyFetchGateway, From 28584451e93308e5d00798d96e9a8bf9a359b627 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 19 Aug 2026 10:48:35 +0000 Subject: [PATCH 2/2] Omit preview v2 while the PackageServiceInstance stub is exported. Preview failed with Cloudflare 10074: delete-class requires the previous script version to export the class. Keep the stub, drop the binding, and defer v2 on both production and preview until the follow-up. Co-authored-by: me --- .../architecture/runtime-worker-migration-runbook.md | 12 +++++------- .../decisions/0025-no-package-services-primitive.md | 10 +++++----- packages/runtime-worker/wrangler.jsonc | 12 ++++-------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/docs/contributing/architecture/runtime-worker-migration-runbook.md b/docs/contributing/architecture/runtime-worker-migration-runbook.md index 077f8a001a..aaa7339f9a 100644 --- a/docs/contributing/architecture/runtime-worker-migration-runbook.md +++ b/docs/contributing/architecture/runtime-worker-migration-runbook.md @@ -176,13 +176,11 @@ the class until `deleted_classes` runs (error 10064). Export a stub, drop the binding, then add the `deleted_classes` migration and its `tools/ci/do-deletion-allowlist.json` entry on a later deploy. -`PackageServiceInstance` is in that window on production: the transferred -objects still exist, so the runtime worker exports a stub and top-level tag `v2` -is deferred until after the binding-only deploy. Preview keeps `v2` and the -matching `tools/ci/do-deletion-allowlist.json` entry because a fresh worker -applies `v1` `new_sqlite_classes` and cannot create an unexported class (error -10070). The follow-up reuses that allowlist entry when it restores top-level -`v2` and removes the stub. +`PackageServiceInstance` is in that window: the runtime worker exports a stub +and omits tag `v2` so production can drop the remote binding. Preview also omits +`v2` while the stub is exported; `deleted_classes` fails with error 10074 when +the previous script version did not export the class. The allowlist entry stays +for the follow-up that restores `v2` and removes the stub. ## Rollback diff --git a/docs/contributing/decisions/0025-no-package-services-primitive.md b/docs/contributing/decisions/0025-no-package-services-primitive.md index da5601b7e1..0662aea9af 100644 --- a/docs/contributing/decisions/0025-no-package-services-primitive.md +++ b/docs/contributing/decisions/0025-no-package-services-primitive.md @@ -40,8 +40,8 @@ The class arrived through a `transferred_classes` migration, so Cloudflare still has a remote binding and existing objects after the source binding is gone. A same-deploy `deleted_classes` migration fails with error 10061. Dropping the binding without exporting the class fails with error 10064. Export a stub, drop -the remote binding, then apply top-level runtime-worker tag `v2` -`deleted_classes` and remove the stub. The `tools/ci/do-deletion-allowlist.json` -entry for that tag stays for preview `v2` and is the same contract the follow-up -reuses. Preview keeps `v2` because a fresh worker applies `v1` -`new_sqlite_classes` and cannot create an unexported class (error 10070). +the remote binding, then apply runtime-worker tag `v2` `deleted_classes` and +remove the stub. The `tools/ci/do-deletion-allowlist.json` entry for that tag +stays for the follow-up. Preview also omits `v2` while the stub is exported: +`deleted_classes` fails with error 10074 when the previous script version did +not export the class. diff --git a/packages/runtime-worker/wrangler.jsonc b/packages/runtime-worker/wrangler.jsonc index 03d26c0944..c92b843243 100644 --- a/packages/runtime-worker/wrangler.jsonc +++ b/packages/runtime-worker/wrangler.jsonc @@ -77,10 +77,10 @@ // Production still has transferred PackageServiceInstance // objects. deleted_classes while the remote binding exists is // error 10061; dropping the binding without exporting the class - // is error 10064. Export the stub, drop the binding here, then - // add tag v2 after this deploy. Preview keeps v2 because a - // fresh worker applies v1 new_sqlite_classes (error 10070 - // without the delete). + // is error 10064. Export the stub and omit the binding here. + // Add tag v2 after this deploy. Preview also omits v2: a + // delete-class on a script whose previous version did not + // export the class is error 10074. ], "observability": { "enabled": true, @@ -270,10 +270,6 @@ "PackageServiceInstance", ], }, - { - "tag": "v2", - "deleted_classes": ["PackageServiceInstance"], - }, ], "worker_loaders": [ {