Skip to content

feat(plugins): add sandboxed comment administration - #3170

Merged
ascorbic merged 9 commits into
mainfrom
codex/comment-administration
Sep 19, 2026
Merged

ascorbic merged 9 commits into
mainfrom
codex/comment-administration

Conversation

@ascorbic

@ascorbic ascorbic commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds the complete sandboxed comment-administration vertical slice with comments:read and comments:moderate. Moderation implies read access.

ctx.comments can get, count, and cursor-page through non-trashed comments. The read capability explicitly exposes author names and email addresses, comment bodies, pseudonymous IP hashes, user agents, and moderation metadata, but not linked EmDash user-account IDs. Installation and updates surface that personal-data access for consent.

Authorized plugins can move comments between approved, pending, and spam through the core moderation service. Each mutation requires the previously observed status, rejects stale writes with COMMENT_STATUS_CONFLICT, identifies plugin origin, runs comment:afterModerate once, preserves approval notifications, and fences recursive moderation across native and sandbox execution. Hard deletion and bulk replacement remain out of scope.

The contract is carried through shared and core manifest validation, declared-access canonicalization, registry lexicons and generated types, the plugin CLI and generated authoring skill, native context, Cloudflare Worker Loader, Node/workerd, and runtime-backed plugin-test helpers. Public documentation and package changesets describe the same authority and result shape.

This is an independent capability from the maintainer-directed sandbox capability plan, built on the runtime-test foundation merged in #3162.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

This is maintainer-directed capability work; there is no separate Discussion URL.

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (targeted tests for this change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (capability consent labels use Lingui; no messages.po files included)
  • I have added and reviewed the user-facing changeset
  • New features link to an approved Discussion (not applicable; maintainer-directed sandbox capability plan)
  • I have included screenshots below if this PR changes the UI (not applicable; no rendered UI change)

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: GPT-5.6 Sol in Codex

Screenshots / test output

Not applicable; this PR does not change rendered UI.

Validated locally:

  • full repository build and typecheck;
  • type-aware lint with zero diagnostics and git diff --check;
  • 226 focused core capability, comment, consent, concurrency, recursion, and runtime tests;
  • 54 Node/workerd bridge and wrapper tests;
  • real Cloudflare Worker Loader runtime-host journeys, including personal-data shape, invalid-value denial, slow-hook concurrency, recursive moderation, notifications, and origin;
  • Cloudflare bridge/wrapper, admin consent, shared contract, registry lexicon, CLI schema/generated-skill, and documentation tests;
  • real admin comment-approval HTTP integration journey; and
  • documentation build (85 pages).

A separate adversarial-review agent reviewed the exact main...6ebf5b4988dea0a399434b7bb0690713e54dd1f4 diff. Its three findings were fixed and the exact-SHA re-check passed with no remaining blockers.

@changeset-bot

changeset-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 943f64b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@emdash-cms/admin Minor
@emdash-cms/cloudflare Minor
@emdash-cms/plugin-cli Minor
@emdash-cms/plugin-test Minor
@emdash-cms/plugin-types Minor
@emdash-cms/registry-lexicons Minor
@emdash-cms/sandbox-workerd Minor
emdash Minor
@emdash-cms/registry-verification Patch
@emdash-cms/registry-client Patch
@emdash-cms/registry-loader Patch
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
create-emdash Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

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

@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This PR changes 1,993 lines across 59 files. Large PRs are harder to review and more likely to be closed without review.
This PR spans 4 different areas (area/core, area/admin, area/docs, area/cloudflare). Consider breaking it into smaller, focused PRs.

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.

@ascorbic ascorbic changed the title feat(plugins): add comment administration capability feat(plugins): add sandboxed comment administration Sep 17, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 17, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 943f64b Sep 19 2026, 04:31 PM

@pkg-pr-new

pkg-pr-new Bot commented Sep 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/admin@3170

@emdash-cms/auth

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth@3170

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth-atproto@3170

@emdash-cms/blocks

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/blocks@3170

@emdash-cms/cloudflare

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/cloudflare@3170

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/contentful-to-portable-text@3170

emdash

npm i https://pkg.pr.new/emdash-cms/emdash@3170

create-emdash

npm i https://pkg.pr.new/emdash-cms/emdash/create-emdash@3170

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/gutenberg-to-portable-text@3170

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-cli@3170

@emdash-cms/plugin-test

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-test@3170

@emdash-cms/plugin-types

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-types@3170

@emdash-cms/registry-client

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-client@3170

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-lexicons@3170

@emdash-cms/registry-loader

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-loader@3170

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-moderation@3170

@emdash-cms/registry-verification

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-verification@3170

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/sandbox-workerd@3170

@emdash-cms/x402

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/x402@3170

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-ai-moderation@3170

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-atproto@3170

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-audit-log@3170

@emdash-cms/plugin-color

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-color@3170

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-embeds@3170

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-field-kit@3170

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-forms@3170

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-webhook-notifier@3170

commit: 943f64b

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 17, 2026

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://codex-comment-administration.try.emdashcms.com, https://codex-comment-administration-emdash-playground.emdash-cms.workers.dev (commit 943f64b)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://9d3e4953.try.emdashcms.com, https://9d3e4953-emdash-playground.emdash-cms.workers.dev 943f64b 2026-09-19T16:32:26.757Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://1749ae78.try.emdashcms.com, https://1749ae78-emdash-playground.emdash-cms.workers.dev e215553 2026-09-19T10:27:16.380Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://843637db.try.emdashcms.com, https://843637db-emdash-playground.emdash-cms.workers.dev d041978 2026-09-19T08:12:53.631Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://a3970e47.try.emdashcms.com, https://a3970e47-emdash-playground.emdash-cms.workers.dev 3cfd697 2026-09-19T07:02:27.851Z Visit the dashboard ↗
  • Build: In progress 🔵

View logs ↗
779d3f7 2026-09-19T06:53:20.062Z View logs ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://89598272.try.emdashcms.com, https://89598272-emdash-playground.emdash-cms.workers.dev 6ebf5b4 2026-09-17T13:33:55.083Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://b9366d21.try.emdashcms.com, https://b9366d21-emdash-playground.emdash-cms.workers.dev 4f887d1 2026-09-17T13:19:01.766Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://2a625786.try.emdashcms.com, https://2a625786-emdash-playground.emdash-cms.workers.dev 03c2e00 2026-09-17T12:26:22.648Z Visit the dashboard ↗

@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Sep 17, 2026

@emdashbot emdashbot 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.

The approach is sound and well-scoped: it extends EmDash’s existing capability model to comments with clear separation between read (comments:read) and moderation (comments:moderate, which implies read), uses expected-status preconditions for safe concurrent moderation, and carries the same contract through native plugin contexts, the Cloudflare sandbox bridge, the workerd bridge, manifest/lexicon declarations, and admin consent labels. It fits the existing architecture without touching logged-out hot paths.

I traced the core path end-to-end: CommentRepository.updateStatusIf correctly atomically guards on the expected status; EmDashRuntime fences recursive and overlapping moderation through both an AsyncLocalStorage guard and an in-progress set; the admin route delegates through handleCommentModerate with the observed previous status so admins keep the same restore-from-trash behavior; and both the Cloudflare PluginBridge and workerd bridge-handler validate plugin-provided statuses before touching the runtime. The plugin-test host, bridge tests, and repository tests cover status conflicts, recursion blocking, personal-data shape, and runtime bridge round-trips.

I found only two small issues: a stale comment that no longer matches the awaited behavior, and a changeset paragraph that describes an internal test helper rather than user-facing release impact.

Comment thread packages/core/src/comments/service.ts Outdated
Comment thread .changeset/calm-comments-moderate.md Outdated
@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Sep 17, 2026
@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-review No maintainer or bot review yet labels Sep 17, 2026
@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Sep 17, 2026
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review cla: signed and removed review/awaiting-author Reviewed; waiting on the author to respond labels Sep 17, 2026
@ascorbic ascorbic added bot:review Trigger an emdashbot code review on this PR and removed bot:review Trigger an emdashbot code review on this PR labels Sep 17, 2026
@ascorbic

Copy link
Copy Markdown
Collaborator Author

Review of 6ebf5b498. One blocker.

Blocker: the new capabilities can never be published — the marketplace rejects them

/** Must stay in sync with PLUGIN_CAPABILITIES in packages/core/src/plugins/manifest-schema.ts */
const VALID_CAPABILITIES = [ ... "content:write", "taxonomies:read", ... ] as const;

packages/marketplace/src/routes/author.ts:254-278, used at :295 and :829

comments:read / comments:moderate were added to packages/core/src/plugins/manifest-schema.ts:31-32, plugin-types, plugin-cli, the admin consent labels and the registry lexicon — but packages/marketplace isn't touched by this diff at all, and the list contains no comments: entry.

Failure scenario: an author publishes a bundle whose emdash-plugin.jsonc declares comments:moderate. Both POST /plugins (register, :295) and POST /plugins/:id/versions (manifestSchema.safeParse(manifest) at :409) fail with 400 Invalid manifest: capabilities.0: Invalid enum value, as do the /dev upload routes that reuse manifestSchema (routes/dev.ts:88,152). The capability the changeset advertises is undistributable and uninstallable through the marketplace channel; only the atproto registry channel works.

It fails closed, so it isn't a privilege issue — but the feature is broken end-to-end on that path. It's also the invariant the file's own comment states, and the precedent capability-addition PR (#1719, taxonomies:read) did update this list.

Fix: add "comments:read" and "comments:moderate" to VALID_CAPABILITIES after content:write, matching core's order.

Worth noting this is the same class of gap as #3172, which needs media:bytes:read / media:metadata:write added to the same list — if several of these land together it's worth a single check across the stack.


Checked and clean: PluginBridge.commentGet/List/Count/SetStatus gate on ctx.props.capabilities host-side, and workerd's dispatch uses requireCapability(opts, …); comments:moderate ⇒ comments:read is materialised in adapt-sandbox-entry.ts, define-plugin.ts, both wrappers, bridge-handler, the Cloudflare runner's props, and declared-access.ts canonicalization, so the digest/escalation check can't be dodged by declaring only moderate. The host re-validates status on every call (assertPluginCommentStatus on both status and expectedStatus), so even a bridge bypass can't reach trash. No plugin create/edit/delete or bulk API exists; findForPlugin/countForPlugin/get all exclude status = 'trash', and single-row CAS via updateStatusIf applies exactly one of two concurrent transitions. toPluginComment drops authorUserId, and every exposed field (email, hashed IP, user agent) is named in the consent label, docs, changeset and lexicon. Pagination clamps 1..100 with encodeCursor/decodeCursor; all filters are parameterised, no sql.raw. The moderation route still does requirePerm(user, "comments:moderate") before any work, no GET was added, and there are no new logged-out queries. Tests are runtime-backed (real Worker Loader host, real SQLite repo, real bridge dispatch) and would fail on regression.

~ 🤖 Codex

@ascorbic

Copy link
Copy Markdown
Collaborator Author

Addressed the marketplace publication blocker in 779d3f7.

The marketplace now imports the canonical PLUGIN_CAPABILITIES tuple from @emdash-cms/plugin-types instead of maintaining a local copy, so comments:read and comments:moderate are accepted consistently for plugin registration, uploaded version manifests, and the /dev routes that reuse manifestSchema. I added a regression test covering both capabilities at both schema boundaries.

Validated with the full marketplace suite (47/47), marketplace typecheck, plugin-types tests (71/71), lint, lockfile verification, and a Wrangler dry-run. An independent adversarial review of the exact new head found no blockers.

@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Sep 19, 2026
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/approved Approved; no new commits since labels Sep 19, 2026
@ascorbic

Copy link
Copy Markdown
Collaborator Author

Merge-order hazard with the sibling marketplace fix

#3170 and #3172 both change packages/marketplace/src/routes/author.ts, and they conflict. Confirmed with git merge-tree against their merge base a4af5781:

packages/marketplace/src/routes/author.ts
+<<<<<<< .our
+=======
+>>>>>>> .their

The two took different approaches to the same bug:

The conflict is loud, so nothing slips through silently at merge time. The risk is in the resolution: keeping #3172's hardcoded block would discard the shared import and re-break comments:read / comments:moderate publication, reintroducing the original bug.

Correct resolution: take #3170's shared PLUGIN_CAPABILITIES plus the @emdash-cms/plugin-types dependency, and drop #3172's marketplace edit. The shared list is a superset once both branches' capability additions land in plugin-types, so nothing is lost. Practically: merge #3170 first, then rebase #3172 to drop its author.ts change.

Worth noting this affects more than these two — #3185 (hooks.content-policy:register) and #3194 (content:publish/content:restore) have the same unpublishable-capability gap and neither touches author.ts. #3170's shared-list approach fixes all four at once, which is another argument for landing it first.

~ 🤖 Codex (claude-opus-5)

…tration

# Conflicts:
#	packages/cloudflare/src/sandbox/bridge.ts
@ascorbic
ascorbic enabled auto-merge (squash) September 19, 2026 10:56
@ascorbic
ascorbic disabled auto-merge September 19, 2026 10:57
@ascorbic ascorbic added bot:review Trigger an emdashbot code review on this PR and removed bot:review Trigger an emdashbot code review on this PR labels Sep 19, 2026
…tration

# Conflicts:
#	apps/release-action/dist/index.js
#	docs/src/content/docs/plugins/creating-plugins/capabilities.mdx
#	packages/admin/src/lib/api/marketplace.ts
#	packages/admin/tests/lib/marketplace.test.ts
#	packages/cloudflare/src/sandbox/bridge.ts
#	packages/cloudflare/src/sandbox/runner.ts
#	packages/cloudflare/src/sandbox/types.ts
#	packages/cloudflare/src/sandbox/wrapper.ts
#	packages/cloudflare/tests/sandbox/wrapper-context.test.ts
#	packages/core/src/emdash-runtime.ts
#	packages/core/src/index.ts
#	packages/core/src/plugins/context.ts
#	packages/core/src/plugins/define-plugin.ts
#	packages/core/src/plugins/index.ts
#	packages/core/src/plugins/manifest-schema.ts
#	packages/core/src/plugins/sandbox/index.ts
#	packages/core/src/plugins/sandbox/types.ts
#	packages/core/tests/integration/plugins/capabilities.test.ts
#	packages/core/tests/unit/plugins/define-plugin.test.ts
#	packages/marketplace/src/routes/author.ts
#	packages/plugin-cli/src/init/templates.ts
#	packages/plugin-cli/src/manifest/schema.ts
#	packages/plugin-cli/tests/manifest-trust-contract.test.ts
#	packages/plugin-test/src/runtime-host.ts
#	packages/plugin-test/test/fixture/emdash-plugin.jsonc
#	packages/plugin-test/test/fixture/src/plugin.ts
#	packages/plugin-types/src/declared-access.ts
#	packages/plugin-types/src/index.ts
#	packages/plugin-types/src/manifest-schema.ts
#	packages/plugin-types/tests/capabilities.test.ts
#	packages/plugin-types/tests/declared-access.test.ts
#	packages/plugin-types/tests/manifest-schema.test.ts
#	packages/registry-lexicons/lexicons/com/emdashcms/experimental/package/releaseExtension.json
#	packages/registry-lexicons/tests/types.test.ts
#	packages/workerd/src/sandbox/bridge-handler.ts
#	packages/workerd/src/sandbox/dev-runner.ts
#	packages/workerd/src/sandbox/runner.ts
#	packages/workerd/src/sandbox/wrapper.ts
#	packages/workerd/test/bridge-handler.test.ts
#	packages/workerd/test/wrapper-context.test.ts
#	skills/creating-plugins/SKILL.md
@ascorbic ascorbic added bot:review Trigger an emdashbot code review on this PR and removed bot:review Trigger an emdashbot code review on this PR labels Sep 19, 2026

@emdashbot emdashbot 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.

Re-review: still the right change, and the prior blockers are resolved

This PR adds the sandboxed comment-administration capability slice (comments:read and comments:moderate) to the plugin runtime contract, the admin consent layer, the core moderation service, and both sandbox bridges (Cloudflare Worker Loader and workerd). The approach remains correct and well-scoped: it gives plugins explicit, consent-gated access to comment personal data and expected-status moderation, routes plugin transitions through the same core service as admin transitions so notifications and hooks behave identically, and avoids touching logged-out routes.

This is a re-review. My previous review approved the change after two findings were addressed, and I verified that those fixes are present:

  • The comment:afterModerate hook is now documented as awaited once per successful transition, not fire-and-forget.
  • The changeset now describes the user-facing release impact (new capabilities, exposed data, error codes, and behavior) rather than internal test helpers.

For this pass I re-read the full diff and traced the implementation end-to-end:

  • Core moderation path: CommentRepository.updateStatusIf atomically guards on expectedStatus and returns clear updated/unchanged/conflict/not_found states. moderateComment fences same-comment recursion with AsyncLocalStorage, while EmDashRuntime.moderateCommentWithOrigin uses a per-runtime set to reject overlapping in-process transitions with COMMENT_MODERATION_IN_PROGRESS.
  • Admin route: packages/core/src/astro/routes/api/admin/comments/[id]/status.ts delegates through handleCommentModerate, passes the observed prior status, checks the existing comments:moderate RBAC permission, and maps CommentStatusConflictError and COMMENT_MODERATION_IN_PROGRESS to 409 responses.
  • Plugin access layer: PluginContextFactory only exposes ctx.comments when the plugin declares comments:read or comments:moderate; comments:moderate implies comments:read consistently through definePlugin, adaptSandboxEntry, the Cloudflare wrapper/runner, and the workerd bridge-handler. PluginComment excludes authorUserId as documented.
  • Bridge security: Capability gating happens on every bridge method; invalid plugin statuses are rejected before reaching the runtime callback; errors are translated into the documented COMMENT_STATUS_* shapes.
  • SQL/data integrity: Comment queries are Kysely builder calls with parameterized values; no interpolation. Comment table queries do not filter on locale because comments are not localized content rows.
  • Changeset/docs: The changeset lists the affected published packages and describes the released capability and error contract. Public docs match the PluginComment shape and the comments:moderate implication rules.
  • Tests: The added tests cover capability gating, atomic concurrency, recursive moderation, runtime-bridge integration, admin HTTP integration, declared-access round-trips, and generated-wrapper behavior.

I found no new logic bugs, security gaps, missing authorization checks, or AGENTS.md convention violations. LGTM.

@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Sep 19, 2026
@github-actions github-actions Bot added review/approved Approved; no new commits since and removed review/needs-rereview Author pushed changes since the last review labels Sep 19, 2026
@ascorbic
ascorbic merged commit 3538bb8 into main Sep 19, 2026
58 checks passed
@ascorbic
ascorbic deleted the codex/comment-administration branch September 19, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant