Skip to content

Run the per-scenario emulators locally, and let a paused execution outlive a human - #1712

Open
RhysSullivan wants to merge 4 commits into
mainfrom
ci/local-emulators
Open

Run the per-scenario emulators locally, and let a paused execution outlive a human#1712
RhysSullivan wants to merge 4 commits into
mainfrom
ci/local-emulators

Conversation

@RhysSullivan

@RhysSullivan RhysSullivan commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #1707, which left two failures. This fixes both; the matrix is now green three runs in a row (36/36 each).

The hosted emulator was never ours to keep green

graphql-introspection-health had started failing on every CI run with 403 API rate limit exceeded from the hosted GitHub emulator instead of the 401 it had armed a fault for. Raising the fault budget from 10 to 100 changed nothing, so whatever produced that 403 sits outside the instance's own fault accounting — and from a shared CI egress IP there is no version of the scenario that can stay under it. Same dependency, different symptom, cost 17 more shards in the two weeks to Aug 20: connect ETIMEDOUT and bare 502s reaching <service>.emulators.dev.

@executor-js/emulate describes itself as "local drop-in replacement services for CI and no-network sandboxes", and the suite already boots WorkOS and Autumn in-process in setup/cloud.boot.ts. createEmulatorInstance now does the same per scenario: OS-assigned port, createEmulator, a control-plane readiness probe, and Effect.acquireRelease so the emulator dies with the scenario's scope. Same package, same wire behaviour, same per-run isolation — a fresh process-local instance keeps ledger assertions as clean as a fresh hosted one — minus the network.

Five scenarios move: graphql-introspection-health (github), oauth-client-handoff (microsoft), connect-handoff and connect-handoff-session (resend), google-health-checks (google). Four needed their bodies wrapped in Effect.scoped.

selfhost/mcp-oauth-scope-discovery-emulate deliberately stays on the deployed instance — proving executor works against a real deployment is the point of that scenario, and mcp-oauth-scope-discovery covers the same contract in-process.

A paused execution has to outlive a human

The browser approval scenario measures what that costs. From the failing trace: GET /api/mcp-sessions/<id> 200 at 17:05:11.898, POST the approval at 17:05:20.629 → 404. 8.7 s from page load to the Approve click on a loaded runner, against a 6 s ceiling, with the page showing "This paused execution is no longer available". 12 shards in two weeks.

Production allows 9 minutes. The 6 s was a test-speed knob, and cloud/mcp-client-sessions is the only thing that wants it small — it derives its teardown wait from the value, so raising it to 30 s is paid for there and nowhere else. That is the trade: seconds on one scenario against a 30-second timeout plus a re-run of the whole matrix.

Note on AGENTS.md

AGENTS.md said to "create per-run hosted instances through the service's /_emulate/instances control route". This PR rewrites that line to prefer in-process instances and to say when a hosted one is still right. Flagging it because it is a documented-policy change, not just a code change.

Verified

Three consecutive full-matrix CI runs, 36/36 green. All five moved scenarios green on selfhost locally, with no emulator process or listener surviving the run. typecheck, lint, format:check clean.

Still open after this

The foreign-org-slug not-found bug behind the biggest flake is filed as #1713 — a product fix in the shell rendering path, not CI hardening, and it needs a cloud stack to verify.

The hosted control plane put the public internet on the critical path of
scenarios that are otherwise entirely local: connect ETIMEDOUT and 502s
reaching the edge failed 17 shards in two weeks, and by Aug 20
graphql-introspection-health failed every run on a 403 rate limit the
instance answered ahead of the fault it had armed - raising the budget from
10 to 100 changed nothing, so it was never ours to stay under.

@executor-js/emulate is built for this ("local drop-in replacement services
for CI and no-network sandboxes") and the suite already boots WorkOS and
Autumn that way. Same package, same wire behaviour, same per-run isolation,
minus the network. Scoped, so the emulator dies with the scenario.
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Console https://executor-preview-pr-1712.executor-e2e.workers.dev
MCP https://executor-preview-pr-1712.executor-e2e.workers.dev/mcp
Deployed commit 2e1fdac

Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 20, 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 Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 2e1fdac Commit Preview URL

Branch Preview URL
Aug 20 2026, 06:22 PM

The browser approval scenario measures what that costs: 8.7s from page load
to the Approve click on a loaded runner, against a 6s ceiling, so the POST
came back 404 and the page said the execution was no longer available. 12
shards in two weeks. Production allows 9 minutes; 6s was a test-speed knob
borrowed from the expiry scenario, which now sleeps correspondingly longer -
the one place the raise is paid for.
@pkg-pr-new

pkg-pr-new Bot commented Aug 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@1712

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@1712

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@1712

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@1712

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@1712

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@1712

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@1712

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@1712

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@1712

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@1712

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@1712

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@1712

executor

npm i https://pkg.pr.new/executor@1712

commit: 2e1fdac

@RhysSullivan RhysSullivan changed the title Run the per-scenario emulators locally instead of over the internet Run the per-scenario emulators locally, and let a paused execution outlive a human Aug 20, 2026
@RhysSullivan
RhysSullivan marked this pull request as ready for review August 20, 2026 18:18
@cloudflare-workers-and-pages

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
executor-cloud 2e1fdac Aug 20 2026, 06:24 PM

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.

1 participant