feat(perception): stage GSeg3D qualification

This commit is contained in:
DCCONSTRUCTIONS
2026-08-26 18:27:39 +03:00
parent 2e20ca7777
commit aed59030b4
9 changed files with 639 additions and 2 deletions
@@ -61,6 +61,7 @@ This T0 check does not reopen or alter that evidence.
| Order | Candidate | Exact revision | Admission role |
| ---: | --- | --- | --- |
| 1 | DFKI GSeg3D core | `116f510485ea5b4707e2b476958d34a5a067f647` | Pinned core dependency |
| 1 | DFKI GSeg3D | `5c5ba6f5ca0d682db2d59b2ad2f6a317ee938b95` | Primary terrain-relative ground/non-ground provider |
| 1 | DFKI Nav2 Ground Consistency | `41cec620efba6c370dccfc59a6ec1134775ff48a` | Primary temporal costmap evidence layer |
| 2 | TRAVEL | `95dc2fbd66a343efd9060c45a5711b6307a950a4` | Class-free challenger |
@@ -86,6 +87,28 @@ Candidate A may start only when all of the following are true:
4. canonical Mission Core Triton is healthy and is not stopped or replaced;
5. the candidate uses a new `ndc-` isolated build/runtime contour.
## Resource incident localized before T1
The apparent continued Worker pressure was not caused by an active GAUSS job.
A PowerShell process from an earlier Mission Core diagnostic had been orphaned
after loading and recursively serializing the complete nested M4.8R3
`result.json`. At discovery it held approximately `74,912.6 MiB` working set
and `193,275.8 MiB` private memory. The pressure killed
`ndc-mission-core-triton` with exit code `137`.
The orphaned diagnostic process was terminated at
`2026-08-26T15:17:39Z`. Free physical memory subsequently recovered to
`83,374,248 KiB`. The existing canonical Triton container was started without
replacement or rebuild and returned to `healthy` at
`2026-08-26T15:18:10Z`.
Future Worker inspection must not pass a complete nested replay result through
PowerShell `ConvertFrom-Json` followed by deep `ConvertTo-Json`. Diagnostics
must select bounded scalar fields before serialization and must have a wall
timeout plus process cleanup. A separate compute-runtime change is required to
give canonical Triton a declared restart policy; this report does not mutate
the Worker Compose source.
## Next command boundary
The next authorized action is T1 Candidate A upstream qualification: build the
@@ -0,0 +1,116 @@
[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
$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
@@ -0,0 +1,65 @@
FROM ros:jazzy-ros-base@sha256:2589a8fba5257307857890173c069852c2abf913a0be7970f172478baecb09e4
ARG GSEG3D_CORE_REVISION=116f510485ea5b4707e2b476958d34a5a067f647
ARG GSEG3D_ROS2_REVISION=5c5ba6f5ca0d682db2d59b2ad2f6a317ee938b95
ARG GROUND_CONSISTENCY_REVISION=41cec620efba6c370dccfc59a6ec1134775ff48a
ARG BUILD_JOBS=12
ENV DEBIAN_FRONTEND=noninteractive
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update \
&& apt-get install --yes --no-install-recommends \
build-essential \
cmake \
git \
jq \
libeigen3-dev \
libgtest-dev \
libnanoflann-dev \
libpcl-dev \
ninja-build \
ros-jazzy-message-filters \
ros-jazzy-nav2-costmap-2d \
ros-jazzy-pcl-conversions \
ros-jazzy-rclcpp-lifecycle \
ros-jazzy-tf2-eigen \
ros-jazzy-tf2-geometry-msgs \
time \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /opt/m49/src
RUN git clone --filter=blob:none https://github.com/dfki-ric/ground_segmentation.git \
&& git -C ground_segmentation checkout --detach "${GSEG3D_CORE_REVISION}" \
&& git clone --filter=blob:none https://github.com/dfki-ric/ground_segmentation_ros2.git \
&& git -C ground_segmentation_ros2 checkout --detach "${GSEG3D_ROS2_REVISION}" \
&& git clone --filter=blob:none https://github.com/dfki-ric/nav2_ground_consistency_costmap_plugin.git \
&& git -C nav2_ground_consistency_costmap_plugin checkout --detach "${GROUND_CONSISTENCY_REVISION}"
RUN cmake -S /opt/m49/src/ground_segmentation \
-B /opt/m49/core-build \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/m49/core-install \
&& cmake --build /opt/m49/core-build --parallel "${BUILD_JOBS}" \
&& ctest --test-dir /opt/m49/core-build --output-on-failure \
&& cmake --install /opt/m49/core-build
RUN source /opt/ros/jazzy/setup.bash \
&& export CMAKE_PREFIX_PATH="/opt/m49/core-install:${CMAKE_PREFIX_PATH:-}" \
&& colcon build \
--base-paths \
/opt/m49/src/ground_segmentation_ros2 \
/opt/m49/src/nav2_ground_consistency_costmap_plugin \
--build-base /opt/m49/ros-build \
--install-base /opt/m49/ros-install \
--merge-install \
--cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON \
--executor sequential \
--event-handlers console_direct+
COPY qualify.sh /usr/local/bin/m49-gseg3d-qualify
RUN chmod 0755 /usr/local/bin/m49-gseg3d-qualify
ENTRYPOINT ["/usr/local/bin/m49-gseg3d-qualify"]
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
set -euo pipefail
readonly EVIDENCE_ROOT=/evidence
readonly RESULT_PATH="${EVIDENCE_ROOT}/result.json"
readonly LOG_PATH="${EVIDENCE_ROOT}/qualification.log"
readonly RESOURCE_PATH="${EVIDENCE_ROOT}/resource.txt"
readonly STARTED_UTC="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
readonly STARTED_NS="$(date +%s%N)"
mkdir -p "${EVIDENCE_ROOT}"
if [[ -e "${RESULT_PATH}" || -e "${LOG_PATH}" || -e "${RESOURCE_PATH}" ]]; then
echo "evidence output already exists" >&2
exit 2
fi
status=failed
failure_stage=bootstrap
finalize() {
local exit_code=$?
local completed_ns
local elapsed_ms
completed_ns="$(date +%s%N)"
elapsed_ms="$(( (completed_ns - STARTED_NS) / 1000000 ))"
python3 - "${RESULT_PATH}" "${status}" "${failure_stage}" "${exit_code}" \
"${STARTED_UTC}" "${elapsed_ms}" <<'PY'
import json
import pathlib
import sys
target, status, stage, exit_code, started_utc, elapsed_ms = sys.argv[1:]
document = {
"schema_version": "missioncore.m49-t1-gseg3d-upstream-qualification/v1",
"status": status,
"failure_stage": None if status == "passed" else stage,
"exit_code": int(exit_code),
"started_utc": started_utc,
"elapsed_ms": int(elapsed_ms),
"authority": {
"candidate_build_qualified": status == "passed",
"ravnoves00_quality_accepted": False,
"realtime_accepted": False,
"navigation_or_actuation_allowed": False,
},
"revisions": {
"ground_segmentation": "116f510485ea5b4707e2b476958d34a5a067f647",
"ground_segmentation_ros2": "5c5ba6f5ca0d682db2d59b2ad2f6a317ee938b95",
"ground_consistency": "41cec620efba6c370dccfc59a6ec1134775ff48a",
},
}
pathlib.Path(target).write_text(
json.dumps(document, indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
PY
}
trap finalize EXIT
exec > >(tee "${LOG_PATH}") 2>&1
failure_stage=source-integrity
test "$(git -C /opt/m49/src/ground_segmentation rev-parse HEAD)" = \
"116f510485ea5b4707e2b476958d34a5a067f647"
test "$(git -C /opt/m49/src/ground_segmentation_ros2 rev-parse HEAD)" = \
"5c5ba6f5ca0d682db2d59b2ad2f6a317ee938b95"
test "$(git -C /opt/m49/src/nav2_ground_consistency_costmap_plugin rev-parse HEAD)" = \
"41cec620efba6c370dccfc59a6ec1134775ff48a"
test -z "$(git -C /opt/m49/src/ground_segmentation status --porcelain)"
test -z "$(git -C /opt/m49/src/ground_segmentation_ros2 status --porcelain)"
test -z "$(git -C /opt/m49/src/nav2_ground_consistency_costmap_plugin status --porcelain)"
failure_stage=core-upstream-tests
/usr/bin/time -v -o "${RESOURCE_PATH}" \
ctest --test-dir /opt/m49/core-build --output-on-failure
failure_stage=ros2-plugin-tests
source /opt/ros/jazzy/setup.bash
source /opt/m49/ros-install/setup.bash
colcon test \
--build-base /opt/m49/ros-build \
--install-base /opt/m49/ros-install \
--test-result-base /opt/m49/test-results \
--packages-select nav2_ground_consistency_costmap_plugin \
--event-handlers console_direct+
colcon test-result --test-result-base /opt/m49/test-results --verbose
failure_stage=ros2-discovery
ros2 pkg prefix ground_segmentation_ros2
ros2 pkg prefix nav2_ground_consistency_costmap_plugin
ros2 pkg executables ground_segmentation_ros2 | \
grep -F "ground_segmentation_ros2_node"
failure_stage=complete
status=passed