208 lines
8.7 KiB
PowerShell
208 lines
8.7 KiB
PowerShell
[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
|