[CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$BuildContext, [Parameter(Mandatory = $true)] [ValidatePattern("^[A-Za-z0-9._-]{1,96}$")] [string]$RunId, [string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\results\m49-t1-gseg3d" ) $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" function Assert-LastExitCode([string]$Operation) { if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" } } function Resolve-DDirectory([string]$Path, [string]$Label, [bool]$Create) { if ($Create -and -not (Test-Path -LiteralPath $Path)) { $null = New-Item -ItemType Directory -Path $Path } $item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force if ( -not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or [IO.Path]::GetPathRoot($item.FullName).TrimEnd("\") -ine "D:" ) { throw "$Label must be a real D: directory" } return $item.FullName } function Get-Container([string]$Name) { $rows = @((& docker inspect $Name) | ConvertFrom-Json) Assert-LastExitCode "Docker inspection for $Name" if ($rows.Count -ne 1) { throw "Container identity for $Name is not unique" } return $rows[0] } if ($env:COMPUTERNAME -cne "DESKTOP-OPJ8J04") { throw "M49 T1 is pinned to Worker 006" } $context = Resolve-DDirectory $BuildContext "M49 T1 build context" $false $output = Resolve-DDirectory $OutputRoot "M49 T1 output root" $true $runOutput = Join-Path $output $RunId if (Test-Path -LiteralPath $runOutput) { throw "M49 T1 output already exists" } $null = New-Item -ItemType Directory -Path $runOutput $runOutput = Resolve-DDirectory $runOutput "M49 T1 run output" $false $dockerConfig = Join-Path $runOutput "docker-config" $null = New-Item -ItemType Directory -Path $dockerConfig '{"auths":{}}' | Set-Content -LiteralPath (Join-Path $dockerConfig "config.json") -Encoding ascii $env:DOCKER_CONFIG = $dockerConfig $os = Get-CimInstance Win32_OperatingSystem $freeMemoryGiB = [double]$os.FreePhysicalMemory / 1MB if ($freeMemoryGiB -lt 16.0) { throw ("M49 T1 requires 16 GiB free memory; observed {0:N2} GiB" -f $freeMemoryGiB) } $canonicalTriton = Get-Container "ndc-mission-core-triton" if (-not $canonicalTriton.State.Running -or $canonicalTriton.State.Health.Status -cne "healthy") { throw "Canonical Mission Core Triton must remain healthy during M49 T1" } $containerName = "ndc-mission-core-m49-t1-gseg3d-$RunId" if (& docker ps -a --format "{{.Names}}" --filter "name=^/$containerName$") { throw "M49 T1 container name already exists" } $imageTag = "ndc/mission-core-m49-t1-gseg3d:20260826" $buildStarted = [DateTimeOffset]::UtcNow & docker build --pull=false --tag $imageTag $context Assert-LastExitCode "M49 T1 image build" $buildCompleted = [DateTimeOffset]::UtcNow $runStarted = [DateTimeOffset]::UtcNow try { & docker run --rm --name $containerName --cpus 16 --memory 24g ` --volume ((($runOutput -replace "\\", "/")) + ":/evidence") ` $imageTag Assert-LastExitCode "M49 T1 upstream qualification" } finally { if (& docker ps -a --format "{{.Names}}" --filter "name=^/$containerName$") { & docker rm --force $containerName *> $null } } $runCompleted = [DateTimeOffset]::UtcNow $image = @((& docker image inspect $imageTag) | ConvertFrom-Json)[0] Assert-LastExitCode "M49 T1 image inspection" $resultPath = Join-Path $runOutput "result.json" if (-not (Test-Path -LiteralPath $resultPath -PathType Leaf)) { throw "M49 T1 result.json is missing" } $result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json if ($result.status -cne "passed") { throw "M49 T1 qualification did not pass" } $summary = [ordered]@{ schema_version = "missioncore.m49-t1-worker-summary/v1" worker_id = "worker-006" run_id = $RunId image_tag = $imageTag image_id = [string]$image.Id image_size_bytes = [long]$image.Size build_started_utc = $buildStarted.ToString("o") build_wall_seconds = [math]::Round(($buildCompleted - $buildStarted).TotalSeconds, 6) qualification_wall_seconds = [math]::Round(($runCompleted - $runStarted).TotalSeconds, 6) free_memory_gib_before = [math]::Round($freeMemoryGiB, 6) canonical_triton_id = [string]$canonicalTriton.Id canonical_triton_health = [string]$canonicalTriton.State.Health.Status candidate_accepted = $true ravnoves00_quality_accepted = $false realtime_accepted = $false navigation_or_actuation_allowed = $false } $summary | ConvertTo-Json -Depth 3 | Set-Content -LiteralPath ( Join-Path $runOutput "worker-summary.json" ) -Encoding utf8 $summary | ConvertTo-Json -Depth 3