Skip to content

fix(workbench): bind production route executables from the artifact manifest, fail closed (#680) - #684

Closed
ScriptedAlchemy wants to merge 7 commits into
mainfrom
cursor/workbench-exact-executable-binding-ef38
Closed

fix(workbench): bind production route executables from the artifact manifest, fail closed (#680)#684
ScriptedAlchemy wants to merge 7 commits into
mainfrom
cursor/workbench-exact-executable-binding-ef38

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Fixes #680

What changes

packages/agent-bundle/src/dev/routes/route-invocation-production.ts no longer lists *-flight.mjs candidates (candidatesFor, workerFiles), guesses the event wrapper path (eventWrapperPath), or hops to the next worker when one fails with Generated route must default-export (missingRouteWorkerError). Every production invocation now:

  1. Reads the epoch's agent-bundle.manifest.json (readArtifactManifest) — a root without a readable, canonical manifest is AB8250.
  2. Binds the exact executables from the feat(manifest): authoritative agent-bundle.manifest.json v2 — consumers read the composite root through the manifest (#592 step 3, #555 W2/S3) #604 manifest rows (new leaf route-invocation-executable.ts, resolveRouteExecutable), before any module is imported or any worker spawned:
    • CLI surface → executables.bins[] row named after application.name (the one routed CLI bin normalizeBinEntries generates): path (bin) + worker; the route must be in routes.cli.routes.
    • rendered script → executables.scripts[] row with rendered.routeId === routeIdworker.
    • tool/prompt/resource → route's serverIdexecutables.mcpServers[] row, kind: 'compiled'launch.worker.
    • event route → routes.events[].execution; with a host, the executables.hooks[] row (kind: 'event-route', routeId, host) is the wrapper. Worker: hooks/hooks-flight.mjs (must be a files[] row) for runtime: 'standalone'; for shared, the first compiled mcpServers[] row with a launch.worker whose hosts include the host — which is exactly eventRuntimeHosting's choice, because normalizeMcpServers orders the model by server name and the manifest sorts rows by id (mcp:<name>). A canonical (host-less) run takes the first such row of any host (it hosts the runtime for every host it reaches, and every hosting worker registers every event route). fallback: 'standalone' with no hosting server binds the standalone worker.
  3. Fails closed (AB8251) for a route the manifest does not compile, a hosted event with no wrapper row for that host, or a bin/script/server without a worker; fails closed (AB8252) for a bound bin/wrapper that does not export its preparation contract, and for a canonical submission of a route with compiled preflight should one reach the child (the service already refuses it as AB8255) — the old code fell through to the handler with raw input in the missing-wrapper and missing-export cases.
  4. Runs the route in exactly the bound worker. renderCompiled takes one workerPath; a failure inside it (handler throw, worker crash, missing-route error) propagates as the invocation's failure. There is no loop and no second candidate.

hooks/hooks-flight.mjs is now named once (hooksFlightWorkerPath in adapters/composite-layout.ts) and used by build/entries.ts and the binding.

The #604 manifest contract is unchanged: no key added or removed, no version bump; the binding only reads rows the parser already proves (referencedPaths, requireLaunchFiles).

Tests

packages/agent-bundle/tests/route-invocation-production.test.ts (new, unit pool; hand-built canonical manifest via serializeArtifactManifest + stand-in Flight workers that record when they start):

  • exact selection for MCP/script/CLI routes, hosted and canonical standalone events, per-host shared-runtime owner across three servers split over two hosts, single-candidate and fallback-standalone binding
  • fail-closed: unknown route, missing host wrapper, missing hooks worker, canonical + preflight → AB8252, CLI surface on a route the routed CLI does not compile
  • renderProductionRoute: the bound worker's Generated route must default-export error is the failure and the sibling mcp/mcp-beta-flight.mjs / hooks/hooks-flight.mjs never start; a handler failure propagates with no other executable run; AB8250/AB8251/AB8252 are raised before any worker starts; a deny preflight from the bound wrapper returns without a worker, and a wrapper lacking prepareRouteInvocation is AB8252

packages/agent-bundle/tests/route-invocation-dev-server.test.ts ('enforces compiled preflight…'): the real compiled artifact now also carries a shared-runtime event route (tool/after) beside the standalone tool/before, so both the server worker and hooks/hooks-flight.mjs exist; the hosted invocation renders, which only the server worker can do — there is no fallback candidate any more.

Docs / changeset

  • website/docs/{en,zh}/guide/development/workbench.mdx: new paragraph on manifest binding and the fail-closed codes.
  • docs/diagnostics.md: AB8250AB8255 row updated (generated diagnostics page follows).
  • .changeset/680-workbench-exact-executable-binding.md (patch).

Deslop

Deslop: Claude Fable 5.1, 3 edits — replaced a type-predicate intersection with a plain find, flattened let wrapper + if/else into eventWrapper, dropped the now-unused ROUTE_INVOCATION_COMPILED_ROUTE_UNAVAILABLE_CODE import from the production module.

Self-review

Reviewer: gpt-5.6-sol-high (generalPurpose), two passes against origin/main.

# Finding Disposition
1 P1 — shared-runtime owner was chosen with the harness's global eventRuntimeServerId, but eventRuntimeHosting picks an owner per host; a three-server artifact split across hosts could fail AB8251 where main's probing ran a valid worker. Fixed (667d370d): owner is now the first compiled mcpServers[] row with a worker reaching the host, verified equal to eventRuntimeHosting via the model/manifest sort orders; the ambiguity error and the eventRuntimeServerId input are gone. Unit matrix with three servers over two hosts added.
2 P1 — no real-artifact coverage of the new binding. Fixed (667d370d): shared-runtime event route added to the compiled dev-server fixture that also carries hooks/hooks-flight.mjs.
3 P2 — docs/changeset listed a host-less preflight submission under AB8252, but the public API refuses it as AB8255. Fixed (67ffdebf): AB8255 documented as the service refusal, AB8252 as the child's guard.

Second pass: "All three findings are resolved. No remaining concrete merge risks found."

Local gate

Run on c2675aeb (branch contains origin/main b435f7b9), Node 22.22.2:

pnpm build                       → exit 0 (Publint passed)
pnpm typecheck                   → exit 0
pnpm lint                        → exit 0 (1478 files, 88 rules)
pnpm test:unit                   → exit 0 (299 files, 4398 passed, 0 failed)
AGENT_BUNDLE_WORKBENCH_PREBUILT=1 AGENT_BUNDLE_PACKAGE_PREBUILT=1 \
  pnpm rstest --config rstest.integration.config.ts \
  packages/agent-bundle/tests/route-invocation-dev-server.test.ts
                                 → exit 0 (3 passed, 0 failed, 38.6 s)
pnpm docs:site:build             → exit 0 (language parity ok, 0 broken links / 28305 anchors)
Open in Web Open in Cursor 

cursoragent and others added 3 commits September 6, 2026 20:14
`hooksFlightWorkerPath` lives in the composite-layout leaf so the hooks
surface plan and the Workbench binding read the same artifact path.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…anifest

Resolve the routed CLI bin, rendered script worker, owning compiled MCP
server worker, and event wrapper plus runtime worker from
agent-bundle.manifest.json before anything runs, instead of listing
*-flight.mjs candidates and hopping to the next worker on a missing-route
error. Preparation fails closed (AB8250/AB8251/AB8252) when the manifest
cannot bind the route or the bound module lacks its preparation export, and
a failure inside the bound worker never runs another executable.

Fixes #680

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
… fail-closed diagnostics

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Sep 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c2675ae

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

This PR includes changesets to release 1 package
Name Type
agent-bundle 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

cursoragent and others added 4 commits September 6, 2026 20:17
…e binding

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…he manifest

eventRuntimeHosting gives the runtime to the first generated server in model
order that targets the host; the model is ordered by server name and
executables.mcpServers[] by id (mcp:<name>), so the first compiled row with
a Flight worker reaching the host is that server. Drops the harness
eventRuntimeServerId tie-breaker, which was global rather than per host, and
the ambiguity failure it required. The dev-server integration test now runs
a shared-runtime event route through a real artifact that also carries the
standalone hooks worker.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…t route; AB8252 is the child's guard

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
…he shared-runtime event

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@pkg-pr-new

pkg-pr-new Bot commented Sep 6, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@684
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@684
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/rsc-markdown-stream@684
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@684

commit: c2675ae

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Superseded by #692 after a symbol-by-symbol comparison against the expanded #680 acceptance criteria. #692 keeps selection in the leased parent and carries the exact manifest-owned execution/preparation binding into the child, includes real compiled multi-server and ineligible-host import sentinels, and avoids the new resolver abstraction prohibited by the issue scope. I am porting #684's unique execution-record runtime selection, shared hooks-worker path constant, preparation-export regression, and bilingual Workbench wording into #692 before its final review and gate.

@ScriptedAlchemy
ScriptedAlchemy deleted the cursor/workbench-exact-executable-binding-ef38 branch September 6, 2026 21:47
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.

Workbench: resolve exact compiled executable from manifest; fail-closed preflight (no flight probing)

2 participants