Files
NODEDC_MISSION_CORE/experiments/perception/worker/Invoke-M49TgsFailClosedEvidence.ps1

206 lines
8.5 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ReleaseRoot,
[Parameter(Mandatory = $true)]
[ValidatePattern("^[A-Za-z0-9._-]{1,96}$")]
[string]$RunId,
[string]$SourcePackPath = "D:\NDC_MISSIONCORE\runtime\derived\e10-lidar-pack-576c994a6c814e2592dd6240ace3902a5db94843312c759a73ba0c9166157d2b\lidar-pack.npz",
[string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\results\m49-tgs-fail-closed"
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$TravelImageTag = "ndc/mission-core-m49-t3-travel:20260826"
$TravelImageId = "sha256:7b412020f4d8392d1d1ed1b33beadc44140f0ea8f781e62dd69796042334300f"
$ParityImageTag = "ndc-mission-core-m48t-upstream-parity:1.9.4-cu130"
$ParityImageId = "sha256:ceb13548617e4bd3f619766bfdff00af3fa5160946b367828da6d2233dcdcba0"
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 Resolve-DFile([string]$Path, [string]$Label) {
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
if (
$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: 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]
}
function Assert-Image([string]$Tag, [string]$ExpectedId) {
$rows = @(((& docker image inspect $Tag) | ConvertFrom-Json))
Assert-LastExitCode "Docker image inspection for $Tag"
if ($rows.Count -ne 1 -or [string]$rows[0].Id -cne $ExpectedId) {
throw "Pinned image identity changed for $Tag"
}
}
function Remove-ExactContainer([string]$Name) {
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$Name$") {
& docker rm --force $Name *> $null
}
}
if ($env:COMPUTERNAME -cne "DESKTOP-OPJ8J04") {
throw "M49 TGS fail-closed evidence is pinned to Worker 006"
}
$release = Resolve-DDirectory $ReleaseRoot "M49 TGS release" $false
$payload = Resolve-DDirectory (Join-Path $release "payload") "M49 TGS payload" $false
$sourcePack = Resolve-DFile $SourcePackPath "RAVNOVES00 source pack"
$output = Resolve-DDirectory $OutputRoot "M49 TGS output root" $true
$runCandidate = Join-Path $output $RunId
if (Test-Path -LiteralPath $runCandidate) { throw "M49 TGS output already exists" }
$null = New-Item -ItemType Directory -Path $runCandidate
$runOutput = Resolve-DDirectory $runCandidate "M49 TGS run output" $false
$releaseDocument = Get-Content -LiteralPath (Join-Path $payload "release.json") -Raw | ConvertFrom-Json
if (
$releaseDocument.schema_version -cne "missioncore.m49-tgs-worker-release/v1" -or
$releaseDocument.worker_id -cne "worker-006" -or
$releaseDocument.candidate_id -cne "travel-tgs-only"
) {
throw "M49 TGS release contract changed"
}
foreach ($property in $releaseDocument.files.PSObject.Properties) {
$path = Join-Path $payload $property.Name
$actual = (Get-FileHash -Algorithm SHA256 -LiteralPath $path).Hash.ToLowerInvariant()
if ($actual -cne [string]$property.Value.sha256) {
throw "M49 TGS payload digest changed: $($property.Name)"
}
}
$sourcePackSha = (Get-FileHash -Algorithm SHA256 -LiteralPath $sourcePack).Hash.ToLowerInvariant()
if ($sourcePackSha -cne "0685d24219d8236caf8b7f1685e93f6d6b59e7fd015a768d88a92bbe8b154944") {
throw "RAVNOVES00 source pack digest changed"
}
$os = Get-CimInstance Win32_OperatingSystem
$freeMemoryGiB = [double]$os.FreePhysicalMemory / 1MB
if ($freeMemoryGiB -lt 16.0) {
throw ("M49 TGS requires 16 GiB free memory; observed {0:N2} GiB" -f $freeMemoryGiB)
}
$tritonBefore = Get-Container "ndc-mission-core-triton"
if (-not $tritonBefore.State.Running -or $tritonBefore.State.Health.Status -cne "healthy") {
throw "Canonical Mission Core Triton must remain healthy during M49 TGS"
}
Assert-Image $TravelImageTag $TravelImageId
Assert-Image $ParityImageTag $ParityImageId
$prepareName = "ndc-mission-core-m49-tgs-prepare-$RunId"
$runName = "ndc-mission-core-m49-tgs-run-$RunId"
$analyzeName = "ndc-mission-core-m49-tgs-analyze-$RunId"
foreach ($name in @($prepareName, $runName, $analyzeName)) {
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$name$") {
throw "M49 TGS container name already exists: $name"
}
}
$started = [DateTimeOffset]::UtcNow
try {
& docker run --rm --name $prepareName --network none --cpus 8 --memory 16g `
--entrypoint python3 `
--volume ((Convert-ToDockerPath $sourcePack) + ":/source/lidar-pack.npz:ro") `
--volume ((Convert-ToDockerPath $payload) + ":/release:ro") `
--volume ((Convert-ToDockerPath $runOutput) + ":/tgs") `
$ParityImageTag /release/prepare_tgs_fail_closed_inputs.py `
--source-pack /source/lidar-pack.npz `
--config /release/m49-tgs-fail-closed-evidence-v1.json `
--output-root /tgs/inputs
Assert-LastExitCode "M49 TGS input preparation"
& docker run --rm --name $runName --network none --cpus 16 --memory 24g `
--entrypoint /bin/bash `
--volume ((Convert-ToDockerPath $payload) + ":/release:ro") `
--volume ((Convert-ToDockerPath $runOutput) + ":/tgs") `
$TravelImageTag /release/run_tgs_fail_closed.sh
Assert-LastExitCode "M49 TGS-only run"
& docker run --rm --name $analyzeName --network none --cpus 8 --memory 16g `
--entrypoint python3 `
--volume ((Convert-ToDockerPath $payload) + ":/release:ro") `
--volume ((Convert-ToDockerPath $runOutput) + ":/tgs") `
$ParityImageTag /release/build_tgs_fail_closed_evidence.py `
--run-root /tgs `
--config /release/m49-tgs-fail-closed-evidence-v1.json `
--output-root /tgs/evidence
Assert-LastExitCode "M49 TGS fail-closed evidence analysis"
} finally {
foreach ($name in @($prepareName, $runName, $analyzeName)) {
Remove-ExactContainer $name
}
}
$completed = [DateTimeOffset]::UtcNow
$resultPath = Join-Path $runOutput "evidence\result.json"
if (-not (Test-Path -LiteralPath $resultPath -PathType Leaf)) {
throw "M49 TGS evidence result is missing"
}
$result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json
if (
$result.status -cne "passed" -or
-not [bool]$result.summary.all_eligible_points_accounted -or
[bool]$result.summary.aos_used
) {
throw "M49 TGS fail-closed acceptance failed"
}
$tritonAfter = Get-Container "ndc-mission-core-triton"
if (
-not $tritonAfter.State.Running -or
$tritonAfter.State.Health.Status -cne "healthy" -or
[string]$tritonAfter.Id -cne [string]$tritonBefore.Id
) {
throw "Canonical Mission Core Triton changed during M49 TGS"
}
$summary = [ordered]@{
schema_version = "missioncore.m49-tgs-worker-summary/v1"
worker_id = "worker-006"
run_id = $RunId
code_revision = [string]$releaseDocument.code_revision
source_pack_sha256 = $sourcePackSha
travel_image_id = $TravelImageId
parity_image_id = $ParityImageId
started_utc = $started.ToString("o")
wall_seconds = [math]::Round(($completed - $started).TotalSeconds, 6)
free_memory_gib_before = [math]::Round($freeMemoryGiB, 6)
canonical_triton_id = [string]$tritonAfter.Id
canonical_triton_health = [string]$tritonAfter.State.Health.Status
all_eligible_points_accounted = [bool]$result.summary.all_eligible_points_accounted
aos_used = [bool]$result.summary.aos_used
visual_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