///|
pub(all) enum CancellationCheck {
CancelledOutcome
CancellationEvent
PartialRecordPersisted
StageBoundaryPreserved
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) enum CancellationStatus {
Pass
NeedsWork
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct CancellationFinding {
run_id : @domain.RunId
check : CancellationCheck
status : CancellationStatus
path : String
message : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct CancellationReport {
run_id : @domain.RunId
ready : Bool
cancel_phase : @routine.RoutinePhase?
artifact_count : Int
findings : Array[CancellationFinding]
summary : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub fn cancellation_finding(
run_id : @domain.RunId,
check : CancellationCheck,
status : CancellationStatus,
path : String,
message : String,
) -> CancellationFinding {
{ run_id, check, status, path, message }
}
///|
fn cancellation_phase(
result : @orchestration.TwoStageRoutineResult,
) -> @routine.RoutinePhase? {
for event in result.events {
if event.kind is RoutineCancelled {
return Some(event.phase)
}
}
None
}
///|
fn outcome_finding(
result : @orchestration.TwoStageRoutineResult,
) -> CancellationFinding {
if result.outcome is Cancelled &&
result.failure_kind is Some(OperatorCancelled) {
cancellation_finding(
result.request.run_id,
CancelledOutcome,
Pass,
"two-stage-routine-result.outcome",
"routine terminates as an operator cancellation",
)
} else {
cancellation_finding(
result.request.run_id,
CancelledOutcome,
NeedsWork,
"two-stage-routine-result.outcome",
"routine result is not an operator cancellation",
)
}
}
///|
fn event_finding(
result : @orchestration.TwoStageRoutineResult,
phase : @routine.RoutinePhase?,
) -> CancellationFinding {
match phase {
Some(cancel_phase) =>
cancellation_finding(
result.request.run_id,
CancellationEvent,
Pass,
"two-stage-routine-result.events",
"routine emits cancellation event at \{cancel_phase.label()}",
)
None =>
cancellation_finding(
result.request.run_id,
CancellationEvent,
NeedsWork,
"two-stage-routine-result.events",
"routine did not emit a cancellation event",
)
}
}
///|
fn partial_record_finding(
result : @orchestration.TwoStageRoutineResult,
) -> CancellationFinding {
let has_analysis_record = result.artifact_paths.contains(
"records/analyses/\{result.request.run_id}.json",
)
if result.partial_record_available && has_analysis_record {
cancellation_finding(
result.request.run_id,
PartialRecordPersisted,
Pass,
"two-stage-routine-result.artifact_paths",
"cancelled routine preserves partial analysis record evidence",
)
} else {
cancellation_finding(
result.request.run_id,
PartialRecordPersisted,
NeedsWork,
"two-stage-routine-result.artifact_paths",
"cancelled routine does not expose a partial analysis record path",
)
}
}
///|
fn boundary_ok_for_phase(
result : @orchestration.TwoStageRoutineResult,
phase : @routine.RoutinePhase,
) -> Bool {
match phase {
Stage1Validation =>
result.record.stage1 is Some(_) &&
result.record.stage2 is None &&
result.stage2_prompt is None &&
result.stage2_model_request is None
Stage2Validation =>
result.record.stage1 is Some(_) &&
result.record.stage2 is Some(_) &&
result.stage2_model_request is Some(_)
_ => true
}
}
///|
fn boundary_finding(
result : @orchestration.TwoStageRoutineResult,
phase : @routine.RoutinePhase?,
) -> CancellationFinding {
match phase {
Some(cancel_phase) =>
if boundary_ok_for_phase(result, cancel_phase) {
cancellation_finding(
result.request.run_id,
StageBoundaryPreserved,
Pass,
"two-stage-routine-result.record",
"cancelled routine stops at the requested phase without fabricating later-stage evidence",
)
} else {
cancellation_finding(
result.request.run_id,
StageBoundaryPreserved,
NeedsWork,
"two-stage-routine-result.record",
"cancelled routine contains evidence from a later phase",
)
}
None =>
cancellation_finding(
result.request.run_id,
StageBoundaryPreserved,
NeedsWork,
"two-stage-routine-result.events",
"stage boundary cannot be checked without a cancellation phase",
)
}
}
///|
fn report_ready(findings : Array[CancellationFinding]) -> Bool {
findings.all(fn(finding) { finding.status is Pass })
}
///|
fn report_summary(report : CancellationReport) -> String {
let pass_count = report.findings.fold(init=0, fn(count, finding) {
if finding.status is Pass {
count + 1
} else {
count
}
})
if report.ready {
"cancellation report passed \{pass_count}/\{report.findings.length()} checks with \{report.artifact_count} artifact(s)"
} else {
"cancellation report has \{report.findings.length() - pass_count} check(s) needing work"
}
}
///|
pub fn prepare_cancellation_report(
result : @orchestration.TwoStageRoutineResult,
) -> CancellationReport {
let phase = cancellation_phase(result)
let findings = [
outcome_finding(result),
event_finding(result, phase),
partial_record_finding(result),
boundary_finding(result, phase),
]
let report : CancellationReport = {
run_id: result.request.run_id,
ready: report_ready(findings),
cancel_phase: phase,
artifact_count: result.artifact_paths.length(),
findings,
summary: "",
}
{ ..report, summary: report_summary(report) }
}