{"record":{"id":"0826dcbc545992ef","repo":"affaan-m/ECC","slug":"canonical-session-snapshot-requires-workers-inde-0826dc","errorCode":null,"errorMessage":"Canonical session snapshot requires workers[${index}].outputs to be an object","messagePattern":"Canonical session snapshot requires workers\\[(.+?)\\]\\.outputs to be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/session-adapters/canonical-session.js","lineNumber":223,"sourceCode":"\n    if (!isObject(worker.runtime)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}].runtime to be an object`);\n    }\n\n    ensureString(worker.runtime.kind, `workers[${index}].runtime.kind`);\n    ensureOptionalString(worker.runtime.command, `workers[${index}].runtime.command`);\n    ensureBoolean(worker.runtime.active, `workers[${index}].runtime.active`);\n    ensureBoolean(worker.runtime.dead, `workers[${index}].runtime.dead`);\n\n    if (!isObject(worker.intent)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}].intent to be an object`);\n    }\n\n    ensureStringAllowEmpty(worker.intent.objective, `workers[${index}].intent.objective`);\n    ensureArrayOfStrings(worker.intent.seedPaths, `workers[${index}].intent.seedPaths`);\n\n    if (!isObject(worker.outputs)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}].outputs to be an object`);\n    }\n\n    ensureArrayOfStrings(worker.outputs.summary, `workers[${index}].outputs.summary`);\n    ensureArrayOfStrings(worker.outputs.validation, `workers[${index}].outputs.validation`);\n    ensureArrayOfStrings(worker.outputs.remainingRisks, `workers[${index}].outputs.remainingRisks`);\n\n    if (!isObject(worker.artifacts)) {\n      throw new Error(`Canonical session snapshot requires workers[${index}].artifacts to be an object`);\n    }\n  });\n\n  if (!isObject(snapshot.aggregates)) {\n    throw new Error('Canonical session snapshot requires aggregates to be an object');\n  }\n\n  ensureInteger(snapshot.aggregates.workerCount, 'aggregates.workerCount');\n  if (snapshot.aggregates.workerCount !== snapshot.workers.length) {\n    throw new Error('Canonical session snapshot requires aggregates.workerCount to match workers.length');","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/session-adapters/canonical-session.js#L205-L241","documentation":"validateCanonicalSnapshot throws this when a worker has no outputs object. The canonical schema requires workers[i].outputs to contain summary, validation, and remainingRisks, each an array of strings, describing what the worker produced. Without it, consumers reading progress summaries would need null checks everywhere.","triggerScenarios":"Persisting or normalizing a snapshot whose worker omits outputs, sets it to null, or assigns a non-object such as an array or string.","commonSituations":"Workers created mid-session before any output was recorded but persisted without the empty scaffold; snapshots imported from older formats; hand-written test fixtures missing the outputs block.","solutions":["Add an outputs object with summary: [], validation: [], remainingRisks: [] (empty arrays are valid) to the worker.","Ensure the worker lifecycle code initializes outputs at creation time rather than lazily.","Regenerate the snapshot via the current normalize*Session adapters.","Validate snapshots in CI with validateCanonicalSnapshot to catch missing outputs blocks."],"exampleFix":"// before\nworker.outputs = null;\n// after\nworker.outputs = { summary: [], validation: [], remainingRisks: [] };","handlingStrategy":"validation","validationCode":"const outputsOk = snapshot.workers.every(w => w && w.outputs && typeof w.outputs === 'object' && Array.isArray(w.outputs.summary) && Array.isArray(w.outputs.validation) && Array.isArray(w.outputs.remainingRisks));\nif (!outputsOk) throw new Error('every worker needs outputs { summary, validation, remainingRisks } arrays');","typeGuard":"function hasOutputs(w) { return !!w && typeof w.outputs === 'object' && w.outputs !== null && Array.isArray(w.outputs.summary); }","tryCatchPattern":"try { persistCanonicalSnapshot(snapshot); } catch (err) { if (String(err.message).includes('.outputs to be an object')) { console.error('Worker missing outputs block:', err.message); /* scaffold empty outputs and retry */ } else { throw err; } }","preventionTips":["Initialize outputs as { summary: [], validation: [], remainingRisks: [] } when a worker is created.","Never assign null to outputs; push into the arrays instead.","Rebuild snapshots via current adapters rather than patching old persisted JSON.","Add snapshot-shape assertions to CI tests."],"tags":["schema-validation","session-snapshot"],"backgroundTag":"schema-validation-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}