{"record":{"id":"289dbbf943725948","repo":"different-ai/openwork","slug":"catalog-does-not-match-pinned-profile-fixture-pr","errorCode":null,"errorMessage":"Catalog does not match pinned profile fixture ${profile.fixtureVersion}","messagePattern":"Catalog does not match pinned profile fixture (.+?)","errorType":"exception","errorClass":"ProbeFailure","httpStatus":null,"severity":"error","filePath":"packages/enterprise-mcp-mock-server/src/testing/probe.ts","lineNumber":853,"sourceCode":"        if (sourceTool) discoveredTools.push(sourceTool)\n      }\n      if (!result.nextCursor) {\n        catalogComplete = true\n        break\n      }\n      cursor = result.nextCursor\n    }\n    if (!catalogComplete) {\n      throw new ProbeFailure(\"MCP_TOOL_DISCOVERY\", \"mcp_pagination_limit\", \"Tool catalog exceeded the 25-page safety limit\")\n    }\n    mutable.toolCount = toolNames.size\n    if (toolNames.size === 0) throw new ProbeFailure(\"MCP_TOOL_DISCOVERY\", \"catalog_empty\", \"Tool catalog was protocol-valid but did not satisfy enterprise readiness because it was empty\")\n    if (mode !== \"connection-readiness\") {\n      const expectedToolNames = new Set(profile.tools.map((tool) => tool.name))\n      const missing = [...expectedToolNames].filter((name) => !toolNames.has(name))\n      const unexpected = [...toolNames].filter((name) => !expectedToolNames.has(name))\n      if (missing.length > 0 || unexpected.length > 0) {\n        throw new ProbeFailure(\n          \"MCP_TOOL_DISCOVERY\",\n          \"profile_fixture_mismatch\",\n          `Catalog does not match pinned profile fixture ${profile.fixtureVersion}`,\n        )\n      }\n    }\n    recordPassed(phases, \"MCP_TOOL_DISCOVERY\", startedAt, `Retrieved ${toolNames.size} unique tools with bounded pagination`)\n\n    const fault = activeFault\n    const shouldCall = options.callTool !== undefined || mode === \"safe-read\" || fault?.phase === \"PROVIDER_AUTHORIZATION\" || fault?.phase === \"PROVIDER_EXECUTION\"\n    if (shouldCall) {\n      const selected = options.callTool\n        ? { name: options.callTool.name, arguments: options.callTool.arguments }\n        : (() => {\n            const mutationRequired = fault?.effect === \"commit-then-disconnect\"\n            const tool = discoveredTools.find((candidate) => candidate.kind === (mutationRequired ? \"mutation\" : \"read\"))\n            if (!tool) throw new ProbeFailure(\"MCP_TOOL_EXECUTION\", \"mcp_tool\", \"No suitable tool was available for the requested probe\")\n            return { name: tool.name, arguments: defaultArguments(tool.inputSchema) }","sourceCodeStart":835,"sourceCodeEnd":871,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/enterprise-mcp-mock-server/src/testing/probe.ts#L835-L871","documentation":"Outside connection-readiness mode, the discovered tool catalog must exactly match the pinned profile fixture: no missing tools and no unexpected extras. Any set difference fails the probe with MCP_TOOL_DISCOVERY / profile_fixture_mismatch, citing the fixture version.","triggerScenarios":"probeEnterpriseMcpMockServer (mode != connection-readiness) computes missing or unexpected tool names when diffing toolNames against profile.tools, and either list is non-empty.","commonSituations":"Mock server profile drift after editing tools without bumping fixtureVersion; server serving a stale or different fixture; extra debug tools registered on the server; a tool renamed in the fixture but not on the server.","solutions":["Diff the server's advertised tool names against profile.tools and reconcile the two sets.","Remove unexpected debug/experimental tools or add the missing tools to the server registry.","If the catalog change is intentional, update the pinned fixture and bump profile.fixtureVersion.","Re-run the probe in the same non-connection-readiness mode and confirm no diff remains."],"exampleFix":"// before: tool added to server but not the fixture\nserver.register(debugTool);\n// after: either remove it or pin it in the fixture\n// fixture: { fixtureVersion: \"2\", tools: [...existing, debugTool] }","handlingStrategy":"validation","validationCode":"const expected = new Set(profile.tools.map((t) => t.name));\nconst actual = new Set(catalog.tools.map((t) => t.name));\nconst missing = [...expected].filter((n) => !actual.has(n));\nconst unexpected = [...actual].filter((n) => !expected.has(n));\nif (missing.length || unexpected.length) {\n  throw new Error(`Fixture drift — missing: ${missing}, unexpected: ${unexpected}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await probeEnterpriseMcpMockServer(options);\n} catch (e) {\n  if (e instanceof ProbeFailure && e.reason === \"profile_fixture_mismatch\") {\n    // diff the catalog against the fixture and reconcile before retrying\n  } else throw e;\n}","preventionTips":["Bump profile.fixtureVersion whenever the tool catalog changes.","Generate the server registry from the fixture instead of registering tools by hand.","Add a CI check diffing server tools against the pinned fixture."],"tags":["mcp","fixture-drift","profile-mismatch"],"backgroundTag":"fixture-version-mismatch","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}