///|
pub(all) enum EscalationTier {
Routine
Review
Urgent
Immediate
} derive(Debug, Eq)
///|
pub(all) enum EvidenceStatus {
EvidenceComplete
EvidencePartial
EvidenceMissing
EvidenceInvalid
} derive(Debug, Eq)
///|
pub(all) struct PathwayRule {
code : String
title : String
tier : EscalationTier
required_instruments : Array[String]
minimum_severity : Severity
rationale : String
} derive(Debug, Eq)
///|
pub(all) struct PathwayDecision {
tier : EscalationTier
evidence : EvidenceStatus
matched_rules : Array[String]
missing_instruments : Array[String]
highest_severity : Severity
score_count : Int
explanation : String
} derive(Debug, Eq)
///|
pub fn escalation_tier_label(tier : EscalationTier) -> String {
match tier {
Routine => "routine"
Review => "review"
Urgent => "urgent"
Immediate => "immediate"
}
}
///|
pub fn evidence_status_label(status : EvidenceStatus) -> String {
match status {
EvidenceComplete => "complete"
EvidencePartial => "partial"
EvidenceMissing => "missing"
EvidenceInvalid => "invalid"
}
}
///|
pub fn severity_rank(severity : Severity) -> Int {
match severity {
Low => 0
Medium => 1
High => 2
Critical => 3
}
}
///|
pub fn escalation_rank(tier : EscalationTier) -> Int {
match tier {
Routine => 0
Review => 1
Urgent => 2
Immediate => 3
}
}
///|
pub fn max_tier(
left : EscalationTier,
right : EscalationTier,
) -> EscalationTier {
if escalation_rank(left) >= escalation_rank(right) {
left
} else {
right
}
}
///|
pub fn max_pathway_severity(left : Severity, right : Severity) -> Severity {
if severity_rank(left) >= severity_rank(right) {
left
} else {
right
}
}
///|
pub fn instrument_present(reports : Array[ScoreReport], name : String) -> Bool {
for report in reports {
if report.instrument == name {
return true
}
}
false
}
///|
pub fn reports_highest_severity(reports : Array[ScoreReport]) -> Severity {
let mut highest = Low
for report in reports {
highest = max_pathway_severity(highest, report.severity)
}
highest
}
///|
pub fn reports_have_invalid_score(reports : Array[ScoreReport]) -> Bool {
for report in reports {
if report.score < 0 {
return true
}
}
false
}
///|
pub fn pathway_rule_matches(
rule : PathwayRule,
reports : Array[ScoreReport],
) -> Bool {
if severity_rank(reports_highest_severity(reports)) <
severity_rank(rule.minimum_severity) {
false
} else {
for instrument in rule.required_instruments {
if !instrument_present(reports, instrument) {
return false
}
}
true
}
}
///|
pub fn pathway_missing_instruments(
rule : PathwayRule,
reports : Array[ScoreReport],
) -> Array[String] {
let missing = []
for instrument in rule.required_instruments {
if !instrument_present(reports, instrument) {
missing.push(instrument)
}
}
missing
}
///|
pub fn pathway_rule_labels(rules : Array[PathwayRule]) -> Array[String] {
rules.map(fn(rule) { rule.code + ": " + rule.title })
}
///|
pub fn evaluate_pathway(
rules : Array[PathwayRule],
reports : Array[ScoreReport],
) -> PathwayDecision {
let mut tier = Routine
let matched = []
let missing = []
for rule in rules {
if pathway_rule_matches(rule, reports) {
tier = max_tier(tier, rule.tier)
matched.push(rule.code + ": " + rule.rationale)
} else {
let rule_missing = pathway_missing_instruments(rule, reports)
for item in rule_missing {
if !missing.contains(item) {
missing.push(item)
}
}
}
}
let evidence = if reports_have_invalid_score(reports) {
EvidenceInvalid
} else if reports.length() == 0 {
EvidenceMissing
} else if missing.length() > 0 {
EvidencePartial
} else {
EvidenceComplete
}
let highest = reports_highest_severity(reports)
let explanation = pathway_decision_explanation(
tier,
evidence,
highest,
matched.length(),
)
{
tier,
evidence,
matched_rules: matched,
missing_instruments: missing,
highest_severity: highest,
score_count: reports.length(),
explanation,
}
}
///|
pub fn pathway_decision_explanation(
tier : EscalationTier,
evidence : EvidenceStatus,
severity : Severity,
matched_count : Int,
) -> String {
escalation_tier_label(tier) +
" tier; evidence=" +
evidence_status_label(evidence) +
"; highest=" +
severity_label(severity) +
"; matched_rules=" +
matched_count.to_string()
}
///|
pub fn render_pathway_decision(decision : PathwayDecision) -> String {
let matched = decision.matched_rules.join(" | ")
let missing = decision.missing_instruments.join(",")
"tier=" +
escalation_tier_label(decision.tier) +
"; evidence=" +
evidence_status_label(decision.evidence) +
"; highest=" +
severity_label(decision.highest_severity) +
"; scores=" +
decision.score_count.to_string() +
"; matched=[" +
matched +
"]; missing=[" +
missing +
"]; " +
decision.explanation
}
///|
pub(all) struct AuditEvent {
sequence : Int
event_type : String
instrument : String
score : Int
severity : Severity
timestamp_minutes : Int
source : String
note : String
} derive(Debug, Eq)
///|
pub fn audit_event(
sequence : Int,
event_type : String,
instrument : String,
report : ScoreReport,
timestamp_minutes : Int,
source : String,
note : String,
) -> AuditEvent {
{
sequence,
event_type,
instrument,
score: report.score,
severity: report.severity,
timestamp_minutes,
source,
note,
}
}
///|
pub fn validate_audit_event(event : AuditEvent) -> ValidationError? {
match validate_range("sequence", event.sequence, 0, 1000000000) {
Some(err) => Some(err)
None =>
match
validate_range(
"timestamp_minutes",
event.timestamp_minutes,
0,
1000000000,
) {
Some(err) => Some(err)
None => validate_range("score", event.score, 0, 1000000000)
}
}
}
///|
pub fn audit_event_label(event : AuditEvent) -> String {
event.sequence.to_string() +
"@" +
event.timestamp_minutes.to_string() +
" " +
event.event_type +
" " +
event.instrument +
" score=" +
event.score.to_string() +
" severity=" +
severity_label(event.severity) +
" source=" +
event.source
}
///|
pub fn audit_ordered(left : AuditEvent, right : AuditEvent) -> Bool {
if left.sequence == right.sequence {
left.timestamp_minutes <= right.timestamp_minutes
} else {
left.sequence < right.sequence
}
}
///|
pub fn sort_audit_events(events : Array[AuditEvent]) -> Array[AuditEvent] {
let sorted = events.copy()
for index = 1; index < sorted.length(); index = index + 1 {
let current = sorted[index]
let mut cursor = index
while cursor > 0 && !audit_ordered(sorted[cursor - 1], current) {
sorted[cursor] = sorted[cursor - 1]
cursor = cursor - 1
}
sorted[cursor] = current
}
sorted
}
///|
pub fn audit_event_labels(events : Array[AuditEvent]) -> Array[String] {
sort_audit_events(events).map(audit_event_label)
}
///|
pub(all) struct TraceSummary {
event_count : Int
unique_instruments : Int
first_timestamp : Int?
last_timestamp : Int?
invalid_event_count : Int
source_labels : Array[String]
} derive(Debug, Eq)
///|
pub fn trace_summary(events : Array[AuditEvent]) -> TraceSummary {
let ordered = sort_audit_events(events)
let instruments = []
let sources = []
let mut invalid = 0
for event in ordered {
if !instruments.contains(event.instrument) {
instruments.push(event.instrument)
}
if !sources.contains(event.source) {
sources.push(event.source)
}
if validate_audit_event(event) is Some(_) {
invalid += 1
}
}
let first_timestamp : Int? = if ordered.length() == 0 {
None
} else {
Some(ordered[0].timestamp_minutes)
}
let last_timestamp : Int? = if ordered.length() == 0 {
None
} else {
Some(ordered[ordered.length() - 1].timestamp_minutes)
}
{
event_count: events.length(),
unique_instruments: instruments.length(),
first_timestamp,
last_timestamp,
invalid_event_count: invalid,
source_labels: sources,
}
}
///|
pub fn render_trace_summary(summary : TraceSummary) -> String {
let first = match summary.first_timestamp {
Some(value) => value.to_string()
None => "none"
}
let last = match summary.last_timestamp {
Some(value) => value.to_string()
None => "none"
}
"events=" +
summary.event_count.to_string() +
"; instruments=" +
summary.unique_instruments.to_string() +
"; first=" +
first +
"; last=" +
last +
"; invalid=" +
summary.invalid_event_count.to_string() +
"; sources=" +
summary.source_labels.join(",")
}