Skip to content

KB/alert

Frozen Data Feed

Last verified

Auto-generated. This article is rebuilt from app/signals/config/alert_thresholds.json by scripts/build_alerts_kb.py. Edit the alert config and re-run the script β€” do not edit this file directly.

Frozen Data Feed

Alert ID: FROZEN_FEED
Category: integrity
Cross-detection: no

A persisted daily metric has printed the SAME value for longer than its publish cadence allows (consecutive-identical-value run >= max(5, 2x cadence) TRADING days; cadence derived from the registry’s release_calendar β€” no hand-list). Fired per-metric by the capture-cycle integrity guard (app/signals/integrity_guard.py), NOT by the macro alert engine; suppressed when the metric’s vintage/as-of column shows the vendor is still publishing (a genuinely flat series is not a dead feed). This is the alarm that catches NFCI frozen at -0.53 for 51 trading days β€” a genuine value-freeze far past its weekly bar. A MONTHLY series like ebp/gz_spread instead legitimately holds one value for a full ~33-trading-day publication interval (just under this bar), so its staleness is owned by the sibling STALE_INPUT alarm via the ebp_obs_date binding + 80-day budget (#15), NOT this value-repeat detector. Frozen-but-present values are invisible to NULL checks, and every downstream lens, grading pass, and analogue match silently consumes the stale copy.

Severity

WARNING β€” conditions deteriorating; worth monitoring

Trigger condition

{
  "type": "computed",
  "computation": "integrity_frozen_feed"
}

Marker, not a rule the macro alert engine evaluates. app/signals/alerts.py:_eval_computed does not recognise integrity_frozen_feed, so the per-cycle evaluate_alerts loop returns False for it every cycle and this alert can never fire from the macro path.

The real trigger lives in app/signals/integrity_guard.py (run_integrity_checks), which writes the alert row into the alerts table directly. It is fired from the capture cycle β€” run_integrity_checks runs inside capture_signals_after_report, right after the pack-size guard. The definition stays in alert_thresholds.json so severity, message template, cooldown, the alerts_config admin surface, and this catalog all read from one place.

Message template

Data integrity: {metric} has printed the same value ({value}) for {run_trading_days} consecutive trading days β€” publish cadence is {publishes} (~{cadence_trading_days} trading day(s); freeze bar {threshold}). The feed may be frozen: downstream lenses, grading, and analogues are consuming a stale copy.

Rendered by app/signals/integrity_guard.py via Python str.format over the per-metric context it builds for the fire, NOT the macro signals dict. A placeholder that fails to resolve logs a warning and falls back to a plainly-built message β€” a template typo must never suppress an integrity alert.

Cooldown / dedup

Notifies

See also