{"record":{"id":"4ac15f43d6f9f2aa","repo":"affaan-m/ECC","slug":"invalid-now-timestamp-now","errorCode":null,"errorMessage":"Invalid now timestamp: ${now}","messagePattern":"Invalid now timestamp: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/skill-evolution/dashboard.js","lineNumber":335,"sourceCode":"      for (const version of skill.versions) {\n        const date = version.created_at ? version.created_at.slice(0, 10) : '-';\n        const reason = version.reason || '-';\n        lines.push(`  v${version.version} \\u2500\\u2500 ${date} \\u2500\\u2500 ${reason}`);\n      }\n    }\n  }\n\n  return {\n    text: panelBox('Version History', lines, width),\n    data: { skills: skillVersions },\n  };\n}\n\nfunction renderDashboard(options = {}) {\n  const now = options.now || new Date().toISOString();\n  const nowMs = Date.parse(now);\n  if (Number.isNaN(nowMs)) {\n    throw new Error(`Invalid now timestamp: ${now}`);\n  }\n\n  const dashboardOptions = { ...options, now };\n  const records = tracker.readSkillExecutionRecords(dashboardOptions);\n  const skillsById = health.discoverSkills(dashboardOptions);\n  const report = health.collectSkillHealth(dashboardOptions);\n  const summary = health.summarizeHealthReport(report);\n\n  const panelRenderers = {\n    'success-rate': () => renderSuccessRatePanel(records, report.skills, dashboardOptions),\n    'failures': () => renderFailureClusterPanel(records, dashboardOptions),\n    'amendments': () => renderAmendmentPanel(skillsById, dashboardOptions),\n    'versions': () => renderVersionTimelinePanel(skillsById, dashboardOptions),\n  };\n\n  const selectedPanel = options.panel || null;\n  if (selectedPanel && !VALID_PANELS.has(selectedPanel)) {\n    throw new Error(`Unknown panel: ${selectedPanel}. Valid panels: ${Array.from(VALID_PANELS).join(', ')}`);","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/skill-evolution/dashboard.js#L317-L353","documentation":"renderDashboard accepts an options.now timestamp that overrides the current time used for staleness/health calculations. The value is parsed with Date.parse and must be a valid date string; anything unparseable produces NaN, which would silently corrupt all age computations, so the dashboard throws instead.","triggerScenarios":"Calling renderDashboard({ now: 'not-a-date' }); passing a locale-formatted date like '15/03/2026' that Date.parse cannot read; passing a Date object instead of an ISO string (Date.parse(Date) coerces oddly/NaN); passing undefined-like strings ('null', 'undefined') from CLI flags.","commonSituations":"Wiring a CLI --now flag straight from process.argv into options.now; env vars containing human-readable dates; tests injecting fixtures with accidentally invalid timestamps; timezone-specific formats on different machines.","solutions":["Pass a valid ISO 8601 string, e.g. renderDashboard({ now: new Date().toISOString() }).","Coerce before calling: const nowMs = Date.parse(opts.now); if (Number.isNaN(nowMs)) fix/throw in the caller.","If the value comes from a CLI flag, validate/parse it at the CLI boundary and report a friendly usage error.","Omit `now` entirely to let the dashboard default to the current time."],"exampleFix":"// before\nrenderDashboard({ now: process.env.REPORT_DATE }); // 'March 15th'\n\n// after\nconst raw = process.env.REPORT_DATE;\nrenderDashboard(raw ? { now: new Date(raw).toISOString() } : {});","handlingStrategy":"validation","validationCode":"const nowMs = Date.parse(opts.now ?? new Date().toISOString());\nif (Number.isNaN(nowMs)) throw new Error(`--now must be an ISO date, got: ${opts.now}`);","typeGuard":"const isIsoDateString = (v) => typeof v === 'string' && v.length > 0 && !Number.isNaN(Date.parse(v));","tryCatchPattern":"try {\n  const result = renderDashboard({ now: raw });\n} catch (err) {\n  if (err.message.startsWith('Invalid now timestamp')) {\n    console.error(`Bad --now value '${raw}'; using current time.`);\n    return renderDashboard({});\n  }\n  throw err;\n}","preventionTips":["Always store/serialize timestamps as ISO 8601 (toISOString()).","Parse CLI date flags with new Date(raw) and check for Invalid Date at the argument-parsing boundary.","Never pass Date instances where an ISO string is expected."],"tags":["validation","timestamp","dashboard"],"backgroundTag":"invalid-date-format","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"}