{"record":{"id":"e4eee8f2aaf7744f","repo":"santifer/career-ops","slug":"malformed-states-file-at-statespath-expected-a","errorCode":null,"errorMessage":"Malformed states file at ${statesPath}: expected a top-level \"states\" list","messagePattern":"Malformed states file at (.+?): expected a top-level \"states\" list","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"tracker-sync-check.mjs","lineNumber":113,"sourceCode":"// against every other status) instead of correctly ranking it as terminal.\n//\n// states.yml has no explicit ordering field, so LIFECYCLE_ORDER is taken from\n// the file's own array order among states NOT marked `terminal: true`; the\n// terminal set and the id -> display-label map are read directly off each\n// state's `terminal` and `label` fields. See the comment above `states:` in\n// templates/states.yml for the contract.\nconst STATES_FILE = join(CAREER_OPS, 'templates/states.yml');\n\n/**\n * Load the canonical lifecycle order, terminal-status set, and id -> label\n * map from templates/states.yml.\n * @param {string} statesPath - Path to templates/states.yml.\n * @returns {{ order: string[], terminal: Set<string>, labels: Record<string,string> }}\n */\nexport function loadLifecycle(statesPath) {\n  const doc = yaml.load(readFileSync(statesPath, 'utf-8'));\n  if (!doc || !Array.isArray(doc.states)) {\n    throw new Error(`Malformed states file at ${statesPath}: expected a top-level \"states\" list`);\n  }\n  const order = [];\n  const terminal = new Set();\n  const labels = {};\n  for (const s of doc.states) {\n    const id = String(s?.id ?? '').trim();\n    if (!id) continue;\n    labels[id] = String(s.label ?? id);\n    if (s.terminal) terminal.add(id);\n    else order.push(id);\n  }\n  return { order, terminal, labels };\n}\n\nconst { order: LIFECYCLE_ORDER, terminal: TERMINAL_STATUSES, labels: CANONICAL_LABELS } = loadLifecycle(STATES_FILE);\n\n// Mirrors the ALIASES map in analyze-patterns.mjs / verify-pipeline.mjs —\n// applications.md status cell normalization (bold markers, trailing dates,","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/tracker-sync-check.mjs#L95-L131","documentation":"loadLifecycle() in tracker-sync-check.mjs reads templates/states.yml (the canonical source for tracker states and lifecycle order), parses it with the yaml library, and expects a top-level `states` array. If the document is null, not an object, or lacks an array `states` key, it throws an Error identifying the file. This is a config-integrity guard.","triggerScenarios":"templates/states.yml is empty, contains valid YAML that is not an object (e.g. a bare scalar or list), or has a different top-level key (e.g. `statuses` instead of `states`). Hand-editing the file and breaking its structure triggers this.","commonSituations":"A user hand-edits states.yml and accidentally changes the top-level key or truncates the file; a merge conflict left unresolved or resolved incorrectly; a tool rewrote the YAML with a different schema.","solutions":["Restore states.yml from the repo: git checkout HEAD -- templates/states.yml.","Re-run node update-system.mjs apply to restore system files.","Validate the YAML: ensure it has `states:` as a top-level key whose value is a list of objects with id/label/terminal fields.","Run node verify-pipeline.mjs after restoring to confirm integrity."],"exampleFix":"# before (broken states.yml)\nstatuses:\n  - id: applied\n\n# after (correct schema)\nstates:\n  - id: Applied\n    label: Applied\n    terminal: false","handlingStrategy":"validation","validationCode":"function validateStatesYml(statesPath) {\n  const doc = yaml.load(readFileSync(statesPath, 'utf-8'));\n  if (!doc || !Array.isArray(doc.states)) {\n    throw new Error(`states.yml at ${statesPath} is missing a top-level 'states' list`);\n  }\n  return doc;\n}\nvalidateStatesYml(STATES_FILE);","typeGuard":null,"tryCatchPattern":"try {\n  const lifecycle = loadLifecycle(STATES_FILE);\n} catch (err) {\n  if (err.message.includes('Malformed states file')) {\n    console.error(`${err.message}\\nRestore: git checkout HEAD -- templates/states.yml`);\n    process.exit(1);\n  }\n  throw err;\n}","preventionTips":["Never hand-edit templates/states.yml — it is a system file.","Add node verify-pipeline.mjs to CI/pre-commit to catch states.yml corruption early.","Run node update-system.mjs apply after updates."],"tags":["config","states-yml","tracker","yaml","config-integrity"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}