feat(simulation): add Worker AI polygon runtime and terrain navigation

This commit is contained in:
DCCONSTRUCTIONS
2026-09-25 16:40:45 +03:00
parent a7c64e009d
commit f01bd39037
88 changed files with 9918 additions and 108 deletions
+121
View File
@@ -0,0 +1,121 @@
"""Replay retained sensor evidence against the shipped CMU adapter on Worker.
Owns exactly one bounded CPU container. Never starts rendering or model GPU jobs.
"""
import argparse
import hashlib
import http.client
import json
import subprocess
import time
from collections import Counter
from datetime import UTC, datetime
from pathlib import Path
from uuid import uuid4
import numpy as np
def main():
p = argparse.ArgumentParser()
p.add_argument("--adapter", type=Path, required=True)
p.add_argument("--run", type=Path, required=True)
p.add_argument("--output", type=Path, required=True)
p.add_argument("--limit", type=int, default=180)
p.add_argument("--terrain", action="store_true")
args = p.parse_args()
profile = json.loads((args.adapter / "models.worker-006.json").read_text())
identity = subprocess.check_output(
[
"docker",
"run",
"-d",
"--name",
"ndc-ai-polygon-navigation-replay-" + uuid4().hex[:8],
"--cpus",
"3",
"--memory",
"2g",
"--label",
"com.nodedc.product=mission-core",
"--label",
"com.nodedc.stack=ai-polygon-qualification",
"--label",
"com.nodedc.role=qualification",
"--label",
"com.nodedc.managed-by=ai-polygon-qualification",
"-p",
"127.0.0.1:18193:8010",
"--mount",
f"type=bind,source={args.adapter},target=/adapter,readonly",
profile["navigation"]["image"],
],
text=True,
).strip()
connection = http.client.HTTPConnection("127.0.0.1", 18193, timeout=3)
source = args.run / "camera/decisions.jsonl"
rows = [json.loads(line) for line in source.read_text().splitlines()]
report = dict(
utc=datetime.now(UTC).isoformat(),
monotonic=time.monotonic(),
input_sha256=hashlib.sha256(source.read_bytes()).hexdigest(),
samples=[],
)
try:
deadline = time.monotonic() + 20
while True:
try:
connection.request("GET", "/ready")
response = connection.getresponse()
response.read()
if response.status == 200:
break
except (OSError, http.client.HTTPException):
connection.close()
if time.monotonic() > deadline:
raise TimeoutError("Replay navigation unavailable")
time.sleep(0.2)
for row in rows[: args.limit]:
if row["goal"] is None:
continue
observation = np.load(args.run / "camera" / f"{row['frame_id']:08d}.range.npz")
payload = dict(
points=observation["points"].tolist(),
pose=observation["pose"].tolist(),
goal=row["goal"],
max_speed_mps=0.15,
allow_reverse=row.get("mission", {}).get("state") == "reversing",
include_terrain=args.terrain,
)
connection.request("POST", "/plan", body=json.dumps(payload))
response = connection.getresponse()
result = json.loads(response.read())
if response.status != 200:
raise RuntimeError(result)
report["samples"].append(
dict(
frame=row["frame_id"],
pose=payload["pose"],
original=row["decision"],
result=result,
)
)
time.sleep(0.18)
finally:
connection.close()
subprocess.run(["docker", "rm", "-f", identity], check=True, capture_output=True)
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(report, indent=2), encoding="utf-8")
failures = Counter(
v["result"].get("diagnostic", {}).get("failure", v["result"]["status"])
for v in report["samples"]
)
blocked = [v for v in report["samples"] if v["result"]["status"] == "blocked"]
print(
json.dumps(dict(failures=failures, first_blocked=blocked[:1], last=report["samples"][-1:]))
)
if __name__ == "__main__":
main()