@vostride/agent-qa-mcp 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/catalog.ts","../src/app-resource.ts","../src/app-wrapper.ts","../src/live-link.ts","../src/instructions.ts","../src/mapping.ts","../src/masked-result.ts","../src/migration-map.ts","../src/projection.ts","../src/resources.ts","../src/http.ts","../src/conformance-support.ts","../src/task-seam.ts"],"sourcesContent":["// The per-caller server factory (Phase 396 plans 01 + 04, D-01 / D-02 / D-05 / D-11 / D-13 / D-16).\n//\n// WHY THIS FILE EXISTS. `buildAgentQaMcpServer(deps)` is the only thing this package hands a host:\n// give it a composed registry, the caller that host minted, and a masker, and it returns an\n// `McpServer` carrying the tools and resource templates this composition can serve, each of which\n// does nothing but validate and call `invokeFunction`. Every serving entry in the v2 SDK takes a\n// FACTORY and runs it once per serving unit — once per HTTP request, once per stdio connection.\n//\n// 2026-10-01 (432-20, D-12): THE SAME CATALOGUE FOR EVERY CALLER. The per-caller visibility law\n// (`visibleToCaller` over required and granted scopes) and the mark tool's credential hiding are\n// deleted, so a tool is absent only when this composition does not register its op — a fact about\n// the host, identical for a tokenless stdio caller and a tokenless HTTP one. Since 432-21 the mark\n// tool's handler refuses nobody either: there is no bearer credential for it to read.\n//\n// THE HANDLERS DO NOTHING. That is D-01's \"pure projection\" spelled as code, and it is the whole\n// architectural claim of the phase: no MCP-local business logic, no second data path, no reaching\n// past the function layer the way the v1 server reached the dashboard's REST API. Read any handler\n// below and the only verbs are `invokeFunction` and the masker.\n//\n// THREE DISPATCH SHAPES AND NO FOURTH, all of them still nothing but validate-and-invoke:\n// single — one op, called with the caller's arguments unchanged.\n// union — D-01's fold. The discriminant names the arm, is CHECKED against the tool's declared\n// op set, is stripped, and the rest goes to that op. The check is T-396-10's mitigation:\n// a caller cannot smuggle an op this tool does not declare, and even if the composed\n// union were wrong, `invokeFunction` re-validates against the op's own contract.\n// pipeline — D-02's one read door. Two `invokeFunction` calls, the second reached only through the\n// first's resolved arm. Two calls and not one because that is what the resolve-then-get\n// contract IS; a single call could not tell an ambiguous reference from a resolved one.\n//\n// NO PROMPTS ARE REGISTERED (D-14). The authoring brief reaches callers as data through the\n// authoring tools, and 398's build-time capability catalog owns discoverability. The SDK's prompt\n// registration verb is therefore named NOWHERE in this file — including in prose, since an\n// acceptance grep counts occurrences of that symbol and requires zero, and a guard a comment can\n// defeat is not a guard.\n//\n// THE TASK SEAM IS NOT IMPORTED HERE, and that absence is MCPS-06's actual content (D-12): a seam\n// that took the JobQueue contract would make every queue change an MCP change. `task-seam.ts` is\n// published on the barrel for a later consumer and reached by nothing in this build.\n//\n// Protocol grounding: SEP-2567 (no per-connection list variance — and since 432-20 no per-caller\n// variance either), SEP-2549 (list results carry cache hints), SEP-2106 (full JSON Schema 2020-12\n// for the advertised contracts).\n\nimport { McpServer, ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server'\nimport type { CallToolResult } from '@modelcontextprotocol/server'\nimport { invokeFunction, RUNS_ARTIFACT_FUNCTION_ID } from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport type { FunctionCaller } from '@vostride/agent-qa-schema'\n\nimport { MCP_APPS_EXTENSION_ID, appResourceUriFor, registerAppResources } from './app-resource.js'\nimport { AGENT_QA_MCP_INSTRUCTIONS } from './instructions.js'\nimport { liveLinkLineFor } from './live-link.js'\nimport type { LiveLinkSupplier } from './live-link.js'\nimport {\n advertisedContracts,\n AGENT_QA_OP_CONTRACTS,\n AGENT_QA_TOOL_PROJECTIONS,\n compositionOf,\n} from './mapping.js'\nimport type { ToolProjection } from './mapping.js'\nimport {\n decorateRunEvidenceImage,\n maskedToolError,\n maskedToolResult,\n} from './masked-result.js'\nimport { V1_TOOL_MIGRATION_MAP } from './migration-map.js'\nimport type { V1ToolMigrationEntry } from './migration-map.js'\nimport { McpProjectionError, toRegisterToolConfig } from './projection.js'\nimport type { ProjectedOpSpec } from './projection.js'\nimport { registerEntityResources } from './resources.js'\n\n/**\n * The version this server reports.\n *\n * A constant here and NOT the package version read off disk: reading `package.json` at runtime is a\n * host capability this package does not have and must not acquire (its runtime dependency allow-list\n * is the two protocol packages, D-20). Plan 05 decides whether the host should pass its own version\n * in, which is the only place that fact honestly lives.\n */\nexport const AGENT_QA_MCP_SERVER_VERSION = '2.0.0'\n\n/** What a host must supply to build a server for one caller. */\nexport interface AgentQaMcpServerDeps {\n /** The composed function registry. Built by the HOST, never by this package (D-09). */\n readonly registry: FunctionRegistry\n /**\n * WHO this server answers as. Minted by the composition root and passed through untouched to\n * `invokeFunction`. Since 432-20 (D-12) nothing here reads it to decide what to list or serve;\n * its `surface` and `origin` reach only the receipts that already consume them. Since 432-21 no\n * field of it is a credential this package reads.\n */\n readonly caller: FunctionCaller\n // 2026-10-14 (441-07, D-06): `maskText` is the host's declared-secret mask.\n /**\n * How text leaving this process is masked (threat T-396-01).\n *\n * REQUIRED, not optional, and the reason is a measured one rather than a preference: the defect\n * class this replaces (T-395-R5-10, closed in 395's final round) was a credential reaching an MCP\n * caller verbatim through an error serialization. An optional masker is absent exactly where\n * nobody thought to pass one, which is the same place the leak was found.\n */\n readonly maskText: (text: string) => string\n /**\n * Which dashboard this process is pointed at, for D-08's permanent link (408 plan 03).\n *\n * OPTIONAL, AND ITS ABSENCE IS THE DEGENERATE CASE RATHER THAN A SECOND BRANCH: a host that\n * supplies nothing and a supplier that answers `undefined` are the same fact — no dashboard is\n * configured and none is running here — and both take the same path to the same named-absence\n * line. There is no arm below that asks which of the two happened, deliberately: a distinction\n * nothing acts on is a distinction that eventually acquires a wrong action.\n *\n * A FACTORY, NOT A STRING, because on the co-hosted composition the bound origin does not exist\n * until a port has been bound — `commands/dashboard.ts` composes this host before it listens.\n */\n readonly liveLink?: LiveLinkSupplier\n}\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\ntype BoundInvoke = (opId: string, input: unknown) => Promise<unknown>\n\n/**\n * Join the mapping's declared contracts with this host's registry declarations.\n *\n * Returns `undefined` when any arm is missing from the registry — which is a REAL answer and not an\n * error: a projection naming an op a given composition does not register is a tool that composition\n * genuinely cannot serve, and refusing to build the whole server over it would take an editor's MCP\n * connection down because one capability was unavailable. A contract missing from the mapping table\n * IS an error, because that is this repository disagreeing with itself.\n */\nfunction resolveSpecs(\n projection: ToolProjection,\n declarations: ReadonlyMap<string, ProjectedOpSpec>,\n): readonly ProjectedOpSpec[] | undefined {\n const specs: ProjectedOpSpec[] = []\n for (const opId of projection.ops) {\n const resolved = declarations.get(opId)\n if (resolved === undefined) return undefined\n specs.push(resolved)\n }\n return specs\n}\n\n/**\n * Read a fold call's arm, refusing anything the tool does not declare (T-396-10).\n *\n * The SDK has already validated the arguments against the fold's discriminated union, so this\n * check is the SECOND reading of the same fact — kept for the reason every other double-check in\n * this layer is kept: the two readings have independent sources (the composed schema in\n * `@vostride/agent-qa-schema`, the op list in `mapping.ts`), so a disagreement between them is\n * exactly the drift worth refusing on rather than dispatching through.\n */\nfunction selectFoldArm(\n projection: ToolProjection,\n args: unknown,\n): { readonly opId: string; readonly input: Record<string, unknown> } {\n const key = projection.discriminant!\n const record = (args ?? {}) as Record<string, unknown>\n const selected = record[key]\n if (typeof selected !== 'string' || !projection.ops.includes(selected)) {\n throw new McpProjectionError(\n projection.name,\n `was called with ${key}=${JSON.stringify(selected)}, which is not one of the ops it declares`,\n )\n }\n // The discriminant is WIRE vocabulary and stops here: what crosses the function-layer wall is the\n // object `invokeFunction` will parse against the op's own `.strict()` contract, which would refuse\n // the extra key.\n const { [key]: _arm, ...input } = record\n return { opId: selected, input }\n}\n\n/** The one arm of an entity resolution that has something further to fetch (D-02). */\nfunction resolvedCardId(resolution: unknown): string | undefined {\n if (typeof resolution !== 'object' || resolution === null) return undefined\n const record = resolution as { kind?: unknown; card?: unknown }\n if (record.kind !== 'resolved') return undefined\n const card = record.card as { id?: unknown } | undefined\n return typeof card?.id === 'string' ? card.id : undefined\n}\n\n/**\n * Run one projected call and answer what the op answered, with the op that answered it.\n *\n * Every branch is `invokeFunction` and argument shuffling. Nothing computes a result, nothing reads\n * a store, nothing decides a policy.\n */\nasync function runProjection(\n projection: ToolProjection,\n args: unknown,\n invoke: BoundInvoke,\n): Promise<{ readonly opId: string; readonly output: unknown }> {\n switch (compositionOf(projection)) {\n case 'single':\n return { opId: projection.ops[0]!, output: await invoke(projection.ops[0]!, args) }\n case 'union': {\n const arm = selectFoldArm(projection, args)\n return { opId: arm.opId, output: await invoke(arm.opId, arm.input) }\n }\n case 'pipeline': {\n // D-02's one read door: resolve the reference the caller has, then — and only when the\n // resolver committed to ONE entity — re-read that entity at its canonical address. The second\n // read is the never-guess `entities.get`, so what a caller finally holds is the card an exact\n // address renders rather than the resolver's own rendering of a match.\n const resolution = await invoke(projection.ops[0]!, args)\n const id = resolvedCardId(resolution)\n if (id === undefined) return { opId: projection.ops[0]!, output: resolution }\n const card = await invoke(projection.ops[1]!, { ref: id })\n return { opId: projection.ops[1]!, output: { ...(resolution as Record<string, unknown>), card } }\n }\n }\n}\n\n/**\n * The concrete run this carrier's result is ABOUT, read from the source the projection declares.\n *\n * DEFENSIVE ON BOTH ARMS, and neither arm is hypothetical. `runIdFrom: 'input'` reads the args the\n * SDK already validated against the advertised input schema; `runIdFrom: 'output'` reads the op's\n * own result, which is a `RunStartAcknowledgement` today and could be a fold's arm tomorrow. Either\n * can answer with something that is not a string — and the honest treatment of that is the same as\n * the honest treatment of a missing dashboard: the LINE becomes the named absence and there is no\n * concrete App address to advertise. What it must never be is a crash, because that would turn a\n * decoration into a way to fail a tool call that had already succeeded.\n */\nfunction carrierRunIdOf(\n projection: ToolProjection,\n args: unknown,\n output: unknown,\n): string | undefined {\n const source = projection.ui?.runIdFrom === 'output' ? output : args\n const runId = (source as { runId?: unknown } | null | undefined)?.runId\n return typeof runId === 'string' && runId !== '' ? runId : undefined\n}\n\n/**\n * Add D-08's link-out line and D-05's concrete App address to a CARRIER's result.\n *\n * ADDITIVE, AND ONLY ADDITIVE. One `content` text part is appended and one `_meta` key is set; the\n * op's own answer — the masked serialization `structuredContent` and its text are both composed\n * from — is byte-identical to what it was. This is deliberately NOT a second serialization: a\n * result whose data channel was rebuilt beside its text channel is exactly the two-channel drift\n * `masked-result.ts` exists to prevent.\n *\n * THE LINE PASSES THROUGH `maskText`, on the house law that everything a surface prints does. It is\n * a no-op on a well-formed link and it is supposed to be: the dashboard base is `masked: false` by\n * the overlay law (a loopback origin this process minted is not the operator's secret), and the\n * page it names is tokenless by D-08. Masking it anyway costs nothing and means nobody has to\n * remember that this one printed string is exempt — which is how the 396-03 gap happened.\n *\n * `_meta.ui.resourceUri` ATTACHES UNCONDITIONALLY — it is not gated on negotiation. This is a\n * RECORDED DEVIATION FROM D-09's LETTER, which says the App reference attaches ONLY when the host\n * negotiated the Apps extension and explicitly rejected unconditional attachment. It is not an\n * oversight, and as of 2026-09-01 it is not the planner's or the executor's judgment either — see\n * the ruling line below. Two grounds were originally recorded; only the first survives:\n *\n * 1. `_meta` IS INERT (RESEARCH A2). A host that never negotiated `io.modelcontextprotocol/ui`\n * has no code that reads it, so what it receives is a key it ignores. Gating the\n * ADVERTISEMENT would buy nothing and cost the thing D-09 actually asks for — a host must be\n * able to SEE that an App exists in order to ask for it — and it would also contradict the\n * already-shipped tools/list `_meta.ui` TEMPLATE, which is advertised unconditionally too.\n * 2. SUPERSEDED 2026-09-01. The second ground read \"the ACTING channel is the `ui://` read, and\n * THAT is gated — by `negotiatedAppsExtension`\". The 408 gap round re-adjudicated that gate:\n * it reads a value the caller composes in its own per-request `_meta` and the SDK forwards\n * unauthenticated, so it is a host-capability signal and not an authorization control\n * (`app-resource.ts`'s header, THE 2026-09-01 GAP-ROUND RULING, road `demote`). The clause is\n * struck as a ground. What DOES bound the acting channel, and what this ground is replaced\n * by: the `ui://` read is reachable only in a composition where the mint is BOUND\n * (`bindingStatus === 'bound'`, D-03's floor), a fact this server verifies. (Until 432-20\n * it was also scope-gated by `visibleToCaller`; D-12 deletes that gate for every caller.)\n *\n * THE RULING, dated 2026-09-01 (408-08 task 1, question 2 — the USER'S answer at that plan's\n * checkpoint, `d09-retain`, quoted verbatim in `408-08-SUMMARY.md`). The deviation from D-09's\n * letter is RETAINED by that ruling, not by a better rationale: D-09 is a ratified user decision,\n * so its letter's fate was the user's to decide and was decided there. Three things this line\n * exists to keep visible. (i) The ORIGINAL justification rested in part on a gate the 2026-08-31\n * verification measured and the 2026-09-01 gap round re-adjudicated — that ground is falsified and\n * struck, above, rather than quietly reworded. (ii) The retention is the user's dated ruling.\n * (iii) RESEARCH A2 — that a host ignores unknown `_meta` keys gracefully — remains `[ASSUMED]`\n * and OPEN: no individual host has been measured choking on one, and UAT item 3 (the real-host\n * App-less leg) is the measurement that would settle it. The code is unchanged by this ruling:\n * `_meta.ui.resourceUri` still attaches whenever a run id is resolvable.\n *\n * A REFUSAL IS NOT DECORATED. `maskedToolError` results, and the withheld-result arm of\n * `maskedToolResult`, are left exactly as they are: a refusal is not a carrier of a watch\n * affordance, and appending \"watch live\" to a sentence explaining why nothing happened would be a\n * link to a run that was never started.\n */\nfunction decorateCarrierResult(input: {\n readonly result: CallToolResult\n readonly projection: ToolProjection\n readonly args: unknown\n readonly output: unknown\n readonly maskText: (text: string) => string\n readonly liveLink?: LiveLinkSupplier\n}): CallToolResult {\n if (input.projection.ui === undefined) return input.result\n if (input.result.isError === true) return input.result\n\n const runId = carrierRunIdOf(input.projection, input.args, input.output)\n const line = liveLinkLineFor(input.liveLink?.dashboardBaseUrl(), runId)\n\n return {\n ...input.result,\n content: [...input.result.content, { type: 'text' as const, text: input.maskText(line) }],\n ...(runId === undefined\n ? {}\n : { _meta: { ...input.result._meta, ui: { resourceUri: appResourceUriFor(runId) } } }),\n }\n}\n\n/**\n * The one generic tool handler.\n *\n * Input validation happened twice before the invoke — once by the SDK against the tool's input\n * contract, once inside `invokeFunction` against the op's own — and both parses are kept, because\n * they are the same check made by two independent parties.\n */\nfunction createProjectionHandler(\n projection: ToolProjection,\n invoke: BoundInvoke,\n maskText: (text: string) => string,\n liveLink?: LiveLinkSupplier,\n) {\n return async (args: unknown): Promise<CallToolResult> => {\n try {\n const { opId, output } = await runProjection(projection, args, invoke)\n // BOTH channels from ONE masked serialization (396-06). `structuredContent` used to be the\n // raw op output, and a declared credential reached the wire through it verbatim while the\n // text beside it read `<SECRET_0>` — RESEARCH Pitfall 9's own named channel, measured.\n const masked = maskedToolResult(output, maskText)\n // 431-05 D-07: the image block is decided AFTER masking, from bytes the masked value still\n // carries unchanged. Deciding it from the raw output would put bytes beside a withheld result.\n const result = opId === RUNS_ARTIFACT_FUNCTION_ID\n ? decorateRunEvidenceImage({ result: masked, output, maskText })\n : masked\n // 408 D-05/D-08/D-09: the watch affordance, on every carrier result, for every host class.\n return decorateCarrierResult({\n result,\n projection,\n args,\n output,\n maskText,\n ...(liveLink === undefined ? {} : { liveLink }),\n })\n } catch (err) {\n // A refusal is a RESULT, not a transport failure: the caller gets the reason as a tool\n // error it can read. The message is masked for the reason the whole file exists — an\n // error string is the channel 395's credential disclosure actually travelled down.\n return maskedToolError(err, maskText)\n }\n }\n}\n\n// ---------------------------------------------------------------------------------------------\n// The retired-v1-name redirect (Phase 398 plan 05, D-15 · XPLN-03)\n// ---------------------------------------------------------------------------------------------\n//\n// WHAT THIS IS. `migration-map.ts` holds thirty-three rulings about names this surface no longer\n// serves. An external agent still pinned to one of them gets the ruling instead of a bare\n// unknown-tool error — and gets it as an ERROR, always. Nothing below invokes anything, forwards\n// anything, or registers anything: a v1 name that became a listed alias would be the v1 surface\n// resurrected with a mismatched input shape, which is the door D-15 refuses to reopen.\n//\n// WHY IT LIVES HERE AND NOT IN `http.ts`. Both hosts reach this one factory — `serveStdio` wraps it\n// on stdio and `createMcpHandler` wraps it on loopback HTTP — so a redirect installed on either\n// transport would answer on one and not the other. SEP-2567's per-request factory model is also\n// what makes the answer per-CALLER: the wrapper below closes over `registered`, the set this\n// instance built for THIS caller, and never over connection state.\n//\n// WHY IT WRAPS THE DISPATCH EDGE (measured 2026-08-17, recorded in `__tests__/redirect.test.ts`).\n// A name nobody registered never reaches code this package wrote: `McpServer` installs its own\n// `tools/call` handler, looks the name up in its registered-tool table, and throws `InvalidParams`\n// on a miss. There is no fall-through to hook and no unknown-tool callback in the SDK's surface, so\n// the only seam that can answer a name with NO handler is that installed handler itself. It is\n// wrapped rather than replaced, and the wrapper's non-member branch is a bare call to the SDK's own\n// function with the arguments it was given — which is what makes \"answers exactly as today\" a\n// structural fact rather than a string this package keeps in step by hand.\n\n/** The JSON-RPC method the wrapper owns. Named once. */\nconst TOOLS_CALL_METHOD = 'tools/call'\n\n/**\n * The narrow shape of the SDK's low-level handler table.\n *\n * Reaching for it is the one liberty this module takes with its dependency, and it is taken with\n * eyes open: `removeRequestHandler` is public API, `setRequestHandler` is public API, and the only\n * unpublished thing is READING BACK the handler already installed so it can be delegated to.\n * The alternative — writing a `tools/call` handler that dispatches registered tools itself — is a\n * second dispatch path through the SDK's private validation, execution and wire-projection steps,\n * which is a far larger bet than one map lookup.\n */\ninterface LowLevelDispatch {\n readonly _requestHandlers?: Map<string, (request: unknown, ctx: unknown) => Promise<unknown>>\n removeRequestHandler(method: string): void\n setRequestHandler(method: string, handler: (request: unknown, ctx: unknown) => unknown): void\n}\n\n/** The tool name a `tools/call` carries, or `undefined` when the request is not shaped like one. */\nfunction callToolName(request: unknown): string | undefined {\n if (typeof request !== 'object' || request === null) return undefined\n const params = (request as { params?: unknown }).params\n if (typeof params !== 'object' || params === null) return undefined\n const name = (params as { name?: unknown }).name\n return typeof name === 'string' ? name : undefined\n}\n\n/**\n * The map entry for an EXACT wire name, or `undefined`.\n *\n * `===` on the string the caller sent, with no normalisation of any kind. Membership is byte\n * equality because the retired set is a set of NAMES: a case-variant is a name nobody ever served,\n * and answering it with a retirement notice would widen the distinguishable set from \"the closed\n * v1 list\" to \"anything that case-folds onto it\" — a strictly larger oracle for nothing gained.\n */\nfunction v1MigrationEntryFor(toolName: string): V1ToolMigrationEntry | undefined {\n return V1_TOOL_MIGRATION_MAP.find((entry) => entry.v1Name === toolName)\n}\n\n/**\n * The redirect's whole decision: which entry, if any, answers this name on this instance.\n *\n * A LIVE HANDLER ALWAYS WINS. The migration map and the live tool vocabulary are disjoint — asserted\n * by name in `__tests__/mapping-bump-guard.test.ts` — and this ordering is what makes that\n * assertion's failure harmless instead of catastrophic: the worst a bad map entry could do is fail\n * to redirect, never shadow a tool a caller can actually call.\n *\n * It is a separate exported function for one reason. Inside the wrapper the ordering is\n * observationally inert while disjointness holds, so no cell driving the server could tell it from\n * its own absence — a guard nothing can red is decoration (measured: mutation leg M9 reds nothing\n * through the server). Pulled out here it takes a `registered` set a cell can doctor, and the\n * ordering becomes a claim with a bar.\n */\nexport function v1RedirectFor(\n toolName: string,\n registered: ReadonlySet<string>,\n): V1ToolMigrationEntry | undefined {\n if (registered.has(toolName)) return undefined\n return v1MigrationEntryFor(toolName)\n}\n\n/**\n * One line about how the v2 tool is called, DERIVED from its declared composition.\n *\n * Not a hand-written sentence per tool: the thing a v1 caller actually gets wrong is the SHAPE, and\n * the shape is exactly what `compositionOf` already reads off the mapping. A fold's line names its\n * discriminant and every arm, because \"which arm\" is the field v1's one-tool-per-verb vocabulary\n * has no equivalent for.\n */\nfunction v1InputShapeNote(projection: ToolProjection): string {\n switch (compositionOf(projection)) {\n case 'single':\n return 'it takes one input object'\n case 'union':\n return `set \\`${projection.discriminant!}\\` to one of ${projection.ops\n .map((op) => `\\`${op}\\``)\n .join(', ')} and pass that arm's own fields`\n case 'pipeline':\n return 'it takes one entity reference and answers the card that reference resolves to'\n }\n}\n\n/**\n * What a caller who named a retired v1 tool is told.\n *\n * THE WITHHOLDING IS IN THE SIGNATURE, not in a branch inside the text. `visibleTarget` is passed\n * ONLY when the caller may see that tool, so the sighted sentence cannot be written without it and\n * the unsighted branch has no tool name in scope to leak. A conditional on a boolean would have put\n * the name in scope on both sides, which is how the wrong branch ends up carrying it.\n *\n * The `retired` and `pending` arms take no caller-dependent input at all — they read the entry and\n * nothing else — so their bytes are the same for every caller by construction rather than by a\n * cell's permission (T-398-13).\n */\nexport function v1RedirectMessage(\n entry: V1ToolMigrationEntry,\n visibleTarget?: ToolProjection,\n): string {\n const opening = `\\`${entry.v1Name}\\` is a retired agent-qa v1 tool name and is not served.`\n\n if (entry.arm === 'renamed-to') {\n if (visibleTarget === undefined) {\n // The retirement notice. It names no tool, because the caller cannot see the one that\n // carries this capability and a name they cannot call is a grant hint, not help (D-08).\n return (\n `${opening} Call \\`tools/list\\` for the tools you may call on this server, and `\n + `\\`agent-qa init --agent\\` for this workspace's capability manifest, which carries the `\n + 'v1 tool-name migration map.'\n )\n }\n return (\n `${opening} The capability it named is now \\`${visibleTarget.name}\\`. ${entry.note} `\n + `Its input shape is not v1's — ${v1InputShapeNote(visibleTarget)}; \\`tools/list\\` `\n + 'advertises the contract the call is validated against.'\n )\n }\n\n if (entry.arm === 'pending') {\n const owned\n = entry.owner === undefined\n ? ''\n : ` The capability it named is a known gap owned by ${entry.owner}.`\n const until = entry.route === undefined ? '' : ` Until then: ${entry.route}`\n return `${opening}${owned} ${entry.note}${until}`\n }\n\n return `${opening} ${entry.note}${entry.route === undefined ? '' : ` Instead: ${entry.route}`}`\n}\n\n/** What the redirect needs to know about the instance it is being installed on. */\ninterface V1RedirectDeps {\n /**\n * The tool names registered on THIS instance — i.e. exactly what `tools/list` answers.\n *\n * Consulting the recorded set rather than recomputing it is deliberate: \"named by the redirect\"\n * and \"listed by `tools/list`\" are the SAME fact rather than two computations that agree today.\n * Since 432-20 (D-12) the only reason a tool is absent is an op this composition does not\n * register, and naming a tool this host cannot serve would be a worse answer than saying nothing.\n */\n readonly registered: ReadonlySet<string>\n readonly maskText: (text: string) => string\n}\n\n/**\n * Wrap the installed `tools/call` handler so exact v1 names are answered and nothing else changes.\n *\n * TWO OUTCOMES AND NOTHING ELSE.\n * * `v1RedirectFor` answers `undefined` — for a live tool, for a non-member, for a request that is\n * not shaped like a `tools/call` — and the SDK's own function is called with the arguments it\n * was given, and its answer returned unchanged. Byte identity is not maintained on this path;\n * it is impossible to lose on it.\n * * It answers an entry, and the entry is THROWN as the same `InvalidParams` class the SDK throws\n * for a name nobody serves, so the sole thing distinguishing a retired name from an unknown one\n * is the sentence — which is history, not a grant. Throwing before any dispatch is also what\n * makes \"never invokes anything\" structural (T-398-12).\n */\nfunction installV1NameRedirect(server: McpServer, deps: V1RedirectDeps): void {\n const dispatch = server.server as unknown as LowLevelDispatch\n const sdkHandler = dispatch._requestHandlers?.get(TOOLS_CALL_METHOD)\n if (typeof sdkHandler !== 'function') {\n // Fail loudly rather than ship a server whose redirect silently is not there. This is the same\n // class as the other throws in this file — the package's belief about its own dependency turned\n // out to be false — and it surfaces at the first build, which is where an SDK upgrade should\n // meet it rather than in a caller's error log months later.\n throw new McpProjectionError(\n TOOLS_CALL_METHOD,\n 'has no installed request handler to wrap; the SDK no longer registers tool dispatch where '\n + 'this package reads it, so the retired-v1-name redirect cannot be placed',\n )\n }\n\n dispatch.removeRequestHandler(TOOLS_CALL_METHOD)\n dispatch.setRequestHandler(TOOLS_CALL_METHOD, (request: unknown, ctx: unknown) => {\n const name = callToolName(request)\n // 432-20 (D-12): no tool is hidden from a caller any more, so there is no hidden-tool refusal\n // to answer here. The mark tool is registered for every caller and its own handler answers.\n const entry = name === undefined ? undefined : v1RedirectFor(name, deps.registered)\n if (entry === undefined) return sdkHandler(request, ctx)\n\n const target\n = entry.arm === 'renamed-to' && entry.v2Tool !== undefined && deps.registered.has(entry.v2Tool)\n ? AGENT_QA_TOOL_PROJECTIONS.find((projection) => projection.name === entry.v2Tool)\n : undefined\n\n // Masked for the reason every other string this package emits is masked: the exemption list is\n // the thing that goes wrong, not the mask. The text is declared data, so this is a no-op today\n // and stays one only because nobody has to remember that it is.\n throw new ProtocolError(\n ProtocolErrorCode.InvalidParams,\n deps.maskText(v1RedirectMessage(entry, target)),\n )\n })\n}\n\n/**\n * Build the server this caller sees.\n *\n * The listing is read through `registry.list(deps.caller)` — the registry's own view of itself for\n * this host — so `summary` and `risk` describe the composition in front of the caller rather than a\n * table in this package that could describe a different one. The view is the same for every caller\n * (432-20, D-12).\n */\nexport function buildAgentQaMcpServer(deps: AgentQaMcpServerDeps): McpServer {\n const server = new McpServer(\n { name: 'agent-qa', version: AGENT_QA_MCP_SERVER_VERSION },\n {\n capabilities: {\n tools: {},\n resources: {},\n // 408 D-04: the official MCP Apps extension, ADVERTISED rather than assumed. Extensions are\n // bilateral opt-in — a client declares support in the `io.modelcontextprotocol/\n // clientCapabilities` envelope it sends on every request, and reads the server's set back\n // from discovery — so a server that renders App HTML without naming the extension here is\n // one no host will ever ask for it. The value is an empty record because this extension\n // carries no server-side options; what it says is that this endpoint speaks it at all.\n extensions: { [MCP_APPS_EXTENSION_ID]: {} },\n },\n // 433-33 (G-433-9): init's pointer, on the one channel every MCP host receives.\n instructions: AGENT_QA_MCP_INSTRUCTIONS,\n },\n )\n\n const invoke: BoundInvoke = (opId, input) =>\n invokeFunction(deps.registry, opId, input, deps.caller)\n\n const declarations = new Map<string, ProjectedOpSpec>()\n for (const declaration of deps.registry.list(deps.caller)) {\n const contracts = AGENT_QA_OP_CONTRACTS[declaration.id]\n if (contracts === undefined) continue\n declarations.set(declaration.id, {\n id: declaration.id,\n summary: declaration.summary,\n risk: declaration.risk,\n input: contracts.input,\n output: contracts.output,\n })\n }\n\n const registered = new Set<string>()\n for (const projection of AGENT_QA_TOOL_PROJECTIONS) {\n if (registered.has(projection.name)) {\n // Unreachable while the mapping table holds distinct names, and asserted anyway: a silent\n // last-wins here would drop a capability from every caller's vocabulary and leave the bump\n // guard comparing two sets that both lost the same member.\n throw new McpProjectionError(\n projection.name,\n 'is declared twice in the mapping table; another projection already occupies that name',\n )\n }\n\n for (const opId of projection.ops) {\n if (AGENT_QA_OP_CONTRACTS[opId] === undefined) {\n throw new McpProjectionError(\n projection.name,\n `names op ${opId}, which has no entry in the contract table`,\n )\n }\n }\n\n const advertised = advertisedContracts(projection)\n if (advertised === undefined) {\n throw new McpProjectionError(\n projection.name,\n 'has no advertised contract; a multi-arm tool needs an entry in AGENT_QA_COMPOSED_CONTRACTS',\n )\n }\n\n const specs = resolveSpecs(projection, declarations)\n if (specs === undefined) continue\n\n registered.add(projection.name)\n const config = toRegisterToolConfig(projection, specs, advertised, deps.maskText)\n\n // 2026-10-01 (432-21, D-12): every tool, the mark door included, goes through the one generic\n // handler. The mark door's credential refusal left with the MCP bearer credential, so a mark\n // answers its receipt on the one call like every other change tool (432-12 D-05/D-14).\n server.registerTool(\n projection.name,\n config,\n createProjectionHandler(projection, invoke, deps.maskText, deps.liveLink),\n )\n }\n\n // D-15: the retired v1 names, answered at the dispatch edge with `registered` — the set the loop\n // above just built — as the authority on what may be named.\n installV1NameRedirect(server, { registered, maskText: deps.maskText })\n\n // D-13: the six entity Resource Templates, resolving through the SAME wall. Registered here rather than by the host so a `resource_link` in any tool result\n // above is dereferenceable on the instance that produced it.\n registerEntityResources(server, {\n registry: deps.registry,\n caller: deps.caller,\n maskText: deps.maskText,\n })\n\n // 408 D-01/D-02/D-04: the App template for a live run, registered HERE for the reason the entity\n // templates are — a `_meta.ui.resourceUri` on any carrier tool above is only a decoration unless\n // it is dereferenceable on the very instance that advertised it. It crosses the SAME wall and\n // registers NOTHING on a composition that cannot honestly mint (D-03's floor), so a host without\n // a live view is told by structural absence rather than by a read that always fails.\n registerAppResources(server, {\n registry: deps.registry,\n caller: deps.caller,\n maskText: deps.maskText,\n // 408 plan 03 (D-08): the SAME supplier the carrier decoration reads, so the anchor inside the\n // App document and the line beside a tool result name one page for one run.\n ...(deps.liveLink === undefined ? {} : { liveLink: deps.liveLink }),\n })\n\n return server\n}\n","// The MCP App resource surface — `ui://agent-qa/live-run/{runId}` (408 plan 01, D-01..D-07 · MCPA-01).\n//\n// WHY THIS FILE EXISTS. 403 made a run watchable at a `liveUrl`; a host that negotiated the official\n// MCP Apps extension (`io.modelcontextprotocol/ui`) renders server-delivered HTML in a sandboxed\n// iframe. This module is the join: one resource template whose read mints a `liveUrl` per member\n// handle and serves the wrapper page that iframes them. Everything it registers, resolves and\n// refuses follows `resources.ts` — the ratified template for a non-tool MCP surface in this package\n// — because a second registration idiom would be a second set of rules for the same three\n// questions (who may see it, what parses the address, what masks the answer).\n//\n// THE MINT CHANNEL IS THE WHOLE SECURITY ARGUMENT (D-01, T-408-01). `runs.liveurl` stays\n// UNPROJECTED as a callable tool: a projected mint tool would put a live credential into\n// model-readable tool-result text, which is the exact shape of T-395-R5-10, and masking it would\n// make the tool useless. Instead the mint happens HERE, by reference, inside the App-rendering\n// path. WHAT THAT BUYS, AT ITS REAL VALUE (corrected 2026-09-01, 408 gap round — see THE\n// 2026-09-01 GAP-ROUND RULING below): this server writes the token into exactly ONE place, the\n// `src` of the frame in the document this read serves, and what a caller does with a document it\n// asked for is outside this server's reach. The earlier sentence here — \"the token lands only in\n// the HTML the HOST renders\" — described a property of the CALLER as though it were a property of\n// this server, and it is WITHDRAWN rather than deleted. The structural property that DOES hold is\n// the one `token-absence.test.ts` measures: no OTHER channel this server emits — tool-result text,\n// `structuredContent`, a refusal echo, a resource listing, a log line — carries the token.\n//\n// AND THAT IS WHY THIS SURFACE DOES NOT MASK ITS SERVED PAYLOAD — the one deliberate divergence\n// from `resources.ts`, which masks its contents for a measured reason (a card composed from STORED\n// data through a handler nothing else masks). This document is composed from data MINTED one\n// millisecond earlier for this exact response, and the token is the payload: a masked token is a\n// broken embed, so masking here would not be safety, it would be the failure mode. The refusal\n// path masks exactly as `resources.ts`'s does, because a refusal echoes CALLER text and that is a\n// different channel with the opposite answer. The split is by channel, and it is pinned by cells\n// rather than by this paragraph.\n//\n// THE `ui://` READ CHANNEL — the full ruling (408 plan 02, adjudicated 2026-08-31; RESEARCH\n// Open Question 2 / Pitfall 2; D-01, D-09, D-14). This is the disposition D-14 requires RECORDED\n// rather than left silent, and all four clauses are load-bearing:\n//\n// 1. THE TOKEN CHANNEL IS HOST-RENDERED HTML (D-01). A minted `liveUrl` reaches a person only\n// inside the document a host paints in its sandbox. It is never tool-result text, never a\n// refusal echo, and never a listing.\n// SUPERSEDED IN PART, 2026-09-01: the WRITE half stands and the REACH half does not. What\n// stands, exactly as written: this server writes the token into one place and one place only,\n// the `src` of the frame in the document this read serves — never tool-result text, never a\n// refusal echo, never a listing, and `token-absence.test.ts` is the standing measurement of\n// that. What is WITHDRAWN is \"reaches a person only inside the document a host paints\":\n// whether the bytes this server serves are painted in a sandbox or consumed some other way is\n// a property of the CALLER and of what it does with a document it asked for, so that half\n// described the wrong party — the same over-claim :15-22 above already withdrew by name. See\n// THE 2026-09-01 GAP-ROUND RULING below, which names what the negotiation check is and what\n// it is for. Retained here rather than rewritten, because an adjudication in this repository\n// is re-grounded on the record, never edited away.\n// 2. THE TEMPLATE IS UNLISTED. `{ list: undefined }` means the address never appears in a\n// `resources/list`, so no model-driven enumeration can walk to a minted token by discovery.\n// 3. A NON-NEGOTIATED READ IS REFUSED, BEFORE ANYTHING IS MINTED. Unlistability alone only\n// closes discovery: a caller that already knows a run id could still read the address and\n// receive token bytes, which is T-408-01 and the posture D-09 explicitly rejected as sole\n// protection. So the read now asks the request itself whether it declared\n// `io.modelcontextprotocol/ui` in its capabilities (`negotiatedAppsExtension`, measured —\n// see below) and throws\n// `AppResourceNegotiationError` if it did not. The refusal happens BEFORE the roster read\n// and before the mint loop, so a refused read mints nothing at all: there is no token in\n// existence on that path to leak, rather than a token that something remembered to withhold.\n// SUPERSEDED IN PART, 2026-09-01: the PREDICATE and the refusal arm stand exactly as written;\n// the SECURITY reading of this clause does not. See THE 2026-09-01 GAP-ROUND RULING below,\n// which names what the check is and what it is for. Retained here rather than rewritten,\n// because an adjudication in this repository is re-grounded on the record, never edited away.\n// 4. THE CREDENTIAL STAYS SHORT-LIVED AND VIEW-SCOPED. 403's `LIVE_URL_TTL_MS` is five minutes\n// and the token authorises watching pixels this caller can already read — so even the\n// negotiated channel hands out the narrowest thing that can render a live view (re-spelled\n// 2026-10-02, 432-42: no caller holds a `read` scope since 432-20).\n// 5. THE AUTHORIZATION BOUNDARY IS THE OPERATOR-GRANTED `read` SCOPE, CHECKED AT REGISTRATION\n// (added 2026-09-01, 408 gap round; D-02). This clause names what THIS SERVER CAN VERIFY, as\n// distinct from anything a caller says about itself. `registerAppResources` registers the\n// template only when all three of its conditions hold, and two of them ARE the boundary:\n// `visibleToCaller(mint.requiredScopes, caller.grantedScopes)` — and the same call for the\n// roster op — over the scopes the REGISTRY declares for the ops this surface reads through,\n// plus `mint.bindingStatus === 'bound'`. The scopes a caller holds are OPERATOR\n// CONFIGURATION: the `read` scope an operator wrote into that credential's entry in\n// `services.mcp.tokens`, or the unconditional grant the spawning process gets on stdio. This\n// server authenticates the bearer that carries them, so that is a fact it verifies rather\n// than a fact it is told. D-02 is the ratified decision that put the boundary there — \"The\n// App rides the existing `read` scope… no new scope in the token vocabulary\" — and a\n// composition failing any condition registers no template at all, so for such a caller this\n// address does not exist. Clause 3's check is a filter ON TOP of this; it is not this.\n// SUPERSEDED, 2026-10-01 (432-20, D-12/D-13): the scope half is deleted with every per-caller\n// permission — \"every door can call every operation\" — so the template registers for every\n// caller of a composition whose mint is bound. What bounds the credential now is what D-13\n// keeps: the loopback-only endpoint, its Host/Origin guards, the bound-mint floor, the\n// five-minute view-scoped token and the unlisted address. Retained here rather than\n// rewritten, on this file's own rule.\n//\n// THE 2026-09-01 GAP-ROUND RULING — ROAD `demote` (408-08 task 1: the user's checkpoint answer,\n// quoted verbatim in `408-08-SUMMARY.md`). `408-VERIFICATION.md` gaps[2] and `408-REVIEW.md` CR-01\n// measured clause 3 against the shipped SDK and found its SECURITY reading false. Three findings,\n// in this file's \"measured, not assumed\" idiom:\n//\n// (a) THE CHECK IS A HOST-CAPABILITY SIGNAL, NOT AN AUTHORIZATION CONTROL. On the modern\n// (2026-07-28) era the SDK's `_inputRequestCapabilityView` returns\n// `ctx.mcpReq.envelope?.[CLIENT_CAPABILITIES_META_KEY]` VERBATIM, and the 2026 codec's\n// `checkInboundEnvelope` validates that member's SHAPE and nothing else (the 2025 codec's\n// is `(_material) => void 0`). Measured 2026-08-31 by the phase verifier against the same\n// shipped `@modelcontextprotocol/server` this package builds on. The value\n// `negotiatedAppsExtension` reads is therefore composed by the CALLER in its own\n// per-request `_meta` and forwarded unauthenticated. This phase's own POSITIVE cell is the\n// proof: the \"negotiating client\" in `app-negotiation.test.ts` is a stock SDK client with\n// one declared capability member and nothing App-shaped about it, and it receives freshly\n// minted liveUrl tokens in its own JSON-RPC response body.\n// (b) WHAT IT THEREFORE DOES BUY, and it is not nothing. A host that cannot render an App does\n// not receive a document it would paint as text — an omitting caller is turned away above\n// the roster read and above the mint loop, so nothing is minted on that path. And a\n// 2025-era caller cannot obtain this App at all, because there is no per-request\n// capabilities channel outside the modern era (408-02 D-G). Both are real, and both are\n// statements about CAPABILITY.\n// (c) WHAT IT DOES NOT BUY. It does not distinguish an Apps host from any other caller that\n// adds one `_meta` member to a `resources/read`. It separates cooperative clients from\n// omitting ones — never Apps hosts from model-driven callers.\n//\n// T-408-01, RE-ADJUDICATED 2026-09-01 — DISPOSITION: `accept`. It was `mitigate`, and 408-02\n// reported it closed; that verdict is withdrawn here. The residual, stated plainly: a caller the\n// operator granted `read` can obtain a live-view credential through this door. BOTH halves of the\n// argument are recorded, because an acceptance that keeps only the comfortable half is the same\n// over-claim in a new coat.\n// ACCEPTING REASONING (D-02's own, restated). Watching a run IS a read. Per-step decision\n// screenshots of the same browser already cross the read path as DURABLE artifacts, so live\n// frames expose the same pixels sooner rather than a new class of thing; the credential is\n// view-scoped and expires in five minutes (`LIVE_URL_TTL_MS`); and D-02 rejected a dedicated\n// live-view scope as \"config friction guarding a channel `read` already exposes\". Nothing this\n// gap round measured answers that rejection — it found the CLAIM wrong, not the boundary.\n// COUNTER-ARGUMENT (408-REVIEW.md CR-01, recorded rather than buried). The credential is NOT\n// strictly scope-equivalent to what a `read` caller already holds: no projected tool yields a\n// live pixel stream of a running browser, and the minted URL works from any browser on the\n// machine for its full five-minute TTL. That is a capability, not merely an artifact arriving\n// sooner, and the acceptance is made in full sight of it.\n// The negative cell the verification asks for — a caller that merely DECLARES, asserting the\n// policy intended rather than the one the gate happens to enforce — is 408-12's subject, and it\n// cites this ruling.\n//\n// THE NEGOTIATION EVIDENCE IS MEASURED, NOT ASSUMED (RESEARCH Open Question 1 / assumption A3).\n// The envelope member spelling below was measured on 2026-08-31 against a real\n// `@modelcontextprotocol/client@2.0.0` over the shipped node handler — the living record is\n// `src/__tests__/app-negotiation.test.ts`, which drives the wire and would red if the SDK moved\n// it. The measurement also produced a fact worth stating plainly, because it decides who can see\n// this App at all: the per-request capabilities envelope exists ONLY on the modern (2026-07-28)\n// wire era. A client that connects with the SDK's default legacy `initialize` handshake sends no\n// per-request capabilities, and a stateless per-request server instance never saw that handshake,\n// so `getClientCapabilities()` holds nothing there either (the SDK says so itself: \"per-request\n// instances that never saw an initialize (stateless legacy) hold nothing, so gates refuse there\").\n// This gate therefore fails CLOSED for a 2025-era caller — no evidence of negotiation, no App —\n// which is exactly what D-09 asks for: the App attaches only where the extension was negotiated,\n// and every other host is served by the link-out that rides every carrier result.\n//\n// ONE CODEC, NO SECOND PARSER (T-396-08 / T-408-02). `parseAppUri` is the only thing in this\n// package that reads a `ui://` address, and it defers the run-id question to the MINT OP'S OWN\n// input contract rather than re-deriving path safety here. A local regex over the id would be a\n// second, weaker reading of a string that names a directory.\n//\n// Protocol grounding. SEP-1730 puts extensions OUTSIDE every conformance tier — a host owes an\n// extension nothing, which is exactly why the link-out rides every carrier result and why an App\n// that never renders costs a caller no capability. SEP-2575 (the stateless protocol) is why the\n// mint happens on the READ rather than once at registration: there is no session to hold a token\n// in, so freshness is the cheap path rather than a feature. SEP-2567 removed per-connection\n// variance from list endpoints, which is the other half of `{ list: undefined }` below — this\n// template's absence from listings is a property of the SERVER, identical for every caller (no\n// caller holds scopes since 432-20, D-12), and not a capability-conditional listing smuggled in\n// through a resolver.\n// SEP-2549's cache hints are declined for the same reason the mint is per-read: a cacheable App\n// document would be a cacheable credential.\n\nimport { CLIENT_CAPABILITIES_META_KEY, ResourceTemplate } from '@modelcontextprotocol/server'\nimport type {\n ClientCapabilities,\n ReadResourceResult,\n ReadResourceTemplateCallback,\n RequestMetaEnvelope,\n ResourceMetadata,\n ServerContext,\n Variables,\n} from '@modelcontextprotocol/server'\nimport {\n invokeFunction,\n FunctionNotBoundError,\n LiveViewUnavailableError,\n RUNS_EVENTS_FUNCTION_ID,\n RUNS_LIVE_URL_FUNCTION_ID,\n UnknownRunError,\n} from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport { handleRosterOf, RunsLiveUrlInputSchema } from '@vostride/agent-qa-schema'\nimport type {\n FunctionCaller,\n RunEventEnvelope,\n RunsLiveUrlResult,\n} from '@vostride/agent-qa-schema'\n\nimport { renderAppWrapperPage } from './app-wrapper.js'\nimport type { AppWrapperMint } from './app-wrapper.js'\nimport { liveRunLinkOf } from './live-link.js'\nimport type { LiveLinkSupplier } from './live-link.js'\n\n/**\n * The official MCP Apps extension id (spec revision 2026-01-26).\n *\n * RESTATED LOCALLY RATHER THAN IMPORTED, and the reason is a measured peer conflict:\n * `@modelcontextprotocol/ext-apps` declares `peerDependencies: { '@modelcontextprotocol/sdk':\n * '^1.29.0' }` — the v1 monolith — while this package ships the 2.0.0 split SDK, so importing its\n * `/server` entry would drag a second SDK generation into production (Pitfall 3). The string is\n * therefore ours, and Plan 06's census pins it against ext-apps' shipped schema so a typo'd\n * reverse-DNS id cannot fail silently as \"never negotiated\".\n */\nexport const MCP_APPS_EXTENSION_ID = 'io.modelcontextprotocol/ui'\n\n/** The media type an App resource is served as. Restated locally for the reason above. */\nexport const APP_RESOURCE_MIME_TYPE = 'text/html;profile=mcp-app'\n\n/** The published App address. ONE template, per run — the runId is the only variable. */\nexport const APP_RESOURCE_URI_TEMPLATE = 'ui://agent-qa/live-run/{runId}'\n\n/**\n * The template EXPANDED for one concrete run (408 plan 03, D-05).\n *\n * WHY THIS IS A FUNCTION AND NOT A STRING EACH CALLER COMPOSES. `projection.ts` advertises the\n * TEMPLATE on a carrier tool's `_meta`, and a carrier RESULT advertises the concrete address of the\n * run it just named — two spellings of one address, in two files, that would be free to disagree\n * about the scheme, the namespace or the segment order. Expanding through the template constant\n * makes drift impossible: there is one place the address is written down and one rule for filling\n * it in.\n *\n * ENCODED WITH `encodeURIComponent`, which is the exact inverse of the `decodeURIComponent` the one\n * codec above applies — so `parseAppUri(appResourceUriFor(id)).runId === id` for every id, and an\n * address this package composes is one this package can read back.\n */\nexport function appResourceUriFor(runId: string): string {\n return APP_RESOURCE_URI_TEMPLATE.replace('{runId}', encodeURIComponent(runId))\n}\n\n/** The registered resource name. Prefixed like the tools, so one namespace reads as one server. */\nexport const APP_RESOURCE_NAME = 'agent_qa_live_run_app'\n\nconst APP_RESOURCE_TITLE = 'agent-qa live run'\n\n// Authored prose about the SURFACE, not about any run — the same class of string as a tool's\n// curated title, so it is not masked. Nothing interpolated here comes from a caller or from storage.\nconst APP_RESOURCE_DESCRIPTION =\n 'The live view for one run, as an MCP App: a sandboxed page embedding the run\\'s live preview '\n + 'for each member handle. Rendered fresh on every read.'\n\n/** The `ui://` scheme and the two fixed path segments, spelled once for the one codec below. */\nconst APP_URI_PREFIX = 'ui://agent-qa/live-run/'\n\n/**\n * The ONE parser of a `ui://` app address.\n *\n * TOTAL AND UNDECORATED: it answers the run id or `undefined`, and it never explains which clause\n * refused — the caller-facing sentence is the read handler's, phrased once.\n *\n * THE RUN ID IS JUDGED BY THE MINT OP'S OWN INPUT CONTRACT, not by a pattern this file invented.\n * `RunsLiveUrlInputSchema` carries `runIdSchema` — the codec that decides whether a string may name\n * this run's own directory, so an address carrying `..`, a path separator or a control character is\n * refused here by exactly the rule that refuses it everywhere else. Stated the other way round,\n * which is the honest reading: an app address is well-formed precisely when the op this read mints\n * through would accept the run it names, so the two can never disagree about one string.\n */\nexport function parseAppUri(href: string): { readonly runId: string } | undefined {\n if (!href.startsWith(APP_URI_PREFIX)) return undefined\n const tail = href.slice(APP_URI_PREFIX.length)\n if (tail === '') return undefined\n let decoded: string\n try {\n decoded = decodeURIComponent(tail)\n } catch {\n return undefined\n }\n const parsed = RunsLiveUrlInputSchema.safeParse({ runId: decoded })\n if (!parsed.success) return undefined\n return { runId: parsed.data.runId }\n}\n\n/**\n * The envelope member carrying the request's declared client capabilities.\n *\n * MEASURED, NOT GUESSED, and re-exported from the SDK rather than restated as a literal so a\n * spelling drift is a compile error instead of a gate that silently answers \"never negotiated\".\n * The measurement (2026-08-31, `src/__tests__/app-negotiation.test.ts`) drove a real\n * `@modelcontextprotocol/client@2.0.0` against `createAgentQaMcpNodeHandler` over a loopback\n * socket and read the resource-read context back out of the handler:\n *\n * ctx.mcpReq.envelope['io.modelcontextprotocol/clientCapabilities'].extensions['io.modelcontextprotocol/ui']\n *\n * That cell is the living record — it asserts the path against the wire, so an SDK that moves the\n * member reds it rather than quietly turning this gate into a blanket refusal.\n */\nexport const APP_NEGOTIATION_CLIENT_CAPABILITIES_KEY = CLIENT_CAPABILITIES_META_KEY\n\n/**\n * The ONE member of the SDK's read context this module reads.\n *\n * Declared structurally rather than as `Pick<ServerContext, 'mcpReq'>` for a reason a cell feels\n * immediately: the SDK's context carries a dozen live functions, and a predicate whose input\n * cannot be written down without them is a predicate only the wire can test. `ServerContext` is\n * assignable to this, so the production call site still hands over the SDK's own object untouched.\n */\nexport interface AppReadContext {\n readonly mcpReq?: { readonly envelope?: Partial<RequestMetaEnvelope> }\n}\n\n/**\n * Did THIS request declare the MCP Apps extension?\n *\n * FAIL-CLOSED at every step: no context, no envelope, no capabilities member, no `extensions`\n * record, or an `extensions` record without our id all answer `false`. The question is \"is there\n * evidence this caller negotiated the extension\", and absence of evidence is not evidence — which\n * matters most for the case the measurement surfaced, where a 2025-era caller carries no envelope\n * at all and would otherwise be waved through by a predicate written as \"not explicitly absent\".\n *\n * WHAT FAILING CLOSED HERE DOES AND DOES NOT PROTECT (dated 2026-09-01, 408 gap round, road\n * `demote` — the full ruling is in this file's header). The predicate is still fail-closed AS A\n * PREDICATE, and every clause above is unchanged. What is CORRECTED is the reading that failing\n * closed here protects the credential. It does not. The value read below is composed by the\n * caller in its own per-request `_meta` and forwarded by the SDK unauthenticated\n * (`_inputRequestCapabilityView` returns it verbatim; `checkInboundEnvelope` checks shape only),\n * so a `false` answer means \"this caller did not SAY it can render an App\" — a host-capability\n * fact — and never \"this caller is not authorized to hold a live-view credential\". What bounds\n * the credential is `bindingStatus === 'bound'` and the local network controls D-13 keeps; the\n * scope check that once sat beside it is deleted (432-20, D-12). See header clause 5.\n *\n * `RequestMetaEnvelope` is an intentionally EMPTY augmentable type in the shipped d.mts, so the\n * envelope is read through one narrow cast at this single seam rather than by widening the SDK's\n * types somewhere a second reader would have to find.\n */\nexport function negotiatedAppsExtension(ctx: AppReadContext | undefined): boolean {\n const envelope = ctx?.mcpReq?.envelope as Record<string, unknown> | undefined\n if (envelope === undefined) return false\n const capabilities = envelope[APP_NEGOTIATION_CLIENT_CAPABILITIES_KEY] as\n | ClientCapabilities\n | undefined\n const extensions = capabilities?.extensions\n if (extensions === undefined) return false\n return Object.hasOwn(extensions, MCP_APPS_EXTENSION_ID)\n}\n\n/**\n * A read refused because the request never declared the Apps extension (clause 3 of the ruling\n * in this file's header; D-09, T-408-01).\n *\n * IT NAMES THE EXTENSION AND CARRIES NOTHING ELSE. The message is authored prose plus a constant\n * this repository owns, so there is nothing caller-supplied in it to mask and — the point of the\n * whole arm — nothing minted in it to leak, because it is thrown before the first mint.\n */\nexport class AppResourceNegotiationError extends Error {\n constructor() {\n super(\n `this resource is an MCP App: it is served only to a client that declared the `\n + `${MCP_APPS_EXTENSION_ID} extension in its capabilities`,\n )\n this.name = 'AppResourceNegotiationError'\n }\n}\n\n/** An address the one codec does not recognise. */\nexport class AppResourceUriError extends Error {\n constructor(detail: string) {\n super(`${detail} is not a canonical ui://agent-qa/live-run address`)\n this.name = 'AppResourceUriError'\n }\n}\n\n/**\n * A refusal from the App read that is NOT a run-liveness fact.\n *\n * Deliberately narrow: absence of a live session is rendered, never thrown (D-07), so anything that\n * reaches this class is a genuine failure of the read — a missing scope, an unknown op, a broken\n * composition — and it carries its message masked for the same reason `resources.ts`'s does.\n */\nexport class AppResourceReadError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AppResourceReadError'\n }\n}\n\n/**\n * A document whose panes would span more than one origin (IN-02, T-408-26; added 2026-09-01).\n *\n * THE INVARIANT THIS SERVES USED TO BE AN ASSUMPTION. The `_meta.ui.csp` block below was derived\n * from `mints[0]` alone, which is correct today only because `runs.liveurl` reads\n * `liveView.origin()` once per invocation — a fact held in ANOTHER package, which nothing on that\n * line checked. A composition that ever minted across origins would have shipped a frame allowance\n * covering the first pane and blocking every other one: a blank inner frame, which is the exact\n * failure this milestone exists to remove, arriving silently.\n *\n * WHY REFUSAL RATHER THAN A WIDER ALLOWANCE. Naming every origin in `frameDomains` would keep the\n * document renderable, but it would also make the allowance a function of how many panes happened\n * to be minted — precisely the \"never broader than the document needs\" property T-408-05 pins.\n * This module's own reasoning is that the allow is as narrow as the document needs; a document that\n * needs two origins is a composition this server does not know how to serve narrowly, and saying so\n * is honest absence rather than a silent widening.\n *\n * ITS MESSAGE CARRIES NO CALLER TEXT AND NO CREDENTIAL. The origins are host-composed and\n * `originOf` returns an origin only — never the path and never the fragment the token lives in — so\n * there is nothing here to mask and nothing here to leak.\n */\nexport class AppResourceOriginSpanError extends Error {\n constructor(origins: readonly string[]) {\n super(\n `this App document would span ${origins.length} origins `\n + `(${[...origins].sort().join(', ')}) and one frame allowance covers one: refusing to serve `\n + `a document whose panes it could not all reach`,\n )\n this.name = 'AppResourceOriginSpanError'\n }\n}\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\nexport type AppResourceInvoke = (opId: string, input: unknown) => Promise<unknown>\n\nexport interface AppResourceReadDeps {\n readonly invoke: AppResourceInvoke\n /** How CALLER text leaving this handler is masked. Required — see the header's channel split. */\n readonly maskText: (text: string) => string\n /**\n * Which dashboard this process is pointed at, for D-08's permanent link (408 plan 03).\n *\n * OPTIONAL, and its absence is a real posture rather than a gap: a composition that knows of no\n * dashboard renders the wrapper with NO anchor at all, which is what plan 01 shipped and what the\n * honest-absence law requires — a link to nothing is the dishonesty this milestone removes.\n *\n * THIS IS THE ONE SLOT WHOSE ABSENCE COSTS A PERSON SOMETHING, which is why it is wired rather\n * than left where plan 01 left it: the wrapper's `expired` and `unreachable-origin` states are\n * D-11's answers for \"the embed cannot show you this\", and both of them are supposed to hand a\n * person the browser instead. A wrapper reaching those states with no link is a dead end wearing\n * an honest sentence.\n */\n readonly liveLink?: LiveLinkSupplier\n}\n\n/**\n * True when a refusal is a statement about this host's LIVENESS rather than about the read.\n *\n * The three shapes a not-live composition can answer with, named by class rather than by message:\n * a host with no live-view port at all (`FunctionNotBoundError` from the binding check, or\n * `LiveViewUnavailableError` from the op when the port is bound but serves no origin), and a run\n * this host holds no session for (`UnknownRunError`). Each becomes the wrapper's honest not-live\n * document — never an error surface, and never a blank frame (D-07).\n */\nfunction isNotLiveRefusal(error: unknown): boolean {\n return (\n error instanceof UnknownRunError\n || error instanceof LiveViewUnavailableError\n || error instanceof FunctionNotBoundError\n )\n}\n\n/**\n * The handle roster this run ANNOUNCED, read off its own first envelope.\n *\n * `runStarted` is seq 1 and carries the roster as an additive payload field (402-04 D-10), so one\n * envelope answers the whole question and the iterator is disposed immediately — a resource read\n * that drained a run's entire event log to learn two integers would be a second, far more expensive\n * answer to a question the first element already answers.\n *\n * Answers `undefined` rather than a default, so the CALLER decides what an unannounced roster\n * means; the read handler reads it as handle 0, the single-member case every non-suite run is.\n *\n * IT ALSO ANSWERS `[]`, AND THAT IS THE SAME DECISION (WR-05, 2026-09-01). `handleRosterOf` answers\n * `[]` for a `runStarted` that really announced `handles: []`, and `undefined` only when the field\n * is absent or malformed — two different bytes on the wire, one question for the caller. The read\n * handler collapses them at `rosterToMint` below: an announced-but-empty roster is a run that named\n * no members, not a run that ended, and `run-ended` is a claim about LIVENESS. Kept as two answers\n * HERE rather than defaulted away, because this function's contract is to report what the envelope\n * said; deciding what it means is the caller's job, and now there is exactly one place doing it.\n */\nasync function announcedRoster(\n invoke: AppResourceInvoke,\n runId: string,\n): Promise<readonly number[] | undefined> {\n const stream = await invoke(RUNS_EVENTS_FUNCTION_ID, { runId })\n const iterable = stream as AsyncIterable<RunEventEnvelope> | undefined\n if (iterable === undefined || typeof iterable[Symbol.asyncIterator] !== 'function') {\n return undefined\n }\n const iterator = iterable[Symbol.asyncIterator]()\n try {\n const first = await iterator.next()\n if (first.done === true) return undefined\n return handleRosterOf(first.value)\n } finally {\n await iterator.return?.(undefined)\n }\n}\n\n/**\n * Build the App read.\n *\n * Exported so a cell can drive it without a server, and so the parse/mint/render behaviour is\n * observable independently of registration — the two halves fail in different directions.\n */\nexport function createAppResourceReadHandler(\n deps: AppResourceReadDeps,\n): (uri: URL, variables: Variables, ctx: AppReadContext) => Promise<ReadResourceResult> {\n return async (\n uri: URL,\n _variables: Variables,\n ctx: AppReadContext,\n ): Promise<ReadResourceResult> => {\n // CLAUSE 3 OF THE HEADER'S RULING, AND IT IS THE FIRST LINE ON PURPOSE (D-09).\n // A RENDERING-CAPABILITY FILTER, NOT THE AUTHORIZATION CHECK (corrected 2026-09-01, 408 gap\n // round, road `demote`; T-408-01 re-adjudicated to `accept` — the ruling is in the header).\n // What this line asks is whether the caller SAID it can render an MCP App. A caller that did\n // not say so is turned away before anything below runs, so this path has no token to withhold\n // rather than a token it remembered not to print — and that ordering is still worth keeping.\n // It is not, however, an authorization check. Since 432-20 (D-12) no per-caller permission\n // exists: `registerAppResources` registered this template because the mint is `bound` in this\n // composition, and a composition without that never reaches this handler at all.\n if (!negotiatedAppsExtension(ctx)) throw new AppResourceNegotiationError()\n\n const parsed = parseAppUri(uri.href)\n if (parsed === undefined) {\n // The echoed address is caller-supplied text, so it is masked exactly as `resources.ts`\n // masks its own — this is the refusal channel, and the channel split is the point.\n throw new AppResourceUriError(deps.maskText(uri.href))\n }\n const { runId } = parsed\n\n let roster: readonly number[] | undefined\n let notLive = false\n try {\n roster = await announcedRoster(deps.invoke, runId)\n } catch (err) {\n if (!isNotLiveRefusal(err)) {\n throw new AppResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n notLive = true\n }\n\n // WR-05 (2026-09-01, T-408-25): `undefined` AND `[]` resolve here, once, by name.\n // `roster ?? [0]` did not fire for `[]` — `??` tests nullishness, not emptiness — so a run whose\n // `runStarted` announced `handles: []` ran the mint loop ZERO times, produced no mints, and was\n // rendered `run-ended` by the count below for a run this host IS holding a live session for.\n // That is not a cosmetic error: under the promoted D-08 model the credentialled embed is one\n // bounded variant of a representation whose primary form is the permanent link, and `run-ended`\n // is how this document says the variant is unavailable. Withdrawing it on a false premise is the\n // same class of dishonesty as labelling a dead pane `live`.\n //\n // Both absences mean what the handler already documents as its default: the single member,\n // handle 0. A named local rather than an expression in the `for` header, because the point is\n // that three paths became two and a reader has to be able to SEE that.\n const rosterToMint = roster === undefined || roster.length === 0 ? [0] : roster\n\n const mints: AppWrapperMint[] = []\n if (!notLive) {\n for (const handle of rosterToMint) {\n // THE ONE INVOCATION WALL, once per handle (D-06). Fresh on EVERY read, which is D-10's\n // fresh-on-render for free: nothing is cached here, so there is no stale token to serve.\n let minted: RunsLiveUrlResult\n try {\n minted = (await deps.invoke(RUNS_LIVE_URL_FUNCTION_ID, {\n runId,\n handle,\n })) as RunsLiveUrlResult\n } catch (err) {\n if (!isNotLiveRefusal(err)) {\n throw new AppResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n // One member of a suite can finish while the run continues, so a per-handle refusal\n // drops that PANE rather than the whole document. Zero surviving mints is the run-level\n // not-live case, decided below by counting rather than by a second flag.\n continue\n }\n mints.push({\n handle: minted.handle,\n liveUrl: minted.liveUrl,\n expiresAt: minted.expiresAt,\n streamKind: minted.stream.kind,\n })\n }\n }\n\n // D-08's link-out, composed from whatever base this composition was pointed at (408 plan 03).\n // The SAME composition every carrier result uses — `liveRunLinkOf` is the one place the address\n // is built — so the anchor inside the App and the line beside a tool result cannot name two\n // different pages for one run. With no base, the slot stays ABSENT rather than fabricated: the\n // wrapper renders no anchor at all for an absent link.\n const base = deps.liveLink?.dashboardBaseUrl()\n const permanentLink\n = base === undefined || base.trim() === '' ? undefined : liveRunLinkOf(base.trim(), runId)\n\n // IN-02 (2026-09-01, T-408-26). THE ALLOWANCE IS DERIVED FROM THE WHOLE DOCUMENT, and the\n // invariant it rests on is ASSERTED HERE rather than assumed to hold in another package. Every\n // mint's origin, distinct, in one set: a mint whose `liveUrl` this host cannot name as a URL\n // contributes nothing (the old `mints[0]`-only form behaved the same way, and that arm is\n // unchanged), and two identical origins contribute one entry, so a two-handle document names\n // its shared origin once rather than once per pane.\n //\n // POSTURE, RECORDED AS THE COMMENT THIS FILE'S CHOICE IS SUPPOSED TO CARRY: a document whose\n // panes would span origins is REFUSED, not served with a widened allowance. See\n // `AppResourceOriginSpanError` for the reasoning. Refused BEFORE the wrapper is composed, so\n // there is no half-honest document in existence on that path.\n const frameOrigins = [\n ...new Set(\n mints\n .map((mint) => originOf(mint.liveUrl))\n .filter((origin): origin is string => origin !== undefined),\n ),\n ]\n if (frameOrigins.length > 1) throw new AppResourceOriginSpanError(frameOrigins)\n const frameDomain = frameOrigins[0]\n\n const html = renderAppWrapperPage({\n runId,\n mints,\n permanentLink,\n runLive: mints.length > 0,\n })\n\n // NOT MASKED, and the inversion of `resources.ts`'s rule is the decision. That module masks\n // because its payload is STORED data reaching a caller through a handler nothing else masks;\n // this payload is a credential minted for this response, whose whole purpose is to be handed to\n // the host's iframe intact. A masked token is a broken embed, so masking here would be the\n // defect rather than the guard. The channel that DOES echo caller text — the refusals above —\n // is masked, and Plan 04's scan cell is the standing gate on every model-readable channel.\n return {\n contents: [\n {\n // Re-formatted through the codec's own vocabulary rather than echoed, so the address a\n // caller reads back is the canonical one.\n uri: `${APP_URI_PREFIX}${runId}`,\n mimeType: APP_RESOURCE_MIME_TYPE,\n text: html,\n // The host's default is `frame-src 'none'`, so an App that names no frame domain paints\n // a BLOCKED inner frame — the blank pane criterion 2 forbids (Pitfall 1). The allowed\n // origin is the minted link's OWN origin rather than a separately configured one, so the\n // allow can never be broader than the document needs (T-408-05). `frameDomain` is the ONE\n // distinct origin `frameOrigins` above resolved over EVERY mint (IN-02) — not `mints[0]`'s,\n // which was the same answer only by a fact held in another package.\n //\n // TWO ABSENCES, NOT ONE (corrected 2026-09-01, 408 gap round; `408-VERIFICATION.md` W-4 /\n // `408-REVIEW.md` WR-03). This comment used to read \"with no mints there is no inner\n // frame, and the block is omitted rather than emitted empty\", which describes only the\n // FIRST of two conditions that both reach `frameDomain === undefined`. They are different\n // questions with different served documents, and collapsing them told a reader about a\n // state the code does not produce:\n // - `mints.length` asks whether there is anything to render at all. Zero mints means\n // `runLive` is `false`, the wrapper emits no `<iframe data-app-live-frame>`, and the\n // omitted `csp` block allows nothing because nothing needs allowing. Honest.\n // - `frameOrigins[0]` is the SEPARATE question of whether any surviving mint yielded a\n // parseable origin to put in `_meta.ui.csp`. With `mints.length > 0` and every\n // `originOf(mint.liveUrl)` answering `undefined`, `runLive` is `true` — the document\n // DOES emit the iframe and DOES assign `frame.src` — while the `csp` block is omitted,\n // so a conformant host falls back to `frame-src 'none'` and the pane is blocked and\n // blank. Not honest, and the sentence above never mentioned it.\n // WHY NO SHIPPED PORT REACHES IT: `runs.liveurl` would have to answer a `liveUrl` that\n // is not a parseable URL, and no shipped port does. The verifier measured this as\n // unreachable and classified W-4 as a documentation finding rather than a gap; the\n // wrapper's probe/timeout arm would in any case settle `unreachable-origin` with the\n // permanent link rather than leave a blank pane under a progress claim, so SC2 survives\n // even on the unreachable path.\n //\n // THE INVARIANT IS UNASSERTED, AND THAT IS A DATED DEFERRAL RATHER THAN A SILENCE\n // (2026-09-01, 408 gap round). \"Every mint that survives into `runLive` has a nameable\n // origin\" is asserted nowhere today — not here, not in `renderAppWrapperPage`, not in a\n // cell. It is the natural candidate and it is NOT taken in this round, because this round\n // is a gap-closure round whose whole reported gap is documentation integrity.\n // THE RULE THAT MAKES THAT CONSISTENT, because the neighbouring round looks\n // contradictory and a reader is entitled to it: THIS ROUND CHANGES WHAT THE SYSTEM\n // SAYS, NEVER WHAT IT DOES. 408-16 task 1 does edit a runtime file — `config.ts` — but\n // it only adds words to an error that was already being thrown on exactly the inputs it\n // was already thrown on; no parse outcome moves in either direction and no input that\n // succeeded now fails. Asserting the invariant here would add a NEW failure mode to a\n // path that currently succeeds. Operator-facing error prose is in scope because it is\n // prose; a new runtime invariant is out of scope because it is behaviour. That is the\n // whole distinction, and it is what makes W-2 closable in this round and W-4's\n // invariant half not.\n //\n // AND THE NEW PROSE CENSUS DOES NOT COVER THIS, which is the question the gap brief asks\n // by name. `__tests__/withdrawn-claim-census.test.ts` gates ONE withdrawn security claim\n // about the token channel, keyed on a channel cue bound to an exclusivity cue; W-4 is a\n // different species — a comment that CONFLATES two conditions rather than one that\n // over-claims a control — and widening that census to \"any comment that conflates two\n // conditions\" is not mechanizable, and a vocabulary that tried would red on honest prose,\n // which this round's own prohibition forbids.\n //\n // `connectDomains` NAMES THE SAME ONE ORIGIN, AND IT IS NOT OPTIONAL (408 plan 06 Task 2,\n // MEASURED 2026-08-31). ext-apps' shipped schema documents `connectDomains` as mapping to\n // `connect-src` with \"empty or omitted -> no network connections (secure default)\", and\n // 408-02 D-H gave this wrapper a no-cors probe of the frame's origin — because Chromium\n // fires `load` for a REFUSED connection, so `load` alone would label an error page `live`.\n // With only `frameDomains` declared, a conformant host serves the App under\n // `connect-src 'none'`, the probe is blocked before it leaves the document, and the\n // wrapper settles in `unreachable-origin` for a live view that is perfectly reachable —\n // measured in `app-host-harness.test.ts`, with Chromium naming the directive in its own\n // console. That is not a blank frame, but it is a lie with a sentence attached, which is\n // worse: it tells a person to go somewhere else while the pixels are right there.\n //\n // It is exactly as narrow as the frame allowance — the same single minted origin, never a\n // wildcard and never a second configured value — so the App can reach the one host it\n // embeds and nothing else.\n ...(frameDomain === undefined\n ? {}\n : {\n _meta: {\n ui: { csp: { frameDomains: [frameDomain], connectDomains: [frameDomain] } },\n },\n }),\n },\n ],\n }\n }\n}\n\n/** The origin of a minted `liveUrl`, or `undefined` if it is not a URL this host can name. */\nfunction originOf(liveUrl: string): string | undefined {\n try {\n return new URL(liveUrl).origin\n } catch {\n return undefined\n }\n}\n\n/**\n * The slice of `McpServer` this module uses.\n *\n * The same narrow structural type `resources.ts` declares, spelled with the SDK's own\n * `ResourceTemplate` / `ResourceMetadata` / `ReadResourceTemplateCallback` — so a cell can observe\n * the registration without assembling a protocol server while a real `McpServer` still satisfies\n * it. Read that module's note before narrowing any member here: a hand-narrowed config or a\n * `readonly` result array makes `McpServer` unassignable and the compiler names the wrong cause.\n *\n * THE READ CALLBACK IS THE SDK'S OWN `ReadResourceTemplateCallback` AND NOT A LOCAL NARROWING, for\n * the reason 408 plan 02 needed a third argument at all: the negotiation evidence arrives in the\n * SDK's read CONTEXT, so a slice that spelled the callback `(uri) => …` would have declared the\n * one parameter the gate reads out of existence.\n */\nexport interface AppResourceRegistrar {\n registerResource(\n name: string,\n template: ResourceTemplate,\n config: ResourceMetadata,\n read: ReadResourceTemplateCallback,\n ): unknown\n}\n\n/** Exactly what this module needs from the host — the same record `catalog.ts` already holds. */\nexport interface AppResourceDeps {\n readonly registry: FunctionRegistry\n readonly caller: FunctionCaller\n readonly maskText: (text: string) => string\n /** D-08's base supplier, passed straight through to the read. See {@link AppResourceReadDeps}. */\n readonly liveLink?: LiveLinkSupplier\n}\n\n/**\n * Register the App template when this composition can honestly serve it, and answer what it\n * registered.\n *\n * Returns the registered template URIs rather than nothing, for `resources.ts`'s reason: \"registered\n * none\" and \"registered one\" are the two halves of the claim, and a caller that had to inspect a\n * server to tell them apart could only ever test one of them.\n *\n * TWO CONDITIONS, BOTH READ OFF THE REGISTRY'S OWN DECLARATIONS (D-02/D-03), AND NEITHER ABOUT THE\n * CALLER (432-20, D-12 deleted the third, a `visibleToCaller` scope check):\n *\n * 1. Both ops this surface reads through — the mint and the roster read — are declared here. A\n * composition that registered neither has no App to offer.\n * 2. The mint is BOUND in this composition. This is D-03's floor made structural: the standalone\n * `agent-qa mcp` process composes no `liveView` port, so its `runs.liveurl` is declared-and-\n * unbound and every mint there would refuse by name. Registering an App on that host would\n * advertise an address whose every read is honestly empty — so it registers nothing at all,\n * and the link-out is that host's whole answer. On a co-hosted composition the same three\n * lines register it, by composition rather than by configuration.\n *\n * A composition that fails any of them gets NO template and NO error — the same answer `catalog.ts`\n * gives a tool whose op is missing, because refusing to build would take an entire MCP connection\n * down over one unavailable capability.\n */\nexport function registerAppResources(\n server: AppResourceRegistrar,\n deps: AppResourceDeps,\n): readonly string[] {\n const declared = deps.registry.list(deps.caller)\n const mint = declared.find((candidate) => candidate.id === RUNS_LIVE_URL_FUNCTION_ID)\n const roster = declared.find((candidate) => candidate.id === RUNS_EVENTS_FUNCTION_ID)\n if (mint === undefined || roster === undefined) return []\n if (mint.bindingStatus !== 'bound') return []\n\n const read = createAppResourceReadHandler({\n // The wall, bound once: every mint crosses `invokeFunction` with this host's registry and this\n // caller, so input validation and the binding check run exactly as they do for a tool call.\n // There is no store, no cache and no second data path.\n invoke: (opId, input) => invokeFunction(deps.registry, opId, input, deps.caller),\n maskText: deps.maskText,\n // Absent stays ABSENT rather than becoming a present `undefined` supplier: the house rule for\n // an optional member, and the two are the same posture to the read either way.\n ...(deps.liveLink === undefined ? {} : { liveLink: deps.liveLink }),\n })\n\n server.registerResource(\n APP_RESOURCE_NAME,\n // `list: undefined` is REQUIRED to be spelled out by the SDK, and here the explicit absence is\n // load-bearing rather than merely honest: an unlisted template cannot be reached by\n // enumeration, so no model walking `resources/list` can discover an address whose read mints a\n // credential (Pitfall 2). Enumerating every watchable run is a listing this surface does not\n // offer, and this is the line that says so.\n new ResourceTemplate(APP_RESOURCE_URI_TEMPLATE, { list: undefined }),\n {\n title: APP_RESOURCE_TITLE,\n description: APP_RESOURCE_DESCRIPTION,\n mimeType: APP_RESOURCE_MIME_TYPE,\n },\n read,\n )\n\n return [APP_RESOURCE_URI_TEMPLATE]\n}\n","// The MCP App WRAPPER page (408 D-04/D-06/D-07/D-10/D-11, ratified 2026-08-31; finished in plan 02).\n//\n// WHAT THIS DOCUMENT IS. A thin host-rendered page that IFRAMES the `liveUrl` Phase 403 already\n// mints and serves. It is not a second embed document: the 403 embed page\n// (`dashboard-server/src/live-view/embed-page.ts`) stays byte-identical and this file re-implements\n// none of it — no socket, no canvas, no frame protocol, no token parse. One embed contract, two\n// consumers (D-04). Copying that file's IDIOMS is deliberate; copying its BYTES would be the\n// second implementation this milestone exists to retire.\n//\n// IT RENDERS NO RUN STATE OF ITS OWN (D-11). No step list, no status line, no verdict. Those need\n// an event-stream credential story inside a sandboxed iframe that this phase refuses to invent; the\n// full two-pane surface stays the dashboard's, one click away through the permanent link. What this\n// page owns is the closed state set below, the handle picker, and the link slot.\n//\n// EVERY ABSENCE IS NAMED, inherited verbatim from the embed page's own header. There is no state in\n// which this page shows a blank rectangle: a run with no live session says so by name\n// (`run-ended`), a host that cannot reach the dashboard origin says so (`unreachable-origin`), and\n// an elapsed token says so (`expired`) rather than leaving a dead frame under a spinner.\n//\n// A MEASURED FACT THAT SHAPES THE `live` ARM, and the reason this page probes rather than trusting\n// an event (measured 2026-08-31, Chromium; the cell is `cli/src/__tests__/app-wrapper-dom.test.ts`):\n// AN IFRAME POINTED AT A REFUSED CONNECTION STILL FIRES `load`. The browser navigates the frame to\n// its own error page and that navigation completes, so `load` says \"a document settled in there\",\n// never \"the origin answered\". A wrapper whose only signal was `load` would therefore label\n// Chromium's error page `live` — the blank inner frame D-11 forbids, wearing the one label that\n// stops a person from looking further. Cross-origin, this page cannot look inside the frame to\n// tell the difference, and it must not ask the INNER page to tell it (criterion 3 freezes that\n// document). So reachability is established by an explicit `fetch(origin, { mode: 'no-cors' })`\n// probe — the one question a sandboxed page can honestly ask about somebody else's origin — and\n// `live` requires BOTH the probe answering and the frame loading. The probe is memoised per\n// ORIGIN, so the handle picker (D-06) swaps among panes on one origin with no network call at all.\n//\n// AND THE MEMO IS ASYMMETRIC — SUCCESS ONLY (2026-09-01, WR-06, T-408-23; the cell is\n// `app-wrapper-dom.test.ts` cell (8)). A `true` is a durable fact about an origin that ANSWERED, so\n// it is cached and the zero-request property above depends on it and on nothing else. A `false` is\n// a fact about ONE MOMENT — a dashboard restarting, a refusal during the first paint — and it is\n// discarded, so the next call probes again. Caching it bought nothing the `true` was not already\n// buying, and cost everything: all of a render's mints share one origin, so a single transient\n// failure answered `false` for the LIFE of the document, pinning every later handle swap to\n// `unreachable-origin` instantly, with no network call and no path back. A momentary observation\n// about somebody else's origin does not get to outlive the moment.\n//\n// THE TIMEOUT ARM IS STILL REQUIRED, because the other unreachable shape does not fail fast: an\n// origin that black-holes packets (the cloud-host-versus-loopback case D-11 was written for) leaves\n// both the probe and the frame pending forever. `APP_WRAPPER_LOAD_TIMEOUT_MS` is the bound past\n// which silence is itself the answer, named rather than left as a spinner.\n//\n// EXPIRY IS DECIDED AT RENDER TIME (D-10). The clock is read ONCE, by the renderer, and what enters\n// the script is a DELTA in milliseconds — never an absolute epoch the script would compare against\n// the HOST's clock. A wrapper rendered on a machine whose clock differs from the host's by a minute\n// would otherwise expire a minute early or a minute late for no reason a person could see. If every\n// mint has already aged out by the time the document is built, the document is BORN `expired`: it\n// never assigns a src, so there is no dead frame to flash before the sentence appears.\n//\n// AND `expired` IS ABSORBING (2026-09-01; the cell is `cli/src/__tests__/app-wrapper-dom.test.ts`\n// cell (6), and 408-VERIFICATION.md is where the defect was measured). The expiry timer is\n// ONE-SHOT, so for as long as anything could re-enter `attach()` the document could be walked back\n// OUT of its terminal state: a handle-picker change re-pointed the frame at an already-aged\n// `liveUrl` and painted the word `live` over a dead pane, permanently — the outcome this header\n// already calls worse than a blank frame. `attach()` therefore returns immediately when the\n// document already reads `expired`, and the expiry callback DISABLES the picker, because an\n// affordance that outlives the thing it operates on is a second lie. Read against D-08: the\n// permanent link is the PRIMARY way to watch a run and the embedded pane is one credential-bounded,\n// time-bounded variant of it, so `expired` is not an interruption of the resting state — it is the\n// RETURN to it, and returns are one-way. Cell (6) renders with a short TTL, waits for `expired`,\n// changes the picker, and asserts the document is still `expired` with no frame src and still\n// carrying the link and the hint D-10 requires it to carry.\n//\n// SELF-CONTAINED AND PURE. No imports, no external stylesheet, no build step: the whole document is\n// the string this function returns, because a host renders it inside a sandbox with no network\n// identity of its own. `renderAppWrapperPage` is a pure function of its input (the clock included,\n// which is why `now` is a parameter and not a call), so a cell drives it directly.\n//\n// VALUES ENTER THE SCRIPT AS STRING LITERALS AND LAND AS `textContent` (T-403-09). The escape\n// helper is `embed-page.ts`'s, copied because the guard must not be re-derived: `JSON.stringify`\n// plus a `<` escape closes the `</script` hole. The picker's options and the run id are BUILT in\n// the script rather than templated above it, so nothing caller-supplied has to be trusted to markup.\n//\n// WITH ONE AMENDED EXCEPTION, AMENDED HERE RATHER THAN REVERSED IN SILENCE (2026-09-01; the cells\n// are `app-wrapper.test.ts`'s markup-anchor, scheme-drop and attribute-escape cells, and\n// `app-wrapper-dom.test.ts` cell (7)). THE PERMANENT LINK'S `href` AND LABEL ARE NOW RENDERED INTO\n// MARKUP. The rule above was sound and its conclusion was wrong for exactly this one value. Under\n// D-08 the permanent link is the PRIMARY way to watch a run, and a primary representation produced\n// by the script is unavailable on precisely the host it exists to cover: a host serving this\n// document under `script-src 'none'` (WR-10, RESEARCH assumption A1) runs NONE of this script, so\n// the anchor stayed empty, the frame stayed hidden and the document sat forever under the\n// connecting sentence — the pane with no way out that this header already calls worse than a blank\n// frame. Two guards PAY for the exception rather than relaxing the rule:\n// (a) a SECOND, separately named escape helper for HTML ATTRIBUTE context (`attributeText`),\n// used for this one value and nothing else, never for a value entering the script; and\n// (b) a SCHEME CHECK that DROPS a `permanentLink` which is not `http:` or `https:`, so a hostile\n// base composes no anchor at all rather than a new kind of one (WR-04's anchor hop — the\n// parse-time hop is the dashboard config schema's, and this renderer is exported and drivable\n// directly, so it guards its own input rather than trusting a boundary it cannot see).\n// The connecting state carries a NAMED HINT for the same reason: a server-rendered document that\n// says only \"connecting\" is making a claim its own script has to keep, and on that host it cannot.\n//\n// Protocol grounding. This module speaks no protocol at all — it returns a string — and the two\n// SEPs that nonetheless shape it are the reason it can. SEP-1730 places extensions outside every\n// conformance tier, so this page is rendered only by a host that OPTED IN to the Apps extension and\n// a host that did not owes it nothing: there is no degraded rendering to design for, only the\n// link-out that rides every carrier result. SEP-2575's stateless protocol is why the page holds no\n// session and mints nothing: it is handed everything it will ever have at render time, which is\n// what makes D-10's answer to an aged token another READ rather than a credential machine inside\n// somebody else's sandbox.\n\n/**\n * Every value `[data-app-state]` can take (D-11's closed set).\n *\n * Exported for the reason `LIVE_EMBED_STATES` is: the DOM cells range over this list, so a state\n * added to the page without a cell is a visible diff rather than an unobserved arm.\n */\nexport const APP_WRAPPER_STATES = [\n 'connecting',\n 'live',\n 'expired',\n 'unreachable-origin',\n 'run-ended',\n] as const\n\nexport type AppWrapperState = (typeof APP_WRAPPER_STATES)[number]\n\n/** What the page says while the inner frame has not painted yet. */\nexport const APP_WRAPPER_CONNECTING_MESSAGE = 'connecting to the live view…'\n\n/**\n * The second line under `connecting`, and the WHOLE of what an initial render says on a host that\n * never runs this document's script (WR-10, RESEARCH assumption A1; the cell is\n * `app-wrapper-dom.test.ts` cell (7)).\n *\n * Named for the same reason every other absence here is named: a document that says only that it is\n * connecting has made a promise its own script has to keep, and under a host CSP of\n * `script-src 'none'` there is no script to keep it. The sentence therefore points at the ONE\n * useful action available with no script at all — the permanent link rendered directly beneath it,\n * which is now markup rather than something the script assigns. One useful action, no apology.\n */\nexport const APP_WRAPPER_CONNECTING_HINT\n = 'if the pane does not appear, open it in your browser'\n\n/** What the page says once the inner frame has loaded on an origin this host can reach. */\nexport const APP_WRAPPER_LIVE_MESSAGE = 'live'\n\n/**\n * What an elapsed live link says (D-10).\n *\n * The wrapper's own sentence rather than the embed page's `link expired`, because the two are about\n * different things: the embed says its socket was refused, and this says the link this App was\n * rendered with has aged out.\n */\nexport const APP_WRAPPER_EXPIRED_MESSAGE = 'live link expired'\n\n/**\n * The second half of the expired state, and the WHOLE of D-10's refresh story (D-10).\n *\n * There is no re-mint inside this sandbox and there is never going to be one — a UI-initiated mint\n * door was rejected precisely because its model-context hygiene is per-host behaviour nobody here\n * controls. What replaces it is this sentence: the way to a fresh token is another watch call, one\n * the person can simply ask for, and saying so is the difference between a dead end and a next\n * move. Separate from the message above so the DOM can show both and a cell can assert each.\n */\nexport const APP_WRAPPER_EXPIRED_HINT = 'ask to watch again — a fresh watch mints a new link'\n\n/**\n * The REQUIRED unreachable-origin sentence (D-11), spelled EXACTLY as CONTEXT ratified it.\n *\n * A host running somewhere that cannot route to a loopback dashboard origin must say so and offer\n * the browser, never show a blank inner frame. This string is a contract: the DOM cells assert\n * against this constant, so the sentence and the assertion can never drift apart.\n */\nexport const APP_WRAPPER_UNREACHABLE_MESSAGE =\n \"this host can't reach the live view — open it in your browser\"\n\n/**\n * What a run with no live session on this host says (D-07).\n *\n * Not an error and not a blank frame — and it points at the way to see the run anyway, which is\n * the permanent link rendered directly beneath it. A run that has finished still HAPPENED, and the\n * dashboard's own page is where its history lives.\n */\nexport const APP_WRAPPER_RUN_ENDED_MESSAGE = 'this run is not live — open it in your browser'\n\n/** The label on the permanent link-out slot, when one is composed (D-08). */\nexport const APP_WRAPPER_PERMANENT_LINK_LABEL = 'open in your browser'\n\n/**\n * How long silence from the inner frame is allowed to last before it is named (D-11, T-408-08).\n *\n * Exported because the DOM cell must wait on the page's OWN bound rather than on a number a test\n * file guessed. Ten seconds is chosen against the two shapes this arm exists for: a black-holed\n * origin never answers at all, and a slow-but-reachable dashboard on loopback answers in\n * milliseconds — there is no realistic case in between, so a longer bound would only make a person\n * stare at a spinner for longer before reading the same sentence.\n */\nexport const APP_WRAPPER_LOAD_TIMEOUT_MS = 10_000\n\n/**\n * The MCP Apps protocol version this wrapper announces in its `ui/initialize` request.\n *\n * MEASURED, not guessed (408-06 Task 1): `@modelcontextprotocol/ext-apps@1.7.5` carries exactly\n * two protocol versions — `2025-11-21` and `2026-01-26` — and `2026-01-26` is the one its\n * `AppBridge` treats as latest. `ext-apps-constants.test.ts` pins the spelling against the\n * package's own shipped schema, so this literal cannot drift from the vocabulary in silence.\n */\nexport const APP_WRAPPER_UI_PROTOCOL_VERSION = '2026-01-26'\n\n/**\n * What this document calls itself to a host (`ui/initialize`'s required `appInfo`).\n *\n * Exported so a cell asserts the SAME bytes the page posts, per this file's standing rule that a\n * value a person or a host can observe is never restated in a test.\n */\nexport const APP_WRAPPER_APP_NAME = 'agent-qa-live-view'\n\n/** The wrapper's own version, bumped only when the handshake it performs changes. */\nexport const APP_WRAPPER_APP_VERSION = '1.0.0'\n\n/**\n * ONE minted view onto ONE member handle of the run.\n *\n * `liveUrl` carries its token in the FRAGMENT (403 D-04), so this value is the only place a live\n * credential exists on this page — it is written into the frame's `src` and nowhere else: not into\n * the document text, not into the picker's labels, not into any attribute a host serialises back.\n */\nexport interface AppWrapperMint {\n readonly handle: number\n readonly liveUrl: string\n readonly expiresAt: number\n readonly streamKind: string\n}\n\nexport interface AppWrapperInput {\n readonly runId: string\n /** One mint per handle on the run's announced roster. Empty is the D-07 not-live case. */\n readonly mints: readonly AppWrapperMint[]\n /** The tokenless dashboard page (D-08). `undefined` when no dashboard origin is composable. */\n readonly permanentLink: string | undefined\n /** Whether this host holds a live session for the run at all. `false` renders `run-ended`. */\n readonly runLive: boolean\n /**\n * The instant this document is being built, in ms-epoch (D-10).\n *\n * A PARAMETER rather than a `Date.now()` call, for the reason every clock in this repository is a\n * port: the expiry arm is the one thing this renderer decides about time, and a cell that cannot\n * choose \"now\" could only ever assert the arm it happened to land in. Defaults to the wall clock,\n * so the read handler passes nothing and gets the honest answer.\n */\n readonly now?: number\n}\n\nconst STYLE = `\n :root { color-scheme: dark light }\n html, body { margin: 0; height: 100%; background: #0b0d10; }\n main { display: grid; grid-template-rows: auto 1fr auto auto; height: 100%; font: 14px/1.5 ui-sans-serif, system-ui, sans-serif; color: #c9d1d9; }\n header { display: flex; gap: .75rem; align-items: center; padding: .5rem .75rem; }\n header:empty { display: none; }\n iframe { border: 0; width: 100%; height: 100%; display: none; background: #0b0d10; }\n main[data-app-state=\"live\"] iframe { display: block; }\n main[data-app-state=\"live\"] p[data-app-message] { display: none; }\n main[data-app-state=\"live\"] p[data-app-hint] { display: none; }\n p[data-app-message] { margin: 0; padding: .5rem .75rem; }\n p[data-app-hint] { margin: 0; padding: 0 .75rem .5rem; opacity: .75; }\n p[data-app-hint]:empty { display: none; }\n footer { padding: .5rem .75rem; }\n select[hidden], a[hidden] { display: none; }\n`\n\n/** The sentence each state shows, and the second line it shows underneath. */\nconst MESSAGES: Readonly<Record<AppWrapperState, string>> = {\n connecting: APP_WRAPPER_CONNECTING_MESSAGE,\n live: APP_WRAPPER_LIVE_MESSAGE,\n expired: APP_WRAPPER_EXPIRED_MESSAGE,\n 'unreachable-origin': APP_WRAPPER_UNREACHABLE_MESSAGE,\n 'run-ended': APP_WRAPPER_RUN_ENDED_MESSAGE,\n}\n\nconst HINTS: Readonly<Record<AppWrapperState, string>> = {\n connecting: APP_WRAPPER_CONNECTING_HINT,\n live: '',\n expired: APP_WRAPPER_EXPIRED_HINT,\n 'unreachable-origin': '',\n 'run-ended': '',\n}\n\n/**\n * The `permanentLink` this renderer is willing to put in an `href`, or `undefined` (WR-04).\n *\n * A URL-shaped OPERATOR config value (`services.dashboard.baseUrl`) reaches this function, and the\n * document it lands in runs with `allow-scripts` at an opaque origin, so a base of\n * `javascript:alert(1)` would compose a script-executing anchor. Anything that is not an absolute\n * `http:`/`https:` URL is therefore treated EXACTLY as an absent link: no anchor at all. That is\n * deliberate reuse rather than a new arm — absence is already the tested, honest posture for `no\n * dashboard origin is composable`, so a hostile base collapses into a state this document already\n * knows how to be in, instead of inventing one nobody has looked at.\n *\n * Defensive, not redundant: the config schema refuses the same shape at PARSE time, but\n * `renderAppWrapperPage` is exported and drivable directly, and it receives its link from a\n * supplier rather than from a freshly parsed config.\n */\nfunction httpPermanentLink(value: string | undefined): string | undefined {\n if (typeof value !== 'string') return undefined\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n return undefined\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? value : undefined\n}\n\n/**\n * Render the App wrapper for one run.\n *\n * The whole document, every time — there is no partial render and no update path, because D-10's\n * answer to a stale App is a FRESH read that mints again rather than a credential machine inside\n * the sandbox.\n */\nexport function renderAppWrapperPage(input: AppWrapperInput): string {\n // The embed page's escape, copied verbatim (embed-page.ts:72) rather than re-derived: the value\n // lands inside a script as a STRING LITERAL and the `<` guard closes the one hole that leaves.\n // ONE helper for every value that enters the script, so the guard cannot be forgotten for a new\n // one — including the handle numbers, which enter as literals like everything else so that\n // \"every value crosses the helper\" is a property a reader can check by grepping for the calls.\n const scriptLiteral = (value: string) => JSON.stringify(value).replaceAll('<', '\\\\u003c')\n\n // THE SECOND HELPER, AND THE ONLY ONE FOR HTML ATTRIBUTE CONTEXT. It exists for exactly one\n // value — the permanent link's `href` and its label — which is the one thing this document renders\n // into MARKUP rather than assigning from the script (see the header's dated amendment: the link\n // is the primary representation and must survive a host that runs no script). `&` goes first or\n // the later replacements would be re-escaped.\n //\n // THE TWO HELPERS MUST NEVER BE USED IN EACH OTHER'S CONTEXT. `scriptLiteral` remains the one\n // helper for EVERY value entering the script and produces a quoted JS literal, which is not an\n // attribute value; this one produces attribute text and does nothing about the `</script` hole.\n // Swapping them silently reopens exactly the guard the other one closes.\n const attributeText = (value: string) =>\n value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n\n const now = input.now ?? Date.now()\n\n // THE RENDERER IS AUTHORITATIVE ABOUT WHETHER A PANE EXISTS, rather than trusting the record it\n // was handed. `runLive: false` means the document must not be ABLE to show a pane, so the urls\n // never reach the script at all — a not-live document that still carried a minted token would be\n // a credential shipped for no reason, which is the one thing D-01's channel argument cannot\n // tolerate. The same line makes \"zero surviving mints ⇒ not live\" (408-01 D-C) structural here.\n const live = input.runLive && input.mints.length > 0\n const mints = live ? input.mints : []\n\n // The LOWEST expiry among the panes, because the document expires when the first of its links\n // does: showing a person a picker whose other option is already dead would be a worse lie than\n // saying the whole thing aged out.\n const lowestExpiry = mints.reduce(\n (lowest, mint) => (mint.expiresAt < lowest ? mint.expiresAt : lowest),\n Number.POSITIVE_INFINITY,\n )\n const expired = live && lowestExpiry <= now\n // The DELTA, not the deadline — see the header. Clamped at zero because a negative timeout is a\n // fact about this render, and this render already turned it into the `expired` initial state.\n const expiresInMs = expired || !live ? 0 : Math.max(0, lowestExpiry - now)\n\n const initialState: AppWrapperState = !live ? 'run-ended' : expired ? 'expired' : 'connecting'\n\n const mintsLiteral = (expired ? [] : mints)\n .map(\n (mint) =>\n `{handle:${scriptLiteral(String(mint.handle))},`\n + `url:${scriptLiteral(mint.liveUrl)},`\n + `kind:${scriptLiteral(mint.streamKind)}}`,\n )\n .join(',')\n\n // Complete IN THE MARKUP, href and label both, so the way out exists before a single line of\n // script has run — and absent entirely for a link this renderer will not vouch for.\n const permanentLink = httpPermanentLink(input.permanentLink)\n const permanentLinkSlot\n = permanentLink === undefined\n ? ''\n : '<a data-app-permanent-link rel=\"noreferrer\" target=\"_blank\" href=\"'\n + attributeText(permanentLink)\n + '\">'\n + attributeText(APP_WRAPPER_PERMANENT_LINK_LABEL)\n + '</a>'\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>agent-qa live run</title>\n<style>${STYLE}</style>\n</head>\n<body>\n<main data-app-state=\"${initialState}\">\n<header><select data-app-handle-picker hidden></select></header>\n${live && !expired ? '<iframe data-app-live-frame sandbox=\"allow-scripts\" referrerpolicy=\"no-referrer\" title=\"agent-qa live view\"></iframe>' : ''}\n<p data-app-message>${MESSAGES[initialState]}</p>\n<p data-app-hint>${HINTS[initialState]}</p>\n<footer>${permanentLinkSlot}</footer>\n</main>\n<script>\n(function () {\n var mints = [${mintsLiteral}];\n var runId = ${scriptLiteral(input.runId)};\n var expiresInMs = ${String(expiresInMs)};\n var loadTimeoutMs = ${String(APP_WRAPPER_LOAD_TIMEOUT_MS)};\n var messages = {\n connecting: ${scriptLiteral(APP_WRAPPER_CONNECTING_MESSAGE)},\n live: ${scriptLiteral(APP_WRAPPER_LIVE_MESSAGE)},\n expired: ${scriptLiteral(APP_WRAPPER_EXPIRED_MESSAGE)},\n 'unreachable-origin': ${scriptLiteral(APP_WRAPPER_UNREACHABLE_MESSAGE)},\n 'run-ended': ${scriptLiteral(APP_WRAPPER_RUN_ENDED_MESSAGE)}\n };\n var hints = {\n connecting: ${scriptLiteral(APP_WRAPPER_CONNECTING_HINT)},\n live: '',\n expired: ${scriptLiteral(APP_WRAPPER_EXPIRED_HINT)},\n 'unreachable-origin': '',\n 'run-ended': ''\n };\n\n var root = document.querySelector('[data-app-state]');\n var frame = document.querySelector('[data-app-live-frame]');\n var picker = document.querySelector('[data-app-handle-picker]');\n var message = document.querySelector('[data-app-message]');\n var hint = document.querySelector('[data-app-hint]');\n\n // WHICH RUN, as an attribute rather than as prose. Identity is not run STATE (D-11 forbids the\n // second, not the first), and it enters through setAttribute from an escaped literal, so a run\n // id can never become markup no matter what it spells.\n root.setAttribute('data-app-run-id', runId);\n\n // The state machine is an ATTRIBUTE plus two textContent writes, exactly as the embed page's is:\n // a state a person can read off the DOM is a state a cell can assert without screenshotting, and\n // text that arrives through textContent can never become markup.\n function setState(state) {\n root.setAttribute('data-app-state', state);\n message.textContent = messages[state] || '';\n hint.textContent = hints[state] || '';\n }\n\n // ---- The minimal ui/initialize handshake (ext-apps spec shape) -------------------------------\n //\n // HAND-ROLLED AND DELIBERATELY ISOLATED IN THIS ONE BLOCK. The ext-apps package\n // declares a peer on the v1 monolith SDK, so importing its app-bridge into production would drag\n // a second SDK generation in (Pitfall 3) — and this page has no bundler anyway. RESEARCH\n // assumption A5 rated the method-name and field spellings MEDIUM (single spec fetch), and plan\n // 02's coverage entry D9 deferred the adjudication to plan 06.\n //\n // PLAN 06 MEASURED IT, AND IT HAD DRIFTED. Against the installed\n // @modelcontextprotocol/ext-apps@1.7.5's own generated schema, McpUiInitializeRequest.params\n // requires THREE members: protocolVersion, appInfo and appCapabilities. This block sent only the\n // first, so a host validating the request against the published schema would have rejected the\n // handshake outright, and the failure would have looked like a host that simply does not support\n // Apps. The two missing members are now sent, and ext-apps-constants.test.ts cell (4d) derives\n // the required list FROM the shipped schema rather than restating it, so the next spec change\n // reds here instead of on a user's machine.\n //\n // IT STILL ASKS FOR NOTHING. appCapabilities is deliberately empty: this document exposes no\n // tools, requests no display mode and declares no experimental feature (the schema requires no\n // member of it). No permissions, no re-mint (D-10) — it announces that this document is ready,\n // which is all a wrapper that renders no run state of its own has to say.\n try {\n if (window.parent !== window) {\n window.parent.postMessage({\n jsonrpc: '2.0',\n id: 'ui-init-1',\n method: 'ui/initialize',\n params: {\n protocolVersion: ${scriptLiteral(APP_WRAPPER_UI_PROTOCOL_VERSION)},\n appInfo: { name: ${scriptLiteral(APP_WRAPPER_APP_NAME)}, version: ${scriptLiteral(APP_WRAPPER_APP_VERSION)} },\n appCapabilities: {}\n }\n }, '*');\n }\n } catch (e) { /* a host that refuses the message changes nothing about what this page shows */ }\n\n if (mints.length === 0) {\n // Either D-07's honest terminal/unknown state or D-10's expired one — both were decided by the\n // RENDERER and are already in the markup. No src was ever assigned, so there is no blank frame\n // to mistake for a stalled one, and nothing below this line can move the document off them.\n return;\n }\n\n // ---- Reachability, once per ORIGIN (see the header's measured note) ---------------------------\n //\n // Memoised deliberately, and ONLY ON SUCCESS. The picker swaps among panes that share one\n // origin, so after the first ANSWERING pane every swap is served from this map and issues NO\n // network request at all (D-06/D-10's zero re-mints, zero calls, which the DOM cell counts) — a\n // property that rides entirely on caching the true. The catch arm therefore FORGETS the entry\n // before answering false: a refusal is a fact about one moment, not about the origin, and every\n // mint on a render shares one origin, so a cached false was total and permanent. See the header.\n var reach = {};\n function reachable(url) {\n var origin;\n try { origin = new URL(url).origin; } catch (e) { return Promise.resolve(false); }\n if (reach[origin] === undefined) {\n reach[origin] = fetch(origin + '/', { mode: 'no-cors', cache: 'no-store' })\n .then(function () { return true; })\n .catch(function () { delete reach[origin]; return false; });\n }\n return reach[origin];\n }\n\n var attachId = 0;\n\n function attach(mint) {\n // THE EXPIRED STATE IS TERMINAL, AND THIS IS THE ONE PLACE IT COULD BE LEFT (D-10). The\n // picker's change handler — and nothing else — can reach this function after the one-shot\n // expiry timer has fired; without this line the next statements would set the connecting state\n // and assign an aged token over a document that had already told the truth, and no timer would\n // ever correct it. The identical predicate inside settle() stays where it is: it closes the\n // OTHER door, a probe or a frame load that was already in flight when the timer fired, so\n // neither guard makes the other dead.\n if (root.getAttribute('data-app-state') === 'expired') return;\n var mine = (attachId += 1);\n var loaded = false;\n var settled = false;\n\n function settle(state) {\n if (settled || mine !== attachId) return;\n if (root.getAttribute('data-app-state') === 'expired') return;\n settled = true;\n setState(state);\n }\n\n setState('connecting');\n // THE ONLY PLACE A TOKEN IS WRITTEN. It goes into the frame's src and nowhere else.\n frame.src = mint.url;\n\n frame.addEventListener('error', function () { settle('unreachable-origin'); }, { once: true });\n frame.addEventListener('load', function () {\n // NECESSARY, NOT SUFFICIENT: Chromium fires this for a refused connection too (header note),\n // so the probe is what decides — a frame that loaded on an origin nothing answered for is an\n // error page, and calling that 'live' is the failure this arm exists to prevent.\n loaded = true;\n reachable(mint.url).then(function (ok) { settle(ok ? 'live' : 'unreachable-origin'); });\n }, { once: true });\n\n reachable(mint.url).then(function (ok) {\n if (!ok) settle('unreachable-origin');\n else if (loaded) settle('live');\n });\n\n // D-11's REQUIRED arm for the origin that never answers at all: a black-holed host fires no\n // error and never loads, so silence past this bound is itself the signal, named rather than\n // left as a spinner.\n setTimeout(function () { settle('unreachable-origin'); }, loadTimeoutMs);\n }\n\n // D-10: the deadline was computed at RENDER time and arrives as a delta, so the host's own clock\n // never enters the comparison. When it fires the document says so and stops — nothing here mints.\n if (expiresInMs > 0) {\n setTimeout(function () {\n attachId += 1;\n // Unconditional: the script returned above when mints was empty, and a non-empty mints is\n // exactly the condition under which the renderer emits the iframe, so there is no reachable\n // state in which this callback runs without a frame to strip.\n frame.removeAttribute('src');\n // The picker is an affordance of the EMBEDDED variant; when the variant is gone the\n // affordance goes with it, so the control a person can reach and the state the document is in\n // cannot disagree.\n picker.setAttribute('disabled', '');\n setState('expired');\n }, expiresInMs);\n }\n\n // D-06/D-10: the picker swaps among tokens ALREADY minted for this render. It never mints, and\n // there is no bridge here that could ask anyone to — a fresh watch call is what re-mints.\n for (var i = 0; i < mints.length; i += 1) {\n var option = document.createElement('option');\n option.value = String(i);\n option.textContent = 'handle ' + mints[i].handle;\n picker.appendChild(option);\n }\n if (mints.length > 1) picker.removeAttribute('hidden');\n picker.addEventListener('change', function () {\n var chosen = mints[Number(picker.value)];\n if (chosen !== undefined) attach(chosen);\n });\n\n attach(mints[0]);\n}());\n</script>\n</body>\n</html>\n`\n}\n","// The PERMANENT link-out to the dashboard's live page (Phase 408 plan 03, D-08 / D-09 · MCPA-01).\n//\n// WHY THIS FILE EXISTS. `app-resource.ts` is the App channel: it mints a short-lived credential and\n// hands it to a host that negotiated the Apps extension. This file is the OTHER half of the same\n// promise, and it is the half that has to work everywhere. D-09 rules that the link-out rides EVERY\n// carrier result — for an App-capable host and an App-less one alike — which is what makes \"never a\n// broken embed\" a structural property rather than something anybody detects. A host that renders no\n// App still receives a working address a person can open; a host that renders the App receives both,\n// so a person can still pop out to the full two-pane dashboard surface.\n//\n// THE LINK IS TOKENLESS, AND THAT IS THE WHOLE OF D-08. It targets `/runs/:id/live` — the page the\n// dashboard already serves, which mints its OWN `liveUrl` locally when somebody opens it while the\n// run is going, and shows 403 D-12's terminal state with the run-detail affordance afterwards. So\n// \"permanent\" is honest: the page outlives the token by construction. The two rejected shapes are\n// worth naming, because both are what a reader would reach for first. A raw tokened embed URL is\n// dead in five minutes, dead with the process that minted it, and is a live credential parked in a\n// conversation transcript — T-408-12 exactly. A run-detail link is durable and never live, so it\n// answers a different question than the one the line is offered for.\n//\n// ONE COMPOSED STRING, AND THAT IS WHY THERE IS NO BUILDER HERE. D-08 rates the link REVERSIBLE\n// precisely because it is one composition of a base and a run id; a link object, a route table or a\n// second addressing vocabulary would each make it something a later phase has to migrate rather\n// than re-spell.\n//\n// THE BASE IS SUPPLIED, NEVER DISCOVERED HERE. Which base is correct is a COMPOSITION fact — the\n// operator's configured `services.dashboard.baseUrl` first, this process's own bound origin second\n// (`commands/dashboard.ts`'s overlay law: the overlay fills an ABSENCE and never replaces a\n// presence, because a configured base is somebody pointing at a reverse proxy, a tunnel or a path\n// prefix). This package holds no config reader and no server, so it takes the answer as a supplier\n// and never as a string: on the dashboard host the origin does not exist until a port is bound.\n//\n// AND WHEN THERE IS NO BASE ANYWHERE, THE LINE IS A NAMED ABSENCE (RESEARCH Open Question 3). A\n// standalone `agent-qa mcp` with no configured dashboard has nothing to link to, and a fabricated\n// URL there would be exactly the dishonesty this milestone removes: a link that reads as an\n// affordance and answers nothing. `LIVE_LINK_ABSENT_LINE` says what is missing and names the config\n// knob that supplies a base, and contains no address at all.\n//\n// AND THERE ARE TWO ABSENCES, NOT ONE (2026-09-01, plan 10, WR-03 · T-408-22). A missing base and a\n// missing run id are different facts with different remedies, so they carry different sentences —\n// `LIVE_LINK_ABSENT_LINE` and `LIVE_LINK_NO_RUN_LINE`. Collapsing them is how a host that HAD a\n// dashboard configured came to be told, on a model-readable channel, to configure it.\n//\n// Protocol grounding. SEP-1730 puts extensions outside every conformance tier — a host owes the\n// Apps extension nothing — which is the protocol-level reason this line exists at all: the ONLY\n// thing every host is obliged to render is a tool result's text, so the affordance that must never\n// break has to ride there. SEP-2575 (the stateless protocol) is why the line is composed per result\n// rather than announced once at connection: there is no session to have told a client about a base\n// in. SEP-2549's cache hints are irrelevant to it by the same token — the line carries no\n// credential and no freshness claim, so it neither needs nor offers one.\n\n/**\n * The tokenless dashboard live page for one run: `<base>/runs/<runId>/live` (D-08).\n *\n * TRAILING SLASHES ARE COLLAPSED rather than tolerated. An operator writing\n * `baseUrl: http://dash.internal/` is writing the same base as one who did not, and a `//` in the\n * middle of a path is a different path to some proxies — so the composition normalises instead of\n * producing two addresses for one dashboard.\n *\n * THE RUN ID IS PERCENT-ENCODED, which is a no-op for every id this system mints (`runIdSchema`\n * refuses any id the path layer would have to rewrite) and is written anyway: this function is\n * exported, and a caller composing a link for an id that came from somewhere else should not be the\n * one place a path segment escapes unencoded.\n */\nexport function liveRunLinkOf(base: string, runId: string): string {\n return `${base.replace(/\\/+$/u, '')}/runs/${encodeURIComponent(runId)}/live`\n}\n\n/**\n * The human-readable line a carrier result carries when a base exists.\n *\n * AN EXPORTED TEMPLATE RATHER THAN A STRING EACH CALL SITE COMPOSES, so a cell asserts the SAME\n * sentence the surface prints. Two carriers and two hosts print this; four hand-written spellings\n * would be four things to keep in step, and the drift would be invisible because nobody diffs two\n * tool results.\n *\n * IT NAMES BOTH READINGS OF THE ONE PAGE — watching a run that is going, and reviewing one that has\n * finished — because the address is the same either way and a line that promised only \"live\" would\n * read as broken the moment the run ended, which is precisely when a person follows it.\n */\nexport function liveLinkLine(url: string): string {\n return `watch live or review: ${url}`\n}\n\n/**\n * What a carrier result says when no dashboard base exists ANYWHERE (RESEARCH Open Question 3).\n *\n * It names the config knob an operator sets to point this host at a dashboard (the 387 D-10\n * mechanism). It contains no URL — an absence that fabricated an address would be worse than no\n * line at all.\n */\nexport const LIVE_LINK_ABSENT_LINE = 'no dashboard configured — set services.dashboard.baseUrl'\n\n/**\n * What a carrier result says when a dashboard base EXISTS but this result names no run to link to\n * (2026-09-01, Phase 408 plan 10, WR-03 · T-408-22).\n *\n * A SECOND NAMED ABSENCE, BECAUSE THERE ARE TWO DISTINCT FACTS. `carrierRunIdOf`\n * (`catalog.ts`) is DEFENSIVE ON BOTH ARMS by design and can honestly answer `undefined` — the\n * `runIdFrom: 'output'` arm reads an op's own result, which is a `RunStartAcknowledgement` today\n * and could be a fold's arm tomorrow, and the documented treatment of a shape it cannot read is a\n * named absence rather than a crash. Until this constant existed, that arm printed\n * `LIVE_LINK_ABSENT_LINE` — so a host that HAS `services.dashboard.baseUrl` set told the caller,\n * and the model reading the result, to set a value already set and pointed at the wrong knob. That\n * is a FALSE STATEMENT on a model-readable channel in a milestone whose law is honest absence, and\n * a wrong sentence is worse than a vague one because a model will act on it.\n *\n * IT NAMES NO CONFIG KNOB, deliberately: there is nothing for the operator to set. The dashboard is\n * configured; this particular result simply is not about a run. And it CONTAINS NO URL, the same\n * property `LIVE_LINK_ABSENT_LINE` above is held to — an absence that fabricated an address would\n * be the dishonesty this file exists to remove.\n */\nexport const LIVE_LINK_NO_RUN_LINE\n = 'no run to link to — this result names no run id'\n\n/**\n * How a HOST answers \"which dashboard is this process pointed at\".\n *\n * A FACTORY, NOT A STRING, on `commands/dashboard.ts`'s own reasoning about the same value: the\n * server has not bound a port when the host is composed, and an ephemeral port (`port: 0`) is a\n * real posture in this suite and in tests. A value captured at composition time would be a guess; a\n * factory read per result is the truth.\n *\n * `undefined` is the degenerate case rather than a second branch: a host that supplies no supplier\n * at all and a supplier that answers `undefined` are the same fact — no dashboard — and they take\n * the same path to the same line.\n */\nexport interface LiveLinkSupplier {\n readonly dashboardBaseUrl: () => string | undefined\n}\n\n/**\n * The one line a carrier result carries, given whatever the host's supplier answers.\n *\n * COMPOSED HERE so the \"base or named absence\" decision has exactly one implementation. It is the\n * decision the whole file exists for, and a second copy of it — in the catalog, in a command, in a\n * later carrier — is the copy that fabricates a URL from an empty string.\n *\n * A BLANK BASE IS AN ABSENT BASE. A configured `baseUrl: \"\"` (or a whitespace-only one) is somebody\n * who has not pointed this host anywhere, and composing `\"/runs/x/live\"` from it would produce a\n * relative fragment that reads as a link in a transcript and resolves against nothing.\n *\n * THE GUARD ORDER IS THE FIX, NOT AN ACCIDENT (2026-09-01, plan 10, WR-03). The BASE is tested\n * first: with no base anywhere, \"no dashboard configured\" is the true and the more actionable\n * sentence whatever the run id is, so the both-absent case answers with the fact an operator can do\n * something about. Only with a base PRESENT does a missing run id become the fact worth naming, and\n * that arm answers `LIVE_LINK_NO_RUN_LINE`. Swapping these two lines back reinstates the false\n * sentence a configured host used to receive.\n */\nexport function liveLinkLineFor(\n base: string | undefined,\n runId: string | undefined,\n): string {\n if (base === undefined || base.trim() === '') return LIVE_LINK_ABSENT_LINE\n if (runId === undefined || runId === '') return LIVE_LINK_NO_RUN_LINE\n return liveLinkLine(liveRunLinkOf(base.trim(), runId))\n}\n","// The server's initialize instructions (433-33, G-433-9 · F-433-36): init's pointer, delivered by\n// the one channel every MCP host receives. agent-qa never writes CLAUDE.md (431 D-20). Static text\n// on purpose: nothing from the workspace or the caller is interpolated. Protocol grounding: on the\n// stateless revision there is no initialize handshake (SEP-2575), and the SDK answers the same\n// text in the discovery result, so a host reaches it on either revision.\n\nexport const AGENT_QA_MCP_INSTRUCTIONS: string = [\n 'This project is tested with agent-qa. Read its runs and knowledge only through the agent_qa_* '\n + 'tools on this server, or the agent-qa CLI with --json.',\n 'Never open .agent-qa/, SQLite files, agent-qa-knowledge/memory/index/, memory/queue/, .lease or '\n + '.epoch, and never list, glob or search those folders: they are agent-qa\\'s runtime state.',\n 'Start with agent_qa_list_runs, then agent_qa_get_run_overview for one run.',\n 'The knowledge guide is agent-qa-knowledge/AGENTS.md; `npx agent-qa skills` lists the skills and '\n + 'their folder.',\n].join('\\n')\n","// The declared tool -> op mapping (Phase 396 plans 01 + 04, D-01 / D-03 / D-04 / D-16 · MCPS-02).\n//\n// WHY THIS FILE EXISTS. The v1 server carried its catalogue as 33 hand-written handlers, each free\n// to reach data its own way; the whole point of the re-derivation is that a tool is a PROJECTION of\n// a registry op and nothing else. What is left over once the handlers are gone is DATA — which tool\n// names exist, which op ids each one stands in front of, and what class of thing it does — and this\n// module is where that data lives so a single artifact can be pinned by the bump guard and ranged\n// over by 397's parity suite. Anything that is not data belongs in `projection.ts` or `catalog.ts`.\n//\n// 2026-09-15, 423-21 D-04/D-18: sixteen tools over twenty-six registry ops; the other TWENTY-FIVE\n// ops are listed below in `UNPROJECTED_OPS` with a reason each. Twenty-six plus twenty-five is the\n// registry's own count, and `__tests__/mapping-bump-guard.test.ts` asserts that partition against\n// the registry's enumeration rather than against the arithmetic in this sentence. The two new\n// tools are the feedback reads (marks history and the mark consequence preview); the typed\n// evidence read lands unprojected on `runs.detail`'s completed-run footing.\n//\n// 2026-09-25 (428 D-07): the unprojected side grows to TWENTY-SIX when `editor.liveurl` is\n// registered; the projected side and the tool count do not move. The editor subject's mint is\n// reachable only through the dashboard door, by ruling.\n//\n// 2026-09-28 (431-04 D-01/D-04/D-10): TWENTY-FOUR tools over THIRTY-FIVE registry ops; the other\n// EIGHTEEN stay in `UNPROJECTED_OPS`, and the registry is fifty-three. `runs.overview` arrives\n// projected, and eight reads move across: the five knowledge reads, `runs.knowledge`, and\n// `runs.evidence` with `runs.artifact` behind one fold. Their prior rulings are kept verbatim in\n// `PROJECTED_RULING_ADDENDA`, each with its dated 431 addendum.\n//\n// 2026-09-30 (432-12 D-05/D-02): TWENTY tools over THIRTY registry ops; the other TWENTY-THREE stay\n// in `UNPROJECTED_OPS`, and the registry is still fifty-three. The two change tools are renamed\n// `agent_qa_change_knowledge` and `agent_qa_change_config` and write in the call. The four proposal\n// apply/list/show tools and the config undo arm are gone with no alias, and their five ops are\n// dispositioned below until 432-17 deletes them from the registry.\n//\n// 2026-10-01 (432-17 D-05/D-02): TWENTY tools over THIRTY registry ops; the other SIXTEEN stay in\n// `UNPROJECTED_OPS`, and the registry is forty-six. The seven proposal, apply and undo ops are\n// deleted from the registry, so their five '432' dispositions and the two 397 dispositions of\n// `proposals.accept` and `proposals.reject` leave the scoping note, and '432' leaves the adjudicator\n// vocabulary with no member left to rule on.\n//\n// 2026-10-01 (432-18 D-14/D-15), written 2026-10-03 (quick-261003-tsr IN-28): TWENTY tools over\n// THIRTY registry ops; the other FOURTEEN stay in `UNPROJECTED_OPS`, and the registry is forty-four.\n// `grants.list` and `grants.revoke` are deleted with the grant ledger.\n//\n// 2026-08-17 (398 D-09): the unprojected side moved from nineteen to twenty when `agent.explain`\n// was registered. This sentence is prose and the guard is the mechanism — but the prose is updated\n// in the same change-set anyway, because a header that goes on stating a partition the code stopped\n// having is the class of untruth the ops' own docstrings were caught in (397 D-18).\n//\n// 2026-08-29 (407-01 D-05): the unprojected side grows again, and the registry with it, when\n// `runs.knowledge` is registered — so the partition holds with both sides one larger. Unprojected\n// DELIBERATELY and on `runs.detail`'s footing: a completed run's whole used-and-learned projection\n// is a large one-shot payload, not a mid-flight read. The guard is the mechanism; this sentence is\n// updated in the same change-set for the reason the paragraph below states.\n//\n// 2026-08-25 (403-01 D-03): twenty to twenty-one, and the registry from forty-two to forty-three,\n// when `runs.liveurl` was registered. Unprojected DELIBERATELY: minting a live-view capability\n// token is handing out a credential, and whether an MCP caller may mint one is Phase 408's\n// question (the MCP App embed) rather than a side effect of this phase registering the op.\n//\n// 2026-08-31 (408 D-01): that question is ANSWERED and the partition does not move for it. The\n// ruling is internal mint only — the App-rendering path invokes `runs.liveurl` by reference and\n// the token reaches a person only through host-rendered HTML — so the op stays on the\n// unprojected side, now by RULING rather than by deferral. Recorded here, at the entry, and at\n// the conformance row, because a deferral that quietly becomes a permanent absence is the same\n// untruth as a partition the code stopped having.\n// 2026-09-01 (408-08, the gap round, road `demote`): the partition still does not move, and the\n// em-dashed half above is corrected in the same place it was claimed. \"The token reaches a person\n// only through host-rendered HTML\" is a statement about what the CALLER does with a document it\n// asked for, not about this server. What this server does is write the token into exactly one\n// place — the frame src of the document the `ui://` read serves — and that door is bounded by the\n// `read` scope an operator granted the caller plus a bound mint, never by the caller's own\n// capability declaration. The entry's own reason carries the full addendum; `app-resource.ts`'s\n// header carries the ruling. The op stays unprojected on the same, stronger footing.\n//\n// Protocol grounding: SEP-2567 removed per-connection list variance, so the tool NAMES a caller can\n// see are a property of the caller's grants and of this table — never of a session. SEP-2549 makes\n// those listings cacheable, which is the other half of the same reason the table is static data.\n\nimport type { StandardSchemaWithJSON } from '@modelcontextprotocol/server'\nimport {\n AuthoringDraftEditInputSchema,\n AuthoringDraftEditOutputSchema,\n AuthoringDraftWriteInputSchema,\n AuthoringDraftWriteOutputSchema,\n AuthoringRefineFoldInputSchema,\n AuthoringRefineFoldOutputSchema,\n AuthoringVerifyDraftInputSchema,\n AuthoringVerifyDraftOutputSchema,\n BriefWhyInputSchema,\n BriefWhyResultSchema,\n ConfigAuthSetInputSchema,\n ConfigChangeFoldInputSchema,\n ConfigChangeFoldOutputSchema,\n ConfigChangeOutputSchema,\n ConfigFieldSetInputSchema,\n ConfigHookAddInputSchema,\n ConfigProjectScaffoldInputSchema,\n ConfigTargetCreateInputSchema,\n ConfigTargetEditInputSchema,\n EntitiesGetInputSchema,\n EntitiesResolveInputSchema,\n EntityCardResolutionSchema,\n EntityCardSchema,\n KnowledgeAcceptChangeInputSchema,\n KnowledgeBundlesListInputSchema,\n KnowledgeBundlesListOutputSchema,\n KnowledgeChangeFoldInputSchema,\n KnowledgeChangeFoldOutputSchema,\n KnowledgeForgetChangeInputSchema,\n KnowledgeGatesListInputSchema,\n KnowledgeGatesListResultSchema,\n KnowledgeChangeOutputSchema,\n KnowledgeRecordShowInputSchema,\n KnowledgeRecordShowResultSchema,\n KnowledgeRecordsDiffInputSchema,\n KnowledgeRecordsDiffOutputSchema,\n KnowledgeRecordsInspectInputSchema,\n KnowledgeRecordsInspectOutputSchema,\n KnowledgeRejectChangeInputSchema,\n RunDigestSchema,\n RunKnowledgeProjectionSchema,\n RunOverviewProjectionSchema,\n RunStartAcknowledgementSchema,\n RunsArtifactInputSchema,\n RunsArtifactOutputContract,\n RunsDigestInputSchema,\n RunsEvidenceFoldInputSchema,\n RunsEvidenceFoldOutputContract,\n RunsEvidenceInputSchema,\n RunsEvidenceOutputContract,\n RunsKnowledgeInputSchema,\n RunsListInputSchema,\n RunsListOutputContract,\n RunsMarkInputSchema,\n RunsMarkOutcomeSchema,\n RunsMarkPreviewResultSchema,\n RunsMarksHistoryInputSchema,\n RunsMarksHistoryResultSchema,\n RunsOverviewInputSchema,\n RunsStartInputSchema,\n TOOL_FOLD_DISCRIMINANT,\n} from '@vostride/agent-qa-schema'\n\n/**\n * What a tool DOES, coarsely — the axis annotations are derived along (`projection.ts`).\n *\n * `read` answers; `workflow` changes something in the call (a test file, a run, knowledge,\n * configuration). `apply` is the sovereign mark door alone: since 432-12 (D-05/D-14) no tool files a\n * proposal and no tool asks for a confirmation, and `apply` names only the mark door, which lands a\n * mark's gold, evidence and fix in the call. Its credential check left with the MCP bearer\n * credential (432-21, D-12), so `apply` is now a name for that one door and gates nothing.\n *\n * KEPT, DATED 2026-10-02 (432-42 census decision): the member is not renamed. It is a published MCP\n * contract value (`mapping-bump-guard.test.ts` pins `kind: 'apply'` on `agent_qa_mark_run`, and the\n * projection derives annotations from it); no D-decision renames a published name here, and the\n * word now means \"the mark door applies its fix in the call\", which is true. It asks nothing.\n */\nexport type ToolProjectionKind = 'read' | 'workflow' | 'apply'\n\n/**\n * How a tool's arms compose — DERIVED from the entry, never stated a second time on it.\n *\n * `single` is a 1:1 projection. `union` is D-01's declared fold: several sibling ops behind one\n * discriminated-union input, the arm selected by a literal. `pipeline` is D-02's one read door:\n * two ops invoked in sequence, the first one's answer choosing whether the second runs at all.\n *\n * A third field on the entry would have been a third thing to keep in step with the first two, and\n * the failure it would have hidden is a fold declared `single` — which registers a tool advertising\n * one arm's contract while the guard reports two arms and agrees with itself.\n */\nexport type ToolComposition = 'single' | 'union' | 'pipeline'\n\n/** The tool-listing `_meta` key a host reads as the largest result it should keep (ADX-03). */\nexport const MAX_RESULT_SIZE_META_KEY = 'anthropic/maxResultSizeChars'\n\n/** 431 D-05: the size hint the three whole-run reads carry. */\nexport const RUN_READ_MAX_RESULT_SIZE_CHARS = 100000\n\n/** One declared tool. */\nexport interface ToolProjection {\n /** Curated `verb_noun` name per spec section 3.3 (D-04). The bump guard pins the exact list. */\n readonly name: string\n /** The registry op ids this tool projects. Length 1 = 1:1; length > 1 = a declared fold. */\n readonly ops: readonly string[]\n readonly kind: ToolProjectionKind\n // 2026-10-01 (432-21, D-12): the `credential?: 'required'` marker (419 D-20) is deleted with the\n // MCP bearer credential. No tool declares a credential and no handler reads one.\n /**\n * A union fold's discriminant key — absent on a 1:1 tool AND on the pipeline.\n *\n * Its presence is what tells a fold from a pipeline, which is why it is spelled per entry rather\n * than assumed from `ops.length > 1`.\n */\n readonly discriminant?: string\n /**\n * This tool CARRIES the live-view MCP App (2026-08-31, Phase 408 plan 01 · D-05 / MCPA-01).\n *\n * ITS PRESENCE IS THE SIGNAL, exactly as `discriminant`'s above is. A carrier is a tool whose\n * declaration references the `ui://` App resource, so a host that negotiated the Apps extension\n * can render the run's live view beside the result; a tool without this member references\n * nothing, and `projection.ts` derives an ABSENT `_meta` for it rather than an empty one. Spelled\n * per entry rather than inferred from a name, a kind or an op id, because the census that\n * enumerates carriers reads THIS field — and a predicate over names would be a second, unwritten\n * declaration of which doors reach a credential channel (the 399.1 lesson).\n *\n * `resource` names which `ui://` template the reference points at; one template exists today and\n * the field is spelled anyway, so a second App is an added member here rather than a second\n * meaning for a boolean.\n *\n * `runIdFrom` names where the CONCRETE runId for a per-call reference is found — on the call's\n * input or in the op's own result. `agent_qa_start_run` answers a `RunStartAcknowledgement`\n * carrying the id the run was given, so its reference is derivable only from the OUTPUT;\n * `agent_qa_get_run_digest` is asked about a run by id, so its reference is derivable from the\n * INPUT, which is what makes it the late-attach door (D-07).\n *\n * THE TASK-SHAPE QUESTION D-05 LEFT OPEN IS CLOSED, and closed by measurement rather than by\n * preference: the task seam is dormant — \"It registers nothing, advertises nothing and routes\n * nothing\" (task-seam.ts:21-23, and catalog.ts:34-36 states the matching absence) — so both\n * carriers are plain tools answering immediate results, and there is no task completion or\n * status poll for a reference to ride. (2026-08-31; the 2.0.0 core SDK has since grown the Tasks\n * vocabulary, which makes the seam's own dated deferral stale at the SDK layer and changes\n * nothing here: registering Tasks is not this phase's job.)\n */\n readonly ui?: {\n readonly resource: 'live-run'\n readonly runIdFrom: 'input' | 'output'\n }\n /**\n * 2026-09-28 (431 D-05): the result-size hint, advertised as `_meta[MAX_RESULT_SIZE_META_KEY]`.\n * Present only on reads whose one-shot answer can outgrow a host's default result budget.\n */\n readonly maxResultSizeChars?: number\n}\n\n/** The composition, read off the entry. See {@link ToolComposition}. */\nexport function compositionOf(projection: ToolProjection): ToolComposition {\n if (projection.ops.length === 1) return 'single'\n return projection.discriminant === undefined ? 'pipeline' : 'union'\n}\n\n/**\n * The live input/output contracts of one projected op.\n *\n * WHY THIS TABLE EXISTS AT ALL, since it looks like a second declaration of something the registry\n * already knows. It is not: `FunctionSpec` — the record holding the LIVE validators — deliberately\n * never leaves the function layer's own directory (T-384-01 / T-384-14), and what a surface can see\n * through `registry.list(caller)` is a `FunctionDeclaration` whose `input`/`output` are already\n * INERT JSON-Schema projections. D-16 mechanic (a) needs the live Standard-Schema objects, so the\n * projection names them here, imported from the ONE module the ops themselves import them from.\n * Drift is therefore impossible in the only sense that matters: this is not a copy of the contract,\n * it is the same object, so the schema advertised in `tools/list` and the schema `invokeFunction`\n * validates with are one thing that cannot disagree.\n *\n * The alternative — `fromJsonSchema(declaration.output)` — was available and rejected: it is a\n * SECOND conversion recipe beside the SDK's own, and the anti-pattern this phase's research names\n * first is exactly two recipes for one conversion.\n *\n * The field type is the SDK's `StandardSchemaWithJSON` and NOT a zod type, which is the same\n * decision seen from the other side: this package's runtime dependency allow-list is exactly the\n * two protocol packages (D-20), so naming a validator library here — even in a type position, which\n * the dependency lint reads no differently — would reopen the collapse the phase exists to make.\n * A zod 4.4 schema satisfies the interface, which is the whole of what either side needs to know.\n */\nexport interface ToolOpContracts {\n readonly input: StandardSchemaWithJSON\n readonly output: StandardSchemaWithJSON\n}\n\n/**\n * Op id -> its live contracts, for every op any declared projection names.\n *\n * `catalog.ts` refuses to build a tool whose op is missing from it, so the two tables can never\n * drift apart silently.\n */\nexport const AGENT_QA_OP_CONTRACTS: Readonly<Record<string, ToolOpContracts>> = Object.freeze({\n 'runs.mark': Object.freeze({ input: RunsMarkInputSchema, output: RunsMarkOutcomeSchema }),\n // 2026-09-15, 423-21 D-18: the feedback reads keep their ops' own strict contracts. The preview\n // takes runs.mark's exact input and answers the read-only plan result.\n 'runs.marks.history': Object.freeze({\n input: RunsMarksHistoryInputSchema,\n output: RunsMarksHistoryResultSchema,\n }),\n 'runs.mark.preview': Object.freeze({ input: RunsMarkInputSchema, output: RunsMarkPreviewResultSchema }),\n 'knowledge.gates.list': Object.freeze({\n input: KnowledgeGatesListInputSchema,\n output: KnowledgeGatesListResultSchema,\n }),\n 'authoring.draft.write': Object.freeze({\n input: AuthoringDraftWriteInputSchema,\n output: AuthoringDraftWriteOutputSchema,\n }),\n 'authoring.draft.edit': Object.freeze({\n input: AuthoringDraftEditInputSchema,\n output: AuthoringDraftEditOutputSchema,\n }),\n 'authoring.draft.verify': Object.freeze({\n input: AuthoringVerifyDraftInputSchema,\n output: AuthoringVerifyDraftOutputSchema,\n }),\n 'runs.start': Object.freeze({\n input: RunsStartInputSchema,\n output: RunStartAcknowledgementSchema,\n }),\n 'config.field.set': Object.freeze({\n input: ConfigFieldSetInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.target.create': Object.freeze({\n input: ConfigTargetCreateInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.target.edit': Object.freeze({\n input: ConfigTargetEditInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.auth.set': Object.freeze({\n input: ConfigAuthSetInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.hook.add': Object.freeze({\n input: ConfigHookAddInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.project.scaffold': Object.freeze({\n input: ConfigProjectScaffoldInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n // 2026-09-30 (432-12 D-05): the three knowledge changes answer what they applied.\n 'knowledge.accept': Object.freeze({\n input: KnowledgeAcceptChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'knowledge.reject': Object.freeze({\n input: KnowledgeRejectChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'knowledge.forget': Object.freeze({\n input: KnowledgeForgetChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'entities.resolve': Object.freeze({\n input: EntitiesResolveInputSchema,\n output: EntityCardResolutionSchema,\n }),\n 'entities.get': Object.freeze({\n input: EntitiesGetInputSchema,\n output: EntityCardSchema,\n }),\n // 2026-09-28 (431-03, D-03/D-07): the canonical list contract — `RunsListOutputSchema` as the\n // validator, the same object `runs.list` enforces with, plus its explicit output document.\n 'runs.list': Object.freeze({\n input: RunsListInputSchema,\n output: RunsListOutputContract,\n }),\n 'runs.digest': Object.freeze({\n input: RunsDigestInputSchema,\n output: RunDigestSchema,\n }),\n // 2026-09-28 (431-04 D-04/D-05/D-07): the eight reads keep their ops' own contracts. The\n // evidence arms use the canonical output contracts, whose validators are the runtime schemas.\n 'knowledge.bundles.list': Object.freeze({\n input: KnowledgeBundlesListInputSchema,\n output: KnowledgeBundlesListOutputSchema,\n }),\n 'knowledge.records.inspect': Object.freeze({\n input: KnowledgeRecordsInspectInputSchema,\n output: KnowledgeRecordsInspectOutputSchema,\n }),\n 'knowledge.records.diff': Object.freeze({\n input: KnowledgeRecordsDiffInputSchema,\n output: KnowledgeRecordsDiffOutputSchema,\n }),\n 'knowledge.record.show': Object.freeze({\n input: KnowledgeRecordShowInputSchema,\n output: KnowledgeRecordShowResultSchema,\n }),\n 'knowledge.brief.why': Object.freeze({\n input: BriefWhyInputSchema,\n output: BriefWhyResultSchema,\n }),\n 'runs.knowledge': Object.freeze({\n input: RunsKnowledgeInputSchema,\n output: RunKnowledgeProjectionSchema,\n }),\n 'runs.overview': Object.freeze({\n input: RunsOverviewInputSchema,\n output: RunOverviewProjectionSchema,\n }),\n 'runs.evidence': Object.freeze({\n input: RunsEvidenceInputSchema,\n output: RunsEvidenceOutputContract,\n }),\n 'runs.artifact': Object.freeze({\n input: RunsArtifactInputSchema,\n output: RunsArtifactOutputContract,\n }),\n})\n\n/**\n * THE CATALOGUE. Twenty tools, and the bump guard pins this exact list by name and by op set.\n * (Sixteen until 2026-09-28, when 431 D-01 added the eight discovery reads; twenty-four until\n * 2026-09-30, when 432-12 removed the four proposal tools.)\n *\n * The read side is D-02: one universal entity door plus the reads a workflow needs mid-flight and\n * the 431 discovery reads. The write side changes things IN THE CALL (432 D-05/D-14): every\n * `workflow` entry writes what it names and answers what it changed, and nothing waits for a second\n * call. There is no apply tool, no `confirmed` input and no elicitation; the mark door is the one\n * `apply` entry, and since 432-21 (D-12) it checks no credential.\n *\n * WHY THERE IS NO PROPOSAL TOOL AT ALL. The inbox's verbs declared a human-origin requirement, so a\n * tool over either decision verb would have listed for every caller and refused every call; the\n * bump guard stated the rule generally until 432-39 deleted the field. 432-12 unprojected the whole\n * inbox and 432-17 deleted it, ops and all (re-spelled 2026-10-02, 432-42).\n */\nexport const AGENT_QA_TOOL_PROJECTIONS: readonly ToolProjection[] = Object.freeze([\n Object.freeze({\n name: 'agent_qa_write_test',\n ops: Object.freeze(['authoring.draft.write']),\n kind: 'workflow',\n }),\n Object.freeze({\n name: 'agent_qa_refine_test',\n ops: Object.freeze(['authoring.draft.edit', 'authoring.draft.verify']),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n Object.freeze({\n name: 'agent_qa_start_run',\n ops: Object.freeze(['runs.start']),\n kind: 'workflow',\n // 408 D-05: a run starts and is immediately watchable. The ack carries the runId, so the\n // per-call reference is derived from the OUTPUT.\n ui: Object.freeze({ resource: 'live-run', runIdFrom: 'output' } as const),\n }),\n // 2026-09-30 (432-12 D-05): the config change tool writes in the call. The undo arm is gone.\n Object.freeze({\n name: 'agent_qa_change_config',\n ops: Object.freeze([\n 'config.field.set',\n 'config.target.create',\n 'config.target.edit',\n 'config.auth.set',\n 'config.hook.add',\n 'config.project.scaffold',\n ]),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n // 2026-09-30 (432-12 D-05/D-09): accept, reject and forget apply in the call. Forget is the\n // explicit removal; a wrong record is otherwise corrected by new feedback.\n Object.freeze({\n name: 'agent_qa_change_knowledge',\n ops: Object.freeze([\n 'knowledge.accept',\n 'knowledge.reject',\n 'knowledge.forget',\n ]),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n Object.freeze({\n name: 'agent_qa_mark_run',\n ops: Object.freeze(['runs.mark']),\n kind: 'apply',\n }),\n // 2026-09-15, 423-21 D-18: marks history and the mark consequence preview beside the mark\n // writer. Both are read projections with no apply envelope, so `agent_qa_mark_run` stays the\n // only door that lands a mark.\n Object.freeze({\n name: 'agent_qa_get_run_marks',\n ops: Object.freeze(['runs.marks.history']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_preview_run_mark',\n ops: Object.freeze(['runs.mark.preview']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_list_knowledge_gates',\n ops: Object.freeze(['knowledge.gates.list']),\n kind: 'read',\n }),\n // 2026-09-28, 431 D-04: the knowledge reads, named one-to-one with their CLI verbs.\n Object.freeze({\n name: 'agent_qa_list_knowledge_bundles',\n ops: Object.freeze(['knowledge.bundles.list']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_inspect_knowledge_records',\n ops: Object.freeze(['knowledge.records.inspect']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_diff_knowledge_records',\n ops: Object.freeze(['knowledge.records.diff']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_show_knowledge_record',\n ops: Object.freeze(['knowledge.record.show']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_explain_brief',\n ops: Object.freeze(['knowledge.brief.why']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_get_entity',\n ops: Object.freeze(['entities.resolve', 'entities.get']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_list_runs',\n ops: Object.freeze(['runs.list']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_get_run_digest',\n ops: Object.freeze(['runs.digest']),\n kind: 'read',\n // 408 D-05/D-07: the watch/status read, and therefore the LATE-ATTACH door — a run started\n // from the CLI, from CI or from the dashboard is watchable through it exactly as an\n // MCP-started one is, because a viewer attaches and never owns. Its runId is on the INPUT.\n ui: Object.freeze({ resource: 'live-run', runIdFrom: 'input' } as const),\n }),\n // 2026-09-28, 431 D-05/D-06/D-07: one completed run's whole reads. The overview is the map, run\n // knowledge the whole used-and-learned projection unchanged, and evidence one addressed document\n // or blob. All three carry the result-size hint.\n Object.freeze({\n name: 'agent_qa_get_run_overview',\n ops: Object.freeze(['runs.overview']),\n kind: 'read',\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n Object.freeze({\n name: 'agent_qa_get_run_knowledge',\n ops: Object.freeze(['runs.knowledge']),\n kind: 'read',\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n Object.freeze({\n name: 'agent_qa_get_run_evidence',\n ops: Object.freeze(['runs.evidence', 'runs.artifact']),\n kind: 'read',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n] as const satisfies readonly ToolProjection[])\n\n/**\n * Tool name -> the contract that tool ADVERTISES, where it is not simply its one op's contract.\n *\n * Exactly two reasons an entry exists here, and no third:\n *\n * 1. A UNION FOLD validates with the discriminated union of its arms' own DTOs, composed in\n * `@vostride/agent-qa-schema` (see `functions/tool-folds.ts` for why it is composed there and\n * not here). Its output is the union of the arms' own outputs, collapsed when they are one.\n * Its input is listed as one object by `projection.ts` (2026-10-20, 446-11).\n * 2. THE PIPELINE advertises the FIRST op's contract on both sides: a caller hands `entities.resolve`\n * the reference it has, and reads back the resolution union — a card, a small disambiguation\n * set, or an honest miss. `entities.get` runs inside the resolved arm and contributes no shape\n * of its own, which is why its contract is absent from the advertisement.\n *\n * 2026-10-01 (432-21, D-12): THE MARK DOOR'S ENTRY IS DELETED. It advertised the op's outcome OR the\n * credential refusal (419 D-20); the refusal left with the MCP bearer credential, so the door\n * advertises exactly its op's own contracts and needs no entry. (The D-11 apply envelope it once\n * carried, `proposal_id` and `confirmed`, went with the apply tools in 432-12, D-05/D-14.)\n */\nexport const AGENT_QA_COMPOSED_CONTRACTS: Readonly<Record<string, ToolOpContracts>> = Object.freeze({\n agent_qa_refine_test: Object.freeze({\n input: AuthoringRefineFoldInputSchema,\n output: AuthoringRefineFoldOutputSchema,\n }),\n agent_qa_change_config: Object.freeze({\n input: ConfigChangeFoldInputSchema,\n output: ConfigChangeFoldOutputSchema,\n }),\n agent_qa_change_knowledge: Object.freeze({\n input: KnowledgeChangeFoldInputSchema,\n output: KnowledgeChangeFoldOutputSchema,\n }),\n // 2026-09-28 (431-04 D-07): the evidence fold, composed in the schema package from both arms'\n // canonical contracts and routed by full op id.\n agent_qa_get_run_evidence: Object.freeze({\n input: RunsEvidenceFoldInputSchema,\n output: RunsEvidenceFoldOutputContract,\n }),\n agent_qa_get_entity: Object.freeze({\n input: EntitiesResolveInputSchema,\n output: EntityCardResolutionSchema,\n }),\n})\n\n/** The contract a tool advertises: its composition when it has one, its one op's otherwise. */\nexport function advertisedContracts(\n projection: ToolProjection,\n): ToolOpContracts | undefined {\n const composed = AGENT_QA_COMPOSED_CONTRACTS[projection.name]\n if (composed !== undefined) return composed\n const [only] = projection.ops\n return only === undefined ? undefined : AGENT_QA_OP_CONTRACTS[only]\n}\n\n/**\n * A tool whose advertised OUTPUT cannot be represented as JSON Schema, and therefore ships with no\n * `outputSchema` at all (2026-08-16, D-16's explicit-degradation clause).\n *\n * MEASURED, NOT PREDICTED. `tools/list` converts every `outputSchema` in zod's OUTPUT mode\n * (`mcp-DXXb3Vv3.mjs:1391`, uncaught), and a contract built over a branded id — `z.string()\n * .transform(asRunId)` — makes that conversion throw `Transforms cannot be represented in JSON\n * Schema`. The consequence is not a poorer listing for one tool: the throw takes the WHOLE\n * `tools/list` response down for every caller who can see the tool. Phase 384 hit the same wall from\n * the other side and answered it by projecting both sides in input mode (`declaration-projection.ts`).\n *\n * WHY OMISSION RATHER THAN A SECOND CONVERSION. Advertising the INPUT-mode document as the output\n * would have worked and been a lie of exactly the kind D-16 forbids: a schema derived by a second\n * recipe, no longer the object `invokeFunction` validates with, presented as though it were. What a\n * caller gets instead is `content` plus `structuredContent` and no advertised shape — less, and\n * true. `validateToolOutput` skips a tool with no `outputSchema`, so the result still flows.\n *\n * THE LIST IS TWO-SIDED. `projection.ts` PROBES the conversion for every tool: an undeclared\n * failure throws, and a declared entry whose contract has since become convertible throws too. So\n * this list cannot silently grow and cannot silently rot.\n *\n * 2026-09-28 (431-03): the way off this list is a canonical `OutputContract` from\n * `@vostride/agent-qa-schema` — the op's own runtime schema as validator, with an explicit output\n * document — never a narrowed stand-in authored here. `agent_qa_start_run` keeps its row.\n */\nexport interface OutputSchemaDegradation {\n readonly tool: string\n readonly opId: string\n /** The schema symbol whose transform the converter refused, for a reader chasing the cause. */\n readonly schema: string\n /** The converter's own message, verbatim as measured on 2026-08-16. */\n readonly measured: string\n readonly adjudication: '397'\n}\n\nexport const DEGRADED_OUTPUT_CONTRACTS: readonly OutputSchemaDegradation[] = Object.freeze([\n // 397 DISPOSITION (2026-08-16 · D-20): keep-degraded. `agent_qa_start_run` advertises no\n // `outputSchema` and keeps it that way. The cause is a property of the CONTRACT, not of this\n // surface — a branded run id is `z.string().transform(asRunId)`, and the converter refuses a\n // transform because there is no true JSON-Schema for \"and then this function runs\". The two ways\n // out are both worse: advertising the input-mode document is the second-recipe lie D-16 forbids,\n // and un-branding the id to please a converter would spend a type-safety property of the whole\n // codebase on one surface's listing. 397 rules the degradation ADJUDICATED and CLOSED rather than\n // pending; re-opening it means changing the contract, which is a golden-diff-visible act. The\n // absence itself is not re-pinned here — `projection.ts` probes the conversion both ways and the\n // shipped projection suite owns that fact (RESEARCH Pitfall 9); the conformance suite asserts\n // only the join.\n Object.freeze({\n tool: 'agent_qa_start_run',\n opId: 'runs.start',\n schema: 'RunStartAcknowledgementSchema',\n measured: 'Transforms cannot be represented in JSON Schema',\n adjudication: '397',\n }),\n // 2026-09-28 (431-03, D-03/D-07 · research A1): the `agent_qa_list_runs` row is REMOVED, not\n // re-ruled. Its objection stands — no hand-written array schema is advertised. What changed is the\n // contract: `runs.list` now declares `RunsListOutputContract`, whose validator is the same\n // `RunsListOutputSchema` object and whose output document is derived from the runtime schema's\n // own output conversion. It converts cleanly, so the probe in `projection.ts` would refuse the row.\n] as const satisfies readonly OutputSchemaDegradation[])\n\n/**\n * A registry op that this surface deliberately does NOT project, and why (2026-08-16 · D-03/D-15).\n *\n * THE DATED SCOPING NOTE IS THIS TABLE, not a comment beside it. 397's parity suite ranges over the\n * projected set, and a suite that scoped itself to whatever happened to be in the mapping would be\n * discovering an accident rather than honouring a decision. Every op the registry declares appears\n * either above or here — the bump guard asserts that partition against the registry's own\n * enumeration, so a new op cannot land undispositioned.\n *\n * `agent.ask` LEADS THE LIST because its exclusion is the one with a decision behind it (D-03).\n * Projecting the agent's own turn entry over MCP is nested-agent delegation: a caller's tool call\n * would spend this project's model tokens, take the lease the local host holds, and stream through a\n * channel a single `tools/call` round trip has no shape for — four independent reasons, and no MCPS\n * requirement asking for any of them. It is deferred as its own seam rather than left out by\n * oversight, and the deferral is dated so a later reader can tell the two apart.\n *\n * The rest are D-02's line — this surface carries the reads a workflow needs MID-FLIGHT and not the\n * whole catalogue — and the two ops that cannot serve an agent-origin caller at all.\n */\nexport interface UnprojectedOp {\n readonly opId: string\n readonly reason: string\n /**\n * Who decided this absence is not a gap.\n *\n * 397 for every op that existed when 397's parity walk ruled the whole register (D-15). WIDENED\n * to admit `'398'` on 2026-08-17 for `agent.explain`, and the widening is the honest move rather\n * than a convenience: 397 could not have adjudicated an op that did not exist, and stamping this\n * one `'397'` to keep a literal green would have made the field record a ruling nobody made — the\n * one thing a provenance column is for. The vocabulary is a CLOSED set and the bump guard pins\n * which entries carry which adjudicator by name, so it cannot widen again by habit.\n *\n * 405-05 adds `runs.artifact` under the SAME `'405'` stamp on the same day and by the same\n * ruling; the vocabulary does not widen for it.\n *\n * WIDENED AGAIN on 2026-08-27 (405-01, D-03) for `runs.detail`, on exactly the 398 and 403\n * reasoning and for no new one: 397 could not have ruled on an op registered eight phases\n * later. The bump guard names which entry carries this adjudicator, in both directions, so an\n * entry stamped `'405'` because it was easier reds there rather than joining a set that has\n * quietly become \"any phase number\".\n *\n * WIDENED AGAIN on 2026-08-29 (407-01, D-05) for `runs.knowledge`, on exactly that reasoning and\n * for no new one: 397 could not have ruled on an op registered ten phases later. Membership is\n * still spelled by op id in the bump guard, in both directions.\n *\n * RE-STAMPED on 2026-08-31 (408 D-01): `'403'` LEAVES this vocabulary and `'408'` enters. This is\n * not a widening and not a rename — it is the provenance moving with the ruling. `runs.liveurl`\n * was the ONLY `'403'` entry, and its 403 stamp recorded a DEFERRAL (\"Phase 408's question\");\n * 408 D-01 answered that question, so the phase that decided this absence is now 408 and saying\n * `'403'` would credit 403 with a ruling it explicitly declined to make. Leaving `'403'` in a\n * closed set with no member would also be exactly the empty literal the bump guard's\n * non-vacuity check passes silently over, which is the hole that check exists to close.\n */\n // WIDENED AGAIN on 2026-09-15 (423-21, D-04) for `runs.evidence`, on the same reasoning: 397\n // could not have ruled on an op registered in 423. Membership is spelled by op id in the guard.\n // WIDENED AGAIN on 2026-09-25 (428 D-07) for `editor.liveurl`, on the same reasoning.\n // NARROWED on 2026-09-28 (431-04 D-10): `'407'` and `'423'` LEAVE. Their only members,\n // `runs.knowledge` and `runs.evidence`, are projected, and a member-less literal is the hole the\n // guard's non-vacuity check exists to close (the 408 re-stamp precedent). Their rulings live on in\n // `PROJECTED_RULING_ADDENDA`.\n // WIDENED on 2026-09-30 (432-12, D-05) for the five pre-432 proposal ops that leave the projected\n // side: the ruling that removed their tools is 432's, and 432-17 deletes the ops themselves.\n // NARROWED on 2026-10-01 (432-17, D-05): the five ops are deleted from the registry, so `'432'`\n // LEAVES with no member, on the 431-04 precedent above.\n readonly adjudication: UnprojectedAdjudication\n}\n\n/** The closed adjudicator vocabulary as a runtime tuple; the type above is derived from it. */\nexport const UNPROJECTED_ADJUDICATIONS = Object.freeze(['397', '398', '405', '408', '428'] as const)\n\nexport type UnprojectedAdjudication = (typeof UNPROJECTED_ADJUDICATIONS)[number]\n\nexport const UNPROJECTED_OPS: readonly UnprojectedOp[] = Object.freeze([\n Object.freeze({\n opId: 'agent.ask',\n reason:\n 'D-03 (dated 2026-08-15): ask-over-MCP is nested-agent delegation — trust, token-driven LLM '\n + 'spend, lease interaction and streaming are four separate problems and no MCPS requirement '\n + 'asks for any of them. Deferred as its own seam, not omitted by oversight.',\n adjudication: '397',\n }),\n // 2026-10-01 (432-17, D-05): `proposals.accept` and `proposals.reject` (397, requiresHumanOrigin)\n // are deleted with the inbox and leave the scoping note.\n // 2026-10-01 (432-18, D-14/D-15): `grants.revoke` (397, requiresHumanOrigin) and `grants.list`\n // (397, not a mid-flight read) are deleted with the grant ledger and leave the scoping note.\n Object.freeze({\n opId: 'runs.get',\n reason:\n 'not a mid-flight workflow read per D-02 — the entity door renders a run\\'s card and the '\n + 'digest carries what triage needs; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'runs.events',\n reason:\n 'not a mid-flight workflow read per D-02, and a stream op besides: a `tools/call` is one '\n + 'round trip and has no shape for a resumable event feed; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'runs.postprocessing',\n reason: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'runs.detail',\n reason:\n 'D-03 (dated 2026-08-27, 405-01): not a mid-flight workflow read per D-02 — this is a '\n + 'COMPLETED run\\'s projected step tree, read by the durable run-detail page, and the '\n + 'entity door already renders a run\\'s card while the digest carries what triage needs. '\n + 'The whole projection of a run is also a large one-shot payload with no shape a '\n + '`tools/call` round trip wants. Deferred as its own seam, not omitted.',\n adjudication: '405',\n }),\n Object.freeze({\n opId: 'runs.liveurl',\n reason:\n 'D-03 (dated 2026-08-25, 403-01): the op MINTS A CREDENTIAL — a short-lived, view-scoped '\n + 'capability token for a running browser. Whether an agent-origin MCP caller may mint one, '\n + 'and what it may hand it to, is Phase 408\\'s question (the MCP App embed); projecting it '\n + 'here would answer that question by accident. Deferred as its own seam, not omitted. '\n + 'ANSWERED (dated 2026-08-31, 408 D-01): the deferral above is discharged, and the ruling '\n + 'is INTERNAL MINT ONLY. The MCP server invokes this op BY REFERENCE, inside its '\n + 'App-rendering path and nowhere else, and the minted token lands only in the '\n + 'host-rendered HTML of the unlisted `ui://agent-qa/live-run/{runId}` App resource — '\n + 'never in tool-result text a model reads. Projecting a mint tool stays REJECTED: a live '\n + 'credential in model context is the T-395-R5-10 shape, and masking it would leave a tool '\n + 'that hands back nothing a host could use. The op therefore STAYS unprojected BY RULING '\n + 'rather than by deferral — answered on the record, never silently reclassified. '\n + 'RE-GROUNDED (dated 2026-09-01, 408 gap round, road `demote`; the full ruling is in '\n + \"`app-resource.ts`'s header). The answer above STANDS and one half of its stated property \"\n + 'is corrected rather than deleted. Whether the document this server serves is '\n + 'host-rendered HTML or text a model consumes is a property of the CALLER, not of this '\n + 'server, so the \"never in tool-result text a model reads\" half over-claimed. What this '\n + 'server guarantees is narrower and it is verifiable: it writes the token into exactly one '\n + 'place, the frame src of the document the `ui://` read serves, and that door is reachable '\n + 'by any caller of a composition whose mint is bound (dated 2026-10-01, 432-20/432-21, '\n + 'D-12: the scope gate that once also bounded it is deleted for every caller, and the '\n + 'loopback bind and the Host/Origin guards still bound who can reach it). The op STAYS '\n + 'unprojected on exactly '\n + 'the same footing, and the reason is unchanged and STRONGER rather than weaker: a '\n + 'projected mint tool would put the credential on a channel a model consumes BY DEFAULT, '\n + 'on every call, for every caller, whereas the `ui://` read is an unlisted address a '\n + 'caller must already know and deliberately ask for.',\n adjudication: '408',\n }),\n Object.freeze({\n opId: 'editor.liveurl',\n reason:\n 'D-07 (dated 2026-09-25, 428): the op MINTS A CREDENTIAL — a view credential for a live '\n + 'EDITOR session, which is private to the dashboard page that owns it; it is reachable only '\n + 'through the dashboard door and never through an MCP tool or the MCP App live-run '\n + 'resource. Projecting it would give an agent a watch carrier for a draft execution, which '\n + 'the owner declined in D-07. Unprojected by ruling, not by deferral.',\n adjudication: '428',\n }),\n Object.freeze({\n opId: 'config.get',\n reason: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'analysis.get',\n reason: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'authoring.funnel.get',\n reason: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'quarantine.add',\n reason: 'not a mid-flight workflow write per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'quarantine.release',\n reason: 'not a mid-flight workflow write per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n Object.freeze({\n opId: 'quarantine.list',\n reason: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n adjudication: '397',\n }),\n // 398 D-09 (dated 2026-08-17): the twentieth entry, and the FIRST op ever dispositioned here that\n // 397 did not rule on — because it did not exist then. Its exclusion is argued rather than scoped,\n // which is why it does not take the mid-flight line: `agent.explain` answers \"what can you do\",\n // and 397 already ruled the v1 discovery tool NOT a gap on this surface, because the protocol\n // answers machine discovery itself. Projecting it anyway would be the third answer that ruling\n // refuses.\n Object.freeze({\n opId: 'agent.explain',\n reason:\n 'D-09 (dated 2026-08-17): the protocol answers machine discovery itself — `tools/list` plus '\n + 'SEP-2575 `server/discover` — and 398\\'s `init --agent` manifest answers agent discovery '\n + 'from the committed catalog. This op answers a PERSON asking in prose, which is a third '\n + 'question with a third audience. 397 ruled the v1 discovery TOOL not-a-gap '\n + 'on exactly this reasoning; projecting the op would reinstate it under a new name.',\n adjudication: '398',\n }),\n // 2026-09-30 (432-12 D-05): the five pre-432 proposal ops went off the catalogue with their\n // tools. 2026-10-01 (432-17 D-05): they are deleted from the registry and leave the scoping note.\n] as const satisfies readonly UnprojectedOp[])\n\n/**\n * An op that LEFT `UNPROJECTED_OPS` for the projected side, with the ruling it was held under.\n *\n * 2026-09-28 (431-04 D-10). The ruling is kept verbatim and the dated 431 addendum says what\n * answered it, so the history a reader chased through the scoping note does not vanish when the\n * entry moves. `ruledBy` is historical provenance, not the live adjudicator vocabulary.\n */\nexport interface ProjectedRuling {\n readonly opId: string\n readonly ruledBy: string\n readonly ruling: string\n readonly addendum: string\n}\n\nexport const PROJECTED_RULING_ADDENDA: readonly ProjectedRuling[] = Object.freeze([\n Object.freeze({\n opId: 'knowledge.bundles.list',\n ruledBy: '397',\n ruling: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n addendum:\n 'D-01/D-04 (dated 2026-09-28, 431-04): projected as `agent_qa_list_knowledge_bundles`. A coding agent in a fresh '\n + 'workspace reads knowledge only through structured channels, so the committed-knowledge '\n + 'reads are served here rather than left to files; this supersedes the 2026-09-14 decision '\n + 'that projected the six safe reads only, whose no-search half stands (D-09).',\n }),\n Object.freeze({\n opId: 'knowledge.records.inspect',\n ruledBy: '397',\n ruling: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n addendum:\n 'D-01/D-04 (dated 2026-09-28, 431-04): projected as `agent_qa_inspect_knowledge_records`. A coding agent in a fresh '\n + 'workspace reads knowledge only through structured channels, so the committed-knowledge '\n + 'reads are served here rather than left to files; this supersedes the 2026-09-14 decision '\n + 'that projected the six safe reads only, whose no-search half stands (D-09).',\n }),\n Object.freeze({\n opId: 'knowledge.records.diff',\n ruledBy: '397',\n ruling: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n addendum:\n 'D-01/D-04 (dated 2026-09-28, 431-04): projected as `agent_qa_diff_knowledge_records`. A coding agent in a fresh '\n + 'workspace reads knowledge only through structured channels, so the committed-knowledge '\n + 'reads are served here rather than left to files; this supersedes the 2026-09-14 decision '\n + 'that projected the six safe reads only, whose no-search half stands (D-09).',\n }),\n Object.freeze({\n opId: 'knowledge.record.show',\n ruledBy: '397',\n ruling: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n addendum:\n 'D-01/D-04 (dated 2026-09-28, 431-04): projected as `agent_qa_show_knowledge_record`. A coding agent in a fresh '\n + 'workspace reads knowledge only through structured channels, so the committed-knowledge '\n + 'reads are served here rather than left to files; this supersedes the 2026-09-14 decision '\n + 'that projected the six safe reads only, whose no-search half stands (D-09).',\n }),\n Object.freeze({\n opId: 'knowledge.brief.why',\n ruledBy: '397',\n ruling: 'not a mid-flight workflow read per D-02; 397 adjudicates',\n addendum:\n 'D-01/D-04 (dated 2026-09-28, 431-04): projected as `agent_qa_explain_brief`. A coding agent in a fresh '\n + 'workspace reads knowledge only through structured channels, so the committed-knowledge '\n + 'reads are served here rather than left to files; this supersedes the 2026-09-14 decision '\n + 'that projected the six safe reads only, whose no-search half stands (D-09).',\n }),\n Object.freeze({\n opId: 'runs.knowledge',\n ruledBy: '407',\n ruling:\n 'D-05 (dated 2026-08-29, 407-01): not a mid-flight workflow read per D-02 — this is a '\n + \"COMPLETED run's used-and-learned projection, read by the durable Knowledge tab, and it is \"\n + 'unprojected on exactly the footing its sibling `runs.detail` is. It carries every step\\'s '\n + \"three served brief channels, each one's serve-time retrieval trace and the truncated \"\n + 'candidate ledger beside it, so it is a large one-shot payload with no shape a '\n + '`tools/call` round trip wants — larger than the step tree, not smaller. A planner '\n + 'mid-flight also has no use for what a FINISHED run was briefed with; the entity door '\n + \"already renders a record's card and the digest carries what triage needs. Deferred as its \"\n + 'own seam, not omitted.',\n addendum:\n 'D-05 (dated 2026-09-28, 431-04): projected as `agent_qa_get_run_knowledge`, answering the '\n + 'whole `runs.knowledge` projection unchanged; the owner declined a step filter. The size '\n + 'objection above is answered in these terms: `agent_qa_get_run_overview` is the entry point '\n + 'that maps a run without bodies, `agent_qa_explain_brief` and '\n + '`agent_qa_show_knowledge_record` are the drill-down, and the tool carries a '\n + '100000-character result-size hint so a host keeps the one-shot answer whole.',\n }),\n Object.freeze({\n opId: 'runs.evidence',\n ruledBy: '423',\n ruling:\n 'D-04 (dated 2026-09-15, 423-21): not a mid-flight workflow read per D-02 — this is one '\n + \"COMPLETED run step's parsed evidence document (console, network, variables, accessibility \"\n + 'or ARIA), read by the dashboard evidence tabs, and it is unprojected on exactly the footing '\n + 'its sibling `runs.detail` is. A network document alone may carry hundreds of records, so it '\n + 'is a large one-shot payload with no shape a `tools/call` round trip wants, and a planner '\n + 'mid-flight has no use for a finished step\\'s captured traffic. The raw SHA bytes stay on '\n + '`runs.artifact` and the two HTTP doors. Deferred as its own seam, not omitted.',\n addendum:\n 'D-07 (dated 2026-09-28, 431-04): projected as the `runs.evidence` arm of '\n + '`agent_qa_get_run_evidence`. A caller asks for ONE step document by the exact address '\n + '`agent_qa_get_run_overview` supplies, so the answer is one addressed document rather than '\n + \"a run's captured traffic. Masking is unchanged: the op stays on the cold read-scope \"\n + 'allowlist. The tool carries the 100000-character result-size hint.',\n }),\n Object.freeze({\n opId: 'runs.artifact',\n ruledBy: '405',\n ruling:\n 'D-12/D-13 (dated 2026-08-27, 405-05): not a mid-flight workflow read per D-02 — this '\n + 'resolves ONE completed run\\'s content-addressed evidence blob, and its result is a '\n + 'base64 body. A `tools/call` round trip is the wrong carriage for bytes: a conversation '\n + 'cannot render a PNG, and a tool that returned one would spend a context window on a '\n + 'payload no reader can read. The two HTTP doors are its carriage, and 408\\'s embed is the '\n + 'surface that renders it. Deferred as its own seam, not omitted. '\n + 'Phase 424 (dated 2026-09-20): the recording fact rides runs.detail; runs.artifact '\n + 'answers a bounded slice when range is supplied; pulling a whole recording through unary '\n + 'base64 is permitted and not recommended; no recording tool is projected because the '\n + 'MX ceiling of 22 is fully allocated.',\n addendum:\n 'D-07 (dated 2026-09-28, 431-04): projected as the `runs.artifact` arm of '\n + '`agent_qa_get_run_evidence`. The blob is addressed by the sha the overview supplies, with no '\n + 'step-to-sha lookup inside the tool, and the rendering objection is answered by the image '\n + 'result arm 431-05 adds. The Phase 424 note that the MX ceiling of 22 was fully allocated is '\n + 'superseded: the ceiling is 24 (D-01).',\n }),\n] as const satisfies readonly ProjectedRuling[])\n","// ONE MASKED SERIALIZATION, TWO CHANNELS (Phase 396 plan 06 · T-396-01 / RESEARCH Pitfall 9).\n//\n// WHY THIS MODULE EXISTS, measured rather than reasoned. Every tool result this package returns has\n// TWO output channels: `content`, the prose a person might read, and `structuredContent`, the object\n// a model reads and a host logs. Until 396-06 drove the wire, only the first was masked:\n//\n// content: [{ type: 'text', text: maskText(JSON.stringify(output)) }]\n// structuredContent: output <-- the raw op output, unmasked\n//\n// A credential this host had DECLARED — its own bearer token — reached the wire verbatim through\n// that second field while the text beside it read `<SECRET_0>`. Observed 2026-08-16 in\n// `packages/cli/src/__tests__/mcp-credential-surface.test.ts` (B1b):\n//\n// AssertionError: structuredContent carried the plant — the machine channel a person never\n// reads: expected 'prop_qxr' to be undefined\n//\n// That is RESEARCH Pitfall 9's own sentence, which named `structuredContent` as the channel and was\n// filed before anyone had driven it: *\"the new projection returns op outputs as `structuredContent`\n// — an unmasked serialization can carry planted values to a machine surface a person never sees.\"*\n//\n// THE FIX IS ONE MASKING, NOT TWO. Masking the object and the text separately would be a second\n// implementation of the same rule, free to disagree with the first — and the disagreement would be\n// invisible, because nobody diffs the two channels of a result. So the output is masked ONCE, as a\n// value, and both channels are answered from that one masked value: `structuredContent` IS it, and\n// `content` is its serialization. A value hidden from one cannot survive in the other.\n//\n// ─────────────────────────────────────────────────────────────────────────────────────────────\n// WHAT THE FIRST VERSION OF THIS MODULE GOT WRONG (CR-01, measured 2026-08-16, fixed the same\n// day). \"One masked serialization\" was originally implemented as: serialize, mask the SERIALIZED\n// DOCUMENT, parse the masked document back. That is escape-blind, and it leaked:\n//\n// const serialized = JSON.stringify(output) ?? 'null' // escapes \" as \\\" , \\ as \\\\ , \\n , \\t\n// const text = maskText(serialized) // literal substring replacement\n//\n// `maskText` is the host's declared-secret mask (`SecretRedactor` in the runner package), a\n// LITERAL replacement of the declared raw values. `JSON.stringify` escapes `\"`, `\\` and every C0\n// control character, so for a registered credential containing one of those bytes the raw value\n// DOES NOT OCCUR in the document the masker scans. The masker matched nothing and the credential\n// reached the caller verbatim — and, because this module answers both channels from the same\n// bytes, it reached BOTH of them. Measured:\n//\n// raw: sk-live\"abc\\def\n// serialized: {\"token\":\"sk-live\\\"abc\\\\def\"}\n// raw value present in the scanned document? false\n//\n// The phase verifier drove the then-shipped environment masker over six inputs and recorded\n// four of five shapes leaking verbatim on both channels, including a `*_CREDENTIALS`-style JSON\n// blob — an entirely ordinary environment value (a password with a quote in it, a service-account\n// blob). The corpus in place at the time could not see it: every credential plant was alphanumeric,\n// so no cell could tell masking of raw values apart from masking of the serialized form. (Phrased\n// without quoted-string-after-`from`: the arch dep lint reads that shape as an import specifier.)\n//\n// SO THE MASKER IS NEVER HANDED A SERIALIZATION. `maskJsonDocument` below walks the JSON value and\n// masks every STRING LEAF and every OBJECT KEY — the raw bytes an operator declared — and only\n// then serializes. The standing corpus for the class is\n// `__tests__/masked-serialization.test.ts`, which drives the shipped masker over a value containing\n// a quote, one containing a backslash, one containing a control character, and a JSON blob.\n// ─────────────────────────────────────────────────────────────────────────────────────────────\n//\n// IT STILL FAILS CLOSED, and the conditions are now named rather than incidental. A masked value\n// that cannot be REPRESENTED — a number or a boolean whose JSON spelling is itself a registered\n// credential, so hiding it in place would change the value's type; two keys of one object that mask\n// to the same name, so the masked object would silently drop a member; anything unserializable —\n// yields a tool error naming the condition instead of a result. The alternative is returning the\n// unmasked object, which is the defect this module exists to close. (The previous version withheld\n// on \"the masked document no longer parses\", which is the same posture reached by accident: a\n// placeholder substituted for a bare number produced invalid JSON. That case is now refused by\n// name, and the numeric cell in the corpus pins it across the change.)\n//\n// THE COST, STATED — and the reason it is a REAL cost rather than a theoretical one: SEP-2106\n// loosened `inputSchema`/`outputSchema` to full JSON Schema 2020-12, so an advertised output\n// contract can now say things precise enough for a masked value to violate them (a `format`, a\n// `pattern`, a `minLength`). A masked value can therefore violate the tool's advertised\n// `outputSchema`, and the SDK\n// then refuses the result. That is the correct direction. An op output that contains a declared\n// credential is a leak; turning a leak into a refusal a caller can see is a better answer than\n// serving it, and it happens only when a legitimate value is byte-equal to a credential this host\n// was told about.\n\nimport type { CallToolResult } from '@modelcontextprotocol/server'\nimport { RunsArtifactResultSchema } from '@vostride/agent-qa-schema'\nimport type { RunsArtifactResult } from '@vostride/agent-qa-schema'\n\n// 2026-10-01 (432-19, D-15): the MCP remedy renderer is deleted with the remedy vocabulary. The\n// mark credential refusal that carried its last sentence is deleted too (432-21, D-12).\n\n/** The one prose a caller reads when a value could not be masked in place. Value-free by design. */\nconst WITHHELD_TEXT =\n 'This result could not be returned: part of its output could not be masked in place — a value '\n + 'whose hidden form would not be the same kind of value, or two names that mask to one name — so '\n + 'the unmasked object was withheld rather than served.'\n\n/**\n * Raised inside the walk when a leaf cannot be masked without changing what the document MEANS.\n *\n * Private, and it never escapes this module: every caller turns it into a withheld answer. It is an\n * exception rather than a sentinel return because it is thrown from inside a recursion whose every\n * frame would otherwise have to re-check for the sentinel — and a missed check there is served\n * output.\n */\nclass UnmaskableValueError extends Error {}\n\n/**\n * Mask every STRING LEAF and every OBJECT KEY of a JSON value, in place, leaving the shape alone.\n *\n * THE MASKER ONLY EVER SEES RAW BYTES. That is the whole correction: a literal-substring masker\n * handed `{\"token\":\"sk-live\\\"abc\"}` cannot find `sk-live\"abc`, and handed `sk-live\"abc` it can.\n */\nfunction maskJsonLeaves(value: unknown, maskText: (text: string) => string): unknown {\n if (typeof value === 'string') return maskText(value)\n if (value === null) return null\n\n if (Array.isArray(value)) {\n return value.map((entry) => maskJsonLeaves(entry, maskText))\n }\n\n if (typeof value === 'object') {\n const masked: Record<string, unknown> = {}\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n // KEYS TOO. A map keyed by a credential — a header table, an env echo — carries the value in\n // the name rather than in the leaf, and the old whole-document mask happened to cover that\n // case. Two keys masking to one name would silently DROP a member, which is a different\n // answer wearing the same shape, so it is refused rather than resolved.\n const maskedKey = maskText(key)\n if (Object.hasOwn(masked, maskedKey)) {\n throw new UnmaskableValueError('two keys of one object mask to the same name')\n }\n // Defined, not assigned: `masked['__proto__'] = …` would set the prototype and drop the key,\n // and a captured variable may legitimately be named `__proto__` (431-03, T-431-07).\n Object.defineProperty(masked, maskedKey, {\n value: maskJsonLeaves(entry, maskText),\n enumerable: true,\n writable: true,\n configurable: true,\n })\n }\n return masked\n }\n\n // JSON's remaining leaves: number and boolean. They hold no string for the masker to replace, so\n // a registered credential whose SPELLING is one of them (`{\"pin\":867530912345}`) cannot be hidden\n // here without turning a number into a string. Refused, which is what the previous implementation\n // did by accident when a placeholder substituted into a bare number broke the document's JSON.\n const spelling = JSON.stringify(value) ?? 'null'\n if (maskText(spelling) !== spelling) {\n throw new UnmaskableValueError('a non-string leaf spells a registered value')\n }\n return value\n}\n\n/**\n * One masked value and its one serialization, or `undefined` when it cannot be represented.\n *\n * The pair is returned together so that no caller can compose a text channel and a data channel out\n * of two different maskings — `text` is `JSON.stringify(value)` and nothing else. Exported because\n * `resources.ts` composes resource contents the same way and must not grow a second answer to the\n * same question.\n */\nexport function maskJsonDocument(\n output: unknown,\n maskText: (text: string) => string,\n): { readonly value: unknown; readonly text: string } | undefined {\n // Round-tripped through the serializer FIRST, so what is masked is exactly what a caller would\n // have received: `toJSON` hooks run, `undefined` members vanish, a `Date` becomes its string.\n // `JSON.stringify` answers `undefined` for `undefined` and for a bare function; `'null'` is the\n // honest serialization of \"the op answered nothing\", and it parses.\n const serialized = JSON.stringify(output) ?? 'null'\n\n let parsed: unknown\n try {\n parsed = JSON.parse(serialized)\n } catch {\n return undefined\n }\n\n let value: unknown\n try {\n value = maskJsonLeaves(parsed, maskText)\n } catch {\n return undefined\n }\n\n const text = JSON.stringify(value)\n if (text === undefined) return undefined\n return { value, text }\n}\n\n/**\n * Mask once, and answer both channels from the one masked value.\n *\n * `structuredContent` IS the masked value and `content` is its serialization, which is the whole\n * point: the object a machine reads and the text a person reads agree about what was hidden,\n * because there is only one masking and one document. One exception: the evidence image arm\n * replaces `bytesBase64` in the text with a marker, while `structuredContent` keeps the bytes.\n */\nexport function maskedToolResult(\n output: unknown,\n maskText: (text: string) => string,\n): CallToolResult {\n const masked = maskJsonDocument(output, maskText)\n if (masked === undefined) {\n return {\n content: [{ type: 'text' as const, text: WITHHELD_TEXT }],\n isError: true,\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: masked.text }],\n structuredContent: masked.value as CallToolResult['structuredContent'],\n }\n}\n\n/**\n * The masked error result every handler in this package answers a refusal with.\n *\n * A refusal is a RESULT the caller can read, not a transport failure — and the message is masked\n * because an error string is the channel 395's credential disclosure actually travelled down\n * (T-395-R5-10). Kept beside `maskedToolResult` so the two halves of one handler's output posture\n * are one thing to read and one thing to change.\n */\nexport function maskedToolError(err: unknown, maskText: (text: string) => string): CallToolResult {\n const message = err instanceof Error ? err.message : String(err)\n return {\n content: [\n {\n type: 'text' as const,\n text: maskText(message),\n },\n ],\n isError: true,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────────────────────\n// THE IMAGE ARM (431-05, D-07 · T-431-10). A complete PNG or JPEG screenshot also travels as an\n// MCP image block, added after masking from bytes the masked value still carries unchanged.\n// `structuredContent` is never changed. The text keeps every field except the bytes, which it\n// names as attached image content (owner decision 2026-09-29, review WR-06).\n// Masking hides strings, never pixels: a screenshot shows what the page showed.\n// ─────────────────────────────────────────────────────────────────────────────────────────────\n\n/** Why an artifact did not travel as an image. Each is a tool error, never a success. */\nexport type RunEvidenceImageRefusal =\n | 'artifact-range-fragment'\n | 'artifact-not-image'\n | 'artifact-image-invalid'\n | 'artifact-image-withheld'\n\nconst RUN_EVIDENCE_IMAGE_TYPES: ReadonlySet<string> = new Set(['image/png', 'image/jpeg'])\n\nexport const RUN_EVIDENCE_IMAGE_TEXT_MARKER = '[image attached as image content]'\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] as const\nconst PNG_IEND_TRAILER = [\n 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n] as const\nconst JPEG_START = [0xff, 0xd8, 0xff] as const\nconst JPEG_END = [0xff, 0xd9] as const\n\nconst CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/\n\nfunction refusalText(refusal: RunEvidenceImageRefusal, contentType: string | undefined): string {\n switch (refusal) {\n case 'artifact-range-fragment':\n return 'artifact-range-fragment: agent_qa_get_run_evidence returns a screenshot only as one '\n + 'complete PNG or JPEG image, and this range covers part of one. Call runs.artifact without '\n + 'a range.'\n case 'artifact-not-image':\n return `artifact-not-image: this artifact is ${contentType ?? 'not typed'}, not a PNG or JPEG `\n + 'screenshot, and agent_qa_get_run_evidence relays no other artifact bytes. Read a step '\n + 'document through action runs.evidence.'\n case 'artifact-image-invalid':\n return 'artifact-image-invalid: the artifact is typed as an image, but its bytes are not one '\n + 'complete PNG or JPEG, so they were not returned.'\n case 'artifact-image-withheld':\n return 'artifact-image-withheld: masking changed the encoded screenshot, so neither the image '\n + 'nor its bytes were returned.'\n }\n}\n\nfunction hasBytesAt(bytes: Uint8Array, expected: readonly number[], offset: number): boolean {\n if (offset < 0 || bytes.length < offset + expected.length) return false\n return expected.every((byte, index) => bytes[offset + index] === byte)\n}\n\nfunction isCompleteImage(contentType: string, bytes: Uint8Array): boolean {\n if (contentType === 'image/png') {\n return hasBytesAt(bytes, PNG_SIGNATURE, 0)\n && hasBytesAt(bytes, PNG_IEND_TRAILER, bytes.length - PNG_IEND_TRAILER.length)\n }\n return hasBytesAt(bytes, JPEG_START, 0)\n && hasBytesAt(bytes, JPEG_END, bytes.length - JPEG_END.length)\n}\n\n/** The bytes of CANONICAL base64 only; anything a strict encoder would not emit is refused. */\nfunction decodeCanonicalBase64(text: string): Uint8Array | undefined {\n if (!CANONICAL_BASE64.test(text)) return undefined\n let binary: string\n try {\n binary = atob(text)\n } catch {\n return undefined\n }\n if (btoa(binary) !== text) return undefined\n return Uint8Array.from(binary, (char) => char.charCodeAt(0))\n}\n\n// The op types a ranged read by the WHOLE blob's head, so a fragment can say image/png while\n// carrying a middle slice. Only a read that provably covers every byte is a whole image.\nfunction coversWholeBlob(artifact: RunsArtifactResult): boolean {\n if (artifact.range === undefined) {\n return artifact.totalLength === undefined || artifact.totalLength === artifact.byteLength\n }\n return artifact.totalLength !== undefined\n && artifact.range.start === 0\n && artifact.range.end === artifact.totalLength - 1\n && artifact.byteLength === artifact.totalLength\n}\n\n/**\n * Add one image block to the evidence tool's `runs.artifact` answer, after masking.\n *\n * `result` is what `maskedToolResult` answered for `output`. A refusal or withheld result is\n * returned untouched. Anything that is not one complete PNG or JPEG, or whose base64 the masking\n * changed, becomes a named tool error carrying no bytes at all.\n */\nexport function decorateRunEvidenceImage(input: {\n readonly result: CallToolResult\n readonly output: unknown\n readonly maskText: (text: string) => string\n}): CallToolResult {\n const { result } = input\n if (result.isError === true) return result\n\n const refuse = (refusal: RunEvidenceImageRefusal, contentType?: string): CallToolResult => ({\n content: [{ type: 'text' as const, text: input.maskText(refusalText(refusal, contentType)) }],\n isError: true,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n })\n\n const parsed = RunsArtifactResultSchema.safeParse(input.output)\n if (!parsed.success) return refuse('artifact-image-invalid')\n const artifact = parsed.data\n if (!RUN_EVIDENCE_IMAGE_TYPES.has(artifact.contentType)) {\n return refuse('artifact-not-image', artifact.contentType)\n }\n if (!coversWholeBlob(artifact)) return refuse('artifact-range-fragment')\n\n const masked = result.structuredContent as\n | { readonly bytesBase64?: unknown; readonly contentType?: unknown }\n | undefined\n if (masked?.bytesBase64 !== artifact.bytesBase64 || masked.contentType !== artifact.contentType) {\n return refuse('artifact-image-withheld')\n }\n\n const bytes = decodeCanonicalBase64(artifact.bytesBase64)\n if (\n bytes === undefined\n || bytes.length !== artifact.byteLength\n || !isCompleteImage(artifact.contentType, bytes)\n ) {\n return refuse('artifact-image-invalid')\n }\n\n const text = JSON.stringify({ ...masked, bytesBase64: RUN_EVIDENCE_IMAGE_TEXT_MARKER })\n return {\n ...result,\n content: [\n ...result.content.map((block) => (block.type === 'text' ? { type: 'text' as const, text } : block)),\n { type: 'image' as const, data: artifact.bytesBase64, mimeType: artifact.contentType },\n ],\n }\n}\n\n// 2026-10-01 (432-21, D-12): the mark door's credential refusal is deleted with the MCP bearer\n// credential. `agent_qa_mark_run` dispatches through the generic projection handler like every other\n// change tool, advertises the op's own outcome, and answers its receipt on the one call.\n","// The v1 -> v2 tool-name migration map (Phase 398 plan 02, D-13 / D-14 · XPLN-03).\n//\n// WHY THIS FILE EXISTS. 397 ruled each of the thirty-three v1 tools in a deletion inventory, with a\n// dated disposition per tool. This module records those rulings in a shape a handler can switch on,\n// so an external agent still pinned to a v1 tool name receives the ruling instead of a bare\n// unknown-tool error (D-15's refuse-and-teach redirect, plan 05). The inventory itself is retired;\n// `__tests__/mapping-bump-guard.test.ts` pins the exact names and arms here, so the record cannot\n// drift silently.\n//\n// WHY THE UNIVERSE IS THE TOOL ROWS ONLY (2026-08-17). The inventory also carried one prompt row\n// (`agent_qa_authoring_context`) and six `agent-qa://schema/...` resource rows. Neither is a name a\n// caller can put in a `tools/call`, so neither can ever arrive at the seam this map answers: a\n// retired PROMPT name reaches a prompt request the server does not serve, and a retired RESOURCE\n// URI reaches a scheme that no longer parses. Widening this map to cover them would put entries in\n// it that nothing can look up, which is the same as an unreachable branch with a comment on it.\n//\n// PROTOCOL GROUNDING. SEP-2567 removed per-connection list variance, so the tool names a caller can\n// see are a property of `mapping.ts` — never of a session, and since 432-20 (D-12) never of the\n// caller either. That is what makes a RETIRED name a permanent fact rather than a per-connection\n// one: no listing on any connection will ever carry these thirty-three names again, which is\n// precisely why the history is worth keeping as data. SEP-2575's stateless posture is the other\n// half — there is no handshake in which a server could once have negotiated the old vocabulary, so\n// the only place a v1 caller's name can be answered is at the call itself.\n//\n// THREE ARMS AND NO FOURTH (D-13). The arms mirror the inventory's `Disposition (397, 2026-08-16)`\n// column exactly:\n//\n// renamed-to the inventory's `n/a -> projected by 396` rows whose target op IS projected — the\n// capability is here under a new name, and `v2Tool` carries it.\n// retired the inventory's `not-a-gap` rows (the capability did not go missing; it is answered\n// elsewhere, or its absence is a rule), PLUS the five A4 rows below.\n// pending the inventory's `gap -> <owner>` rows — a real absence, routed to the milestone that\n// owns it. `owner` carries that milestone and `route` the interim answer.\n//\n// THE A4 ADJUDICATION, MADE HERE DELIBERATELY (2026-08-17, RESEARCH assumption A4 · this plan).\n// Five inventory rows are ruled `n/a -> projected by 396` and yet name ops that ended up in\n// `UNPROJECTED_OPS` after 396 plan 04's fold decisions: `agent_qa_get_config` (`config.get`),\n// `agent_qa_get_run` (`runs.get`), and `agent_qa_get_run_steps` / `agent_qa_get_run_logs` /\n// `agent_qa_get_run_execution_logs` (`runs.get` / `runs.events`). D-13's law is that every\n// `renamed-to` target is a LIVE tool name, and there is no live tool in front of an unprojected op,\n// so these five cannot take that arm. They are ruled RETIRED with route text mirroring the\n// corresponding `UNPROJECTED_OPS` reason — the entity door, the digest, the manifest's posture\n// section — rather than given a fourth arm, because \"the op exists but this surface does not project\n// it\" is not a different KIND of answer to a caller: the name is gone and here is what to call\n// instead, which is what `retired` already means. The inventory's own ruling is untouched; what is\n// added is the join those two tables did not have between them.\n\n/** Which of D-13's three closed answers a retired v1 name gets. */\nexport type V1MigrationArm = 'renamed-to' | 'retired' | 'pending'\n\n/** One retired v1 tool name and its ruled disposition. */\nexport interface V1ToolMigrationEntry {\n /** The v1 tool name, verbatim from the inventory's tool table. */\n readonly v1Name: string\n readonly arm: V1MigrationArm\n /** The live v2 tool that carries this capability. Present ONLY on `renamed-to`. */\n readonly v2Tool?: string\n /** The inventory's ruled reason, dated. Never empty. */\n readonly note: string\n /** What to call instead. Present on `retired` and `pending`; a `renamed-to` row's route is its tool. */\n readonly route?: string\n /** The milestone that owns the absence. Present ONLY on `pending`. */\n readonly owner?: string\n}\n\n/**\n * THE MAP. One entry per v1 tool, in the inventory's original row order.\n *\n * The order is the inventory's rather than alphabetical, and the bump guard pins the SORTED set\n * separately — order is a reading convenience here and a pinned fact nowhere, which is why nothing\n * below depends on it.\n */\nexport const V1_TOOL_MIGRATION_MAP: readonly V1ToolMigrationEntry[] = Object.freeze([\n // 1\n Object.freeze({\n v1Name: 'agent_qa_discover',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): the protocol answers discovery itself, so a hand-written '\n + 'catalogue tool beside it would be a second, drifting answer to one question.',\n route:\n '`tools/list` (plus SEP-2575 `server/discover`) answers machine discovery; 398\\'s build-time '\n + 'capability catalog, carried by `agent-qa init --agent`, answers the human-facing version.',\n }),\n // 2\n Object.freeze({\n v1Name: 'agent_qa_get_config',\n arm: 'retired',\n note:\n 'A4 adjudication (2026-08-17, phase 398 plan 02): the inventory rules this row `n/a -> '\n + 'projected by 396`, but `config.get` is in UNPROJECTED_OPS after 396 plan 04 — not a '\n + 'mid-flight workflow read per D-02 — so there is no live tool to rename to.',\n route:\n 'no MCP tool reads configuration; the workspace posture an agent needs reaches it through '\n + '`agent-qa init --agent`\\'s manifest (398 D-16), by env-ref name and never by value.',\n }),\n // 3\n Object.freeze({\n v1Name: 'agent_qa_schema_reference',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): a served COPY of a contract is exactly the drift that '\n + 'advertising the live contract replaced.',\n route:\n 'every tool advertises its op\\'s live `inputSchema`/`outputSchema` in `tools/list` (396 D-16), '\n + 'so a caller reads the contract the gate actually validates with; a fold lists its arms\\' '\n + 'fields as one object, and its `action` field says which fields each action takes.',\n }),\n // 4\n Object.freeze({\n v1Name: 'agent_qa_validate_definition',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): a standalone linter over arbitrary text is a second validator '\n + 'that can disagree with the one that gates writes.',\n route:\n 'validation reaches a caller as `authoring.draft.verify`\\'s verdict inside the authoring '\n + 'funnel — the verify arm of `agent_qa_refine_test`.',\n }),\n // 5\n Object.freeze({\n v1Name: 'agent_qa_generate_id',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): died with the CRUD model. Minting a canonical id on a surface '\n + 'is what 394-11 removed from the CLI, for this same reason.',\n route:\n 'ids are minted host-side where the entity is written; a caller names what it wants and reads '\n + 'the id back off the entity card `agent_qa_get_entity` returns.',\n }),\n // 6\n Object.freeze({\n v1Name: 'agent_qa_validate_id',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): died with the CRUD model. A standalone validator would be a '\n + 'second answer to a question already answered at every parse point.',\n route:\n 'the one URI codec (`packages/schema/src/entity/uri.ts`) validates every `agentqa://` '\n + 'reference as it is parsed, including the one `agent_qa_get_entity` resolves.',\n }),\n // 7\n Object.freeze({\n v1Name: 'agent_qa_list_tests',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): nothing in the registry enumerates the test corpus — `entities.resolve` '\n + 'resolves a reference to an entity, which is a different question.',\n route:\n 'until the owning milestone mints `entities.list`, a known reference resolves through '\n + '`agent_qa_get_entity`; enumeration has no tool.',\n owner: 'M5 (live view & run invocation)',\n }),\n // 8\n Object.freeze({\n v1Name: 'agent_qa_read_test',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_get_entity',\n note:\n 'projected by 396 (inventory row 8, 2026-08-16): `entities.get` is D-02\\'s universal entity '\n + 'read, kind TST, behind the one read door.',\n }),\n // 9\n Object.freeze({\n v1Name: 'agent_qa_validate_test',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): row 4\\'s ruling. `authoring.draft.verify` is the only validator, '\n + 'and it validates a draft in the funnel rather than arbitrary text a caller pasted.',\n route:\n 'the verify arm of `agent_qa_refine_test` returns the same verdict that gates the write.',\n }),\n // 10\n Object.freeze({\n v1Name: 'agent_qa_create_test',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_write_test',\n note:\n 'projected by 396 (inventory row 10, 2026-08-16): `authoring.draft.write` is workflow-coarse '\n + 'and verifies a draft rather than performing v1\\'s blind write, so the input shape differs. '\n + 'Since 2026-10-02 (432-40, D-06) it writes the test file in the call unless a keep-gate '\n + 'rejected the draft.',\n }),\n // 11\n Object.freeze({\n v1Name: 'agent_qa_update_test',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_refine_test',\n note:\n 'projected by 396 (inventory row 11, 2026-08-16): `authoring.draft.edit` is the edit arm of '\n + 'the refine fold, selected by the fold discriminant.',\n }),\n // 12\n Object.freeze({\n v1Name: 'agent_qa_delete_test',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): a rule, not an absence. MCPS-02 forbids a surface delete verb '\n + 'for irreversible deletes.',\n route:\n 'removing a committed test is a repository edit a person makes and reviews; no surface has a '\n + 'delete door and none is coming.',\n }),\n // 13\n Object.freeze({\n v1Name: 'agent_qa_list_suites',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): folded into row 7\\'s verb — enumerating the corpus answers \"which '\n + 'tests exist, and in which files\". A suite is a file, so this is not a second registry.',\n route:\n 'until `entities.list` lands, suite membership is read from the workspace files themselves; '\n + 'the TST records inside them resolve through `agent_qa_get_entity`.',\n owner: 'M5 (live view & run invocation)',\n }),\n // 14\n Object.freeze({\n v1Name: 'agent_qa_read_suite',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): there is no suite RECORD to read. `ENTITY_KINDS` has no suite '\n + 'kind and a suite is a committed file addressed by workspace path.',\n route:\n 'the TST records inside a suite are `agent_qa_get_entity`\\'s job; the file itself is read '\n + 'from the workspace.',\n }),\n // 15\n Object.freeze({\n v1Name: 'agent_qa_validate_suite',\n arm: 'retired',\n note: 'not-a-gap (397, 2026-08-16): row 4\\'s ruling — one validator, inside the funnel.',\n route:\n 'the verify arm of `agent_qa_refine_test` validates the draft that joins the suite file.',\n }),\n // 16\n Object.freeze({\n v1Name: 'agent_qa_create_suite',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): a suite is a committed file the authoring funnel writes. A '\n + 'blind create is the v1 write the verified authoring funnel replaced (re-spelled '\n + '2026-10-02, 432-40, D-06: the funnel writes in the call).',\n route:\n '`agent_qa_write_test` names the suite file a draft joins and writes it in the call, unless a '\n + 'keep-gate rejected the draft.',\n }),\n // 17\n Object.freeze({\n v1Name: 'agent_qa_update_suite',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): row 16\\'s ruling, through the edit arm instead of the write '\n + '(re-spelled 2026-10-02, 432-40, D-06: the edit lands in the call).',\n route: '`agent_qa_refine_test` edits the written test; the suite file changes in the call.',\n }),\n // 18\n Object.freeze({\n v1Name: 'agent_qa_delete_suite',\n arm: 'retired',\n note: 'not-a-gap (397, 2026-08-16): row 12\\'s MCPS-02 rule, applied to the file rather than the record.',\n route: 'removing a suite file is a repository edit a person makes and reviews; no surface door exists.',\n }),\n // 19\n Object.freeze({\n v1Name: 'agent_qa_list_hooks',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16, corrected the same day): the 396 reason overstated `config.get`, which '\n + 'projects the resolved CONFIG\\'s leaves; hook definitions live in the separate '\n + '`workspace.hooksFile`, so no registered op reads them today.',\n route:\n 'until the owning milestone re-opens the hook execution model, hooks are read from '\n + '`workspace.hooksFile` in the workspace; no tool enumerates them.',\n owner: 'M7 (skills layer)',\n }),\n // 20\n Object.freeze({\n v1Name: 'agent_qa_read_hook',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): with row 19, ONE hook-read verb and not two. What `config.get` shows '\n + 'is `workspace.hooksFile` — the path, not the hooks.',\n route:\n 'until that verb lands, a single hook is read from the hooks file itself; no tool projects it.',\n owner: 'M7 (skills layer)',\n }),\n // 21\n Object.freeze({\n v1Name: 'agent_qa_create_hook',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_change_config',\n note:\n 'projected by 396 (inventory row 21, 2026-08-16): `config.hook.add` is an arm of the config '\n + 'fold. Since 2026-09-30 (432-12, D-05) the fold is `agent_qa_change_config` and the hook is '\n + 'written in the call, with the files it changed on the answer.',\n }),\n // 22\n Object.freeze({\n v1Name: 'agent_qa_update_hook',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): `config.field.set` reaches any schema-addressable CONFIG path and the '\n + 'hooks file is not one, so an existing hook has no edit verb. Minting one now would pin an '\n + 'edit shape to a contract the owning milestone revisits.',\n route:\n 'adding a hook goes through `agent_qa_change_config`; editing an existing one is a '\n + 'hooks-file edit a person makes until the owner rules on the verb.',\n owner: 'M7 (skills layer)',\n }),\n // 23\n Object.freeze({\n v1Name: 'agent_qa_delete_hook',\n arm: 'retired',\n note: 'not-a-gap (397, 2026-08-16): row 12\\'s MCPS-02 rule.',\n route: 'removing a hook is an edit to the hooks file that a person makes and reviews.',\n }),\n // 24\n Object.freeze({\n v1Name: 'agent_qa_run_hook',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): a hook\\'s whole contract is \"runs at this lifecycle point\". '\n + 'Invoking one by name from a surface is arbitrary script execution decoupled from the '\n + 'lifecycle that gives it meaning — the private-power shape M4 abolished.',\n route:\n 'hooks run at their declared lifecycle points during a run started by `agent_qa_start_run`; '\n + 'nothing invokes one out of band.',\n }),\n // 25\n Object.freeze({\n v1Name: 'agent_qa_enqueue_test_run',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_start_run',\n note:\n 'projected by 396 (inventory row 25, 2026-08-16): `runs.start` is workflow-coarse, and the '\n + 'test scope is an argument rather than a tool of its own.',\n }),\n // 26\n Object.freeze({\n v1Name: 'agent_qa_enqueue_suite_run',\n arm: 'renamed-to',\n v2Tool: 'agent_qa_start_run',\n note:\n 'projected by 396 (inventory row 26, 2026-08-16): the SAME op as row 25 at suite scope, which '\n + 'is why D-01 allows one tool over both.',\n }),\n // 27\n Object.freeze({\n v1Name: 'agent_qa_get_run',\n arm: 'retired',\n note:\n 'A4 adjudication (2026-08-17, phase 398 plan 02): the inventory rules this row `n/a -> '\n + 'projected by 396`, but `runs.get` is in UNPROJECTED_OPS after 396 plan 04 — not a '\n + 'mid-flight workflow read per D-02 — so there is no live tool to rename to.',\n route:\n 'the entity door renders a run\\'s card: `agent_qa_get_entity` on the run reference. '\n + '`agent_qa_list_runs` enumerates recent runs.',\n }),\n // 28\n Object.freeze({\n v1Name: 'agent_qa_get_run_steps',\n arm: 'retired',\n note:\n 'A4 adjudication (2026-08-17, phase 398 plan 02): ruled `n/a -> projected by 396` against '\n + '`runs.get`/`runs.events`, both of which are in UNPROJECTED_OPS — `runs.events` is a stream '\n + 'op besides, and a `tools/call` is one round trip with no shape for a resumable feed.',\n route:\n '`agent_qa_get_run_digest` carries what triage needs from a run, including its steps\\' '\n + 'outcome; the run\\'s card comes from `agent_qa_get_entity`.',\n }),\n // 29\n Object.freeze({\n v1Name: 'agent_qa_get_run_logs',\n arm: 'retired',\n note:\n 'A4 adjudication (2026-08-17, phase 398 plan 02): ruled `n/a -> projected by 396` against '\n + '`runs.events`, which is in UNPROJECTED_OPS as a stream op with no single-round-trip shape.',\n route:\n '`agent_qa_get_run_digest` carries the triage-relevant remainder of a run; the full event '\n + 'feed is read from the run artifacts on disk, not over this surface.',\n }),\n // 30\n Object.freeze({\n v1Name: 'agent_qa_get_run_execution_logs',\n arm: 'retired',\n note:\n 'A4 adjudication (2026-08-17, phase 398 plan 02): row 29\\'s reading — `runs.events` is '\n + 'unprojected, so the second logs alias has no live tool either.',\n route:\n '`agent_qa_get_run_digest` for triage; execution logs live in the run\\'s artifacts on disk.',\n }),\n // 31\n Object.freeze({\n v1Name: 'agent_qa_get_run_artifact',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): artifact bytes over a tool result is a disclosure surface nobody has '\n + 'scoped, so the read is routed WITH that scoping rather than minted without it — an artifact '\n + 'read without it is the gap made worse.',\n route:\n 'until the owning milestone ships artifact resolution, artifacts are read from the run '\n + 'directory on disk; `agent_qa_get_run_digest` names what a run produced.',\n owner: 'M5 (artifact resolution route)',\n }),\n // 32\n Object.freeze({\n v1Name: 'agent_qa_cancel_run',\n arm: 'pending',\n note:\n 'gap (397, 2026-08-16): ruled a REAL gap as `runs.cancel` and routed to its owner rather than '\n + 'minted in 397, because D-17 binds the adjudicator too.',\n route:\n 'until `runs.cancel` lands, a run is stopped by the host that started it; this surface starts '\n + 'runs through `agent_qa_start_run` and cannot stop one.',\n owner: 'M5 (live-view control arbiter)',\n }),\n // 33\n Object.freeze({\n v1Name: 'agent_qa_classify_failure',\n arm: 'retired',\n note:\n 'not-a-gap (397, 2026-08-16): classification on demand over dashboard-fetched data is the '\n + 'private data path M4 abolished, not a capability that went missing.',\n route:\n '`analysis.get` reads the verdict the `analyze-run` job produced; over this surface the '\n + 'triage answer is `agent_qa_get_run_digest`.',\n }),\n] as const satisfies readonly V1ToolMigrationEntry[])\n","// Op contract -> `registerTool` config (Phase 396 plans 01 + 04, D-16 / MCPS-02).\n//\n// WHY THIS FILE EXISTS. Everything a caller learns about a tool — its title, its description, the\n// JSON Schema of its input, the JSON Schema of its result, and the hints a host uses to decide\n// whether to confirm before calling it — is DERIVED here from what the op already declares, and is\n// authored nowhere. That is D-16's \"drift impossible by construction\" made into a module: there is\n// no second place to update when an op's contract changes, because there is no first place.\n//\n// ONE CONVERSION ROUTE, CHOSEN AND STATED. The op's live Standard-Schema contract is handed to\n// `registerTool` untouched and the SDK converts it (zod 4.6.7 is above the 4.2 floor the\n// self-conversion needs). The rejected alternative was to run the function layer's own\n// `toSchemaProjection` and hand the result to `fromJsonSchema`. Both work; having both is the\n// defect. The route taken is the one where the object advertised in `tools/list` and the object\n// `invokeFunction` validates against are the SAME object rather than two derivations of it.\n// 2026-10-20 (446-11, D-25): a union fold's listing is the one derived view (`flatFoldInput`);\n// its calls are still validated against the composed contract itself.\n//\n// 2026-09-28 (431-03, D-03 · research A1): that object may now be a canonical `OutputContract`\n// from `@vostride/agent-qa-schema`. Its `validate` IS the op's runtime schema (the same object\n// `invokeFunction` enforces with) and its output conversion is an explicit document derived from\n// that schema, so a branded run id or an own `__proto__` variable no longer forces a degradation.\n// Nothing here special-cases it: the probe below still asks the SDK's own question in output mode,\n// and still refuses both an undeclared failure and a stale degradation row.\n//\n// ANNOTATIONS ARE DERIVED, AND THEY NEVER ENFORCE. `readOnlyHint` and friends steer a host's UX —\n// whether to auto-approve, whether to warn. They are not a permission system and this file is not a\n// gate: enforcement is `invokeFunction`'s scope check and the policy gate underneath it. Because\n// they only steer, the honest thing is to derive them mechanically from what the op declares about\n// itself rather than to hand-write a hint per tool that can quietly become a lie.\n//\n// DEGRADATION IS LOUD (plan 04). One conversion route means one place a construct can be\n// unrepresentable, and this is it: the output-mode conversion is PROBED for every tool before the\n// contract is advertised. An unrepresentable output that the mapping has not declared throws by\n// name; a declared one ships with no `outputSchema` and a sentence in the description saying so.\n// What never happens is a silently narrowed document — a listing that looks complete and describes\n// a shape nothing produces.\n//\n// Protocol grounding: SEP-2106 loosened `inputSchema`/`outputSchema` to full JSON Schema 2020-12,\n// which is what makes handing the SDK a real contract — refinements, unions, descriptions and all —\n// viable at all; SEP-2549 makes the resulting listing cacheable, which is why nothing here varies\n// per call.\n\nimport type { StandardSchemaWithJSON, ToolAnnotations } from '@modelcontextprotocol/server'\nimport type { RiskActionDescriptor } from '@vostride/agent-qa-schema'\n\n// ONE authoritative spelling of the App address: the module that publishes the template is the\n// module that parses it, and this derivation imports it rather than restating the string.\nimport { APP_RESOURCE_URI_TEMPLATE } from './app-resource.js'\nimport { compositionOf, DEGRADED_OUTPUT_CONTRACTS, MAX_RESULT_SIZE_META_KEY } from './mapping.js'\nimport type { ToolOpContracts, ToolProjection } from './mapping.js'\n\n/**\n * The draft the SDK converts every advertised schema to.\n *\n * Pinned here to the SDK's own `JSON_SCHEMA_CONVERSION_TARGET` (`src-CX2iR2pK.mjs`) because the\n * probe below must ask the SAME question `tools/list` will ask. A probe run against a different\n * target would be measuring a conversion nobody performs.\n */\nconst JSON_SCHEMA_CONVERSION_TARGET = 'draft-2020-12'\n\n/**\n * Everything the derivation reads about ONE op, assembled by `catalog.ts`.\n *\n * The two halves come from two places on purpose. `summary` and `risk` are read\n * off the registry's own declaration for this host, so they describe the composition a caller is\n * actually talking to; `input` and `output` are the live contracts named by the mapping table,\n * because the registry deliberately publishes only inert projections of those (T-384-14). Nothing\n * in this record is authored by this package — it is two views of the op, joined by its id.\n */\nexport interface ProjectedOpSpec {\n readonly id: string\n readonly summary: string\n readonly risk: RiskActionDescriptor\n readonly input: StandardSchemaWithJSON\n readonly output: StandardSchemaWithJSON\n}\n\n/**\n * Exactly the `registerTool` config fields this projection derives.\n *\n * `outputSchema` is OPTIONAL, and its absence is a decision rather than a gap — see\n * `DEGRADED_OUTPUT_CONTRACTS` and `probeOutputSchema` below.\n */\nexport interface RegisterToolConfig {\n readonly title: string\n readonly description: string\n readonly inputSchema: StandardSchemaWithJSON\n readonly outputSchema?: StandardSchemaWithJSON\n readonly annotations: ToolAnnotations\n /**\n * The SDK's own extension slot, carrying the live-view App reference for a CARRIER tool\n * (2026-08-31, Phase 408 plan 01 · D-05/D-09 · MCPA-01).\n *\n * OPTIONAL, and its absence is a decision in the same sense `outputSchema`'s is: a tool that\n * declares no `ui` member gets no `_meta` KEY at all rather than a `_meta` whose `ui` is\n * `undefined`, because the two are different documents on the wire and only the first is honest\n * about a tool that references no App.\n *\n * WHAT IT IS ON THE LISTING CHANNEL: inert metadata. Extensions are bilateral opt-in, so a host\n * that never negotiated `io.modelcontextprotocol/ui` ignores this field by definition — it acts\n * on nothing here, which is what makes \"the App attaches only when the host negotiated\" true of\n * every channel that ACTS without needing a listing that varies per connection (SEP-2567 removed\n * that, and the per-request factory context carries no client capabilities to key one on). The\n * channels that act are gated where the capabilities actually arrive: in request handling.\n */\n readonly _meta?: Record<string, unknown>\n}\n\n/**\n * A tool is read-only when every arm is: the risk descriptor's explicit `readOnly`, the op's own\n * word. A fold containing one write is not read-only.\n *\n * 2026-10-01 (432-20, D-12): the second signal — \"the op asks for no scope beyond `read`\" — left\n * with the scopes, which declarations no longer carry. Every projected read op declares\n * `readOnly: true` and every projected write op does not, so the annotation set is unchanged.\n */\nfunction isReadOnly(specs: readonly ProjectedOpSpec[]): boolean {\n return specs.every((spec) => spec.risk.readOnly === true)\n}\n\n/**\n * Derive the honest annotation set.\n *\n * `destructiveHint` is true when ANY arm declares itself destructive — the union direction, because\n * a fold is as dangerous as its most dangerous arm and a host deciding whether to confirm is asking\n * about the call it is about to make, not about the average of the ones it could have made.\n *\n * `idempotentHint` follows `readOnlyHint` and nothing else. A read is idempotent; for anything that\n * writes, this product has no per-op declaration of idempotence to read, and asserting one from\n * nowhere is exactly the lie the honest-annotations rule forbids. When such a declaration exists,\n * this is the one line that changes.\n */\nfunction deriveAnnotations(specs: readonly ProjectedOpSpec[]): ToolAnnotations {\n const readOnlyHint = isReadOnly(specs)\n return {\n readOnlyHint,\n destructiveHint: specs.some((spec) => spec.risk.destructive === true),\n idempotentHint: readOnlyHint,\n }\n}\n\n/**\n * Compose a human-facing description from the arms' own summaries.\n *\n * A 1:1 projection reads as its op's summary verbatim — there is nothing to add, and adding\n * something would be authoring a second description of one capability.\n *\n * A UNION FOLD lists its arms, each labelled with the op id it stands for, and says which key\n * selects between them — because a caller told only \"manage configuration\" cannot work out which\n * arm a given input selects, and the discriminant IS the op id.\n *\n * THE PIPELINE names its steps in order. Its second op contributes no shape to the advertisement\n * (see `AGENT_QA_COMPOSED_CONTRACTS`), so a caller reading only the schemas would never learn that\n * a second capability runs, and \"what did this call actually do\" is not a question a projection may\n * leave unanswerable.\n */\nfunction describe(projection: ToolProjection, specs: readonly ProjectedOpSpec[]): string {\n const composition = compositionOf(projection)\n if (composition === 'single') return specs[0]!.summary\n const arms = specs.map((spec) => `${spec.id}: ${spec.summary}`).join('\\n')\n if (composition === 'pipeline') {\n return `${arms}\\nThese run in the order listed; the second runs only when the first resolves.`\n }\n return `${arms}\\nSelect one with \"${projection.discriminant!}\", whose value is the op id above.`\n}\n\n/**\n * The sentence appended when a tool ships without an `outputSchema`.\n *\n * A caller reads descriptions; a caller does not read this repository. An omission nobody is TOLD\n * about is exactly the silent narrowing D-16 forbids, so the omission travels in the one channel\n * that reaches the other end.\n */\nfunction degradationSentence(degradation: { readonly schema: string }): string {\n return (\n `\\nThis tool advertises no outputSchema: its result contract (${degradation.schema}) contains a `\n + 'construct JSON Schema cannot represent, and a narrowed stand-in would describe a shape '\n + 'nothing produces. The result still arrives as structuredContent.'\n )\n}\n\n/**\n * Ask the SDK's own converter whether this output contract can be advertised at all.\n *\n * PROBED, NEVER ASSUMED, and probed in OUTPUT mode because that is the mode `tools/list` uses for\n * `outputSchema` — a probe in input mode would answer a question nobody asks and pass for every\n * contract this check exists to catch. The conversion is pure and deterministic, so running it once\n * here and once again inside the SDK costs a listing nothing and buys the failure a name.\n *\n * The three answers, and each one is a decision:\n * - converts, undeclared -> advertise it.\n * - throws, DECLARED -> advertise nothing, say so in the description.\n * - throws, undeclared -> refuse to build the tool, naming the tool, the schema and the\n * converter's own message. Left to the SDK this would surface as an\n * exception inside `tools/list`, taking the whole listing down for\n * every caller with no indication of which tool caused it.\n * - converts, DECLARED -> also refuse. A degradation entry that no longer describes reality is\n * a tool silently withholding a schema it could publish, and a list\n * that can only grow is a list that rots.\n */\nfunction probeOutputSchema(\n projection: ToolProjection,\n output: StandardSchemaWithJSON,\n): StandardSchemaWithJSON | undefined {\n const declared = DEGRADED_OUTPUT_CONTRACTS.find((entry) => entry.tool === projection.name)\n\n let failure: string | undefined\n try {\n output['~standard'].jsonSchema.output({ target: JSON_SCHEMA_CONVERSION_TARGET })\n } catch (err) {\n failure = err instanceof Error ? err.message : String(err)\n }\n\n if (failure === undefined) {\n if (declared === undefined) return output\n throw new McpProjectionError(\n projection.name,\n `is listed in DEGRADED_OUTPUT_CONTRACTS for ${declared.schema}, but that contract now `\n + 'converts cleanly in output mode; remove the entry so the schema is advertised again',\n )\n }\n\n if (declared === undefined) {\n throw new McpProjectionError(\n projection.name,\n `advertises an output contract JSON Schema cannot represent (${failure}). Declare it in `\n + 'DEGRADED_OUTPUT_CONTRACTS with the measured message, or give the op a contract that '\n + 'converts — an unrepresentable outputSchema throws inside tools/list and takes the whole '\n + 'listing down for every caller',\n )\n }\n\n return undefined\n}\n\n/**\n * Derive one tool's `registerTool` config.\n *\n * `advertised` is passed IN rather than looked up here so this module stays a derivation over\n * values: `catalog.ts` owns the join between the mapping's data and this host's registry, and a\n * second lookup inside the derivation would be a second chance for the two to disagree.\n *\n * `maskText` is a REQUIRED parameter and covers the DERIVED prose. The reason is the fresh wound\n * this phase inherits: 395 closed a high-severity defect where a credential reached an MCP caller\n * through a serialization nobody had thought of as an output channel. A description is composed\n * from op summaries, and a summary is prose somebody may one day interpolate a resolved value into;\n * routing it through the masker costs nothing on the ordinary path and closes the channel\n * structurally rather than by remembering. Optionality is the failure mode here — an optional\n * masker is a masker that is absent exactly where nobody looked — so the parameter has no default\n * and the type refuses a call that omits it.\n *\n * TWO THINGS ARE DELIBERATELY NOT MASKED, and both would be damage rather than safety. The `title`\n * is the curated tool NAME from the mapping table: a declared constant in this repository's own\n * source, never data, and a masker that rewrote it would rename the tool a caller must call. The\n * SCHEMAS are contracts rather than text — masking one would corrupt the very object\n * `invokeFunction` validates against, and they carry field names and types, not values.\n */\nexport function toRegisterToolConfig(\n projection: ToolProjection,\n specs: readonly ProjectedOpSpec[],\n advertised: ToolOpContracts,\n maskText: (text: string) => string,\n): RegisterToolConfig {\n if (specs.length === 0) {\n throw new McpProjectionError(\n projection.name,\n 'projects no ops; a tool with no arm has nothing to validate against and nothing to call',\n )\n }\n\n if (specs.length !== projection.ops.length) {\n // Unreachable through `catalog.ts`, which resolves every arm or none, and asserted anyway: a\n // tool derived from a SUBSET of its declared arms would advertise a contract narrower than the\n // one its handler dispatches over, and the caller who found the missing arm would be told its\n // valid input was invalid.\n throw new McpProjectionError(\n projection.name,\n `declares ${projection.ops.length} ops but was derived from ${specs.length}`,\n )\n }\n\n const outputSchema = probeOutputSchema(projection, advertised.output)\n const degradation = outputSchema === undefined\n ? DEGRADED_OUTPUT_CONTRACTS.find((entry) => entry.tool === projection.name)\n : undefined\n\n const description = describe(projection, specs)\n const meta = listingMeta(projection)\n const fold = compositionOf(projection) === 'union'\n const inputSchema = fold ? flatFoldInput(projection, advertised.input) : advertised.input\n // Converted once here, so a fold that cannot be listed fails the build rather than tools/list.\n if (fold) inputSchema['~standard'].jsonSchema.input({ target: JSON_SCHEMA_CONVERSION_TARGET })\n return {\n title: projection.name,\n description: maskText(\n degradation === undefined ? description : description + degradationSentence(degradation),\n ),\n inputSchema,\n ...(outputSchema === undefined ? {} : { outputSchema }),\n annotations: deriveAnnotations(specs),\n // 408 D-05: the App reference, DERIVED from the projection's own carrier declaration by the\n // same pipeline that derives the annotations above — never a pair of tool names written here.\n // The conditional spread is the house absent-field rule: a non-carrier's config has no `_meta`\n // key at all.\n //\n // NOT MASKED, and it joins the two exemptions the header names for their reason rather than by\n // analogy. `resourceUri` is the address constant this package publishes — a declared literal in\n // this repository's own source, exactly like the `title` above it — and a masker that rewrote\n // it would point every host at an address the resource codec refuses, which is the tool-rename\n // failure with a URI scheme attached. Nothing interpolated into it comes from a caller, from\n // storage or from a resolved value; the run id never appears here, because this is the\n // TEMPLATE and a per-call reference is composed downstream. The result-size hint (431 D-05) is\n // a declared constant too, and rides the same record (`listingMeta`).\n ...(meta === undefined ? {} : { _meta: meta }),\n }\n}\n\n/**\n * The listing `_meta` a projection declares, or `undefined` when it declares none.\n *\n * 2026-09-28 (431 D-05): the App reference and the result-size hint are independent members of one\n * record, so a tool declaring both advertises both; neither replaces the other.\n */\nfunction listingMeta(projection: ToolProjection): Record<string, unknown> | undefined {\n const meta: Record<string, unknown> = {\n ...(projection.ui === undefined ? {} : { ui: { resourceUri: APP_RESOURCE_URI_TEMPLATE } }),\n ...(projection.maxResultSizeChars === undefined\n ? {}\n : { [MAX_RESULT_SIZE_META_KEY]: projection.maxResultSizeChars }),\n }\n return Object.keys(meta).length === 0 ? undefined : meta\n}\n\ntype JsonObject = Record<string, unknown>\n\n// 2026-10-20 (446-11, D-25 · F-446-11-8): Claude Code drops a tool whose listed input is a\n// top-level oneOf. A fold therefore lists one object (an `action` enum beside its arms' fields),\n// while the SDK still validates each call against the strict union.\nfunction flatFoldInput(\n projection: ToolProjection,\n input: StandardSchemaWithJSON,\n): StandardSchemaWithJSON {\n const standard = input['~standard']\n return {\n '~standard': {\n version: standard.version,\n vendor: standard.vendor,\n validate: (value, options) => standard.validate(value, options),\n jsonSchema: {\n input: (options) => flatFoldDocument(projection, standard.jsonSchema.input(options)),\n output: (options) => standard.jsonSchema.output(options),\n },\n },\n }\n}\n\ninterface FoldField {\n readonly shapes: JsonObject[]\n readonly notes: string[]\n readonly usedBy: string[]\n readonly requiredBy: string[]\n}\n\nfunction flatFoldDocument(projection: ToolProjection, document: JsonObject): JsonObject {\n const key = projection.discriminant!\n const { oneOf, type: _type, ...rest } = document\n const arms = Array.isArray(oneOf) ? (oneOf as JsonObject[]) : []\n const unsupported = ['anyOf', 'allOf', 'properties'].filter((name) => rest[name] !== undefined)\n if (arms.length !== projection.ops.length || unsupported.length > 0) {\n throw new McpProjectionError(\n projection.name,\n `has an input contract that is not a ${projection.ops.length}-arm union of objects, so it `\n + 'cannot be listed as one object',\n )\n }\n\n const ops: string[] = []\n const fields = new Map<string, FoldField>()\n let actionNote: string | undefined\n let strict = true\n for (const arm of arms) {\n const properties = (arm.properties ?? {}) as Record<string, JsonObject>\n const opId = properties[key]?.const\n if (arm.type !== 'object' || typeof opId !== 'string' || !projection.ops.includes(opId)) {\n throw new McpProjectionError(\n projection.name,\n `has a union arm that is not an object selected by a declared ${key}`,\n )\n }\n ops.push(opId)\n if (arm.additionalProperties !== false) strict = false\n actionNote ??= properties[key]?.description as string | undefined\n const required = (arm.required ?? []) as readonly string[]\n for (const [name, schema] of Object.entries(properties)) {\n if (name === key) continue\n const field = fields.get(name) ?? { shapes: [], notes: [], usedBy: [], requiredBy: [] }\n const { description, ...shape } = schema\n if (!field.shapes.some((seen) => JSON.stringify(seen) === JSON.stringify(shape))) {\n field.shapes.push(shape)\n }\n if (typeof description === 'string' && !field.notes.includes(description)) {\n field.notes.push(description)\n }\n field.usedBy.push(opId)\n if (required.includes(name)) field.requiredBy.push(opId)\n fields.set(name, field)\n }\n }\n\n const perAction = ops.map((opId) => {\n const taken = [...fields].filter(([, field]) => field.usedBy.includes(opId))\n const listed = taken.map(([name, field]) =>\n field.requiredBy.includes(opId) ? name : `${name} (optional)`,\n )\n return `${opId} takes ${listed.length === 0 ? 'no other field' : listed.join(', ')}.`\n })\n const properties: Record<string, JsonObject> = {\n [key]: {\n type: 'string',\n enum: ops,\n description: [actionNote, ...perAction].filter(Boolean).join(' '),\n },\n }\n const required = [key]\n for (const [name, field] of fields) {\n const scope = field.usedBy.length === ops.length\n ? 'every action'\n : `${field.usedBy.join(' or ')} only`\n const need = field.requiredBy.length === 0\n ? 'optional'\n : field.requiredBy.length === field.usedBy.length\n ? 'required'\n : `required for ${field.requiredBy.join(' or ')}`\n const shape = field.shapes.length === 1 ? field.shapes[0]! : { anyOf: field.shapes }\n const description = [...field.notes, `For ${scope}; ${need}.`].join(' ')\n properties[name] = { ...shape, description }\n if (field.requiredBy.length === ops.length) required.push(name)\n }\n\n return {\n ...rest,\n type: 'object',\n properties,\n required,\n ...(strict ? { additionalProperties: false } : {}),\n }\n}\n\n/** A projection that cannot be derived honestly, named with the tool it is about. */\nexport class McpProjectionError extends Error {\n constructor(readonly toolName: string, detail: string) {\n super(`${toolName} ${detail}`)\n this.name = 'McpProjectionError'\n }\n}\n","// The entity Resource Templates surface (Phase 396 plan 03, D-13 · MCPS-02).\n//\n// WHY THIS FILE EXISTS. 387 gave every entity a published address — `agentqa://memory/MEM-001` —\n// and tool results carry those addresses as `resource_link`s. A link nothing can dereference is a\n// decoration, so this module registers the five templates that make them resolvable, and resolves\n// them the only way this package is allowed to resolve anything: `invokeFunction` on `entities.get`.\n// There is no second data path here, no store, no cache and no card rendering — `entities.get`\n// already answers \"render the thing at this address\" for every surface, and a resources handler\n// that rendered its own card would be the v1 server's mistake with a new URI scheme.\n//\n// THE TEMPLATES ARE DERIVED, NEVER RESTATED. They are built by iterating the kind vocabulary and\n// reading `ENTITY_URI_SEGMENTS`, which is the same table the codec parses with. A hand-written list\n// of five strings here would be a second vocabulary that agrees with the first until somebody\n// renames a segment — and the failure mode of that disagreement is a template advertising an\n// address the parser refuses, i.e. a door that 404s by construction.\n//\n// THE CODEC IS THE ONLY PARSER, AND THAT IS THE SECURITY PROPERTY (T-396-08). Everything reaching\n// `resources/read` is caller-supplied. `parseEntityUri` refuses `agentqa://memory/TST-001` because\n// the segment and the id prefix disagree, refuses a trailing path because a sub-resource that\n// resolves to its parent is a lie, and canonicalises `MEM-1` to `MEM-001` so one address is one\n// address. A local regex in this file would be a second, weaker reading of the same string — this\n// module therefore contains no `agentqa://` pattern of its own, and an acceptance grep pins that.\n//\n// EVERY CALLER SEES THE SAME TEMPLATES (2026-10-01, 432-20, D-12). The scope-based visibility law\n// that once withheld these from a caller granted nothing is deleted: the templates are registered\n// whenever the composition registers `entities.get`, which is a fact about the host and never\n// about the caller. Subject validation is unchanged — the codec below still refuses every address\n// it cannot parse, for every caller.\n//\n// MASKING IS REQUIRED, NOT OPTIONAL, AND FOR A MEASURED REASON. Resource contents are composed from\n// STORED DATA, and this handler is registered directly rather than through `catalog.ts`'s one\n// generic handler — so nothing masks it unless this module does. That is exactly the shape of the\n// defect this phase inherits (T-395-R5-10: a credential reaching an MCP caller verbatim through a\n// serialisation nobody had counted as an output channel), and the refusal path is masked for the\n// same reason as the success path.\n//\n// SUBSCRIPTIONS ARE NOT IMPLEMENTED, and the deferral is dated: SEP-2575 replaced\n// `resources/subscribe` + the HTTP GET stream with a single opted-in `subscriptions/listen` stream.\n// Shipping the OLD verb would be shipping a shape the 2026-07-28 protocol has already retired, and\n// shipping the new one is a transport concern this package does not own. Post-v2.0 (D-13).\n//\n// Protocol grounding: SEP-2575 (stateless protocol; the subscription model above), SEP-2549 (list\n// results carry cache hints — nothing registered here varies per call, so a listing is cacheable),\n// SEP-2106 (full JSON Schema 2020-12 for advertised contracts; resources advertise none).\n\nimport { ResourceTemplate } from '@modelcontextprotocol/server'\nimport type { ReadResourceResult, ResourceMetadata } from '@modelcontextprotocol/server'\nimport { invokeFunction } from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport {\n ENTITY_KINDS,\n ENTITY_URI_SEGMENTS,\n formatEntityUri,\n parseEntityUri,\n} from '@vostride/agent-qa-schema'\nimport type { EntityKind, FunctionCaller } from '@vostride/agent-qa-schema'\n\nimport { maskJsonDocument } from './masked-result.js'\n\n/**\n * The ONE op this surface reads through.\n *\n * A constant rather than a literal at three sites, and declared here rather than imported: the\n * function layer keeps its id constants inside its own directory and does not publish them on its\n * barrel, so the id is spelled once here.\n */\nexport const ENTITIES_GET_OP_ID = 'entities.get'\n\n/** The media type entity cards are handed out as. They are JSON documents, not prose. */\nexport const ENTITY_RESOURCE_MIME_TYPE = 'application/json'\n\n/** One derived template: everything `registerResource` needs for one kind. */\nexport interface EntityResourceTemplate {\n readonly kind: EntityKind\n readonly segment: string\n /** The registered resource name. Prefixed like the tools, so one namespace reads as one server. */\n readonly name: string\n readonly uriTemplate: string\n readonly title: string\n readonly description: string\n}\n\nfunction templateFor(kind: EntityKind): EntityResourceTemplate {\n const segment = ENTITY_URI_SEGMENTS[kind]\n return {\n kind,\n segment,\n name: `agent_qa_entity_${segment}`,\n uriTemplate: `agentqa://${segment}/{id}`,\n title: `agent-qa ${segment} entity`,\n // Authored prose about a KIND, not about any entity's content — the same class of string as a\n // tool's curated title, so it is not masked. Nothing interpolated here comes from storage.\n description:\n `The entity card for one ${segment} addressed by its canonical agentqa:// URI `\n + `(for example agentqa://${segment}/${kind}-001). Resolved through the entities read op.`,\n }\n}\n\n/**\n * The five templates, derived once at module load.\n *\n * Iterating `ENTITY_KINDS` and indexing `ENTITY_URI_SEGMENTS` is how `kinds.ts` builds its own\n * reverse table, so the listing ORDER here is the vocabulary's canonical order rather than an\n * accident of object-key iteration.\n */\nexport const ENTITY_RESOURCE_TEMPLATES: readonly EntityResourceTemplate[] =\n ENTITY_KINDS.map(templateFor)\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\nexport type EntityResourceInvoke = (opId: string, input: unknown) => Promise<unknown>\n\nexport interface EntityResourceReadDeps {\n readonly invoke: EntityResourceInvoke\n /** How text leaving this handler is masked (threat T-396-07). Required — see the header. */\n readonly maskText: (text: string) => string\n}\n\n/** A URI the one codec does not recognise as an address. */\nexport class EntityResourceUriError extends Error {\n constructor(detail: string) {\n super(`${detail} is not a canonical agentqa:// entity address`)\n this.name = 'EntityResourceUriError'\n }\n}\n\n/** A refusal from the entity read, carried out with its message masked. */\nexport class EntityResourceReadError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'EntityResourceReadError'\n }\n}\n\n/**\n * Build the read handler every template shares.\n *\n * ONE handler for all five, because the kind is already in the URI and the codec already read it:\n * a per-kind handler would be five copies of one function differing in a value it does not use.\n *\n * Exported so a cell can drive it without a server, and so the parse/refuse behaviour is observable\n * independently of registration — the two halves of D-13 fail in different directions.\n */\nexport function createEntityResourceReadHandler(\n deps: EntityResourceReadDeps,\n): (uri: URL) => Promise<ReadResourceResult> {\n return async (uri: URL): Promise<ReadResourceResult> => {\n const parsed = parseEntityUri(uri.href)\n if (parsed === undefined) {\n // The refusal is the CODEC's verdict, phrased. Nothing here re-examines the string to decide\n // WHY it failed: the codec's reasons (unknown segment, disagreeing prefix, trailing path,\n // malformed body) are its own, and re-deriving them would be the second parser by another\n // name. The echoed URI is caller-supplied text, so it is masked like everything else.\n throw new EntityResourceUriError(deps.maskText(uri.href))\n }\n\n let card: unknown\n try {\n // The canonical short-ID, not the raw URI. `entities.get` accepts both, and passing the\n // parsed value is what makes the parse load-bearing rather than a check that happens to run\n // before a string is forwarded untouched.\n card = await deps.invoke(ENTITIES_GET_OP_ID, { ref: parsed.shortId })\n } catch (err) {\n throw new EntityResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n\n // MASKED AS A VALUE, NEVER AS A SERIALIZATION (CR-01, 2026-08-16). This line used to read\n // `deps.maskText(JSON.stringify(card))`, which handed a literal-substring masker an ESCAPED\n // document: a stored value containing `\"`, `\\` or a control character does not occur in it, so\n // the masker matched nothing and the card reached the caller verbatim. `maskJsonDocument` walks\n // the card and masks its string leaves and keys instead — the same one masking `masked-result.\n // ts` performs for tool results, shared rather than restated, because two answers to \"how is a\n // JSON payload masked\" is exactly how one channel drifts open while the other looks closed.\n const masked = maskJsonDocument(card, deps.maskText)\n if (masked === undefined) {\n // FAILS CLOSED, like the tool channel: a card whose masked form would not be the same kind of\n // value is withheld rather than served. The message names the condition and quotes nothing.\n throw new EntityResourceReadError(\n 'This entity could not be returned: part of its card could not be masked in place, so the '\n + 'unmasked record was withheld rather than served.',\n )\n }\n\n return {\n contents: [\n {\n // Re-FORMATTED through the codec rather than echoed: the address a caller reads back is\n // the canonical one, so `agentqa://memory/MEM-1` answers about `MEM-001` and says so.\n uri: formatEntityUri(parsed.kind, parsed.shortId),\n mimeType: ENTITY_RESOURCE_MIME_TYPE,\n text: masked.text,\n },\n ],\n }\n }\n}\n\n/**\n * The slice of `McpServer` this module uses.\n *\n * ONE signature — the SDK's template overload, spelled with the SDK's own `ResourceMetadata` and\n * `ReadResourceResult` — so a cell can observe every registration without assembling a protocol\n * server while a real `McpServer` still satisfies it. Both halves of that depend on the types\n * matching the SDK EXACTLY: a hand-narrowed config record, or a hand-narrowed result with a\n * `readonly` contents array, makes `McpServer` unassignable here (overload resolution then fails on\n * the string overload, whose message names a mismatch that is not the real one). Measured, not\n * assumed — the SDK cell in this module's tests registers on a real server, so this interface\n * cannot drift away from the thing it stands for without a compile error.\n */\nexport interface EntityResourceRegistrar {\n registerResource(\n name: string,\n template: ResourceTemplate,\n config: ResourceMetadata,\n read: (uri: URL) => Promise<ReadResourceResult>,\n ): unknown\n}\n\n/** Exactly what this module needs from the host — the same record `catalog.ts` already holds. */\nexport interface EntityResourceDeps {\n readonly registry: FunctionRegistry\n readonly caller: FunctionCaller\n readonly maskText: (text: string) => string\n}\n\n/**\n * Register the entity resource templates this caller may use, and answer which those were.\n *\n * Returns the registered templates rather than nothing, so the gate below is observable from the\n * outside: \"registered none\" and \"registered five\" are the two halves of D-05's claim, and a caller\n * that had to inspect a server to tell them apart could only ever test one of them.\n *\n * A composition that never registered `entities.get` gets NO templates and no error, which is the\n * same answer `catalog.ts` gives a tool whose op is missing: refusing to build would take a whole\n * MCP connection down because one capability was unavailable.\n */\nexport function registerEntityResources(\n server: EntityResourceRegistrar,\n deps: EntityResourceDeps,\n): readonly EntityResourceTemplate[] {\n const declaration = deps.registry\n .list(deps.caller)\n .find((candidate) => candidate.id === ENTITIES_GET_OP_ID)\n if (declaration === undefined) return []\n\n const read = createEntityResourceReadHandler({\n // The wall, bound once: every template's read crosses `invokeFunction` with this host's\n // registry and this caller, so input validation and the binding check run exactly as they do\n // for a tool call.\n invoke: (opId, input) => invokeFunction(deps.registry, opId, input, deps.caller),\n maskText: deps.maskText,\n })\n\n for (const template of ENTITY_RESOURCE_TEMPLATES) {\n server.registerResource(\n template.name,\n // `list: undefined` is REQUIRED to be spelled out by the SDK, and the value is the honest\n // one: enumerating every entity of a kind is a listing this surface does not offer, and the\n // SDK asks for the explicit `undefined` precisely so that absence is a decision.\n new ResourceTemplate(template.uriTemplate, { list: undefined }),\n // v2 requires the metadata argument; it is not optional the way it was in v1.\n {\n title: template.title,\n description: template.description,\n mimeType: ENTITY_RESOURCE_MIME_TYPE,\n },\n read,\n )\n }\n\n return ENTITY_RESOURCE_TEMPLATES\n}\n","// The loopback HTTP face of the same catalog (Phase 396 plan 01, D-10 / MCPS-05).\n//\n// WHY THIS FILE EXISTS, AND WHY IT EXISTS NOW rather than with the plan that first mounts it. Two\n// consumers need an HTTP face of this server and neither is a product feature: the conformance\n// suite's `server` mode takes a URL and cannot spawn a stdio command (measured in this phase's\n// research — D-17's stated shape is unrunnable as written), and any driver that wants to exercise\n// the wire without a child process reaches for the same handler. Shipping the FACTORY here, with no\n// socket and no lifecycle, is what lets plan 07 point `conformance server --url` at the shipped\n// artifact instead of at something a CI script assembled.\n//\n// IT BINDS NOTHING. `createAgentQaMcpNodeHandler` returns a request FUNCTION. Creating a server,\n// choosing a port, deciding which interface to listen on and validating Host/Origin are all the\n// host's, which is what keeps this package free of every host API — it names no `node:` module, and\n// neither does the adapter it calls, because the SDK's own adapter is duck-typed for exactly this.\n//\n// THE V1 WILDCARD CORS HEADER IS NOT CARRIED FORWARD, and this comment is where a future reader who\n// goes looking for it finds out why. The deleted `local-http.ts` answered every request and every\n// preflight with `Access-Control-Allow-Origin: *`, which on a loopback JSON-RPC endpoint invites the\n// DNS-rebinding reach the v2 docs put host and origin guards in front of the handler to refuse.\n// Nothing here emits a CORS header; a host that decides it needs one is deciding that on purpose.\n//\n// Protocol grounding: SEP-2575 (stateless — the factory below runs once per REQUEST, holds nothing\n// between them, and there is no session id anywhere), SEP-2567 (list results no longer vary per\n// connection). 2026-10-02 (432-42, D-12): no list varies by caller either — every caller sees and\n// calls the same twenty tools, with no token.\n\nimport { createMcpHandler } from '@modelcontextprotocol/server'\nimport type { McpRequestContext } from '@modelcontextprotocol/server'\nimport { toNodeHandler } from '@modelcontextprotocol/node'\n\nimport { buildAgentQaMcpServer } from './catalog.js'\nimport type { AgentQaMcpServerDeps } from './catalog.js'\n\n/**\n * How a host composes the server for one request.\n *\n * It takes the SDK's own construction context, so a per-request fact such as `era` arrives here\n * rather than being read back out of a header inside a tool handler. What it returns is the same\n * `deps` a stdio host composes, which is what keeps ONE `buildAgentQaMcpServer` shape across both\n * transports. 2026-10-02 (432-42, D-12): nothing about the caller decides what it may see; the\n * shipped host passes one fixed tokenless caller.\n */\nexport type AgentQaMcpDepsResolver = (ctx: McpRequestContext) => AgentQaMcpServerDeps\n\n/**\n * A Node request handler serving this catalog over stateless streamable HTTP.\n *\n * The factory is re-run per request, which is the SDK's own model and not an inefficiency to route\n * around: a per-request instance is what makes a caller's tool set a property of that caller rather\n * than of whoever connected first, and it is why absence stays structural on this transport too.\n *\n * IT TAKES A RESOLVER AND NOT A FIXED `deps` (plan 05). 2026-10-02 (432-42, D-12/D-13): the\n * bearer check that once sat in front of this handler is deleted with MCP tokens (432-21); what\n * stays in front of it is the host's Host and Origin guard on the loopback listener. The resolver\n * receives the SDK context and builds the instance; it reads no header and verifies nothing.\n *\n * A host with one fixed caller passes `() => deps` — the static case is the degenerate resolver,\n * not a second signature to keep in step.\n */\nexport function createAgentQaMcpNodeHandler(resolveDeps: AgentQaMcpDepsResolver) {\n return toNodeHandler(createMcpHandler((ctx) => buildAgentQaMcpServer(resolveDeps(ctx))))\n}\n","// The ONE lens two schema-comparison suites look through (2026-08-16, Phase 397 D-06 · MCPS-02).\n//\n// WHAT THIS FILE IS. Four normalisations that make an advertised JSON-Schema document and the\n// function layer's own inert projection comparable, plus one fold check (`foldArmFindings`,\n// 2026-10-20, 446-11), and NOTHING ELSE. It converts nothing, builds\n// nothing, reaches nothing: the functions below are pure, take plain objects, return plain objects,\n// and name no package. That is why the file adds no entry to this package's dependency census —\n// there is no specifier in it to add.\n//\n// WHY IT MOVED HERE OUT OF A TEST. It was authored inside `projection-fidelity.test.ts`, where it\n// had exactly one consumer. Phase 397's conformance suite lives in `packages/cli` and needs the\n// same lens for its structural-schema-equality leg, and no package may reach another package's\n// `__tests__` directory. The two ways out were to publish the lens or to re-derive it, and D-06\n// rules out the second by name: a second conversion recipe for one comparison is the\n// redundant-mechanism trap, and the way it fails is silent — the copy that drifts looser is the\n// one that passes over real drift, and nothing compares the two copies to each other.\n//\n// SO THE TWO CONSUMERS SHARE ONE OBJECT: this package's own fidelity suite, and 397's parity suite\n// over in the cli package. A third would be a third consumer of the same object, not a third lens.\n//\n// WHY THE NORMALISATIONS EXIST AT ALL (MCPS-07's citation, and the honest one). Both stamps\n// they remove are artifacts of the SDK's own conversion under SEP-2106's full JSON Schema 2020-12\n// posture for tool input/output schemas, produced by the converter SEP-1613 pins on the SDK side:\n// the `$schema` dialect marker it writes, and the `type: \"object\"` it adds to a composition root it\n// can prove is object-shaped. The function layer's projection speaks the same vocabulary and writes\n// neither. Nothing here normalises a difference the PRODUCT introduced — only two the transport's\n// converter did. The fourth (431-03) undoes the 2025-11-25 codec's `{ result }` wrap around a\n// non-object output root, which is likewise the transport's and not the product's.\n//\n// READ THE DOCSTRINGS BEFORE WIDENING ANYTHING. Each normalisation is gated as narrowly as it is\n// for a MEASURED reason, recorded in its own comment. A strip that dropped content rather than a\n// dialect marker or an SDK stamp would be the way to make a drift cell pass over a contract that\n// genuinely moved — which is the one failure the suites consuming this file exist to catch.\n\n/** A JSON-Schema document as it travels: an ordinary object, with nothing runnable on it. */\nexport type JsonDocument = Record<string, unknown>\n\n/**\n * Drop `$schema`, which the SDK's conversion stamps and the registry's projection does not.\n *\n * A DIALECT MARKER, not content: it says which JSON Schema draft the document speaks and describes\n * nothing about the contract. Removing it is the one normalisation this file performs, and it is\n * called out rather than buried because a normalisation that removed content would be the way to\n * make a drift cell pass over real drift.\n */\nexport function withoutDialect(document: unknown): JsonDocument {\n const { $schema: _dialect, ...rest } = (document ?? {}) as JsonDocument\n return stripRedundantObjectStamp(rest)\n}\n\n/**\n * Drop the `type: \"object\"` the SDK stamps onto a COMPOSITION root.\n *\n * The second and last normalisation, and it is as narrow as the first. `standardSchemaToJsonSchema`\n * stamps `type: \"object\"` on a typeless root it can prove is object-shaped — a `oneOf` whose every\n * member is `type: \"object\"`, which is exactly what a zod discriminated union emits. The SDK's own\n * comment calls the stamp \"redundant-but-valid\", and a document is not changed by adding a\n * constraint every one of its branches already imposes.\n *\n * IT IS GATED ON THE COMPOSITION KEYWORD, so a genuine `type` disagreement still reds: the only\n * case dropped is a root that carries `oneOf`/`anyOf` AND the stamp, which is the one case the SDK\n * manufactures. An ungated `delete document.type` would have made the whole drift cell blind to a\n * contract whose root type actually moved.\n */\nexport function stripRedundantObjectStamp(document: JsonDocument): JsonDocument {\n const composed = document.oneOf !== undefined || document.anyOf !== undefined\n if (!composed || document.type !== 'object') return document\n const { type: _stamp, ...rest } = document\n return rest\n}\n\n/**\n * One union arm of a fold's composed contract, with the fold's discriminant taken back out.\n *\n * `required: []` is DROPPED rather than kept, and the case is real rather than defensive:\n * `config.undo.propose` takes an all-optional input, so its own projection carries no `required`\n * key at all while the extended arm carries `['action']` — and removing the discriminant from that\n * leaves an empty array where the other side has nothing. JSON Schema reads an absent `required`\n * and an empty one identically, so the two documents agree; keeping the empty array would have\n * failed the cell on a difference that describes no difference.\n */\nexport function armWithoutDiscriminant(arm: JsonDocument, discriminant: string): JsonDocument {\n const properties = { ...((arm.properties ?? {}) as JsonDocument) }\n delete properties[discriminant]\n const required = ((arm.required ?? []) as readonly string[]).filter((key) => key !== discriminant)\n const rebuilt: JsonDocument = { ...arm, properties, required }\n if (required.length === 0) delete rebuilt.required\n return rebuilt\n}\n\n/**\n * What a fold's one listed object leaves out of, or adds to, one arm's own contract.\n *\n * 2026-10-20 (446-11, D-25): a fold lists one object instead of its union, so an arm is no longer\n * a member to compare whole. It is covered when the `discriminant` enum names it, every field it\n * takes is listed with its own shape (the listing may add a description, never drop one), and the\n * listing requires nothing the arm does not. That a call is still validated arm by arm is the\n * C446-TOOL-SCHEMA counter-cell's claim, not this lens's.\n */\nexport function foldArmFindings(\n listed: JsonDocument,\n discriminant: string,\n opId: string,\n own: JsonDocument,\n): readonly string[] {\n const findings: string[] = []\n for (const key of ['oneOf', 'anyOf', 'allOf']) {\n if (listed[key] !== undefined) findings.push(`the listing carries a top-level ${key}`)\n }\n if (listed.type !== 'object') findings.push('the listing is not type object')\n const properties = (listed.properties ?? {}) as Record<string, JsonDocument>\n const selector = properties[discriminant]?.enum\n if (!Array.isArray(selector) || !selector.includes(opId)) {\n findings.push(`${discriminant} does not list ${opId}`)\n }\n const ownProperties = (own.properties ?? {}) as Record<string, JsonDocument>\n for (const [name, field] of Object.entries(ownProperties)) {\n const shown = properties[name]\n if (shown === undefined) {\n findings.push(`${name} is not listed`)\n continue\n }\n const { description: ownNote, ...ownShape } = field\n const { description: shownNote, ...shownShape } = shown\n const merged = Array.isArray(shownShape.anyOf) && Object.keys(shownShape).length === 1\n const shapes = merged ? [shownShape, ...(shownShape.anyOf as readonly unknown[])] : [shownShape]\n if (!shapes.some((shape) => JSON.stringify(shape) === JSON.stringify(ownShape))) {\n findings.push(`${name} is listed with another shape`)\n }\n const kept = typeof shownNote === 'string' && shownNote.includes(String(ownNote))\n if (typeof ownNote === 'string' && !kept) {\n findings.push(`${name} lost its own description`)\n }\n }\n const allowed = new Set([discriminant, ...((own.required ?? []) as readonly string[])])\n for (const name of (listed.required ?? []) as readonly string[]) {\n if (!allowed.has(name)) findings.push(`the listing requires ${name}, which ${opId} does not`)\n }\n if (own.additionalProperties === false && listed.additionalProperties !== false) {\n findings.push('the listing admits fields no arm takes')\n }\n return findings\n}\n\n/**\n * Undo the SEP-2106 legacy `{ result }` wrap the SDK's 2025-11-25 codec puts around a non-object\n * output root (2026-09-28, 431-03).\n *\n * A transport artifact, like the two stamps above: the 2026-07-28 codec advertises a list's array\n * root as-is, while the 2025-11-25 codec projects it to `{ type: 'object', properties: { result },\n * required: ['result'] }` and wraps `structuredContent` to match. Gated to exactly that document —\n * nothing but those three keys (and a dialect marker), one property named `result`, and a wrapped\n * root that is not itself an object — so an op whose real output is an object with a `result`\n * field is left alone. Apply it BEFORE `withoutDialect`: the wrapped root keeps its own `$schema`.\n */\nexport function withoutLegacyResultWrap(document: unknown): JsonDocument {\n const wrapper = (document ?? {}) as JsonDocument\n const keys = Object.keys(wrapper).filter((key) => key !== '$schema').sort()\n if (keys.join(',') !== 'properties,required,type' || wrapper.type !== 'object') return wrapper\n const properties = wrapper.properties as JsonDocument\n const required = wrapper.required as unknown\n if (Object.keys(properties ?? {}).join(',') !== 'result') return wrapper\n if (!Array.isArray(required) || required.length !== 1 || required[0] !== 'result') return wrapper\n const natural = properties.result as JsonDocument\n if (typeof natural !== 'object' || natural === null || natural.type === 'object') return wrapper\n return natural\n}\n","// The dormant JobView -> Task projection (Phase 396 plan 03, D-12 · MCPS-06).\n//\n// WHY THIS FILE EXISTS, AND WHY IT DOES NOTHING. MCPS-06 asks for the seam between agent-qa's job\n// queue and MCP's long-running-task vocabulary to EXIST, so that the day the vocabulary settles the\n// work is a registration and not a re-derivation. It does not ask for the seam to be wired, and\n// wiring it today would be wiring this surface to something that is not there.\n//\n// C-MCP-3, dated 2026-07-28 — the deferral, with its evidence:\n// * Tasks were REMOVED from the core protocol into an official extension,\n// `io.modelcontextprotocol/tasks` (SEP-2663). `tasks/result` became polling `tasks/get` +\n// `tasks/update`, and `tasks/list` was removed outright.\n// * That extension ships no npm package, and its own README calls it unofficial.\n// * The SDK this package builds on (`@modelcontextprotocol/server` 2.0.0) carries the older\n// vocabulary marked, verbatim: \"@deprecated 2025-11-25 wire vocabulary with no SDK runtime;\n// kept importable for interoperability only\" — and excludes `tasks/*` from its typed method\n// maps, so there is no runtime to register against even if one wanted to.\n// * No conformance tier requires tasks (SEP-1730).\n// Four independent reasons pointing the same way. A projection written against a vocabulary in that\n// state is worth having; a REGISTRATION against it is a public promise this server cannot keep.\n//\n// WHAT THIS MODULE DELIBERATELY DOES NOT DO. It registers nothing, advertises nothing and routes\n// nothing. `catalog.ts` does not import it — that absence is import-anchored by an acceptance grep\n// rather than asserted in prose, because a comment cannot hold a coupling shut. It reaches no port,\n// no host API and no sibling module: one exported pure function, one exported table, one type.\n//\n// IT CONSUMES THE PUBLIC READ DTO AND NOTHING ELSE. `Job` — the schema package's published job\n// record, which is what D-12 calls the JobView — is the whole input. The JobQueue CONTRACT (claim,\n// heartbeat, bounded retry, the `attempts`-at-claim discipline) never crosses into this package,\n// and that is the coupling MCPS-06 is actually about: a seam that took the queue port would make\n// every queue change an MCP change.\n//\n// THE MAPPING IS LOSSY, AND THE LOSS IS THE RECONCILIATION. agent-qa's four non-terminal statuses\n// are CHECKPOINT BOUNDARIES, chosen so that a job resumed after a crash never re-invokes the LLM\n// for work it already paid for; MCP's states are what a REMOTE POLLER needs, and a poller is asking\n// exactly one question — \"may I stop polling yet?\". `queued`, `authored`, `bundling` and\n// `committing` are four different answers to a question the poller is not asking, so they collapse\n// onto `working`. The three terminal statuses stay distinct, because \"someone stopped this\" and\n// \"this is broken\" are not the same answer.\n//\n// THE RESULT IS NOT A WIRE `Task`, AND IS NOT TYPED AS ONE. It carries the wire's FIELD NAMES so\n// that the eventual registration is a pass-through rather than a rename, but it omits `ttl` and\n// `pollInterval` — transport-lifecycle facts that a projection of a job record cannot know and must\n// not invent — and it does not import the SDK's deprecated `Task` type, because importing a type\n// marked \"no SDK runtime\" would be this package taking a dependency on a vocabulary it has just\n// finished arguing is not ready. The type is mcp-local for the same reason it is small: it crosses\n// no package boundary, so the DTO house law (mint shared vocabulary in `schema`) does not reach it.\n//\n// Protocol grounding: SEP-2663 (tasks moved out of core into the tasks extension; polling model),\n// SEP-2575 (the stateless protocol that made a pollable handle the only shape a long-running\n// operation can take).\n\nimport type { Job, JobStatus } from '@vostride/agent-qa-schema'\n\n/**\n * The MCP task states this projection can produce.\n *\n * Four of the wire's five. The fifth, `input_required`, is deliberately absent from the table\n * below and NOT from this union: it is a real state of the protocol that no agent-qa job status\n * currently means, and a future status that did mean it should be able to say so by adding one row\n * rather than by widening a type.\n */\nexport type McpTaskState = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled'\n\n/**\n * The whole mapping, as data.\n *\n * `as const satisfies Record<JobStatus, McpTaskState>` is what makes this exhaustive AT COMPILE\n * TIME: add an eighth member to `JobStatus` and this object stops satisfying the record, so the\n * build fails at the one place that has to make a decision about it. The alternative — a `switch`\n * with a `default` — is the same table with a hole in it, and the hole answers `working` for a\n * status nobody has thought about yet, which is the wrong answer precisely when it matters.\n *\n * Exported because the table IS the reconciliation D-12 asks to be pinned, and a later phase\n * registering the extension will read it rather than restate it.\n */\nexport const JOB_STATUS_TO_MCP_TASK_STATE = {\n // The four checkpoint boundaries. One answer, four times, on purpose.\n queued: 'working',\n authored: 'working',\n bundling: 'working',\n committing: 'working',\n // The three terminal states, kept apart.\n done: 'completed',\n failed: 'failed',\n cancelled: 'cancelled',\n} as const satisfies Record<JobStatus, McpTaskState>\n\n/**\n * What one job looks like to a remote poller.\n *\n * Field names are the wire's (`taskId`, `statusMessage`, `lastUpdatedAt`) rather than the job\n * record's, because this record's whole purpose is to be handed OUT: naming it after the source\n * would push the rename onto the registration, which is the step this seam exists to make trivial.\n * `lastUpdatedAt` carries `Job.updatedAt` verbatim; only the label differs.\n */\nexport interface McpTaskProjection {\n readonly taskId: string\n readonly status: McpTaskState\n /** The job's own one-line summary. The only prose that crosses. */\n readonly statusMessage: string\n readonly createdAt: string\n readonly lastUpdatedAt: string\n}\n\n/**\n * Project one job record into the task view.\n *\n * Total, pure, synchronous, and deliberately narrow. `attempts`, `kind`, `runRef` and\n * `conclusionKind` are NOT carried, and their absence is asserted by an exact-key cell rather than\n * left to be noticed: `attempts` is the retry discipline's private counter, and `conclusionKind` is\n * internal vocabulary (`knowledge_skipped_draft`, `insufficient_model_output`) that means nothing to\n * a caller outside this system. A projection that leaks the source record's shape is not a\n * projection; it is the coupling with an extra step.\n *\n * NOTHING IS MASKED HERE, and that is a statement rather than an oversight. This function is called\n * by nothing — it registers no handler and returns no result to any transport — so there is no\n * output channel to mask. Whoever eventually registers it inherits the masking obligation every\n * other handler in this package carries, because `statusMessage` is a job's own summary text and\n * summaries are prose somebody may one day interpolate a resolved value into.\n */\nexport function projectJobAsTask(job: Job): McpTaskProjection {\n return {\n taskId: job.id,\n status: JOB_STATUS_TO_MCP_TASK_STATE[job.status],\n statusMessage: job.summary,\n createdAt: job.createdAt,\n lastUpdatedAt: job.updatedAt,\n }\n}\n"],"mappings":"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","names":["invokeFunction","properties","required","ResourceTemplate","invokeFunction","invokeFunction","ResourceTemplate","invokeFunction"]}
1
+ {"version":3,"sources":["../src/catalog.ts","../src/app-resource.ts","../src/app-wrapper.ts","../src/live-link.ts","../src/instructions.ts","../src/mapping.ts","../src/masked-result.ts","../src/projection.ts","../src/resources.ts","../src/http.ts","../src/conformance-support.ts"],"sourcesContent":["// Handlers only validate and call `invokeFunction`; every caller sees one catalogue (SEP-2567).\n\nimport { McpServer } from '@modelcontextprotocol/server'\nimport type { CallToolResult } from '@modelcontextprotocol/server'\nimport { invokeFunction, RUNS_ARTIFACT_FUNCTION_ID } from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport type { FunctionCaller } from '@vostride/agent-qa-schema'\n\nimport { MCP_APPS_EXTENSION_ID, appResourceUriFor, registerAppResources } from './app-resource.js'\nimport { AGENT_QA_MCP_INSTRUCTIONS } from './instructions.js'\nimport { liveLinkLineFor } from './live-link.js'\nimport type { LiveLinkSupplier } from './live-link.js'\nimport {\n advertisedContracts,\n AGENT_QA_OP_CONTRACTS,\n AGENT_QA_TOOL_PROJECTIONS,\n compositionOf,\n} from './mapping.js'\nimport type { ToolProjection } from './mapping.js'\nimport {\n decorateRunEvidenceImage,\n maskedToolError,\n maskedToolResult,\n} from './masked-result.js'\nimport { McpProjectionError, toRegisterToolConfig } from './projection.js'\nimport type { ProjectedOpSpec } from './projection.js'\nimport { registerEntityResources } from './resources.js'\n\n// A constant: reading `package.json` at runtime is a host capability this package lacks.\nexport const AGENT_QA_MCP_SERVER_VERSION = '2.0.0'\n\n/** What a host must supply to build a server for one caller. */\nexport interface AgentQaMcpServerDeps {\n // Built by the host, never by this package.\n readonly registry: FunctionRegistry\n // Passed through untouched to `invokeFunction`; nothing here reads it to decide what to serve.\n readonly caller: FunctionCaller\n // Required: an optional masker is absent exactly where nobody thought to pass one.\n readonly maskText: (text: string) => string\n // A factory, because on the co-hosted composition the origin exists only once a port is bound.\n readonly liveLink?: LiveLinkSupplier\n}\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\ntype BoundInvoke = (opId: string, input: unknown) => Promise<unknown>\n\n/**\n * Join the mapping's declared contracts with this host's registry declarations.\n *\n * Returns `undefined` when any arm is missing from the registry — which is a REAL answer and not an\n * error: a projection naming an op a given composition does not register is a tool that composition\n * genuinely cannot serve, and refusing to build the whole server over it would take an editor's MCP\n * connection down because one capability was unavailable. A contract missing from the mapping table\n * IS an error, because that is this repository disagreeing with itself.\n */\nfunction resolveSpecs(\n projection: ToolProjection,\n declarations: ReadonlyMap<string, ProjectedOpSpec>,\n): readonly ProjectedOpSpec[] | undefined {\n const specs: ProjectedOpSpec[] = []\n for (const opId of projection.ops) {\n const resolved = declarations.get(opId)\n if (resolved === undefined) return undefined\n specs.push(resolved)\n }\n return specs\n}\n\n// A second reading of the arm: the schema package and `mapping.ts` can drift apart.\nfunction selectFoldArm(\n projection: ToolProjection,\n args: unknown,\n): { readonly opId: string; readonly input: Record<string, unknown> } {\n const key = projection.discriminant!\n const record = (args ?? {}) as Record<string, unknown>\n const selected = record[key]\n if (typeof selected !== 'string' || !projection.ops.includes(selected)) {\n throw new McpProjectionError(\n projection.name,\n `was called with ${key}=${JSON.stringify(selected)}, which is not one of the ops it declares`,\n )\n }\n // The discriminant is WIRE vocabulary and stops here: what crosses the function-layer wall is the\n // object `invokeFunction` will parse against the op's own `.strict()` contract, which would refuse\n // the extra key.\n const { [key]: _arm, ...input } = record\n return { opId: selected, input }\n}\n\n/** The one arm of an entity resolution that has something further to fetch. */\nfunction resolvedCardId(resolution: unknown): string | undefined {\n if (typeof resolution !== 'object' || resolution === null) return undefined\n const record = resolution as { kind?: unknown; card?: unknown }\n if (record.kind !== 'resolved') return undefined\n const card = record.card as { id?: unknown } | undefined\n return typeof card?.id === 'string' ? card.id : undefined\n}\n\n/**\n * Run one projected call and answer what the op answered, with the op that answered it.\n *\n * Every branch is `invokeFunction` and argument shuffling. Nothing computes a result, nothing reads\n * a store, nothing decides a policy.\n */\nasync function runProjection(\n projection: ToolProjection,\n args: unknown,\n invoke: BoundInvoke,\n): Promise<{ readonly opId: string; readonly output: unknown }> {\n switch (compositionOf(projection)) {\n case 'single':\n return { opId: projection.ops[0]!, output: await invoke(projection.ops[0]!, args) }\n case 'union': {\n const arm = selectFoldArm(projection, args)\n return { opId: arm.opId, output: await invoke(arm.opId, arm.input) }\n }\n case 'pipeline': {\n // Resolve, then re-read the one resolved entity at its canonical address with `entities.get`.\n const resolution = await invoke(projection.ops[0]!, args)\n const id = resolvedCardId(resolution)\n if (id === undefined) return { opId: projection.ops[0]!, output: resolution }\n const card = await invoke(projection.ops[1]!, { ref: id })\n return { opId: projection.ops[1]!, output: { ...(resolution as Record<string, unknown>), card } }\n }\n }\n}\n\n/**\n * The concrete run this carrier's result is ABOUT, read from the source the projection declares.\n *\n * DEFENSIVE ON BOTH ARMS, and neither arm is hypothetical. `runIdFrom: 'input'` reads the args the\n * SDK already validated against the advertised input schema; `runIdFrom: 'output'` reads the op's\n * own result, which is a `RunStartAcknowledgement` today and could be a fold's arm tomorrow. Either\n * can answer with something that is not a string — and the honest treatment of that is the same as\n * the honest treatment of a missing dashboard: the LINE becomes the named absence and there is no\n * concrete App address to advertise. What it must never be is a crash, because that would turn a\n * decoration into a way to fail a tool call that had already succeeded.\n */\nfunction carrierRunIdOf(\n projection: ToolProjection,\n args: unknown,\n output: unknown,\n): string | undefined {\n const source = projection.ui?.runIdFrom === 'output' ? output : args\n const runId = (source as { runId?: unknown } | null | undefined)?.runId\n return typeof runId === 'string' && runId !== '' ? runId : undefined\n}\n\n// Additive only: a masked link line and `_meta.ui.resourceUri`, attached without negotiation.\nfunction decorateCarrierResult(input: {\n readonly result: CallToolResult\n readonly projection: ToolProjection\n readonly args: unknown\n readonly output: unknown\n readonly maskText: (text: string) => string\n readonly liveLink?: LiveLinkSupplier\n}): CallToolResult {\n if (input.projection.ui === undefined) return input.result\n if (input.result.isError === true) return input.result\n\n const runId = carrierRunIdOf(input.projection, input.args, input.output)\n const line = liveLinkLineFor(input.liveLink?.dashboardBaseUrl(), runId)\n\n return {\n ...input.result,\n content: [...input.result.content, { type: 'text' as const, text: input.maskText(line) }],\n ...(runId === undefined\n ? {}\n : { _meta: { ...input.result._meta, ui: { resourceUri: appResourceUriFor(runId) } } }),\n }\n}\n\n/**\n * The one generic tool handler.\n *\n * Input validation happened twice before the invoke — once by the SDK against the tool's input\n * contract, once inside `invokeFunction` against the op's own — and both parses are kept, because\n * they are the same check made by two independent parties.\n */\nfunction createProjectionHandler(\n projection: ToolProjection,\n invoke: BoundInvoke,\n maskText: (text: string) => string,\n liveLink?: LiveLinkSupplier,\n) {\n return async (args: unknown): Promise<CallToolResult> => {\n try {\n const { opId, output } = await runProjection(projection, args, invoke)\n // Both channels come from one masked serialization, so `structuredContent` holds no secret.\n const masked = maskedToolResult(output, maskText)\n // The image block is decided after masking, so no bytes sit beside a withheld result.\n const result = opId === RUNS_ARTIFACT_FUNCTION_ID\n ? decorateRunEvidenceImage({ result: masked, output, maskText })\n : masked\n return decorateCarrierResult({\n result,\n projection,\n args,\n output,\n maskText,\n ...(liveLink === undefined ? {} : { liveLink }),\n })\n } catch (err) {\n // A refusal is a readable tool error, masked because an error string can carry a credential.\n return maskedToolError(err, maskText)\n }\n }\n}\n\n// The listing comes from `registry.list(deps.caller)`, so it describes this composition.\nexport function buildAgentQaMcpServer(deps: AgentQaMcpServerDeps): McpServer {\n const server = new McpServer(\n { name: 'agent-qa', version: AGENT_QA_MCP_SERVER_VERSION },\n {\n capabilities: {\n tools: {},\n resources: {},\n // Extensions are bilateral opt-in: a host asks only for an App the server advertises.\n extensions: { [MCP_APPS_EXTENSION_ID]: {} },\n },\n // Instructions reach every MCP host, so init's pointer goes here.\n instructions: AGENT_QA_MCP_INSTRUCTIONS,\n },\n )\n\n const invoke: BoundInvoke = (opId, input) =>\n invokeFunction(deps.registry, opId, input, deps.caller)\n\n const declarations = new Map<string, ProjectedOpSpec>()\n for (const declaration of deps.registry.list(deps.caller)) {\n const contracts = AGENT_QA_OP_CONTRACTS[declaration.id]\n if (contracts === undefined) continue\n declarations.set(declaration.id, {\n id: declaration.id,\n summary: declaration.summary,\n risk: declaration.risk,\n input: contracts.input,\n output: contracts.output,\n })\n }\n\n const registered = new Set<string>()\n for (const projection of AGENT_QA_TOOL_PROJECTIONS) {\n if (registered.has(projection.name)) {\n // Unreachable while the mapping table holds distinct names, and asserted anyway: a silent\n // last-wins here would drop a capability from every caller's vocabulary.\n throw new McpProjectionError(\n projection.name,\n 'is declared twice in the mapping table; another projection already occupies that name',\n )\n }\n\n for (const opId of projection.ops) {\n if (AGENT_QA_OP_CONTRACTS[opId] === undefined) {\n throw new McpProjectionError(\n projection.name,\n `names op ${opId}, which has no entry in the contract table`,\n )\n }\n }\n\n const advertised = advertisedContracts(projection)\n if (advertised === undefined) {\n throw new McpProjectionError(\n projection.name,\n 'has no advertised contract; a multi-arm tool needs an entry in AGENT_QA_COMPOSED_CONTRACTS',\n )\n }\n\n const specs = resolveSpecs(projection, declarations)\n if (specs === undefined) continue\n\n registered.add(projection.name)\n const config = toRegisterToolConfig(projection, specs, advertised, deps.maskText)\n\n server.registerTool(\n projection.name,\n config,\n createProjectionHandler(projection, invoke, deps.maskText, deps.liveLink),\n )\n }\n\n // Registered here so a `resource_link` resolves on the instance that produced it.\n registerEntityResources(server, {\n registry: deps.registry,\n caller: deps.caller,\n maskText: deps.maskText,\n })\n\n // Registered here so `_meta.ui.resourceUri` resolves on the instance that advertised it.\n registerAppResources(server, {\n registry: deps.registry,\n caller: deps.caller,\n maskText: deps.maskText,\n // The same supplier the carrier decoration reads, so both name one page for one run.\n ...(deps.liveLink === undefined ? {} : { liveLink: deps.liveLink }),\n })\n\n return server\n}\n","// Each read mints the token the document carries, so it is unlisted and never cached (SEP-2575).\n\nimport { CLIENT_CAPABILITIES_META_KEY, ResourceTemplate } from '@modelcontextprotocol/server'\nimport type {\n ClientCapabilities,\n ReadResourceResult,\n ReadResourceTemplateCallback,\n RequestMetaEnvelope,\n ResourceMetadata,\n ServerContext,\n Variables,\n} from '@modelcontextprotocol/server'\nimport {\n invokeFunction,\n FunctionNotBoundError,\n LiveViewUnavailableError,\n RUNS_EVENTS_FUNCTION_ID,\n RUNS_LIVE_URL_FUNCTION_ID,\n UnknownRunError,\n} from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport { handleRosterOf, RunsLiveUrlInputSchema } from '@vostride/agent-qa-schema'\nimport type {\n FunctionCaller,\n RunEventEnvelope,\n RunsLiveUrlResult,\n} from '@vostride/agent-qa-schema'\n\nimport { renderAppWrapperPage } from './app-wrapper.js'\nimport type { AppWrapperMint } from './app-wrapper.js'\nimport { liveRunLinkOf } from './live-link.js'\nimport type { LiveLinkSupplier } from './live-link.js'\n\n// Restated, not imported: ext-apps peer-depends on SDK v1, and this package ships the v2 split SDK.\nexport const MCP_APPS_EXTENSION_ID = 'io.modelcontextprotocol/ui'\n\n/** The media type an App resource is served as. Restated locally for the reason above. */\nexport const APP_RESOURCE_MIME_TYPE = 'text/html;profile=mcp-app'\n\n/** The published App address. ONE template, per run — the runId is the only variable. */\nexport const APP_RESOURCE_URI_TEMPLATE = 'ui://agent-qa/live-run/{runId}'\n\n// `encodeURIComponent` inverts `parseAppUri`'s decode, so an address reads back the same id.\nexport function appResourceUriFor(runId: string): string {\n return APP_RESOURCE_URI_TEMPLATE.replace('{runId}', encodeURIComponent(runId))\n}\n\n/** The registered resource name. Prefixed like the tools, so one namespace reads as one server. */\nexport const APP_RESOURCE_NAME = 'agent_qa_live_run_app'\n\nconst APP_RESOURCE_TITLE = 'agent-qa live run'\n\n// Authored prose about the SURFACE, not about any run — the same class of string as a tool's\n// curated title, so it is not masked. Nothing interpolated here comes from a caller or from storage.\nconst APP_RESOURCE_DESCRIPTION =\n 'The live view for one run, as an MCP App: a sandboxed page embedding the run\\'s live preview '\n + 'for each member handle. Rendered fresh on every read.'\n\n/** The `ui://` scheme and the two fixed path segments, spelled once for the one codec below. */\nconst APP_URI_PREFIX = 'ui://agent-qa/live-run/'\n\n/**\n * The ONE parser of a `ui://` app address.\n *\n * TOTAL AND UNDECORATED: it answers the run id or `undefined`, and it never explains which clause\n * refused — the caller-facing sentence is the read handler's, phrased once.\n *\n * THE RUN ID IS JUDGED BY THE MINT OP'S OWN INPUT CONTRACT, not by a pattern this file invented.\n * `RunsLiveUrlInputSchema` carries `runIdSchema` — the codec that decides whether a string may name\n * this run's own directory, so an address carrying `..`, a path separator or a control character is\n * refused here by exactly the rule that refuses it everywhere else. Stated the other way round,\n * which is the honest reading: an app address is well-formed precisely when the op this read mints\n * through would accept the run it names, so the two can never disagree about one string.\n */\nexport function parseAppUri(href: string): { readonly runId: string } | undefined {\n if (!href.startsWith(APP_URI_PREFIX)) return undefined\n const tail = href.slice(APP_URI_PREFIX.length)\n if (tail === '') return undefined\n let decoded: string\n try {\n decoded = decodeURIComponent(tail)\n } catch {\n return undefined\n }\n const parsed = RunsLiveUrlInputSchema.safeParse({ runId: decoded })\n if (!parsed.success) return undefined\n return { runId: parsed.data.runId }\n}\n\n// Re-exported from the SDK so a spelling drift fails the build instead of never negotiating.\nexport const APP_NEGOTIATION_CLIENT_CAPABILITIES_KEY = CLIENT_CAPABILITIES_META_KEY\n\n/**\n * The ONE member of the SDK's read context this module reads.\n *\n * Declared structurally rather than as `Pick<ServerContext, 'mcpReq'>` for a reason a cell feels\n * immediately: the SDK's context carries a dozen live functions, and a predicate whose input\n * cannot be written down without them is a predicate only the wire can test. `ServerContext` is\n * assignable to this, so the production call site still hands over the SDK's own object untouched.\n */\nexport interface AppReadContext {\n readonly mcpReq?: { readonly envelope?: Partial<RequestMetaEnvelope> }\n}\n\n// Fails closed, but the caller writes the envelope unauthenticated: a capability signal, not auth.\nexport function negotiatedAppsExtension(ctx: AppReadContext | undefined): boolean {\n const envelope = ctx?.mcpReq?.envelope as Record<string, unknown> | undefined\n if (envelope === undefined) return false\n const capabilities = envelope[APP_NEGOTIATION_CLIENT_CAPABILITIES_KEY] as\n | ClientCapabilities\n | undefined\n const extensions = capabilities?.extensions\n if (extensions === undefined) return false\n return Object.hasOwn(extensions, MCP_APPS_EXTENSION_ID)\n}\n\n// Thrown before the first mint, so its message holds no token and no caller text.\nexport class AppResourceNegotiationError extends Error {\n constructor() {\n super(\n `this resource is an MCP App: it is served only to a client that declared the `\n + `${MCP_APPS_EXTENSION_ID} extension in its capabilities`,\n )\n this.name = 'AppResourceNegotiationError'\n }\n}\n\n/** An address the one codec does not recognise. */\nexport class AppResourceUriError extends Error {\n constructor(detail: string) {\n super(`${detail} is not a canonical ui://agent-qa/live-run address`)\n this.name = 'AppResourceUriError'\n }\n}\n\n// A missing live session is rendered, never thrown; this class carries real read failures, masked.\nexport class AppResourceReadError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AppResourceReadError'\n }\n}\n\n// The frame allowance names one origin, so a document spanning origins is refused, not widened.\nexport class AppResourceOriginSpanError extends Error {\n constructor(origins: readonly string[]) {\n super(\n `this App document would span ${origins.length} origins `\n + `(${[...origins].sort().join(', ')}) and one frame allowance covers one: refusing to serve `\n + `a document whose panes it could not all reach`,\n )\n this.name = 'AppResourceOriginSpanError'\n }\n}\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\nexport type AppResourceInvoke = (opId: string, input: unknown) => Promise<unknown>\n\nexport interface AppResourceReadDeps {\n readonly invoke: AppResourceInvoke\n /** How CALLER text leaving this handler is masked. Required — see the header's channel split. */\n readonly maskText: (text: string) => string\n // Optional: without it the wrapper renders no anchor, and its expired states offer no link.\n readonly liveLink?: LiveLinkSupplier\n}\n\nfunction isNotLiveRefusal(error: unknown): boolean {\n return (\n error instanceof UnknownRunError\n || error instanceof LiveViewUnavailableError\n || error instanceof FunctionNotBoundError\n )\n}\n\n// `undefined` means no roster and `[]` an empty one; the read handler resolves both.\nasync function announcedRoster(\n invoke: AppResourceInvoke,\n runId: string,\n): Promise<readonly number[] | undefined> {\n const stream = await invoke(RUNS_EVENTS_FUNCTION_ID, { runId })\n const iterable = stream as AsyncIterable<RunEventEnvelope> | undefined\n if (iterable === undefined || typeof iterable[Symbol.asyncIterator] !== 'function') {\n return undefined\n }\n const iterator = iterable[Symbol.asyncIterator]()\n try {\n const first = await iterator.next()\n if (first.done === true) return undefined\n return handleRosterOf(first.value)\n } finally {\n await iterator.return?.(undefined)\n }\n}\n\n/**\n * Build the App read.\n *\n * Exported so a cell can drive it without a server, and so the parse/mint/render behaviour is\n * observable independently of registration — the two halves fail in different directions.\n */\nexport function createAppResourceReadHandler(\n deps: AppResourceReadDeps,\n): (uri: URL, variables: Variables, ctx: AppReadContext) => Promise<ReadResourceResult> {\n return async (\n uri: URL,\n _variables: Variables,\n ctx: AppReadContext,\n ): Promise<ReadResourceResult> => {\n // A rendering-capability filter, not authorization; it runs first so a refusal mints nothing.\n if (!negotiatedAppsExtension(ctx)) throw new AppResourceNegotiationError()\n\n const parsed = parseAppUri(uri.href)\n if (parsed === undefined) {\n // The echoed address is caller-supplied text, so it is masked exactly as `resources.ts`\n // masks its own — this is the refusal channel, and the channel split is the point.\n throw new AppResourceUriError(deps.maskText(uri.href))\n }\n const { runId } = parsed\n\n let roster: readonly number[] | undefined\n let notLive = false\n try {\n roster = await announcedRoster(deps.invoke, runId)\n } catch (err) {\n if (!isNotLiveRefusal(err)) {\n throw new AppResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n notLive = true\n }\n\n // `??` misses `[]`; an announced-empty roster mints handle 0 instead of reading as `run-ended`.\n const rosterToMint = roster === undefined || roster.length === 0 ? [0] : roster\n\n const mints: AppWrapperMint[] = []\n if (!notLive) {\n for (const handle of rosterToMint) {\n // Fresh on every read: nothing is cached, so no stale token is served.\n let minted: RunsLiveUrlResult\n try {\n minted = (await deps.invoke(RUNS_LIVE_URL_FUNCTION_ID, {\n runId,\n handle,\n })) as RunsLiveUrlResult\n } catch (err) {\n if (!isNotLiveRefusal(err)) {\n throw new AppResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n // One member of a suite can finish while the run continues, so a per-handle refusal\n // drops that PANE rather than the whole document. Zero surviving mints is the run-level\n // not-live case, decided below by counting rather than by a second flag.\n continue\n }\n mints.push({\n handle: minted.handle,\n liveUrl: minted.liveUrl,\n expiresAt: minted.expiresAt,\n streamKind: minted.stream.kind,\n })\n }\n }\n\n // `liveRunLinkOf` builds the address carrier results use; with no base the link stays absent.\n const base = deps.liveLink?.dashboardBaseUrl()\n const permanentLink\n = base === undefined || base.trim() === '' ? undefined : liveRunLinkOf(base.trim(), runId)\n\n // Distinct origins of every mint; more than one is refused before the wrapper is composed.\n const frameOrigins = [\n ...new Set(\n mints\n .map((mint) => originOf(mint.liveUrl))\n .filter((origin): origin is string => origin !== undefined),\n ),\n ]\n if (frameOrigins.length > 1) throw new AppResourceOriginSpanError(frameOrigins)\n const frameDomain = frameOrigins[0]\n\n const html = renderAppWrapperPage({\n runId,\n mints,\n permanentLink,\n runLive: mints.length > 0,\n })\n\n // Not masked: the payload is a credential minted for this read; masking it breaks the embed.\n return {\n contents: [\n {\n // Re-formatted through the codec's own vocabulary rather than echoed, so the address a\n // caller reads back is the canonical one.\n uri: `${APP_URI_PREFIX}${runId}`,\n mimeType: APP_RESOURCE_MIME_TYPE,\n text: html,\n // Hosts default `frame-src` and `connect-src` to none; allow the minted origin in both.\n ...(frameDomain === undefined\n ? {}\n : {\n _meta: {\n ui: { csp: { frameDomains: [frameDomain], connectDomains: [frameDomain] } },\n },\n }),\n },\n ],\n }\n }\n}\n\n/** The origin of a minted `liveUrl`, or `undefined` if it is not a URL this host can name. */\nfunction originOf(liveUrl: string): string | undefined {\n try {\n return new URL(liveUrl).origin\n } catch {\n return undefined\n }\n}\n\n// A narrow `McpServer` slice; the read callback keeps the SDK type, as the gate reads its context.\nexport interface AppResourceRegistrar {\n registerResource(\n name: string,\n template: ResourceTemplate,\n config: ResourceMetadata,\n read: ReadResourceTemplateCallback,\n ): unknown\n}\n\n/** Exactly what this module needs from the host — the same record `catalog.ts` already holds. */\nexport interface AppResourceDeps {\n readonly registry: FunctionRegistry\n readonly caller: FunctionCaller\n readonly maskText: (text: string) => string\n readonly liveLink?: LiveLinkSupplier\n}\n\n// Registers only when both ops are declared and the mint is bound; otherwise no template, no error.\nexport function registerAppResources(\n server: AppResourceRegistrar,\n deps: AppResourceDeps,\n): readonly string[] {\n const declared = deps.registry.list(deps.caller)\n const mint = declared.find((candidate) => candidate.id === RUNS_LIVE_URL_FUNCTION_ID)\n const roster = declared.find((candidate) => candidate.id === RUNS_EVENTS_FUNCTION_ID)\n if (mint === undefined || roster === undefined) return []\n if (mint.bindingStatus !== 'bound') return []\n\n const read = createAppResourceReadHandler({\n // The wall, bound once: every mint crosses `invokeFunction` with this host's registry and this\n // caller, so input validation and the binding check run exactly as they do for a tool call.\n // There is no store, no cache and no second data path.\n invoke: (opId, input) => invokeFunction(deps.registry, opId, input, deps.caller),\n maskText: deps.maskText,\n // Absent stays ABSENT rather than becoming a present `undefined` supplier: the house rule for\n // an optional member, and the two are the same posture to the read either way.\n ...(deps.liveLink === undefined ? {} : { liveLink: deps.liveLink }),\n })\n\n server.registerResource(\n APP_RESOURCE_NAME,\n // Unlisted, so no model walking `resources/list` finds an address whose read mints a token.\n new ResourceTemplate(APP_RESOURCE_URI_TEMPLATE, { list: undefined }),\n {\n title: APP_RESOURCE_TITLE,\n description: APP_RESOURCE_DESCRIPTION,\n mimeType: APP_RESOURCE_MIME_TYPE,\n },\n read,\n )\n\n return [APP_RESOURCE_URI_TEMPLATE]\n}\n","// A pure page string, stateless per SEP-2575: it holds no session and mints nothing.\n\n// The DOM cells range over this list, so a state added without a cell shows up as a diff.\nexport const APP_WRAPPER_STATES = [\n 'connecting',\n 'live',\n 'expired',\n 'unreachable-origin',\n 'run-ended',\n] as const\n\nexport type AppWrapperState = (typeof APP_WRAPPER_STATES)[number]\n\n/** What the page says while the inner frame has not painted yet. */\nexport const APP_WRAPPER_CONNECTING_MESSAGE = 'connecting to the live view…'\n\n// Under `script-src 'none'` this hint is all the page says, so it points at the link in markup.\nexport const APP_WRAPPER_CONNECTING_HINT\n = 'if the pane does not appear, open it in your browser'\n\n/** What the page says once the inner frame has loaded on an origin this host can reach. */\nexport const APP_WRAPPER_LIVE_MESSAGE = 'live'\n\n// The embed's `link expired` means a refused socket; this one means the App's link aged out.\nexport const APP_WRAPPER_EXPIRED_MESSAGE = 'live link expired'\n\n// No re-mint happens inside the sandbox; a fresh token comes from another watch call.\nexport const APP_WRAPPER_EXPIRED_HINT = 'ask to watch again — a fresh watch mints a new link'\n\nexport const APP_WRAPPER_UNREACHABLE_MESSAGE =\n \"this host can't reach the live view — open it in your browser\"\n\nexport const APP_WRAPPER_RUN_ENDED_MESSAGE = 'this run is not live — open it in your browser'\n\nexport const APP_WRAPPER_PERMANENT_LINK_LABEL = 'open in your browser'\n\n// A black-holed origin never answers and a loopback dashboard answers in ms; nothing sits between.\nexport const APP_WRAPPER_LOAD_TIMEOUT_MS = 10_000\n\n// ext-apps carries `2025-11-21` and `2026-01-26`; its `AppBridge` treats `2026-01-26` as latest.\nexport const APP_WRAPPER_UI_PROTOCOL_VERSION = '2026-01-26'\n\n/**\n * What this document calls itself to a host (`ui/initialize`'s required `appInfo`).\n *\n * Exported so a cell asserts the SAME bytes the page posts, per this file's standing rule that a\n * value a person or a host can observe is never restated in a test.\n */\nexport const APP_WRAPPER_APP_NAME = 'agent-qa-live-view'\n\n/** The wrapper's own version, bumped only when the handshake it performs changes. */\nexport const APP_WRAPPER_APP_VERSION = '1.0.0'\n\n// `liveUrl` holds the token in its fragment; it goes into the frame's `src` and nowhere else.\nexport interface AppWrapperMint {\n readonly handle: number\n readonly liveUrl: string\n readonly expiresAt: number\n readonly streamKind: string\n}\n\nexport interface AppWrapperInput {\n readonly runId: string\n // One mint per handle on the announced roster; empty means not live.\n readonly mints: readonly AppWrapperMint[]\n /** The tokenless dashboard page. `undefined` when no dashboard origin is composable. */\n readonly permanentLink: string | undefined\n /** Whether this host holds a live session for the run at all. `false` renders `run-ended`. */\n readonly runLive: boolean\n // A parameter so a cell can choose the instant; defaults to the wall clock.\n readonly now?: number\n}\n\nconst STYLE = `\n :root { color-scheme: dark light }\n html, body { margin: 0; height: 100%; background: #0b0d10; }\n main { display: grid; grid-template-rows: auto 1fr auto auto; height: 100%; font: 14px/1.5 ui-sans-serif, system-ui, sans-serif; color: #c9d1d9; }\n header { display: flex; gap: .75rem; align-items: center; padding: .5rem .75rem; }\n header:empty { display: none; }\n iframe { border: 0; width: 100%; height: 100%; display: none; background: #0b0d10; }\n main[data-app-state=\"live\"] iframe { display: block; }\n main[data-app-state=\"live\"] p[data-app-message] { display: none; }\n main[data-app-state=\"live\"] p[data-app-hint] { display: none; }\n p[data-app-message] { margin: 0; padding: .5rem .75rem; }\n p[data-app-hint] { margin: 0; padding: 0 .75rem .5rem; opacity: .75; }\n p[data-app-hint]:empty { display: none; }\n footer { padding: .5rem .75rem; }\n select[hidden], a[hidden] { display: none; }\n`\n\n/** The sentence each state shows, and the second line it shows underneath. */\nconst MESSAGES: Readonly<Record<AppWrapperState, string>> = {\n connecting: APP_WRAPPER_CONNECTING_MESSAGE,\n live: APP_WRAPPER_LIVE_MESSAGE,\n expired: APP_WRAPPER_EXPIRED_MESSAGE,\n 'unreachable-origin': APP_WRAPPER_UNREACHABLE_MESSAGE,\n 'run-ended': APP_WRAPPER_RUN_ENDED_MESSAGE,\n}\n\nconst HINTS: Readonly<Record<AppWrapperState, string>> = {\n connecting: APP_WRAPPER_CONNECTING_HINT,\n live: '',\n expired: APP_WRAPPER_EXPIRED_HINT,\n 'unreachable-origin': '',\n 'run-ended': '',\n}\n\n// Only absolute `http:` or `https:` survives: a `javascript:` base would run in the sandbox.\nfunction httpPermanentLink(value: string | undefined): string | undefined {\n if (typeof value !== 'string') return undefined\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n return undefined\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? value : undefined\n}\n\n// The whole document every time; a stale App is answered by a fresh read that mints again.\nexport function renderAppWrapperPage(input: AppWrapperInput): string {\n // The `scriptLiteral` escape of `renderLiveEmbedPage`, copied verbatim rather than\n // re-derived: the value lands inside a script as a STRING LITERAL and the `<` guard closes the\n // one hole that leaves.\n // ONE helper for every value that enters the script, so the guard cannot be forgotten for a new\n // one — including the handle numbers, which enter as literals like everything else so that\n // \"every value crosses the helper\" is a property a reader can check by grepping for the calls.\n const scriptLiteral = (value: string) => JSON.stringify(value).replaceAll('<', '\\\\u003c')\n\n // THE SECOND HELPER, AND THE ONLY ONE FOR HTML ATTRIBUTE CONTEXT. It exists for exactly one\n // value — the permanent link's `href` and its label — which is the one thing this document renders\n // into MARKUP rather than assigning from the script, because the link is the primary\n // representation and must survive a host that runs no script. `&` goes first or the later\n // replacements would be re-escaped.\n //\n // THE TWO HELPERS MUST NEVER BE USED IN EACH OTHER'S CONTEXT. `scriptLiteral` remains the one\n // helper for EVERY value entering the script and produces a quoted JS literal, which is not an\n // attribute value; this one produces attribute text and does nothing about the `</script` hole.\n // Swapping them silently reopens exactly the guard the other one closes.\n const attributeText = (value: string) =>\n value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n\n const now = input.now ?? Date.now()\n\n // With `runLive` false the urls never reach the script, so a not-live page carries no token.\n const live = input.runLive && input.mints.length > 0\n const mints = live ? input.mints : []\n\n // The LOWEST expiry among the panes, because the document expires when the first of its links\n // does: showing a person a picker whose other option is already dead would be a worse lie than\n // saying the whole thing aged out.\n const lowestExpiry = mints.reduce(\n (lowest, mint) => (mint.expiresAt < lowest ? mint.expiresAt : lowest),\n Number.POSITIVE_INFINITY,\n )\n const expired = live && lowestExpiry <= now\n // A delta, not a deadline, so the host's clock never enters it; clamped at zero because this\n // render already turned a negative one into the `expired` initial state.\n const expiresInMs = expired || !live ? 0 : Math.max(0, lowestExpiry - now)\n\n const initialState: AppWrapperState = !live ? 'run-ended' : expired ? 'expired' : 'connecting'\n\n const mintsLiteral = (expired ? [] : mints)\n .map(\n (mint) =>\n `{handle:${scriptLiteral(String(mint.handle))},`\n + `url:${scriptLiteral(mint.liveUrl)},`\n + `kind:${scriptLiteral(mint.streamKind)}}`,\n )\n .join(',')\n\n // Complete IN THE MARKUP, href and label both, so the way out exists before a single line of\n // script has run — and absent entirely for a link this renderer will not vouch for.\n const permanentLink = httpPermanentLink(input.permanentLink)\n const permanentLinkSlot\n = permanentLink === undefined\n ? ''\n : '<a data-app-permanent-link rel=\"noreferrer\" target=\"_blank\" href=\"'\n + attributeText(permanentLink)\n + '\">'\n + attributeText(APP_WRAPPER_PERMANENT_LINK_LABEL)\n + '</a>'\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>agent-qa live run</title>\n<style>${STYLE}</style>\n</head>\n<body>\n<main data-app-state=\"${initialState}\">\n<header><select data-app-handle-picker hidden></select></header>\n${live && !expired ? '<iframe data-app-live-frame sandbox=\"allow-scripts\" referrerpolicy=\"no-referrer\" title=\"agent-qa live view\"></iframe>' : ''}\n<p data-app-message>${MESSAGES[initialState]}</p>\n<p data-app-hint>${HINTS[initialState]}</p>\n<footer>${permanentLinkSlot}</footer>\n</main>\n<script>\n(function () {\n var mints = [${mintsLiteral}];\n var runId = ${scriptLiteral(input.runId)};\n var expiresInMs = ${String(expiresInMs)};\n var loadTimeoutMs = ${String(APP_WRAPPER_LOAD_TIMEOUT_MS)};\n var messages = {\n connecting: ${scriptLiteral(APP_WRAPPER_CONNECTING_MESSAGE)},\n live: ${scriptLiteral(APP_WRAPPER_LIVE_MESSAGE)},\n expired: ${scriptLiteral(APP_WRAPPER_EXPIRED_MESSAGE)},\n 'unreachable-origin': ${scriptLiteral(APP_WRAPPER_UNREACHABLE_MESSAGE)},\n 'run-ended': ${scriptLiteral(APP_WRAPPER_RUN_ENDED_MESSAGE)}\n };\n var hints = {\n connecting: ${scriptLiteral(APP_WRAPPER_CONNECTING_HINT)},\n live: '',\n expired: ${scriptLiteral(APP_WRAPPER_EXPIRED_HINT)},\n 'unreachable-origin': '',\n 'run-ended': ''\n };\n\n var root = document.querySelector('[data-app-state]');\n var frame = document.querySelector('[data-app-live-frame]');\n var picker = document.querySelector('[data-app-handle-picker]');\n var message = document.querySelector('[data-app-message]');\n var hint = document.querySelector('[data-app-hint]');\n\n // The run id enters through setAttribute from an escaped literal, so it never becomes markup.\n root.setAttribute('data-app-run-id', runId);\n\n // The state machine is an ATTRIBUTE plus two textContent writes, exactly as the embed page's is:\n // a state a person can read off the DOM is a state a cell can assert without screenshotting, and\n // text that arrives through textContent can never become markup.\n function setState(state) {\n root.setAttribute('data-app-state', state);\n message.textContent = messages[state] || '';\n hint.textContent = hints[state] || '';\n }\n\n // ---- The minimal ui/initialize handshake (ext-apps spec shape) -------------------------------\n //\n // Hand-rolled: ext-apps' app-bridge peers on the v1 SDK, and this page has no bundler.\n try {\n if (window.parent !== window) {\n window.parent.postMessage({\n jsonrpc: '2.0',\n id: 'ui-init-1',\n method: 'ui/initialize',\n params: {\n protocolVersion: ${scriptLiteral(APP_WRAPPER_UI_PROTOCOL_VERSION)},\n appInfo: { name: ${scriptLiteral(APP_WRAPPER_APP_NAME)}, version: ${scriptLiteral(APP_WRAPPER_APP_VERSION)} },\n appCapabilities: {}\n }\n }, '*');\n }\n } catch (e) { /* a host that refuses the message changes nothing about what this page shows */ }\n\n if (mints.length === 0) {\n // The renderer already wrote the terminal or expired state, and no src was ever assigned.\n return;\n }\n\n // ---- Reachability, once per ORIGIN ------------------------------------------------------------\n //\n // Only success is cached: every pane shares one origin, so a cached refusal would be permanent.\n var reach = {};\n function reachable(url) {\n var origin;\n try { origin = new URL(url).origin; } catch (e) { return Promise.resolve(false); }\n if (reach[origin] === undefined) {\n reach[origin] = fetch(origin + '/', { mode: 'no-cors', cache: 'no-store' })\n .then(function () { return true; })\n .catch(function () { delete reach[origin]; return false; });\n }\n return reach[origin];\n }\n\n var attachId = 0;\n\n function attach(mint) {\n // Expired is terminal; a picker change after the one-shot expiry timer must not leave it.\n if (root.getAttribute('data-app-state') === 'expired') return;\n var mine = (attachId += 1);\n var loaded = false;\n var settled = false;\n\n function settle(state) {\n if (settled || mine !== attachId) return;\n if (root.getAttribute('data-app-state') === 'expired') return;\n settled = true;\n setState(state);\n }\n\n setState('connecting');\n // THE ONLY PLACE A TOKEN IS WRITTEN. It goes into the frame's src and nowhere else.\n frame.src = mint.url;\n\n frame.addEventListener('error', function () { settle('unreachable-origin'); }, { once: true });\n frame.addEventListener('load', function () {\n // NECESSARY, NOT SUFFICIENT: Chromium fires this for a refused connection too,\n // so the probe is what decides — a frame that loaded on an origin nothing answered for is an\n // error page, and calling that 'live' is the failure this arm exists to prevent.\n loaded = true;\n reachable(mint.url).then(function (ok) { settle(ok ? 'live' : 'unreachable-origin'); });\n }, { once: true });\n\n reachable(mint.url).then(function (ok) {\n if (!ok) settle('unreachable-origin');\n else if (loaded) settle('live');\n });\n\n // A black-holed origin fires no error and never loads; silence past this bound is the signal.\n setTimeout(function () { settle('unreachable-origin'); }, loadTimeoutMs);\n }\n\n // The deadline arrives as a delta from render time, so the host's own clock never enters it.\n if (expiresInMs > 0) {\n setTimeout(function () {\n attachId += 1;\n // Unconditional: the script returned above when mints was empty, and a non-empty mints is\n // exactly the condition under which the renderer emits the iframe, so there is no reachable\n // state in which this callback runs without a frame to strip.\n frame.removeAttribute('src');\n // The picker is an affordance of the EMBEDDED variant; when the variant is gone the\n // affordance goes with it, so the control a person can reach and the state the document is in\n // cannot disagree.\n picker.setAttribute('disabled', '');\n setState('expired');\n }, expiresInMs);\n }\n\n // The picker swaps among tokens minted for this render; only a fresh watch call re-mints.\n for (var i = 0; i < mints.length; i += 1) {\n var option = document.createElement('option');\n option.value = String(i);\n option.textContent = 'handle ' + mints[i].handle;\n picker.appendChild(option);\n }\n if (mints.length > 1) picker.removeAttribute('hidden');\n picker.addEventListener('change', function () {\n var chosen = mints[Number(picker.value)];\n if (chosen !== undefined) attach(chosen);\n });\n\n attach(mints[0]);\n}());\n</script>\n</body>\n</html>\n`\n}\n","// Every host renders tool-result text, so the tokenless link rides every carrier result (SEP-1730).\n\n// Trailing slashes collapse so one dashboard has one address; the run id is percent-encoded anyway.\nexport function liveRunLinkOf(base: string, runId: string): string {\n return `${base.replace(/\\/+$/u, '')}/runs/${encodeURIComponent(runId)}/live`\n}\n\n/**\n * The human-readable line a carrier result carries when a base exists.\n *\n * AN EXPORTED TEMPLATE RATHER THAN A STRING EACH CALL SITE COMPOSES, so a cell asserts the SAME\n * sentence the surface prints. Two carriers and two hosts print this; four hand-written spellings\n * would be four things to keep in step, and the drift would be invisible because nobody diffs two\n * tool results.\n *\n * IT NAMES BOTH READINGS OF THE ONE PAGE — watching a run that is going, and reviewing one that has\n * finished — because the address is the same either way and a line that promised only \"live\" would\n * read as broken the moment the run ended, which is precisely when a person follows it.\n */\nexport function liveLinkLine(url: string): string {\n return `watch live or review: ${url}`\n}\n\n// Names the config knob and holds no URL: a fabricated address is worse than none.\nexport const LIVE_LINK_ABSENT_LINE = 'no dashboard configured — set services.dashboard.baseUrl'\n\n// A base exists but the result names no run: no knob to set and no URL.\nexport const LIVE_LINK_NO_RUN_LINE\n = 'no run to link to — this result names no run id'\n\n/**\n * How a HOST answers \"which dashboard is this process pointed at\".\n *\n * A FACTORY, NOT A STRING, on `commands/dashboard.ts`'s own reasoning about the same value: the\n * server has not bound a port when the host is composed, and an ephemeral port (`port: 0`) is a\n * real posture in this suite and in tests. A value captured at composition time would be a guess; a\n * factory read per result is the truth.\n *\n * `undefined` is the degenerate case rather than a second branch: a host that supplies no supplier\n * at all and a supplier that answers `undefined` are the same fact — no dashboard — and they take\n * the same path to the same line.\n */\nexport interface LiveLinkSupplier {\n readonly dashboardBaseUrl: () => string | undefined\n}\n\n// The base is tested first: with none anywhere, the missing config is the actionable line.\nexport function liveLinkLineFor(\n base: string | undefined,\n runId: string | undefined,\n): string {\n if (base === undefined || base.trim() === '') return LIVE_LINK_ABSENT_LINE\n if (runId === undefined || runId === '') return LIVE_LINK_NO_RUN_LINE\n return liveLinkLine(liveRunLinkOf(base.trim(), runId))\n}\n","// Static text; with no initialize handshake (SEP-2575) the SDK answers it in the discovery result.\n\nexport const AGENT_QA_MCP_INSTRUCTIONS: string = [\n 'This project is tested with agent-qa. Read its runs and knowledge only through the agent_qa_* '\n + 'tools on this server, or the agent-qa CLI with --json.',\n 'Never open .agent-qa/, SQLite files, agent-qa-knowledge/memory/index/, memory/queue/, .lease or '\n + '.epoch, and never list, glob or search those folders: they are agent-qa\\'s runtime state.',\n 'Start with agent_qa_list_runs, then agent_qa_get_run_overview for one run.',\n 'The knowledge guide is agent-qa-knowledge/AGENTS.md; `npx agent-qa skills` lists the skills and '\n + 'their folder.',\n].join('\\n')\n","// Static data: which tool fronts which ops, ranged by the cli parity suite (SEP-2567, SEP-2549).\n\nimport type { StandardSchemaWithJSON } from '@modelcontextprotocol/server'\nimport {\n AuthoringDraftEditInputSchema,\n AuthoringDraftEditOutputSchema,\n AuthoringDraftWriteInputSchema,\n AuthoringDraftWriteOutputSchema,\n AuthoringRefineFoldInputSchema,\n AuthoringRefineFoldOutputSchema,\n AuthoringVerifyDraftInputSchema,\n AuthoringVerifyDraftOutputSchema,\n BriefWhyInputSchema,\n BriefWhyResultSchema,\n ConfigAuthSetInputSchema,\n ConfigChangeFoldInputSchema,\n ConfigChangeFoldOutputSchema,\n ConfigChangeOutputSchema,\n ConfigFieldSetInputSchema,\n ConfigHookAddInputSchema,\n ConfigProjectScaffoldInputSchema,\n ConfigTargetCreateInputSchema,\n ConfigTargetEditInputSchema,\n EntitiesGetInputSchema,\n EntitiesResolveInputSchema,\n EntityCardResolutionSchema,\n EntityCardSchema,\n KnowledgeAcceptChangeInputSchema,\n KnowledgeBundlesListInputSchema,\n KnowledgeBundlesListOutputSchema,\n KnowledgeChangeFoldInputSchema,\n KnowledgeChangeFoldOutputSchema,\n KnowledgeForgetChangeInputSchema,\n KnowledgeGatesListInputSchema,\n KnowledgeGatesListResultSchema,\n KnowledgeChangeOutputSchema,\n KnowledgeRecordShowInputSchema,\n KnowledgeRecordShowResultSchema,\n KnowledgeRecordsDiffInputSchema,\n KnowledgeRecordsDiffOutputSchema,\n KnowledgeRecordsInspectInputSchema,\n KnowledgeRecordsInspectOutputSchema,\n KnowledgeRejectChangeInputSchema,\n RunDigestSchema,\n RunKnowledgeProjectionSchema,\n RunOverviewProjectionSchema,\n RunStartAcknowledgementSchema,\n RunsArtifactInputSchema,\n RunsArtifactOutputContract,\n RunsDigestInputSchema,\n RunsEvidenceFoldInputSchema,\n RunsEvidenceFoldOutputContract,\n RunsEvidenceInputSchema,\n RunsEvidenceOutputContract,\n RunsKnowledgeInputSchema,\n RunsListInputSchema,\n RunsListOutputContract,\n RunsMarkInputSchema,\n RunsMarkOutcomeSchema,\n RunsMarkPreviewResultSchema,\n RunsMarksHistoryInputSchema,\n RunsMarksHistoryResultSchema,\n RunsOverviewInputSchema,\n RunsStartInputSchema,\n TOOL_FOLD_DISCRIMINANT,\n} from '@vostride/agent-qa-schema'\n\n/**\n * What a tool DOES, coarsely — the axis annotations are derived along (`projection.ts`).\n *\n * `read` answers; `workflow` changes something in the call (a test file, a run, knowledge,\n * configuration). `apply` names the mark door, which records the mark and applies its fix in the\n * call and asks nothing.\n */\nexport type ToolProjectionKind = 'read' | 'workflow' | 'apply'\n\n// Derived from the entry rather than stated, so a fold can never be declared `single`.\nexport type ToolComposition = 'single' | 'union' | 'pipeline'\n\n/** The tool-listing `_meta` key a host reads as the largest result it should keep. */\nexport const MAX_RESULT_SIZE_META_KEY = 'anthropic/maxResultSizeChars'\n\nexport const RUN_READ_MAX_RESULT_SIZE_CHARS = 100000\n\n/** One declared tool. */\nexport interface ToolProjection {\n /** Curated `verb_noun` name per spec section 3.3. */\n readonly name: string\n /** The registry op ids this tool projects. Length 1 = 1:1; length > 1 = a declared fold. */\n readonly ops: readonly string[]\n readonly kind: ToolProjectionKind\n /**\n * A union fold's discriminant key — absent on a 1:1 tool AND on the pipeline.\n *\n * Its presence is what tells a fold from a pipeline, which is why it is spelled per entry rather\n * than assumed from `ops.length > 1`.\n */\n readonly discriminant?: string\n // Presence marks a carrier; `runIdFrom` says whether the run id is on the input or the result.\n readonly ui?: {\n readonly resource: 'live-run'\n readonly runIdFrom: 'input' | 'output'\n }\n // Present only on reads whose one-shot answer can outgrow a host's default result budget.\n readonly maxResultSizeChars?: number\n}\n\n/** The composition, read off the entry. See {@link ToolComposition}. */\nexport function compositionOf(projection: ToolProjection): ToolComposition {\n if (projection.ops.length === 1) return 'single'\n return projection.discriminant === undefined ? 'pipeline' : 'union'\n}\n\n// The ops' own live validators, so the advertised schema and `invokeFunction`'s cannot disagree.\nexport interface ToolOpContracts {\n readonly input: StandardSchemaWithJSON\n readonly output: StandardSchemaWithJSON\n}\n\n/**\n * Op id -> its live contracts, for every op any declared projection names.\n *\n * `catalog.ts` refuses to build a tool whose op is missing from it, so the two tables can never\n * drift apart silently.\n */\nexport const AGENT_QA_OP_CONTRACTS: Readonly<Record<string, ToolOpContracts>> = Object.freeze({\n 'runs.mark': Object.freeze({ input: RunsMarkInputSchema, output: RunsMarkOutcomeSchema }),\n // The preview takes `runs.mark`'s exact input and answers the read-only plan result.\n 'runs.marks.history': Object.freeze({\n input: RunsMarksHistoryInputSchema,\n output: RunsMarksHistoryResultSchema,\n }),\n 'runs.mark.preview': Object.freeze({ input: RunsMarkInputSchema, output: RunsMarkPreviewResultSchema }),\n 'knowledge.gates.list': Object.freeze({\n input: KnowledgeGatesListInputSchema,\n output: KnowledgeGatesListResultSchema,\n }),\n 'authoring.draft.write': Object.freeze({\n input: AuthoringDraftWriteInputSchema,\n output: AuthoringDraftWriteOutputSchema,\n }),\n 'authoring.draft.edit': Object.freeze({\n input: AuthoringDraftEditInputSchema,\n output: AuthoringDraftEditOutputSchema,\n }),\n 'authoring.draft.verify': Object.freeze({\n input: AuthoringVerifyDraftInputSchema,\n output: AuthoringVerifyDraftOutputSchema,\n }),\n 'runs.start': Object.freeze({\n input: RunsStartInputSchema,\n output: RunStartAcknowledgementSchema,\n }),\n 'config.field.set': Object.freeze({\n input: ConfigFieldSetInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.target.create': Object.freeze({\n input: ConfigTargetCreateInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.target.edit': Object.freeze({\n input: ConfigTargetEditInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.auth.set': Object.freeze({\n input: ConfigAuthSetInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.hook.add': Object.freeze({\n input: ConfigHookAddInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'config.project.scaffold': Object.freeze({\n input: ConfigProjectScaffoldInputSchema,\n output: ConfigChangeOutputSchema,\n }),\n 'knowledge.accept': Object.freeze({\n input: KnowledgeAcceptChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'knowledge.reject': Object.freeze({\n input: KnowledgeRejectChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'knowledge.forget': Object.freeze({\n input: KnowledgeForgetChangeInputSchema,\n output: KnowledgeChangeOutputSchema,\n }),\n 'entities.resolve': Object.freeze({\n input: EntitiesResolveInputSchema,\n output: EntityCardResolutionSchema,\n }),\n 'entities.get': Object.freeze({\n input: EntitiesGetInputSchema,\n output: EntityCardSchema,\n }),\n // `RunsListOutputSchema` is the same validator `runs.list` enforces with.\n 'runs.list': Object.freeze({\n input: RunsListInputSchema,\n output: RunsListOutputContract,\n }),\n 'runs.digest': Object.freeze({\n input: RunsDigestInputSchema,\n output: RunDigestSchema,\n }),\n // The evidence arms use the canonical output contracts, whose validators are the runtime schemas.\n 'knowledge.bundles.list': Object.freeze({\n input: KnowledgeBundlesListInputSchema,\n output: KnowledgeBundlesListOutputSchema,\n }),\n 'knowledge.records.inspect': Object.freeze({\n input: KnowledgeRecordsInspectInputSchema,\n output: KnowledgeRecordsInspectOutputSchema,\n }),\n 'knowledge.records.diff': Object.freeze({\n input: KnowledgeRecordsDiffInputSchema,\n output: KnowledgeRecordsDiffOutputSchema,\n }),\n 'knowledge.record.show': Object.freeze({\n input: KnowledgeRecordShowInputSchema,\n output: KnowledgeRecordShowResultSchema,\n }),\n 'knowledge.brief.why': Object.freeze({\n input: BriefWhyInputSchema,\n output: BriefWhyResultSchema,\n }),\n 'runs.knowledge': Object.freeze({\n input: RunsKnowledgeInputSchema,\n output: RunKnowledgeProjectionSchema,\n }),\n 'runs.overview': Object.freeze({\n input: RunsOverviewInputSchema,\n output: RunOverviewProjectionSchema,\n }),\n 'runs.evidence': Object.freeze({\n input: RunsEvidenceInputSchema,\n output: RunsEvidenceOutputContract,\n }),\n 'runs.artifact': Object.freeze({\n input: RunsArtifactInputSchema,\n output: RunsArtifactOutputContract,\n }),\n})\n\n// Write tools change things in the call and answer what changed; nothing waits for a second call.\nexport const AGENT_QA_TOOL_PROJECTIONS: readonly ToolProjection[] = Object.freeze([\n Object.freeze({\n name: 'agent_qa_write_test',\n ops: Object.freeze(['authoring.draft.write']),\n kind: 'workflow',\n }),\n Object.freeze({\n name: 'agent_qa_refine_test',\n ops: Object.freeze(['authoring.draft.edit', 'authoring.draft.verify']),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n Object.freeze({\n name: 'agent_qa_start_run',\n ops: Object.freeze(['runs.start']),\n kind: 'workflow',\n // The ack carries the run id, so the per-call reference comes from the output.\n ui: Object.freeze({ resource: 'live-run', runIdFrom: 'output' } as const),\n }),\n Object.freeze({\n name: 'agent_qa_change_config',\n ops: Object.freeze([\n 'config.field.set',\n 'config.target.create',\n 'config.target.edit',\n 'config.auth.set',\n 'config.hook.add',\n 'config.project.scaffold',\n ]),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n // Forget is the explicit removal; a wrong record is otherwise corrected by new feedback.\n Object.freeze({\n name: 'agent_qa_change_knowledge',\n ops: Object.freeze([\n 'knowledge.accept',\n 'knowledge.reject',\n 'knowledge.forget',\n ]),\n kind: 'workflow',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n }),\n Object.freeze({\n name: 'agent_qa_mark_run',\n ops: Object.freeze(['runs.mark']),\n kind: 'apply',\n }),\n // Both are reads, so `agent_qa_mark_run` stays the only door that lands a mark.\n Object.freeze({\n name: 'agent_qa_get_run_marks',\n ops: Object.freeze(['runs.marks.history']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_preview_run_mark',\n ops: Object.freeze(['runs.mark.preview']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_list_knowledge_gates',\n ops: Object.freeze(['knowledge.gates.list']),\n kind: 'read',\n }),\n // The knowledge reads, named one-to-one with their CLI verbs.\n Object.freeze({\n name: 'agent_qa_list_knowledge_bundles',\n ops: Object.freeze(['knowledge.bundles.list']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_inspect_knowledge_records',\n ops: Object.freeze(['knowledge.records.inspect']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_diff_knowledge_records',\n ops: Object.freeze(['knowledge.records.diff']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_show_knowledge_record',\n ops: Object.freeze(['knowledge.record.show']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_explain_brief',\n ops: Object.freeze(['knowledge.brief.why']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_get_entity',\n ops: Object.freeze(['entities.resolve', 'entities.get']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_list_runs',\n ops: Object.freeze(['runs.list']),\n kind: 'read',\n }),\n Object.freeze({\n name: 'agent_qa_get_run_digest',\n ops: Object.freeze(['runs.digest']),\n kind: 'read',\n // The late-attach door: a viewer attaches to any run, so the run id comes from the input.\n ui: Object.freeze({ resource: 'live-run', runIdFrom: 'input' } as const),\n }),\n // A completed run's whole reads, each carrying the result-size hint.\n Object.freeze({\n name: 'agent_qa_get_run_overview',\n ops: Object.freeze(['runs.overview']),\n kind: 'read',\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n Object.freeze({\n name: 'agent_qa_get_run_knowledge',\n ops: Object.freeze(['runs.knowledge']),\n kind: 'read',\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n Object.freeze({\n name: 'agent_qa_get_run_evidence',\n ops: Object.freeze(['runs.evidence', 'runs.artifact']),\n kind: 'read',\n discriminant: TOOL_FOLD_DISCRIMINANT,\n maxResultSizeChars: RUN_READ_MAX_RESULT_SIZE_CHARS,\n }),\n] as const satisfies readonly ToolProjection[])\n\n// Entries exist only for a union fold's composed contract and the pipeline's first-op contract.\nexport const AGENT_QA_COMPOSED_CONTRACTS: Readonly<Record<string, ToolOpContracts>> = Object.freeze({\n agent_qa_refine_test: Object.freeze({\n input: AuthoringRefineFoldInputSchema,\n output: AuthoringRefineFoldOutputSchema,\n }),\n agent_qa_change_config: Object.freeze({\n input: ConfigChangeFoldInputSchema,\n output: ConfigChangeFoldOutputSchema,\n }),\n agent_qa_change_knowledge: Object.freeze({\n input: KnowledgeChangeFoldInputSchema,\n output: KnowledgeChangeFoldOutputSchema,\n }),\n // Composed in the schema package from both arms' canonical contracts, routed by full op id.\n agent_qa_get_run_evidence: Object.freeze({\n input: RunsEvidenceFoldInputSchema,\n output: RunsEvidenceFoldOutputContract,\n }),\n agent_qa_get_entity: Object.freeze({\n input: EntitiesResolveInputSchema,\n output: EntityCardResolutionSchema,\n }),\n})\n\n/** The contract a tool advertises: its composition when it has one, its one op's otherwise. */\nexport function advertisedContracts(\n projection: ToolProjection,\n): ToolOpContracts | undefined {\n const composed = AGENT_QA_COMPOSED_CONTRACTS[projection.name]\n if (composed !== undefined) return composed\n const [only] = projection.ops\n return only === undefined ? undefined : AGENT_QA_OP_CONTRACTS[only]\n}\n\n// A transform makes the `tools/list` conversion throw for every caller, so no output schema.\nexport interface OutputSchemaDegradation {\n readonly tool: string\n readonly opId: string\n /** The schema symbol whose transform the converter refused, for a reader chasing the cause. */\n readonly schema: string\n /** The converter's own message, verbatim. */\n readonly measured: string\n}\n\nexport const DEGRADED_OUTPUT_CONTRACTS: readonly OutputSchemaDegradation[] = Object.freeze([\n // The branded run id is a transform; un-branding it would trade type safety for one listing.\n Object.freeze({\n tool: 'agent_qa_start_run',\n opId: 'runs.start',\n schema: 'RunStartAcknowledgementSchema',\n measured: 'Transforms cannot be represented in JSON Schema',\n }),\n] as const satisfies readonly OutputSchemaDegradation[])\n\n// Every registry op is projected above or listed here; parity.test.ts checks the partition.\nexport interface UnprojectedOp {\n readonly opId: string\n readonly reason: string\n}\n\nconst NOT_MID_FLIGHT_READ =\n 'not a mid-flight workflow read: this surface carries only the reads a workflow needs while it '\n + 'runs'\n\nconst NOT_MID_FLIGHT_WRITE =\n 'not a mid-flight workflow write: this surface carries only the writes a workflow needs while it '\n + 'runs'\n\nexport const UNPROJECTED_OPS: readonly UnprojectedOp[] = Object.freeze([\n Object.freeze({\n opId: 'agent.ask',\n reason:\n 'Ask over MCP is nested-agent delegation: a tool call would spend this project\\'s model '\n + 'tokens, take the lease the local host holds and stream through a channel a single '\n + '`tools/call` round trip has no shape for.',\n }),\n Object.freeze({\n opId: 'runs.get',\n reason:\n 'not a mid-flight workflow read: the entity door renders a run\\'s card and the digest '\n + 'carries what triage needs',\n }),\n Object.freeze({\n opId: 'runs.events',\n reason:\n 'not a mid-flight workflow read, and a stream besides: a `tools/call` is one round trip and '\n + 'has no shape for a resumable event feed',\n }),\n Object.freeze({\n opId: 'runs.postprocessing',\n reason: NOT_MID_FLIGHT_READ,\n }),\n Object.freeze({\n opId: 'runs.detail',\n reason:\n 'not a mid-flight workflow read: it is a completed run\\'s whole step tree, read by the '\n + 'run-detail page, and a large one-shot payload with no shape a `tools/call` round trip '\n + 'wants',\n }),\n Object.freeze({\n opId: 'runs.liveurl',\n reason:\n 'The op MINTS A CREDENTIAL, a short-lived view token for a running browser: the MCP server '\n + 'mints it only inside its App-rendering path and writes it into the frame src of the '\n + 'unlisted `ui://agent-qa/live-run/{runId}` resource, so a mint tool would put the '\n + 'credential on a channel a model reads by default.',\n }),\n Object.freeze({\n opId: 'editor.liveurl',\n reason:\n 'The op MINTS A CREDENTIAL, a view credential for a live editor session that is private to '\n + 'the dashboard page owning it, so it is reachable only through the dashboard door and '\n + 'never through an MCP tool or the MCP App live-run resource.',\n }),\n Object.freeze({\n opId: 'config.get',\n reason: NOT_MID_FLIGHT_READ,\n }),\n Object.freeze({\n opId: 'analysis.get',\n reason: NOT_MID_FLIGHT_READ,\n }),\n Object.freeze({\n opId: 'authoring.funnel.get',\n reason: NOT_MID_FLIGHT_READ,\n }),\n Object.freeze({\n opId: 'quarantine.add',\n reason: NOT_MID_FLIGHT_WRITE,\n }),\n Object.freeze({\n opId: 'quarantine.release',\n reason: NOT_MID_FLIGHT_WRITE,\n }),\n Object.freeze({\n opId: 'quarantine.list',\n reason: NOT_MID_FLIGHT_READ,\n }),\n Object.freeze({\n opId: 'agent.explain',\n reason:\n 'The protocol answers machine discovery itself through `tools/list` and SEP-2575 '\n + '`server/discover`, and `init --agent` answers agent discovery from the committed catalog; '\n + 'this op answers a person asking in prose, which a discovery tool would only restate.',\n }),\n] as const satisfies readonly UnprojectedOp[])\n","// Masked once, leaf by leaf, before serializing; a masked value may then fail its SEP-2106 schema.\n\nimport type { CallToolResult } from '@modelcontextprotocol/server'\nimport { RunsArtifactResultSchema } from '@vostride/agent-qa-schema'\nimport type { RunsArtifactResult } from '@vostride/agent-qa-schema'\n\n/** The one prose a caller reads when a value could not be masked in place. Value-free by design. */\nconst WITHHELD_TEXT =\n 'This result could not be returned: part of its output could not be masked in place — a value '\n + 'whose hidden form would not be the same kind of value, or two names that mask to one name — so '\n + 'the unmasked object was withheld rather than served.'\n\n/**\n * Raised inside the walk when a leaf cannot be masked without changing what the document MEANS.\n *\n * Private, and it never escapes this module: every caller turns it into a withheld answer. It is an\n * exception rather than a sentinel return because it is thrown from inside a recursion whose every\n * frame would otherwise have to re-check for the sentinel — and a missed check there is served\n * output.\n */\nclass UnmaskableValueError extends Error {}\n\n/**\n * Mask every STRING LEAF and every OBJECT KEY of a JSON value, in place, leaving the shape alone.\n *\n * THE MASKER ONLY EVER SEES RAW BYTES. That is the whole correction: a literal-substring masker\n * handed `{\"token\":\"sk-live\\\"abc\"}` cannot find `sk-live\"abc`, and handed `sk-live\"abc` it can.\n */\nfunction maskJsonLeaves(value: unknown, maskText: (text: string) => string): unknown {\n if (typeof value === 'string') return maskText(value)\n if (value === null) return null\n\n if (Array.isArray(value)) {\n return value.map((entry) => maskJsonLeaves(entry, maskText))\n }\n\n if (typeof value === 'object') {\n const masked: Record<string, unknown> = {}\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n // A credential can sit in a key, and two keys masking to one name are refused, not merged.\n const maskedKey = maskText(key)\n if (Object.hasOwn(masked, maskedKey)) {\n throw new UnmaskableValueError('two keys of one object mask to the same name')\n }\n // Defined, not assigned: assigning `__proto__` sets the prototype and drops the key.\n Object.defineProperty(masked, maskedKey, {\n value: maskJsonLeaves(entry, maskText),\n enumerable: true,\n writable: true,\n configurable: true,\n })\n }\n return masked\n }\n\n // A number or boolean spelling a registered value cannot be masked in place, so it is refused.\n const spelling = JSON.stringify(value) ?? 'null'\n if (maskText(spelling) !== spelling) {\n throw new UnmaskableValueError('a non-string leaf spells a registered value')\n }\n return value\n}\n\n/**\n * One masked value and its one serialization, or `undefined` when it cannot be represented.\n *\n * The pair is returned together so that no caller can compose a text channel and a data channel out\n * of two different maskings — `text` is `JSON.stringify(value)` and nothing else. Exported because\n * `resources.ts` composes resource contents the same way and must not grow a second answer to the\n * same question.\n */\nexport function maskJsonDocument(\n output: unknown,\n maskText: (text: string) => string,\n): { readonly value: unknown; readonly text: string } | undefined {\n // Round-tripped through the serializer FIRST, so what is masked is exactly what a caller would\n // have received: `toJSON` hooks run, `undefined` members vanish, a `Date` becomes its string.\n // `JSON.stringify` answers `undefined` for `undefined` and for a bare function; `'null'` is the\n // honest serialization of \"the op answered nothing\", and it parses.\n const serialized = JSON.stringify(output) ?? 'null'\n\n let parsed: unknown\n try {\n parsed = JSON.parse(serialized)\n } catch {\n return undefined\n }\n\n let value: unknown\n try {\n value = maskJsonLeaves(parsed, maskText)\n } catch {\n return undefined\n }\n\n const text = JSON.stringify(value)\n if (text === undefined) return undefined\n return { value, text }\n}\n\n/**\n * Mask once, and answer both channels from the one masked value.\n *\n * `structuredContent` IS the masked value and `content` is its serialization, which is the whole\n * point: the object a machine reads and the text a person reads agree about what was hidden,\n * because there is only one masking and one document. One exception: the evidence image arm\n * replaces `bytesBase64` in the text with a marker, while `structuredContent` keeps the bytes.\n */\nexport function maskedToolResult(\n output: unknown,\n maskText: (text: string) => string,\n): CallToolResult {\n const masked = maskJsonDocument(output, maskText)\n if (masked === undefined) {\n return {\n content: [{ type: 'text' as const, text: WITHHELD_TEXT }],\n isError: true,\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: masked.text }],\n structuredContent: masked.value as CallToolResult['structuredContent'],\n }\n}\n\n// A refusal is a readable result, masked because an error string can carry a credential.\nexport function maskedToolError(err: unknown, maskText: (text: string) => string): CallToolResult {\n const message = err instanceof Error ? err.message : String(err)\n return {\n content: [\n {\n type: 'text' as const,\n text: maskText(message),\n },\n ],\n isError: true,\n }\n}\n\n// An image block is added after masking; masking hides strings, never pixels.\n\n/** Why an artifact did not travel as an image. Each is a tool error, never a success. */\nexport type RunEvidenceImageRefusal =\n | 'artifact-range-fragment'\n | 'artifact-not-image'\n | 'artifact-image-invalid'\n | 'artifact-image-withheld'\n\nconst RUN_EVIDENCE_IMAGE_TYPES: ReadonlySet<string> = new Set(['image/png', 'image/jpeg'])\n\nexport const RUN_EVIDENCE_IMAGE_TEXT_MARKER = '[image attached as image content]'\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] as const\nconst PNG_IEND_TRAILER = [\n 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,\n] as const\nconst JPEG_START = [0xff, 0xd8, 0xff] as const\nconst JPEG_END = [0xff, 0xd9] as const\n\nconst CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/\n\nfunction refusalText(refusal: RunEvidenceImageRefusal, contentType: string | undefined): string {\n switch (refusal) {\n case 'artifact-range-fragment':\n return 'artifact-range-fragment: agent_qa_get_run_evidence returns a screenshot only as one '\n + 'complete PNG or JPEG image, and this range covers part of one. Call runs.artifact without '\n + 'a range.'\n case 'artifact-not-image':\n return `artifact-not-image: this artifact is ${contentType ?? 'not typed'}, not a PNG or JPEG `\n + 'screenshot, and agent_qa_get_run_evidence relays no other artifact bytes. Read a step '\n + 'document through action runs.evidence.'\n case 'artifact-image-invalid':\n return 'artifact-image-invalid: the artifact is typed as an image, but its bytes are not one '\n + 'complete PNG or JPEG, so they were not returned.'\n case 'artifact-image-withheld':\n return 'artifact-image-withheld: masking changed the encoded screenshot, so neither the image '\n + 'nor its bytes were returned.'\n }\n}\n\nfunction hasBytesAt(bytes: Uint8Array, expected: readonly number[], offset: number): boolean {\n if (offset < 0 || bytes.length < offset + expected.length) return false\n return expected.every((byte, index) => bytes[offset + index] === byte)\n}\n\nfunction isCompleteImage(contentType: string, bytes: Uint8Array): boolean {\n if (contentType === 'image/png') {\n return hasBytesAt(bytes, PNG_SIGNATURE, 0)\n && hasBytesAt(bytes, PNG_IEND_TRAILER, bytes.length - PNG_IEND_TRAILER.length)\n }\n return hasBytesAt(bytes, JPEG_START, 0)\n && hasBytesAt(bytes, JPEG_END, bytes.length - JPEG_END.length)\n}\n\n/** The bytes of CANONICAL base64 only; anything a strict encoder would not emit is refused. */\nfunction decodeCanonicalBase64(text: string): Uint8Array | undefined {\n if (!CANONICAL_BASE64.test(text)) return undefined\n let binary: string\n try {\n binary = atob(text)\n } catch {\n return undefined\n }\n if (btoa(binary) !== text) return undefined\n return Uint8Array.from(binary, (char) => char.charCodeAt(0))\n}\n\n// The op types a ranged read by the WHOLE blob's head, so a fragment can say image/png while\n// carrying a middle slice. Only a read that provably covers every byte is a whole image.\nfunction coversWholeBlob(artifact: RunsArtifactResult): boolean {\n if (artifact.range === undefined) {\n return artifact.totalLength === undefined || artifact.totalLength === artifact.byteLength\n }\n return artifact.totalLength !== undefined\n && artifact.range.start === 0\n && artifact.range.end === artifact.totalLength - 1\n && artifact.byteLength === artifact.totalLength\n}\n\n/**\n * Add one image block to the evidence tool's `runs.artifact` answer, after masking.\n *\n * `result` is what `maskedToolResult` answered for `output`. A refusal or withheld result is\n * returned untouched. Anything that is not one complete PNG or JPEG, or whose base64 the masking\n * changed, becomes a named tool error carrying no bytes at all.\n */\nexport function decorateRunEvidenceImage(input: {\n readonly result: CallToolResult\n readonly output: unknown\n readonly maskText: (text: string) => string\n}): CallToolResult {\n const { result } = input\n if (result.isError === true) return result\n\n const refuse = (refusal: RunEvidenceImageRefusal, contentType?: string): CallToolResult => ({\n content: [{ type: 'text' as const, text: input.maskText(refusalText(refusal, contentType)) }],\n isError: true,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n })\n\n const parsed = RunsArtifactResultSchema.safeParse(input.output)\n if (!parsed.success) return refuse('artifact-image-invalid')\n const artifact = parsed.data\n if (!RUN_EVIDENCE_IMAGE_TYPES.has(artifact.contentType)) {\n return refuse('artifact-not-image', artifact.contentType)\n }\n if (!coversWholeBlob(artifact)) return refuse('artifact-range-fragment')\n\n const masked = result.structuredContent as\n | { readonly bytesBase64?: unknown; readonly contentType?: unknown }\n | undefined\n if (masked?.bytesBase64 !== artifact.bytesBase64 || masked.contentType !== artifact.contentType) {\n return refuse('artifact-image-withheld')\n }\n\n const bytes = decodeCanonicalBase64(artifact.bytesBase64)\n if (\n bytes === undefined\n || bytes.length !== artifact.byteLength\n || !isCompleteImage(artifact.contentType, bytes)\n ) {\n return refuse('artifact-image-invalid')\n }\n\n const text = JSON.stringify({ ...masked, bytesBase64: RUN_EVIDENCE_IMAGE_TEXT_MARKER })\n return {\n ...result,\n content: [\n ...result.content.map((block) => (block.type === 'text' ? { type: 'text' as const, text } : block)),\n { type: 'image' as const, data: artifact.bytesBase64, mimeType: artifact.contentType },\n ],\n }\n}\n\n","// Tool config derived from the op's live contract; the SDK converts it (SEP-2106).\n\nimport type { StandardSchemaWithJSON, ToolAnnotations } from '@modelcontextprotocol/server'\nimport type { RiskActionDescriptor } from '@vostride/agent-qa-schema'\n\n// ONE authoritative spelling of the App address: the module that publishes the template is the\n// module that parses it, and this derivation imports it rather than restating the string.\nimport { APP_RESOURCE_URI_TEMPLATE } from './app-resource.js'\nimport { compositionOf, DEGRADED_OUTPUT_CONTRACTS, MAX_RESULT_SIZE_META_KEY } from './mapping.js'\nimport type { ToolOpContracts, ToolProjection } from './mapping.js'\n\n/**\n * The draft the SDK converts every advertised schema to.\n *\n * Pinned here to the SDK's own `JSON_SCHEMA_CONVERSION_TARGET` (`src-CX2iR2pK.mjs`) because the\n * probe below must ask the SAME question `tools/list` will ask. A probe run against a different\n * target would be measuring a conversion nobody performs.\n */\nconst JSON_SCHEMA_CONVERSION_TARGET = 'draft-2020-12'\n\n// `summary` and `risk` come from the registry's declaration; `input` and `output` from the mapping.\nexport interface ProjectedOpSpec {\n readonly id: string\n readonly summary: string\n readonly risk: RiskActionDescriptor\n readonly input: StandardSchemaWithJSON\n readonly output: StandardSchemaWithJSON\n}\n\n/**\n * Exactly the `registerTool` config fields this projection derives.\n *\n * `outputSchema` is OPTIONAL, and its absence is a decision rather than a gap — see\n * `DEGRADED_OUTPUT_CONTRACTS` and `probeOutputSchema` below.\n */\nexport interface RegisterToolConfig {\n readonly title: string\n readonly description: string\n readonly inputSchema: StandardSchemaWithJSON\n readonly outputSchema?: StandardSchemaWithJSON\n readonly annotations: ToolAnnotations\n // A non-carrier gets no `_meta` key at all; a host that never negotiated the App ignores it.\n readonly _meta?: Record<string, unknown>\n}\n\n// Read-only only when every arm's risk descriptor says `readOnly`; one write arm makes it a write.\nfunction isReadOnly(specs: readonly ProjectedOpSpec[]): boolean {\n return specs.every((spec) => spec.risk.readOnly === true)\n}\n\n/**\n * Derive the honest annotation set.\n *\n * `destructiveHint` is true when ANY arm declares itself destructive — the union direction, because\n * a fold is as dangerous as its most dangerous arm and a host deciding whether to confirm is asking\n * about the call it is about to make, not about the average of the ones it could have made.\n *\n * `idempotentHint` follows `readOnlyHint` and nothing else. A read is idempotent; for anything that\n * writes, this product has no per-op declaration of idempotence to read, and asserting one from\n * nowhere is exactly the lie the honest-annotations rule forbids. When such a declaration exists,\n * this is the one line that changes.\n */\nfunction deriveAnnotations(specs: readonly ProjectedOpSpec[]): ToolAnnotations {\n const readOnlyHint = isReadOnly(specs)\n return {\n readOnlyHint,\n destructiveHint: specs.some((spec) => spec.risk.destructive === true),\n idempotentHint: readOnlyHint,\n }\n}\n\n/**\n * Compose a human-facing description from the arms' own summaries.\n *\n * A 1:1 projection reads as its op's summary verbatim — there is nothing to add, and adding\n * something would be authoring a second description of one capability.\n *\n * A UNION FOLD lists its arms, each labelled with the op id it stands for, and says which key\n * selects between them — because a caller told only \"manage configuration\" cannot work out which\n * arm a given input selects, and the discriminant IS the op id.\n *\n * THE PIPELINE names its steps in order. Its second op contributes no shape to the advertisement\n * (see `AGENT_QA_COMPOSED_CONTRACTS`), so a caller reading only the schemas would never learn that\n * a second capability runs, and \"what did this call actually do\" is not a question a projection may\n * leave unanswerable.\n */\nfunction describe(projection: ToolProjection, specs: readonly ProjectedOpSpec[]): string {\n const composition = compositionOf(projection)\n if (composition === 'single') return specs[0]!.summary\n const arms = specs.map((spec) => `${spec.id}: ${spec.summary}`).join('\\n')\n if (composition === 'pipeline') {\n return `${arms}\\nThese run in the order listed; the second runs only when the first resolves.`\n }\n return `${arms}\\nSelect one with \"${projection.discriminant!}\", whose value is the op id above.`\n}\n\n// An omitted output schema is told to the caller in the description, where it reads.\nfunction degradationSentence(degradation: { readonly schema: string }): string {\n return (\n `\\nThis tool advertises no outputSchema: its result contract (${degradation.schema}) contains a `\n + 'construct JSON Schema cannot represent, and a narrowed stand-in would describe a shape '\n + 'nothing produces. The result still arrives as structuredContent.'\n )\n}\n\n/**\n * Ask the SDK's own converter whether this output contract can be advertised at all.\n *\n * PROBED, NEVER ASSUMED, and probed in OUTPUT mode because that is the mode `tools/list` uses for\n * `outputSchema` — a probe in input mode would answer a question nobody asks and pass for every\n * contract this check exists to catch. The conversion is pure and deterministic, so running it once\n * here and once again inside the SDK costs a listing nothing and buys the failure a name.\n *\n * The three answers, and each one is a decision:\n * - converts, undeclared -> advertise it.\n * - throws, DECLARED -> advertise nothing, say so in the description.\n * - throws, undeclared -> refuse to build the tool, naming the tool, the schema and the\n * converter's own message. Left to the SDK this would surface as an\n * exception inside `tools/list`, taking the whole listing down for\n * every caller with no indication of which tool caused it.\n * - converts, DECLARED -> also refuse. A degradation entry that no longer describes reality is\n * a tool silently withholding a schema it could publish, and a list\n * that can only grow is a list that rots.\n */\nfunction probeOutputSchema(\n projection: ToolProjection,\n output: StandardSchemaWithJSON,\n): StandardSchemaWithJSON | undefined {\n const declared = DEGRADED_OUTPUT_CONTRACTS.find((entry) => entry.tool === projection.name)\n\n let failure: string | undefined\n try {\n output['~standard'].jsonSchema.output({ target: JSON_SCHEMA_CONVERSION_TARGET })\n } catch (err) {\n failure = err instanceof Error ? err.message : String(err)\n }\n\n if (failure === undefined) {\n if (declared === undefined) return output\n throw new McpProjectionError(\n projection.name,\n `is listed in DEGRADED_OUTPUT_CONTRACTS for ${declared.schema}, but that contract now `\n + 'converts cleanly in output mode; remove the entry so the schema is advertised again',\n )\n }\n\n if (declared === undefined) {\n throw new McpProjectionError(\n projection.name,\n `advertises an output contract JSON Schema cannot represent (${failure}). Declare it in `\n + 'DEGRADED_OUTPUT_CONTRACTS with the measured message, or give the op a contract that '\n + 'converts — an unrepresentable outputSchema throws inside tools/list and takes the whole '\n + 'listing down for every caller',\n )\n }\n\n return undefined\n}\n\n// Derived prose is masked; the `title` and the schemas are not, as masking them breaks the tool.\nexport function toRegisterToolConfig(\n projection: ToolProjection,\n specs: readonly ProjectedOpSpec[],\n advertised: ToolOpContracts,\n maskText: (text: string) => string,\n): RegisterToolConfig {\n if (specs.length === 0) {\n throw new McpProjectionError(\n projection.name,\n 'projects no ops; a tool with no arm has nothing to validate against and nothing to call',\n )\n }\n\n if (specs.length !== projection.ops.length) {\n // Unreachable through `catalog.ts`, which resolves every arm or none, and asserted anyway: a\n // tool derived from a SUBSET of its declared arms would advertise a contract narrower than the\n // one its handler dispatches over, and the caller who found the missing arm would be told its\n // valid input was invalid.\n throw new McpProjectionError(\n projection.name,\n `declares ${projection.ops.length} ops but was derived from ${specs.length}`,\n )\n }\n\n const outputSchema = probeOutputSchema(projection, advertised.output)\n const degradation = outputSchema === undefined\n ? DEGRADED_OUTPUT_CONTRACTS.find((entry) => entry.tool === projection.name)\n : undefined\n\n const description = describe(projection, specs)\n const meta = listingMeta(projection)\n const fold = compositionOf(projection) === 'union'\n const inputSchema = fold ? flatFoldInput(projection, advertised.input) : advertised.input\n // Converted once here, so a fold that cannot be listed fails the build rather than tools/list.\n if (fold) inputSchema['~standard'].jsonSchema.input({ target: JSON_SCHEMA_CONVERSION_TARGET })\n return {\n title: projection.name,\n description: maskText(\n degradation === undefined ? description : description + degradationSentence(degradation),\n ),\n inputSchema,\n ...(outputSchema === undefined ? {} : { outputSchema }),\n annotations: deriveAnnotations(specs),\n // Not masked: `resourceUri` is a declared constant, and masking it would break the address.\n ...(meta === undefined ? {} : { _meta: meta }),\n }\n}\n\n// The App reference and the result-size hint are independent members; neither replaces the other.\nfunction listingMeta(projection: ToolProjection): Record<string, unknown> | undefined {\n const meta: Record<string, unknown> = {\n ...(projection.ui === undefined ? {} : { ui: { resourceUri: APP_RESOURCE_URI_TEMPLATE } }),\n ...(projection.maxResultSizeChars === undefined\n ? {}\n : { [MAX_RESULT_SIZE_META_KEY]: projection.maxResultSizeChars }),\n }\n return Object.keys(meta).length === 0 ? undefined : meta\n}\n\ntype JsonObject = Record<string, unknown>\n\n// Claude Code drops a tool whose input is a top-level `oneOf`, so a fold lists one object.\nfunction flatFoldInput(\n projection: ToolProjection,\n input: StandardSchemaWithJSON,\n): StandardSchemaWithJSON {\n const standard = input['~standard']\n return {\n '~standard': {\n version: standard.version,\n vendor: standard.vendor,\n validate: (value, options) => standard.validate(value, options),\n jsonSchema: {\n input: (options) => flatFoldDocument(projection, standard.jsonSchema.input(options)),\n output: (options) => standard.jsonSchema.output(options),\n },\n },\n }\n}\n\ninterface FoldField {\n readonly shapes: JsonObject[]\n readonly notes: string[]\n readonly usedBy: string[]\n readonly requiredBy: string[]\n}\n\nfunction flatFoldDocument(projection: ToolProjection, document: JsonObject): JsonObject {\n const key = projection.discriminant!\n const { oneOf, type: _type, ...rest } = document\n const arms = Array.isArray(oneOf) ? (oneOf as JsonObject[]) : []\n const unsupported = ['anyOf', 'allOf', 'properties'].filter((name) => rest[name] !== undefined)\n if (arms.length !== projection.ops.length || unsupported.length > 0) {\n throw new McpProjectionError(\n projection.name,\n `has an input contract that is not a ${projection.ops.length}-arm union of objects, so it `\n + 'cannot be listed as one object',\n )\n }\n\n const ops: string[] = []\n const fields = new Map<string, FoldField>()\n let actionNote: string | undefined\n let strict = true\n for (const arm of arms) {\n const properties = (arm.properties ?? {}) as Record<string, JsonObject>\n const opId = properties[key]?.const\n if (arm.type !== 'object' || typeof opId !== 'string' || !projection.ops.includes(opId)) {\n throw new McpProjectionError(\n projection.name,\n `has a union arm that is not an object selected by a declared ${key}`,\n )\n }\n ops.push(opId)\n if (arm.additionalProperties !== false) strict = false\n actionNote ??= properties[key]?.description as string | undefined\n const required = (arm.required ?? []) as readonly string[]\n for (const [name, schema] of Object.entries(properties)) {\n if (name === key) continue\n const field = fields.get(name) ?? { shapes: [], notes: [], usedBy: [], requiredBy: [] }\n const { description, ...shape } = schema\n if (!field.shapes.some((seen) => JSON.stringify(seen) === JSON.stringify(shape))) {\n field.shapes.push(shape)\n }\n if (typeof description === 'string' && !field.notes.includes(description)) {\n field.notes.push(description)\n }\n field.usedBy.push(opId)\n if (required.includes(name)) field.requiredBy.push(opId)\n fields.set(name, field)\n }\n }\n\n const perAction = ops.map((opId) => {\n const taken = [...fields].filter(([, field]) => field.usedBy.includes(opId))\n const listed = taken.map(([name, field]) =>\n field.requiredBy.includes(opId) ? name : `${name} (optional)`,\n )\n return `${opId} takes ${listed.length === 0 ? 'no other field' : listed.join(', ')}.`\n })\n const properties: Record<string, JsonObject> = {\n [key]: {\n type: 'string',\n enum: ops,\n description: [actionNote, ...perAction].filter(Boolean).join(' '),\n },\n }\n const required = [key]\n for (const [name, field] of fields) {\n const scope = field.usedBy.length === ops.length\n ? 'every action'\n : `${field.usedBy.join(' or ')} only`\n const need = field.requiredBy.length === 0\n ? 'optional'\n : field.requiredBy.length === field.usedBy.length\n ? 'required'\n : `required for ${field.requiredBy.join(' or ')}`\n const shape = field.shapes.length === 1 ? field.shapes[0]! : { anyOf: field.shapes }\n const description = [...field.notes, `For ${scope}; ${need}.`].join(' ')\n properties[name] = { ...shape, description }\n if (field.requiredBy.length === ops.length) required.push(name)\n }\n\n return {\n ...rest,\n type: 'object',\n properties,\n required,\n ...(strict ? { additionalProperties: false } : {}),\n }\n}\n\n/** A projection that cannot be derived honestly, named with the tool it is about. */\nexport class McpProjectionError extends Error {\n constructor(readonly toolName: string, detail: string) {\n super(`${toolName} ${detail}`)\n this.name = 'McpProjectionError'\n }\n}\n","// Registered outside the generic handler, so contents and refusals are masked here (SEP-2549).\n\nimport { ResourceTemplate } from '@modelcontextprotocol/server'\nimport type { ReadResourceResult, ResourceMetadata } from '@modelcontextprotocol/server'\nimport { invokeFunction } from '@vostride/agent-qa-agent'\nimport type { FunctionRegistry } from '@vostride/agent-qa-agent'\nimport {\n ENTITY_KINDS,\n ENTITY_URI_SEGMENTS,\n formatEntityUri,\n parseEntityUri,\n} from '@vostride/agent-qa-schema'\nimport type { EntityKind, FunctionCaller } from '@vostride/agent-qa-schema'\n\nimport { maskJsonDocument } from './masked-result.js'\n\n/**\n * The ONE op this surface reads through.\n *\n * A constant rather than a literal at three sites, and declared here rather than imported: the\n * function layer keeps its id constants inside its own directory and does not publish them on its\n * barrel, so the id is spelled once here.\n */\nexport const ENTITIES_GET_OP_ID = 'entities.get'\n\n/** The media type entity cards are handed out as. They are JSON documents, not prose. */\nexport const ENTITY_RESOURCE_MIME_TYPE = 'application/json'\n\n/** One derived template: everything `registerResource` needs for one kind. */\nexport interface EntityResourceTemplate {\n readonly kind: EntityKind\n readonly segment: string\n /** The registered resource name. Prefixed like the tools, so one namespace reads as one server. */\n readonly name: string\n readonly uriTemplate: string\n readonly title: string\n readonly description: string\n}\n\nfunction templateFor(kind: EntityKind): EntityResourceTemplate {\n const segment = ENTITY_URI_SEGMENTS[kind]\n return {\n kind,\n segment,\n name: `agent_qa_entity_${segment}`,\n uriTemplate: `agentqa://${segment}/{id}`,\n title: `agent-qa ${segment} entity`,\n // Authored prose about a KIND, not about any entity's content — the same class of string as a\n // tool's curated title, so it is not masked. Nothing interpolated here comes from storage.\n description:\n `The entity card for one ${segment} addressed by its canonical agentqa:// URI `\n + `(for example agentqa://${segment}/${kind}-001). Resolved through the entities read op.`,\n }\n}\n\n/**\n * The five templates, derived once at module load.\n *\n * Iterating `ENTITY_KINDS` and indexing `ENTITY_URI_SEGMENTS` is how `kinds.ts` builds its own\n * reverse table, so the listing ORDER here is the vocabulary's canonical order rather than an\n * accident of object-key iteration.\n */\nexport const ENTITY_RESOURCE_TEMPLATES: readonly EntityResourceTemplate[] =\n ENTITY_KINDS.map(templateFor)\n\n/** The host-bound `(registry, caller)` closure over `invokeFunction`. */\nexport type EntityResourceInvoke = (opId: string, input: unknown) => Promise<unknown>\n\nexport interface EntityResourceReadDeps {\n readonly invoke: EntityResourceInvoke\n // Required: resource contents come from stored data that nothing else masks.\n readonly maskText: (text: string) => string\n}\n\n/** A URI the one codec does not recognise as an address. */\nexport class EntityResourceUriError extends Error {\n constructor(detail: string) {\n super(`${detail} is not a canonical agentqa:// entity address`)\n this.name = 'EntityResourceUriError'\n }\n}\n\n/** A refusal from the entity read, carried out with its message masked. */\nexport class EntityResourceReadError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'EntityResourceReadError'\n }\n}\n\n// One handler for every kind, because the codec already read the kind from the URI.\nexport function createEntityResourceReadHandler(\n deps: EntityResourceReadDeps,\n): (uri: URL) => Promise<ReadResourceResult> {\n return async (uri: URL): Promise<ReadResourceResult> => {\n const parsed = parseEntityUri(uri.href)\n if (parsed === undefined) {\n // The refusal is the CODEC's verdict, phrased. Nothing here re-examines the string to decide\n // WHY it failed: the codec's reasons (unknown segment, disagreeing prefix, trailing path,\n // malformed body) are its own, and re-deriving them would be the second parser by another\n // name. The echoed URI is caller-supplied text, so it is masked like everything else.\n throw new EntityResourceUriError(deps.maskText(uri.href))\n }\n\n let card: unknown\n try {\n // The canonical short-ID, not the raw URI. `entities.get` accepts both, and passing the\n // parsed value is what makes the parse load-bearing rather than a check that happens to run\n // before a string is forwarded untouched.\n card = await deps.invoke(ENTITIES_GET_OP_ID, { ref: parsed.shortId })\n } catch (err) {\n throw new EntityResourceReadError(\n deps.maskText(err instanceof Error ? err.message : String(err)),\n )\n }\n\n // Masked as a value: escaping in a serialized document hides raw secrets from the masker.\n const masked = maskJsonDocument(card, deps.maskText)\n if (masked === undefined) {\n // FAILS CLOSED, like the tool channel: a card whose masked form would not be the same kind of\n // value is withheld rather than served. The message names the condition and quotes nothing.\n throw new EntityResourceReadError(\n 'This entity could not be returned: part of its card could not be masked in place, so the '\n + 'unmasked record was withheld rather than served.',\n )\n }\n\n return {\n contents: [\n {\n // Re-FORMATTED through the codec rather than echoed: the address a caller reads back is\n // the canonical one, so `agentqa://memory/MEM-1` answers about `MEM-001` and says so.\n uri: formatEntityUri(parsed.kind, parsed.shortId),\n mimeType: ENTITY_RESOURCE_MIME_TYPE,\n text: masked.text,\n },\n ],\n }\n }\n}\n\n/**\n * The slice of `McpServer` this module uses.\n *\n * ONE signature — the SDK's template overload, spelled with the SDK's own `ResourceMetadata` and\n * `ReadResourceResult` — so a cell can observe every registration without assembling a protocol\n * server while a real `McpServer` still satisfies it. Both halves of that depend on the types\n * matching the SDK EXACTLY: a hand-narrowed config record, or a hand-narrowed result with a\n * `readonly` contents array, makes `McpServer` unassignable here (overload resolution then fails on\n * the string overload, whose message names a mismatch that is not the real one). Measured, not\n * assumed — the SDK cell in this module's tests registers on a real server, so this interface\n * cannot drift away from the thing it stands for without a compile error.\n */\nexport interface EntityResourceRegistrar {\n registerResource(\n name: string,\n template: ResourceTemplate,\n config: ResourceMetadata,\n read: (uri: URL) => Promise<ReadResourceResult>,\n ): unknown\n}\n\n/** Exactly what this module needs from the host — the same record `catalog.ts` already holds. */\nexport interface EntityResourceDeps {\n readonly registry: FunctionRegistry\n readonly caller: FunctionCaller\n readonly maskText: (text: string) => string\n}\n\n// A composition without `entities.get` gets no templates and no error, so the connection stays up.\nexport function registerEntityResources(\n server: EntityResourceRegistrar,\n deps: EntityResourceDeps,\n): readonly EntityResourceTemplate[] {\n const declaration = deps.registry\n .list(deps.caller)\n .find((candidate) => candidate.id === ENTITIES_GET_OP_ID)\n if (declaration === undefined) return []\n\n const read = createEntityResourceReadHandler({\n // The wall, bound once: every template's read crosses `invokeFunction` with this host's\n // registry and this caller, so input validation and the binding check run exactly as they do\n // for a tool call.\n invoke: (opId, input) => invokeFunction(deps.registry, opId, input, deps.caller),\n maskText: deps.maskText,\n })\n\n for (const template of ENTITY_RESOURCE_TEMPLATES) {\n server.registerResource(\n template.name,\n // `list: undefined` is REQUIRED to be spelled out by the SDK, and the value is the honest\n // one: enumerating every entity of a kind is a listing this surface does not offer, and the\n // SDK asks for the explicit `undefined` precisely so that absence is a decision.\n new ResourceTemplate(template.uriTemplate, { list: undefined }),\n // v2 requires the metadata argument; it is not optional the way it was in v1.\n {\n title: template.title,\n description: template.description,\n mimeType: ENTITY_RESOURCE_MIME_TYPE,\n },\n read,\n )\n }\n\n return ENTITY_RESOURCE_TEMPLATES\n}\n","// A request function only: it binds no socket and emits no CORS header; stateless per SEP-2575.\n\nimport { createMcpHandler } from '@modelcontextprotocol/server'\nimport type { McpRequestContext } from '@modelcontextprotocol/server'\nimport { toNodeHandler } from '@modelcontextprotocol/node'\n\nimport { buildAgentQaMcpServer } from './catalog.js'\nimport type { AgentQaMcpServerDeps } from './catalog.js'\n\n// Takes the SDK's per-request context, so facts such as `era` arrive here, not from a header.\nexport type AgentQaMcpDepsResolver = (ctx: McpRequestContext) => AgentQaMcpServerDeps\n\n// Reruns the factory per request; the host's Host and Origin guard sits in front of this handler.\nexport function createAgentQaMcpNodeHandler(resolveDeps: AgentQaMcpDepsResolver) {\n return toNodeHandler(createMcpHandler((ctx) => buildAgentQaMcpServer(resolveDeps(ctx))))\n}\n","// Pure normalisations two schema suites share; each strips only an SDK artifact (SEP-2106).\n\n/** A JSON-Schema document as it travels: an ordinary object, with nothing runnable on it. */\nexport type JsonDocument = Record<string, unknown>\n\n/**\n * Drop `$schema`, which the SDK's conversion stamps and the registry's projection does not.\n *\n * A DIALECT MARKER, not content: it says which JSON Schema draft the document speaks and describes\n * nothing about the contract. Removing it is the one normalisation this file performs, and it is\n * called out rather than buried because a normalisation that removed content would be the way to\n * make a drift cell pass over real drift.\n */\nexport function withoutDialect(document: unknown): JsonDocument {\n const { $schema: _dialect, ...rest } = (document ?? {}) as JsonDocument\n return stripRedundantObjectStamp(rest)\n}\n\n/**\n * Drop the `type: \"object\"` the SDK stamps onto a COMPOSITION root.\n *\n * The second and last normalisation, and it is as narrow as the first. `standardSchemaToJsonSchema`\n * stamps `type: \"object\"` on a typeless root it can prove is object-shaped — a `oneOf` whose every\n * member is `type: \"object\"`, which is exactly what a zod discriminated union emits. The SDK's own\n * comment calls the stamp \"redundant-but-valid\", and a document is not changed by adding a\n * constraint every one of its branches already imposes.\n *\n * IT IS GATED ON THE COMPOSITION KEYWORD, so a genuine `type` disagreement still reds: the only\n * case dropped is a root that carries `oneOf`/`anyOf` AND the stamp, which is the one case the SDK\n * manufactures. An ungated `delete document.type` would have made the whole drift cell blind to a\n * contract whose root type actually moved.\n */\nexport function stripRedundantObjectStamp(document: JsonDocument): JsonDocument {\n const composed = document.oneOf !== undefined || document.anyOf !== undefined\n if (!composed || document.type !== 'object') return document\n const { type: _stamp, ...rest } = document\n return rest\n}\n\n/**\n * One union arm of a fold's composed contract, with the fold's discriminant taken back out.\n *\n * `required: []` is DROPPED rather than kept, and the case is real rather than defensive:\n * `config.undo.propose` takes an all-optional input, so its own projection carries no `required`\n * key at all while the extended arm carries `['action']` — and removing the discriminant from that\n * leaves an empty array where the other side has nothing. JSON Schema reads an absent `required`\n * and an empty one identically, so the two documents agree; keeping the empty array would have\n * failed the cell on a difference that describes no difference.\n */\nexport function armWithoutDiscriminant(arm: JsonDocument, discriminant: string): JsonDocument {\n const properties = { ...((arm.properties ?? {}) as JsonDocument) }\n delete properties[discriminant]\n const required = ((arm.required ?? []) as readonly string[]).filter((key) => key !== discriminant)\n const rebuilt: JsonDocument = { ...arm, properties, required }\n if (required.length === 0) delete rebuilt.required\n return rebuilt\n}\n\n// Covered: the enum names the arm, its fields keep their shapes, and nothing extra is required.\nexport function foldArmFindings(\n listed: JsonDocument,\n discriminant: string,\n opId: string,\n own: JsonDocument,\n): readonly string[] {\n const findings: string[] = []\n for (const key of ['oneOf', 'anyOf', 'allOf']) {\n if (listed[key] !== undefined) findings.push(`the listing carries a top-level ${key}`)\n }\n if (listed.type !== 'object') findings.push('the listing is not type object')\n const properties = (listed.properties ?? {}) as Record<string, JsonDocument>\n const selector = properties[discriminant]?.enum\n if (!Array.isArray(selector) || !selector.includes(opId)) {\n findings.push(`${discriminant} does not list ${opId}`)\n }\n const ownProperties = (own.properties ?? {}) as Record<string, JsonDocument>\n for (const [name, field] of Object.entries(ownProperties)) {\n const shown = properties[name]\n if (shown === undefined) {\n findings.push(`${name} is not listed`)\n continue\n }\n const { description: ownNote, ...ownShape } = field\n const { description: shownNote, ...shownShape } = shown\n const merged = Array.isArray(shownShape.anyOf) && Object.keys(shownShape).length === 1\n const shapes = merged ? [shownShape, ...(shownShape.anyOf as readonly unknown[])] : [shownShape]\n if (!shapes.some((shape) => JSON.stringify(shape) === JSON.stringify(ownShape))) {\n findings.push(`${name} is listed with another shape`)\n }\n const kept = typeof shownNote === 'string' && shownNote.includes(String(ownNote))\n if (typeof ownNote === 'string' && !kept) {\n findings.push(`${name} lost its own description`)\n }\n }\n const allowed = new Set([discriminant, ...((own.required ?? []) as readonly string[])])\n for (const name of (listed.required ?? []) as readonly string[]) {\n if (!allowed.has(name)) findings.push(`the listing requires ${name}, which ${opId} does not`)\n }\n if (own.additionalProperties === false && listed.additionalProperties !== false) {\n findings.push('the listing admits fields no arm takes')\n }\n return findings\n}\n\n// Undoes the `2025-11-25` codec's `{ result }` wrap; run it before `withoutDialect` (SEP-2106).\nexport function withoutLegacyResultWrap(document: unknown): JsonDocument {\n const wrapper = (document ?? {}) as JsonDocument\n const keys = Object.keys(wrapper).filter((key) => key !== '$schema').sort()\n if (keys.join(',') !== 'properties,required,type' || wrapper.type !== 'object') return wrapper\n const properties = wrapper.properties as JsonDocument\n const required = wrapper.required as unknown\n if (Object.keys(properties ?? {}).join(',') !== 'result') return wrapper\n if (!Array.isArray(required) || required.length !== 1 || required[0] !== 'result') return wrapper\n const natural = properties.result as JsonDocument\n if (typeof natural !== 'object' || natural === null || natural.type === 'object') return wrapper\n return natural\n}\n"],"mappings":"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","names":["invokeFunction","properties","required","ResourceTemplate","invokeFunction","invokeFunction","ResourceTemplate","invokeFunction"]}