{"record":{"id":"c716ba87674ca689","repo":"Yeachan-Heo/oh-my-codex","slug":"evaluator-output-score-must-be-numeric-when-provid","errorCode":null,"errorMessage":"Evaluator output score must be numeric when provided.","messagePattern":"Evaluator output score must be numeric when provided\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/autoresearch/contracts.ts","lineNumber":203,"sourceCode":"\nexport function parseEvaluatorResult(raw: string): AutoresearchEvaluatorResult {\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch {\n    throw contractError('Evaluator output must be valid JSON with required boolean pass and optional numeric score.');\n  }\n\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw contractError('Evaluator output must be a JSON object.');\n  }\n\n  const result = parsed as Record<string, unknown>;\n  if (typeof result.pass !== 'boolean') {\n    throw contractError('Evaluator output must include boolean pass.');\n  }\n  if (result.score !== undefined && typeof result.score !== 'number') {\n    throw contractError('Evaluator output score must be numeric when provided.');\n  }\n\n  return {\n    pass: result.pass,\n    ...(result.score === undefined ? {} : { score: result.score }),\n  };\n}\n\nexport async function loadAutoresearchMissionContract(missionDirArg: string): Promise<AutoresearchMissionContract> {\n  const missionDir = resolve(missionDirArg);\n  if (!existsSync(missionDir)) {\n    throw contractError(`mission-dir does not exist: ${missionDir}`);\n  }\n\n  const repoRoot = readGit(missionDir, ['rev-parse', '--show-toplevel']);\n  ensurePathInside(repoRoot, missionDir);\n\n  const missionFile = join(missionDir, 'mission.md');","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/contracts.ts#L185-L221","documentation":"parseEvaluatorResult throws when the output object includes a 'score' field whose value is not a number. score is optional, but when present it must be numeric so downstream ranking/keep-policy logic can compare it.","triggerScenarios":"Evaluator prints '{\"pass\":true,\"score\":\"0.9\"}' (string), score: null, or score: true — typeof !== 'number' fails the check.","commonSituations":"Scores serialized as strings from shell or CSV-derived pipelines; null used as 'no score' instead of omitting the key; booleans from flag-style scripts.","solutions":["Emit score as a bare JSON number or omit the key entirely.","Use JSON.stringify so numbers stay numbers.","If score is unavailable, leave the field out rather than sending null or ''. "],"exampleFix":"# before\necho '{\"pass\":true,\"score\":\"0.9\"}'\n\n# after\necho '{\"pass\":true,\"score\":0.9}'","handlingStrategy":"type-guard","validationCode":"function outputScoreIsNumericIfPresent(raw: string): boolean {\n  try {\n    const v = JSON.parse(raw) as Record<string, unknown>;\n    return v.score === undefined || typeof v.score === 'number';\n  } catch { return false; }\n}","typeGuard":"const hasNumericScore = (v: Record<string, unknown>): boolean =>\n  v.score === undefined || typeof v.score === 'number';","tryCatchPattern":"try {\n  parseEvaluatorResult(stdout);\n} catch (err) {\n  if ((err as Error).message.includes('score must be numeric')) {\n    // emit score as a JSON number or omit the field\n  }\n  throw err;\n}","preventionTips":["Omit score when not computed; never send null or string scores.","Serialize with JSON.stringify so numbers remain numbers."],"tags":["evaluator","json","type-validation","score"],"backgroundTag":"json-field-type-mismatch","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}