{"record":{"id":"3d505bacb47d77d2","repo":"santifer/career-ops","slug":"cv-section-order-diverges-from-cv-md-rendered-r","errorCode":null,"errorMessage":"CV section order diverges from cv.md: rendered ${renderedOrder}; cv.md ${sourceOrder}","messagePattern":"CV section order diverges from cv\\.md: rendered (.+?); cv\\.md (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"generate-pdf.mjs","lineNumber":491,"sourceCode":"  // CV tailored per modes/pdf.md's documented order looks like. Only treat it\n  // as a real problem if it ALSO fails to match that canonical order.\n  const canonicalComparable = rendered.filter(section => CANONICAL_TAILORED_POSITIONS.has(section.key));\n  if (canonicalComparable.length >= 2\n      && findOrderDivergence(canonicalComparable, CANONICAL_TAILORED_POSITIONS) === -1) {\n    return;\n  }\n\n  const renderedOrder = renderedComparable.map(section => section.title).join(' -> ');\n  const sourceOrder = source\n    .filter(section => renderedComparable.some(renderedSection => renderedSection.key === section.key))\n    .map(section => section.title)\n    .join(' -> ');\n  const message = `CV section order diverges from cv.md: rendered ${renderedOrder}; cv.md ${sourceOrder}`;\n  if (allowReorder) {\n    console.warn(`⚠️  ${message} (proceeding — --allow-reorder set)`);\n    return;\n  }\n  throw new Error(message);\n}\n\n/**\n * Every canonical section key the alias table can produce, in template order.\n * Derived from the table rather than restated so the two cannot drift.\n */\nexport const CV_SECTION_KEYS = [...new Set(SECTION_ALIASES.values())];\n\n// The all-caps comments the templates use to delimit sections, matched exactly\n// as cv-sections-core.mjs matches them when stripping empty sections.\nconst SECTION_MARKER_RE = /<!--\\s+[A-Z][A-Z ]*-->/g;\nconst SECTION_TITLE_RE = /class=[\"'][^\"']*\\bsection-title\\b[^\"']*[\"'][^>]*>([\\s\\S]*?)<\\/[^>]+>/gi;\n\nconst DISPLAY_TITLE_MAX = 60;\n\n/**\n * A rendered section title, made safe to quote back in a console warning.\n *","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/generate-pdf.mjs#L473-L509","documentation":"validateCvSectionOrder compares the section order of the rendered CV HTML against the heading order declared in cv.md (and, as a second chance, the canonical tailored order). If the rendered relative order matches neither, it throws — unless --allow-reorder was set, which downgrades the throw to a warning. It guards against an agent accidentally scrambling CV sections during tailoring.","triggerScenarios":"Rendering a tailored CV whose sections were reordered in a way that breaks both cv.md's order and the canonical tailored order (summary, competencies, experience, projects, education, certifications, awards, interests, skills) without passing --allow-reorder; or editing the HTML template/reorder step so sections come out shuffled.","commonSituations":"An agent hand-tailors a CV moving e.g. Awards before Experience in an order that matches neither reference; a custom template emits sections in a new order; a deliberate reorder done by the user without knowing the --allow-reorder escape hatch exists.","solutions":["Re-order the CV sections to match cv.md's heading order (or the canonical tailored order), then regenerate","If the reorder is deliberate (e.g. Projects before Education for a technical role), re-run with --allow-reorder (or set allowReorder in the config/profile flow) to downgrade to a warning","Check cv.md's heading order matches what you intend — the source of truth may itself be stale","Inspect the rendered HTML section-title order against the order printed in the error message","Set cv.sections in config/profile.yml so reorderCvSections applies the intended order before validation"],"exampleFix":"$ node generate-pdf.mjs --in cv.html --out cv.pdf\nError: CV section order diverges from cv.md: rendered Education -> Projects -> Experience; cv.md Experience -> Projects -> Education\n\n# before\n$ node generate-pdf.mjs --in cv.html --out cv.pdf\n# after (deliberate reorder)\n$ node generate-pdf.mjs --in cv.html --out cv.pdf --allow-reorder","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nconst cv = readFileSync('cv.md', 'utf-8');\nconst headings = [...cv.matchAll(/^##\\s+(.+)$/gm)].map(m => m[1].trim().toLowerCase());\nconst allowedOrders = [\n  ['summary','competencies','experience','projects','education','certifications','awards','interests','skills'],\n];\n// verify the rendered section order matches cv.md headings or the canonical tailored order before generating","typeGuard":"const orderMatches = (renderedKeys, referenceKeys) =>\n  renderedKeys.length >= 2 &&\n  renderedKeys.every((k, i) => i === 0 || referenceKeys.indexOf(k) > referenceKeys.indexOf(renderedKeys[i - 1]));","tryCatchPattern":"try {\n  validateCvSectionOrder(html, cvMarkdown);\n} catch (err) {\n  if (err.message.startsWith('CV section order diverges')) {\n    console.warn(err.message, '— pass --allow-reorder if this reorder is deliberate');\n    return; // or rethrow in CI\n  }\n  throw err;\n}","preventionTips":["Keep cv.md heading order as the source of truth and derive tailored CVs from it","For deliberate reorders (Projects before Education), always pass --allow-reorder","Set cv.sections in config/profile.yml so reorderCvSections applies the intended order before validation","Diff rendered section titles against cv.md headings when hand-tailoring a CV"],"tags":["validation","cv","ordering"],"backgroundTag":"schema-validation-failed","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}