{"record":{"id":"1ca29872a56709ac","repo":"koala73/worldmonitor","slug":"relativepath-is-math-round-agedays-days-old-max-max-live","errorCode":null,"errorMessage":"${relativePath} is ${Math.round(ageDays)} days old (max ${MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS}); run `npm run freeze:crawlable-live-pulse` to republish current values","messagePattern":"(.+?) is (.+?) days old \\(max (.+?)\\); run `npm run freeze:crawlable-live-pulse` to republish current values","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/build-crawlable-corpus.mjs","lineNumber":481,"sourceCode":"    .sort((a, b) => b.match[1].localeCompare(a.match[1]));\n  if (candidates.length === 0) {\n    throw new Error(`No crawlable live-pulse snapshot found in ${RESILIENCE_SNAPSHOT_DIR}`);\n  }\n\n  const [{ filename, match }] = candidates;\n  const relativePath = join(RESILIENCE_SNAPSHOT_DIR, filename);\n  const snapshot = readJson(rootDir, relativePath);\n  if (snapshot.capturedAt !== match[1]) {\n    throw new Error(\n      `${relativePath} filename date ${match[1]} does not match capturedAt ${snapshot.capturedAt}`,\n    );\n  }\n  if (!snapshot.countries || !snapshot.chokepoints || !snapshot.crises || !snapshot.signalConvergence) {\n    throw new Error(`${relativePath} is missing required live-pulse sections`);\n  }\n  const ageDays = livePulseSnapshotAgeDays(snapshot.capturedAt);\n  if (ageDays > MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS) {\n    throw new Error(\n      `${relativePath} is ${Math.round(ageDays)} days old (max ${MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS}); `\n      + 'run `npm run freeze:crawlable-live-pulse` to republish current values',\n    );\n  }\n  return relativePath;\n}\n\nfunction formatStaticDateTime(iso) {\n  const timestamp = Date.parse(iso);\n  if (!Number.isFinite(timestamp)) return String(iso || '');\n  return new Intl.DateTimeFormat('en-US', {\n    year: 'numeric',\n    month: 'short',\n    day: 'numeric',\n    hour: 'numeric',\n    minute: '2-digit',\n    timeZone: 'UTC',\n    timeZoneName: 'short',","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/build-crawlable-corpus.mjs#L463-L499","documentation":"resolveLatestLivePulseSnapshotPath enforces snapshot freshness: livePulseSnapshotAgeDays(capturedAt) must not exceed MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS. An expired snapshot makes every downstream claim stale, so the build throws '<relativePath> is N days old (max M); run `npm run freeze:crawlable-live-pulse` to republish current values'.","triggerScenarios":"Building the crawlable corpus when the latest frozen live-pulse snapshot's capturedAt is more than MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS days before today's date.","commonSituations":"CI running after a weekend/holiday with no re-freeze; the freeze step skipped in the release pipeline; system clock or timezone skew inflating age; snapshot pinned to an old file whose capturedAt never updates.","solutions":["Run `npm run freeze:crawlable-live-pulse` to republish a current snapshot, then rebuild.","Ensure the freeze step runs as part of CI/build on every deploy.","Verify system date/timezone are correct if age looks wrong for a fresh snapshot.","If intentionally working offline, adjust MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS only as a deliberate, reviewed policy change."],"exampleFix":"// CI before\n- npm run build:crawlable-corpus\n// after\n- npm run freeze:crawlable-live-pulse\n- npm run build:crawlable-corpus","handlingStrategy":"retry","validationCode":"const ageDays = (Date.now() - Date.parse(snapshot.capturedAt + 'T00:00:00Z')) / 86400000;\nif (Math.round(ageDays) > MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS) console.warn(`snapshot ${snapshot.capturedAt} is stale; re-freeze before build`);","typeGuard":null,"tryCatchPattern":"try {\n  const path = resolveLatestLivePulseSnapshotPath();\n} catch (err) {\n  if (err.message.includes('days old (max')) {\n    execSync('npm run freeze:crawlable-live-pulse', { stdio: 'inherit' });\n    // retry once after re-freezing\n  } else throw err;\n}","preventionTips":["Run the freeze step automatically at the start of every build/CI job.","Alert when the latest snapshot approaches the max age so refreshes aren't missed after weekends.","Verify machine clocks/timezones when age calculations look incorrect."],"tags":["build","stale-data","snapshot","freshness","live-pulse"],"backgroundTag":"stale-snapshot-data","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"}