feat(simulation): prefer rover world terrain
This commit is contained in:
@@ -18,7 +18,9 @@ import httpx
|
|||||||
TUS_VERSION: Final = "1.0.0"
|
TUS_VERSION: Final = "1.0.0"
|
||||||
BUILD_REQUEST_SCHEMA: Final = "gaussian-pipeline.build-request/v1"
|
BUILD_REQUEST_SCHEMA: Final = "gaussian-pipeline.build-request/v1"
|
||||||
JOB_SCHEMA: Final = "gaussian-pipeline.job/v1"
|
JOB_SCHEMA: Final = "gaussian-pipeline.job/v1"
|
||||||
RESULT_SCHEMA: Final = "gaussian-pipeline.build-result/v1"
|
LEGACY_RESULT_SCHEMA: Final = "gaussian-pipeline.build-result/v1"
|
||||||
|
RESULT_SCHEMA: Final = "gaussian-pipeline.build-result/v2"
|
||||||
|
RESULT_SCHEMAS: Final = frozenset({LEGACY_RESULT_SCHEMA, RESULT_SCHEMA})
|
||||||
CAPABILITIES_SCHEMA: Final = "gaussian-pipeline.capabilities/v1"
|
CAPABILITIES_SCHEMA: Final = "gaussian-pipeline.capabilities/v1"
|
||||||
ARCHIVE_INGEST_REQUEST_SCHEMA: Final = "gaussian-pipeline.archive-ingest-request/v1"
|
ARCHIVE_INGEST_REQUEST_SCHEMA: Final = "gaussian-pipeline.archive-ingest-request/v1"
|
||||||
ARCHIVE_INGEST_SCHEMA: Final = "gaussian-pipeline.archive-ingest/v1"
|
ARCHIVE_INGEST_SCHEMA: Final = "gaussian-pipeline.archive-ingest/v1"
|
||||||
@@ -356,7 +358,7 @@ class GaussianPipelineGateway:
|
|||||||
def get_result(self, job_id: str) -> dict[str, Any]:
|
def get_result(self, job_id: str) -> dict[str, Any]:
|
||||||
_safe_id(job_id, "job id")
|
_safe_id(job_id, "job id")
|
||||||
result = self._json("GET", f"/v1/jobs/{quote(job_id, safe='')}/result")
|
result = self._json("GET", f"/v1/jobs/{quote(job_id, safe='')}/result")
|
||||||
if result.get("schema_version") != RESULT_SCHEMA or result.get("job_id") != job_id:
|
if result.get("schema_version") not in RESULT_SCHEMAS or result.get("job_id") != job_id:
|
||||||
raise GaussianPipelineGatewayError("Gaussian result identity does not match")
|
raise GaussianPipelineGatewayError("Gaussian result identity does not match")
|
||||||
_validate_runtime_provenance(result)
|
_validate_runtime_provenance(result)
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -679,8 +679,9 @@ def _world_manifest(project_id: str, artifacts: list[dict[str, Any]]) -> dict[st
|
|||||||
"streamed_sog_url": url_for("stream-manifest"),
|
"streamed_sog_url": url_for("stream-manifest"),
|
||||||
},
|
},
|
||||||
"collision": {
|
"collision": {
|
||||||
"mesh_url": url_for("collision-mesh"),
|
"mesh_url": url_for("rover-terrain-mesh") or url_for("collision-mesh"),
|
||||||
"available": url_for("collision-mesh") is not None,
|
"available": (url_for("rover-terrain-mesh") or url_for("collision-mesh"))
|
||||||
|
is not None,
|
||||||
},
|
},
|
||||||
"transforms": {
|
"transforms": {
|
||||||
"world_from_visual": [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1],
|
"world_from_visual": [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1],
|
||||||
|
|||||||
@@ -350,7 +350,14 @@ def test_gateway_rejects_symlink_source_and_token(tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_gateway_submits_tracks_and_imports_digest_bound_artifact(tmp_path: Path) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
"result_schema",
|
||||||
|
["gaussian-pipeline.build-result/v1", "gaussian-pipeline.build-result/v2"],
|
||||||
|
)
|
||||||
|
def test_gateway_submits_tracks_and_imports_digest_bound_artifact(
|
||||||
|
tmp_path: Path,
|
||||||
|
result_schema: str,
|
||||||
|
) -> None:
|
||||||
artifact = b"preview-sog"
|
artifact = b"preview-sog"
|
||||||
artifact_sha = hashlib.sha256(artifact).hexdigest()
|
artifact_sha = hashlib.sha256(artifact).hexdigest()
|
||||||
job_id = "gsp-20260825200000-deadbeef"
|
job_id = "gsp-20260825200000-deadbeef"
|
||||||
@@ -375,7 +382,7 @@ def test_gateway_submits_tracks_and_imports_digest_bound_artifact(tmp_path: Path
|
|||||||
return httpx.Response(
|
return httpx.Response(
|
||||||
200,
|
200,
|
||||||
json={
|
json={
|
||||||
"schema_version": "gaussian-pipeline.build-result/v1",
|
"schema_version": result_schema,
|
||||||
"job_id": job_id,
|
"job_id": job_id,
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"source_revision": "a" * 40,
|
"source_revision": "a" * 40,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from k1link.simulation.projects import (
|
|||||||
SimulationProjectConflictError,
|
SimulationProjectConflictError,
|
||||||
SimulationProjectService,
|
SimulationProjectService,
|
||||||
SimulationProjectStore,
|
SimulationProjectStore,
|
||||||
|
_world_manifest,
|
||||||
)
|
)
|
||||||
from k1link.web.simulation_projects_api import build_simulation_projects_router
|
from k1link.web.simulation_projects_api import build_simulation_projects_router
|
||||||
|
|
||||||
@@ -224,6 +225,27 @@ def test_service_materializes_world_manifest_and_deletes_both_copies(tmp_path: P
|
|||||||
assert provider.deleted == ["gsp-20260826000000-deadbeef"]
|
assert provider.deleted == ["gsp-20260826000000-deadbeef"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_world_manifest_prefers_seed_connected_rover_terrain() -> None:
|
||||||
|
manifest = _world_manifest(
|
||||||
|
"sim-" + "a" * 32,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"role": "collision-mesh",
|
||||||
|
"logical_path": "collision/scene.collision.glb",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "rover-terrain-mesh",
|
||||||
|
"logical_path": "rover/terrain.collision.glb",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert manifest["collision"]["available"] is True
|
||||||
|
assert manifest["collision"]["mesh_url"].endswith(
|
||||||
|
"/artifacts/rover/terrain.collision.glb"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_service_resumes_a_persisted_provider_job_without_reupload(tmp_path: Path) -> None:
|
def test_service_resumes_a_persisted_provider_job_without_reupload(tmp_path: Path) -> None:
|
||||||
store = SimulationProjectStore(tmp_path)
|
store = SimulationProjectStore(tmp_path)
|
||||||
project = store.create(
|
project = store.create(
|
||||||
|
|||||||
Reference in New Issue
Block a user