fix(core): add controlled media usage activation - #2445
fix(core): add controlled media usage activation#2445khoinguyenpham04 wants to merge 24 commits into
Conversation
…utomatic-reconciliation # Conflicts: # .changeset/safe-collection-deletion.md # packages/core/src/database/migrations/runner.ts # packages/core/src/database/repositories/media-usage.ts # packages/core/src/database/types.ts # packages/core/src/emdash-runtime.ts # packages/core/src/media/usage/collection-deletion-processor.ts # packages/core/src/media/usage/collection-deletion.ts # packages/core/tests/integration/database/media-usage-incremental-work-migration.test.ts # packages/core/tests/integration/database/migrations.test.ts # packages/core/tests/integration/runtime/media-usage-scheduled-driver.test.ts # packages/core/tests/workerd/media-usage-collection-deletion-d1.test.ts
🦋 Changeset detectedLatest commit: c862530 The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Scope checkThis PR changes 1,113 lines across 16 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
There was a problem hiding this comment.
This is a sound follow-up to #2443: it adds a deliberately gated admin API to turn on Media Usage indexing, which is exactly the safety gate the system needs before it starts capturing real writes. The implementation follows EmDash's conventions well — thin route wrappers, handler-layer ApiResult, schema:manage plus admin token scope, CSRF via the existing middleware, redacted status responses, OpenAPI/client updates, and D1 query-budget tests. Logged-out routes are untouched.
I checked the diff, the full new route/handler/core changes, and relevant siblings. The code looks correct: the status endpoint omits lease tokens and raw error values, the POST requires both literal confirmations via Zod, the lease/conflict/version-mismatch errors map cleanly to 409s, and the test suite covers auth, redaction, idempotency, lease races, and failure paths.
One small AGENTS-style cleanup: the registration test in packages/core/tests/unit/api/media-usage-activation-route.test.ts is a config-pin test — it asserts the literal route pattern back at the source. It cannot fail on a real regression and will break whenever the route is intentionally moved or renamed. It should be removed; the behavior tests that actually call the route already prove it is wired up correctly.
There was a problem hiding this comment.
I reviewed the full diff statically and traced the new activation endpoints through the handler, route, business logic, OpenAPI schema, client, tests, docs, and the auth/write-fence middleware.
Approach judgment: This is a reasonable completion of the Media Usage indexing foundation. It adds a deliberate, admin-controlled activation gate rather than auto-activating, which matches the PR description and the existing architecture. The API envelope, authorization (schema:manage + admin scope for bearer tokens), and CSRF handling (middleware-enforced for session POSTs) all line up with EmDash conventions. The change is additive and does not touch logged-out paths, so query-count snapshots should be unaffected.
What I checked:
- Error-code registration and HTTP-status mapping for the new activation codes.
- Handler-to-route wiring, including
requirePerm,requireScope,parseBody, andunwrapResult. - Schema validation (
writersDrained: trueandmaintenanceReady: trueliterals,.strict()). - The activation business logic: lease claiming, bounded batch processing (≤1 collection/call), idempotent active state, conflict/error paths, and redacted status reads.
- Trigger installation is idempotent via
capture-triggers.ts, so retries after partial installs should not get stuck. - OpenAPI additions and client method wiring.
- New unit and workerd test coverage.
- Docs links/anchors and changeset.
- No SQL interpolation issues, no new content-table queries missing locale filters, no new logged-out queries.
Headline conclusion: The code looks correct and well-scoped. I did not find any blocking issues, logic bugs, AGENTS.md convention violations, or missing authorization/CSRF checks. Runtime test/lint claims in the PR description are noted but not independently verified.
One non-blocking design note: maintenanceReady is enforced only at the route schema boundary and is not forwarded into activateMediaUsageCapture. That is acceptable because the route is the intended entry point and the confirmation is operator-level, but you may want to thread it to the business-function boundary for symmetry if internal callers ever invoke activation directly.
ascorbic
left a comment
There was a problem hiding this comment.
The code seems fine. The docs though have really weird LLM wording that's very unclear to anyone who doesn't know the internals of EmDash. It needs some serious rewriting with a user-facing voice.
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | c862530 | Aug 14 2026, 03:20 PM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
What does this PR do?
Adds a deliberate, administrator-controlled way to turn on automatic Media Usage indexing after a production deployment is ready.
The indexing foundation stays dormant until an administrator explicitly starts activation. This PR provides that final safety gate:
schema:manage; bearer-token calls need theadminscope, session-based POSTs need CSRF protection, and every POST requires explicit confirmation that writers are stopped and background maintenance is ready;An
activeresult means that new content changes are being captured. Historical content continues to catch up through the bounded background reconciliation added by #2443.This is stacked directly on #2443 and should be reviewed relative to
feature/media-usage-automatic-reconciliation.Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
No visual changes.
Verified locally:
PostgreSQL and Durable Object SQL runtime tests were not available locally. Their shared code paths are typechecked, while the available SQLite and real D1/workerd tests cover the public activation contract and bounded request behavior.
Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
feature/media-usage-production-activation. Updated automatically when the playground redeploys.