---
module: incident.processing-rules
title: Processing Rules
tab: Internal
order: 20
audience: internal
---

> **Internal ops/support view.** Ownership, admin actions, and first-response triage for the Processing Rules screen. Served entirely by **hiveops-incident** (port 8080, NGINX `/api/incident/`). Grounded in code 2026-07-01.

## What this screen controls

Three independent rule sets, all owned by hiveops-incident and applied inside `IncidentAutoCreationService`:

- **Opening Rules** (`ticket_processing_rules`) — decide whether a device event becomes an incident: `CREATE_INCIDENT`, `SUPPRESS`, or `OPEN_AND_CLOSE`.
- **Closing Rules** (`incident_closing_rules`) — auto-resolve/close open incidents when a recovery event arrives (`targetStatus` = `RESOLVED` or `CLOSED`).
- **Event Exceptions** (`event_exceptions`) — events received with an unrecognised event type, auto-recorded by `JournalEventService` for admins to review.

Adoons (hiveops-ai) rule suggestions are an optional assist — see the Architect tab for the async pipeline.

## Roles required

Read operations (list rules, drafts, audit, exceptions, poll suggestions) are open to any authenticated user. **Every mutation is admin-gated** with `@PreAuthorize("hasAnyRole('MSP_ADMIN','BCOS_ADMIN')")`:

| Action | Endpoint | Role gate |
|--------|----------|-----------|
| Create rule | `POST /api/ticket-processing-rules` | MSP_ADMIN / BCOS_ADMIN |
| Create draft | `POST /api/ticket-processing-rules/drafts` | MSP_ADMIN / BCOS_ADMIN |
| Update rule | `PUT /api/ticket-processing-rules/{id}` | MSP_ADMIN / BCOS_ADMIN |
| Enable/disable | `PATCH /api/ticket-processing-rules/{id}/enabled` | MSP_ADMIN / BCOS_ADMIN |
| Approve draft | `PATCH /api/ticket-processing-rules/{id}/approve` | MSP_ADMIN / BCOS_ADMIN |
| Delete rule | `DELETE /api/ticket-processing-rules/{id}` | MSP_ADMIN / BCOS_ADMIN |
| Closing rule create/update/enable/delete | `/api/incident-closing-rules...` | MSP_ADMIN / BCOS_ADMIN |
| Dismiss exception | `DELETE /api/event-exceptions/{id}` and `.../by-type/{eventTypeRaw}` | MSP_ADMIN / BCOS_ADMIN |

Rule suggestion enqueue/poll (`/api/adoons/rule-suggestions`) is **not** admin-gated but is institution-scoped via `InstitutionContext.resolveScope()`.

## First things to check when it misbehaves

**"My rule isn't firing."**
1. Confirm the rule is **Enabled** — `findEnabledByEventType` only returns enabled rules.
2. Confirm the **event type matches exactly** — rules key on the raw `event_type` string (SCREAMING_SNAKE_CASE). If the event is arriving as an unrecognised type, it will show under **Event Exceptions**, not match any rule.
3. Check the **Text Pattern** — if set, the rule only fires when the event details *contain* that text (case-insensitive `contains`). A too-specific pattern silently blocks the rule.
4. Check **institution scope**. Institution-scoped rules win over Global, and text-pattern rules win over catch-all within the same scope. See the matching gotcha below.

**"Wrong action taken (incident suppressed that shouldn't be)."**
- `SUPPRESS` matched — look for a Global suppress rule on that event type. Rule eval decisions are logged: grep incident logs (Loki, `localhost:3100` on services VM) for `Rule eval:` and `SUPPRESS rule` lines; every match logs rule name, action, institution, and pattern.

**"Closing rule didn't resolve the incident."**
- Closing rules run in `processRecovery`, which **first** applies the built-in `RECOVERY_MAP`, then configurable closing rules. Confirm the trigger event type and that the incident's type is in the rule's `closeIncidentTypes` CSV.

**"Adoons suggestion stuck / says unavailable."**
- `GET /api/adoons/status` proxies to hiveops-ai `/actuator/health`; if `available:false`, hiveops-ai is down/unreachable — the rules screen still works, only suggestions are affected.
- Async suggestions go through Kafka. A suggestion stuck at `PENDING` means hiveops-ai never published to `adoons.rule-suggestion.ready`. A stale-sweep in `RuleSuggestionAsyncService` marks old PENDING rows; check hiveops-ai and the `adoons.rule-suggestion.requested` topic.

## Common failure modes + fixes

| Symptom | Likely cause | Fix |
|---------|-------------|-----|
| Rule mutation returns 403 | Caller is not MSP_ADMIN/BCOS_ADMIN | Use an admin JWT |
| Rule saved but never fires | Disabled, wrong event type, or over-specific text pattern | Re-check enabled flag, exact event type, and pattern |
| Institution rule ignored | ATM institution name doesn't equal the rule's institution *name* (rule stores institution **key**, resolved to name at match time — see gotcha) | Verify the institution key resolves to the ATM's institution name |
| Unknown event floods Exceptions | Agent emitting an event type with no `event_type` lookup / no rule | Create a rule or add the event type; then Dismiss the exception |
| Suggestion never returns | hiveops-ai down or Kafka topic not consumed | Check hiveops-ai health + `adoons.rule-suggestion.ready` |

## Matching gotcha (institution scope)

In `findApplicableRule`, a rule's stored `institution` value is treated as an **institution key**, resolved via `institutionKeyService.findByKey(...).getInstitutionName()` and compared to the ATM's `institution` (a **name**). If the key doesn't resolve, it falls back to comparing the raw stored value. A mismatch between what's stored (key vs name) and the ATM's institution name will cause an institution-scoped rule to silently fall through to Global. Verify with the `Rule eval:` log line, which prints the ATM institution it tried to match.

Related: [technical.incident] · [platform.service-ownership]
