[CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$JobRoot, [Parameter(Mandatory = $true)] [string]$RunnerPath, [Parameter(Mandatory = $true)] [string]$BaselineRunnerPath, [Parameter(Mandatory = $true)] [string]$QualificationManifest, [Parameter(Mandatory = $true)] [string]$ValidFovRoot, [string]$RuntimeRoot = "D:\NDC_MISSIONCORE\runtime", [string]$CalibrationSha256 = "05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9", [string]$CalibrationSlot = "camera_1" ) $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" function Assert-LastExitCode { param([string]$Operation) if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" } } function Assert-RegularFile { param([string]$Path, [string]$Label) $item = Get-Item -LiteralPath $Path -Force if (-not $item.PSIsContainer -and -not ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { return $item.FullName } throw "$Label is not a regular file" } function Assert-Directory { param([string]$Path, [string]$Label) $item = Get-Item -LiteralPath $Path -Force if ($item.PSIsContainer -and -not ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { return $item.FullName } throw "$Label is not a real directory" } function Convert-ToDockerPath { param([string]$Path) return $Path.Replace("\", "/") } $jobDirectory = Assert-Directory (Resolve-Path -LiteralPath $JobRoot).Path "Job root" $runner = Assert-RegularFile (Resolve-Path -LiteralPath $RunnerPath).Path "Qualification runner" $baselineRunner = Assert-RegularFile (Resolve-Path -LiteralPath $BaselineRunnerPath).Path "Baseline runner" $qualification = Assert-RegularFile (Resolve-Path -LiteralPath $QualificationManifest).Path "Qualification manifest" $validFov = Assert-Directory (Resolve-Path -LiteralPath $ValidFovRoot).Path "Valid-FOV root" $null = Assert-RegularFile (Join-Path $validFov "manifest.json") "Valid-FOV manifest" $null = Assert-RegularFile (Join-Path $validFov "mask.png") "Valid-FOV mask" if ((Split-Path $runner -Parent) -ne (Split-Path $baselineRunner -Parent)) { throw "Qualification and baseline runners must share one read-only mount" } $runtime = Assert-Directory (Resolve-Path -LiteralPath $RuntimeRoot).Path "Runtime root" $job = Get-Content -LiteralPath (Join-Path $jobDirectory "job.json") -Raw | ConvertFrom-Json if ($job.schema_version -ne "missioncore.compute-job/v1" -or $job.job_id -ne (Split-Path $jobDirectory -Leaf)) { throw "Compute job manifest is incompatible" } if ($CalibrationSha256 -notmatch "^[a-f0-9]{64}$" -or $CalibrationSlot -notmatch "^[A-Za-z0-9._-]+$") { throw "Calibration binding is invalid" } $sourceId = [string]$job.input.source_id $epoch = [int]$job.input.codec_epoch $frameCount = [int]$job.input.segment_count $timelineStart = [double]$job.input.timeline.start_seconds $timelineEnd = [double]$job.input.timeline.end_seconds $timelineDuration = $timelineEnd - $timelineStart if ($frameCount -lt 1 -or $timelineDuration -le 0) { throw "Compute job frame/timeline contract is invalid" } $qualificationDocument = Get-Content -LiteralPath $qualification -Raw | ConvertFrom-Json if ( $qualificationDocument.schema_version -ne "missioncore.recorded-qualification-slice/v1" -or $qualificationDocument.identity.job_id -ne $job.job_id -or $qualificationDocument.identity.input_sha256 -ne $job.input_sha256 ) { throw "Qualification manifest is not bound to this job" } Write-Output ("PHASE=inputs-validated QUALIFICATION_FRAMES={0}" -f @($qualificationDocument.frames).Count) $epochRoot = Join-Path $jobDirectory ("input\camera\{0}\epoch-{1}" -f $sourceId, $epoch) $epochRoot = Assert-Directory $epochRoot "Camera epoch" $initPath = Assert-RegularFile (Join-Path $epochRoot "init.mp4") "Camera init" $segmentsRoot = Assert-Directory (Join-Path $epochRoot "segments") "Camera segments" $derivedRoot = Join-Path $runtime "derived\qualification" $tmpRoot = Join-Path $runtime "tmp" $cacheRoot = Assert-Directory (Join-Path $runtime "cache\perception-p0-models-v1") "Model cache" $torchEnvironment = Assert-Directory (Join-Path $runtime "derived\perception-p0-env-v1") "Torch environment" $transformersEnvironment = Assert-Directory (Join-Path $runtime "derived\perception-p0-transformers4576-v1") "Transformers environment" $runnerRoot = Split-Path $runner -Parent $runnerName = Split-Path $runner -Leaf $baselineRunnerName = Split-Path $baselineRunner -Leaf $qualificationRoot = Split-Path $qualification -Parent $qualificationName = Split-Path $qualification -Leaf $null = New-Item -ItemType Directory -Path $derivedRoot -Force $null = New-Item -ItemType Directory -Path $tmpRoot -Force $preflightArgs = @( "run", "--rm", "--gpus", "all", "--network", "none", "--security-opt", "no-new-privileges:true", "--cap-drop", "ALL", "-e", "PYTHONPATH=/opt/transformers:/opt/env", "-e", "TORCH_HOME=/cache/torch", "-e", "HF_HOME=/cache/huggingface", "-e", "HF_HUB_OFFLINE=1", "-e", "TRANSFORMERS_OFFLINE=1", "-v", ((Convert-ToDockerPath $jobDirectory) + ":/job:ro"), "-v", ((Convert-ToDockerPath $cacheRoot) + ":/cache:rw"), "-v", ((Convert-ToDockerPath $torchEnvironment) + ":/opt/env:ro"), "-v", ((Convert-ToDockerPath $transformersEnvironment) + ":/opt/transformers:ro"), "-v", ((Convert-ToDockerPath $runnerRoot) + ":/runner:ro"), "--entrypoint", "python3", "nvcr.io/nvidia/tritonserver:26.06-py3", ("/runner/{0}" -f $baselineRunnerName), "preflight", "--job", "/job", "--cache", "/cache" ) Write-Output "PHASE=worker-preflight-started" & docker @preflightArgs Assert-LastExitCode "Worker preflight" Write-Output "PHASE=worker-preflight-complete" $runToken = [Guid]::NewGuid().ToString("N") $workRoot = Join-Path $tmpRoot ("{0}-e1-{1}" -f $job.job_id, $runToken) $framesRoot = Join-Path $workRoot "frames" $streamPath = Join-Path $workRoot "camera.mp4" $ptsPath = Join-Path $workRoot "pts.json" $timelinePath = Join-Path $workRoot "timeline.jsonl" $publishRoot = Join-Path $derivedRoot (".{0}-e1-{1}.publish" -f $job.job_id, $runToken) $stagingRoot = Join-Path $publishRoot "output" $null = New-Item -ItemType Directory -Path $framesRoot $null = New-Item -ItemType Directory -Path $publishRoot Write-Output "PHASE=private-staging-created" try { $stream = [IO.File]::Open($streamPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None) try { $input = [IO.File]::OpenRead($initPath) try { $input.CopyTo($stream) } finally { $input.Dispose() } for ($sequence = 1; $sequence -le $frameCount; $sequence++) { $path = Assert-RegularFile (Join-Path $segmentsRoot ("{0}.m4s" -f $sequence)) "Camera segment" $input = [IO.File]::OpenRead($path) try { $input.CopyTo($stream) } finally { $input.Dispose() } if ($sequence % 500 -eq 0 -or $sequence -eq $frameCount) { Write-Output ("PHASE=stream-reconstruction SEGMENTS={0}/{1}" -f $sequence, $frameCount) } } $stream.Flush($true) } finally { $stream.Dispose() } Write-Output "PHASE=frame-extraction-started" & ffmpeg -hide_banner -loglevel fatal -i $streamPath -map 0:v:0 -fps_mode passthrough (Join-Path $framesRoot "frame-%06d.png") Assert-LastExitCode "Camera extraction" & ffprobe -v error -select_streams v:0 -show_entries frame=best_effort_timestamp_time -of json $streamPath | Set-Content -LiteralPath $ptsPath -Encoding utf8 Assert-LastExitCode "Camera timestamp probe" $decodedFrames = @(Get-ChildItem -LiteralPath $framesRoot -File -Filter "frame-*.png") $ptsDocument = Get-Content -LiteralPath $ptsPath -Raw | ConvertFrom-Json $pts = @($ptsDocument.frames) if ($decodedFrames.Count -ne $frameCount -or $pts.Count -ne $frameCount) { throw "Decoded frame count differs from the compute job" } $firstEpochSeconds = [double]::Parse( ([string]$pts[0].best_effort_timestamp_time).Trim(), [Globalization.CultureInfo]::InvariantCulture ) $previousEpochSeconds = -1.0 $timelineWriter = [IO.StreamWriter]::new($timelinePath, $false, [Text.UTF8Encoding]::new($false)) try { for ($index = 0; $index -lt $frameCount; $index++) { $epochSeconds = [double]::Parse( ([string]$pts[$index].best_effort_timestamp_time).Trim(), [Globalization.CultureInfo]::InvariantCulture ) - $firstEpochSeconds if ($epochSeconds -le $previousEpochSeconds -or $epochSeconds -gt ($timelineDuration + 0.001)) { throw "Decoded camera timestamps are not strictly monotonic inside the compute job timeline" } $row = [ordered]@{ frame_index = $index epoch_seconds = $epochSeconds session_seconds = $timelineStart + $epochSeconds } $timelineWriter.WriteLine(($row | ConvertTo-Json -Compress)) $previousEpochSeconds = $epochSeconds } $timelineWriter.Flush() } finally { $timelineWriter.Dispose() } Write-Output ("PHASE=frame-extraction-complete FRAMES={0}" -f $frameCount) $dockerArgs = @( "run", "--rm", "--gpus", "all", "--network", "none", "--security-opt", "no-new-privileges:true", "--cap-drop", "ALL", "--shm-size", "2g", "-e", "PYTHONPATH=/opt/transformers:/opt/env", "-e", "TORCH_HOME=/cache/torch", "-e", "HF_HOME=/cache/huggingface", "-e", "HF_HUB_OFFLINE=1", "-e", "TRANSFORMERS_OFFLINE=1", "-v", ((Convert-ToDockerPath $jobDirectory) + ":/job:ro"), "-v", ((Convert-ToDockerPath $framesRoot) + ":/frames:ro"), "-v", ((Convert-ToDockerPath $workRoot) + ":/work:ro"), "-v", ((Convert-ToDockerPath $publishRoot) + ":/publish:rw"), "-v", ((Convert-ToDockerPath $cacheRoot) + ":/cache:rw"), "-v", ((Convert-ToDockerPath $torchEnvironment) + ":/opt/env:ro"), "-v", ((Convert-ToDockerPath $transformersEnvironment) + ":/opt/transformers:ro"), "-v", ((Convert-ToDockerPath $runnerRoot) + ":/runner:ro"), "-v", ((Convert-ToDockerPath $qualificationRoot) + ":/qualification:ro"), "-v", ((Convert-ToDockerPath $validFov) + ":/valid-fov:ro"), "--entrypoint", "python3", "nvcr.io/nvidia/tritonserver:26.06-py3", ("/runner/{0}" -f $runnerName), "--job", "/job", "--frames", "/frames", "--timeline", "/work/timeline.jsonl", "--qualification", ("/qualification/{0}" -f $qualificationName), "--valid-fov-root", "/valid-fov", "--output", "/publish/output", "--cache", "/cache", "--calibration-sha256", $CalibrationSha256, "--calibration-slot", $CalibrationSlot, "--telemetry-interval-seconds", "1" ) & docker @dockerArgs Assert-LastExitCode "Preprocessing qualification" $result = Get-Content -LiteralPath (Join-Path $stagingRoot "result.json") -Raw | ConvertFrom-Json if ( $result.schema_version -ne "missioncore.perception-preprocessing-qualification-result/v1" -or $result.result_id -notmatch "^qualification-result-[a-f0-9]{64}$" ) { throw "Qualification result manifest is incompatible" } $finalRoot = Join-Path $derivedRoot ([string]$result.result_id) if (Test-Path -LiteralPath $finalRoot) { throw "An immutable qualification result with the same identity already exists: $finalRoot" } Move-Item -LiteralPath $stagingRoot -Destination $finalRoot Remove-Item -LiteralPath $publishRoot -Force Write-Output ("RESULT_ROOT={0}" -f $finalRoot) Write-Output ("RESULT_ID={0}" -f $result.result_id) } finally { if (Test-Path -LiteralPath $workRoot) { Remove-Item -LiteralPath $workRoot -Recurse -Force } }