{"record":{"id":"179ba01a3e0327e1","repo":"koala73/worldmonitor","slug":"comparison-measurement-requires-the-captured-snapshot-date","errorCode":null,"errorMessage":"Comparison measurement requires the captured snapshot date","messagePattern":"Comparison measurement requires the captured snapshot date","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/build-comparison-pages.mjs","lineNumber":580,"sourceCode":"function comparisonWebPageLd({ name, description, url, lastmod, faqId, baseUrl }) {\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'WebPage',\n    '@id': url + '#webpage',\n    name,\n    description,\n    url,\n    inLanguage: 'en-US',\n    dateModified: lastmod,\n    isPartOf: { '@id': new URL('/#website', baseUrl).href },\n    breadcrumb: { '@id': url + '#breadcrumb' },\n    mainEntity: { '@id': faqId },\n  };\n}\n\nfunction renderMeasurement(slug, snapshotDate, escapeHtml) {\n  if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(snapshotDate ?? '')) {\n    throw new Error('Comparison measurement requires the captured snapshot date');\n  }\n  const paragraphs = COMPARISON_MEASUREMENTS[slug];\n  if (!paragraphs?.length) throw new Error(slug + ' needs a World Monitor measurement explanation');\n  const maritime = slug === 'chokepoint-monitoring-tools';\n  const snapshotPath = maritime ? '/chokepoints/status.json' : '/country-instability-index/cii-ranking.json';\n  return [\n    '      <h2>How World Monitor measures this</h2>',\n    ...renderParagraphs(paragraphs, escapeHtml),\n    '      <p>Coverage: the <a href=\"/sources/\">source catalog</a> lists ' + escapeHtml(formatCount(WORLD_MONITOR_PROVIDER_COUNT)) + ' active providers across the product, not per metric. Availability varies by source and location.</p>',\n    '      <p data-measurement-snapshot><a href=\"' + snapshotPath + '\">Published ' + (maritime ? 'chokepoint status' : 'country instability') + ' snapshot</a>, captured <time datetime=\"' + escapeHtml(snapshotDate) + '\">' + escapeHtml(snapshotDate) + '</time>. This reference remains dated when live values change.</p>',\n  ];\n}\n\nfunction renderComparePage(page, { tpl, baseUrl, lastmod, snapshotDate }) {\n  const { escapeHtml, breadcrumbLd, pageDocument } = tpl;\n  const pageUrl = new URL(page.path, baseUrl).href;\n  const description = page.metaDescription ?? (page.h1\n    + ' - ' + page.claim","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/build-comparison-pages.mjs#L562-L598","documentation":"renderMeasurement embeds a 'How World Monitor measures this' section with a snapshot date that must be an ISO YYYY-MM-DD string. The snapshot date anchors the measurement claims to a captured data date; if snapshotDate is missing, null, or not in the exact format, the build throws 'Comparison measurement requires the captured snapshot date'.","triggerScenarios":"renderMeasurement invoked (directly or via page rendering) with snapshotDate undefined/null or a string failing /^\\d{4}-\\d{2}-\\d{2}$/ — e.g. '2026/09/15', '2026-9-1', or a full ISO timestamp '2026-09-15T00:00:00Z'.","commonSituations":"A caller passes the whole snapshot object instead of its capturedAt field; a config file stores the date with slashes or a full timestamp; the date constant was removed during a refactor and undefined flows through.","solutions":["Pass the capturedAt value from the frozen live-pulse snapshot, formatted exactly YYYY-MM-DD.","If you have a full timestamp, slice the date part: capturedAt.slice(0, 10) (valid only if it starts with YYYY-MM-DD).","Check the caller/config supplying snapshotDate — a missing env/config value becomes undefined here."],"exampleFix":"// before\nrenderMeasurement(slug, snapshot.capturedAt, escapeHtml); // '2026-09-15T04:12:00Z'\n// after\nrenderMeasurement(slug, snapshot.capturedAt.slice(0, 10), escapeHtml); // '2026-09-15'","handlingStrategy":"validation","validationCode":"if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(snapshotDate ?? '')) throw new Error('snapshotDate must be YYYY-MM-DD');","typeGuard":"const isIsoDate = (v) => typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(v);","tryCatchPattern":null,"preventionTips":["Always slice full ISO timestamps to 10 chars before passing as snapshotDate.","Store snapshot dates in config in plain YYYY-MM-DD form."],"tags":["build","validation","date-format","comparison-pages"],"backgroundTag":"invalid-date-format","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}