{"record":{"id":"b8af2532dc31669d","repo":"affaan-m/ECC","slug":"tool-unknown","errorCode":"tool.unknown","errorMessage":"tool ${name} is not declared","messagePattern":"tool (.+?) is not declared","errorType":"error_code","errorClass":"ReplayError","httpStatus":null,"severity":"error","filePath":"scripts/lib/eval-harness/replay.js","lineNumber":123,"sourceCode":"      throw new ReplayError('replay.bad_declaration', `tool ${name} must declare determinism`);\n    }\n  }\n\n  const calls = [];\n  const emit = (entry) => {\n    calls.push(entry);\n    if (typeof options.onCall === 'function') {\n      options.onCall(entry);\n    }\n  };\n\n  return {\n    mode,\n    calls,\n    call(name, args = {}) {\n      const tool = tools[name];\n      if (!tool) {\n        throw new ReplayError('tool.unknown', `tool ${name} is not declared`);\n      }\n      const rank = envelope.effectRank(tool.effect_class);\n      if (rank > maxRank) {\n        emit({ tool: name, mode, status: 'refused', code: 'tool.effect_forbidden' });\n        throw new ReplayError('tool.effect_forbidden', `tool ${name} is ${tool.effect_class}, above the allowed ${options.maxEffectClass || 'SE2'}`, { tool: name });\n      }\n      if (mode === 'replay') {\n        if (rank >= envelope.effectRank('SE3')) {\n          emit({ tool: name, mode, status: 'refused', code: 'tool.effect_forbidden' });\n          throw new ReplayError('tool.effect_forbidden', `tool ${name} (${tool.effect_class}) can never be replayed`, { tool: name });\n        }\n        const record = store.get(name, args);\n        emit({ tool: name, mode, status: 'replayed', fixture_key: record.key, args_hash: record.args_hash, response_hash: record.response_hash });\n        return record.response;\n      }\n      const response = tool.impl(args);\n      const record = store.put(name, args, response);\n      emit({ tool: name, mode, status: 'recorded', fixture_key: record.key, args_hash: record.args_hash, response_hash: record.response_hash });","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/eval-harness/replay.js#L105-L141","documentation":"replayer.call(name, args) throws ReplayError('tool.unknown') when the requested tool name is not a key of the tools map passed to createReplayer. The replayer only permits calls to explicitly declared tools so every call's effect class and determinism are known. There is no dynamic registration after construction.","triggerScenarios":"Calling r.call('fetchWether', ...) with a typo; calling a tool that was declared in another suite's tools map; a name mismatch between where tools are declared and where call() happens (e.g. kebab-case vs camelCase); calling a tool that was removed in a refactor.","commonSituations":"Renaming a tool in the registry without updating call sites; loading tool names from config/test data where the fixture references an old name; sharing fixture sets between suites with different registries; case-sensitive lookup ('FetchWeather' ≠ 'fetchWeather').","solutions":["Add the tool to the tools map passed to createReplayer with full declaration (effect_class, determinism, impl), or","Fix the name in the call() site to exactly match a declared key — print Object.keys(tools) to compare.","Synchronize tool names across config, fixtures, and call sites; consider exporting a shared TOOLS constant used by both declaration and call sites.","If the name comes from data (test plan/fixture), validate it against the registry before running the suite."],"exampleFix":"// before\nr.call('fetchWether', { city: 'Paris' }); // typo\n\n// after\nr.call('fetchWeather', { city: 'Paris' });","handlingStrategy":"type-guard","validationCode":"if (!(toolName in tools)) {\n  throw new Error(`unknown tool ${toolName}; available: ${Object.keys(tools).join(', ')}`);\n}","typeGuard":"function isDeclaredTool(tools, name) {\n  return Object.prototype.hasOwnProperty.call(tools, name);\n}","tryCatchPattern":"try {\n  return replayer.call(name, args);\n} catch (e) {\n  if (e instanceof ReplayError && e.code === 'tool.unknown') {\n    throw new Error(`${name} not declared; declared tools: ${Object.keys(tools).join(', ')}`);\n  }\n  throw e;\n}","preventionTips":["Keep tool names in one shared constant/module used by both the registry and call sites","Validate external/test-plan tool names against the registry before execution","Grep for call sites after renaming any tool","Keep one naming convention (camelCase) for all tool keys"],"tags":["tool-registry","typo","validation","replay"],"backgroundTag":"record-not-found","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}