fix(sla): validate SLA target hours (non-negative, <=2dp, first_response<=resolution) (PMS-338) #255
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/PMS-338-sla-target-validation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Background
UpsertSlaTargetRequestinsrc/modules/sla/models.rsaccepted anyfirst_response_hours/resolution_hours(bothOption<Decimal>, DECIMAL(10,2) in the DB) with no validation at any layer: negative or zero hours, more than two decimal places, and an inverted pair (first-response deadline later than resolution) all passed through.Goal
Reject incoherent SLA targets with a 422 at the request layer.
Proposed approach
Add
validate_sla_target_hoursinsrc/utils/validation.rs, mirroring the budget rule (validate_budget_hours) but requiring a strictly-positive value. A blank/Nonefield already means "no target", so a stored0(an instantaneous deadline) is never the intent and is rejected; the validator also enforces at most two decimal places and the DECIMAL(10,2) magnitude bound. It is applied to both hours fields via#[validate(custom(...))]; onOption<Decimal>the validator runs on the inner value and skipsNone.Add a schema-level
#[validate(schema(function = validate_sla_target_range))]on the struct (mirroringvalidate_invoice_date_range's shape) that, when both hours areSome, rejectsfirst_response_hours > resolution_hours.Assumption (documented inline): strictly-positive hours required; blank/None means "no target".
Alternatives considered
Allowing zero hours was rejected as it encodes an instantaneous deadline that no SLA intends;
Nonealready expresses "no target". A DB-level CHECK alone was rejected because it would surface as a 500 rather than a 422.Acceptance criteria
validate_sla_target_hoursadded tosrc/utils/validation.rs(strictly-positive, <=2dp, DECIMAL(10,2) bound).first_response_hoursandresolution_hoursonUpsertSlaTargetRequest.validate_sla_target_rangerejectsfirst_response_hours > resolution_hourswhen both are present.cargo fmt --all --check,cargo test --lib, andcargo clippy --all-targets -- -D warningspass.