{"record":{"id":"9407341276c17fb4","repo":"Yeachan-Heo/oh-my-codex","slug":"cannot-record-final-review-blockers-for-goal-id","errorCode":null,"errorMessage":"Cannot record final review blockers for ${goal.id} while it is ${goal.status}; start or resume the ultragoal first.","messagePattern":"Cannot record final review blockers for (.+?) while it is (.+?); start or resume the ultragoal first\\.","errorType":"exception","errorClass":"UltragoalError","httpStatus":null,"severity":"error","filePath":"src/ultragoal/artifacts.ts","lineNumber":2090,"sourceCode":"      status: goal.status,\n      evidence: options.evidence,\n      codexGoal: options.codexGoal,\n      qualityGate,\n      message: 'Aggregate ultragoal plan completed with a clean final quality gate.',\n    });\n  }\n  return plan;\n  });\n}\n\nexport async function recordFinalReviewBlockers(cwd: string, options: RecordFinalReviewBlockersOptions): Promise<{ plan: UltragoalPlan; blockedGoal: UltragoalItem; addedGoal: UltragoalItem }> {\n  return withUltragoalMutationLock(cwd, async () => {\n  const plan = await readUltragoalPlanUnderLock(cwd);\n  const goal = plan.goals.find((candidate) => candidate.id === options.goalId);\n  if (!goal) throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);\n  assertNonEmpty(options.evidence, '--evidence');\n  if (goal.status !== 'in_progress') {\n    throw new UltragoalError(`Cannot record final review blockers for ${goal.id} while it is ${goal.status}; start or resume the ultragoal first.`);\n  }\n  if (!isFinalRunCompletionCandidate(plan, goal)) {\n    throw new UltragoalError(`Cannot record final review blockers for ${goal.id}; it is not the only unresolved ultragoal story.`);\n  }\n\n  const now = iso(options.now);\n  const expectedObjective = expectedCodexObjective(plan, goal);\n  const aggregateMode = codexGoalMode(plan) === 'aggregate';\n  const reconciliation = reconcileCodexGoalSnapshot(\n    options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal),\n    {\n      expectedObjective,\n      acceptedObjectives: aggregateMode ? compatibleCodexObjectives(plan) : undefined,\n      allowedStatuses: ['active'],\n      requireSnapshot: true,\n      requireComplete: false,\n    },\n  );","sourceCodeStart":2072,"sourceCodeEnd":2108,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/ultragoal/artifacts.ts#L2072-L2108","documentation":"recordFinalReviewBlockers requires the target goal to be in_progress. You cannot record final review blockers for a goal that is pending, complete, failed, or review_blocked — start or resume it first.","triggerScenarios":"Calling recordFinalReviewBlockers when goal.status !== 'in_progress' (e.g. 'pending' never started, or already 'review_blocked').","commonSituations":"Calling the blocker-recording step before the start checkpoint; double-invoking the same blocker recording; retrying after the goal transitioned away.","solutions":["Record an in_progress checkpoint for the goal first, then call recordFinalReviewBlockers","Guard against duplicate invocations in your orchestration","If the goal is already review_blocked, no further blocker recording is needed for it"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (goal.status !== 'in_progress') await checkpointUltragoal(cwd, { goalId, status: 'in_progress', evidence: 'start' });","typeGuard":"const isInProgress = (goal: UltragoalItem) => goal.status === 'in_progress';","tryCatchPattern":null,"preventionTips":["Start the goal before recording blockers","Idempotency-check before re-invoking blocker recording"],"tags":["ultragoal","review-blockers","state-machine"],"backgroundTag":"invalid-state-transition","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}