Skip to content

Alert Engine

Route: /alert-ontology

The Alert Engine is a rule-based flagging system that evaluates every item-site series against a library of named conditions and attaches severity labels to those that match. Alerts are complementary to Exceptions: alerts are ontology-driven and can be queried in natural language; exceptions are pipeline-scoped triage records.


Alerts vs Exceptions

Alerts Exceptions
Trigger Evaluated against the alert ontology rules Generated by POST /api/exception-log/generate
Scope All series, any time Active pipeline only
Status management No open/reviewed/snoozed lifecycle Full status workflow
Primary use Reporting, filtering, surfacing risk Planner triage and action

Use alerts to answer questions like "show me all items with high safety stock and long lead time". Use exceptions to manage your daily planning queue.


Seeding the Ontology

Before alerts can fire, the ontology must be loaded into the database. An administrator does this once:

POST /api/alerts/ontology/seed

This writes all 34 default rules to the scenario schema. It is safe to run multiple times — existing rules are not duplicated.

To view the current rules in the UI, navigate to Admin → Alert Rules (visible to admin users only).

Alert Rules

The Alert Rules page shows the seeded ontology rules, their conditions and severity.


Severity Levels

Each rule is assigned a severity:

Severity Meaning
high Immediate attention recommended. Likely to impact service level or cost significantly.
medium Notable condition worth reviewing. May escalate if not addressed.
low Informational. No immediate action required but useful for analysis.

The 32 Default Rules

The ontology ships with 34 pre-built rules covering stock levels, forecast quality, demand patterns, lead times, safety stock, distributions, annual demand, and supply order activity. They are grouped by domain:

Stock Level Rules

Rule Name Display Name Condition Severity
high_stock High Stock stock_days > 90 high
low_stock Low Stock stock_days < 10 high
high_on_hand High On-Hand Inventory on_hand > 1000 medium

Forecast Quality Rules

Rule Name Display Name Condition Severity
bad_forecast Poor Forecast Accuracy forecast_accuracy < 0.70 medium
high_forecast_error High Forecast Error (WAPE) wape > 0.30 medium

Service Level Rules

Rule Name Display Name Condition Severity
low_service_level Low Service Level fill_rate < P20 dynamic threshold high

The low_service_level rule uses a dynamic threshold: the threshold is computed as the 20th percentile of fill rate across all items in the run. This means the 20% of items with the worst fill rates always trigger this rule, regardless of the absolute fill rate value.

Demand Pattern Rules

Rule Name Display Name Condition Severity
high_variability High Demand Variability cv > 0.5 medium
zero_demand Zero / No Demand demand_rate < 0.001 low
intermittent_demand Intermittent Demand is_intermittent = true low
indirect_demand Indirect Demand indirect_demand_rate > 0 medium
critical_item Critical Item criticality > 0.7 high

Lead Time Rules

Rule Name Display Name Condition Severity
long_lead_time Long Lead Time lead_time > P90 dynamic threshold medium
short_lead_time Short Lead Time lead_time < 2 weeks low

The long_lead_time rule uses a dynamic threshold: the 90th percentile of non-zero wait times across all items. The top 10% of items by lead time always trigger this rule.

Safety Stock Rules

Rule Name Display Name Condition Severity
high_safety_stock High Safety Stock safety_stock > 500 medium
no_safety_stock No Safety Stock safety_stock = 0 medium

Demand Spread Rules

Rule Name Display Name Condition Severity
high_demand_std High Demand Std Dev demand_std > 100 medium

Distribution Type Rules (Informational)

These low-severity rules flag items whose demand has been fitted to a specific parametric distribution by the Distribution Fitting step.

Rule Name Display Name Condition
dist_normal Normal Distribution demand distribution = normal
dist_gamma Gamma Distribution demand distribution = gamma
dist_lognormal Lognormal Distribution demand distribution = lognormal
dist_poisson Poisson Distribution demand distribution = poisson
dist_weibull Weibull Distribution demand distribution = weibull

Annual Demand Rules

Rule Name Display Name Condition Severity
high_annual_demand High Annual Demand demand_12m > 10,000 low
low_annual_demand Low Annual Demand demand_12m < 100 low

Data Quality and Structural Rules (Informational)

Rule Name Display Name Condition
has_distribution Has Fitted Distribution distribution fitted = true
in_bom In Bill of Materials in_bom = true

Supply Order Rules

These rules query live supply plan data in ClickHouse to find items that currently have active repair or return orders in the supply projection.

Rule Name Display Name Condition Severity
has_repair_orders Items with Repair Orders Item has at least one REPAIR-type supply order in the active pipeline medium
has_return_orders Items with Return Orders Item has at least one RETURN-type supply order in the active pipeline low

Natural language synonyms for has_repair_orders: "repairable items", "items with repair orders", "repair orders", "items being repaired", "repair pipeline", "parts under repair", "serviceable items"

Natural language synonyms for has_return_orders: "items with return orders", "return orders", "items being returned", "return pipeline", "customer returns"

Seed required after ontology update

If you updated from a version that did not have these rules, run POST /api/alerts/ontology/seed after restarting the API to write them to the database. The API loads DEFAULT_ONTOLOGY on startup, but the DB rules take precedence — seeding is required for the rules to be active.


Natural Language Parser

Each rule has a list of synonyms — alternative phrasings that mean the same thing in supply chain language. For example, the high_stock rule recognises: "too much stock", "excess inventory", "overstock", "high DOS", "high weeks of supply", "high DIO", "high coverage", and many more.

The alert engine resolves a free-text query using a three-tier cascade:

1. LLM parser (Ollama / Mistral)      ← highest accuracy, requires local Ollama
2. Rust TF-IDF engine (alerts_rs)     ← fast, no GPU needed
3. Python scikit-learn TF-IDF         ← fallback when Rust extension absent

Tier 1 — LLM Parser (Ollama / Mistral)

When Ollama is running locally, the engine sends the query to a local LLM (default: mistral) which returns a structured condition set with confidence score. If the LLM confidence exceeds llm_confidence_threshold (default 0.55), its result is used directly.

Configure via the alerts parameter type in Settings:

Parameter Default Description
llm_parser_enabled true Set false to always skip LLM and use TF-IDF
ollama_url http://localhost:31434 Ollama server URL
ollama_model mistral Any model served by Ollama (e.g. llama3, phi3)
llm_confidence_threshold 0.55 Below this score, fall back to TF-IDF

Starting Ollama

Install Ollama from ollama.ai, then: ollama run mistral. The engine detects it automatically on the next alert query.

Graceful fallback

If Ollama is unreachable or returns low confidence, the engine silently falls back to TF-IDF — no error is shown to the user. Check the process log for LLM parser failed debug messages.

Tier 2 & 3 — TF-IDF Matching

The TF-IDF engines (Rust or Python scikit-learn) use cosine similarity to match a free-text query to the closest rule by its synonyms corpus.

Example queries that resolve correctly:

Query Matched Rule
"show me items running low" low_stock
"find all backorder risk" low_service_level
"which parts have high DOS?" high_stock
"items with Weibull demand" dist_weibull
"parts used in assemblies" in_bom
"long supplier lead time" long_lead_time

If neither Rust extension nor sklearn is installed, rules can only be matched by their exact name field.


Interpreting Alert Results

When you query the alerts API or view alerts in the Alert Rules screen, each result row shows:

  • Item + Site — the series that triggered
  • Rule name — which rule fired
  • Field value — the actual metric value that triggered (e.g. stock_days = 142)
  • Threshold — the rule's threshold (e.g. > 90)
  • Severity — high / medium / low

A single item can trigger multiple rules simultaneously. For example, an item might be flagged for both high_stock and dist_lognormal and in_bom at the same time.


Customising Rules

Administrators can modify rule thresholds from the Alert Rules screen (/alert-ontology). To change a threshold:

  1. Navigate to Admin → Alert Rules
  2. Find the rule by name
  3. Click the edit button
  4. Update the threshold value and save

Changes take effect immediately for future alert evaluations. Reseeding the ontology (POST /api/alerts/ontology/seed) resets all rules back to their defaults, so save any custom changes first if you need to reseed.


Adding Custom Rules

Custom rules can be added via the API (POST /api/alerts/ontology) with:

{
  "name": "my_custom_rule",
  "display_name": "My Custom Rule",
  "description": "Items where X exceeds Y",
  "field": "field_name",
  "operator": ">",
  "threshold": 500.0,
  "severity": "medium",
  "synonyms": ["phrase one", "phrase two"]
}

The field must be a metric available in the alert SQL lateral joins. See the API documentation at http://localhost:8002/docs for the full field list.