{"record":{"id":"92395237964775f3","repo":"ruvnet/ruflo","slug":"scoreby-nearest-requires-a-probe-vector","errorCode":null,"errorMessage":"scoreBy='nearest' requires a probe vector","messagePattern":"scoreBy='nearest' requires a probe vector","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agenticow-speculate-tools.ts","lineNumber":149,"sourceCode":"      },\n      required: ['basePath', 'candidates'],\n    },\n    handler: async (input) => {\n      const api = await loadAgenticow();\n      if (!api) return degradedResult('agenticow-not-found');\n\n      const basePath = resolveMemoryPath(String(input.basePath));\n      const dimension = input.dimension as number | undefined;\n      const scoreBy = (input.scoreBy as string) === 'count' ? 'count' : 'nearest';\n      const k = Number.isInteger(input.k) && (input.k as number) > 0 ? (input.k as number) : 1;\n      const probe = Array.isArray(input.probe) ? (input.probe as number[]) : null;\n\n      const rawCandidates = input.candidates as CandidateInput[];\n      if (!Array.isArray(rawCandidates) || rawCandidates.length === 0) {\n        throw new Error('at least one candidate is required');\n      }\n      if (scoreBy === 'nearest' && !probe) {\n        throw new Error(\"scoreBy='nearest' requires a probe vector\");\n      }\n\n      // Build the generic {label, fn} candidates. Each fn ingests into its own\n      // branch handle, then (for 'nearest') probes it so we can score.\n      // Map validated label → explicit branchPath so the branchPath() resolver\n      // below is O(1) instead of re-scanning + re-validating rawCandidates per\n      // candidate (explore() calls branchPath once per candidate → was O(n²)).\n      const explicitBranchPaths = new Map<string, string>();\n      const candidates: SpeculativeCandidate<CandidateOutcome>[] = rawCandidates.map((c) => {\n        const label = validateLabel(String(c.label));\n        if (!Array.isArray(c.ingest) || c.ingest.length === 0) {\n          throw new Error(`candidate ${label} must ingest at least one vector`);\n        }\n        if (typeof c.branchPath === 'string' && c.branchPath) {\n          explicitBranchPaths.set(label, c.branchPath);\n        }\n        const records = c.ingest.map((r) => ({\n          ...(Number.isInteger(r.id) ? { id: r.id as number } : {}),","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/mcp-tools/agenticow-speculate-tools.ts#L131-L167","documentation":"Thrown by the agenticow_speculate MCP tool when scoreBy resolves to 'nearest' (the default) but no probe vector was supplied. Scoring by 'nearest' ranks each speculative branch by how close its best-ingested vector sits to the probe, so the probe is mandatory input for that mode. Without it the similarity score is undefined and the tool refuses to guess.","triggerScenarios":"Calling agenticow_speculate with scoreBy omitted (defaults to 'nearest') or explicitly set to 'nearest', while omitting the probe field. Also triggers when probe is passed as a non-array (e.g. a string or object) because the handler nulls it via `Array.isArray(input.probe) ? ... : null`.","commonSituations":"A caller copies a 'count'-mode example and switches scoreBy back to 'nearest' without adding a probe; passing probe as a JSON string instead of a numeric array; migrating from a scoreBy='count' workflow to similarity ranking and forgetting the query embedding.","solutions":["Supply a numeric probe array whose length equals the candidate vector dimension, e.g. probe: [0.12, -0.03, ...].","If you only want to rank branches by how many ingests they accepted, set scoreBy: 'count' instead and omit probe.","Verify probe is a JS/JSON array of numbers, not a stringified array or object — a non-array is treated as missing.","Confirm the probe dimension matches each candidate's ingest vectors or the branch query will fail downstream."],"exampleFix":"// before\nagenticow_speculate({ basePath, candidates, scoreBy: 'nearest' })\n// after\nagenticow_speculate({ basePath, candidates, scoreBy: 'nearest', probe: embedding })","handlingStrategy":"validation","validationCode":"function validateSpeculateInput(input) {\n  const scoreBy = input.scoreBy === 'count' ? 'count' : 'nearest';\n  if (scoreBy === 'nearest') {\n    if (!Array.isArray(input.probe) || input.probe.length === 0) {\n      throw new Error(\"scoreBy='nearest' requires a non-empty probe array\");\n    }\n    if (!input.probe.every((n) => typeof n === 'number' && Number.isFinite(n))) {\n      throw new Error('probe must be an array of finite numbers');\n    }\n  }\n}","typeGuard":"function isProbeVector(v: unknown): v is number[] {\n  return Array.isArray(v) && v.length > 0 && v.every((n) => typeof n === 'number' && Number.isFinite(n));\n}","tryCatchPattern":null,"preventionTips":["Default to passing an explicit scoreBy and matching probe together.","Generate the probe from the same embedding pipeline as the ingest vectors so dimensions match.","Unit-test the speculate call with both 'count' and 'nearest' modes."],"tags":["agenticow","mcp-tools","validation","vector-search","speculative"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}