Skip to content

Add the package-storage audit route and harden entitlement estimate reads - #1030

Merged
kody-bot merged 2 commits into
mainfrom
cursor/orchistrate-issue-231-package-state-model-e462
Jul 29, 2026
Merged

kody-bot merged 2 commits into
mainfrom
cursor/orchistrate-issue-231-package-state-model-e462

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

Pre-cleanup groundwork for #1024 (removing the legacy raw-package-id app bucket), plus one hardening fix informed by production evidence:

  • GET /admin/package-storage-audit.json (admin RBAC): the read-only audit that gates the Remove the legacy raw-package-id app storage bucket #1024 delete-vs-migrate decision. Platform-wide, it reports every has_app package's legacy raw-id bucket size (probed per-user through storageRunnerRpc; probing is side-effect-free — getEstimatedBytes never registers buckets — and 4096 bytes is the never-written SQLite floor), which published app sources still import the banned ambient storage (reusing the repo-check AST scan, now exported), and orphaned kind='app' inventory rows from packages deleted before Clear package-owned durable state on delete and key app values by appId only #1026. Bounded: ?limit= (default 200, max 500) with a truncated flag, DO probes in concurrency-5 chunks, per-package error tolerance so one bad row can't sink the report.
  • Entitlement estimator retry: assertStorageRunnerWriteWithinEntitlement fans out getEstimatedBytes over every registered bucket and fails closed on any error. Since Clear package-owned durable state on delete and key app values by appId only #1026, package delete clears buckets concurrently with live traffic, and we observed exactly one production write flake ("Unable to verify the storage byte entitlement…") coinciding to the second with a package deletion. Each chunk now gets one bounded retry (150ms) before the existing fail-closed error.

Production verification that motivated this (run via MCP against prod): packageStorage() round-trips (KV + SQL) in the real invocation runtime across runs; package_delete deallocates the bucket (post-delete query: no such table); zero Value scope "app" errors in run records since the fallback removal.

Testing

  • npm run validate (full local gate)
  • New node tests: audit route 401/403, happy path across two users, empty vs non-empty legacy buckets, ambient-import flagging, probe/scan error tolerance, orphan detection, limit/truncation; entitlement retry (fail→retry→succeed, fail→fail→throw)
  • New workers test: never-written DO getEstimatedBytes baseline (4096) and probe-does-not-register behavior

Refs #1024

System recap — composes existing primitives (low risk)

Mode: recap · Base: main @ 9bf6dd26 · Head: 2f9e8 (audit commit)

Classification: composes — a read-only admin surface wiring existing primitives together, plus a bounded retry inside an existing durable-storage code path. No schema changes, no new primitives, primitives.yaml unchanged.

Primitives touched

Primitive Group Impact
app-ui / admin surfaces composes — new admin JSON route /admin/package-storage-audit.json (RBAC)
durable-storage assistant extends (softly) — one bounded retry before the fail-closed entitlement error
saved-packages assistant composes — read-only D1 queries over saved_packages / user_storage_buckets
rbac auth composes — requireUserWithRole('admin') gating

System map

The admin route reads package rows and bucket inventory from D1, probes legacy buckets through StorageRunner per owning user, and scans published sources with the existing repo-check helper.

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
	adminRoute["app-ui<br/>Admin audit route"]:::touched
	rbac["rbac<br/>Role-based access control"]:::touched
	d1AppDb["d1-app-db<br/>D1 app database"]:::untouched
	durableStorage["durable-storage<br/>StorageRunner buckets"]:::extended
	repoChecks["saved-packages<br/>Repo checks / published source"]:::touched
	adminRoute -->|"requireUserWithRole('admin')"| rbac
	adminRoute -->|"saved_packages has_app rows + orphan kind='app' inventory"| d1AppDb
	adminRoute -->|"getEstimatedBytes per raw-id bucket (per-user, read-only)"| durableStorage
	adminRoute -->|"loadPackageSourceBySourceId + collectAmbientStorageImportFiles"| repoChecks
	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

Invariants

Per-user isolation: the D1 enumeration is deliberately platform-wide (admin surface, RBAC-gated, read-only), but every StorageRunner probe passes the row's own userId, so DO access stays namespaced. No writes anywhere in the audit path.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added an admin package storage audit API.
    • Audit reports include package storage estimates, ambient import files, orphaned storage buckets, errors, totals, and truncation status.
    • Added support for limiting audit results with the limit parameter.
  • Bug Fixes

    • Improved storage usage checks by retrying transient estimate failures.
    • Never-used storage buckets now report a consistent empty baseline.
  • Tests

    • Added coverage for authorization, audit reporting, result limits, storage failures, retries, and empty buckets.

GET /admin/package-storage-audit.json (admin RBAC) reports, platform-wide,
every has_app package's legacy raw-id bucket size (probed per-user via
StorageRunner, no registration side effects; 4096 bytes = never-written
floor), which published app sources still import the banned ambient
storage (reusing the repo-check AST scan), and orphaned kind='app'
inventory rows. This is step 1 of #1024: decide delete-vs-migrate for the
legacy app bucket from evidence.

Also gives the entitlement estimator one bounded retry per chunk before
failing closed: package delete now clears buckets concurrently with live
traffic, and we observed a production write flake coinciding exactly with
a bucket deletion.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@cursor[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9d0bb82-86e2-48ff-9595-9833e355a7e1

📥 Commits

Reviewing files that changed from the base of the PR and between 960f49a and 9eb4db2.

📒 Files selected for processing (4)
  • packages/worker/src/app/handlers/admin-package-storage-audit.node.test.ts
  • packages/worker/src/app/handlers/admin-package-storage-audit.ts
  • packages/worker/src/storage-runner.entitlement.node.test.ts
  • packages/worker/src/storage-runner.ts
📝 Walkthrough

Walkthrough

Adds an admin JSON endpoint that audits package storage usage, ambient imports, and orphan buckets. It also adds retry handling for storage estimate reads, an empty-bucket baseline constant, route wiring, exported scan logic, and comprehensive tests.

Changes

Package storage audit endpoint

Layer / File(s) Summary
Audit contract and request handling
packages/worker/src/app/handlers/admin-package-storage-audit.ts
Defines audit report types and implements admin-only GET handling with bounded limits.
Audit data loading and package probes
packages/worker/src/app/handlers/admin-package-storage-audit.ts, packages/worker/src/repo/checks.ts
Loads app packages and orphan buckets, probes legacy storage bytes, scans ambient imports, and computes totals.
Route wiring and endpoint coverage
packages/worker/src/app/router.ts, packages/worker/src/app/routes.ts, packages/worker/src/app/handlers/admin-package-storage-audit.node.test.ts
Registers the endpoint and tests authorization, audit results, source errors, and truncation.

Storage estimate reliability

Layer / File(s) Summary
Chunked estimate retry behavior
packages/worker/src/storage-runner.ts
Adds an empty estimate baseline and retries failed estimate chunks once before rejecting.
Empty bucket estimate baseline
packages/worker/src/storage-runner.workers.test.ts
Verifies never-written buckets return the baseline without registering ownership.
Retry and failure test coverage
packages/worker/src/storage-runner.entitlement.node.test.ts
Tests transient recovery and failure after the retry also rejects.

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

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant AuditHandler
  participant Database
  participant StorageRunner
  participant SourceLoader
  Admin->>AuditHandler: Request package storage audit
  AuditHandler->>Database: Query app packages and orphan buckets
  AuditHandler->>StorageRunner: Estimate legacy bucket bytes
  AuditHandler->>SourceLoader: Load package source
  AuditHandler-->>Admin: Return JSON audit report
Loading

Possibly related PRs

  • kentcdodds/kody#965: Adds the schema and ownership behavior used to identify orphan app buckets.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: the new package-storage audit route and the entitlement estimate retry hardening.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/orchistrate-issue-231-package-state-model-e462

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 29, 2026 22:09
@github-actions

github-actions Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

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

Worker: kody-pr-1030
D1: kody-pr-1030-db
KV: kody-pr-1030-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: 3

🧹 Nitpick comments (1)
packages/worker/src/app/handlers/admin-package-storage-audit.node.test.ts (1)

261-269: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the empty-bucket baseline from the exported constant instead of hardcoding 4096.

nonEmptyLegacyBuckets compares against emptyStorageRunnerEstimatedBytes; if that floor changes, these assertions silently stop testing the boundary. Import the constant and use baseline / baseline * 2.

Also applies to: 328-347

🤖 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/handlers/admin-package-storage-audit.node.test.ts`
around lines 261 - 269, Update the storage audit test mock and related
assertions in the mockModule.storageRunnerRpc scenarios to import and use the
exported emptyStorageRunnerEstimatedBytes constant, assigning baseline and
baseline * 2 for empty and data buckets instead of hardcoding 4096 and 8192.
Apply the same replacement to the additional cases around the referenced
assertions.
🤖 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/handlers/admin-package-storage-audit.node.test.ts`:
- Around line 112-135: Update the mock query handler’s orphan filtering around
packageIds to validate package ownership by both userId and storageId, then add
a test fixture where one user’s bucket storageId matches another user’s package
and assert that bucket is reported as an orphan. Ensure same-user package
matches remain excluded.

In `@packages/worker/src/app/handlers/admin-package-storage-audit.ts`:
- Around line 156-170: Update the query in listOrphanAppBuckets to join
saved_packages on both package id/storage_id and matching user_id, ensuring
orphan detection is scoped to the bucket owner. Add the same report limit used
by the packages query so the orphan results are bounded consistently.

In `@packages/worker/src/storage-runner.ts`:
- Around line 583-600: Update the readChunk retry flow around storageRunnerRpc
and getEstimatedBytes so the initial Promise.all attempt is fully settled before
starting the delayed retry, preventing overlapping reads from exceeding the
five-request concurrency cap. Preserve the existing retry result behavior, and
add a multi-storage-ID test covering one immediate failure and one pending read
to verify the retry waits for both outcomes.

---

Nitpick comments:
In `@packages/worker/src/app/handlers/admin-package-storage-audit.node.test.ts`:
- Around line 261-269: Update the storage audit test mock and related assertions
in the mockModule.storageRunnerRpc scenarios to import and use the exported
emptyStorageRunnerEstimatedBytes constant, assigning baseline and baseline * 2
for empty and data buckets instead of hardcoding 4096 and 8192. Apply the same
replacement to the additional cases around the referenced assertions.
🪄 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: 3b92526d-c3b4-4f21-bedc-52bb85fa7e2a

📥 Commits

Reviewing files that changed from the base of the PR and between 9bf6dd2 and 960f49a.

📒 Files selected for processing (8)
  • packages/worker/src/app/handlers/admin-package-storage-audit.node.test.ts
  • packages/worker/src/app/handlers/admin-package-storage-audit.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/repo/checks.ts
  • packages/worker/src/storage-runner.entitlement.node.test.ts
  • packages/worker/src/storage-runner.ts
  • packages/worker/src/storage-runner.workers.test.ts

Comment thread packages/worker/src/app/handlers/admin-package-storage-audit.ts Outdated
Comment thread packages/worker/src/storage-runner.ts Outdated
Scope the orphan-bucket join by user_id so a cross-user package id
collision cannot hide an orphan, bound the orphan list (500 rows +
orphanTruncated), and settle all in-flight estimate reads before the
entitlement retry so the concurrency cap holds.
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