koala73/worldmonitor · error · Error

${pagePath} brief heading leaks an ISO-3166 alpha-2 code

Error message

${pagePath} brief heading leaks an ISO-3166 alpha-2 code

What it means

Sibling of error 90: after checking headings, the corpus builder flattens the brief's block-level text (line breaks at <br>, </p>, </h*>, </li>, </div>) and runs the ISO-code regex over it. If the brief body itself carries a bare ISO-3166 alpha-2 code, the build throws rather than publishing the page.

Solutions

  1. Open the failing pagePath and locate the alpha-2 code occurrence in the rendered brief text.
  2. Replace the code with the full country name in the source data or brief template.
  3. Add a lint/template rule so brief text goes through a name-resolution helper instead of raw codes.
  4. Rebuild and confirm the guard passes.

Example fix

// before
brief = `Latest update for ${country.iso2}: ...`
// after
brief = `Latest update for ${country.name}: ...`
Defensive patterns

Strategy: validation

Validate before calling

const text = brief.replace(/<[^>]+>/g, ' ');
if (MEANS_FOR_ISO_RE.test(text)) throw new Error('brief contains raw ISO-3166 alpha-2 code');

Prevention

When it happens

Trigger: Running the crawlable-corpus build when the brief (or main page) prose text, after stripping tags, contains a standalone ISO-3166 alpha-2 code string matched by MEANS_FOR_ISO_RE.

Common situations: Brief templates that append '(US)' style code suffixes; analyst copy pasted with codes; feed data where only the alpha-2 code was available for a field the brief renders verbatim.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/f7267b6601628d35. Report an issue: GitHub.

Appendix: source

Thrown at scripts/build-crawlable-corpus.mjs:3597

      .filter((match) => !/\bclass="source"/.test(match[2]))
      .map((match) => corpusVisibleText(match[3]).replace(/&(amp|lt|gt|quot|#39);/g,
        (entity) => ({ '&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '"', '&#39;': "'" })[entity]));
    const gap = briefCitationGroundingGap({ text: claims.join('\n'), sources });
    if (gap) throw new Error(`${pagePath} brief has unsupported citation: ${gap}`);
  }
  const headingSource = brief ?? main;
  const headingHits = [...headingSource.matchAll(/<h[1-6]\b[^>]*>([\s\S]*?)<\/h[1-6]>/gi)];
  for (const hit of headingHits) {
    const text = hit[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
    if (MEANS_FOR_ISO_RE.test(text)) {
      throw new Error(`${pagePath} heading leaks ISO code: ${text}`);
    }
  }
  const briefLines = corpusMainHtml(brief ?? html)
    .replace(/<br\b[^>]*>|<\/(?:p|h[1-6]|li|div)>/gi, '\n')
    .replace(/<[^>]+>/g, ' ');
  if (MEANS_FOR_ISO_RE.test(briefLines)) {
    throw new Error(`${pagePath} brief heading leaks an ISO-3166 alpha-2 code`);
  }
}

// A floor, not completeness. #7615 shipped this as
// `developmentsPageCount !== indexedCountryPageCount` -- every indexed country
// owed a dated development -- which no real capture can satisfy: the news cycle
// simply does not mention most countries. A fully keyed freeze on 2026-09-04
// covered 61 of 196 pages (54 headline-matched, 40 briefs, 18 timelines), so
// the gate rejected every snapshot the freeze could produce. That left the
// weekly refresh unable to publish and armed the
// MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS fuse against the whole corpus build.
//
// Rendering is not this gate's job -- assertDevelopmentsRendered already fails
// per page when a frozen item is dropped, and it compares against the same
// snapshot rows, so demanding equality here proved nothing extra. What is worth
// catching is a COLLAPSE: the digest matcher breaking, or a wrong-tiered key
// leaving briefs and timelines empty. Gate on a floor that a quiet news week
// clears and a broken pipeline does not.

View on GitHub (pinned to 7d06c8633d)