Skip to content

Retire the D1 package_invocations table (#1061) - #1064

Merged
kody-bot merged 1 commit into
mainfrom
cursor/invoke-ledger-runlog-do-faa1
Jul 30, 2026
Merged

kody-bot merged 1 commit into
mainfrom
cursor/invoke-ledger-runlog-do-faa1

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 30, 2026 •

Copy link
Copy Markdown
Member

Why

Executes #1061. #1053 moved the keyed package-invocation idempotency ledger into the per-user RunLog Durable Object with a dual-read window for pre-migration D1 rows. Kent explicitly waived that window today: keys claimed before ~14:00 UTC 2026-07-30 stop replaying and may re-execute on redelivery — accepted. The RunLog DO becomes the only ledger store; no D1 ledger reads or writes remain anywhere on the invoke path.

What changed

  • Keyed invoke path (idempotent-module-invocation.ts): the dual-read fallback (resolveLegacyFallback, legacy poll, poll-disappearance legacy lookup) is gone. A pre-migration-style key is indistinguishable from a new key: it claims in the DO and executes fresh. All DO-ledger semantics are untouched (mismatch 409, 100 ms/1 s polling, 15-minute stale reclaim, bounded replay).
  • Legacy repo helpers (repo.ts): getPackageInvocationByKey, the row schema, mapRow, and PackageInvocationRecord removed. The token helpers and the shared response-bounding (boundedResponseJson / parseStoredResponse, now DO-only) stay.
  • Retention (app/retention.ts): the package_invocations sweep, its policy entry, and packageInvocationRetentionDays removed; the DO's own 90-day sweep (shipped in Migrate the keyed package-invocation idempotency ledger from D1 into the per-user RunLog DO #1053) is the only retention. The generic batch/chunk/round-robin retention tests that used the table as their fixture now run against workflow_runs — same coverage, different fixture.
  • Account coverage: package_invocations removed from account-retention-dispositions.ts and account/data-targets.ts (the deletion/export guards derive requirements from the migrated schema, so keeping either entry after the drop would fail the stale-coverage checks). DO ledger rows remain covered via the RunLog surface (export run_records section, deletion clearAll) from Migrate the keyed package-invocation idempotency ledger from D1 into the per-user RunLog DO #1053.
  • Entitlements (entitlements/service.ts): the storage_bytes sum no longer queries package_invocations — beyond the issue's bullet list, but required: the query would throw at runtime once the table is dropped. The DO-resident ledger is excluded from the storage quota exactly like run records (self-expiring operational state, not user content).
  • Migration: 0112-drop-package-invocations.sql (DROP TABLE IF EXISTS package_invocations; indexes from 0055 drop with it). 0029 stays in history untouched; the migration ledger is updated; migrations:check green (117 files, next free prefix 0113). The 0105 restore-safe-row-sizes migration test applies only migrations before 0105, so it remains valid history coverage.
  • Tests: the node suite's fake D1 now throws on any package_invocations statement (read or write) — every keyed test passing against it is the proof for the done-definition. The four dual-read tests are replaced by one explicit test: a pre-migration-style key misses cleanly and executes fresh instead of erroring. Dead CREATE TABLE package_invocations fixtures removed from workers-seed.ts and the two email dispatch workers suites.
  • Docs: run-records ledger section, data-storage retention list + JSON-columns note (also fixes the long-standing misattribution of the *_json scope columns, which live on package_invocation_tokens), invocation-overhead guardrails, and the disaster-recovery ledger-risk note updated to the single-store reality.

Deploy-window note

There is a brief mixed window during deploy where previous-version isolates (which still carry the fallback read) can race the applied drop migration; their legacy lookup then fails and the keyed path returns a retriable 500 (idempotency_lookup_failed) for fresh keys until the new version takes over. Providers retry; this is within the waived-window acceptance. New-version isolates never touch D1.

Sibling awareness

Stays clear of the #1048 narrow-phase territory: no changes to runtime-tool-factories.ts, invoke-check.ts, runtime-helper-manifest.ts, package-runtime/**, or repo/checks.ts. (Branch note: this work is a fresh history off main @ 44b86473; it reuses this run's designated branch name because Cursor Cloud's PR mechanism is pinned to it.)

Program report

MERGE-READY

Status: green and mergeable at head 048ecd48 (mergeStateStatus CLEAN against main).

  • Local npm run validate exit 0 on the head commit (format, lint, typecheck, node + workers unit, Playwright E2E, MCP E2E, backup:build, primitives/migrations checks).
  • CI: all jobs green on the first run (🧹 Static, 🧪 Node, ☁️ Workers, 🔌 MCP, 🎭 E2E, ✅ Validate, preview deploy).
  • AI reviewers: Bugbot pass, CodeRabbit pass — zero findings.
  • Done-definition check: no D1 ledger reads/writes anywhere on the invoke path (test-enforced: the fake D1 throws on any package_invocations statement); drop migration in place with 0029 kept in history; migrations:check green; npm run validate green.
  • After merge + deploy the conductor probes: fresh keyed replay still works on the DO; a pre-migration key executes fresh instead of erroring. Note the brief deploy-window 500s described above are expected and retriable.
System recap — extends the keyed invocation path and D1 schema (medium risk)

Mode: recap · Base: main @ 44b86473 · Head: 048ecd48

Classification: extends — removes the legacy D1 half of the invocation ledger contract (fallback read, sweep, account coverage, entitlement sum) and drops the table. No new primitive; the RunLog DO ledger (shipped in #1053) is unchanged.

Primitives touched

Primitive Group Impact
d1-app-db storage extends — 0112-drop-package-invocations.sql drops the legacy ledger table
scheduled-cron surfaces extends — package_invocations sweep removed from the retention cron
account-export assistant composes — legacy-table disposition/data-target entries removed; DO coverage unchanged
entitlements auth composes — storage_bytes no longer sums the dropped table
run-records storage composes — docs only; the DO ledger is now the single store

Unmapped path: packages/worker/src/package-invocations/ (keyed packages.invoke surface) — extends: dual-read fallback and legacy repo helpers deleted.

System map

The keyed invoke path now talks only to the RunLog DO; every D1 edge to the legacy table is deleted and the table itself is dropped.

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
	invoke["package-invocations<br/>Keyed packages.invoke"]:::extended
	runRecords["run-records<br/>Run records (RunLog DO)"]:::untouched
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	cron["scheduled-cron<br/>Retention cron"]:::extended
	accountExport["account-export<br/>Account data export"]:::touched
	entitlements["entitlements<br/>Plans and quotas"]:::touched
	invoke -->|"claim/finish/replay (unchanged, DO-only)"| runRecords
	invoke -.->|"REMOVED: dual-read fallback getPackageInvocationByKey"| d1AppDb
	cron -.->|"REMOVED: package_invocations sweep"| d1AppDb
	accountExport -.->|"REMOVED: legacy-table deletion/export targets"| d1AppDb
	entitlements -.->|"REMOVED: storage_bytes sum over the table"| d1AppDb
	d1AppDb ---|"0112 DROP TABLE package_invocations"| d1AppDb
	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

Concern Before (dual-read window) After
Pre-migration key redelivery replayed from the D1 row executes fresh (accepted; window waived)
Keyed hot path D1 traffic one awaited read on fresh claims/reclaims none
Retention DO sweep + legacy D1 cron sweep DO sweep only
Schema package_invocations present (write-orphaned) dropped via 0112; 0029 kept in history
storage_bytes entitlement summed legacy ledger text bytes ledger excluded (DO-resident, like run records)

Invariants

  • Strengthens no-per-event-shared-writes to completion for this surface: the shared D1 writer now sees zero invocation-ledger traffic, reads included.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • Data & Reliability

    • Keyed package invocations now use the RunLog ledger exclusively, with no legacy database fallback.
    • Previously migrated keys that cannot be found will execute afresh on redelivery.
    • Replay responses remain bounded, and ledger retention is handled locally for 90 days.
  • Account Management

    • User data export and deletion now include the active invocation-token records.
  • Maintenance

    • Removed legacy invocation storage and its associated retention and quota accounting.

The RunLog DO ledger is now the only store for keyed package-invocation
idempotency (issue #1061; Kent explicitly waived the dual-read window —
pre-migration keys stop replaying and execute fresh on redelivery):

- remove the dual-read D1 fallback from the keyed invoke path and the
  legacy row schema/lookup from repo.ts (no D1 ledger reads or writes
  remain anywhere on the invoke path; the node suite's fake D1 now throws
  on ANY package_invocations statement)
- remove the package_invocations retention sweep, its policy entry, and
  its account export/deletion coverage (dispositions + data targets)
- remove the table from the storage_bytes entitlement sum (the ledger is
  DO-resident, excluded like run records; the query would break after the
  drop)
- add 0112-drop-package-invocations.sql (0029 stays in history) and
  register it in the migration ledger
- rewrite the generic retention batch/chunk/round-robin tests onto
  workflow_runs and drop dead test-schema fixtures for the table
@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR drops the legacy package_invocations table and removes its retention, quota, account-data, and D1 fallback paths. Keyed invocations now use the RunLog Durable Object ledger, with updated tests, fixtures, migration metadata, and architecture documentation.

Changes

Package invocation ledger retirement

Layer / File(s) Summary
Remove the legacy ledger from storage lifecycle
packages/worker/migrations/..., tools/migration-ledger.json, packages/worker/src/account/..., packages/worker/src/entitlements/...
Drops package_invocations and removes it from account targets, storage accounting, entitlement mocks, and retention dispositions.
Use RunLog DO idempotency exclusively
packages/worker/src/package-invocations/*, packages/worker/src/package-invocations/service.node.test.ts
Removes legacy D1 fallback lookup and row mapping, adds bounded replay serialization, and verifies pre-migration key misses execute freshly through the RunLog Durable Object.
Remove legacy retention processing
packages/worker/src/app/retention.ts, packages/worker/src/app/retention.node.test.ts
Deletes package-invocation retention exports and scheduling, while updating pruning tests to cover workflow runs.
Align fixtures and architecture documentation
docs/contributing/architecture/*, docs/contributing/disaster-recovery.md, packages/worker/src/email/*, packages/worker/src/test-support/*
Removes dropped-table test schemas and documents RunLog Durable Object retention, replay, overhead, and disaster-recovery behavior.

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

Possibly related issues

Possibly related PRs

  • kentcdodds/kody#1053 — Migrates keyed package-invocation idempotency storage to the RunLog Durable Object.
  • kentcdodds/kody#1046 — Changes package-invocation idempotency behavior alongside removal of the legacy fallback.
  • kentcdodds/kody#1010 — Connects storage entitlement enforcement to the updated D1 storage-byte accounting.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 matches the main change: retiring the D1 package_invocations table.
✨ 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/invoke-ledger-runlog-do-faa1

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.

@github-actions

Copy link
Copy Markdown
Contributor

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

Worker: kody-pr-1064
D1: kody-pr-1064-db
KV: kody-pr-1064-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.

🧹 Nitpick comments (1)
packages/worker/migrations/0112-drop-package-invocations.sql (1)

1-8: 🧹 Nitpick | 🔵 Trivial

Confirm rollout ordering for the DROP TABLE.

No remaining package_invocations references remain in the tracked code, but D1 migrations and Worker code deploys are separate steps. Run this migration only after every Worker instance is running the code version that no longer reads package_invocations; otherwise a rolling deploy can leave old instances querying the missing table.

🤖 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/migrations/0112-drop-package-invocations.sql` around lines 1
- 8, Document and enforce rollout ordering for migration 0112: deploy the Worker
version that no longer reads package_invocations to every instance before
applying the DROP TABLE migration. Update the migration or associated deployment
guidance to make this prerequisite explicit, while preserving the unrelated
package_invocation_tokens table.
🤖 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.

Nitpick comments:
In `@packages/worker/migrations/0112-drop-package-invocations.sql`:
- Around line 1-8: Document and enforce rollout ordering for migration 0112:
deploy the Worker version that no longer reads package_invocations to every
instance before applying the DROP TABLE migration. Update the migration or
associated deployment guidance to make this prerequisite explicit, while
preserving the unrelated package_invocation_tokens table.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 052a0f7f-2d6a-4330-b752-ccf7d468331d

📥 Commits

Reviewing files that changed from the base of the PR and between 56e4851 and 048ecd4.

📒 Files selected for processing (21)
  • docs/contributing/architecture/data-storage.md
  • docs/contributing/architecture/invocation-overhead-guardrails.md
  • docs/contributing/architecture/run-records.md
  • docs/contributing/disaster-recovery.md
  • packages/worker/migrations/0112-drop-package-invocations.sql
  • packages/worker/src/account/data-targets.ts
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/app/account-retention-dispositions.ts
  • packages/worker/src/app/retention.node.test.ts
  • packages/worker/src/app/retention.ts
  • packages/worker/src/email/inbound.workers.test.ts
  • packages/worker/src/email/system-email-subscriptions.workers.test.ts
  • packages/worker/src/entitlements/entitlements.node.test.ts
  • packages/worker/src/entitlements/service.ts
  • packages/worker/src/package-invocations/idempotency.ts
  • packages/worker/src/package-invocations/idempotent-module-invocation.ts
  • packages/worker/src/package-invocations/repo.ts
  • packages/worker/src/package-invocations/service.node.test.ts
  • packages/worker/src/package-registry/service.node.test.ts
  • packages/worker/src/test-support/workers-seed.ts
  • tools/migration-ledger.json
💤 Files with no reviewable changes (9)
  • packages/worker/src/test-support/workers-seed.ts
  • packages/worker/src/account/data-targets.ts
  • packages/worker/src/app/account-retention-dispositions.ts
  • packages/worker/src/package-registry/service.node.test.ts
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/email/inbound.workers.test.ts
  • packages/worker/src/entitlements/entitlements.node.test.ts
  • packages/worker/src/app/retention.ts
  • packages/worker/src/email/system-email-subscriptions.workers.test.ts

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