///|
pub(all) enum ProductLaunchAction {
OpenOperatorWorkspace
InspectProductStatus
InspectReadinessReport
RunCutoverChecklist
OpenHandoffRunbook
ArchiveLegacyApp
ExportLaunchEvidence
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ProductLaunchBinding {
id : String
schema_id : String
source_path : String
redacted : Bool
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ProductLaunchPanel {
id : String
label : String
ready : Bool
binding_ids : Array[String]
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ProductLaunchManifest {
id : String
mount_path : String
run_id : @domain.RunId
ready : Bool
blocking_gate_count : Int
status_path : String
bindings : Array[ProductLaunchBinding]
panels : Array[ProductLaunchPanel]
actions : Array[ProductLaunchAction]
summary : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub fn product_launch_binding(
id : String,
schema_id : String,
source_path : String,
redacted? : Bool = false,
) -> ProductLaunchBinding {
{ id, schema_id, source_path, redacted }
}
///|
pub fn product_launch_panel(
id : String,
label : String,
binding_ids : Array[String],
ready? : Bool = true,
) -> ProductLaunchPanel {
{ id, label, ready, binding_ids }
}
///|
fn product_status_path(run_id : @domain.RunId) -> String {
"records/product-status/\{run_id}.json"
}
///|
fn product_surface_path(run_id : @domain.RunId, name : String) -> String {
"apps/moondesk-price-action/product-status/\{run_id}/\{name}.json"
}
///|
fn add_blocker(count : Int, passed : Bool) -> Int {
if passed {
count
} else {
count + 1
}
}
///|
fn blocking_gate_count(status : MoonfishProductStatus) -> Int {
add_blocker(
add_blocker(
add_blocker(
add_blocker(
add_blocker(
add_blocker(0, status.acceptance_report.passed),
status.readiness_report.ready,
),
status.comparison_report.ready,
),
status.cutover_plan.ready_to_cutover,
),
status.handoff_report.ready,
),
status.decommission_report.ready,
)
}
///|
fn launch_bindings(
status : MoonfishProductStatus,
) -> Array[ProductLaunchBinding] {
let run_id = status.workspace.bundle.request.run_id
[
product_launch_binding(
"product-status",
"product-status",
product_status_path(run_id),
),
product_launch_binding(
"workspace",
"analysis-workspace",
product_surface_path(run_id, "workspace"),
),
product_launch_binding(
"pack-manifest",
"pack-manifest",
product_surface_path(run_id, "pack-manifest"),
),
product_launch_binding(
"readiness", "cutover-readiness-report", "records/evaluations/cutover-readiness.json",
),
product_launch_binding(
"cutover-plan",
"cutover-plan",
"records/cutovers/\{run_id}.json",
),
product_launch_binding(
"operator-handoff",
"operator-handoff-report",
"records/handoffs/\{run_id}.json",
),
product_launch_binding(
"decommission",
"decommission-report",
"\{status.decommission_report.archive_root}/final-status.json",
),
]
}
///|
fn launch_panels(status : MoonfishProductStatus) -> Array[ProductLaunchPanel] {
[
product_launch_panel(
"launch-overview",
"Launch Overview",
["product-status", "readiness", "operator-handoff"],
ready=blocking_gate_count(status) == 0,
),
product_launch_panel(
"cutover-checklist",
"Cutover Checklist",
["readiness", "cutover-plan", "pack-manifest"],
ready=status.readiness_report.ready &&
status.cutover_plan.ready_to_cutover,
),
product_launch_panel(
"handoff-runbook",
"Handoff Runbook",
["operator-handoff", "workspace"],
ready=status.handoff_report.ready,
),
product_launch_panel(
"decommission-archive",
"Decommission Archive",
["decommission", "cutover-plan"],
ready=status.decommission_report.ready,
),
]
}
///|
fn launch_actions(ready : Bool) -> Array[ProductLaunchAction] {
if ready {
[
OpenOperatorWorkspace,
InspectProductStatus,
InspectReadinessReport,
RunCutoverChecklist,
OpenHandoffRunbook,
ArchiveLegacyApp,
ExportLaunchEvidence,
]
} else {
[OpenOperatorWorkspace, InspectProductStatus, InspectReadinessReport]
}
}
///|
fn launch_summary(manifest : ProductLaunchManifest) -> String {
if manifest.ready {
"product launch manifest ready with \{manifest.panels.length()} panel(s), \{manifest.actions.length()} action(s), and status at \{manifest.status_path}"
} else {
"product launch manifest blocked by \{manifest.blocking_gate_count} gate(s); inspect \{manifest.status_path}"
}
}
///|
pub fn prepare_product_launch_manifest(
status : MoonfishProductStatus,
) -> ProductLaunchManifest {
let run_id = status.workspace.bundle.request.run_id
let blocking_gate_count = blocking_gate_count(status)
let ready = blocking_gate_count == 0
let manifest : ProductLaunchManifest = {
id: "moonfish-product-launch",
mount_path: "apps/moondesk-price-action/product-status",
run_id,
ready,
blocking_gate_count,
status_path: product_status_path(run_id),
bindings: launch_bindings(status),
panels: launch_panels(status),
actions: launch_actions(ready),
summary: "",
}
{ ..manifest, summary: launch_summary(manifest) }
}