Yeachan-Heo/oh-my-codex · error · UltragoalError

Final code-review must use an independent architect subagent

Error message

Final code-review must use an independent architect subagent; self-review or default/authoring-lane review cannot approve the ultragoal gate.

What it means

During final ultragoal quality-gate validation, the codeReview.independentReview.architect evidence exists but its agentRole is not 'architect'. The gate requires that the final code review be performed by an independent architect subagent; a self-review or a review performed by the default/authoring lane cannot approve the ultragoal gate.

Source

Thrown at src/ultragoal/artifacts.ts:1744

  assertNonEmpty(review.evidence, 'codeReview.evidence');
  const independentReview = (review as Partial<UltragoalQualityGate['codeReview']>).independentReview;
  if (!independentReview || typeof independentReview !== 'object') {
    throw new UltragoalError('Final code-review independent review unavailable: codeReview.independentReview must include completed code-reviewer and architect subagent evidence; use record-review-blockers instead of self-approving.');
  }
  const codeReviewer = independentReview.codeReviewer;
  if (!codeReviewer || typeof codeReviewer !== 'object') {
    throw new UltragoalError('Final code-review independent review unavailable: missing codeReview.independentReview.codeReviewer evidence from the code-reviewer subagent.');
  }
  if (codeReviewer.agentRole !== 'code-reviewer') {
    throw new UltragoalError('Final code-review must use an independent code-reviewer subagent; self-review or default/authoring-lane review cannot approve the ultragoal gate.');
  }
  assertNonEmpty(codeReviewer.evidence, 'codeReview.independentReview.codeReviewer.evidence');
  const architect = independentReview.architect;
  if (!architect || typeof architect !== 'object') {
    throw new UltragoalError('Final code-review independent review unavailable: missing codeReview.independentReview.architect evidence from the architect subagent.');
  }
  if (architect.agentRole !== 'architect') {
    throw new UltragoalError('Final code-review must use an independent architect subagent; self-review or default/authoring-lane review cannot approve the ultragoal gate.');
  }
  assertNonEmpty(architect.evidence, 'codeReview.independentReview.architect.evidence');
  validateArchitectureInvariantGate(gate, requiredInvariants);
  return gate as UltragoalQualityGate;
}

export async function startNextUltragoal(cwd: string, options: StartNextOptions = {}): Promise<{ plan: UltragoalPlan; goal: UltragoalItem | null; resumed: boolean; done: boolean }> {
  return withUltragoalMutationLock(cwd, async () => {
  const plan = await readUltragoalPlanUnderLock(cwd);
  const now = iso(options.now);
  if (plan.aggregateCompletion?.status === 'complete') return { plan, goal: null, resumed: false, done: true };
  const existing = plan.goals.find((goal) => goal.status === 'in_progress' && isScheduleEligibleGoal(goal));
  if (existing) {
    await appendLedger(cwd, { ts: now, event: 'goal_resumed', goalId: existing.id, status: existing.status, message: 'Resuming active ultragoal' });
    return { plan, goal: existing, resumed: true, done: false };
  }

  let next = plan.goals.find((goal) => goal.status === 'pending' && isScheduleEligible(goal));

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Re-run the final code review using an independent architect subagent and set independentReview.architect.agentRole to exactly 'architect' with non-empty evidence
  2. Check the quality-gate JSON producer: ensure it records the architect subagent's role, not the authoring agent's role
  3. Verify codeReviewer evidence and other required gate sections are also non-empty before resubmitting

Example fix

// before
"independentReview": { "codeReviewer": {"agentRole": "general", "evidence": ["..."]}, "architect": {"agentRole": "general", "evidence": ["reviewed diff"]} }
// after
"independentReview": { "codeReviewer": {"agentRole": "code-reviewer", "evidence": ["..."]}, "architect": {"agentRole": "architect", "evidence": ["architect subagent review notes"]} }
Defensive patterns

Strategy: validation

Validate before calling

const ok = gate?.codeReview?.independentReview?.architect?.agentRole === 'architect'
  && (gate.codeReview.independentReview.architect.evidence ?? []).length > 0;
if (!ok) throw new Error('quality gate lacks independent architect review');

Type guard

const isArchitectReview = (g: unknown): g is { agentRole: 'architect'; evidence: string[] } =>
  typeof g === 'object' && g !== null && (g as any).agentRole === 'architect' && Array.isArray((g as any).evidence);

Try / catch

catch (e) { if (e instanceof UltragoalError && /independent architect subagent/.test(e.message)) { rerunReviewWithArchitectSubagent(); } else throw e; }

Prevention

When it happens

Trigger: Calling checkpointUltragoal/completion with --quality-gate-json whose codeReview.independentReview.architect object is present but has agentRole !== 'architect' (e.g. 'default', 'coder', 'authoring-lane', or missing role) while the goal is a final gate candidate under strict mode.

Common situations: Teams wiring up the quality gate JSON by hand or via a script that fills in the reviewing agent's own role; pipelines where the architect subagent wasn't spawned and someone pasted reviewer evidence from the main agent; schema changes to the gate format that renamed agentRole.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/ad5a99af443cbdfa. Report an issue: GitHub.