{"record":{"id":"6d1809b5eec94fc2","repo":"Yeachan-Heo/oh-my-codex","slug":"sandbox-md-frontmatter-evaluator-keep-policy-must-6d1809","errorCode":null,"errorMessage":"sandbox.md frontmatter evaluator.keep_policy must be one of: score_improvement, pass_only.","messagePattern":"sandbox\\.md frontmatter evaluator\\.keep_policy must be one of: score_improvement, pass_only\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/autoresearch/contracts.ts","lineNumber":144,"sourceCode":"    }\n\n    result[key] = value;\n    currentSection = null;\n  }\n\n  return result;\n}\n\nfunction parseKeepPolicy(raw: unknown): AutoresearchKeepPolicy | undefined {\n  if (raw === undefined) return undefined;\n  if (typeof raw !== 'string') {\n    throw contractError('sandbox.md frontmatter evaluator.keep_policy must be a string when provided.');\n  }\n  const normalized = raw.trim().toLowerCase();\n  if (!normalized) return undefined;\n  if (normalized === 'pass_only') return 'pass_only';\n  if (normalized === 'score_improvement') return 'score_improvement';\n  throw contractError('sandbox.md frontmatter evaluator.keep_policy must be one of: score_improvement, pass_only.');\n}\n\nexport function parseSandboxContract(content: string): ParsedSandboxContract {\n  const { frontmatter, body } = extractFrontmatter(content);\n  const parsedFrontmatter = parseSimpleYamlFrontmatter(frontmatter);\n  const evaluatorRaw = parsedFrontmatter.evaluator;\n\n  if (!evaluatorRaw || typeof evaluatorRaw !== 'object' || Array.isArray(evaluatorRaw)) {\n    throw contractError(EVALUATOR_BLOCK_ERROR);\n  }\n\n  const evaluator = evaluatorRaw as { command?: unknown; format?: unknown; keep_policy?: unknown };\n  const command = typeof evaluator.command === 'string'\n    ? evaluator.command.trim()\n    : '';\n  const format = typeof evaluator.format === 'string'\n    ? evaluator.format.trim().toLowerCase()\n    : '';","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/contracts.ts#L126-L162","documentation":"parseKeepPolicy throws when evaluator.keep_policy is a non-empty string but not one of the two supported values after trimming/lowercasing: 'pass_only' or 'score_improvement'. The v1 contract only defines these two retention policies.","triggerScenarios":"Frontmatter with 'keep_policy: always', 'keep_policy: none', or a typo like 'pass-only' or 'passonly' — normalized string matches neither accepted constant.","commonSituations":"Typos in policy names; using kebab-case instead of snake_case; guessing policy names from other tools ('retain', 'keep-all').","solutions":["Use exactly 'keep_policy: score_improvement' or 'keep_policy: pass_only' (snake_case, case-insensitive).","Delete the key to fall back to the default behavior.","Double-check for hyphens vs underscores and stray characters."],"exampleFix":"# before\nevaluator:\n  keep_policy: pass-only\n\n# after\nevaluator:\n  keep_policy: pass_only","handlingStrategy":"validation","validationCode":"const VALID_KEEP_POLICIES = new Set(['pass_only', 'score_improvement']);\n\nfunction keepPolicyIsValid(raw: unknown): boolean {\n  return raw === undefined || (typeof raw === 'string' && (raw.trim() === '' || VALID_KEEP_POLICIES.has(raw.trim().toLowerCase())));\n}","typeGuard":"const isKeepPolicy = (v: unknown): v is 'pass_only' | 'score_improvement' =>\n  v === 'pass_only' || v === 'score_improvement';","tryCatchPattern":"try {\n  parseSandboxContract(content);\n} catch (err) {\n  if ((err as Error).message.includes('keep_policy must be one of')) {\n    // correct to pass_only or score_improvement (snake_case)\n  }\n  throw err;\n}","preventionTips":["Use only pass_only or score_improvement.","Prefer snake_case; avoid hyphens.","Omit the key when unsure to use the default."],"tags":["yaml","frontmatter","keep-policy","enum-validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}