{"record":{"id":"f025e1060f6ac8bd","repo":"koala73/worldmonitor","slug":"unknown-physical-divergence-freshness-reason-st","errorCode":null,"errorMessage":"Unknown physical divergence freshness reason: ${String(reason)}","messagePattern":"Unknown physical divergence freshness reason: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"shared/physical-divergence-contract.js","lineNumber":115,"sourceCode":"    physicalStaleAfterCalendarDays: 12,\n    paperMaxAgeMs: 36 * 60 * 60 * 1000,\n    fxMaxAgeMs: 60 * 60 * 60 * 1000,\n    missingReasons: MISSING_REASONS,\n    staleReasons: STALE_REASONS,\n  }),\n  reasons: REASONS,\n  storedReadingReasonsByState: STORED_READING_REASONS_BY_STATE,\n  rpcFallbackReasons: RPC_FALLBACK_REASONS,\n  readingReasonValues: READING_REASON_VALUES,\n  compositeReasonValues: COMPOSITE_REASON_VALUES,\n  readingReasonPattern: pattern(READING_REASON_VALUES),\n  compositeReasonPattern: pattern(COMPOSITE_REASON_VALUES),\n});\n\nexport function physicalDivergenceStateForFreshnessReason(reason) {\n  if (MISSING_REASONS.includes(reason)) return 'missing_input';\n  if (STALE_REASONS.includes(reason)) return 'stale_input';\n  throw new TypeError(`Unknown physical divergence freshness reason: ${String(reason)}`);\n}\n\nexport function isPhysicalDivergenceStoredReadingReason(state, reason) {\n  return STORED_READING_REASONS_BY_STATE[state]?.includes(reason) === true;\n}\n\nexport function isPhysicalDivergenceStoredCompositeReason(state, reason) {\n  if (state === 'ok') return reason === '';\n  return NON_OK_STATE_PRIORITY.includes(state)\n    && COMPOSITE_MEMBER_REASONS.includes(reason)\n    && reason.endsWith(`:${state}`);\n}\n\nexport function buildPhysicalStressComposite(readings) {\n  const values = Array.isArray(readings) ? readings : [];\n  const byMetal = new Map();\n  for (const reading of values) {\n    if (!METAL_ORDER.includes(reading?.metal)) {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/shared/physical-divergence-contract.js#L97-L133","documentation":"physicalDivergenceStateForFreshnessReason maps a freshness-reason string to a divergence state ('missing_input' or 'stale_input') using fixed allow-lists (MISSING_REASONS / STALE_REASONS). Any reason string not on those lists throws a TypeError, since the physical-divergence contract only defines a closed set of reasons.","triggerScenarios":"Calling with a typo'd or renamed reason (e.g. 'stale-data' instead of a contract reason), a reason added by a newer producer but consumed by an older contract version, or passing null/undefined/non-string values.","commonSituations":"Contract version drift between producer and consumer; hand-written reason strings instead of the exported constants; refactor renaming a reason in one place only.","solutions":["Use the contract-exported reason constants instead of string literals","Check the reason against MISSING_REASONS/STALE_REASONS (or the reason patterns) before calling","Align producer and consumer to the same shared/physical-divergence-contract.js version","Add the new reason to the contract deliberately and update both reason lists if it is a legitimate new state"],"exampleFix":"// before\nconst state = physicalDivergenceStateForFreshnessReason('stale-data');\n// after\nimport { STALE_REASONS, physicalDivergenceStateForFreshnessReason } from './physical-divergence-contract.js';\nconst state = STALE_REASONS.includes('stale_data') ? physicalDivergenceStateForFreshnessReason('stale_data') : null;","handlingStrategy":"type-guard","validationCode":"import { MISSING_REASONS, STALE_REASONS } from './physical-divergence-contract.js';\nfunction isKnownFreshnessReason(reason) {\n  return MISSING_REASONS.includes(reason) || STALE_REASONS.includes(reason);\n}","typeGuard":"function isFreshnessReason(v) {\n  return typeof v === 'string' &&\n    (MISSING_REASONS.includes(v) || STALE_REASONS.includes(v));\n}","tryCatchPattern":"try {\n  state = physicalDivergenceStateForFreshnessReason(reason);\n} catch (e) {\n  if (e instanceof TypeError && e.message.startsWith('Unknown physical divergence freshness reason')) {\n    state = null; // treat as unrecognized input, log the reason value\n  } else throw e;\n}","preventionTips":["Import and reuse the contract's reason constants; never hand-write reason strings","Keep producer and consumer on the same contract version","Add new reasons to the contract explicitly with tests","Narrow with isFreshnessReason before calling"],"tags":["contract","typeerror","data-contract"],"backgroundTag":"invalid-enum-value","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}