///|
/// Structured operational reports for CLI output, dashboards, and archives.
/// Values remain machine-readable while headline text stays concise enough for
/// a coach or operator to act on.
pub(all) enum ReportSectionKind {
ReportOverview
ReportQuality
ReportRecovery
ReportTraining
ReportForecast
ReportDecision
ReportActions
} derive(FromJson, ToJson, Debug, Eq)
///|
pub(all) struct OperationalReportMetric {
key : String
label : String
value : Double
unit : String
status : String
confidence : Double
} derive(FromJson, ToJson, Debug, Eq)
///|
pub(all) struct OperationalReportSection {
kind : ReportSectionKind
title : String
summary : String
metrics : Array[OperationalReportMetric]
rows : Array[Array[String]]
warnings : Array[String]
} derive(FromJson, ToJson, Debug, Eq)
///|
pub(all) struct OperationalReport {
report_id : String
generated_at : String
subject_id : String
headline : String
overall_score : Double
confidence : Double
sections : Array[OperationalReportSection]
feature_vector : Array[Double]
warnings : Array[String]
} derive(FromJson, ToJson, Debug, Eq)
///|
pub fn report_section_name(kind : ReportSectionKind) -> String {
match kind {
ReportOverview => "overview"
ReportQuality => "quality"
ReportRecovery => "recovery"
ReportTraining => "training"
ReportForecast => "forecast"
ReportDecision => "decision"
ReportActions => "actions"
}
}
///|
fn report_bound(value : Double, low : Double, high : Double) -> Double {
if value.is_nan() || value.is_inf() {
low
} else {
value.clamp(min=low, max=high)
}
}
///|
pub fn report_metric(
key : String,
label : String,
value : Double,
unit : String,
status : String,
confidence : Double,
) -> OperationalReportMetric {
{
key,
label,
value,
unit,
status,
confidence: report_bound(confidence, 0.0, 1.0),
}
}
///|
pub fn report_section(
kind : ReportSectionKind,
title : String,
summary : String,
metrics : Array[OperationalReportMetric],
rows : Array[Array[String]],
warnings : Array[String],
) -> OperationalReportSection {
{ kind, title, summary, metrics, rows, warnings }
}
///|
pub fn report_overview_section(
report : AnalysisReport,
gate : QualityGateResult,
) -> OperationalReportSection {
report_section(
ReportOverview,
"Analysis overview",
"End-to-end HRV analysis and quality gate summary.",
[
report_metric(
"raw_count",
"Raw intervals",
report.raw_count.to_double(),
"beats",
"observed",
1.0,
),
report_metric(
"clean_count",
"Clean intervals",
report.cleaned_intervals.length().to_double(),
"beats",
"observed",
gate.score,
),
report_metric(
"mean_rr",
"Mean RR",
report.metrics.mean_rr,
"ms",
"observed",
gate.score,
),
report_metric(
"rmssd",
"RMSSD",
report.metrics.rmssd,
"ms",
"observed",
gate.score,
),
report_metric(
"quality",
"Quality score",
gate.score,
"ratio",
if gate.passed {
"pass"
} else {
"fail"
},
gate.score,
),
],
[],
gate.reasons,
)
}
///|
pub fn report_recovery_section(
report : LongitudinalRecoveryReport,
) -> OperationalReportSection {
let rows = []
for assessment in report.assessments {
rows.push([
assessment.record.date,
assessment.readiness_score.to_string(),
recovery_status_name(assessment.status),
assessment.confidence.to_string(),
])
}
report_section(
ReportRecovery,
"Recovery trend",
recovery_report_message(report),
[
report_metric(
"current_score",
"Current readiness",
report.current_score,
"score",
recovery_status_name(report.current_status),
report.quality_ratio,
),
report_metric(
"quality_ratio",
"Usable-day ratio",
report.quality_ratio,
"ratio",
"observed",
report.quality_ratio,
),
report_metric(
"missing_days",
"Missing days",
report.missing_days.to_double(),
"days",
if report.missing_days > 0 {
"watch"
} else {
"complete"
},
1.0,
),
report_metric(
"stable_streak",
"Stable streak",
report.stable_streak.to_double(),
"days",
"observed",
report.quality_ratio,
),
],
rows,
if report.trajectory == RecoveryWorsening {
["Recovery trend is worsening."]
} else {
[]
},
)
}
///|
pub fn report_training_section(
plan : TrainingLoadPlan,
) -> OperationalReportSection {
let rows = []
for day in plan.days {
rows.push([
day.date,
day.effective_load.to_string(),
day.duration_minutes.to_string(),
day.quality_ratio.to_string(),
])
}
report_section(
ReportTraining,
"Training load",
load_plan_recovery_message(plan),
[
report_metric(
"acute_load",
"Acute load",
plan.profile.acute_load,
"load",
"observed",
load_plan_quality(plan),
),
report_metric(
"chronic_load",
"Chronic load",
plan.profile.chronic_load,
"load",
"reference",
load_plan_quality(plan),
),
report_metric(
"load_ratio",
"Acute/chronic ratio",
plan.profile.acute_chronic_ratio,
"ratio",
if plan.profile.acute_chronic_ratio > 1.30 {
"warning"
} else {
"stable"
},
load_plan_quality(plan),
),
report_metric(
"strain",
"Strain",
plan.profile.strain,
"load",
"observed",
load_plan_quality(plan),
),
],
rows,
if plan.alerts.length() > 0 {
[load_plan_recovery_message(plan)]
} else {
[]
},
)
}
///|
pub fn report_decision_section(plan : DecisionPlan) -> OperationalReportSection {
let rows = []
for action in plan.actions {
rows.push([
action.priority.to_string(),
action.title,
action.intensity_ceiling.to_string(),
action.requires_recheck.to_string(),
])
}
report_section(
ReportDecision,
"Decision support",
plan.headline,
[
report_metric(
"decision_score",
"Decision score",
plan.score,
"score",
decision_severity_name(plan.level),
plan.confidence,
),
report_metric(
"risk_score",
"Risk score",
decision_plan_risk_score(plan),
"ratio",
decision_severity_name(plan.level),
plan.confidence,
),
report_metric(
"intensity_ceiling",
"Intensity ceiling",
decision_plan_intensity_ceiling(plan),
"ratio",
"recommended",
plan.confidence,
),
],
rows,
plan.findings.map(finding => finding.evidence),
)
}
///|
pub fn report_forecast_section(
bundle : ForecastBundle,
) -> OperationalReportSection {
report_section(
ReportForecast,
"Forecast",
bundle.recommendation,
[
report_metric(
"recovery_slope",
"Recovery slope",
bundle.recovery.slope,
"score/day",
if bundle.recovery.slope < 0.0 {
"declining"
} else {
"stable"
},
bundle.recovery.coverage,
),
report_metric(
"load_slope",
"Load slope",
bundle.load.slope,
"load/day",
if bundle.load.slope > 5.0 {
"rising"
} else {
"stable"
},
bundle.load.coverage,
),
report_metric(
"forecast_mae",
"Holdout MAE",
bundle.backtest.mean_absolute_error,
"score",
if bundle.backtest.stable {
"stable"
} else {
"watch"
},
bundle.recovery.coverage,
),
report_metric(
"directional_accuracy",
"Directional accuracy",
bundle.backtest.directional_accuracy,
"ratio",
"backtest",
bundle.recovery.coverage,
),
],
[],
if !bundle.backtest.stable {
[
"Forecast error is high; use the interval rather than the point estimate.",
]
} else {
[]
},
)
}
///|
pub fn report_action_section(
actions : Array[DecisionAction],
) -> OperationalReportSection {
let rows = []
for action in actions {
rows.push([
action.priority.to_string(),
action.title,
action.instruction,
action.duration_minutes.to_string(),
action.intensity_ceiling.to_string(),
])
}
report_section(
ReportActions,
"Recommended actions",
"Prioritized actions emitted by the decision layer.",
[],
rows,
[],
)
}
///|
fn report_section_append(
sections : Array[OperationalReportSection],
section : OperationalReportSection,
) -> Unit {
sections.push(section)
}
///|
pub fn build_operational_report(
report_id : String,
generated_at : String,
subject_id : String,
analysis : AnalysisReport?,
gate : QualityGateResult,
recovery : LongitudinalRecoveryReport?,
training : TrainingLoadPlan?,
forecast : ForecastBundle?,
decision : DecisionPlan?,
) -> OperationalReport {
let sections = []
let warnings = []
match analysis {
Some(value) =>
report_section_append(sections, report_overview_section(value, gate))
None => warnings.push("analysis report is unavailable")
}
match recovery {
Some(value) =>
report_section_append(sections, report_recovery_section(value))
None => warnings.push("longitudinal recovery is unavailable")
}
match training {
Some(value) =>
report_section_append(sections, report_training_section(value))
None => warnings.push("training load is unavailable")
}
match forecast {
Some(value) =>
report_section_append(sections, report_forecast_section(value))
None => warnings.push("forecast is unavailable")
}
match decision {
Some(value) => {
report_section_append(sections, report_decision_section(value))
report_section_append(sections, report_action_section(value.actions))
}
None => warnings.push("decision support is unavailable")
}
let score = match decision {
Some(value) => value.score
None => if gate.passed { gate.score * 100.0 } else { gate.score * 50.0 }
}
let confidence = match decision {
Some(value) => value.confidence
None => gate.score
}
let features = []
features.push(score)
features.push(confidence)
features.push(gate.score)
features.push(sections.length().to_double())
match recovery {
Some(value) =>
for feature in recovery_report_feature_vector(value) {
features.push(feature)
}
None => ()
}
match training {
Some(value) =>
for feature in load_plan_feature_vector(value) {
features.push(feature)
}
None => ()
}
{
report_id,
generated_at,
subject_id,
headline: match decision {
Some(value) => value.headline
None => "Operational report generated with limited context."
},
overall_score: report_bound(score, 0.0, 100.0),
confidence: report_bound(confidence, 0.0, 1.0),
sections,
feature_vector: features,
warnings,
}
}
///|
pub fn operational_report_is_usable(report : OperationalReport) -> Bool {
report.sections.length() >= 2 &&
report.overall_score >= 0.0 &&
report.overall_score <= 100.0 &&
report.confidence >= 0.0
}
///|
pub fn operational_report_feature_vector(
report : OperationalReport,
) -> Array[Double] {
let result = []
for value in report.feature_vector {
result.push(value)
}
result.push(report.overall_score)
result.push(report.confidence)
result.push(report.warnings.length().to_double())
result
}
///|
pub fn operational_report_to_csv(report : OperationalReport) -> String {
let grid = [
["section", "metric", "label", "value", "unit", "status", "confidence"],
]
for section in report.sections {
for metric in section.metrics {
grid.push([
report_section_name(section.kind),
metric.key,
metric.label,
metric.value.to_string(),
metric.unit,
metric.status,
metric.confidence.to_string(),
])
}
}
to_csv(grid)
}
///|
pub fn operational_report_rows_csv(report : OperationalReport) -> String {
let grid = [["section", "title", "row"]]
for section in report.sections {
for row in section.rows {
grid.push([
report_section_name(section.kind),
section.title,
row.join("|"),
])
}
}
to_csv(grid)
}
///|
pub fn operational_report_markdown(report : OperationalReport) -> String {
let builder = StringBuilder::new()
builder.write_string("# ")
builder.write_string(report.headline)
builder.write_string("\n\n")
builder.write_string("Score: ")
builder.write_string(report.overall_score.to_string())
builder.write_string(" Confidence: ")
builder.write_string(report.confidence.to_string())
builder.write_string("\n\n")
for section in report.sections {
builder.write_string("## ")
builder.write_string(section.title)
builder.write_string("\n\n")
builder.write_string(section.summary)
builder.write_string("\n\n")
for metric in section.metrics {
builder.write_string("- ")
builder.write_string(metric.label)
builder.write_string(": ")
builder.write_string(metric.value.to_string())
builder.write_string(" ")
builder.write_string(metric.unit)
builder.write_string("\n")
}
builder.write_string("\n")
}
builder.to_string()
}
///|
pub fn operational_report_section(
report : OperationalReport,
kind : ReportSectionKind,
) -> OperationalReportSection? {
for section in report.sections {
if section.kind == kind {
return Some(section)
}
}
None
}
///|
pub fn operational_report_warning_count(report : OperationalReport) -> Int {
let mut count = report.warnings.length()
for section in report.sections {
count += section.warnings.length()
}
count
}
///|
pub fn operational_report_headline(report : OperationalReport) -> String {
"\{report.headline} score=\{report.overall_score.to_string()} confidence=\{report.confidence.to_string()}"
}