Skip to content

Track storage bucket ownership in D1 instead of deriving it from run history - #965

Merged
kody-bot merged 7 commits into
mainfrom
cursor/storage-bucket-ownership-8a57
Jul 26, 2026
Merged

kody-bot merged 7 commits into
mainfrom
cursor/storage-bucket-ownership-8a57

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 26, 2026 •

Copy link
Copy Markdown
Owner

Unblocks the legacy removal tracked in #956, and closes a backup gap that is live right now.

The live gap

StorageRunner Durable Objects are named [userId, storageId], and Cloudflare cannot enumerate DOs by name — so anything asking "which buckets does this user own?" has to derive it from D1. Three consumers derived it partly from package_runtime_runs, a run-history table that #955 stopped writing.

dr/exporter.ts builds the platform disaster-recovery inventory from D1 only, so a bucket created since the #955 deploy and referenced only by a run record is already missing from backups. Account deletion and export were on the same footing, just with a longer fuse: their legacy arms keep working until the rows drain around 2026-08-25, after which a bucket known only there becomes unenumerable and its Durable Object storage would survive account deletion.

Why this had to happen now rather than after the drain

The legacy package_runtime_runs rows are the only surviving record of pre-#955 ad-hoc buckets. Migration 0097 backfills from them while they still exist. Wait for the drain and that history is gone permanently, with no way to reconstruct which buckets a user owns.

What changed

Bucket ownership is now state, in a user_storage_buckets table keyed (user_id, storage_id). Deriving it from run history was the original mistake — the same state-vs-history invariant #955 added, violated one layer down.

Registration happens at the single accessor, storageRunnerRpc, on mutating operations only (setValue, deleteValue, importStorage, and sqlQuery when writable). Reads never register, and neither does clearStorage — see the deletion race below. An in-isolate dedupe set bounded at 4096 keeps a hot isolate to one write per bucket, so this does not become a per-event D1 write.

Service enumeration is now authoritative too. It previously required a PackageServiceInstance DO to have projected into package_service_states, so a stopped service whose DO never woke was only findable through the legacy arm. Services are declared in package.json#kody.services, so deletion now unions manifest-declared services with the state table, degrading to the state table alone if a repo fetch fails. A manifest error can never abort a deletion, and it now surfaces a caller-visible warning rather than reporting clean success.

What this changes for #956

The DR gap is fixed rather than documented, and the "verify package_service_states has converged before 2026-08-25" deadline item is gone, because bucket enumeration no longer depends on projection having happened.

Correction to an earlier version of this description: it claimed every package_runtime_runs read was removed. That was wrong, and review caught it. One legacy arm is deliberately restored — listAccountUserPackageServices({ includeLegacyRuntimeRuns: true }) on the account-deletion path only. Migration 0097 backfills storage ids, not (packageId, serviceName) tuples, so a pre-#955 service whose DO never projected and whose manifest declaration has since been removed would otherwise be missed, leaving its Durable Object alive after deletion. Correctness beats the cleanliness claim; #956 tracks removing it after the drain.

Reviewing this

packages/worker/src/storage-buckets/service.ts is the new writer and readers. packages/worker/src/app/account-user-inventory.ts is the shared enumeration extracted from the two copies that had drifted between account-deletion.ts and account-export.ts.

One deliberate split worth knowing: account export paging stays on bounded per-request sources, while account deletion pays the manifest fetches. Paging wants cheap bounded pages; deletion wants completeness because a missed bucket leaks storage. Count and paging share one source set (jobs, archived_job_artifacts, user_storage_buckets, app packages, package_service_states storage ids, and one RunLog RPC) specifically so they cannot report different totals — there is a test asserting they agree, including for a RunLog-only id.

Known follow-up, called out rather than hidden: a manifest-declared service that has never run still won't appear in paginated export discovery. Deletion covers it. Making it cheap would mean registering declared service buckets at publish time.

Review round

Three automated passes found seven issues, all fixed in-branch. The ones worth knowing about:

  • Deletion raced bucket registration (Bugbot). clearStorage registered ownership, and account deletion calls clearStorage — so a fire-and-forget upsert could recreate rows for an already-deleted user. My own change introduced a data-residue path of exactly the kind this PR exists to prevent. Fixed by removing clearStorage from the registering set, after tracing every purge path that runs after D1 rows are deleted.
  • Export paging rebuilt the full inventory per page, including a network manifest fetch per saved package. Fixed back to bounded paging, with a test asserting paging performs no manifest loads.
  • Count and paging disagreed, making exports look truncated; then the fix over-narrowed and dropped RunLog-only ids entirely. Both directions are now covered by the agreement test.
  • Unguarded decodeURIComponent on a caller-supplied storage id threw URIError instead of returning not-found.

Bugbot's final pass is clean; CodeRabbit marked its findings addressed.

Verification

npm run validate green: 1387 tests across 423 files, Playwright E2E, MCP E2E, primitives:check, migrations:check.

Tests cover the cases that motivated this: deletion purging a bucket known only via user_storage_buckets, a service declared only in a manifest, a service known only via legacy rows, a manifest load failure warning without aborting, DR inventory including bucket and service state, and the backfill picking up legacy-only buckets.

System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ ca183641 · Head: 54878b37

Classification: extends — no new primitive; bucket ownership moves from derived history to stored state, and three consumers are repointed.

Primitives touched

Primitive Group Impact
durable-storage assistant extends — storageRunnerRpc registers ownership on mutating ops
d1-app-db storage extends — migration 0097 adds user_storage_buckets + backfill
backup-control-plane storage extends — DR inventory reads ownership state, not run history
account-export assistant extends — shared inventory helper; count and paging share one source set
app-ui surfaces extends — account deletion enumeration (server-side)
entitlements auth composes — table registered for account data coverage

System map

Bucket ownership stops being inferred from run history and becomes a D1 table that DR, deletion, and export all read.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	durableStorage["durable-storage<br/>Durable storage buckets"]:::extended
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	backupControlPlane["backup-control-plane<br/>Production backup control plane"]:::extended
	accountExport["account-export<br/>Account data export"]:::extended
	appUi["app-ui<br/>Browser app"]:::extended
	runRecords["run-records<br/>Run records"]:::untouched
	savedPackages["saved-packages<br/>Saved packages"]:::untouched
	durableStorage -->|"register on mutating storageRunnerRpc"| d1AppDb
	d1AppDb -->|"0097 user_storage_buckets + backfill"| backupControlPlane
	d1AppDb -->|"listUserStorageBucketIds"| accountExport
	d1AppDb -->|"DO purge enumeration"| appUi
	savedPackages -->|"manifest-declared services for deletion"| appUi
	runRecords -->|"listRunRecordStorageIds in count and paging"| accountExport
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

Question Before After
Which buckets does a user own? derived from package_runtime_runs history user_storage_buckets state table
Which services exist? required a DO to have projected state manifest declarations ∪ projected state ∪ legacy (deletion only)
DR bucket inventory stale since #955 deploy ownership state (fixed)
Export count vs paging n/a one shared source set, test-enforced

Invariants

Applies state-vs-history one layer below where #955 introduced it: ownership is state and must not be inferred from run history. no-per-event-shared-writes is respected — registration is write-path only, deduped in isolate, and bounded.

per-user-isolation unchanged; dr/exporter.ts remains the documented operator-level exception.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features
    • Added per-user durable tracking for storage bucket ownership (user_storage_buckets) with automatic updates on storage writes.
    • Added shared account inventory helpers used by account export and account deletion (including manifest-defined package services).
    • Updated platform disaster-recovery inventory to build from registered storage buckets and package_service_states.
  • Bug Fixes
    • Improved resilience and deduplication for bucket registration when writes fail or required tables are missing.
  • Documentation
    • Updated disaster-recovery documentation to clarify authoritative inventory sources.
  • Tests
    • Expanded migration validation and account/DR export/deletion regression coverage.

cursoragent and others added 3 commits July 26, 2026 19:50
Add user_storage_buckets as authoritative state (with a one-time
package_runtime_runs backfill), register buckets on StorageRunner
mutators with isolate-local dedupe, and cover the table in account
export/deletion targets.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Repoint DR inventory, account deletion, and account export off
package_runtime_runs onto user_storage_buckets plus manifest/state
service enumeration so post-#955 buckets and idle services stay
discoverable.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
durable_object_summaries pages again over user_storage_buckets and
entity/state tables without per-page manifest fetches. Manifest-inclusive
enumeration stays on deletion and one-shot full export inventory.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Jul 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds user_storage_buckets ownership tracking, registers buckets during writable StorageRunner operations, centralizes account inventory discovery, updates account deletion/export sources, and changes DR inventory to use registered buckets and package_service_states.

Changes

Storage inventory lifecycle

Layer / File(s) Summary
Bucket persistence and write registration
packages/worker/migrations/0097-user-storage-buckets.sql, packages/worker/src/storage-buckets/*, packages/worker/src/storage-runner.ts
Adds the ownership table and backfill, registration/listing helpers, test schema support, and write-path registration with deduplication.
Shared account inventory and deletion
packages/worker/src/app/account-user-inventory.ts, packages/worker/src/app/account-deletion.ts, packages/worker/src/app/account-data-targets.ts, packages/worker/src/app/account-retention-dispositions.ts
Combines storage and package-service sources, includes user_storage_buckets in account operations, and covers manifest-only services and registered storage deletion.
Account export inventory and discovery
packages/worker/src/app/account-export.ts, packages/worker/src/app/account-export.node.test.ts
Uses shared inventory helpers and authoritative sources for storage-runner and package-service discovery and export authorization.
Platform disaster-recovery inventory
packages/worker/src/dr/exporter.ts, packages/worker/src/dr/exporter.node.test.ts, docs/contributing/disaster-recovery.md
Builds platform storage inventory from registered buckets and package_service_states, with documentation updated to describe inventory boundaries.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StorageRunner
  participant StorageBucketService
  participant D1Database
  participant AccountWorkflow
  StorageRunner->>StorageBucketService: Register writable storage bucket
  StorageBucketService->>D1Database: Upsert user_storage_buckets
  AccountWorkflow->>D1Database: Read registered buckets and service states
  AccountWorkflow->>StorageRunner: Export or clear discovered storage
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: moving storage bucket ownership tracking from run history to D1-backed state.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/storage-bucket-ownership-8a57

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kody-bot
kody-bot marked this pull request as ready for review July 26, 2026 20:15
@github-actions

github-actions Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-965.kody-a99.workers.dev

Worker: kody-pr-965
D1: kody-pr-965-db
KV: kody-pr-965-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (7)
packages/worker/src/app/account-deletion.node.test.ts (2)

181-221: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

New mock branches look correct; the legacy package_runtime_runs branches below are now unreachable.

Given the new contract test asserts owned sources no longer reference package_runtime_runs, the routing branches at Lines 222-307 are dead fixture code and can be dropped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-deletion.node.test.ts` around lines 181 -
221, Remove the now-unreachable legacy package_runtime_runs mock-routing
branches immediately following the package_service_states handling, through the
section before the next active query branch. Keep the new package_service_states
and user_storage_buckets branches unchanged, and remove only fixture logic that
handles package_runtime_runs.

2181-2184: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shared consoleWarn spy is mutated without restoration. Both tests install a silencing implementation on the module-level spy from #worker/test-support/console-spies.ts but never restore it, so warnings can stay suppressed for later tests in the same file unless the support module re-installs the spy per test.

  • packages/worker/src/app/account-deletion.node.test.ts#L2181-L2184: restore/reset consoleWarn in the existing finally block.
  • packages/worker/src/app/account-export.node.test.ts#L1456-L1456: reset consoleWarn at the end of the test (or rely on a global restoreAllMocks).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-deletion.node.test.ts` around lines 2181 -
2184, Restore or reset the shared consoleWarn spy after the account-deletion
test, using its existing finally block, so the mock implementation cannot leak
to later tests. Also reset consoleWarn at the end of the account-export test, or
ensure the global restoreAllMocks mechanism reliably handles it:
packages/worker/src/app/account-deletion.node.test.ts#L2181-L2184 requires the
finally-block cleanup;
packages/worker/src/app/account-export.node.test.ts#L1456-L1456 requires
end-of-test cleanup.
packages/worker/src/app/account-export.ts (2)

458-468: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shared SQL fragment couples callers to a placeholder count.

exportStorageIdBaseSql needs exactly four userId binds, repeated at Lines 1848-1852 and 1902-1906. Exporting a small helper that returns { sql, binds } (or building the bind array from a constant) would keep them in sync if a UNION branch is ever added.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-export.ts` around lines 458 - 468, The shared
exportStorageIdBaseSql fragment currently requires callers to manually maintain
four userId binds. Add a helper near exportStorageIdBaseSql that returns the SQL
and its corresponding bind array, then update both call sites around the
discovery queries to consume that helper instead of hardcoding repeated userId
values; keep the SQL and bind order synchronized if UNION branches change.

1897-1909: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Per-row ownership probe inside the page loop is an N+1.

Each discovered service issues its own SELECT 1 against the base set. Since selected is already bounded by pageSize, one query with id IN (...) (or a NOT IN anti-join over the base subquery) would collapse this to a single round trip.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-export.ts` around lines 1897 - 1909, Replace
the per-row ownership query in the loop over selected with one batched ownership
lookup for all selected storage IDs, using a parameterized IN predicate or
equivalent anti-join against exportStorageIdBaseSql. Build an ID-to-ownership
result set from that single query, then reuse it while processing each row;
preserve the existing ownership semantics and bindings.
packages/worker/src/app/account-user-inventory.ts (2)

79-112: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Manifest loads run strictly sequentially per saved package.

Each iteration awaits a manifest load, so enumeration cost is O(packages) round trips on the deletion/full-export path. Bounded-concurrency batching (e.g. chunks of 5-10 via Promise.all) keeps the same failure isolation with much lower latency for users with many packages.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-user-inventory.ts` around lines 79 - 112, The
package manifest enumeration loop should use bounded concurrency instead of
awaiting each load sequentially. Update the flow around
loadPackageManifestBySourceId to process savedPackage items in small batches
(for example, 5–10 at a time) with Promise.all, while preserving per-package
error isolation, service aggregation through byKey, and the existing warning for
failed loads.

107-117: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Manifest-load failures are only console.warned, so deletion silently under-reports.

listAccountUserPackageServices is used by account-deletion.ts (listUserPackageServices → collectUserDeletionInventory), which builds a caller-visible warnings array. A manifest failure here means a manifest-only service DO is never purged, yet the deletion result reports clean success. Consider accepting an optional warnings: Array<string> and pushing these messages so the deletion/export result reflects incomplete enumeration.

♻️ Sketch
 export async function listAccountUserPackageServices(input: {
 	env: Env
 	userId: string
 	baseUrl: string
+	warnings?: Array<string>
 }): Promise<Array<AccountUserPackageService>> {
@@
 			} catch (error) {
-				console.warn(
-					`Failed to load package manifest for service enumeration (package ${savedPackage.id}): ${getErrorMessage(error)}`,
-				)
+				const message = `Failed to load package manifest for service enumeration (package ${savedPackage.id}): ${getErrorMessage(error)}`
+				input.warnings?.push(message)
+				console.warn(message)
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-user-inventory.ts` around lines 107 - 117,
Update listAccountUserPackageServices to accept an optional warnings:
Array<string> parameter and append both manifest-enumeration failure messages to
it instead of only calling console.warn. Update the account-deletion call chain,
including listUserPackageServices and collectUserDeletionInventory, to pass
through the existing caller-visible warnings array while preserving console
warnings where appropriate.
packages/worker/src/app/account-export.node.test.ts (1)

1582-1588: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate contract assertion.

account-deletion.node.test.ts already asserts ./account-export.ts contains no package_runtime_runs reference in its owned-sources loop; this test repeats it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/account-export.node.test.ts` around lines 1582 -
1588, Remove the duplicate test `account export source no longer reads
package_runtime_runs` from `account-export.node.test.ts`, relying on the
existing owned-sources assertion in `account-deletion.node.test.ts` to enforce
this contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/app/account-export.ts`:
- Around line 715-718: Update countUserStorageIds to use the same D1-only source
as durable_object_summaries paging—exportStorageIdBaseSql plus
package_service_states—instead of listUserStorageIds, so storage_runners.count
matches the ids clients can enumerate.
- Around line 1544-1545: The section readers must avoid one-shot inventory
helpers on per-request paths. In packages/worker/src/app/account-export.ts lines
1544-1545, replace the listUserStorageIds(...).includes(...) check with a
targeted exportStorageIdBaseSql probe and package_service_states fallback. Also
update lines 1668-1674 to resolve {packageId, serviceName} from
package_service_states first, falling back to manifest enumeration only when no
row exists.

---

Nitpick comments:
In `@packages/worker/src/app/account-deletion.node.test.ts`:
- Around line 181-221: Remove the now-unreachable legacy package_runtime_runs
mock-routing branches immediately following the package_service_states handling,
through the section before the next active query branch. Keep the new
package_service_states and user_storage_buckets branches unchanged, and remove
only fixture logic that handles package_runtime_runs.
- Around line 2181-2184: Restore or reset the shared consoleWarn spy after the
account-deletion test, using its existing finally block, so the mock
implementation cannot leak to later tests. Also reset consoleWarn at the end of
the account-export test, or ensure the global restoreAllMocks mechanism reliably
handles it: packages/worker/src/app/account-deletion.node.test.ts#L2181-L2184
requires the finally-block cleanup;
packages/worker/src/app/account-export.node.test.ts#L1456-L1456 requires
end-of-test cleanup.

In `@packages/worker/src/app/account-export.node.test.ts`:
- Around line 1582-1588: Remove the duplicate test `account export source no
longer reads package_runtime_runs` from `account-export.node.test.ts`, relying
on the existing owned-sources assertion in `account-deletion.node.test.ts` to
enforce this contract.

In `@packages/worker/src/app/account-export.ts`:
- Around line 458-468: The shared exportStorageIdBaseSql fragment currently
requires callers to manually maintain four userId binds. Add a helper near
exportStorageIdBaseSql that returns the SQL and its corresponding bind array,
then update both call sites around the discovery queries to consume that helper
instead of hardcoding repeated userId values; keep the SQL and bind order
synchronized if UNION branches change.
- Around line 1897-1909: Replace the per-row ownership query in the loop over
selected with one batched ownership lookup for all selected storage IDs, using a
parameterized IN predicate or equivalent anti-join against
exportStorageIdBaseSql. Build an ID-to-ownership result set from that single
query, then reuse it while processing each row; preserve the existing ownership
semantics and bindings.

In `@packages/worker/src/app/account-user-inventory.ts`:
- Around line 79-112: The package manifest enumeration loop should use bounded
concurrency instead of awaiting each load sequentially. Update the flow around
loadPackageManifestBySourceId to process savedPackage items in small batches
(for example, 5–10 at a time) with Promise.all, while preserving per-package
error isolation, service aggregation through byKey, and the existing warning for
failed loads.
- Around line 107-117: Update listAccountUserPackageServices to accept an
optional warnings: Array<string> parameter and append both manifest-enumeration
failure messages to it instead of only calling console.warn. Update the
account-deletion call chain, including listUserPackageServices and
collectUserDeletionInventory, to pass through the existing caller-visible
warnings array while preserving console warnings where appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6dc01f71-9ec9-44e3-935a-475fbc945336

📥 Commits

Reviewing files that changed from the base of the PR and between ca18364 and a33b7a4.

📒 Files selected for processing (21)
  • docs/contributing/disaster-recovery.md
  • packages/worker/migrations/0097-user-storage-buckets.sql
  • packages/worker/src/app/account-data-targets.ts
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/app/account-deletion.ts
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/account-export.ts
  • packages/worker/src/app/account-retention-dispositions.node.test.ts
  • packages/worker/src/app/account-retention-dispositions.ts
  • packages/worker/src/app/account-user-inventory.ts
  • packages/worker/src/dr/exporter.node.test.ts
  • packages/worker/src/dr/exporter.ts
  • packages/worker/src/entitlements/test-schema.ts
  • packages/worker/src/storage-buckets/migration.node.test.ts
  • packages/worker/src/storage-buckets/service.node.test.ts
  • packages/worker/src/storage-buckets/service.ts
  • packages/worker/src/storage-buckets/service.workers.test.ts
  • packages/worker/src/storage-buckets/test-schema.ts
  • packages/worker/src/storage-runner.ts
  • packages/worker/src/storage-runner.workers.test.ts
  • tools/migration-ledger.json

Comment thread packages/worker/src/app/account-export.ts
Comment thread packages/worker/src/app/account-export.ts Outdated
Make storage_runners counts match D1 discovery paging, probe ownership
and package-service lookups without full inventory rebuilds, batch the
service-stage base check, and surface manifest degradation in deletion
warnings so incomplete purges cannot look clean.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/storage-runner.ts Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/app/account-export.ts`:
- Around line 481-507: Update isExportDiscoverableStorageId to safely handle
malformed percent-encoding in packagePart or servicePart: wrap both
decodeURIComponent calls in error handling and return false when decoding
throws. Preserve the existing database lookup for valid decoded components and
the current false returns for invalid service storage IDs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 34895cfc-e075-459e-9dbd-abc44dad1f7e

📥 Commits

Reviewing files that changed from the base of the PR and between a33b7a4 and dc46439.

📒 Files selected for processing (5)
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/app/account-deletion.ts
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/account-export.ts
  • packages/worker/src/app/account-user-inventory.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/worker/src/app/account-user-inventory.ts
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/account-deletion.node.test.ts

Comment thread packages/worker/src/app/account-export.ts
Guard decodeURIComponent on caller-supplied service: storage ids so a
bare % returns the normal not-found path instead of throwing URIError.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 4 potential issues.

There are 5 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d009f75. Configure here.

Comment thread packages/worker/src/app/account-export.ts Outdated
Comment thread packages/worker/src/app/account-export.ts
Comment thread packages/worker/src/app/account-export.ts Outdated
Comment thread packages/worker/src/app/account-user-inventory.ts

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/app/account-export.node.test.ts`:
- Around line 1740-1762: Update the test around readAccountExportSection to
create the required user_storage_buckets or ownership fixture for the supplied
storageId, ensuring lookup reaches URI decoding and validation. Keep the
malformed service identifier `service:pkg%:worker%` and assert it is converted
to the “Storage runner was not found for account export.” error, rather than
passing through missing-ownership handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 84d9d7bd-ec88-468c-83e9-7da6559671f0

📥 Commits

Reviewing files that changed from the base of the PR and between dc46439 and d009f75.

📒 Files selected for processing (2)
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/account-export.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/worker/src/app/account-export.ts

Comment thread packages/worker/src/app/account-export.node.test.ts
cursoragent and others added 2 commits July 26, 2026 20:53
Account deletion clears StorageRunner DOs then deletes user_storage_buckets.
Registering on clearStorage could fire-and-forget an upsert that recreates
rows for an already-deleted user. Registration stays on genuine write paths.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Union listRunRecordStorageIds into export count, ownership probes, and
discovery paging so RunLog-only buckets stay exportable and count≡paging.
Restore package_runtime_runs on the deletion path only (issue #956), and
dedupe package-manifest loads within a single inventory request.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
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.

3 participants