x4d-devkit 0.43.0rc2__tar.gz → 0.43.0rc4__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.43.0rc2/x4d_devkit.egg-info → x4d_devkit-0.43.0rc4}/PKG-INFO +1 -1
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/pyproject.toml +1 -1
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_clean_basemap.py +54 -0
- x4d_devkit-0.43.0rc4/tests/test_clean_basemap_preannotation.py +96 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_sdk_api.py +1 -1
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/clean_basemap.py +128 -7
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4/x4d_devkit.egg-info}/PKG-INFO +1 -1
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit.egg-info/SOURCES.txt +1 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/LICENSE +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/README.md +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/setup.cfg +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_annotation_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_annotation_reference.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_assets_client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_boundary.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_box.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_build_info.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_clean_basemap_client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_cli_auth.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_client_json_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_client_projects.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_clip_archives.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_contract_validation.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_coordinate_frames.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_current_state.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_current_state_identity_consumers_example.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_dataset_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_dataset_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_detection_eval.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_evaluate.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_export_bundle.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_image_review.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_inference_input.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_inference_schemas.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_inference_service.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_label_schemas.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_lidar_materialization.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_loader.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_matching.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_metrics.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_models.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_platform_pose.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_preannotation_client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_reconstruction_client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_release_gate.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_roadmark_preview.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_semantic_scene_client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_semantic_scene_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_semantic_scene_native_clip.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_time_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_token.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_tracking_eval.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_training_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_transform.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_transform_chain.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_validation.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_work_session.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/annotation_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/annotation_reference.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/build_info.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/cli.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/_origin.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/annotation_reference.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/assets.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/bags.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/capabilities.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/checkpoints.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/clean_basemap.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/client.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/clip_work_sessions.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/clips.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/dataset_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/image_review.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/label_schemas.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/preannotation.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/projects.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/reconstruction.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/semantic_scene.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/services.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/client/test_sets.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/consumer_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/coordinate_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/core/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/core/loader.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/core/models.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/core/token.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/core/transform.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/current_state.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/dataset_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/dataset_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/api.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/box.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/detection.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/matching.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/metrics.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/eval/tracking.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/export_bundle.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/image_review.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/input.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/models.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/schemas.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/service.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/inference/tasks.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/json_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/label_schema.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/lidar_materialization.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/materialize.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/roadmark_preview.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/semantic_scene_authoring.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/semantic_scene_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/time_contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/training_identity.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/validation/__init__.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/validation/contract.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/validation/platform_pose.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/validation/report.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/validation/validator.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit/work_session.py +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit.egg-info/dependency_links.txt +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit.egg-info/entry_points.txt +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/x4d_devkit.egg-info/requires.txt +0 -0
- {x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/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.43.
|
|
7
|
+
version = "0.43.0rc4"
|
|
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"
|
|
@@ -10,6 +10,7 @@ from x4d_devkit.clean_basemap import (
|
|
|
10
10
|
CLEAN_BASEMAP_CONTRACT_VERSION,
|
|
11
11
|
CLEAN_BASEMAP_INPUT_FIELDS,
|
|
12
12
|
DECISION_CODES,
|
|
13
|
+
KEEP_CODES,
|
|
13
14
|
KEEP_GROUND,
|
|
14
15
|
MAPPING_DTYPE,
|
|
15
16
|
REMOVE_MODEL_DYNAMIC,
|
|
@@ -24,6 +25,7 @@ from x4d_devkit.clean_basemap import (
|
|
|
24
25
|
validate_clean_basemap_annotation,
|
|
25
26
|
validate_clean_basemap_native_binding,
|
|
26
27
|
validate_clean_basemap_resource,
|
|
28
|
+
compute_clean_basemap_preannotation_revision,
|
|
27
29
|
)
|
|
28
30
|
from x4d_devkit.semantic_scene_contract import (
|
|
29
31
|
compute_annotation_dependency_revisions,
|
|
@@ -96,6 +98,9 @@ def fixture():
|
|
|
96
98
|
},
|
|
97
99
|
}
|
|
98
100
|
inputs = {key: "sha256:" + "b" * 64 for key in CLEAN_BASEMAP_INPUT_FIELDS}
|
|
101
|
+
inputs["preannotation_revision"] = compute_clean_basemap_preannotation_revision(
|
|
102
|
+
None
|
|
103
|
+
)
|
|
99
104
|
dependencies = compute_annotation_dependency_revisions(native["annotation"])
|
|
100
105
|
for key in inputs:
|
|
101
106
|
if key in dependencies:
|
|
@@ -109,6 +114,7 @@ def fixture():
|
|
|
109
114
|
inputs, profile
|
|
110
115
|
),
|
|
111
116
|
"input_identity": inputs,
|
|
117
|
+
"preannotation_evidence": None,
|
|
112
118
|
"profile": profile,
|
|
113
119
|
"point_count": 4,
|
|
114
120
|
"bounds": [xyz.min(0).tolist(), xyz.max(0).tolist()],
|
|
@@ -308,6 +314,54 @@ def test_previous_contract_and_decision_bytes_are_rejected():
|
|
|
308
314
|
)
|
|
309
315
|
|
|
310
316
|
|
|
317
|
+
@pytest.mark.parametrize("family", ["decisions", "mapping"])
|
|
318
|
+
def test_every_byte_in_the_last_record_obeys_its_exact_decision_domain(family):
|
|
319
|
+
count = 4096
|
|
320
|
+
anchor = "sha256:" + "a" * 64
|
|
321
|
+
if family == "decisions":
|
|
322
|
+
carrier = encode_clean_basemap_decisions(
|
|
323
|
+
asset_sha256=anchor, decisions=np.full(count, KEEP_GROUND)
|
|
324
|
+
)
|
|
325
|
+
domain = DECISION_CODES
|
|
326
|
+
decode = decode_clean_basemap_decisions
|
|
327
|
+
arguments = dict(asset_sha256=anchor, point_count=count)
|
|
328
|
+
byte_offset = -1
|
|
329
|
+
else:
|
|
330
|
+
carrier = encode_clean_basemap_mapping(
|
|
331
|
+
geometry_raw_sha256=anchor,
|
|
332
|
+
sweep_indices=np.zeros(count, dtype=np.uint32),
|
|
333
|
+
raw_point_ordinals=np.arange(count),
|
|
334
|
+
timestamps_ns=np.full(count, 100),
|
|
335
|
+
owner_source_indices=np.zeros(count, dtype=np.uint32),
|
|
336
|
+
owner_point_ordinals=np.arange(count),
|
|
337
|
+
decisions=np.full(count, KEEP_GROUND),
|
|
338
|
+
)
|
|
339
|
+
domain = KEEP_CODES
|
|
340
|
+
decode = decode_clean_basemap_mapping
|
|
341
|
+
arguments = dict(geometry_raw_sha256=anchor, point_count=count)
|
|
342
|
+
byte_offset = -MAPPING_DTYPE.itemsize + MAPPING_DTYPE.fields["decision"][1]
|
|
343
|
+
raw = bytearray(zstandard.ZstdDecompressor().decompress(carrier.payload))
|
|
344
|
+
for code in range(256):
|
|
345
|
+
raw[byte_offset] = code
|
|
346
|
+
payload = zstandard.ZstdCompressor().compress(raw)
|
|
347
|
+
descriptor = carrier.descriptor(family)
|
|
348
|
+
descriptor.update(
|
|
349
|
+
path=f"generated/reconstruction/clean_basemap/{family}/{sha256_bytes(payload)[7:]}.zst",
|
|
350
|
+
sha256=sha256_bytes(payload),
|
|
351
|
+
raw_sha256=sha256_bytes(bytes(raw)),
|
|
352
|
+
size_bytes=len(payload),
|
|
353
|
+
)
|
|
354
|
+
if code in domain:
|
|
355
|
+
values = decode(payload, descriptor=descriptor, **arguments)
|
|
356
|
+
decisions = values if family == "decisions" else values["decision"]
|
|
357
|
+
assert decisions[-1] == code
|
|
358
|
+
assert np.all(decisions[:-1] == KEEP_GROUND)
|
|
359
|
+
else:
|
|
360
|
+
message = "decision" if family == "decisions" else "mapping records"
|
|
361
|
+
with pytest.raises(ValueError, match=message):
|
|
362
|
+
decode(payload, descriptor=descriptor, **arguments)
|
|
363
|
+
|
|
364
|
+
|
|
311
365
|
def test_pose_coverage_rejections_are_accounted_and_cannot_be_mapped():
|
|
312
366
|
manifest, assets, _ = fixture()
|
|
313
367
|
sweep = manifest["sweep_sources"][0]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from tests.test_clean_basemap import fixture
|
|
6
|
+
from x4d_devkit.clean_basemap import (
|
|
7
|
+
CLEAN_BASEMAP_PREANNOTATION_CONTRACT_VERSION,
|
|
8
|
+
clean_basemap_preannotation_reference,
|
|
9
|
+
compute_clean_basemap_dependency_identity,
|
|
10
|
+
compute_clean_basemap_preannotation_revision,
|
|
11
|
+
compute_clean_basemap_revision,
|
|
12
|
+
parse_clean_basemap_manifest,
|
|
13
|
+
validate_clean_basemap_preannotation_evidence,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def evidence_fixture():
|
|
18
|
+
manifest, _, native = fixture()
|
|
19
|
+
evidence = {
|
|
20
|
+
"contract_version": CLEAN_BASEMAP_PREANNOTATION_CONTRACT_VERSION,
|
|
21
|
+
"clip_id": manifest["clip_id"],
|
|
22
|
+
"candidate_id": "sha256:" + "c" * 64,
|
|
23
|
+
"profile_id": "detector-profile-1",
|
|
24
|
+
"pipeline_identity": "sha256:" + "d" * 64,
|
|
25
|
+
"checkpoint_identity": "sha256:" + "e" * 64,
|
|
26
|
+
"source_identity": {
|
|
27
|
+
key: manifest["input_identity"][key]
|
|
28
|
+
for key in (
|
|
29
|
+
"samples_revision",
|
|
30
|
+
"sweeps_revision",
|
|
31
|
+
"calibration_revision",
|
|
32
|
+
"pose_revision",
|
|
33
|
+
)
|
|
34
|
+
},
|
|
35
|
+
"annotation": native["annotation"],
|
|
36
|
+
}
|
|
37
|
+
manifest["preannotation_evidence"] = clean_basemap_preannotation_reference(evidence)
|
|
38
|
+
manifest["input_identity"]["preannotation_revision"] = (
|
|
39
|
+
compute_clean_basemap_preannotation_revision(evidence)
|
|
40
|
+
)
|
|
41
|
+
manifest["dependency_identity"] = compute_clean_basemap_dependency_identity(
|
|
42
|
+
manifest["input_identity"], manifest["profile"]
|
|
43
|
+
)
|
|
44
|
+
manifest["basemap_revision"] = compute_clean_basemap_revision(manifest)
|
|
45
|
+
return manifest, evidence
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_evidence_is_bound_separately_and_does_not_add_native_instances():
|
|
49
|
+
manifest, evidence = evidence_fixture()
|
|
50
|
+
before = copy.deepcopy(manifest["instance_sources"])
|
|
51
|
+
parsed = parse_clean_basemap_manifest(manifest)
|
|
52
|
+
assert (
|
|
53
|
+
validate_clean_basemap_preannotation_evidence(
|
|
54
|
+
evidence, clip_id=parsed.clip_id, input_identity=manifest["input_identity"]
|
|
55
|
+
)
|
|
56
|
+
== evidence
|
|
57
|
+
)
|
|
58
|
+
assert parsed.to_dict()["instance_sources"] == before
|
|
59
|
+
assert "annotation" not in parsed.to_dict()["preannotation_evidence"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.parametrize(
|
|
63
|
+
"field",
|
|
64
|
+
["samples_revision", "sweeps_revision", "calibration_revision", "pose_revision"],
|
|
65
|
+
)
|
|
66
|
+
def test_evidence_from_different_geometry_cannot_bind(field):
|
|
67
|
+
manifest, evidence = evidence_fixture()
|
|
68
|
+
evidence["source_identity"][field] = "sha256:" + "f" * 64
|
|
69
|
+
with pytest.raises(ValueError, match="source differs"):
|
|
70
|
+
validate_clean_basemap_preannotation_evidence(
|
|
71
|
+
evidence,
|
|
72
|
+
clip_id=manifest["clip_id"],
|
|
73
|
+
input_identity=manifest["input_identity"],
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_different_candidate_or_absent_evidence_requires_new_identity():
|
|
78
|
+
manifest, evidence = evidence_fixture()
|
|
79
|
+
evidence["candidate_id"] = "sha256:" + "f" * 64
|
|
80
|
+
with pytest.raises(ValueError, match="revision differs"):
|
|
81
|
+
validate_clean_basemap_preannotation_evidence(
|
|
82
|
+
evidence,
|
|
83
|
+
clip_id=manifest["clip_id"],
|
|
84
|
+
input_identity=manifest["input_identity"],
|
|
85
|
+
)
|
|
86
|
+
with pytest.raises(ValueError, match="revision differs"):
|
|
87
|
+
validate_clean_basemap_preannotation_evidence(
|
|
88
|
+
None, clip_id=manifest["clip_id"], input_identity=manifest["input_identity"]
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_historical_v2_is_rejected_even_with_current_fields():
|
|
93
|
+
manifest, _ = evidence_fixture()
|
|
94
|
+
manifest["contract_version"] = "x4d-clean-static-basemap-v2"
|
|
95
|
+
with pytest.raises(ValueError, match="current contract"):
|
|
96
|
+
parse_clean_basemap_manifest(manifest)
|
|
@@ -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.43.
|
|
14
|
+
assert x4d_devkit.__version__ == "0.43.0rc4"
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def test_loader_exposes_and_enforces_only_current_schema(tmp_path):
|
|
@@ -36,7 +36,11 @@ from x4d_devkit.semantic_scene_contract import (
|
|
|
36
36
|
)
|
|
37
37
|
from x4d_devkit.time_contract import parse_time_ns
|
|
38
38
|
|
|
39
|
-
CLEAN_BASEMAP_CONTRACT_VERSION = "x4d-clean-static-basemap-
|
|
39
|
+
CLEAN_BASEMAP_CONTRACT_VERSION = "x4d-clean-static-basemap-v3"
|
|
40
|
+
CLEAN_BASEMAP_PREANNOTATION_CONTRACT_VERSION = "x4d-clean-basemap-preannotation-v1"
|
|
41
|
+
_GEOMETRY_INPUT_FIELDS = frozenset(
|
|
42
|
+
{"samples_revision", "sweeps_revision", "calibration_revision", "pose_revision"}
|
|
43
|
+
)
|
|
40
44
|
CLEAN_BASEMAP_OPERATION = "reconstruction.prepare_clean_static_basemap"
|
|
41
45
|
CLEAN_BASEMAP_MAPPING_FORMAT = "x4d-clean-static-basemap-mapping-v1"
|
|
42
46
|
CLEAN_BASEMAP_DECISION_FORMAT = "x4d-clean-static-basemap-decisions-v2"
|
|
@@ -49,6 +53,7 @@ CLEAN_BASEMAP_INPUT_FIELDS = frozenset(
|
|
|
49
53
|
"scene_ownership_revision",
|
|
50
54
|
"instance_shape_input_revision",
|
|
51
55
|
"image_input_revision",
|
|
56
|
+
"preannotation_revision",
|
|
52
57
|
}
|
|
53
58
|
)
|
|
54
59
|
KEEP_STATIC = 0
|
|
@@ -183,6 +188,117 @@ def compute_clean_basemap_revision(value: Mapping[str, Any]) -> str:
|
|
|
183
188
|
return canonical_json_sha256(data)
|
|
184
189
|
|
|
185
190
|
|
|
191
|
+
def parse_clean_basemap_preannotation_evidence(value: Any) -> dict | None:
|
|
192
|
+
"""Validate supplemental hypotheses without granting native ownership."""
|
|
193
|
+
if value is None:
|
|
194
|
+
return None
|
|
195
|
+
data = _thaw(value)
|
|
196
|
+
_object(
|
|
197
|
+
data,
|
|
198
|
+
{
|
|
199
|
+
"contract_version",
|
|
200
|
+
"clip_id",
|
|
201
|
+
"candidate_id",
|
|
202
|
+
"profile_id",
|
|
203
|
+
"pipeline_identity",
|
|
204
|
+
"checkpoint_identity",
|
|
205
|
+
"source_identity",
|
|
206
|
+
"annotation",
|
|
207
|
+
},
|
|
208
|
+
"preannotation_evidence",
|
|
209
|
+
)
|
|
210
|
+
ensure_i_json(data, path="preannotation_evidence")
|
|
211
|
+
if data["contract_version"] != CLEAN_BASEMAP_PREANNOTATION_CONTRACT_VERSION:
|
|
212
|
+
raise ValueError("preannotation evidence requires the current contract")
|
|
213
|
+
parse_portable_token(data["clip_id"], path="preannotation_evidence.clip_id")
|
|
214
|
+
parse_portable_token(data["profile_id"], path="preannotation_evidence.profile_id")
|
|
215
|
+
for key in ("candidate_id", "pipeline_identity", "checkpoint_identity"):
|
|
216
|
+
_hash(data[key], f"preannotation_evidence.{key}")
|
|
217
|
+
_object(
|
|
218
|
+
data["source_identity"], _GEOMETRY_INPUT_FIELDS, "preannotation source_identity"
|
|
219
|
+
)
|
|
220
|
+
for key, identity in data["source_identity"].items():
|
|
221
|
+
_hash(identity, f"preannotation source_identity.{key}")
|
|
222
|
+
annotation = parse_clip_annotations(data["annotation"])
|
|
223
|
+
if annotation.clip_id != data["clip_id"]:
|
|
224
|
+
raise ValueError("preannotation evidence annotation belongs to another Clip")
|
|
225
|
+
data["annotation"] = annotation.to_dict()
|
|
226
|
+
return data
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def clean_basemap_preannotation_reference(value: Any) -> dict | None:
|
|
230
|
+
data = parse_clean_basemap_preannotation_evidence(value)
|
|
231
|
+
if data is None:
|
|
232
|
+
return None
|
|
233
|
+
annotation = data.pop("annotation")
|
|
234
|
+
return {**data, "annotation_revision": annotation["annotation_revision"]}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def compute_clean_basemap_preannotation_revision(value: Any) -> str:
|
|
238
|
+
return canonical_json_sha256(
|
|
239
|
+
{"evidence": clean_basemap_preannotation_reference(value)}
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _validate_preannotation_reference(reference, *, clip_id, input_identity):
|
|
244
|
+
if reference is not None:
|
|
245
|
+
_object(
|
|
246
|
+
reference,
|
|
247
|
+
{
|
|
248
|
+
"contract_version",
|
|
249
|
+
"clip_id",
|
|
250
|
+
"candidate_id",
|
|
251
|
+
"profile_id",
|
|
252
|
+
"pipeline_identity",
|
|
253
|
+
"checkpoint_identity",
|
|
254
|
+
"source_identity",
|
|
255
|
+
"annotation_revision",
|
|
256
|
+
},
|
|
257
|
+
"preannotation_evidence",
|
|
258
|
+
)
|
|
259
|
+
if (
|
|
260
|
+
reference["contract_version"]
|
|
261
|
+
!= CLEAN_BASEMAP_PREANNOTATION_CONTRACT_VERSION
|
|
262
|
+
or reference["clip_id"] != clip_id
|
|
263
|
+
):
|
|
264
|
+
raise ValueError("preannotation evidence contract or Clip differs")
|
|
265
|
+
parse_portable_token(
|
|
266
|
+
reference["profile_id"], path="preannotation_evidence.profile_id"
|
|
267
|
+
)
|
|
268
|
+
for key in (
|
|
269
|
+
"candidate_id",
|
|
270
|
+
"pipeline_identity",
|
|
271
|
+
"checkpoint_identity",
|
|
272
|
+
"annotation_revision",
|
|
273
|
+
):
|
|
274
|
+
_hash(reference[key], f"preannotation_evidence.{key}")
|
|
275
|
+
_object(
|
|
276
|
+
reference["source_identity"],
|
|
277
|
+
_GEOMETRY_INPUT_FIELDS,
|
|
278
|
+
"preannotation source_identity",
|
|
279
|
+
)
|
|
280
|
+
if reference["source_identity"] != {
|
|
281
|
+
key: input_identity[key] for key in _GEOMETRY_INPUT_FIELDS
|
|
282
|
+
}:
|
|
283
|
+
raise ValueError("preannotation evidence source differs from clean basemap")
|
|
284
|
+
if (
|
|
285
|
+
canonical_json_sha256({"evidence": reference})
|
|
286
|
+
!= input_identity["preannotation_revision"]
|
|
287
|
+
):
|
|
288
|
+
raise ValueError("preannotation evidence revision differs from clean basemap")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def validate_clean_basemap_preannotation_evidence(value, *, clip_id, input_identity):
|
|
292
|
+
"""Validate the full frozen evidence against its manifest dependency."""
|
|
293
|
+
data = parse_clean_basemap_preannotation_evidence(value)
|
|
294
|
+
_validate_preannotation_reference(
|
|
295
|
+
clean_basemap_preannotation_reference(data),
|
|
296
|
+
clip_id=clip_id,
|
|
297
|
+
input_identity=input_identity,
|
|
298
|
+
)
|
|
299
|
+
return data
|
|
300
|
+
|
|
301
|
+
|
|
186
302
|
def compute_clean_basemap_dependency_identity(
|
|
187
303
|
input_identity: Mapping[str, str], profile: Mapping[str, Any]
|
|
188
304
|
) -> str:
|
|
@@ -285,6 +401,7 @@ def parse_clean_basemap_manifest(
|
|
|
285
401
|
"basemap_revision",
|
|
286
402
|
"dependency_identity",
|
|
287
403
|
"input_identity",
|
|
404
|
+
"preannotation_evidence",
|
|
288
405
|
"profile",
|
|
289
406
|
"point_count",
|
|
290
407
|
"bounds",
|
|
@@ -303,6 +420,11 @@ def parse_clean_basemap_manifest(
|
|
|
303
420
|
):
|
|
304
421
|
raise ValueError("clean basemap requires the current contract in clip_world")
|
|
305
422
|
parse_portable_token(data["clip_id"], path="clean_basemap.clip_id")
|
|
423
|
+
_validate_preannotation_reference(
|
|
424
|
+
data["preannotation_evidence"],
|
|
425
|
+
clip_id=data["clip_id"],
|
|
426
|
+
input_identity=data["input_identity"],
|
|
427
|
+
)
|
|
306
428
|
_hash(data["basemap_revision"], "basemap_revision")
|
|
307
429
|
if data["dependency_identity"] != compute_clean_basemap_dependency_identity(
|
|
308
430
|
data["input_identity"], data["profile"]
|
|
@@ -528,9 +650,8 @@ def encode_clean_basemap_mapping(
|
|
|
528
650
|
}
|
|
529
651
|
count = len(vectors["sweep_index"])
|
|
530
652
|
_integer(count, 1, SEMANTIC_SCENE_MAX_SCENE_POINTS_PER_CHUNK, "point_count")
|
|
531
|
-
if (
|
|
532
|
-
|
|
533
|
-
or not set(int(v) for v in vectors["decision"]) <= KEEP_CODES
|
|
653
|
+
if any(len(vector) != count for vector in vectors.values()) or np.any(
|
|
654
|
+
~np.isin(vectors["decision"], tuple(KEEP_CODES))
|
|
534
655
|
):
|
|
535
656
|
raise ValueError(
|
|
536
657
|
"mapping must have one retained decision and address per geometry point"
|
|
@@ -560,7 +681,7 @@ def decode_clean_basemap_mapping(
|
|
|
560
681
|
)
|
|
561
682
|
if (
|
|
562
683
|
np.any(records["reserved"] != 0)
|
|
563
|
-
or
|
|
684
|
+
or np.any(~np.isin(records["decision"], tuple(KEEP_CODES)))
|
|
564
685
|
or np.any(records["timestamp_ns"] > _MAX_I64)
|
|
565
686
|
):
|
|
566
687
|
raise ValueError(
|
|
@@ -574,7 +695,7 @@ def encode_clean_basemap_decisions(
|
|
|
574
695
|
) -> CleanBasemapPayload:
|
|
575
696
|
values = _vector(decisions, 255, "decisions")
|
|
576
697
|
_integer(len(values), 1, 1 << 24, "source_point_count")
|
|
577
|
-
if
|
|
698
|
+
if np.any(~np.isin(values, tuple(DECISION_CODES))):
|
|
578
699
|
raise ValueError("unknown clean basemap decision code")
|
|
579
700
|
return _encode(_DECISION_MAGIC, asset_sha256, values.astype(np.uint8))
|
|
580
701
|
|
|
@@ -591,7 +712,7 @@ def decode_clean_basemap_decisions(
|
|
|
591
712
|
values = _decode(
|
|
592
713
|
payload, descriptor, _DECISION_MAGIC, asset_sha256, point_count, np.dtype("u1")
|
|
593
714
|
)
|
|
594
|
-
if
|
|
715
|
+
if np.any(~np.isin(values, tuple(DECISION_CODES))):
|
|
595
716
|
raise ValueError("unknown clean basemap decision code")
|
|
596
717
|
return values
|
|
597
718
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{x4d_devkit-0.43.0rc2 → x4d_devkit-0.43.0rc4}/tests/test_current_state_identity_consumers_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|