///|
/// Program-wide quality and coverage summary.
pub(all) struct ProgramSummary {
feature_count : Int
observed_feature_count : Int
pass_count : Int
fail_count : Int
unmeasured_count : Int
coverage : Double
pass_rate : Double
defect_rate : Double
mean_cpk : Double
minimum_cpk : Double
high_risk_count : Int
warning_count : Int
}
///|
fn program_feature_observed(
feature : Feature,
observations : Array[Observation],
) -> Bool {
observations_for(feature~, observations~).length() > 0
}
///|
/// Aggregate all planned features and their observations.
pub fn summarize_program(
features~ : Array[Feature],
observations~ : Array[Observation],
plan~ : MeasurementPlan,
) -> ProgramSummary {
let mut observed_feature_count = 0
let mut pass_count = 0
let mut fail_count = 0
let mut unmeasured_count = 0
let mut high_risk_count = 0
let mut cpk_total = 0.0
let mut minimum_cpk = 0.0
let mut first_cpk = true
for feature in features {
if program_feature_observed(feature, observations) {
observed_feature_count += 1
}
let analysis = analyze_observations(
feature~,
observations~,
uncertainty=0.0,
)
pass_count += analysis.summary.pass_count
fail_count += analysis.summary.fail_count
if analysis.count == 0 {
unmeasured_count += 1
}
if analysis_risk(analysis) == RiskLevel::High {
high_risk_count += 1
}
let cpk = analysis.summary.capability.cpk
cpk_total += cpk
if first_cpk {
minimum_cpk = cpk
first_cpk = false
} else if cpk < minimum_cpk {
minimum_cpk = cpk
}
}
let feature_count = features.length()
let pass_rate = if observed_feature_count == 0 {
0.0
} else {
pass_count.to_double() / (pass_count + fail_count).to_double()
}
let defect_rate = if pass_count + fail_count == 0 {
0.0
} else {
fail_count.to_double() / (pass_count + fail_count).to_double()
}
let mean_cpk = if feature_count == 0 {
0.0
} else {
cpk_total / feature_count.to_double()
}
{
feature_count,
observed_feature_count,
pass_count,
fail_count,
unmeasured_count,
coverage: plan.summary.coverage,
pass_rate,
defect_rate,
mean_cpk,
minimum_cpk,
high_risk_count,
warning_count: plan.summary.warnings.length(),
}
}
///|
/// Return whether a program is acceptable for offline release.
pub fn program_is_acceptable(summary : ProgramSummary) -> Bool {
summary.feature_count > 0 &&
summary.fail_count == 0 &&
summary.unmeasured_count == 0 &&
summary.coverage >= 1.0 &&
summary.warning_count == 0
}
///|
/// Return the pass rate for a program summary.
pub fn program_pass_rate(summary : ProgramSummary) -> Double {
summary.pass_rate
}
///|
/// Return the defect rate for a program summary.
pub fn program_defect_rate(summary : ProgramSummary) -> Double {
summary.defect_rate
}
///|
/// Return the count of all classified observations.
pub fn program_observation_count(summary : ProgramSummary) -> Int {
summary.pass_count + summary.fail_count
}
///|
/// Return whether a program has any unmeasured features.
pub fn program_has_unmeasured(summary : ProgramSummary) -> Bool {
summary.unmeasured_count > 0
}
///|
/// Return the Cpk gap to the common 1.33 target.
pub fn program_cpk_margin(summary : ProgramSummary) -> Double {
summary.minimum_cpk - 1.33
}
///|
/// Return the number of features with high operational risk.
pub fn program_high_risk_count(summary : ProgramSummary) -> Int {
summary.high_risk_count
}
///|
/// Return a compact program status label.
pub fn program_status(summary : ProgramSummary) -> String {
if program_is_acceptable(summary) {
"acceptable"
} else if summary.fail_count > 0 {
"failed"
} else if summary.unmeasured_count > 0 {
"incomplete"
} else {
"review"
}
}