{"record":{"id":"d387c21bde6360db","repo":"koala73/worldmonitor","slug":"pagepath-heading-leaks-iso-code-text","errorCode":null,"errorMessage":"${pagePath} heading leaks ISO code: ${text}","messagePattern":"(.+?) heading leaks ISO code: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/build-crawlable-corpus.mjs","lineNumber":3590,"sourceCode":"    throw new Error(`${pagePath} renders literal markdown emphasis in <main>`);\n  }\n  const brief = intelBriefHtml(html);\n  if (brief && sources !== undefined) {\n    // Check the rendered claim blocks as well as the input. A later formatter\n    // must not add an entity or change a citation after publish-time validation.\n    const claims = [...brief.matchAll(/<(p|li)\\b([^>]*)>([\\s\\S]*?)<\\/\\1>/gi)]\n      .filter((match) => !/\\bclass=\"source\"/.test(match[2]))\n      .map((match) => corpusVisibleText(match[3]).replace(/&(amp|lt|gt|quot|#39);/g,\n        (entity) => ({ '&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '\"', '&#39;': \"'\" })[entity]));\n    const gap = briefCitationGroundingGap({ text: claims.join('\\n'), sources });\n    if (gap) throw new Error(`${pagePath} brief has unsupported citation: ${gap}`);\n  }\n  const headingSource = brief ?? main;\n  const headingHits = [...headingSource.matchAll(/<h[1-6]\\b[^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi)];\n  for (const hit of headingHits) {\n    const text = hit[1].replace(/<[^>]+>/g, ' ').replace(/\\s+/g, ' ').trim();\n    if (MEANS_FOR_ISO_RE.test(text)) {\n      throw new Error(`${pagePath} heading leaks ISO code: ${text}`);\n    }\n  }\n  const briefLines = corpusMainHtml(brief ?? html)\n    .replace(/<br\\b[^>]*>|<\\/(?:p|h[1-6]|li|div)>/gi, '\\n')\n    .replace(/<[^>]+>/g, ' ');\n  if (MEANS_FOR_ISO_RE.test(briefLines)) {\n    throw new Error(`${pagePath} brief heading leaks an ISO-3166 alpha-2 code`);\n  }\n}\n\n// A floor, not completeness. #7615 shipped this as\n// `developmentsPageCount !== indexedCountryPageCount` -- every indexed country\n// owed a dated development -- which no real capture can satisfy: the news cycle\n// simply does not mention most countries. A fully keyed freeze on 2026-09-04\n// covered 61 of 196 pages (54 headline-matched, 40 briefs, 18 timelines), so\n// the gate rejected every snapshot the freeze could produce. That left the\n// weekly refresh unable to publish and armed the\n// MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS fuse against the whole corpus build.","sourceCodeStart":3572,"sourceCodeEnd":3608,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/build-crawlable-corpus.mjs#L3572-L3608","documentation":"The crawlable-corpus build script validates that generated country/corpus pages do not leak machine ISO-3166 codes in visible headings. A heading (h1-h6) in the brief or main HTML matched MEANS_FOR_ISO_RE, meaning human-facing text contains an ISO code where a country name is expected. The build throws to stop a low-quality page from being published to the SEO corpus.","triggerScenarios":"Running the crawlable-corpus build (or its per-page validator) when a generated page's brief or main document contains an <h1>-<h6> whose stripped text matches the ISO-code detection regex, e.g. a heading like '<h2>Situation in DE</h2>'.","commonSituations":"Data templates that interpolate the country's ISO alpha-2/alpha-3 code instead of its display name; upstream data feeds returning codes in name fields; a newly added country lacking a localized display name so the template falls back to the code.","solutions":["Find the page (pagePath is in the message) and inspect its heading source; identify which field supplied the heading text.","Replace the ISO code with the country's display name in the data entry or template that renders the heading.","If a name is missing upstream, add a code->name mapping fallback in the generator before rendering headings.","Re-run the build to confirm the page passes the ISO-leak guard."],"exampleFix":"// before\ntemplate `<h2>Security briefing: ${country.iso2}</h2>`\n// after\ntemplate `<h2>Security briefing: ${country.displayName ?? NAME_BY_ISO[country.iso2]}</h2>`","handlingStrategy":"validation","validationCode":"const ISO_LEAK = /\\b[A-Z]{2,3}\\b/;\nconst text = heading.replace(/<[^>]+>/g, ' ').trim();\nif (ISO_LEAK.test(text)) throw new Error(`heading leaks ISO code: ${text}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always render country display names, never ISO codes, in user-visible templates.","Keep a code->name map as the single fallback source.","Run the corpus validator locally before pushing."],"tags":["build","seo","content-validation"],"backgroundTag":"schema-validation-failed","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"}