[CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ReleaseRoot, [Parameter(Mandatory = $true)] [ValidatePattern("^[A-Za-z0-9._-]{1,96}$")] [string]$RunId, [string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\results\m48q-native-risk-case-mining" ) $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" function Assert-LastExitCode([string]$Operation) { if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" } } function Get-Sha256([string]$Path) { return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() } 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 Assert-RegularFile([string]$Path, [string]$Label) { $item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { throw "$Label must be a regular file" } return $item.FullName } function Convert-ToDockerPath([string]$Path) { return $Path.Replace("\", "/") } 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 "M4.8Q native risk case mining is pinned to DESKTOP-OPJ8J04" } $release = Resolve-DDirectory $ReleaseRoot "M4.8Q release root" $false $output = Resolve-DDirectory $OutputRoot "M4.8Q output root" $true $runOutput = Join-Path $output $RunId if (Test-Path -LiteralPath $runOutput) { throw "M4.8Q output already exists" } $runner = Assert-RegularFile ( Join-Path $release "run_m48q_native_risk_case_mining_worker.py" ) "M4.8Q runner" $profile = Assert-RegularFile ( Join-Path $release "m48q-native-risk-case-mining-v1.json" ) "M4.8Q profile" $runnerSha256 = Get-Sha256 $runner $profileSha256 = Get-Sha256 $profile if ($runnerSha256 -cne "39bb1d810b167d6e97dcb091505b52d4a812d69419dcb32fe23ea5d14d605d67") { throw "M4.8Q runner SHA-256 changed" } if ($profileSha256 -cne "c455055e63578d505edc80b66d67e795916a3d0297cc18bfee5a6af7b032ceda") { throw "M4.8Q profile SHA-256 changed" } $graphRoot = Resolve-DDirectory ( "D:\NDC_MISSIONCORE\runtime\results\m48n-native-reference-graph-shadow\ravnoves00-full-12fps-v0" ) "M4.8Q graph evidence root" $false $comparisonRoot = Resolve-DDirectory ( "D:\NDC_MISSIONCORE\runtime\results\m48n-native-vs-704\ravnoves00-full-v0" ) "M4.8Q comparison evidence root" $false $graphResult = Assert-RegularFile (Join-Path $graphRoot "result.json") "graph result" $graphFrames = Assert-RegularFile (Join-Path $graphRoot "frames.jsonl") "graph frames" $comparisonResult = Assert-RegularFile (Join-Path $comparisonRoot "result.json") "comparison result" $comparisonFrames = Assert-RegularFile (Join-Path $comparisonRoot "frames.jsonl") "comparison frames" $video = Assert-RegularFile ( "D:\NDC_MISSIONCORE\runtime\experiments\e46e\inputs\right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8.mp4" ) "RAVNOVES00 video" $graphResultSha256 = Get-Sha256 $graphResult $graphFramesSha256 = Get-Sha256 $graphFrames $comparisonResultSha256 = Get-Sha256 $comparisonResult $comparisonFramesSha256 = Get-Sha256 $comparisonFrames $videoSha256 = Get-Sha256 $video if ($graphResultSha256 -cne "c5c3a831b1d1c3271161c91fa5c5c40533eb663ca288ed0220334a147aed6e15") { throw "M4.8Q graph result SHA-256 changed" } if ($graphFramesSha256 -cne "b245af969600670d0975e89cae02b44206e3f1328eff48d5b4639b1b2ab57346") { throw "M4.8Q graph frame evidence SHA-256 changed" } if ($comparisonResultSha256 -cne "fd91c2f1f477038d5af51656d510aba39d69ad2e1a387f15d98ade19dd3a0c49") { throw "M4.8Q comparison result SHA-256 changed" } if ($comparisonFramesSha256 -cne "6a35125d4e003edfd8a33b4239bad0910f137fde3a770e9d5baab721cdc145b2") { throw "M4.8Q comparison frame evidence SHA-256 changed" } if ($videoSha256 -cne "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8") { throw "RAVNOVES00 video SHA-256 changed" } $media = Resolve-DDirectory ( "D:\NDC_MISSIONCORE\runtime\derived\perception-e15-media-pyav180-lz445-v1" ) "PyAV dependency" $false $pillow = Resolve-DDirectory ( "D:\NDC_MISSIONCORE\runtime\derived\perception-p0-env-v1" ) "Pillow dependency" $false $image = ( "nvcr.io/nvidia/tritonserver:26.06-py3@" + "sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794" ) & docker image inspect $image *> $null Assert-LastExitCode "pinned M4.8Q image inspection" $canonicalTriton = Get-Container "ndc-mission-core-triton" if (-not $canonicalTriton.State.Running -or $canonicalTriton.State.Health.Status -cne "healthy") { throw "Canonical Triton must remain healthy during M4.8Q mining" } $canonicalTritonId = [string]$canonicalTriton.Id $runnerName = "ndc-mission-core-m48q-native-risk-case-mining" if (& docker ps -a --format "{{.Names}}" --filter "name=^/$runnerName$") { throw "M4.8Q bounded container already exists" } try { & docker run ` --name $runnerName ` --label "com.nodedc.product=mission-core" ` --label "com.nodedc.stack=ndc-mission-core-compute" ` --label "com.nodedc.role=bounded-native-risk-case-mining" ` --label "com.nodedc.managed-by=codex-bounded-experiment" ` --network none ` --read-only ` --security-opt "no-new-privileges:true" ` --cap-drop ALL ` --pids-limit 128 ` --cpus 4 ` --memory 4g ` --tmpfs "/tmp:rw,noexec,nosuid,size=512m" ` -e "PYTHONDONTWRITEBYTECODE=1" ` -e "PYTHONPATH=/opt/media:/opt/pillow" ` -v ((Convert-ToDockerPath $release) + ":/release:ro") ` -v ((Convert-ToDockerPath $output) + ":/output:rw") ` -v ((Convert-ToDockerPath $media) + ":/opt/media:ro") ` -v ((Convert-ToDockerPath $pillow) + ":/opt/pillow:ro") ` -v ((Convert-ToDockerPath $graphRoot) + ":/evidence/graph:ro") ` -v ((Convert-ToDockerPath $comparisonRoot) + ":/evidence/comparison:ro") ` -v ((Convert-ToDockerPath $video) + ":/source/right.mp4:ro") ` --entrypoint python3 ` $image ` /release/run_m48q_native_risk_case_mining_worker.py ` --profile /release/m48q-native-risk-case-mining-v1.json ` --graph-result /evidence/graph/result.json ` --graph-frames /evidence/graph/frames.jsonl ` --comparison-result /evidence/comparison/result.json ` --comparison-frames /evidence/comparison/frames.jsonl ` --video /source/right.mp4 ` --output-root ("/output/{0}" -f $RunId) ` --expected-profile-sha256 $profileSha256 ` --expected-graph-result-sha256 $graphResultSha256 ` --expected-graph-frames-sha256 $graphFramesSha256 ` --expected-comparison-result-sha256 $comparisonResultSha256 ` --expected-comparison-frames-sha256 $comparisonFramesSha256 ` --expected-video-sha256 $videoSha256 ` --expected-runner-sha256 $runnerSha256 Assert-LastExitCode "M4.8Q native risk case mining" if ( -not (Test-Path -LiteralPath (Join-Path $runOutput "result.json") -PathType Leaf) -or -not (Test-Path -LiteralPath (Join-Path $runOutput "cases.jsonl") -PathType Leaf) -or @(Get-ChildItem -LiteralPath (Join-Path $runOutput "cases") -Filter "*.jpg" -File).Count -ne 24 ) { throw "M4.8Q result artifacts are incomplete" } } finally { if (& docker ps -a --format "{{.Names}}" --filter "name=^/$runnerName$") { & docker rm -f $runnerName *> $null } $canonicalAfter = Get-Container "ndc-mission-core-triton" if ( [string]$canonicalAfter.Id -cne $canonicalTritonId -or -not $canonicalAfter.State.Running -or $canonicalAfter.State.Health.Status -cne "healthy" ) { throw "Canonical Triton changed during M4.8Q mining" } } $result = Get-Content -LiteralPath (Join-Path $runOutput "result.json") -Raw | ConvertFrom-Json [pscustomobject]@{ run_id = $RunId output_root = $runOutput status = $result.status case_count = $result.selection.case_count report_identity_sha256 = $result.report_identity_sha256 canonical_triton = "healthy-and-unchanged" } | ConvertTo-Json -Depth 4