x4d-devkit 0.45.1__tar.gz → 0.46.0rc2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {x4d_devkit-0.45.1/x4d_devkit.egg-info → x4d_devkit-0.46.0rc2}/PKG-INFO +1 -1
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/pyproject.toml +1 -1
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_clean_basemap.py +132 -223
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_clean_basemap_client.py +3 -3
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_sdk_api.py +1 -1
- x4d_devkit-0.46.0rc2/tests/test_semantic_scene_independent.py +138 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/clean_basemap.py +57 -357
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/semantic_scene_authoring.py +235 -94
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/semantic_scene_contract.py +389 -91
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2/x4d_devkit.egg-info}/PKG-INFO +1 -1
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit.egg-info/SOURCES.txt +1 -1
- x4d_devkit-0.45.1/tests/test_clean_basemap_preannotation.py +0 -96
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/LICENSE +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/README.md +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/setup.cfg +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_annotation_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_annotation_reference.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_assets_client.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_boundary.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_box.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_build_info.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_cli_auth.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_client_json_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_client_projects.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_clip_archives.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_contract_validation.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_coordinate_frames.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_current_state.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_current_state_identity_consumers_example.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_dataset_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_dataset_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_detection_eval.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_evaluate.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_export_bundle.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_image_review.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_inference_input.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_inference_schemas.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_inference_service.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_label_schemas.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_lidar_materialization.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_loader.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_matching.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_metrics.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_models.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_platform_pose.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_preannotation_client.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_reconstruction_client.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_release_gate.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_roadmark_preview.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_semantic_scene_client.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_semantic_scene_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_semantic_scene_native_clip.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_source_attributes.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_time_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_token.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_tracking_eval.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_training_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_transform.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_transform_chain.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_validation.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_vector_map.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_vector_map_geometry.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_vector_map_session.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_work_session.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/tests/test_work_session_validation_reuse.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/annotation_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/annotation_reference.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/build_info.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/cli.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/_origin.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/annotation_reference.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/assets.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/bags.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/capabilities.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/checkpoints.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/clean_basemap.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/client.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/clip_work_sessions.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/clips.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/dataset_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/image_review.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/label_schemas.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/preannotation.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/projects.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/reconstruction.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/semantic_scene.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/services.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/client/test_sets.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/consumer_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/coordinate_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/core/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/core/loader.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/core/models.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/core/token.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/core/transform.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/current_state.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/dataset_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/dataset_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/api.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/box.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/detection.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/matching.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/metrics.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/eval/tracking.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/export_bundle.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/image_review.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/input.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/models.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/schemas.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/service.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/inference/tasks.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/json_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/label_schema.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/lidar_materialization.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/materialize.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/roadmark_preview.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/time_contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/training_identity.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/validation/__init__.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/validation/contract.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/validation/platform_pose.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/validation/report.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/validation/validator.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/vector_map.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/vector_map_geometry.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit/work_session.py +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit.egg-info/dependency_links.txt +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit.egg-info/entry_points.txt +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit.egg-info/requires.txt +0 -0
- {x4d_devkit-0.45.1 → x4d_devkit-0.46.0rc2}/x4d_devkit.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "x4d-devkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.46.0rc2"
|
|
8
8
|
description = "Official X-4D external SDK and CLI for datasets, platform APIs, training bridges, and automation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -5,7 +5,6 @@ import pytest
|
|
|
5
5
|
import zstandard
|
|
6
6
|
|
|
7
7
|
from tests.semantic_scene_contract_fixtures import current_semantic_scene_component
|
|
8
|
-
from x4d_devkit.annotation_contract import build_clip_annotations
|
|
9
8
|
from x4d_devkit.clean_basemap import (
|
|
10
9
|
CLEAN_BASEMAP_CONTRACT_VERSION,
|
|
11
10
|
CLEAN_BASEMAP_INPUT_FIELDS,
|
|
@@ -22,15 +21,12 @@ from x4d_devkit.clean_basemap import (
|
|
|
22
21
|
encode_clean_basemap_decisions,
|
|
23
22
|
encode_clean_basemap_mapping,
|
|
24
23
|
parse_clean_basemap_manifest,
|
|
25
|
-
validate_clean_basemap_annotation,
|
|
26
24
|
validate_clean_basemap_native_binding,
|
|
27
25
|
validate_clean_basemap_resource,
|
|
28
|
-
compute_clean_basemap_preannotation_revision,
|
|
29
26
|
)
|
|
30
27
|
from x4d_devkit.semantic_scene_contract import (
|
|
31
|
-
compute_annotation_dependency_revisions,
|
|
32
28
|
decode_scene_geometry,
|
|
33
|
-
|
|
29
|
+
empty_semantic_scene_instance_index,
|
|
34
30
|
sha256_bytes,
|
|
35
31
|
)
|
|
36
32
|
|
|
@@ -39,72 +35,42 @@ def fixture():
|
|
|
39
35
|
native = current_semantic_scene_component()
|
|
40
36
|
scene = clean_basemap_scene_source(native["scene_index"])
|
|
41
37
|
first = scene["chunks"][0]
|
|
42
|
-
|
|
43
|
-
native["scene_geometry_payloads"][first["geometry"]],
|
|
44
|
-
point_count=3,
|
|
45
|
-
expected_payload_sha256=first["geometry_sha256"],
|
|
46
|
-
expected_raw_sha256=first["geometry_raw_sha256"],
|
|
47
|
-
)
|
|
48
|
-
xyz = np.vstack([geometry.xyz, [9.5, 0, 0]]).astype(np.float32)
|
|
49
|
-
rgb = np.vstack([geometry.rgb, [100, 110, 120]]).astype(np.uint8)
|
|
50
|
-
encoded = encode_scene_geometry(xyz, rgb)
|
|
38
|
+
payload = native["scene_geometry_payloads"][first["geometry"]]
|
|
51
39
|
descriptor = {
|
|
52
|
-
"path": f"generated/reconstruction/clean_basemap/geometry/{
|
|
53
|
-
"sha256":
|
|
54
|
-
"raw_sha256":
|
|
55
|
-
"size_bytes": len(
|
|
40
|
+
"path": f"generated/reconstruction/clean_basemap/geometry/{first['geometry_sha256'][7:]}.spc.zst",
|
|
41
|
+
"sha256": first["geometry_sha256"],
|
|
42
|
+
"raw_sha256": first["geometry_raw_sha256"],
|
|
43
|
+
"size_bytes": len(payload),
|
|
56
44
|
}
|
|
57
|
-
decisions = [1, 0,
|
|
45
|
+
decisions = [1, 0, 3, 18, 33]
|
|
58
46
|
source_hash = "sha256:" + "a" * 64
|
|
59
47
|
decision_payload = encode_clean_basemap_decisions(
|
|
60
48
|
asset_sha256=source_hash, decisions=decisions
|
|
61
49
|
)
|
|
62
50
|
mapping = encode_clean_basemap_mapping(
|
|
63
|
-
geometry_raw_sha256=
|
|
64
|
-
sweep_indices=[0, 0, 0
|
|
65
|
-
raw_point_ordinals=[0, 1, 2
|
|
66
|
-
timestamps_ns=[100, 100, 100
|
|
67
|
-
|
|
68
|
-
owner_point_ordinals=[0, 1, 2, 0],
|
|
69
|
-
decisions=decisions[:4],
|
|
51
|
+
geometry_raw_sha256=first["geometry_raw_sha256"],
|
|
52
|
+
sweep_indices=[0, 0, 0],
|
|
53
|
+
raw_point_ordinals=[0, 1, 2],
|
|
54
|
+
timestamps_ns=[100, 100, 100],
|
|
55
|
+
decisions=decisions[:3],
|
|
70
56
|
)
|
|
71
|
-
instance_sources = [
|
|
72
|
-
{
|
|
73
|
-
key: row[key]
|
|
74
|
-
for key in (
|
|
75
|
-
"instance_token",
|
|
76
|
-
"point_count",
|
|
77
|
-
"geometry",
|
|
78
|
-
"geometry_sha256",
|
|
79
|
-
"geometry_raw_sha256",
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
| {"motion": "static"}
|
|
83
|
-
for row in native["instance_index"]["instances"]
|
|
84
|
-
]
|
|
85
57
|
profile = {
|
|
86
|
-
"algorithm": {"id": "clean_static_basemap", "version": "
|
|
58
|
+
"algorithm": {"id": "clean_static_basemap", "version": "0.6.0"},
|
|
87
59
|
"voxel_size_m": 0.03,
|
|
88
60
|
"min_range_m": 2.0,
|
|
89
61
|
"max_range_m": 60.0,
|
|
90
62
|
"lidar_channels": ["scanner-a"],
|
|
91
63
|
"unknown_policy": "retain",
|
|
92
64
|
"point_deskew": True,
|
|
93
|
-
"foreground_policy": "
|
|
65
|
+
"foreground_policy": "model_motion_ground_v1",
|
|
94
66
|
"occlusion_policy": "original_observations",
|
|
95
67
|
"policies": {
|
|
96
68
|
name: {"id": name, "version": "1.0.0", "parameters": {}}
|
|
97
|
-
for name in ("geometry", "ground", "
|
|
69
|
+
for name in ("geometry", "ground", "rgb")
|
|
98
70
|
},
|
|
99
71
|
}
|
|
100
72
|
inputs = {key: "sha256:" + "b" * 64 for key in CLEAN_BASEMAP_INPUT_FIELDS}
|
|
101
|
-
|
|
102
|
-
None
|
|
103
|
-
)
|
|
104
|
-
dependencies = compute_annotation_dependency_revisions(native["annotation"])
|
|
105
|
-
for key in inputs:
|
|
106
|
-
if key in dependencies:
|
|
107
|
-
inputs[key] = dependencies[key]
|
|
73
|
+
bounds = [first["bounds_min_m"], first["bounds_max_m"]]
|
|
108
74
|
manifest = {
|
|
109
75
|
"contract_version": CLEAN_BASEMAP_CONTRACT_VERSION,
|
|
110
76
|
"clip_id": native["annotation"]["clip_id"],
|
|
@@ -114,27 +80,25 @@ def fixture():
|
|
|
114
80
|
inputs, profile
|
|
115
81
|
),
|
|
116
82
|
"input_identity": inputs,
|
|
117
|
-
"preannotation_evidence": None,
|
|
118
83
|
"profile": profile,
|
|
119
|
-
"point_count":
|
|
120
|
-
"bounds":
|
|
84
|
+
"point_count": 3,
|
|
85
|
+
"bounds": bounds,
|
|
121
86
|
"scene_source": scene,
|
|
122
|
-
"instance_sources": instance_sources,
|
|
123
87
|
"sweep_sources": [
|
|
124
88
|
{
|
|
125
89
|
"sample_data_token": "sweep-0",
|
|
126
90
|
"channel": "scanner-a",
|
|
127
91
|
"point_count": 5,
|
|
128
92
|
"asset_sha256": source_hash,
|
|
129
|
-
"time_bounds": [{"sec": 0, "nanosec": 100}
|
|
93
|
+
"time_bounds": [{"sec": 0, "nanosec": 100}] * 2,
|
|
130
94
|
"decisions": decision_payload.descriptor("decisions"),
|
|
131
95
|
}
|
|
132
96
|
],
|
|
133
97
|
"chunks": [
|
|
134
98
|
{
|
|
135
99
|
"ordinal": 0,
|
|
136
|
-
"point_count":
|
|
137
|
-
"bounds":
|
|
100
|
+
"point_count": 3,
|
|
101
|
+
"bounds": bounds,
|
|
138
102
|
"geometry": descriptor,
|
|
139
103
|
"mapping": mapping.descriptor("mapping"),
|
|
140
104
|
}
|
|
@@ -147,10 +111,10 @@ def fixture():
|
|
|
147
111
|
},
|
|
148
112
|
}
|
|
149
113
|
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
150
|
-
assets = dict(native["scene_geometry_payloads"]
|
|
114
|
+
assets = dict(native["scene_geometry_payloads"])
|
|
151
115
|
assets.update(
|
|
152
116
|
{
|
|
153
|
-
descriptor["path"]:
|
|
117
|
+
descriptor["path"]: payload,
|
|
154
118
|
mapping.descriptor("mapping")["path"]: mapping.payload,
|
|
155
119
|
decision_payload.descriptor("decisions")["path"]: decision_payload.payload,
|
|
156
120
|
}
|
|
@@ -158,19 +122,22 @@ def fixture():
|
|
|
158
122
|
return manifest, assets, native
|
|
159
123
|
|
|
160
124
|
|
|
161
|
-
def
|
|
125
|
+
def original_points(manifest, assets):
|
|
162
126
|
geometry = manifest["chunks"][0]["geometry"]
|
|
163
|
-
|
|
127
|
+
return decode_scene_geometry(
|
|
164
128
|
assets[geometry["path"]],
|
|
165
|
-
point_count=
|
|
129
|
+
point_count=3,
|
|
166
130
|
expected_payload_sha256=geometry["sha256"],
|
|
167
131
|
expected_raw_sha256=geometry["raw_sha256"],
|
|
168
132
|
).xyz
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def validate(manifest, assets):
|
|
136
|
+
original = original_points(manifest, assets)
|
|
169
137
|
return validate_clean_basemap_resource(
|
|
170
138
|
manifest,
|
|
171
139
|
read_asset=assets.__getitem__,
|
|
172
|
-
observation_to_world=lambda sweep, ordinals, times:
|
|
173
|
-
instance_to_world=lambda token, times, xyz: xyz + [10, 0, 0],
|
|
140
|
+
observation_to_world=lambda sweep, ordinals, times: original[ordinals],
|
|
174
141
|
)
|
|
175
142
|
|
|
176
143
|
|
|
@@ -180,52 +147,56 @@ def remap(manifest, assets, **overrides):
|
|
|
180
147
|
assets[chunk["mapping"]["path"]],
|
|
181
148
|
descriptor=chunk["mapping"],
|
|
182
149
|
geometry_raw_sha256=chunk["geometry"]["raw_sha256"],
|
|
183
|
-
point_count=
|
|
150
|
+
point_count=3,
|
|
184
151
|
)
|
|
185
152
|
arguments = {
|
|
186
153
|
"sweep_indices": mapping["sweep_index"],
|
|
187
154
|
"raw_point_ordinals": mapping["raw_point_ordinal"],
|
|
188
155
|
"timestamps_ns": mapping["timestamp_ns"],
|
|
189
|
-
"owner_source_indices": mapping["owner_source_index"],
|
|
190
|
-
"owner_point_ordinals": mapping["owner_point_ordinal"],
|
|
191
156
|
"decisions": mapping["decision"],
|
|
192
157
|
}
|
|
193
|
-
|
|
158
|
+
encoded = encode_clean_basemap_mapping(
|
|
194
159
|
geometry_raw_sha256=chunk["geometry"]["raw_sha256"], **(arguments | overrides)
|
|
195
160
|
)
|
|
196
|
-
chunk["mapping"] =
|
|
197
|
-
assets[chunk["mapping"]["path"]] =
|
|
161
|
+
chunk["mapping"] = encoded.descriptor("mapping")
|
|
162
|
+
assets[chunk["mapping"]["path"]] = encoded.payload
|
|
198
163
|
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
199
164
|
|
|
200
165
|
|
|
201
|
-
def
|
|
166
|
+
def test_complete_scene_and_exact_original_observation_roundtrip():
|
|
202
167
|
manifest, assets, native = fixture()
|
|
203
168
|
parsed = validate(manifest, assets)
|
|
204
169
|
assert parsed.to_dict() == manifest
|
|
205
|
-
validate_clean_basemap_annotation(parsed, native["annotation"])
|
|
206
170
|
validate_clean_basemap_native_binding(
|
|
207
171
|
parsed,
|
|
208
172
|
scene_index=native["scene_index"],
|
|
209
|
-
instance_index=
|
|
173
|
+
instance_index=empty_semantic_scene_instance_index(),
|
|
174
|
+
)
|
|
175
|
+
assert set(parsed.data["input_identity"]) == {
|
|
176
|
+
"samples_revision",
|
|
177
|
+
"sweeps_revision",
|
|
178
|
+
"calibration_revision",
|
|
179
|
+
"pose_revision",
|
|
180
|
+
}
|
|
181
|
+
assert (
|
|
182
|
+
"instance_sources" not in parsed.data
|
|
183
|
+
and "preannotation_evidence" not in parsed.data
|
|
210
184
|
)
|
|
211
|
-
|
|
212
|
-
|
|
185
|
+
assert "owner_source_index" not in MAPPING_DTYPE.names
|
|
186
|
+
manifest["point_count"] = 9
|
|
187
|
+
assert parsed.data["point_count"] == 3
|
|
213
188
|
with pytest.raises(TypeError):
|
|
214
189
|
parsed.data["profile"]["voxel_size_m"] = 1
|
|
215
190
|
|
|
216
191
|
|
|
217
192
|
@pytest.mark.parametrize(
|
|
218
|
-
"overrides,
|
|
193
|
+
"overrides,message",
|
|
219
194
|
[
|
|
220
|
-
({"sweep_indices": [1, 0, 0
|
|
221
|
-
({"raw_point_ordinals": [5, 1, 2
|
|
222
|
-
({"raw_point_ordinals": [0, 0, 2
|
|
223
|
-
({"raw_point_ordinals": [0, 1,
|
|
224
|
-
({"timestamps_ns": [101, 100, 100
|
|
225
|
-
({"owner_source_indices": [9, 0, 0, 1]}, "source index"),
|
|
226
|
-
({"owner_point_ordinals": [0, 1, 3, 0]}, "native point ordinal"),
|
|
227
|
-
({"owner_point_ordinals": [0, 1, 1, 0]}, "duplicate native scene"),
|
|
228
|
-
({"owner_source_indices": [0, 0, 1, 1]}, "instance correspondence"),
|
|
195
|
+
({"sweep_indices": [1, 0, 0]}, "source index"),
|
|
196
|
+
({"raw_point_ordinals": [5, 1, 2]}, "original point ordinal"),
|
|
197
|
+
({"raw_point_ordinals": [0, 0, 2]}, "duplicate original observation"),
|
|
198
|
+
({"raw_point_ordinals": [0, 1, 3]}, "decision"),
|
|
199
|
+
({"timestamps_ns": [101, 100, 100]}, "exact point time"),
|
|
229
200
|
],
|
|
230
201
|
)
|
|
231
202
|
def test_valid_hash_cannot_hide_wrong_addresses_or_removed_sources(overrides, message):
|
|
@@ -235,77 +206,65 @@ def test_valid_hash_cannot_hide_wrong_addresses_or_removed_sources(overrides, me
|
|
|
235
206
|
validate(manifest, assets)
|
|
236
207
|
|
|
237
208
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
manifest["instance_sources"][0]["motion"] = "dynamic"
|
|
241
|
-
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
242
|
-
with pytest.raises(ValueError, match="dynamic instance"):
|
|
243
|
-
validate(manifest, assets)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
@pytest.mark.parametrize("result", [np.zeros((2, 3)), np.full((1, 3), np.nan)])
|
|
247
|
-
def test_instance_transform_rejects_incomplete_or_nonfinite_results(result):
|
|
209
|
+
@pytest.mark.parametrize("kind", ["fabricated", "incomplete", "nonfinite"])
|
|
210
|
+
def test_original_observation_projection_is_required(kind):
|
|
248
211
|
manifest, assets, _ = fixture()
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
212
|
+
result = {
|
|
213
|
+
"fabricated": np.full((3, 3), 999.0),
|
|
214
|
+
"incomplete": np.zeros((2, 3)),
|
|
215
|
+
"nonfinite": np.full((3, 3), np.nan),
|
|
216
|
+
}[kind]
|
|
217
|
+
with pytest.raises(
|
|
218
|
+
ValueError, match="original observations|incomplete or nonfinite"
|
|
219
|
+
):
|
|
257
220
|
validate_clean_basemap_resource(
|
|
258
221
|
manifest,
|
|
259
222
|
read_asset=assets.__getitem__,
|
|
260
|
-
observation_to_world=lambda
|
|
261
|
-
instance_to_world=lambda token, times, xyz: result,
|
|
223
|
+
observation_to_world=lambda *args: result,
|
|
262
224
|
)
|
|
263
225
|
|
|
264
226
|
|
|
265
|
-
def
|
|
266
|
-
manifest, assets,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
read_asset=assets.__getitem__,
|
|
271
|
-
observation_to_world=lambda sweep, ordinals, times: np.full(
|
|
272
|
-
(len(ordinals), 3), 999.0
|
|
273
|
-
),
|
|
274
|
-
instance_to_world=lambda token, times, xyz: xyz + [10, 0, 0],
|
|
275
|
-
)
|
|
227
|
+
def test_native_payload_is_verified_even_with_correct_manifest_binding():
|
|
228
|
+
manifest, assets, native = fixture()
|
|
229
|
+
assets[native["scene_index"]["chunks"][0]["geometry"]] = b"tampered native geometry"
|
|
230
|
+
with pytest.raises(ValueError, match="byte-exact"):
|
|
231
|
+
validate(manifest, assets)
|
|
276
232
|
|
|
277
233
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
234
|
+
@pytest.mark.parametrize("key", sorted(CLEAN_BASEMAP_INPUT_FIELDS))
|
|
235
|
+
def test_actual_source_or_pose_change_changes_dependency(key):
|
|
236
|
+
manifest, _, _ = fixture()
|
|
237
|
+
inputs = dict(manifest["input_identity"], **{key: "sha256:" + "f" * 64})
|
|
238
|
+
assert (
|
|
239
|
+
compute_clean_basemap_dependency_identity(inputs, manifest["profile"])
|
|
240
|
+
!= manifest["dependency_identity"]
|
|
283
241
|
)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
validate(manifest, assets)
|
|
289
|
-
remap(manifest, assets, raw_point_ordinals=[0, 1, 2, 4])
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@pytest.mark.parametrize("code", [2, 16, 17])
|
|
245
|
+
def test_retired_box_and_geometry_decisions_are_rejected(code):
|
|
290
246
|
with pytest.raises(ValueError, match="decision"):
|
|
291
|
-
|
|
247
|
+
encode_clean_basemap_decisions(
|
|
248
|
+
asset_sha256="sha256:" + "a" * 64, decisions=[code]
|
|
249
|
+
)
|
|
292
250
|
|
|
293
251
|
|
|
294
252
|
def test_previous_contract_and_decision_bytes_are_rejected():
|
|
295
253
|
manifest, _, _ = fixture()
|
|
296
|
-
manifest["contract_version"] = "x4d-clean-static-basemap-
|
|
254
|
+
manifest["contract_version"] = "x4d-clean-static-basemap-v3"
|
|
297
255
|
with pytest.raises(ValueError, match="contract"):
|
|
298
256
|
parse_clean_basemap_manifest(manifest)
|
|
299
257
|
carrier = encode_clean_basemap_decisions(
|
|
300
258
|
asset_sha256="sha256:" + "a" * 64, decisions=[REMOVE_MODEL_DYNAMIC]
|
|
301
259
|
)
|
|
302
260
|
raw = zstandard.ZstdDecompressor().decompress(carrier.payload)
|
|
303
|
-
|
|
261
|
+
old_raw = b"X4DCBD2\0" + raw[8:]
|
|
262
|
+
old = zstandard.ZstdCompressor().compress(old_raw)
|
|
304
263
|
descriptor = carrier.descriptor("decisions")
|
|
305
264
|
descriptor.update(
|
|
306
265
|
path=f"generated/reconstruction/clean_basemap/decisions/{sha256_bytes(old)[7:]}.zst",
|
|
307
266
|
sha256=sha256_bytes(old),
|
|
308
|
-
raw_sha256=sha256_bytes(
|
|
267
|
+
raw_sha256=sha256_bytes(old_raw),
|
|
309
268
|
size_bytes=len(old),
|
|
310
269
|
)
|
|
311
270
|
with pytest.raises(ValueError, match="bound to different"):
|
|
@@ -315,29 +274,23 @@ def test_previous_contract_and_decision_bytes_are_rejected():
|
|
|
315
274
|
|
|
316
275
|
|
|
317
276
|
@pytest.mark.parametrize("family", ["decisions", "mapping"])
|
|
318
|
-
def
|
|
319
|
-
count = 4096
|
|
320
|
-
anchor = "sha256:" + "a" * 64
|
|
277
|
+
def test_every_byte_in_last_record_obeys_exact_decision_domain(family):
|
|
278
|
+
count, anchor = 4096, "sha256:" + "a" * 64
|
|
321
279
|
if family == "decisions":
|
|
322
280
|
carrier = encode_clean_basemap_decisions(
|
|
323
281
|
asset_sha256=anchor, decisions=np.full(count, KEEP_GROUND)
|
|
324
282
|
)
|
|
325
|
-
domain = DECISION_CODES
|
|
326
|
-
|
|
327
|
-
arguments = dict(asset_sha256=anchor, point_count=count)
|
|
328
|
-
byte_offset = -1
|
|
283
|
+
domain, decode = DECISION_CODES, decode_clean_basemap_decisions
|
|
284
|
+
arguments, byte_offset = dict(asset_sha256=anchor, point_count=count), -1
|
|
329
285
|
else:
|
|
330
286
|
carrier = encode_clean_basemap_mapping(
|
|
331
287
|
geometry_raw_sha256=anchor,
|
|
332
288
|
sweep_indices=np.zeros(count, dtype=np.uint32),
|
|
333
289
|
raw_point_ordinals=np.arange(count),
|
|
334
290
|
timestamps_ns=np.full(count, 100),
|
|
335
|
-
owner_source_indices=np.zeros(count, dtype=np.uint32),
|
|
336
|
-
owner_point_ordinals=np.arange(count),
|
|
337
291
|
decisions=np.full(count, KEEP_GROUND),
|
|
338
292
|
)
|
|
339
|
-
domain = KEEP_CODES
|
|
340
|
-
decode = decode_clean_basemap_mapping
|
|
293
|
+
domain, decode = KEEP_CODES, decode_clean_basemap_mapping
|
|
341
294
|
arguments = dict(geometry_raw_sha256=anchor, point_count=count)
|
|
342
295
|
byte_offset = -MAPPING_DTYPE.itemsize + MAPPING_DTYPE.fields["decision"][1]
|
|
343
296
|
raw = bytearray(zstandard.ZstdDecompressor().decompress(carrier.payload))
|
|
@@ -353,87 +306,30 @@ def test_every_byte_in_the_last_record_obeys_its_exact_decision_domain(family):
|
|
|
353
306
|
)
|
|
354
307
|
if code in domain:
|
|
355
308
|
values = decode(payload, descriptor=descriptor, **arguments)
|
|
356
|
-
|
|
357
|
-
assert decisions[-1] == code
|
|
358
|
-
assert np.all(decisions[:-1] == KEEP_GROUND)
|
|
309
|
+
assert (values if family == "decisions" else values["decision"])[-1] == code
|
|
359
310
|
else:
|
|
360
|
-
|
|
361
|
-
with pytest.raises(ValueError, match=message):
|
|
311
|
+
with pytest.raises(ValueError):
|
|
362
312
|
decode(payload, descriptor=descriptor, **arguments)
|
|
363
313
|
|
|
364
314
|
|
|
365
|
-
def test_pose_coverage_rejections_are_accounted_and_cannot_be_mapped():
|
|
366
|
-
manifest, assets, _ = fixture()
|
|
367
|
-
sweep = manifest["sweep_sources"][0]
|
|
368
|
-
carrier = encode_clean_basemap_decisions(
|
|
369
|
-
asset_sha256=sweep["asset_sha256"], decisions=[1, 0, 0, 2, 34]
|
|
370
|
-
)
|
|
371
|
-
sweep["decisions"] = carrier.descriptor("decisions")
|
|
372
|
-
assets[sweep["decisions"]["path"]] = carrier.payload
|
|
373
|
-
manifest["diagnostics"]["decision_counts"].update({"17": 0, "34": 1})
|
|
374
|
-
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
375
|
-
assert decode_clean_basemap_decisions(
|
|
376
|
-
carrier.payload,
|
|
377
|
-
descriptor=sweep["decisions"],
|
|
378
|
-
asset_sha256=sweep["asset_sha256"],
|
|
379
|
-
point_count=5,
|
|
380
|
-
).tolist() == [1, 0, 0, 2, 34]
|
|
381
|
-
validate(manifest, assets)
|
|
382
|
-
remap(manifest, assets, raw_point_ordinals=[0, 1, 2, 4])
|
|
383
|
-
with pytest.raises(ValueError, match="decision"):
|
|
384
|
-
validate(manifest, assets)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
def test_auto_track_regrouping_invalidates_temporal_ownership():
|
|
388
|
-
_, _, native = fixture()
|
|
389
|
-
original = compute_annotation_dependency_revisions(native["annotation"])
|
|
390
|
-
rows = copy.deepcopy(native["annotation"]["annotations"])
|
|
391
|
-
rows[0]["instance_token"] = "regrouped-track"
|
|
392
|
-
edited = build_clip_annotations(
|
|
393
|
-
native["annotation"]["clip_id"],
|
|
394
|
-
native["annotation"]["annotation_frame_id"],
|
|
395
|
-
rows,
|
|
396
|
-
)
|
|
397
|
-
assert (
|
|
398
|
-
compute_annotation_dependency_revisions(edited)["scene_ownership_revision"]
|
|
399
|
-
!= original["scene_ownership_revision"]
|
|
400
|
-
)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def test_native_label_edit_keeps_geometry_binding_but_motion_or_source_edit_does_not():
|
|
404
|
-
manifest, _, native = fixture()
|
|
405
|
-
edited = copy.deepcopy(native["annotation"]["annotations"])
|
|
406
|
-
edited[0]["motion"] = "dynamic"
|
|
407
|
-
annotation = build_clip_annotations(
|
|
408
|
-
native["annotation"]["clip_id"],
|
|
409
|
-
native["annotation"]["annotation_frame_id"],
|
|
410
|
-
edited,
|
|
411
|
-
).to_dict()
|
|
412
|
-
with pytest.raises(ValueError, match="dependencies"):
|
|
413
|
-
validate_clean_basemap_annotation(manifest, annotation)
|
|
414
|
-
scene = copy.deepcopy(native["scene_index"])
|
|
415
|
-
scene["chunks"][0]["semantic_histogram"] = [{"code": 0, "count": 3}]
|
|
416
|
-
# Existing native parsing enforces the independent label revision too.
|
|
417
|
-
from x4d_devkit.semantic_scene_contract import compute_scene_semantics_revision
|
|
418
|
-
|
|
419
|
-
scene["scene_semantics_revision"] = compute_scene_semantics_revision(scene)
|
|
420
|
-
assert clean_basemap_scene_source(scene) == manifest["scene_source"]
|
|
421
|
-
|
|
422
|
-
|
|
423
315
|
@pytest.mark.parametrize(
|
|
424
316
|
"edit",
|
|
425
317
|
[
|
|
426
318
|
lambda m: m.update(extra=True),
|
|
427
319
|
lambda m: m.update(point_count=True),
|
|
428
|
-
lambda m: m["input_identity"].update(
|
|
320
|
+
lambda m: m["input_identity"].update(
|
|
321
|
+
scene_ownership_revision="sha256:" + "f" * 64
|
|
322
|
+
),
|
|
323
|
+
lambda m: m.update(instance_sources=[]),
|
|
324
|
+
lambda m: m.update(preannotation_evidence=None),
|
|
429
325
|
lambda m: m["chunks"][0]["geometry"].update(path="../other.spc.zst"),
|
|
430
326
|
lambda m: m["chunks"][0].update(ordinal=1),
|
|
431
327
|
lambda m: m["chunks"].append(copy.deepcopy(m["chunks"][0])),
|
|
432
328
|
lambda m: m["diagnostics"]["decision_counts"].update({"17": 0}),
|
|
433
|
-
lambda m: m["instance_sources"].reverse(),
|
|
434
329
|
lambda m: m["sweep_sources"].append(copy.deepcopy(m["sweep_sources"][0])),
|
|
435
330
|
lambda m: m["profile"].update(unknown_policy="delete"),
|
|
436
331
|
lambda m: m["profile"].update(point_deskew=False),
|
|
332
|
+
lambda m: m["profile"]["policies"].update(motion={}),
|
|
437
333
|
],
|
|
438
334
|
)
|
|
439
335
|
def test_manifest_rejects_partial_unknown_and_noncanonical_shapes(edit):
|
|
@@ -444,6 +340,16 @@ def test_manifest_rejects_partial_unknown_and_noncanonical_shapes(edit):
|
|
|
444
340
|
parse_clean_basemap_manifest(manifest)
|
|
445
341
|
|
|
446
342
|
|
|
343
|
+
def test_native_label_edit_keeps_geometry_binding():
|
|
344
|
+
manifest, _, native = fixture()
|
|
345
|
+
scene = copy.deepcopy(native["scene_index"])
|
|
346
|
+
scene["chunks"][0]["semantic_histogram"] = [{"code": 0, "count": 3}]
|
|
347
|
+
from x4d_devkit.semantic_scene_contract import compute_scene_semantics_revision
|
|
348
|
+
|
|
349
|
+
scene["scene_semantics_revision"] = compute_scene_semantics_revision(scene)
|
|
350
|
+
assert clean_basemap_scene_source(scene) == manifest["scene_source"]
|
|
351
|
+
|
|
352
|
+
|
|
447
353
|
def test_decoder_rejects_cross_geometry_reserved_bytes_and_extra_frames():
|
|
448
354
|
manifest, assets, _ = fixture()
|
|
449
355
|
chunk = manifest["chunks"][0]
|
|
@@ -453,33 +359,36 @@ def test_decoder_rejects_cross_geometry_reserved_bytes_and_extra_frames():
|
|
|
453
359
|
payload,
|
|
454
360
|
descriptor=chunk["mapping"],
|
|
455
361
|
geometry_raw_sha256="sha256:" + "f" * 64,
|
|
456
|
-
point_count=
|
|
362
|
+
point_count=3,
|
|
457
363
|
)
|
|
458
364
|
raw = bytearray(zstandard.ZstdDecompressor().decompress(payload))
|
|
459
365
|
raw[44 + MAPPING_DTYPE.fields["reserved"][1]] = 1
|
|
460
366
|
malformed = zstandard.ZstdCompressor().compress(raw)
|
|
461
367
|
for body in (malformed, payload + payload):
|
|
462
|
-
descriptor =
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
368
|
+
descriptor = dict(
|
|
369
|
+
path=f"generated/reconstruction/clean_basemap/mapping/{sha256_bytes(body)[7:]}.zst",
|
|
370
|
+
sha256=sha256_bytes(body),
|
|
371
|
+
raw_sha256=sha256_bytes(bytes(raw)),
|
|
372
|
+
size_bytes=len(body),
|
|
373
|
+
)
|
|
468
374
|
with pytest.raises(ValueError):
|
|
469
375
|
decode_clean_basemap_mapping(
|
|
470
376
|
body,
|
|
471
377
|
descriptor=descriptor,
|
|
472
378
|
geometry_raw_sha256=chunk["geometry"]["raw_sha256"],
|
|
473
|
-
point_count=
|
|
379
|
+
point_count=3,
|
|
474
380
|
)
|
|
475
381
|
|
|
476
382
|
|
|
477
|
-
|
|
383
|
+
@pytest.mark.parametrize(
|
|
384
|
+
"changes",
|
|
385
|
+
[
|
|
386
|
+
{"raw_point_ordinals": [-1, 1, 2]},
|
|
387
|
+
{"timestamps_ns": [100.0] * 3},
|
|
388
|
+
{"decisions": [KEEP_GROUND, 0, 18]},
|
|
389
|
+
],
|
|
390
|
+
)
|
|
391
|
+
def test_mapping_encoder_rejects_float_negative_and_removed_observations(changes):
|
|
478
392
|
manifest, assets, _ = fixture()
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
{"timestamps_ns": [100.0] * 4},
|
|
482
|
-
{"decisions": [KEEP_GROUND, 0, 0, 17]},
|
|
483
|
-
):
|
|
484
|
-
with pytest.raises(ValueError):
|
|
485
|
-
remap(manifest, assets, **changes)
|
|
393
|
+
with pytest.raises(ValueError):
|
|
394
|
+
remap(manifest, assets, **changes)
|
|
@@ -67,12 +67,12 @@ def test_typed_client_uses_scoped_routes_and_verified_geometry():
|
|
|
67
67
|
geometry = client.reconstruction.fetch_clean_basemap_geometry(
|
|
68
68
|
current, chunk_ordinal=0
|
|
69
69
|
)
|
|
70
|
-
assert geometry.xyz.shape == (
|
|
71
|
-
assert np.array_equal(geometry.rgb[-1], [
|
|
70
|
+
assert geometry.xyz.shape == (3, 3)
|
|
71
|
+
assert np.array_equal(geometry.rgb[-1], [70, 80, 90])
|
|
72
72
|
mapping = client.reconstruction.fetch_clean_basemap_mapping(
|
|
73
73
|
current, chunk_ordinal=0
|
|
74
74
|
)
|
|
75
|
-
assert mapping["
|
|
75
|
+
assert mapping["raw_point_ordinal"].tolist() == [0, 1, 2]
|
|
76
76
|
cancelled = client.reconstruction.cancel_clean_basemap_task(
|
|
77
77
|
project_id=7, task_id="task-0"
|
|
78
78
|
)
|
|
@@ -11,7 +11,7 @@ from x4d_devkit.eval.matching import MetricData
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def test_package_version_is_current_release():
|
|
14
|
-
assert x4d_devkit.__version__ == "0.
|
|
14
|
+
assert x4d_devkit.__version__ == "0.46.0rc2"
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def test_loader_exposes_and_enforces_only_current_schema(tmp_path):
|