{"record":{"id":"2a7e1ab3234988c5","repo":"pbakaus/impeccable","slug":"invalid-impeccable-live-copy-agent-mock-result-jso","errorCode":null,"errorMessage":"Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT JSON","messagePattern":"Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT JSON","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skill/scripts/live-copy-edit-agent.mjs","lineNumber":501,"sourceCode":"    : [];\n  return {\n    status,\n    message: result.message || null,\n    appliedEntryIds,\n    failed,\n    files,\n    notes,\n    warnings,\n  };\n}\n\nfunction mockBatchResult(batch, env, cwd = process.cwd()) {\n  applyMockWrites(env, cwd);\n  const raw = env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT;\n  if (raw) {\n    const parsed = parseCopyEditBatchResult(raw);\n    if (parsed) return parsed;\n    throw new Error('Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT JSON');\n  }\n  return {\n    status: 'done',\n    appliedEntryIds: (batch?.entries || []).map((entry) => entry.id).filter(Boolean),\n    failed: [],\n    files: [],\n    notes: ['mock copy-edit batch result'],\n  };\n}\n\nfunction applyMockWrites(env, cwd) {\n  const raw = env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES;\n  if (!raw) return;\n  const writes = tryParseJson(raw);\n  if (!writes || typeof writes !== 'object' || Array.isArray(writes)) {\n    throw new Error('Invalid IMPECCABLE_LIVE_COPY_AGENT_MOCK_WRITES JSON');\n  }\n  for (const [relativeFile, content] of Object.entries(writes)) {","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/skill/scripts/live-copy-edit-agent.mjs#L483-L519","documentation":"Thrown by mockBatchResult() in skill/scripts/live-copy-edit-agent.mjs when IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT is set but its value does not parse (via parseCopyEditBatchResult) into a valid batch result object. The mock runner is the test/dev path (IMPECCABLE_LIVE_COPY_AGENT=mock); an invalid override breaks the mock contract.","triggerScenarios":"Setting IMPECCABLE_LIVE_COPY_AGENT=mock and IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT to malformed JSON, or to JSON missing the required `status` field (must be 'done' | 'partial' | 'error').","commonSituations":"Hand-editing the mock result env var and breaking the JSON; pasting a partial object; quoting issues in the shell mangling the value.","solutions":["Provide valid JSON with a status field, e.g. {\"status\":\"done\",\"appliedEntryIds\":[],\"failed\":[],\"files\":[],\"notes\":[]}.","Validate the JSON with `echo \"$IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT\" | jq .` before starting the server.","Unset the var to fall back to the default mock result."],"exampleFix":"// before\nexport IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT='{status: done}'\n// after\nexport IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT='{\"status\":\"done\",\"appliedEntryIds\":[],\"failed\":[],\"files\":[],\"notes\":[]}'","handlingStrategy":"try-catch","validationCode":"function parseMockResult(raw) {\n  if (!raw) return null;\n  let obj;\n  try { obj = JSON.parse(raw); } catch { throw new Error('IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT is not valid JSON'); }\n  if (!['done', 'partial', 'error'].includes(obj?.status)) {\n    throw new Error('mock result needs a status of done|partial|error');\n  }\n  return obj;\n}","typeGuard":"function isValidMockResultJson(raw) {\n  if (!raw) return true;\n  try {\n    const o = JSON.parse(raw);\n    return o && ['done', 'partial', 'error'].includes(o.status);\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  JSON.parse(process.env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT);\n} catch (err) {\n  console.error('Fix or unset IMPECCABLE_LIVE_COPY_AGENT_MOCK_RESULT:', err.message);\n  process.exit(1);\n}","preventionTips":["Validate mock env JSON with jq before starting the server.","Keep a known-good mock result committed for tests."],"tags":["live-copy-edit","mock","environment","json"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}