{"record":{"id":"e37c3ba15bbd68ce","repo":"ruvnet/ruflo","slug":"metric-must-be-finite","errorCode":null,"errorMessage":"metric must be finite","messagePattern":"metric must be finite","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/flywheel-receipt.ts","lineNumber":207,"sourceCode":"}\n\nexport function policyCandidateId(policy: Record<string, unknown>): string {\n  return sha256Ref(canonicalizeJcs(policy));\n}\n\n/** UUIDv7 with a 48-bit millisecond timestamp and RFC-4122 variant bits. */\nexport function uuidV7(now = Date.now()): string {\n  const bytes = randomBytes(16);\n  const timestamp = BigInt(now);\n  for (let i = 5; i >= 0; i--) bytes[5 - i] = Number((timestamp >> BigInt(i * 8)) & 0xffn);\n  bytes[6] = (bytes[6] & 0x0f) | 0x70;\n  bytes[8] = (bytes[8] & 0x3f) | 0x80;\n  const hex = bytes.toString('hex');\n  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nconst decimal = (value: number, scale = 12): string => {\n  if (!Number.isFinite(value)) throw new Error('metric must be finite');\n  const normalized = value.toFixed(scale).replace(/\\.?0+$/, '');\n  return normalized === '-0' || normalized === '' ? '0' : normalized;\n};\n\nfunction seedFrom(parts: string[]): { seed: number; hex: string } {\n  const digest = createHash('sha256').update(parts.join('')).digest();\n  return { seed: digest.readUInt32BE(0), hex: digest.toString('hex') };\n}\n\n/**\n * Deterministic three-way quickselect. Bootstrap promotion needs one quantile,\n * not a fully sorted distribution; selecting it in expected O(n) removes the\n * O(n log n) sort from every evaluation. Three-way partitioning also keeps the\n * common all-equal bootstrap case linear.\n */\nfunction selectKth(values: number[], k: number): number {\n  let left = 0;\n  let right = values.length - 1;","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/services/flywheel-receipt.ts#L189-L225","documentation":"Thrown by the internal decimal() formatter when Number.isFinite(value) is false. decimal() converts numeric metrics (baselineScore, candidateScore, heldOutDeltas entries, lift, probabilities) into fixed-scale canonical strings for the receipt payload. NaN or Infinity cannot be represented as finite decimals and would corrupt the promotion statistics.","triggerScenarios":"Calling createFlywheelReceipt() or computePromotionStatistics() where baselineScore, candidateScore, or any element of heldOutDeltas is NaN, Infinity, or -Infinity. Also reachable if a division elsewhere produced NaN and it propagated into a score.","commonSituations":"Score pipeline divides by zero yielding Infinity; a missing metric defaulted to NaN; heldOutDeltas computed from malformed paired outcomes; log/softmax underflow producing NaN.","solutions":["Validate all scores with Number.isFinite() before receipt creation.","Guard upstream divisions with Math.max(Math.abs(denom), epsilon) (the code already does this for relativeLift).","Reject or default non-finite deltas at the evaluation boundary.","Add unit tests asserting finite-only score arrays."],"exampleFix":"// before\ncreateFlywheelReceipt({ baselineScore: 0.42, candidateScore: NaN, heldOutDeltas: [...], /* ... */ });\n// after\nif (!Number.isFinite(candidateScore)) throw new Error('candidate score not finite');\ncreateFlywheelReceipt({ baselineScore: 0.42, candidateScore, heldOutDeltas: [...], /* ... */ });","handlingStrategy":"validation","validationCode":"function assertAllFinite(scores: number[], label: string): void {\n  for (let i = 0; i < scores.length; i++) {\n    if (!Number.isFinite(scores[i])) {\n      throw new Error(`non-finite ${label}[${i}]: ${scores[i]}`);\n    }\n  }\n}\nassertAllFinite([baselineScore, candidateScore, ...heldOutDeltas], 'score');","typeGuard":"const isFiniteNumber = (x: unknown): x is number => typeof x === 'number' && Number.isFinite(x);","tryCatchPattern":"try {\n  createFlywheelReceipt(input);\n} catch (e) {\n  if (e instanceof Error && e.message === 'metric must be finite') {\n    throw new Error('evaluation produced non-finite scores; check upstream math for NaN/Infinity');\n  }\n  throw e;\n}","preventionTips":["Validate every score with Number.isFinite before building the receipt input.","Guard divisions with epsilon floors (the code does this for relativeLift — replicate for your own metrics).","Add property-based tests asserting finite-only score arrays from the evaluation pipeline."],"tags":["validation","statistics","metrics","receipt"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}