Skip to content

Unify plugin capability names#816

Merged
ascorbic merged 3 commits intomainfrom
opencode/issue767-20260429064350
Apr 29, 2026
Merged

Unify plugin capability names#816
ascorbic merged 3 commits intomainfrom
opencode/issue767-20260429064350

Conversation

@ask-bonk
Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot commented Apr 29, 2026

Final summary: Implemented the unified plugin capability formula with deprecation aliases per the issue.


What does this PR do?

Implements the unified plugin capability formula proposed in the issue: every capability now follows <resource>[.<sub-resource>]:<verb>[:<qualifier>], hook-registration permissions are split out into their own hooks.<family>:register namespace, and :any is replaced with the conspicuous :unrestricted qualifier. Old names keep working through a runtime alias layer for one minor; the bundle/validate CLIs warn for each deprecated name and publish hard-fails before authentication.

Closes #767

Old New
read:content content:read
write:content content:write
read:media media:read
write:media media:write
read:users users:read
network:fetch network:request
network:fetch:any network:request:unrestricted
email:provide hooks.email-transport:register
email:intercept hooks.email-events:register
page:inject hooks.page-fragments:register

Where the alias layer lives — and the runtime never sees the old names:

  • definePlugin and adaptSandboxEntry rewrite via normalizeCapabilities() before applying capability implications, so write:content still implies the (canonical) content:read.
  • context.ts and hooks.ts were updated to check the canonical names only — no dual-checks.
  • marketplace.ts diffCapabilities normalizes both sides before diffing, so a v1 read:content → v2 content:read upgrade reports an empty diff (no spurious "capability changed" prompt).
  • bundle warns for each deprecated name, validate (which delegates to bundle) warns, publish errors before authentication.

Type of change

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

The issue itself has been the discussion (filed by the maintainer asking for implementation) — /bonk implement this from the maintainer is the implementation request.

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes (18 baseline diagnostics, all preexisting and in unrelated files)
  • pnpm test passes (786 plugin/marketplace tests pass; 8 unrelated failures are admin-build infra issues)
  • 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 (no admin UI changes)
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: the linked issue is the design proposal

Tests added

  • tests/unit/plugins/capability-normalization.test.ts — 15 new tests pinning CAPABILITY_RENAMES, isDeprecatedCapability, normalizeCapability, and normalizeCapabilities (idempotence, dedup, no-mutation).
  • tests/unit/plugins/define-plugin.test.ts — added 3 tests for the alias layer in native plugins (rewrite all 10 deprecated names, dedup current+deprecated, normalize before applying implications).
  • tests/unit/plugins/adapt-sandbox-entry.test.ts — added 2 tests for the same in sandboxed plugins.
  • tests/unit/api/marketplace-handlers.test.ts — added 1 test that diffCapabilities treats an installed read:content v1 → published content:read v2 as no change (no confirmCapabilityChanges needed).
  • Existing tests that constructed ResolvedPlugin objects directly were updated to use canonical names — these tests bypass definePlugin, so they're testing the runtime invariant that the pipeline only sees canonical names.

AI-generated code disclosure

  • This PR includes AI-generated code

Notes for reviewers

  • Templates' .agents/skills/creating-plugins/** were left alone to avoid bulk drive-by changes — they'll pick up the new names through a separate template-sync flow. Old names in those template skills still work through the alias layer.
  • The example plugins under packages/plugins/* and the marketplace audit fixtures still declare old names. They continue to work via the alias layer; updating them is a follow-up.
  • I deliberately left email:send unchanged per the issue's open question — send is a genuine verb distinct from CRUD, so renaming it to email:write wouldn't read better.

Closes #767

github run

Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 29, 2026

🦋 Changeset detected

Latest commit: a70fab2

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

This PR includes changesets to release 13 packages
Name Type
emdash Minor
@emdash-cms/cloudflare Minor
@emdash-cms/admin Minor
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
create-emdash 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

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

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
emdash-i18n a70fab2 Apr 29 2026, 11:15 AM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

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 a70fab2 Apr 29 2026, 11:16 AM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

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
emdash-perf-coordinator a70fab2 Apr 29 2026, 11:15 AM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

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
emdash-playground a70fab2 Apr 29 2026, 11:17 AM

@github-actions
Copy link
Copy Markdown
Contributor

PR template validation failed

Please fix the following issues by editing your PR description:

See CONTRIBUTING.md for the full contribution policy.

@github-actions
Copy link
Copy Markdown
Contributor

Scope check

This PR changes 1,369 lines across 38 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.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

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
emdash-demo-cache a70fab2 Apr 29 2026, 11:16 AM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 29, 2026

Open in StackBlitz

@emdash-cms/admin

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

@emdash-cms/auth

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

@emdash-cms/blocks

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

@emdash-cms/cloudflare

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

emdash

npm i https://pkg.pr.new/emdash@816

create-emdash

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

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

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

@emdash-cms/x402

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

@emdash-cms/plugin-ai-moderation

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

@emdash-cms/plugin-atproto

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

@emdash-cms/plugin-audit-log

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

@emdash-cms/plugin-color

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

@emdash-cms/plugin-embeds

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

@emdash-cms/plugin-forms

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

@emdash-cms/plugin-webhook-notifier

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

commit: a70fab2

@github-actions
Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the capability renaming/unification plan from #767 by introducing canonical capability names, adding a runtime alias/normalization layer for legacy names, and wiring deprecation warnings/errors into the plugin CLI and marketplace upgrade diffing.

Changes:

  • Introduces canonical capability strings + legacy alias mapping utilities (CAPABILITY_RENAMES, normalizeCapability(ies)) and updates runtime checks to only use canonical names.
  • Updates hook registration gating to the new hooks.<family>:register namespace and replaces :any with :unrestricted.
  • Adds CLI warnings (bundle/validate) and publish-time hard-fail for deprecated capability names; normalizes capability diffs in marketplace upgrades; updates docs and tests accordingly.

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
skills/creating-plugins/references/hooks.md Updates hook capability requirements/examples to canonical names.
skills/creating-plugins/references/api-routes.md Updates external proxy example to network:request.
skills/creating-plugins/SKILL.md Updates capability references and tables to canonical names.
packages/core/tests/unit/plugins/standard-format.test.ts Updates expected serialized capabilities to canonical names.
packages/core/tests/unit/plugins/pipeline-rebuild.test.ts Updates test plugin capabilities for hook pipeline rebuild scenarios.
packages/core/tests/unit/plugins/page-hooks-execution.test.ts Updates page fragments capability naming and assertions.
packages/core/tests/unit/plugins/marketplace-client.test.ts Updates manifest fixtures to canonical capabilities.
packages/core/tests/unit/plugins/manager.test.ts Updates implication expectations to content:writecontent:read.
packages/core/tests/unit/plugins/hooks.test.ts Updates hook gating tests to canonical capabilities.
packages/core/tests/unit/plugins/exclusive-hooks.test.ts Updates email hook capability fixtures to new hook-registration capabilities.
packages/core/tests/unit/plugins/email-pipeline.test.ts Updates email pipeline tests to canonical + hook-registration capabilities.
packages/core/tests/unit/plugins/define-plugin.test.ts Updates capability validation/implication tests and adds alias-layer tests.
packages/core/tests/unit/plugins/capability-normalization.test.ts Adds unit tests for rename map + normalization helpers.
packages/core/tests/unit/plugins/adapt-sandbox-entry.test.ts Updates and extends adapter tests for canonicalization + alias layer.
packages/core/tests/unit/api/marketplace-handlers.test.ts Updates capability diff expectations and adds “rename is no change” coverage.
packages/core/tests/integration/plugins/capabilities.test.ts Updates enforcement error matching and capability fixtures.
packages/core/tests/integration/comments/hooks.test.ts Updates comment hook capability fixtures to users:read.
packages/core/src/plugins/types.ts Defines canonical + deprecated capability unions, rename map, and normalization helpers.
packages/core/src/plugins/manifest-schema.ts Splits current vs deprecated capability enums; keeps combined accepted list.
packages/core/src/plugins/hooks.ts Updates HOOK_REQUIRED_CAPABILITY mapping to canonical + hook-registration capabilities.
packages/core/src/plugins/define-plugin.ts Normalizes deprecated capability names before applying implications.
packages/core/src/plugins/context.ts Updates context gating and error messages to canonical capabilities.
packages/core/src/plugins/adapt-sandbox-entry.ts Normalizes deprecated capability names in sandbox adapter before implications.
packages/core/src/emdash-runtime.ts Updates built-in plugin capabilities to canonical names.
packages/core/src/cli/commands/publish.ts Hard-fails publish if manifest contains deprecated capability names.
packages/core/src/cli/commands/bundle.ts Adds deprecated-capability warnings; updates network warning logic/messages.
packages/core/src/api/handlers/marketplace.ts Normalizes both sides in diffCapabilities to avoid spurious upgrade prompts.
docs/src/content/docs/reference/hooks.mdx Updates hook docs to new capability names.
docs/src/content/docs/plugins/sandbox.mdx Updates sandbox docs to canonical capabilities.
docs/src/content/docs/plugins/overview.mdx Updates overview docs + adds rename table and deprecation note.
docs/src/content/docs/plugins/installing.mdx Updates installation audit capability labels to canonical names.
docs/src/content/docs/plugins/hooks.mdx Updates content hook capability requirements to canonical names.
docs/src/content/docs/plugins/creating-plugins.mdx Updates example plugin descriptor capabilities to canonical names.
docs/src/content/docs/plugins/api-routes.mdx Updates external API proxy docs to network:request.
docs/src/content/docs/plugins/admin-ui.mdx Updates example capability to network:request.
docs/src/content/docs/migration/porting-plugins.mdx Updates migration table capability strings to canonical names.
docs/src/content/docs/coming-from/astro.mdx Updates example capability to content:read.
.changeset/unified-plugin-capabilities.md Adds minor changeset describing renames + deprecation behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/plugins/types.ts Outdated
* Type guard: is this capability one of the deprecated legacy names?
*/
export function isDeprecatedCapability(cap: string): cap is DeprecatedPluginCapability {
return cap in CAPABILITY_RENAMES;
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

isDeprecatedCapability uses the in operator, which also matches properties on Object.prototype (e.g. "toString", "constructor"). That means normalizeCapability("toString") would incorrectly treat it as deprecated and return a non-string value from the prototype chain, violating the function contract (“unknown strings are returned as-is”) and potentially breaking callers.

Use an own-property check instead (e.g. Object.hasOwn(CAPABILITY_RENAMES, cap) / Object.prototype.hasOwnProperty.call(...)) or construct CAPABILITY_RENAMES with Object.create(null) to avoid a prototype entirely. Consider adding a test case for "toString"/"proto" to prevent regressions.

Suggested change
return cap in CAPABILITY_RENAMES;
return Object.prototype.hasOwnProperty.call(CAPABILITY_RENAMES, cap);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@ascorbic ascorbic left a comment

Choose a reason for hiding this comment

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

@ask-bonk thanks for the PR. I found one runtime blocker and one smaller docs issue.

HIGH: Cloudflare sandbox still enforces the old capability names

packages/cloudflare/src/sandbox/bridge.ts and packages/cloudflare/src/sandbox/bridge-http.ts still check legacy capabilities like read:content, write:content, network:fetch, and network:fetch:any. This PR updates manifests/descriptors and core runtime checks to canonical names like content:read and network:request, but those canonical names are passed through to the Cloudflare bridge and denied there.

Trigger: publish or install a sandboxed plugin with capabilities: ["content:read", "network:request"], then call ctx.content.get() or ctx.http.fetch(). The bridge sees no read:content / network:fetch and throws a missing capability error.

Fix: normalize capabilities before passing them into the bridge and update bridge enforcement to check canonical names. Keep the normalization path so existing installed manifests with legacy names continue working.

LOW: Publish failure links to a missing docs page

packages/core/src/cli/commands/publish.ts points deprecated-capability failures at https://emdashcms.com/docs/plugins/capabilities, but this repo does not have a docs/plugins/capabilities page. Users who hit the new publish error get sent to a 404.

Trigger: run emdash plugin publish on a tarball containing read:content.

Fix: point to the existing capability section in the plugin overview docs, or add the referenced page.

@ask-bonk
Copy link
Copy Markdown
Contributor Author

ask-bonk Bot commented Apr 29, 2026

@ascorbic Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

@ascorbic
Copy link
Copy Markdown
Collaborator

/ultrabonk address the issues in the reviews

Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>
@ask-bonk
Copy link
Copy Markdown
Contributor Author

ask-bonk Bot commented Apr 29, 2026

All review feedback has been addressed. Below is the PR body for the new changes.


What does this PR do?

Addresses the three review findings on PR #816:

Copilot — isDeprecatedCapability matched prototype keys. The previous cap in CAPABILITY_RENAMES check also returned true for inherited keys like toString, constructor, and __proto__, which broke the documented contract that unknown strings are returned as-is from normalizeCapability. Switched to Object.hasOwn(CAPABILITY_RENAMES, cap) and added five regression tests covering toString, constructor, hasOwnProperty, __proto__, and valueOf, plus a normalizeCapability test that pins prototype keys returning the original string (not the prototype function reference).

ascorbic HIGH — Cloudflare sandbox bridge still enforced legacy names. packages/cloudflare/src/sandbox/bridge.ts and bridge-http.ts were checking read:content, write:content, read:media, write:media, read:users, network:fetch, and network:fetch:any while the rest of the runtime had moved to canonical names. A plugin published with capabilities: ["content:read", "network:request"] would have its bridge calls denied. Two-part fix:

  • The bridge now enforces canonical names only (content:read, content:write, media:read, media:write, users:read, network:request, network:request:unrestricted).
  • The runner (runner.ts) and the wrapper-code generator (wrapper.ts) call normalizeCapabilities() before the manifest crosses into the bridge, so installed manifests that still declare legacy names get rewritten to canonical before reaching enforcement. Old installs keep working without any republish.

To make this possible, exported CAPABILITY_RENAMES, isDeprecatedCapability, normalizeCapability, normalizeCapabilities, CurrentPluginCapability, and DeprecatedPluginCapability from the public emdash API. Also updated packages/cloudflare/src/plugins/vectorize-search.ts (which declared read:content) and packages/cloudflare/tests/sandbox/bridge-http.test.ts (30 tests, all passing on the new names). Bumped the admin's CAPABILITY_LABELS map to recognize both legacy and canonical capability strings so manifest UIs render meaningful copy on either side of the rename.

ascorbic LOW — Publish error pointed at a 404. emdash plugin publish redirected authors at https://emdashcms.com/docs/plugins/capabilities, which doesn't exist. Updated to https://emdashcms.com/docs/plugins/overview#capabilities, which is where the rename table actually lives in this PR.

Updated the changeset to bump @emdash-cms/cloudflare (minor) and @emdash-cms/admin (patch) since both ship behavior changes.

Type of change

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

These are bug fixes against the open feature PR #816 — the underlying feature itself was discussed and approved on issue #767.

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (preexisting Astro/admin demo failures only — unrelated Node 20 vs 22 mismatch)
  • pnpm lint passes (0 errors after the Object.hasOwn fix; same 4 preexisting no-unsafe-type-assertion warnings in packages/blocks/src/validation.ts)
  • pnpm test passes (744 plugin/marketplace tests + 157 cloudflare tests; same 8 preexisting admin-build failures around @emdash-cms/admin/dist/index.js resolution that this PR does not touch)
  • 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 (no admin UI string changes; CAPABILITY_LABELS was already English-keyed and consumed via t(label))
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: this is a bug-fix follow-up, not a new feature

Tests added

  • packages/core/tests/unit/plugins/capability-normalization.test.ts — added does not match Object.prototype keys (5 cases) under isDeprecatedCapability and returns Object.prototype keys as-is (3 cases) under normalizeCapability. These pin the regression: with the old in check, normalizeCapability("toString") returned Object.prototype.toString; now it returns "toString".
  • packages/cloudflare/tests/sandbox/bridge-http.test.ts — updated all 30 tests to use canonical capability names (network:request, network:request:unrestricted). The bridge-http enforcement path is now tested only against canonical names; the legacy-name path is covered by the runner-level normalization tests in core.

AI-generated code disclosure

  • This PR includes AI-generated code

Notes for reviewers

  • I deliberately didn't add a unit test for runner.ts calling normalizeCapabilities before bridge construction — bridge.ts and runner.ts rely on the Cloudflare WorkerEntrypoint runtime and there's no existing harness for unit-testing them. The behavior is covered by the type system (canonical names only) plus the normalization unit tests.
  • wrapper.ts was also updated to normalize before deciding which APIs to expose in the generated wrapper code (hasReadUsers). Without this, a manifest declaring canonical users:read would not get the user APIs in the wrapper context.
  • Demo plugins under packages/plugins/* and audit fixtures under packages/marketplace/tests/fixtures/audit/* still use legacy names — same as before, those continue to work via the alias layer and were intentionally left out of scope per the original PR's note.

github run

@ascorbic
Copy link
Copy Markdown
Collaborator

/ultrabonk tests are failing. fix pls

Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>
@ask-bonk
Copy link
Copy Markdown
Contributor Author

ask-bonk Bot commented Apr 29, 2026

Lint clean. The fix is minimal and targeted: align the test expectation with the actual CAPABILITY_LABELS keys (canonical names + legacy aliases) the PR introduced.


What does this PR do?

Fixes the Browser Tests job failure on PR #816. The CAPABILITY_LABELS test in packages/admin/tests/lib/marketplace.test.ts was still asserting the pre-rename key list (read:content, write:content, read:media, write:media, network:fetch, network:fetch:any), but the source map in packages/admin/src/lib/api/marketplace.ts was updated as part of the review-feedback commit to include both canonical names (content:read, content:write, media:read, media:write, users:read, network:request, network:request:unrestricted) and legacy aliases. The toEqual assertion was strict, so the array length and order both diverged and the test failed.

Updated the expected key list to match the actual source order: 7 canonical names followed by 7 legacy aliases. No source/runtime changes — this is a test-only realignment.

The other failing check on PR #816 (Validate PR) is the PR-template "Feature PRs need a linked Discussion" complaint, which is metadata and outside the scope of a tests fix.

Type of change

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

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes (pnpm --silent lint:quick reports 0 diagnostics)
  • pnpm test passes (could not run admin browser tests locally — Playwright browser binary not installed in this sandbox; the failing assertion is now aligned with the source-of-truth CAPABILITY_LABELS key order)
  • 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 (no admin UI string changes)
  • I have added a changeset (test-only fix, no published-package behavior change)
  • New features link to an approved Discussion: bug fix, not a feature

AI-generated code disclosure

  • This PR includes AI-generated code

github run

@ascorbic ascorbic enabled auto-merge (squash) April 29, 2026 11:21
@ascorbic ascorbic dismissed their stale review April 29, 2026 11:24

Now fixed

@ascorbic ascorbic merged commit d4be24f into main Apr 29, 2026
32 of 33 checks passed
@ascorbic ascorbic deleted the opencode/issue767-20260429064350 branch April 29, 2026 11:24
@emdashbot emdashbot Bot mentioned this pull request Apr 29, 2026
ascorbic added a commit that referenced this pull request Apr 29, 2026
The Apply workflow has been silently broken for ~2 days, so PRs that
landed in that window (#820, #816, #811) merged with stale snapshots
in the repo. CI's Measure on this PR shows the real per-route counts
on top of current main: uniform +1 cold and +1 warm on all public
routes except /pages/about and /rss.xml. This is pre-existing drift,
not caused by this PR — it's the natural consequence of the Apply
workflow failing to commit the auto-updated snapshots that the
Measure step correctly produced on those merged PRs.

Apply CI's regenerated snapshots from this PR's Measure run so main
ends up in a consistent state once this lands. Future PRs will then
get their own real drift signal rather than inheriting this baseline
correction.
ascorbic added a commit that referenced this pull request Apr 29, 2026
* fix(ci): query-counts-apply workflow no longer silently fails

The Apply workflow has been silently broken for ~2 days, never pushing
auto-updated snapshots to PRs that drifted. Two distinct bugs:

(1) Same-repo PRs: the artifact was unpacked into
    $GITHUB_WORKSPACE/artifact, but the later actions/checkout step
    defaults to clean: true and wipes the workspace, deleting our
    payload before the Apply step's cp could read it. Stage under
    $RUNNER_TEMP/qc-artifact instead, which sits outside the workspace.

(2) Fork PRs: the cross-check used listPullRequestsAssociatedWithCommit
    against the base repo, which doesn't reliably surface fork PRs from
    that view, so valid fork artifacts were rejected as 'not associated
    with commit'. Replace with pulls.get(prNumber) and verify
    pr.head.sha === workflow_run.head_sha — equivalent tamper-resistance
    (a forged pr-number won't match), works for forks.

Add pull-requests: read so pulls.get works when the default token
permissions are restricted.

* ci: reconcile query-count snapshot baseline

The Apply workflow has been silently broken for ~2 days, so PRs that
landed in that window (#820, #816, #811) merged with stale snapshots
in the repo. CI's Measure on this PR shows the real per-route counts
on top of current main: uniform +1 cold and +1 warm on all public
routes except /pages/about and /rss.xml. This is pre-existing drift,
not caused by this PR — it's the natural consequence of the Apply
workflow failing to commit the auto-updated snapshots that the
Measure step correctly produced on those merged PRs.

Apply CI's regenerated snapshots from this PR's Measure run so main
ends up in a consistent state once this lands. Future PRs will then
get their own real drift signal rather than inheriting this baseline
correction.
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.

Plugin capability names are inconsistent — propose unified formula and deprecation path

2 participants