{"record":{"id":"4ac15f43d6f9f2aa","repo":"affaan-m/ECC","slug":"invalid-now-timestamp-now","errorCode":null,"errorMessage":"Invalid now timestamp: ${now}","messagePattern":"Invalid now timestamp: (.+?)","errorType":"exception","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/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/skill-evolution/dashboard.js#L317-L353","documentation":"Thrown by renderDashboard when options.now is provided but Date.parse(now) returns NaN. When omitted, now defaults to new Date().toISOString() which is always valid, so the error only fires on an explicit bad value.","triggerScenarios":"Calling renderDashboard({ now: 'yesterday' }), renderDashboard({ now: '12/31/25' }) with a locale format some engines reject, or renderDashboard({ now: someUndefinedVar }) where the var is a non-empty garbage string. Empty string is falsy and falls back to the default, so it does not trigger.","commonSituations":"Forwarding a user-typed date string without validation; passing a Date object instead of its ISO string (Date.parse(dateObj) works, but inconsistent across engines); timezone/offset formatting that produces an unparseable token.","solutions":["Omit options.now to use the current time, or pass a strict ISO 8601 string (new Date().toISOString()).","Validate with Number.isNaN(Date.parse(now)) before passing.","If accepting user input, parse and re-serialize: new Date(input).toISOString()."],"exampleFix":"// before\nrenderDashboard({ now: userInput }); // userInput = '2025-31-12'\n\n// after\nrenderDashboard({ now: new Date(userInput).toISOString() });","handlingStrategy":"validation","validationCode":"function safeNow(now) {\n  const v = now || new Date().toISOString();\n  if (Number.isNaN(Date.parse(v))) throw new TypeError('now is not a date');\n  return v;\n}\nrenderDashboard({ now: safeNow(opts.now) });","typeGuard":"function isIsoTimestamp(v) {\n  return typeof v === 'string' && !Number.isNaN(Date.parse(v));\n}","tryCatchPattern":"try {\n  renderDashboard({ now });\n} catch (err) {\n  if (/Invalid now timestamp/.test(err.message)) renderDashboard({}); // drop bad now\n  else throw err;\n}","preventionTips":["Omit options.now unless you need a fixed point in time (tests, replays).","Always pass new Date().toISOString() rather than locale strings.","Validate user-supplied timestamps at the boundary, not at the API call."],"tags":["dashboard","timestamp","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}