use indexmap::IndexMap;
use parallax_core::{
CapabilityLevel, ErrorCode, ParallaxError, Remediation, RuntimeCapabilities, RuntimeKind,
};
use parallax_ues::{UniversalExecutionState, UES_FORMAT_VERSION};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RequiredSemantic {
Values,
Globals,
Locals,
ControlPosition,
StackFrames,
Exceptions,
Closures,
AsyncState,
SameRuntimeResume,
CrossRuntimeResume,
DeterministicReplay,
}
impl RequiredSemantic {
pub fn capability_name(&self) -> &'static str {
match self {
Self::Values => "values",
Self::Globals => "globals",
Self::Locals => "locals",
Self::ControlPosition => "control_position",
Self::StackFrames => "stack_frames",
Self::Exceptions => "exception_state",
Self::Closures => "closures",
Self::AsyncState => "async_migration",
Self::SameRuntimeResume => "continuation_restore",
Self::CrossRuntimeResume => "cross_runtime_resume",
Self::DeterministicReplay => "continuation_restore", }
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MigrationContract {
pub version: u32,
pub source: RuntimeKind,
pub target: RuntimeKind,
pub mode: String,
pub required: Vec<RequiredSemantic>,
#[serde(default = "default_true")]
pub allow_experimental: bool,
#[serde(default)]
pub allow_partial: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expected_ues_format: Option<u32>,
#[serde(default)]
pub extensions: IndexMap<String, serde_json::Value>,
}
fn default_true() -> bool {
true
}
impl MigrationContract {
pub fn value_migration(source: RuntimeKind, target: RuntimeKind) -> Self {
Self {
version: 1,
source,
target,
mode: "value".into(),
required: vec![RequiredSemantic::Values, RequiredSemantic::Globals],
allow_experimental: true,
allow_partial: true,
expected_ues_format: None,
extensions: IndexMap::new(),
}
}
pub fn continuation_checkpoint(source: RuntimeKind, target: RuntimeKind) -> Self {
let mut required = vec![
RequiredSemantic::Values,
RequiredSemantic::Locals,
RequiredSemantic::ControlPosition,
RequiredSemantic::StackFrames,
RequiredSemantic::SameRuntimeResume,
];
if source != target {
required.push(RequiredSemantic::CrossRuntimeResume);
}
Self {
version: 1,
source,
target,
mode: "continuation".into(),
required,
allow_experimental: true,
allow_partial: true,
expected_ues_format: Some(UES_FORMAT_VERSION),
extensions: IndexMap::new(),
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ContractFinding {
pub semantic: RequiredSemantic,
pub capability: String,
pub level: CapabilityLevel,
pub blocking: bool,
pub message: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ContractAnalysis {
pub contract: MigrationContract,
pub findings: Vec<ContractFinding>,
pub satisfied: bool,
pub status: String,
#[serde(default)]
pub notes: Vec<String>,
}
impl ContractAnalysis {
pub fn format_human(&self) -> String {
let mut out = format!(
"MigrationContract v{} {} → {} mode={} status={}\n",
self.contract.version,
self.contract.source,
self.contract.target,
self.contract.mode,
self.status
);
for f in &self.findings {
let mark = if f.blocking { "BLOCK" } else { "ok" };
out.push_str(&format!(
" [{mark}] {:?} via {} = {} — {}\n",
f.semantic,
f.capability,
f.level.glyph(),
f.message
));
}
for n in &self.notes {
out.push_str(&format!(" note: {n}\n"));
}
out
}
}
fn level_acceptable(level: CapabilityLevel, contract: &MigrationContract) -> bool {
match level {
CapabilityLevel::Yes => true,
CapabilityLevel::Partial => contract.allow_partial,
CapabilityLevel::Experimental => contract.allow_experimental,
CapabilityLevel::No => false,
}
}
fn caps_for(runtime: &RuntimeKind) -> RuntimeCapabilities {
match runtime {
RuntimeKind::Python => RuntimeCapabilities::python(),
RuntimeKind::JavaScript => RuntimeCapabilities::javascript(),
RuntimeKind::Wasm => RuntimeCapabilities::wasm(),
RuntimeKind::Other(_) => RuntimeCapabilities::none(),
}
}
pub fn analyze_contract(contract: &MigrationContract) -> ContractAnalysis {
let target_caps = caps_for(&contract.target);
let mut findings = Vec::new();
let mut notes = Vec::new();
if contract.mode == "continuation" {
notes.push(
"Continuation mode requires a checkpoint-produced UES; arbitrary live stacks Unsupported"
.into(),
);
if contract.source != contract.target {
notes.push(
"Cross-runtime continuation resume is currently Unsupported (EXP gate only)".into(),
);
}
}
for semantic in &contract.required {
if *semantic == RequiredSemantic::DeterministicReplay {
findings.push(ContractFinding {
semantic: semantic.clone(),
capability: "deterministic_replay".into(),
level: CapabilityLevel::No,
blocking: true,
message: "Deterministic replay engine is not implemented".into(),
});
continue;
}
let cap = semantic.capability_name();
let level = target_caps.level_of(cap).unwrap_or(CapabilityLevel::No);
let acceptable = level_acceptable(level, contract);
let blocking = !acceptable;
findings.push(ContractFinding {
semantic: semantic.clone(),
capability: cap.into(),
level,
blocking,
message: if blocking {
format!(
"required semantic {:?} not satisfied on {}",
semantic, contract.target
)
} else {
format!("satisfied at {}", level.glyph())
},
});
}
let blocked = findings.iter().any(|f| f.blocking);
let status = if blocked {
if findings.iter().any(|f| {
f.blocking && matches!(f.level, CapabilityLevel::No) && f.capability.contains("cross")
}) {
"unsupported"
} else {
"rejected"
}
} else {
"ok"
};
ContractAnalysis {
contract: contract.clone(),
findings,
satisfied: !blocked,
status: status.into(),
notes,
}
}
pub fn require_contract(contract: &MigrationContract) -> parallax_core::Result<ContractAnalysis> {
let analysis = analyze_contract(contract);
if analysis.satisfied {
return Ok(analysis);
}
let detail = analysis.format_human();
Err(ParallaxError::new(
ErrorCode::MigrationRejected,
format!(
"migration contract not satisfied ({} → {}, mode={})",
contract.source, contract.target, contract.mode
),
)
.with_source("parallax-migrate")
.with_operation("require_contract")
.context("status", analysis.status.clone())
.context("report", detail)
.remediate(Remediation::with_detail(
"Inspect the contract report; use value migration or same-runtime checkpoint resume",
"Cross-runtime continuation resume is Unsupported in this Continuum milestone",
)))
}
pub fn analyze_ues_contract(
contract: &MigrationContract,
ues: &UniversalExecutionState,
) -> ContractAnalysis {
let mut analysis = analyze_contract(contract);
if let Some(expected) = contract.expected_ues_format {
if ues.format_version != expected {
analysis.satisfied = false;
analysis.status = "rejected".into();
analysis.findings.push(ContractFinding {
semantic: RequiredSemantic::ControlPosition,
capability: "ues_format".into(),
level: CapabilityLevel::No,
blocking: true,
message: format!("UES format {} != expected {}", ues.format_version, expected),
});
}
}
if ues.source_runtime != contract.source {
analysis.satisfied = false;
analysis.status = "rejected".into();
analysis.notes.push(format!(
"UES source_runtime {} != contract source {}",
ues.source_runtime, contract.source
));
}
if contract.mode == "continuation"
&& ues.control_state.safepoint_kind.as_deref() != Some("explicit_checkpoint")
{
analysis.satisfied = false;
analysis.status = "unsupported".into();
analysis.findings.push(ContractFinding {
semantic: RequiredSemantic::ControlPosition,
capability: "control_position".into(),
level: CapabilityLevel::No,
blocking: true,
message: "UES was not produced at an explicit checkpoint safepoint".into(),
});
}
if !analysis.satisfied && analysis.status == "ok" {
analysis.status = "rejected".into();
}
analysis
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn same_runtime_python_checkpoint_ok() {
let c =
MigrationContract::continuation_checkpoint(RuntimeKind::Python, RuntimeKind::Python);
let a = analyze_contract(&c);
assert!(a.satisfied, "{}", a.format_human());
}
#[test]
fn cross_runtime_continuation_rejected() {
let c = MigrationContract::continuation_checkpoint(
RuntimeKind::Python,
RuntimeKind::JavaScript,
);
let a = analyze_contract(&c);
assert!(!a.satisfied);
assert!(matches!(a.status.as_str(), "rejected" | "unsupported"));
let err = require_contract(&c).unwrap_err();
assert_eq!(err.code, ErrorCode::MigrationRejected);
}
#[test]
fn wasm_continuation_unsupported() {
let c = MigrationContract::continuation_checkpoint(RuntimeKind::Wasm, RuntimeKind::Wasm);
let a = analyze_contract(&c);
assert!(!a.satisfied);
}
}