feat(simulation): add Polygon live worker gateway

This commit is contained in:
DCCONSTRUCTIONS
2026-07-24 20:33:08 +03:00
parent 359f0d1d39
commit b7ccca3481
13 changed files with 2365 additions and 9 deletions
+134 -2
View File
@@ -18,7 +18,7 @@ from k1link.simulation import (
RunKind,
RunState,
)
from k1link.web.polygon_api import build_polygon_router
from k1link.web.polygon_api import StartStockRoverRequest, build_polygon_router
SHA_A = "a" * 64
SHA_B = "b" * 64
@@ -130,7 +130,8 @@ def test_polygon_api_is_read_only_and_fails_closed_when_unconfigured() -> None:
router = build_polygon_router(root_provider=lambda: None)
routes = [route for route in router.routes if isinstance(route, APIRoute)]
assert all(route.methods <= {"GET", "HEAD"} for route in routes)
archive_routes = [route for route in routes if "/worker" not in route.path]
assert all(route.methods <= {"GET", "HEAD"} for route in archive_routes)
with pytest.raises(HTTPException) as failure:
_endpoint(router, "/api/v1/polygon/runs", "GET")(limit=20)
assert failure.value.status_code == 503
@@ -183,3 +184,134 @@ def test_polygon_api_rejects_corrupt_evidence_without_partial_response(
_endpoint(router, "/api/v1/polygon/runs", "GET")(limit=20)
assert failure.value.status_code == 500
assert "целостности" in failure.value.detail
class _FakeWorkerGateway:
def __init__(self) -> None:
self.calls: list[tuple[str, str]] = []
self.active_run_id: str | None = None
def status(self) -> dict[str, Any]:
return self._status()
def live(self) -> dict[str, Any]:
if self.active_run_id is None:
raise AssertionError("test worker has no active run")
return {
"schema_version": "missioncore.vehicle-state/v1",
"run_id": self.active_run_id,
"sequence": 1,
"observed_at_utc": "2026-07-24T18:00:00Z",
"host_monotonic_ns": 123,
"sim_time_ns": 456,
"frame_id": "map_enu",
"child_frame_id": "base_link_flu",
"pose": {
"position_m": {"x": 1.0, "y": 2.0, "z": 0.1},
"orientation_xyzw": {"x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0},
},
"source": {
"provider": "gazebo",
"topic": "/world/rover/dynamic_pose/info",
"signal": "ground-truth",
"quality": "diagnostic",
},
"safety": {
"scope": "virtual-only",
"actuator_authority": False,
"navigation_or_safety_accepted": False,
},
}
def start(
self,
*,
run_id: str,
mission_core_commit: str,
idempotency_key: str,
) -> dict[str, Any]:
self.calls.append(("start", idempotency_key))
assert mission_core_commit == "d" * 40
self.active_run_id = run_id
return self._status()
def stop(self, *, run_id: str, idempotency_key: str) -> dict[str, Any]:
self.calls.append(("stop", idempotency_key))
assert run_id == self.active_run_id
self.active_run_id = None
return self._status()
def _status(self) -> dict[str, Any]:
return {
"schema_version": "missioncore.simulation-worker-status/v1",
"worker_id": "mission-gpu-s1",
"transport": "unix",
"mode": "simulation",
"available": True,
"control_available": True,
"active_run_id": self.active_run_id,
"run_state": "running" if self.active_run_id else None,
"provider_ids": ["px4-gazebo-stock-rover"] if self.active_run_id else [],
"isolation": {
"network": "loopback-only-netns",
"process_identity": "missioncore",
"artifact_policy": "d-only",
},
"authority": {
"scope": "virtual-only",
"actuator_authority": False,
"direct_actuator_setpoints_allowed": False,
},
}
def test_polygon_worker_api_fails_closed_then_proxies_virtual_only_lifecycle() -> None:
worker = _FakeWorkerGateway()
disabled = build_polygon_router(
root_provider=lambda: None,
worker_provider=lambda: worker,
control_provider=lambda: False,
commit_provider=lambda: "d" * 40,
)
status = _endpoint(disabled, "/api/v1/polygon/worker", "GET")()
assert status["available"] is True
assert status["control_available"] is False
with pytest.raises(HTTPException) as failure:
_endpoint(disabled, "/api/v1/polygon/worker/runs", "POST")(
request=StartStockRoverRequest(scenario_id="stock-rover-ackermann"),
idempotency_key="start-disabled",
)
assert failure.value.status_code == 403
enabled = build_polygon_router(
root_provider=lambda: None,
worker_provider=lambda: worker,
control_provider=lambda: True,
commit_provider=lambda: "d" * 40,
)
running = _endpoint(enabled, "/api/v1/polygon/worker/runs", "POST")(
request=StartStockRoverRequest(scenario_id="stock-rover-ackermann"),
idempotency_key="start-001",
)
assert running["active_run_id"].startswith("s1c-ddddddd-")
live = _endpoint(enabled, "/api/v1/polygon/worker/live", "GET")()
assert live["run_id"] == running["active_run_id"]
assert live["source"]["quality"] == "diagnostic"
stopped = _endpoint(enabled, "/api/v1/polygon/worker/runs/{run_id}/stop", "POST")(
run_id=running["active_run_id"],
idempotency_key="stop-001",
)
assert stopped["active_run_id"] is None
assert worker.calls == [("start", "start-001"), ("stop", "stop-001")]
def test_polygon_worker_status_is_explicitly_unavailable_when_not_registered() -> None:
router = build_polygon_router(
root_provider=lambda: None,
worker_provider=lambda: None,
)
status = _endpoint(router, "/api/v1/polygon/worker", "GET")()
assert status["schema_version"] == "missioncore.simulation-worker-status/v1"
assert status["available"] is False
assert status["control_available"] is False
assert status["authority"]["scope"] == "virtual-only"