{"record":{"id":"91fc7310eb540f98","repo":"santifer/career-ops","slug":"reportnum-must-be-a-numeric-report-number","errorCode":null,"errorMessage":"reportNum must be a numeric report number","messagePattern":"reportNum must be a numeric report number","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"application-artifacts.mjs","lineNumber":33,"sourceCode":"import { isMainModule } from './lib/is-main-module.mjs';\n\nconst DEFAULT_OUTPUT_ROOT = resolve('output');\nconst DECISIONS = new Set(['reuse', 'reuse-with-edits', 'regenerate']);\n\n/** Convert a user-facing label into a safe, readable path segment. */\nexport function slugifySegment(value, fallback = 'application') {\n  const slug = String(value ?? '')\n    .trim()\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '');\n  return slug || fallback;\n}\n\n/** Return all stable paths belonging to one application artifact bundle. */\nexport function applicationArtifactPaths({ reportNum, company, role, version = 1, root = DEFAULT_OUTPUT_ROOT }) {\n  if (!/^\\d+$/.test(String(reportNum ?? ''))) {\n    throw new Error('reportNum must be a numeric report number');\n  }\n  if (!/^\\d+$/.test(String(version ?? '')) || Number(version) < 1) {\n    throw new Error('version must be a positive integer');\n  }\n  const key = `${String(reportNum).padStart(3, '0')}-${slugifySegment(company)}-${slugifySegment(role, 'role')}`;\n  const applicationRoot = join(resolve(root), key);\n  const tailoredRoot = join(applicationRoot, 'cv', 'tailored', `v${String(version).padStart(3, '0')}`);\n  return {\n    key,\n    root: applicationRoot,\n    jd: {\n      current: join(applicationRoot, 'jd', 'current.md'),\n      previous: join(applicationRoot, 'jd', 'previous.md'),\n    },\n    cv: {\n      source: {\n        html: join(applicationRoot, 'cv', 'source', 'original.html'),\n        pdf: join(applicationRoot, 'cv', 'source', 'original.pdf'),","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/application-artifacts.mjs#L15-L51","documentation":"applicationArtifactPaths builds a stable directory/file bundle key of the form NNN-company-role and requires reportNum to be a string of digits only (checked with /^\\d+$/). If reportNum is absent, non-numeric, or contains separators like '#' or leading text, it throws. This guarantees predictable, sortable artifact paths under the output root.","triggerScenarios":"Calling applicationArtifactPaths with reportNum: undefined, with a string like '042-a' or '#42', with a number in a form String() renders non-numerically (e.g. NaN), or passing a tracker row label instead of the raw report number.","commonSituations":"Passing values parsed from markdown links like '[042](reports/...)' without stripping the decoration; using tracker row numbers that include prefixes; a variable that failed to populate upstream so undefined flows in.","solutions":["Pass the plain numeric report number: applicationArtifactPaths({ reportNum: 42, company, role }).","Normalize extracted values first, e.g. String(reportNum).replace(/\\D/g, ''), and confirm it is non-empty before calling.","Check upstream parsing that produced reportNum — log it and fix the extraction from the tracker/report filename."],"exampleFix":"// before\nconst paths = applicationArtifactPaths({ reportNum: row.num, company, role }); // row.num = '#42'\n// after\nconst num = String(row.num).replace(/^#/, '');\nif (!/^\\d+$/.test(num)) throw new Error(`bad report number: ${row.num}`);\nconst paths = applicationArtifactPaths({ reportNum: num, company, role });","handlingStrategy":"type-guard","validationCode":"function isNumericReportNum(n) { return /^\\d+$/.test(String(n ?? '')); }\nif (!isNumericReportNum(reportNum)) throw new Error(`reportNum must be numeric, got ${reportNum}`);","typeGuard":"function isReportNum(v) {\n  return (typeof v === 'number' && Number.isInteger(v) && v > 0) || (typeof v === 'string' && /^\\d+$/.test(v));\n}","tryCatchPattern":"try {\n  const paths = applicationArtifactPaths({ reportNum, company, role });\n} catch (err) {\n  if (err.message === 'reportNum must be a numeric report number') {\n    console.error(`Strip decorations from report number: got ${reportNum}`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Extract report numbers with /\\d+/ from tracker links or filenames instead of passing raw decorated strings.","Normalize to a plain integer at ingestion time (parseInt) and store it once.","Add a small helper stripReportNum() and use it everywhere tracker rows feed artifact paths."],"tags":["validation","paths","identifier"],"backgroundTag":"invalid-identifier-format","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"}