///|
/// Severity used by an application-facing quality alert.
pub(all) enum AlertSeverity {
Info
Warning
Critical
} derive(Debug, Eq, ToJson)
///|
/// A structured alert that can be handed to a dashboard or work-order system.
pub(all) struct QualityAlert {
severity : AlertSeverity
code : String
message : String
index : Int
value : Double?
} derive(Debug, ToJson)
///|
/// A bounded observation window for repeatable batch reviews.
pub(all) struct QualityWindow {
id : String
values : Array[Double]
specification : Specification?
} derive(Debug, ToJson)
///|
pub fn QualityWindow::new(
id~ : String,
values~ : Array[Double],
specification~ : Specification?,
) -> QualityWindow {
{ id, values, specification }
}
///|
/// Create a window from a subgroup collection while preserving the first batch id.
pub fn window_from_groups(
groups : Array[Subgroup],
specification? : Specification,
) -> QualityWindow? {
if groups.length() == 0 {
None
} else {
Some({ id: groups[0].batch, values: flatten(groups), specification })
}
}
///|
/// Evaluate one window using limits, robust outliers, and specification defects.
pub fn evaluate_window(window : QualityWindow) -> Array[QualityAlert] {
let alerts : Array[QualityAlert] = []
if window.values.length() == 0 {
alerts.push({
severity: Critical,
code: "EMPTY_WINDOW",
message: "quality window has no measurements",
index: -1,
value: None,
})
return alerts
}
let center = mean_of(window.values)
let deviation = std_of(window.values, center)
for index, value in window.values {
if deviation > 0.0 && (value - center).abs() > 3.0 * deviation {
alerts.push({
severity: Critical,
code: "THREE_SIGMA",
message: "measurement exceeds three-sigma limit",
index,
value: Some(value),
})
}
}
match window.specification {
Some(spec) =>
for index, value in window.values {
if value < spec.lower || value > spec.upper {
alerts.push({
severity: Critical,
code: "OUT_OF_SPEC",
message: "measurement is outside specification",
index,
value: Some(value),
})
}
}
None => ()
}
match iqr_outliers(window.values, 1.5) {
Some(flags) =>
for index, flag in flags {
if flag {
alerts.push({
severity: Warning,
code: "IQR_OUTLIER",
message: "measurement is an interquartile-range outlier",
index,
value: Some(window.values[index]),
})
}
}
None => ()
}
let run = longest_run(window.values, center)
if run >= 8 {
alerts.push({
severity: Warning,
code: "LONG_RUN",
message: "eight measurements remain on one side of center",
index: window.values.length() - run,
value: None,
})
}
alerts
}
///|
/// Compare two windows and return a change alert when the center shifts.
pub fn compare_windows(
previous : QualityWindow,
current : QualityWindow,
threshold : Double,
) -> QualityAlert? {
if previous.values.length() == 0 ||
current.values.length() == 0 ||
threshold < 0.0 {
None
} else {
let old_center = mean_of(previous.values)
let new_center = mean_of(current.values)
let old_deviation = std_of(previous.values, old_center)
let score = if old_deviation == 0.0 {
if old_center == new_center {
0.0
} else {
threshold + 1.0
}
} else {
(new_center - old_center).abs() / old_deviation
}
if score >= threshold {
Some({
severity: if score >= threshold * 2.0 {
Critical
} else {
Warning
},
code: "CENTER_SHIFT",
message: "window center shifted from baseline",
index: -1,
value: Some(new_center),
})
} else {
None
}
}
}
///|
/// Summarize multiple windows into their means.
pub fn window_means(windows : Array[QualityWindow]) -> Array[Double] {
let result : Array[Double] = []
for window in windows {
if window.values.length() > 0 {
result.push(mean_of(window.values))
}
}
result
}
///|
/// Summarize multiple windows into their sample deviations.
pub fn window_deviations(windows : Array[QualityWindow]) -> Array[Double] {
let result : Array[Double] = []
for window in windows {
if window.values.length() > 1 {
result.push(std_of(window.values, mean_of(window.values)))
}
}
result
}
///|
/// Return a deterministic count of critical alerts.
pub fn critical_alert_count(alerts : Array[QualityAlert]) -> Int {
let mut count = 0
for alert in alerts {
if alert.severity == Critical {
count += 1
}
}
count
}
///|
/// Return a deterministic count of warnings and critical alerts.
pub fn actionable_alert_count(alerts : Array[QualityAlert]) -> Int {
let mut count = 0
for alert in alerts {
if alert.severity != Info {
count += 1
}
}
count
}
///|
/// Group alerts by their stable machine-readable code.
pub fn alert_codes(alerts : Array[QualityAlert]) -> Array[String] {
let result : Array[String] = []
for alert in alerts {
let mut exists = false
for code in result {
if code == alert.code {
exists = true
}
}
if !exists {
result.push(alert.code)
}
}
result
}
///|
/// Build independent windows from a flat sequence.
pub fn windows_from_values(
values : Array[Double],
width : Int,
specification? : Specification,
) -> Array[QualityWindow]? {
match subgroup(values, width) {
None => None
Some(groups) => {
let result : Array[QualityWindow] = []
for group in groups {
result.push({ id: "window", values: group, specification })
}
Some(result)
}
}
}
///|
/// Evaluate all windows and attach their local index to generated alerts.
pub fn evaluate_windows(windows : Array[QualityWindow]) -> Array[QualityAlert] {
let result : Array[QualityAlert] = []
for window in windows {
for alert in evaluate_window(window) {
result.push(alert)
}
}
result
}
///|
/// A compact scorecard useful for a status badge or release report.
pub(all) struct Scorecard {
observations : Int
windows : Int
alerts : Int
critical : Int
defect_rate : Double?
center : Double?
deviation : Double?
} derive(Debug, ToJson)
///|
pub fn scorecard(windows : Array[QualityWindow]) -> Scorecard {
let values : Array[Double] = []
let mut specification : Specification? = None
for window in windows {
for value in window.values {
values.push(value)
}
match (specification, window.specification) {
(None, Some(spec)) => specification = Some(spec)
_ => ()
}
}
let alerts = evaluate_windows(windows)
let center = if values.length() == 0 { None } else { Some(mean_of(values)) }
let deviation = if values.length() < 2 {
None
} else {
Some(std_of(values, mean_of(values)))
}
let defect_rate = match specification {
Some(spec) => defect_rate(values, spec)
None => None
}
{
observations: values.length(),
windows: windows.length(),
alerts: alerts.length(),
critical: critical_alert_count(alerts),
defect_rate,
center,
deviation,
}
}
///|
/// Return only windows whose mean is outside the supplied engineering band.
pub fn filter_shifted_windows(
windows : Array[QualityWindow],
lower : Double,
upper : Double,
) -> Array[QualityWindow] {
let result : Array[QualityWindow] = []
if lower <= upper {
for window in windows {
if window.values.length() > 0 {
let center = mean_of(window.values)
if center < lower || center > upper {
result.push(window)
}
}
}
}
result
}
///|
/// Return the first window with an actionable alert.
pub fn first_actionable_window(windows : Array[QualityWindow]) -> Int? {
for index, window in windows {
if actionable_alert_count(evaluate_window(window)) > 0 {
return Some(index)
}
}
None
}