Ir al contenido

ADR-010 — Rule Severity Levels

Accepted

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.

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.

SeverityBehaviorFSM effectExample
BLOCKINGPrevents the operation entirelyFSM rejects the transitionMAX_WEEKLY_HOURS: employee would exceed legal weekly hour cap
WARNINGAdvisory — operation proceeds, violation is logged and surfaced to the userFSM allows the transitionMAX_CONSECUTIVE_SHIFTS: employee approaching consecutive-day limit
INFOInformational — logged for audit trail only, not surfaced as an alertNo FSM effectEmployee 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?”).

  • The RuleSeverity enum in Python has exactly three members: BLOCKING, WARNING, INFO.
  • OVERTIME_LIMIT is WARNING by default — the operation proceeds but the violation is flagged. Tenants can escalate it to BLOCKING via 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 — BLOCKING renders as error in PrimeNG because it is the most severe domain outcome, not because it is a technical error.