koala73/worldmonitor · error · Error

${pagePath} is missing its recent-developments section

Error message

${pagePath} is missing its recent-developments section

What it means

During corpus verification (around line 3500), the frozen developments payload is normalized with the same publish rules as the renderer and, if the rows contain dated items, the generated HTML page must contain the data-country-developments marker. If dated developments exist but the marker is absent, the page silently dropped the section, so the build throws to prevent publishing an incomplete country page.

Solutions

  1. Regenerate the country pages so the rendered HTML includes the recent-developments section with the data-country-developments attribute
  2. Restore the data-country-developments attribute in the page template's developments section markup
  3. Check the render condition/feature flag hiding the section for countries with dated items and fix it
  4. Confirm the frozen developments data and the page HTML come from the same build (stale HTML vs fresh data)

Example fix

// before (template)
<section class="developments">...</section>
// after
<section class="developments" data-country-developments>...</section>
Defensive patterns

Strategy: validation

Validate before calling

if (rowsHasDatedItems(developments) && !html.includes('data-country-developments')) {
  throw new Error(`${pagePath}: dated developments exist but section marker missing`);
}

Try / catch

try {
  assertFrozenDevelopmentsRendered({ pagePath, html, developments, countryCode, countryName });
} catch (err) {
  if (err.message.includes('missing its recent-developments section')) {
    console.error(`Template for ${pagePath} dropped the developments section — check data-country-developments marker`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Running the corpus build/verification when a country page's HTML lacks the data-country-developments attribute while the normalized developments contain at least one dated item (developmentsHasDatedItem(rows) is true). Happens when the page template omits the section, the renderer output was stripped, or a render condition hides the section.

Common situations: Template refactor removed or renamed the data-country-developments attribute; a conditional render guard (feature flag or thin-brief check) hides the section; frozen data was updated with new dated items but the page was not regenerated; hand-edited HTML dropped the section.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

// Durable guard (#7615): the enrichment must be permanent, not a one-off
// content pass. After rendering, every frozen developments row for this
// country must be present in the page HTML — a silent drop (wrong slug, lost
// prop, over-eager filter) fails the build instead of shipping a page whose
// snapshot claims items the crawler cannot see.
export function assertCountryDevelopmentsRendered({
  pagePath,
  html,
  developments,
  countryCode = '',
  countryName = '',
}) {
  const rawRows = developments && typeof developments === 'object' ? developments : null;
  // Same publish rules as the renderer, so a withheld thin brief is not
  // reported as dropped and a repaired heading is looked for as repaired.
  const rows = rawRows ? normalizeFrozenDevelopments(rawRows, { countryCode, countryName }) : null;
  if (!rows || !developmentsHasDatedItem(rows)) return;
  if (!html.includes('data-country-developments')) {
    throw new Error(`${pagePath} is missing its recent-developments section`);
  }
  for (const headline of rows.headlines || []) {
    // Anchor-scoped: a bare URL substring passes when the URL merely appears
    // in prose or another link. The headline must render as a link.
    if (!html.includes(`href="${escapeHtml(headline.url)}"`)) {
      throw new Error(`${pagePath} dropped frozen headline ${headline.url}`);
    }
  }
  if (rows.brief && typeof rows.brief.text === 'string' && rows.brief.text.trim()) {
    // Anchor on first AND last content lines after stripping section titles,
    // bullets, and emphasis markers. Every generated brief opens with the same
    // boilerplate header, so the first line alone cannot catch a cross-country
    // swap; markdown conversion means raw `**` and ISO titles never appear.
    const contentLines = rows.brief.text.trim().split('\n')
      .map((line) => unwrapBriefEmphasisLine(line.trim()))
      .filter(Boolean)
      .filter((line) => !isBriefSectionHeader(line, { countryCode, countryName }))
      .map((line) => line.replace(/^(?:[•\-]\s*|\*\s+)/, '').replace(/\*\*/g, ''));

View on GitHub (pinned to 7d06c8633d)