ADR-010 — Rule Severity Levels
ADR-010 — Rule Severity Levels
Sección titulada «ADR-010 — Rule Severity Levels»Accepted
Context
Sección titulada «Context»The business rules engine needs a severity classification for validation outcomes. Four levels were initially considered — BLOCKING, ERROR, WARNING, INFO — but ERROR occupies an ambiguous middle ground: “serious issue, operation may proceed but is flagged.” In practice, a rule either prevents the operation (BLOCKING) or it doesn’t (WARNING/INFO). ERROR conflates domain validation with technical failures, which already have their own channel (Python exceptions, HTTP status codes, application logging).
Additionally, BLOCKING serves a specific role in the FSM: it is the product of business logic evaluation against domain constraints (e.g., Argentine labor law caps on weekly hours; see [[adr-021-argentine-legal-context|ADR-021]]). This is fundamentally different from a technical error, which represents an uncaptured or unexpected failure condition.
Decision
Sección titulada «Decision»Three severity levels are defined for business rules: BLOCKING, WARNING, and INFO. The ERROR level is excluded. ERROR occupies an ambiguous middle ground that conflates domain validation with technical failures; since a rule either prevents the operation or it doesn’t, ERROR adds no value and is dropped. The three retained levels map cleanly to FSM behavior and user-facing feedback.
| Severity | Behavior | FSM effect | Example |
|---|---|---|---|
BLOCKING | Prevents the operation entirely | FSM rejects the transition | MAX_WEEKLY_HOURS: employee would exceed legal weekly hour cap |
WARNING | Advisory — operation proceeds, violation is logged and surfaced to the user | FSM allows the transition | MAX_CONSECUTIVE_SHIFTS: employee approaching consecutive-day limit |
INFO | Informational — logged for audit trail only, not surfaced as an alert | No FSM effect | Employee approaching contract renewal date |
Key distinction — “you cannot” vs “something went wrong”: Domain severity levels and technical errors must not share an enum. BLOCKING, WARNING, and INFO are intentional, predictable outcomes of evaluating domain rules — the system knows exactly why the result occurred and can explain it to the user. Technical errors (database failures, network timeouts, unhandled exceptions) are unexpected conditions that surface through Python exceptions, HTTP 4xx/5xx responses, and structured logging — never through rule severity. Mixing the two produces ambiguous UX (“is this my fault or the system’s?”) and ambiguous code (“should I catch this or validate against it?”).
Consequences
Sección titulada «Consequences»- The
RuleSeverityenum in Python has exactly three members:BLOCKING,WARNING,INFO. OVERTIME_LIMITisWARNINGby default — the operation proceeds but the violation is flagged. Tenants can escalate it toBLOCKINGvia rule configuration.- Frontend displays BLOCKING as a hard stop (e.g.,
p-message severity='error'), WARNING as an advisory (p-message severity='warn'), and INFO as informational (p-message severity='info'). The PrimeNG severity mapping is intentionally different from the domain enum name —BLOCKINGrenders aserrorin PrimeNG because it is the most severe domain outcome, not because it is a technical error.