Skip to content

agent-bundle/test: export loadRouteModule(id) so consumers stop static-importing every route module for schema-identity suites (xref rows 3 & 11) #493

Description

@ScriptedAlchemy

Problem

Cross-reference matrix rows 3 & 11 / suggestion 9 asked whether agent-bundle should expose a public read-only route manifest (React Router's virtual route manifest, TanStack's routesByFile) so the Workbench, tests, and agent-side topology stop reaching around the compiled route graph.

Assessment: the manifest already exists on every surface that needs one, and the single real workaround found is not about topology but about loading a route module by compiled id — which the agent-bundle/test registry can already do, through a helper it does not export.

Evidence

What is already public (no new module warranted):

  • testManifest() from agent-bundle/test (packages/agent-bundle/src/test/manifest.ts) — route ids, kinds, serverId placements, relativePath + source, statically extracted config, layouts, providers, scripts, cliCommands, the graph digest, plugin identity, targets, diagnostics.
  • .agent-bundle/routes.d.ts (routes/typegen.ts) — compile-time AgentBundleRoutes keyed by route id with typed RouteInput<Id> / RouteResult<Id>, and since feat(test): type renderRoute ids, inputs, and results from the generated route registration #456 the AgentBundleRouteContracts registration that types renderRoute ids, inputs, and results.
  • agent-bundle inspect --json (routes/inspect.ts) — the same graph for scripts and CI.
  • The Workbench consumes the graph through the dev server's own routes, which is the intended coupling for an in-repo consumer.

Consumers checked:

  • examples/worktree-proximity (main 2e59d6e): its "topology" is the worktree/agent topology held in durable state (src/providers/agent-topology.ts, src/coordination.ts), not route topology. tests/route-unit/routes.test.ts already uses testManifest() for route ids and diagnostics. No route-manifest workaround exists; the "coordinator wants a topology digest" premise is unsupported by the code.
  • agent-plugins/cargo-conductor (3f70b60): tests/route-unit/*.test.ts use testManifest() for routes and scripts; no workaround.
  • agent-plugins/movie-library feat/react-app-shell (f37a286): tests/support/route-modules.ts is 120 lines — 47 static import * as mN from '../../src/mcp/<server>/tools/<tool>.tsx' plus a Map — consumed by tests/surface/routes.test.ts to assert loaded-module identity: expect(module.inputSchema).toBe(operation.inputSchema), resultSchema instanceof z.ZodObject, typeof module.default === 'function', and config equality with the catalog registration. The header says "Regenerate the list when a placement changes."

That file cannot be replaced by a manifest of ids and digests: the assertions need the evaluated module. It could be replaced by iterating testManifest().routes and loading each module through the registry — the registry already holds a lazy loader per route id (AgentTestRouteRegistry.loaders, generated by rstest/setup-module.ts), and registeredRouteLoader(manifest, routeId) exists in packages/agent-bundle/src/test/registry.ts:113 — but agent-bundle/test exports only AGENT_TEST_REGISTRY_VERSION, registerTestRoutes, testManifest from that module (test/index.ts:60). renderRoute uses the loader internally; a test that wants the module object has no supported way to get it.

Caveat on the "deletes real code" bar: movie-library runs that surface suite in its plain rstest.config.ts pool (comment: "The route-unit suite runs under the framework-generated configuration … never here"), so adopting a loader would also mean moving the suite into the agentBundleRstest() pool. That is the consumer's call, which is why this is an issue rather than a PR.

Proposed shape

Extend agent-bundle/test, not a new agent-bundle/manifest module or virtual module:

// agent-bundle/test
export const loadRouteModule: <Id extends RouteId = string>(
  routeId: Id,
  options?: { manifest?: AgentBundleTestManifest },
) => Promise<AgentRouteModule>;   // config, inputSchema, resultSchema, default
  • Resolves through registeredRouteLoader; throws AgentTestError('manifest-unavailable', …) with the same recovery text renderRoute uses when no registry or a foreign manifest is present.
  • Typed against the registered route ids the way renderRoute is since feat(test): type renderRoute ids, inputs, and results from the generated route registration #456 (RouteTargetConstraint over @agent-bundle/runtime's Register), so a removed placement is a type error — which is what the static import list currently buys.
  • Docs: website/docs/{en,zh}/guide/development/testing.mdx gains one paragraph beside testManifest(); changeset patch.

Not proposed: per-route schema digests in the manifest (no consumer asked for them; identity is asserted by reference), a runtime agent-bundle/manifest export (the compiled artifact already embeds the routes it serves), or a virtual module (Rspack-only constraint, and nothing in the surveyed apps would import it).

Acceptance

  • import { loadRouteModule } from 'agent-bundle/test' returns the evaluated module for every id in testManifest().routes under agentBundleRstest(), and fails closed with manifest-unavailable outside it.
  • Route-unit test in packages/agent-bundle/tests/route-unit covers a tool, a CLI, and a script route plus the foreign-manifest rejection.
  • en + zh testing docs updated; API reference regenerated by pnpm docs:site:build.
  • Verified against movie-library by replacing tests/support/route-modules.ts with testManifest() + loadRouteModule() in the route-unit pool (consumer-side follow-up, linked from this issue).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmeta-frameworkAgent Bundle compiler-coupled meta-frameworktestingFramework test harnesses and integration evidence

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions