{"record":{"id":"450d651ade47e4b8","repo":"Yeachan-Heo/oh-my-codex","slug":"final-architecture-invariant-gate-requires-archite-450d65","errorCode":null,"errorMessage":"Final architecture-invariant gate requires architectureInvariantGate.sourceArtifacts.","messagePattern":"Final architecture-invariant gate requires architectureInvariantGate\\.sourceArtifacts\\.","errorType":"validation","errorClass":"UltragoalError","httpStatus":null,"severity":"error","filePath":"src/ultragoal/artifacts.ts","lineNumber":1640,"sourceCode":"}\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[]>();\n  for (const invariant of invariantGate.invariants) {\n    if (!invariant || typeof invariant !== 'object') throw new UltragoalError('Final architecture-invariant gate invariants must be objects.');\n    const record = invariant as Partial<UltragoalArchitectureInvariantEvidence> & { blockers?: unknown };\n    const text = assertNonEmpty(record.invariant, 'architectureInvariantGate.invariants[].invariant');\n    const source = assertNonEmpty(record.source, 'architectureInvariantGate.invariants[].source');\n    if (!sourceReferencesAnyArtifact(source, sourceArtifacts)) {","sourceCodeStart":1622,"sourceCodeEnd":1658,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/ultragoal/artifacts.ts#L1622-L1658","documentation":"The architectureInvariantGate is missing the sourceArtifacts array. Validation requires an array (even empty, though entries are then checked individually and required invariants must be referenced) listing the source artifacts the invariants derive from.","triggerScenarios":"Providing architectureInvariantGate with status='passed' and evidence but omitting sourceArtifacts, or setting it to a non-array value (string, object).","commonSituations":"Hand-constructing the gate object and forgetting the field; copying an example that predates the sourceArtifacts requirement; type loosened to any so the omission isn't caught at compile time.","solutions":["Add sourceArtifacts as an array of artifact reference strings (e.g. ['docs/architecture/invariants.md'])","Ensure each entry references the source artifacts required by the plan's required invariants (they are matched via sourceReferencesArtifact)","If unsure which artifacts, read the plan's requiredInvariants and mirror their sourceArtifact values","Type the gate payload as UltragoalQualityGate so TypeScript flags the omission"],"exampleFix":"// before\narchitectureInvariantGate: { status: 'passed', evidence: 'ok', invariants: [] }\n\n// after\narchitectureInvariantGate: { status: 'passed', sourceArtifacts: ['docs/architecture/invariants.md'], evidence: 'ok', invariants: [] }","handlingStrategy":"type-guard","validationCode":"const aig = gate.architectureInvariantGate;\nif (!Array.isArray(aig?.sourceArtifacts)) throw new Error('sourceArtifacts array required');","typeGuard":"function hasSourceArtifacts(g: unknown): g is { sourceArtifacts: string[] } { return Array.isArray((g as any)?.sourceArtifacts); }","tryCatchPattern":null,"preventionTips":["Use the library's own types for gate payloads","Centralize gate construction in one helper that includes all required arrays","Add a schema check (e.g. zod) over the gate before submitting"],"tags":["ultragoal","quality-gate","source-artifacts","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}