{"record":{"id":"adf169330b52f8a5","repo":"paperclipai/paperclip","slug":"operation-unavailable","errorCode":"operation_unavailable","errorMessage":"No mock operation is bound to this descriptor.","messagePattern":"No mock operation is bound to this descriptor\\.","errorType":"error_code","errorClass":"SemanticDispatchFailure","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/semantic-tools/dispatcher.ts","lineNumber":408,"sourceCode":"        };\n        break;\n      case \"request_approval\":\n        command = { kind: \"request_approval\", taskId, approvalType: requiredString(input.approvalType), payload: optionalJson(input.payload) };\n        break;\n      case \"decide_approval\":\n        command = { kind: \"decide_approval\", taskId, approvalId: requiredString(input.approvalId), decision: requiredString(input.decision) as Extract<CapabilitySemanticCommand, { kind: \"decide_approval\" }>[\"decision\"], note: requiredString(input.note) };\n        break;\n      case \"comment_on_approval\":\n        command = { kind: \"comment_on_approval\", taskId, approvalId: requiredString(input.approvalId), body: requiredString(input.body) };\n        break;\n      case \"control_workspace_service\":\n        command = { kind: \"control_workspace_service\", taskId, serviceId: requiredString(input.serviceId), action: requiredString(input.action) as Extract<CapabilitySemanticCommand, { kind: \"control_workspace_service\" }>[\"action\"], url: nullableOptionalString(input.url) };\n        break;\n      case \"schedule_wake\":\n        command = { kind: \"schedule_wake\", taskId, reason: requiredString(input.reason) as Extract<CapabilitySemanticCommand, { kind: \"schedule_wake\" }>[\"reason\"], payload: optionalJson(input.payload), delayTicks: requiredNumber(input.delayTicks) };\n        break;\n      default:\n        throw new SemanticDispatchFailure(\"operation_unavailable\", \"No mock operation is bound to this descriptor.\");\n    }\n    const outcome = await this.port.tryApplyCommand({ runId, idempotencyKey, command });\n    if (operationId === \"create_skill\" && outcome.ok) {\n      const id = outcome.result.entityRefs.find(ref => ref.startsWith(\"skill:\"))?.slice(6);\n      const skill = this.port.snapshot().skills?.find(candidate => candidate.id === id);\n      if (skill) return readSuccess(outcome.result.stateRevision, {\n        id: skill.id, name: skill.name, slug: skill.slug, description: skill.description,\n        versionId: skill.versionId, studioPath: `/skills/studio/${skill.id}`,\n      });\n    }\n    return commandOutcome(outcome);\n  }\n\n  #record(\n    context: CapabilitySemanticPolicyContext,\n    decision: CapabilitySemanticAuthorizationDecision,\n    callId: string | null,\n    input: unknown,","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/paperclip-runner/src/semantic-tools/dispatcher.ts#L390-L426","documentation":"SemanticDispatchFailure with code `operation_unavailable`, thrown from the semantic tools dispatcher when an input descriptor maps to a command kind that has no case in #applyMutation's switch. The dispatcher only binds a fixed set of mock operations; descriptors outside that set fall into the default branch and are rejected, meaning the mock control plane cannot execute the requested operation.","triggerScenarios":"#execute → #applyMutation with an operation whose normalized kind is not one of the handled cases (e.g. an unlisted or newly added semantic operation) so the switch hits `default`; calling a descriptor supported by the real control plane but not bound in the mock dispatcher.","commonSituations":"A new semantic operation was added upstream but the mock dispatcher switch was not extended; typo or version drift causing the descriptor to normalize to an unbound kind; tests exercising an operation the mock fixture does not implement.","solutions":["Use one of the dispatcher's supported operations (e.g. control_workspace_service, schedule_wake) instead of the unbound descriptor","Add a case for the new operation kind in #applyMutation of packages/paperclip-runner/src/semantic-tools/dispatcher.ts","Verify the operationId/descriptor spelling matches a registered mock operation","Check whether the mock fixture version supports the operation; upgrade the fixture if newer operations are needed"],"exampleFix":"// before (dispatcher.ts, #applyMutation)\ncase \"control_workspace_service\": ... break;\n// default: throw new SemanticDispatchFailure(\"operation_unavailable\", ...)\n// after — add the missing binding\ncase \"schedule_wake\":\n  command = { kind: \"schedule_wake\", taskId, reason: requiredString(input.reason), payload: optionalJson(input.payload), delayTicks: requiredNumber(input.delayTicks) };\n  break;","handlingStrategy":"try-catch","validationCode":"const SUPPORTED = new Set([\"control_workspace_service\", \"schedule_wake\" /* ...registered kinds */]);\nif (!SUPPORTED.has(operation.kind)) {\n  throw new Error(`Operation '${operation.kind}' is not bound in the mock dispatcher`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const outcome = await dispatcher.execute(input);\n} catch (e) {\n  if (e instanceof SemanticDispatchFailure && e.code === \"operation_unavailable\") {\n    // fall back to a supported operation or skip with a clear test failure\n  } else throw e;\n}","preventionTips":["Keep the dispatcher switch cases in sync with the semantic operation registry","Add the new case to #applyMutation whenever a new CapabilitySemanticCommand kind is introduced","Assert in tests that every registered descriptor has a bound mock operation","Check the fixture's supported-operation list before invoking newer operations"],"tags":["dispatcher","mock","unsupported-operation","semantic-tools"],"backgroundTag":"operation-not-supported","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}