{"record":{"id":"7761cdbfc24f33e4","repo":"Yeachan-Heo/oh-my-codex","slug":"autoresearch-goal-mission-slug-is-already-compl","errorCode":null,"errorMessage":"Autoresearch goal ${mission.slug} is already complete; create a new goal or explicitly reopen via a future workflow before recording more verdicts.","messagePattern":"Autoresearch goal (.+?) is already complete; create a new goal or explicitly reopen via a future workflow before recording more verdicts\\.","errorType":"validation","errorClass":"AutoresearchGoalError","httpStatus":null,"severity":"error","filePath":"src/autoresearch/goal.ts","lineNumber":201,"sourceCode":"    throw new AutoresearchGoalError(`Invalid autoresearch-goal mission at ${repoRelative(cwd, path)}.`);\n  }\n  return parsed;\n}\n\nexport async function readAutoresearchGoalCompletion(cwd: string, slug: string): Promise<AutoresearchGoalCompletion | null> {\n  const path = autoresearchGoalCompletionPath(cwd, slugifyMissionName(slug));\n  if (!existsSync(path)) return null;\n  const parsed = JSON.parse(await readFile(path, 'utf-8')) as AutoresearchGoalCompletion;\n  return parsed;\n}\n\nexport async function recordAutoresearchGoalVerdict(\n  cwd: string,\n  options: RecordAutoresearchGoalVerdictOptions,\n): Promise<{ mission: AutoresearchGoalMission; completion: AutoresearchGoalCompletion }> {\n  const mission = await readAutoresearchGoal(cwd, options.slug);\n  if (mission.status === 'complete') {\n    throw new AutoresearchGoalError(`Autoresearch goal ${mission.slug} is already complete; create a new goal or explicitly reopen via a future workflow before recording more verdicts.`);\n  }\n  const evidence = requireText(options.evidence, '--evidence');\n  const now = iso(options.now);\n  const completion: AutoresearchGoalCompletion = {\n    schema_version: 1,\n    slug: mission.slug,\n    verdict: options.verdict,\n    passed: options.verdict === 'pass',\n    summary: options.summary?.trim() || evidence,\n    evidence,\n    ...(options.artifactPath?.trim() ? { artifact_path: options.artifactPath.trim() } : {}),\n    ...(mission.critic_command ? { critic_command: mission.critic_command } : {}),\n    recorded_at: now,\n  };\n\n  mission.status = options.verdict === 'pass' ? 'passed' : options.verdict === 'fail' ? 'failed' : 'blocked';\n  mission.updated_at = now;\n  await writeMission(cwd, mission);","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/goal.ts#L183-L219","documentation":"recordAutoresearchGoalVerdict refuses to record new verdicts once the mission's status is 'complete'. This is a terminal-state guard: a completed goal is immutable by design, and further verdicts require a new goal or an explicit future reopen workflow.","triggerScenarios":"Calling recordAutoresearchGoalVerdict(cwd, { slug, ... }) for a mission whose JSON has status === 'complete' — typically after completeAutoresearchGoal already succeeded or the status was set manually.","commonSituations":"Pipelines that keep iterating after a goal completes, re-running an automation step that records verdicts, or scripts that do not check mission status before recording.","solutions":["Check mission.status before recording and branch your automation to stop or start a new goal","Create a new autoresearch goal with `omx autoresearch-goal create` if more verdicts are genuinely needed","If the completion was premature, manually revert status in the mission file only if no supported reopen workflow exists and you accept the risk","Make your recording step idempotent by first reading the mission and skipping when complete"],"exampleFix":"// before\nawait recordAutoresearchGoalVerdict(repoRoot, { slug, evidence }); // throws if status === 'complete'\n// after\nconst mission = await readAutoresearchGoal(repoRoot, slug);\nif (mission.status !== 'complete') {\n  await recordAutoresearchGoalVerdict(repoRoot, { slug, evidence });\n}","handlingStrategy":"validation","validationCode":"const mission = await readAutoresearchGoal(cwd, slug);\nif (mission.status === 'complete') {\n  console.log('goal already complete; skipping verdict recording');\n  process.exit(0);\n}","typeGuard":"function isMissionComplete(m: { status?: string }): boolean {\n  return m.status === 'complete';\n}","tryCatchPattern":"try {\n  await recordAutoresearchGoalVerdict(cwd, options);\n} catch (e) {\n  if (e instanceof AutoresearchGoalError && e.message.includes('already complete')) return; // idempotent skip\n  throw e;\n}","preventionTips":["Read mission status before recording verdicts and branch automation accordingly","Start a new goal when further work is needed after completion","Make CI verdict steps idempotent by treating 'already complete' as success"],"tags":["autoresearch","terminal-state","workflow-state","idempotency"],"backgroundTag":"invalid-state-transition","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}