///|
pub(all) enum HandoffGate {
AcceptancePassed
ReadinessPassed
ComparisonReady
AppToolMounted
OperatorWorkflow
CutoverChecklistReady
RollbackReady
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) enum HandoffStatus {
HandoffPass
HandoffBlocked
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct HandoffFinding {
gate : HandoffGate
status : HandoffStatus
path : String
message : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct HandoffRunbookStep {
index : Int
title : String
action_path : String
expected_evidence : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct OperatorHandoffInput {
acceptance_report : @acceptance.AcceptanceReport
readiness_report : @evaluation.CutoverReadinessReport
comparison_report : @comparison.CutoverComparisonReport
cutover_plan : @cutover.CutoverPlan
app_tool_manifest : @app.MoondeskAppToolManifest
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct OperatorHandoffReport {
ready : Bool
launch_path : String
pass_count : Int
blocked_count : Int
findings : Array[HandoffFinding]
runbook : Array[HandoffRunbookStep]
summary : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub fn operator_handoff_input(
acceptance_report : @acceptance.AcceptanceReport,
readiness_report : @evaluation.CutoverReadinessReport,
comparison_report : @comparison.CutoverComparisonReport,
cutover_plan : @cutover.CutoverPlan,
app_tool_manifest : @app.MoondeskAppToolManifest,
) -> OperatorHandoffInput {
{
acceptance_report,
readiness_report,
comparison_report,
cutover_plan,
app_tool_manifest,
}
}
///|
fn finding(
gate : HandoffGate,
status : HandoffStatus,
path : String,
message : String,
) -> HandoffFinding {
{ gate, status, path, message }
}
///|
fn runbook_step(
index : Int,
title : String,
action_path : String,
expected_evidence : String,
) -> HandoffRunbookStep {
{ index, title, action_path, expected_evidence }
}
///|
fn acceptance_finding(report : @acceptance.AcceptanceReport) -> HandoffFinding {
if report.passed {
finding(
AcceptancePassed,
HandoffPass,
"acceptance-report",
"product acceptance gates pass for canonical migration fixtures",
)
} else {
finding(
AcceptancePassed,
HandoffBlocked,
"acceptance-report",
"acceptance report has unresolved product gates",
)
}
}
///|
fn readiness_finding(
report : @evaluation.CutoverReadinessReport,
) -> HandoffFinding {
if report.ready {
finding(
ReadinessPassed,
HandoffPass,
"cutover-readiness-report",
"cutover readiness gates pass with comparison evidence",
)
} else {
finding(
ReadinessPassed,
HandoffBlocked,
"cutover-readiness-report",
"cutover readiness has unresolved blockers",
)
}
}
///|
fn comparison_finding(
report : @comparison.CutoverComparisonReport,
) -> HandoffFinding {
if report.ready && report.pass_count == report.cases.length() {
finding(
ComparisonReady,
HandoffPass,
"cutover-comparison-report",
"golden fixture, live snapshot, and rollback comparison checks pass",
)
} else {
finding(
ComparisonReady,
HandoffBlocked,
"cutover-comparison-report",
"comparison report still needs review",
)
}
}
///|
fn app_mount_finding(manifest : @app.MoondeskAppToolManifest) -> HandoffFinding {
if manifest.id == "moondesk-price-action" &&
manifest.mount_path == "apps/moondesk-price-action" &&
manifest.controls.length() >= 6 &&
manifest.required_tools.contains("run_two_stage_routine") &&
manifest.required_tools.contains("ingest_market_snapshot") {
finding(
AppToolMounted,
HandoffPass,
manifest.mount_path,
"Moondesk price-action app-tool has mount path, controls, and required runtime tools",
)
} else {
finding(
AppToolMounted,
HandoffBlocked,
manifest.mount_path,
"Moondesk app-tool manifest is missing launch requirements",
)
}
}
///|
fn operator_workflow_finding(
manifest : @app.MoondeskAppToolManifest,
) -> HandoffFinding {
let required_surfaces = [
"run-analysis", "chart-panel", "event-stream-panel", "prompt-debug-panel", "start-follow-up",
"export-run", "replay-run",
]
let missing = required_surfaces.fold(init=0, fn(count, id) {
if manifest.surfaces.any(fn(surface) { surface.id == id && surface.enabled }) {
count
} else {
count + 1
}
})
if missing == 0 && manifest.redacted_binding_count >= 3 {
finding(
OperatorWorkflow,
HandoffPass,
"moondesk-app-tool-manifest.surfaces",
"operator workflow exposes run, chart, events, debug, follow-up, export, replay, and redacted bindings",
)
} else {
finding(
OperatorWorkflow,
HandoffBlocked,
"moondesk-app-tool-manifest.surfaces",
"\{missing} required operator surface(s) are missing or disabled",
)
}
}
///|
fn checklist_finding(plan : @cutover.CutoverPlan) -> HandoffFinding {
if plan.ready_to_cutover &&
plan.checklist.length() >= 6 &&
plan.imported_data_manifest_path != "" {
finding(
CutoverChecklistReady,
HandoffPass,
"cutover-plan.checklist",
"cutover checklist has readiness, import, freeze, switch, rollback-window, and archive steps",
)
} else {
finding(
CutoverChecklistReady,
HandoffBlocked,
"cutover-plan.checklist",
"cutover checklist is not executable yet",
)
}
}
///|
fn rollback_finding(plan : @cutover.CutoverPlan) -> HandoffFinding {
if plan.rollback_days >= 1 &&
plan.rollback_plan.length() >= 3 &&
plan.rollback_plan.any(fn(step) { step.path == "../paa" }) {
finding(
RollbackReady,
HandoffPass,
"cutover-plan.rollback_plan",
"PA Agent read-only rollback window and evidence capture steps are present",
)
} else {
finding(
RollbackReady,
HandoffBlocked,
"cutover-plan.rollback_plan",
"rollback plan is incomplete",
)
}
}
///|
fn count_status(
findings : Array[HandoffFinding],
status : HandoffStatus,
) -> Int {
findings.fold(init=0, fn(count, item) {
if item.status == status {
count + 1
} else {
count
}
})
}
///|
fn handoff_runbook(input : OperatorHandoffInput) -> Array[HandoffRunbookStep] {
[
runbook_step(
0,
"Open price-action app-tool",
input.app_tool_manifest.mount_path,
"moondesk-app-tool-manifest",
),
runbook_step(
1,
"Run or ingest market evidence",
"apps/moondesk-price-action/run-views/\{input.app_tool_manifest.run_id}",
"analysis-workspace",
),
runbook_step(
2,
"Review chart, events, prompts, and decision",
"records/analyses/\{input.app_tool_manifest.run_id}.json",
"analysis-record",
),
runbook_step(
3,
"Export, replay, and attach follow-up",
"records/exports/\{input.app_tool_manifest.run_id}.json",
"export-manifest",
),
runbook_step(
4,
"Execute cutover checklist",
input.cutover_plan.imported_data_manifest_path,
"cutover-plan",
),
]
}
///|
pub fn prepare_operator_handoff_report(
input : OperatorHandoffInput,
) -> OperatorHandoffReport {
let findings = [
acceptance_finding(input.acceptance_report),
readiness_finding(input.readiness_report),
comparison_finding(input.comparison_report),
app_mount_finding(input.app_tool_manifest),
operator_workflow_finding(input.app_tool_manifest),
checklist_finding(input.cutover_plan),
rollback_finding(input.cutover_plan),
]
let blocked_count = count_status(findings, HandoffBlocked)
let pass_count = count_status(findings, HandoffPass)
let ready = blocked_count == 0
{
ready,
launch_path: input.app_tool_manifest.mount_path,
pass_count,
blocked_count,
findings,
runbook: handoff_runbook(input),
summary: if ready {
"operator handoff ready with \{pass_count}/\{findings.length()} gate(s) and \{handoff_runbook(input).length()} runbook step(s)"
} else {
"operator handoff blocked by \{blocked_count} gate(s)"
},
}
}