koala73/worldmonitor · error · Error
${pagePath} dropped its frozen intel brief
Error message
${pagePath} dropped its frozen intel brief What it means
The frozen-intel-brief anchor check strips all tags from the page HTML and requires the brief's first and last content lines (first 120 chars, HTML-escaped, deduplicated) to appear verbatim in the resulting page text. If either anchor is missing, the page dropped part of its frozen intel brief, so the build throws rather than publish a truncated or altered brief.
Solutions
- Regenerate the page so it includes the full frozen brief content
- Fix the formatter/post-processor that alters the brief's first or last line (entity encoding, whitespace normalization, truncation)
- Verify the frozen brief and the page HTML are from the same build output; rebuild if stale
- Check that nothing (styles, lazy loading, conditional rendering) removes the brief from the emitted static HTML
Example fix
// before: formatter re-escapes entities after validation
const html = escapeAll(revalidate(html));
// after: run all transformations first, then validate
const html = escapeAll(html);
assertFrozenBriefAnchors({ pagePath, html, rows }); Defensive patterns
Strategy: validation
Validate before calling
const pageText = html.replace(/<[^>]+>/g, '');
for (const line of briefContentLines(brief)) {
if (!pageText.includes(escapeHtml(line.slice(0, 120)))) {
throw new Error(`${pagePath}: brief line missing from page text: ${line.slice(0, 40)}...`);
}
} Try / catch
try {
assertFrozenBriefAnchors({ pagePath, html, rows });
} catch (err) {
if (err.message.includes('dropped its frozen intel brief')) {
console.error(`Brief content altered or truncated for ${pagePath}; diff the rendered page against the frozen brief`);
}
throw err;
} Prevention
- Treat the frozen brief as immutable after publish-time validation; no formatter may run afterward
- Run all entity/whitespace-normalizing formatters BEFORE anchor validation, not after
- Keep briefs short enough that truncation middleware cannot cut them
- Add a CI diff check between frozen brief content and rendered page text
When it happens
Trigger: Asserting a generated country page when the stripped page text no longer contains the brief's opening or closing content line. Triggered by truncation, entity/encoding drift, or a formatter that alters whitespace or punctuation in the brief's first or last line.
Common situations: A post-processing step truncates long pages; a later formatter escapes or unescapes entities differently (e.g. & vs &) so the escaped anchor no longer matches; content rendered lazily or conditionally is missing from the static HTML; brief text edited after freezing without re-rendering the page.
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
- ${pagePath} is missing its recent-developments section
- ${pagePath} brief has unsupported citation: ${gap}
- no module entry script in ${dashboardPath} — run: ${BUILD_CO
- is missing methodology prose
- is missing following prose
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/30548c6163402e85.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-crawlable-corpus.mjs:3525
}
}
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, ''));
const anchors = [contentLines[0], contentLines.at(-1)]
.filter((line, index, all) => line && all.indexOf(line) === index)
.map((line) => escapeHtml(line.slice(0, 120)));
const pageText = html.replace(/<[^>]+>/g, '');
for (const anchor of anchors) {
if (!pageText.includes(anchor)) {
throw new Error(`${pagePath} dropped its frozen intel brief`);
}
}
}
const briefSources = Array.isArray(rows.brief?.sources) ? rows.brief.sources : [];
for (const source of briefSources) {
if (typeof source?.url === 'string' && !html.includes(`href="${escapeHtml(source.url)}"`)) {
throw new Error(`${pagePath} dropped frozen brief source ${source.url}`);
}
}
for (const event of rows.timeline || []) {
if (!html.includes(escapeHtml(event.title))) {
throw new Error(`${pagePath} dropped frozen timeline event ${event.title}`);
}
if (typeof event.occurredAt === 'string' && !html.includes(`datetime="${escapeHtml(event.occurredAt)}"`)) {
throw new Error(`${pagePath} dropped the date of frozen timeline event ${event.title}`);
}
}
}View on GitHub (pinned to 7d06c8633d)