{"record":{"id":"1499822b46354a70","repo":"Yeachan-Heo/oh-my-codex","slug":"final-quality-gate-is-missing-architectureinvarian","errorCode":null,"errorMessage":"Final quality gate is missing architectureInvariantGate evidence; include derived architecture/domain invariants, source artifacts, implementation/test/review evidence, or record final blockers for unproved invariants.","messagePattern":"Final quality gate is missing architectureInvariantGate evidence; include derived architecture/domain invariants, source artifacts, implementation/test/review evidence, or record final blockers for unproved invariants\\.","errorType":"validation","errorClass":"UltragoalError","httpStatus":null,"severity":"error","filePath":"src/ultragoal/artifacts.ts","lineNumber":1634,"sourceCode":"    ].filter((value): value is string => typeof value === 'string' && value.trim().length > 0);\n    for (const text of texts) {\n      invariants.push(...extractArchitectureInvariantsFromArtifact(text, `${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER}`, sourcePrefix));\n    }\n  }\n  return uniqueRequiredArchitectureInvariants(invariants);\n}\n\nasync function collectRequiredArchitectureInvariants(cwd: string): Promise<RequiredArchitectureInvariant[]> {\n  const briefInvariants = extractArchitectureInvariantsFromBrief(await readFile(ultragoalBriefPath(cwd), 'utf-8'));\n  const steeringInvariants = extractArchitectureInvariantsFromAcceptedSteering(await readSteeringLedgerEntries(cwd));\n  return uniqueRequiredArchitectureInvariants([...briefInvariants, ...steeringInvariants]);\n}\n\n\nfunction validateArchitectureInvariantGate(gate: Partial<UltragoalQualityGate>, requiredInvariants: readonly RequiredArchitectureInvariant[]): void {\n  const invariantGate = gate.architectureInvariantGate;\n  if (!invariantGate || typeof invariantGate !== 'object') {\n    throw new UltragoalError('Final quality gate is missing architectureInvariantGate evidence; include derived architecture/domain invariants, source artifacts, implementation/test/review evidence, or record final blockers for unproved invariants.');\n  }\n  if (invariantGate.status !== 'passed') {\n    throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.status=\"passed\"; record blocker-resolution work for unproved invariants.');\n  }\n  if (!Array.isArray(invariantGate.sourceArtifacts)) {\n    throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.sourceArtifacts.');\n  }\n  const sourceArtifacts = invariantGate.sourceArtifacts.map((source) => assertNonEmpty(source, 'architectureInvariantGate.sourceArtifacts[]'));\n  for (const required of requiredInvariants) {\n    if (!sourceArtifacts.some((source) => sourceReferencesArtifact(source, required.sourceArtifact))) {\n      throw new UltragoalError(`Final architecture-invariant gate sourceArtifacts must include required invariant source artifact: ${required.sourceArtifact}`);\n    }\n  }\n  assertNonEmpty(invariantGate.evidence, 'architectureInvariantGate.evidence');\n  if (!Array.isArray(invariantGate.invariants)) {\n    throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.invariants.');\n  }\n  const provided = new Map<string, UltragoalArchitectureInvariantEvidence[]>();","sourceCodeStart":1616,"sourceCodeEnd":1652,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/ultragoal/artifacts.ts#L1616-L1652","documentation":"The final quality gate validation found no architectureInvariantGate object. Finalizing a plan requires explicit architecture-invariant evidence: derived invariants, source artifacts, implementation/test/review evidence, or recorded blockers.","triggerScenarios":"Calling finalize with a gate object that omits architectureInvariantGate entirely or sets it to a non-object (null, string, array) — e.g. building a minimal gate with only tests/review evidence.","commonSituations":"Older integrations written before the architecture-invariant gate existed; minimal/hand-rolled gate payloads; spreading partial gate objects where the field is optional in the author's local type but required at runtime.","solutions":["Add an architectureInvariantGate object to the gate with status, sourceArtifacts, evidence, and invariants","Populate invariants from the plan's required architecture/domain invariants and cite the source artifacts","If invariants cannot be proved, record final blockers per the guidance instead of omitting the gate","Update stale gate-building code from earlier tool versions"],"exampleFix":"// before\ngate = { tests: { status: 'passed', evidence: '...' } }; // no architectureInvariantGate\n\n// after\ngate = {\n  tests: { status: 'passed', evidence: '...' },\n  architectureInvariantGate: {\n    status: 'passed',\n    sourceArtifacts: ['docs/architecture/invariants.md'],\n    evidence: 'invariants verified in review + tests',\n    invariants: [],\n  },\n};","handlingStrategy":"type-guard","validationCode":"const gate = buildGate();\nif (!gate.architectureInvariantGate || typeof gate.architectureInvariantGate !== 'object') throw new Error('add architectureInvariantGate before finalize');","typeGuard":"function hasInvariantGate(gate: Partial<UltragoalQualityGate>): gate is UltragoalQualityGate { return !!gate.architectureInvariantGate && typeof gate.architectureInvariantGate === 'object'; }","tryCatchPattern":"try { await finalize(cwd, { gate }); } catch (e) { if (e instanceof UltragoalError && e.message.includes('architectureInvariantGate evidence')) { /* build and attach invariant gate, retry */ } else throw e; }","preventionTips":["Type gate payloads as UltragoalQualityGate so missing fields fail at compile time","Keep a gate-builder helper that always emits all required sections","Record blockers explicitly rather than omitting the gate when invariants are unproved"],"tags":["ultragoal","quality-gate","finalize","missing-evidence"],"backgroundTag":"missing-required-evidence","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}