{"record":{"id":"1f25699e5b36eb5c","repo":"affaan-m/ECC","slug":"gate-taskset-invalid","errorCode":"gate.taskset_invalid","errorMessage":"taskset needs version, family, and a non-empty tasks array","messagePattern":"taskset needs version, family, and a non-empty tasks array","errorType":"exception","errorClass":"GateError","httpStatus":null,"severity":"error","filePath":"scripts/lib/eval-harness/gate.js","lineNumber":139,"sourceCode":"    throw new GateError('gate.variant_invalid', `variant.json in ${resolved} needs name and a valid effect_class`);\n  }\n  const entry = manifest.entry === undefined ? 'run.js' : manifest.entry;\n  if (typeof entry !== 'string' || !entry || path.isAbsolute(entry) || path.win32.isAbsolute(entry) || entry.includes('\\\\') || entry.split('/').includes('..')) {\n    throw new GateError('gate.variant_invalid', 'entry must be a relative regular file within the variant');\n  }\n  const entryPath = path.resolve(resolved, entry);\n  const relative = path.relative(resolved, entryPath);\n  if (!relative || relative.startsWith('..' + path.sep) || path.isAbsolute(relative) || !listFiles(resolved).includes(relative.split(path.sep).join('/')) || !fs.lstatSync(entryPath).isFile()) {\n    throw new GateError('gate.variant_invalid', 'entry must be covered by the variant digest');\n  }\n  return { dir: resolved, name: manifest.name, effect_class: manifest.effect_class, entry: relative, digest: digestDir(resolved) };\n}\n\nfunction loadTaskset(tasksetPath) {\n  const resolved = path.resolve(tasksetPath);\n  const taskset = JSON.parse(fs.readFileSync(resolved, 'utf8'));\n  if (!taskset || typeof taskset !== 'object' || !taskset.version || !taskset.family || !Array.isArray(taskset.tasks) || taskset.tasks.length === 0) {\n    throw new GateError('gate.taskset_invalid', 'taskset needs version, family, and a non-empty tasks array');\n  }\n  if (new Set(taskset.tasks.map(task => task && task.id)).size !== taskset.tasks.length) throw new GateError('gate.taskset_invalid', 'task ids must be unique');\n  for (const task of taskset.tasks) {\n    if (!task || typeof task !== 'object' || typeof task.id !== 'string' || !task.id || !('input' in task) || !('expected' in task)) {\n      throw new GateError('gate.taskset_invalid', 'every task needs id, input, and expected');\n    }\n  }\n  return { ...taskset, path: resolved, digest: sha256Hex(fs.readFileSync(resolved)) };\n}\n\n/** Scan variant sources for tripwire patterns and effect-class expansion. */\nfunction scanTripwires(variant, options = {}) {\n  const rules = options.tripwires || DEFAULT_TRIPWIRES;\n  const maxRank = envelope.effectRank(options.max_effect_class || 'SE1');\n  const hits = [];\n  if (envelope.effectRank(variant.effect_class) > maxRank) {\n    hits.push({ variant: variant.name, rule: 'effect_class_expansion', file: 'variant.json', line: 1, detail: `${variant.effect_class} exceeds ${options.max_effect_class || 'SE1'}` });\n  }","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/eval-harness/gate.js#L121-L157","documentation":"loadTaskset parses the taskset JSON and requires it to be an object with truthy `version`, `family`, and a non-empty `tasks` array. Missing or malformed top-level structure throws GateError('gate.taskset_invalid') with this message.","triggerScenarios":"JSON file that parses to null/an array/a string; taskset lacking version or family; `tasks` absent, not an array, or an empty array; malformed JSON would throw SyntaxError before this check but structural gaps hit this error.","commonSituations":"Empty `[]` placeholder tasksets; exports missing metadata fields; a file accidentally saved with `{}`; tasksets authored against an older schema where family was named differently; feeding a capsule metadata file to loadTaskset by mistake.","solutions":["Add the required fields: e.g. { \"version\": 1, \"family\": \"my-task-family\", \"tasks\": [ ... ] }.","Populate tasks with at least one task object.","Validate the JSON parses to an object (`node -e \"console.log(typeof require('./taskset.json'))\"`).","Confirm you are loading the actual taskset file, not another JSON artifact."],"exampleFix":"// before (taskset.json)\n{ \"version\": 1, \"tasks\": [] }\n// after\n{ \"version\": 1, \"family\": \"capsule-group\", \"tasks\": [{ \"id\": \"t1\", \"input\": \"x\", \"expected\": \"y\" }] }","handlingStrategy":"validation","validationCode":"function tasksetStructureOk(ts) {\n  return ts != null && typeof ts === 'object' &&\n    Boolean(ts.version) && Boolean(ts.family) &&\n    Array.isArray(ts.tasks) && ts.tasks.length > 0;\n}\nconst ts = JSON.parse(fs.readFileSync(p, 'utf8'));\nif (!tasksetStructureOk(ts)) throw new Error('taskset needs version, family, non-empty tasks');","typeGuard":"function isTaskset(v) {\n  return typeof v === 'object' && v !== null &&\n    'version' in v && 'family' in v && Array.isArray(v.tasks);\n}","tryCatchPattern":"try {\n  const taskset = loadTaskset(p);\n} catch (e) {\n  if (e.code === 'gate.taskset_invalid' && /version, family/.test(e.message)) {\n    console.error('Add version, family, and at least one task to the taskset JSON');\n  } else throw e;\n}","preventionTips":["Use a JSON schema check for {version, family, tasks[]} in CI.","Never commit empty placeholder tasksets.","Confirm you are loading the taskset file, not another JSON artifact.","Include at least one task before registering the taskset."],"tags":["validation","json","eval-harness"],"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"}