{"record":{"id":"21d5cea56566a5fa","repo":"ruvnet/ruflo","slug":"selfconsistency-aggregator-mean-requires-every","errorCode":null,"errorMessage":"selfConsistency: aggregator='mean' requires every sample to be a finite number","messagePattern":"selfConsistency: aggregator='mean' requires every sample to be a finite number","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/neural/src/utils/self-consistency.ts","lineNumber":102,"sourceCode":"    // arrays). Float32Array does NOT JSON-encode losslessly by default —\n    // callers wanting f32 majority should pre-convert via Array.from.\n    const counts = new Map<string, { value: T; count: number }>();\n    for (const s of samples) {\n      const key = canonicalKey(s);\n      const existing = counts.get(key);\n      if (existing) existing.count += 1;\n      else counts.set(key, { value: s, count: 1 });\n    }\n    let best: { value: T; count: number } = { value: samples[0], count: 0 };\n    for (const c of counts.values()) {\n      if (c.count > best.count) best = c;\n    }\n    finalAnswer = best.value;\n    agreement = best.count / samples.length;\n  } else if (aggregator === 'mean') {\n    const nums = samples as unknown as number[];\n    if (!nums.every((v) => typeof v === 'number' && Number.isFinite(v))) {\n      throw new Error(\"selfConsistency: aggregator='mean' requires every sample to be a finite number\");\n    }\n    const mean = nums.reduce((a, b) => a + b, 0) / nums.length;\n    const variance = nums.reduce((s, v) => s + (v - mean) ** 2, 0) / nums.length;\n    const stddev = Math.sqrt(variance);\n    const range = Math.max(1e-9, Math.abs(mean) || 1); // avoid div-by-0\n    finalAnswer = mean as unknown as T;\n    agreement = Math.max(0, Math.min(1, 1 - stddev / range));\n  } else {\n    finalAnswer = samples[0];\n    agreement = 1;\n  }\n\n  return { finalAnswer, samples, agreement, config };\n}\n\n/**\n * Canonical-form key for grouping. JSON.stringify is enough for primitives,\n * arrays, and plain objects with stable key order. Callers wanting locale-","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/neural/src/utils/self-consistency.ts#L84-L120","documentation":"When aggregator is 'mean', selfConsistency() reduces all N samples numerically and requires every sample to be a finite number; one bad sample out of N aborts the aggregation. Non-numbers (strings, undefined, null, objects) and non-finite numbers (NaN, Infinity, -Infinity) are all rejected via an every() check before the mean/variance computation.","triggerScenarios":"The operation returns mixed types — a number on success but a string or undefined on a parse failure or missing field; a model call that occasionally yields NaN after Number('N/A'); a division-by-zero branch leaking Infinity into one sample.","commonSituations":"Applying 'mean' to LLM/model outputs without normalizing them to numbers first; aggregation configs copied from a majority-vote use case; samples drawn from heterogeneous optional fields.","solutions":["Normalize inside the operation: coerce with Number(x) and check Number.isFinite, or throw your own domain error instead of letting a non-number flow through","Filter or replace failed samples (e.g. resolve to a sentinel you drop) before they reach the aggregator","Switch aggregator to 'majority' when outputs are not strictly numeric","Add a unit test asserting the operation always returns finite numbers"],"exampleFix":"// before\nawait selfConsistency(() => model.sample(), { N: 5, aggregator: 'mean' });\n// after\nawait selfConsistency(async () => {\n  const out = await model.sample();\n  const n = Number(out.score);\n  if (!Number.isFinite(n)) throw new RangeError('sample is not a finite number');\n  return n;\n}, { N: 5, aggregator: 'mean' });","handlingStrategy":"type-guard","validationCode":"// make the operation itself safe so every sample is a finite number\nconst safeOp = async () => {\n  const out = await operation();\n  const n = Number(out);\n  if (!Number.isFinite(n)) throw new RangeError('sample is not a finite number');\n  return n;\n};\nawait selfConsistency(safeOp, { N: 5, aggregator: 'mean' });","typeGuard":"function isFiniteNumber(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v);\n}","tryCatchPattern":"try {\n  await selfConsistency(op, { N, aggregator: 'mean' });\n} catch (e) {\n  if (String(e).includes(\"aggregator='mean'\")) {\n    // fall back to majority vote over the same samples\n    await selfConsistency(op, { N, aggregator: 'majority' });\n  } else {\n    throw e;\n  }\n}","preventionTips":["Use 'mean' only when the operation is contractually numeric","Coerce and check Number.isFinite inside the operation","Filter failed samples out before aggregation","Add a type test asserting the operation returns finite numbers"],"tags":["aggregation","type-safety","nan"],"backgroundTag":"type-mismatch","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}