Migration engine

Implemented in parallax-migrate.

Goals

  • Move data bindings between runtimes through PIR
  • Detect semantic incompatibilities before pretending success
  • Keep policy explicit (ConversionPolicy / CLI flags)
  • Report measured phase timings

Loss taxonomy

LevelMeaningDefault policy
NONEEquivalentAllow
SAFERepresentation differs, semantics preservedAllow
POTENTIALLY_LOSSYDepends on contentsAllow (allow_potentially_lossy)
LOSSYKnown corruption risk (e.g. unsafe int → Number)Reject unless --allow-lossy
UNSUPPORTEDCannot representKeep as Unsupported node (or reject if configured)

Conversion policy knobs

Field / flagDefaultEffect
prefer_bigint / (default on)trueUnsafe ints → PIR bigint for JS
--no-prefer-bigintDisable BigInt promotion
--allow-lossyoffPermit LOSSY coercions
allow_potentially_lossytrueAllow amber findings
reject_unsupportedfalseHard-fail on Unsupported

Phase timings

MigrationReport.timings fields (microseconds):

FieldSource
capture_usLive adapter execution (when used)
analyze_usSemantic walk
convert_usPIR rewrite
restore_usTarget adapter restore
total_usSum of measured phases

Never fabricated — if a phase did not run, the optional field is omitted / zero as documented by the CLI JSON schema.

Typical findings

  • SAFE — tuple/set → JS array; BigInt promotion path
  • LOSSY — integer outside [−2^53+1, 2^53−1] without BigInt preference
  • UNSUPPORTED — functions, host objects without encoders

API surface (library)

#![allow(unused)]
fn main() {
use parallax_migrate::migrate_document;
use parallax_core::{ConversionPolicy, RuntimeKind};

let (pir_out, report) = migrate_document(
    RuntimeKind::Python,
    RuntimeKind::JavaScript,
    &pir_in,
    &ConversionPolicy::default(),
)?;
}

CLI users should prefer plx migrate — it wires capture and restore around this function.