x4d-devkit 0.44.0rc1__tar.gz → 0.45.0__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.
Files changed (134) hide show
  1. {x4d_devkit-0.44.0rc1/x4d_devkit.egg-info → x4d_devkit-0.45.0}/PKG-INFO +8 -8
  2. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/README.md +7 -7
  3. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/pyproject.toml +1 -1
  4. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_contract_validation.py +3 -4
  5. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_current_state.py +2 -2
  6. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_dataset_identity.py +1 -1
  7. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_export_bundle.py +2 -2
  8. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_inference_input.py +2 -2
  9. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_inference_schemas.py +3 -3
  10. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_inference_service.py +1 -1
  11. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_label_schemas.py +2 -2
  12. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_loader.py +1 -1
  13. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_models.py +2 -3
  14. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_preannotation_client.py +1 -1
  15. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_sdk_api.py +4 -4
  16. x4d_devkit-0.45.0/tests/test_source_attributes.py +54 -0
  17. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_training_identity.py +3 -3
  18. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_work_session.py +4 -5
  19. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/annotation_contract.py +2 -2
  20. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/cli.py +1 -1
  21. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/core/loader.py +5 -5
  22. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/core/models.py +6 -6
  23. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/dataset_contract.py +16 -8
  24. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/dataset_identity.py +1 -1
  25. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/tracking.py +4 -4
  26. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/export_bundle.py +1 -1
  27. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/input.py +1 -1
  28. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/schemas.py +2 -2
  29. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/label_schema.py +1 -1
  30. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/lidar_materialization.py +1 -1
  31. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/materialize.py +5 -5
  32. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/semantic_scene_contract.py +3 -3
  33. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/time_contract.py +1 -1
  34. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/validation/platform_pose.py +1 -1
  35. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/validation/validator.py +6 -6
  36. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0/x4d_devkit.egg-info}/PKG-INFO +8 -8
  37. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit.egg-info/SOURCES.txt +1 -0
  38. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/LICENSE +0 -0
  39. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/setup.cfg +0 -0
  40. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_annotation_contract.py +0 -0
  41. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_annotation_reference.py +0 -0
  42. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_assets_client.py +0 -0
  43. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_boundary.py +0 -0
  44. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_box.py +0 -0
  45. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_build_info.py +0 -0
  46. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_clean_basemap.py +0 -0
  47. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_clean_basemap_client.py +0 -0
  48. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_clean_basemap_preannotation.py +0 -0
  49. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_cli_auth.py +0 -0
  50. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_client_json_contract.py +0 -0
  51. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_client_projects.py +0 -0
  52. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_clip_archives.py +0 -0
  53. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_coordinate_frames.py +0 -0
  54. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_current_state_identity_consumers_example.py +0 -0
  55. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_dataset_contract.py +0 -0
  56. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_detection_eval.py +0 -0
  57. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_evaluate.py +0 -0
  58. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_image_review.py +0 -0
  59. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_lidar_materialization.py +0 -0
  60. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_matching.py +0 -0
  61. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_metrics.py +0 -0
  62. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_platform_pose.py +0 -0
  63. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_reconstruction_client.py +0 -0
  64. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_release_gate.py +0 -0
  65. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_roadmark_preview.py +0 -0
  66. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_semantic_scene_authoring.py +0 -0
  67. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_semantic_scene_client.py +0 -0
  68. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_semantic_scene_contract.py +0 -0
  69. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_semantic_scene_native_clip.py +0 -0
  70. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_time_contract.py +0 -0
  71. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_token.py +0 -0
  72. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_tracking_eval.py +0 -0
  73. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_transform.py +0 -0
  74. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_transform_chain.py +0 -0
  75. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_validation.py +0 -0
  76. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_vector_map.py +0 -0
  77. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_vector_map_geometry.py +0 -0
  78. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/tests/test_vector_map_session.py +0 -0
  79. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/__init__.py +0 -0
  80. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/annotation_reference.py +0 -0
  81. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/build_info.py +0 -0
  82. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/clean_basemap.py +0 -0
  83. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/__init__.py +0 -0
  84. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/_origin.py +0 -0
  85. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/annotation_reference.py +0 -0
  86. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/assets.py +0 -0
  87. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/bags.py +0 -0
  88. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/capabilities.py +0 -0
  89. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/checkpoints.py +0 -0
  90. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/clean_basemap.py +0 -0
  91. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/client.py +0 -0
  92. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/clip_work_sessions.py +0 -0
  93. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/clips.py +0 -0
  94. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/dataset_identity.py +0 -0
  95. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/image_review.py +0 -0
  96. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/label_schemas.py +0 -0
  97. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/preannotation.py +0 -0
  98. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/projects.py +0 -0
  99. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/reconstruction.py +0 -0
  100. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/semantic_scene.py +0 -0
  101. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/semantic_scene_authoring.py +0 -0
  102. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/services.py +0 -0
  103. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/client/test_sets.py +0 -0
  104. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/consumer_identity.py +0 -0
  105. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/coordinate_contract.py +0 -0
  106. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/core/__init__.py +0 -0
  107. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/core/token.py +0 -0
  108. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/core/transform.py +0 -0
  109. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/current_state.py +0 -0
  110. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/__init__.py +0 -0
  111. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/api.py +0 -0
  112. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/box.py +0 -0
  113. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/detection.py +0 -0
  114. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/matching.py +0 -0
  115. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/eval/metrics.py +0 -0
  116. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/image_review.py +0 -0
  117. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/__init__.py +0 -0
  118. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/models.py +0 -0
  119. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/service.py +0 -0
  120. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/inference/tasks.py +0 -0
  121. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/json_contract.py +0 -0
  122. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/roadmark_preview.py +0 -0
  123. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/semantic_scene_authoring.py +0 -0
  124. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/training_identity.py +0 -0
  125. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/validation/__init__.py +0 -0
  126. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/validation/contract.py +0 -0
  127. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/validation/report.py +0 -0
  128. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/vector_map.py +0 -0
  129. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/vector_map_geometry.py +0 -0
  130. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit/work_session.py +0 -0
  131. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit.egg-info/dependency_links.txt +0 -0
  132. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit.egg-info/entry_points.txt +0 -0
  133. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit.egg-info/requires.txt +0 -0
  134. {x4d_devkit-0.44.0rc1 → x4d_devkit-0.45.0}/x4d_devkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x4d-devkit
3
- Version: 0.44.0rc1
3
+ Version: 0.45.0
4
4
  Summary: Official X-4D external SDK and CLI for datasets, platform APIs, training bridges, and automation
5
5
  Author: windzu
6
6
  License-Expression: Apache-2.0
@@ -97,18 +97,18 @@ platform-to-platform data flow. See
97
97
  generic identity model, and
98
98
  [docs/training-current-state-data.md](docs/training-current-state-data.md) for
99
99
  work-session materialization and conditional annotation writeback. Every
100
- Dataset 0.17 Clip carries its authoritative Label Schema snapshot at root
100
+ Dataset 0.18 Clip carries its authoritative Label Schema snapshot at root
101
101
  `label_schema.json`.
102
102
  Shared validation rules for platform submit, X-Points preflight, local clip
103
103
  validation, and training consumers are documented in
104
104
  [docs/shared-contract-validation.md](docs/shared-contract-validation.md).
105
- The Dataset 0.17 native contract, exact nanosecond time, Multi-LiDAR layout,
105
+ The Dataset 0.18 native contract, exact nanosecond time, Multi-LiDAR layout,
106
106
  and model materialization are documented in
107
- [docs/dataset-0.17.md](docs/dataset-0.17.md). The single-file annotation
107
+ [docs/dataset-0.18.md](docs/dataset-0.18.md). The single-file annotation
108
108
  authority, semantic revision, and
109
109
  derived track views are documented in
110
110
  [docs/annotation-contract.md](docs/annotation-contract.md).
111
- Portable export producers and consumers share the exact `0.17` manifest
111
+ Portable export producers and consumers share the exact `0.18` manifest
112
112
  parser documented in
113
113
  [docs/export-bundle-contract.md](docs/export-bundle-contract.md).
114
114
  `examples/current_state_identity_consumers.py` provides an offline downstream
@@ -133,7 +133,7 @@ Included:
133
133
  - Typed point-level semantic-scene authoring sessions, dirty semantic-chunk upload, and
134
134
  complete compare-and-set submit without a per-point mutation API.
135
135
  - Strict validation of `x4d-training-identity-v5` manifests.
136
- - Strict producer-option and manifest parsing for export bundle `0.17`.
136
+ - Strict producer-option and manifest parsing for export bundle `0.18`.
137
137
  - Clip preannotation protocol, source-only inference adapter, and service
138
138
  wrapper for algorithm projects.
139
139
 
@@ -247,7 +247,7 @@ comparison = compare_project_label_schema_snapshots(project_schema, current)
247
247
  assert comparison.status == "same"
248
248
  ```
249
249
 
250
- The native Dataset 0.17 Clip stores the immutable identity in
250
+ The native Dataset 0.18 Clip stores the immutable identity in
251
251
  `meta.label_schema` and the complete authoritative snapshot in root
252
252
  `label_schema.json`. Registry records are used when creating/binding Clips, not
253
253
  when loading or validating their current contents.
@@ -402,7 +402,7 @@ asset existence and point-cloud layout checks without downloading the assets.
402
402
 
403
403
  Third-party model projects should use `x4d-devkit[inference]` instead of
404
404
  hand-writing the X-4D preannotation protocol. The pipeline receives an
405
- annotation-isolated `InferenceClip` and returns one complete Dataset 0.17
405
+ annotation-isolated `InferenceClip` and returns one complete Dataset 0.18
406
406
  annotation document.
407
407
 
408
408
  ```python
@@ -54,18 +54,18 @@ platform-to-platform data flow. See
54
54
  generic identity model, and
55
55
  [docs/training-current-state-data.md](docs/training-current-state-data.md) for
56
56
  work-session materialization and conditional annotation writeback. Every
57
- Dataset 0.17 Clip carries its authoritative Label Schema snapshot at root
57
+ Dataset 0.18 Clip carries its authoritative Label Schema snapshot at root
58
58
  `label_schema.json`.
59
59
  Shared validation rules for platform submit, X-Points preflight, local clip
60
60
  validation, and training consumers are documented in
61
61
  [docs/shared-contract-validation.md](docs/shared-contract-validation.md).
62
- The Dataset 0.17 native contract, exact nanosecond time, Multi-LiDAR layout,
62
+ The Dataset 0.18 native contract, exact nanosecond time, Multi-LiDAR layout,
63
63
  and model materialization are documented in
64
- [docs/dataset-0.17.md](docs/dataset-0.17.md). The single-file annotation
64
+ [docs/dataset-0.18.md](docs/dataset-0.18.md). The single-file annotation
65
65
  authority, semantic revision, and
66
66
  derived track views are documented in
67
67
  [docs/annotation-contract.md](docs/annotation-contract.md).
68
- Portable export producers and consumers share the exact `0.17` manifest
68
+ Portable export producers and consumers share the exact `0.18` manifest
69
69
  parser documented in
70
70
  [docs/export-bundle-contract.md](docs/export-bundle-contract.md).
71
71
  `examples/current_state_identity_consumers.py` provides an offline downstream
@@ -90,7 +90,7 @@ Included:
90
90
  - Typed point-level semantic-scene authoring sessions, dirty semantic-chunk upload, and
91
91
  complete compare-and-set submit without a per-point mutation API.
92
92
  - Strict validation of `x4d-training-identity-v5` manifests.
93
- - Strict producer-option and manifest parsing for export bundle `0.17`.
93
+ - Strict producer-option and manifest parsing for export bundle `0.18`.
94
94
  - Clip preannotation protocol, source-only inference adapter, and service
95
95
  wrapper for algorithm projects.
96
96
 
@@ -204,7 +204,7 @@ comparison = compare_project_label_schema_snapshots(project_schema, current)
204
204
  assert comparison.status == "same"
205
205
  ```
206
206
 
207
- The native Dataset 0.17 Clip stores the immutable identity in
207
+ The native Dataset 0.18 Clip stores the immutable identity in
208
208
  `meta.label_schema` and the complete authoritative snapshot in root
209
209
  `label_schema.json`. Registry records are used when creating/binding Clips, not
210
210
  when loading or validating their current contents.
@@ -359,7 +359,7 @@ asset existence and point-cloud layout checks without downloading the assets.
359
359
 
360
360
  Third-party model projects should use `x4d-devkit[inference]` instead of
361
361
  hand-writing the X-4D preannotation protocol. The pipeline receives an
362
- annotation-isolated `InferenceClip` and returns one complete Dataset 0.17
362
+ annotation-isolated `InferenceClip` and returns one complete Dataset 0.18
363
363
  annotation document.
364
364
 
365
365
  ```python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "x4d-devkit"
7
- version = "0.44.0rc1"
7
+ version = "0.45.0"
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"
@@ -24,9 +24,8 @@ def _time(value: int) -> dict[str, int]:
24
24
  def _meta(*, keyframe_count: int = 1) -> dict:
25
25
  return {
26
26
  "clip_id": "clip-a",
27
- "schema_version": "0.17",
27
+ "schema_version": "0.18",
28
28
  "session_id": "session-a",
29
- "vehicle_id": "vehicle-a",
30
29
  "capture_time": _time(1),
31
30
  "duration_s": float(max(0, keyframe_count - 1)),
32
31
  "keyframe_count": keyframe_count,
@@ -152,7 +151,7 @@ def _context(
152
151
  ) -> ClipValidationContext:
153
152
  return ClipValidationContext(
154
153
  clip_id="clip-a",
155
- clip_schema_version="0.17",
154
+ clip_schema_version="0.18",
156
155
  label_schema=_schema(),
157
156
  samples=[_sample()] if samples is None else samples,
158
157
  sample_data=[_sample_data()] if sample_data is None else sample_data,
@@ -423,7 +422,7 @@ def test_context_rejects_non_list_payloads_and_invalid_meta():
423
422
  with pytest.raises(TypeError):
424
423
  ClipValidationContext(
425
424
  clip_id="clip-a",
426
- clip_schema_version="0.17",
425
+ clip_schema_version="0.18",
427
426
  label_schema=_schema(),
428
427
  samples=(),
429
428
  sample_data=[],
@@ -34,7 +34,7 @@ def _identity(**overrides):
34
34
  "vector_map_revision": None,
35
35
  "label_schema": schema_identity(),
36
36
  "business_metadata_revision": "business-metadata",
37
- "clip_schema_version": "0.17",
37
+ "clip_schema_version": "0.18",
38
38
  "ready": True,
39
39
  "blockers": [],
40
40
  }
@@ -233,5 +233,5 @@ def test_normalize_clip_identity_rejects_removed_source_granularity(field):
233
233
 
234
234
 
235
235
  def test_normalize_clip_identity_rejects_non_current_clip_schema_version():
236
- with pytest.raises(ValueError, match="clip_schema_version must be '0.17'"):
236
+ with pytest.raises(ValueError, match="clip_schema_version must be '0.18'"):
237
237
  normalize_clip_identity(_identity(clip_schema_version="0.10"))
@@ -49,7 +49,7 @@ def _identity(clip_id: str = "clip-a", **overrides):
49
49
  "vector_map_revision": None,
50
50
  "label_schema": schema_identity(),
51
51
  "business_metadata_revision": "sha256:business-metadata",
52
- "clip_schema_version": "0.17",
52
+ "clip_schema_version": "0.18",
53
53
  "ready": True,
54
54
  "blockers": [],
55
55
  }
@@ -20,7 +20,7 @@ def _manifest(*, include_sweeps: bool = True) -> dict:
20
20
  return {
21
21
  "export_id": "exp_20260711_a3f8c1d2",
22
22
  "exported_at": {"sec": 1_783_735_200, "nanosec": 123_456_000},
23
- "schema_version": "0.17",
23
+ "schema_version": "0.18",
24
24
  "options": {
25
25
  "include_sweeps": include_sweeps,
26
26
  "pointcloud_format": "pcd_binary",
@@ -31,7 +31,7 @@ def _manifest(*, include_sweeps: bool = True) -> dict:
31
31
  "clips": [
32
32
  {
33
33
  "clip_id": "20260711_G150-002_003",
34
- "schema_version": "0.17",
34
+ "schema_version": "0.18",
35
35
  "label_schema": schema_identity(),
36
36
  "annotation_frame_id": "base_link",
37
37
  "channels": ["cam_front", "lidar"],
@@ -30,7 +30,7 @@ def _inference_clip(tmp_path) -> tuple[ClipLoader, InferenceClip]:
30
30
  sweeps_revision=_digest("b"),
31
31
  calibration_revision="calibration-1",
32
32
  pose_revision="pose-1",
33
- clip_schema_version="0.17",
33
+ clip_schema_version="0.18",
34
34
  )
35
35
  access = PreannotationClipAccess(
36
36
  project_id=7,
@@ -174,7 +174,7 @@ def test_inference_clip_rejects_a_mismatched_source_identity(tmp_path):
174
174
  sweeps_revision=clip.source_identity.sweeps_revision,
175
175
  calibration_revision=clip.source_identity.calibration_revision,
176
176
  pose_revision=clip.source_identity.pose_revision,
177
- clip_schema_version="0.17",
177
+ clip_schema_version="0.18",
178
178
  )
179
179
 
180
180
  with pytest.raises(ValueError, match="source identity"):
@@ -37,7 +37,7 @@ def _request_payload() -> dict:
37
37
  "sweeps_revision": _digest("f"),
38
38
  "calibration_revision": "calibration-1",
39
39
  "pose_revision": "pose-1",
40
- "clip_schema_version": "0.17",
40
+ "clip_schema_version": "0.18",
41
41
  },
42
42
  "label_schema": schema_identity(),
43
43
  "base_annotation_revision": _digest("a"),
@@ -108,7 +108,7 @@ def test_source_identity_projects_only_pure_inference_dependencies():
108
108
  "semantic_scene_revision": _digest("d"),
109
109
  "vector_map_revision": None,
110
110
  "label_schema": schema_identity(),
111
- "clip_schema_version": "0.17",
111
+ "clip_schema_version": "0.18",
112
112
  "ready": True,
113
113
  "blockers": [],
114
114
  }
@@ -120,7 +120,7 @@ def test_source_identity_projects_only_pure_inference_dependencies():
120
120
  "sweeps_revision": _digest("f"),
121
121
  "calibration_revision": "calibration-1",
122
122
  "pose_revision": "pose-1",
123
- "clip_schema_version": "0.17",
123
+ "clip_schema_version": "0.18",
124
124
  }
125
125
 
126
126
 
@@ -83,7 +83,7 @@ def _fixture(tmp_path, pipeline=None, *, run_inline=True):
83
83
  sweeps_revision=_digest("e"),
84
84
  calibration_revision="calibration-1",
85
85
  pose_revision="pose-1",
86
- clip_schema_version="0.17",
86
+ clip_schema_version="0.18",
87
87
  )
88
88
  selected = pipeline or FakePipeline()
89
89
 
@@ -285,7 +285,7 @@ def test_batch_resolution_deduplicates_by_task_free_binding():
285
285
  "vector_map_revision": None,
286
286
  "business_metadata_revision": "business-a",
287
287
  "label_schema": identity,
288
- "clip_schema_version": "0.17",
288
+ "clip_schema_version": "0.18",
289
289
  "ready": True,
290
290
  "blockers": [],
291
291
  },
@@ -302,7 +302,7 @@ def test_batch_resolution_deduplicates_by_task_free_binding():
302
302
  "vector_map_revision": None,
303
303
  "business_metadata_revision": "business-b",
304
304
  "label_schema": identity,
305
- "clip_schema_version": "0.17",
305
+ "clip_schema_version": "0.18",
306
306
  "ready": True,
307
307
  "blockers": [],
308
308
  },
@@ -28,7 +28,7 @@ def loader(tmp_path):
28
28
 
29
29
  def test_loader_builds_current_typed_models_and_indexes(loader):
30
30
  assert isinstance(loader.meta, ClipMeta)
31
- assert loader.schema_version == "0.17"
31
+ assert loader.schema_version == "0.18"
32
32
  assert loader.annotation_revision.startswith("sha256:")
33
33
  assert all(isinstance(item, Sample) for item in loader.samples)
34
34
  assert all(isinstance(item, Annotation) for item in loader.annotations)
@@ -82,9 +82,8 @@ def test_clip_meta_serializes_exact_current_metadata():
82
82
  sensors = {"cam_front": SensorInfo("camera", "cam_front")}
83
83
  meta = ClipMeta(
84
84
  clip_id="clip-a",
85
- schema_version="0.17",
85
+ schema_version="0.18",
86
86
  session_id="session-a",
87
- vehicle_id="vehicle-a",
88
87
  capture_time=TimeNs(1, 2),
89
88
  duration_s=1.0,
90
89
  num_keyframes=1,
@@ -96,7 +95,7 @@ def test_clip_meta_serializes_exact_current_metadata():
96
95
  scene_tags=["urban"],
97
96
  )
98
97
  wire = meta.to_dict()
99
- assert wire["schema_version"] == "0.17"
98
+ assert wire["schema_version"] == "0.18"
100
99
  assert wire["capture_time"] == {"sec": 1, "nanosec": 2}
101
100
  assert wire["scene_tags"] == ["urban"]
102
101
  assert "route_tag" not in wire
@@ -117,7 +117,7 @@ def _portable_candidate() -> dict:
117
117
  "sweeps_revision": _digest("f"),
118
118
  "calibration_revision": "calibration-1",
119
119
  "pose_revision": "pose-1",
120
- "clip_schema_version": "0.17",
120
+ "clip_schema_version": "0.18",
121
121
  },
122
122
  "label_schema": schema_identity(),
123
123
  "base_annotation_revision": _digest("0"),
@@ -11,14 +11,14 @@ 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.44.0rc1"
14
+ assert x4d_devkit.__version__ == "0.45.0"
15
15
 
16
16
 
17
17
  def test_loader_exposes_and_enforces_only_current_schema(tmp_path):
18
18
  loader = ClipLoader(write_current_clip(tmp_path / "current"))
19
- assert loader.schema_version == "0.17"
20
- loader.require_schema_version("0.17")
21
- loader.require_schema_version({"0.17"})
19
+ assert loader.schema_version == "0.18"
20
+ loader.require_schema_version("0.18")
21
+ loader.require_schema_version({"0.18"})
22
22
  with pytest.raises(SchemaVersionMismatch):
23
23
  loader.require_schema_version("0.10")
24
24
  with pytest.raises(SchemaVersionMismatch):
@@ -0,0 +1,54 @@
1
+ """Vehicle-free metadata and the independent business-metadata boundary."""
2
+
3
+ import copy
4
+
5
+ import pytest
6
+
7
+ from tests.current_clip_fixtures import current_clip_tables, write_current_clip
8
+ from x4d_devkit.core.loader import ClipLoader
9
+ from x4d_devkit.dataset_contract import (
10
+ DatasetContractError,
11
+ parse_clip_meta,
12
+ project_business_metadata,
13
+ project_source_metadata,
14
+ )
15
+
16
+
17
+ def test_vehicle_free_clip_loads_and_roundtrips(tmp_path):
18
+ tables = current_clip_tables()
19
+ clip_dir = write_current_clip(tmp_path / "test-clip")
20
+ clip = ClipLoader(clip_dir)
21
+ assert clip.meta.source_attributes is None
22
+ assert clip.meta.to_dict() == tables["meta.json"]
23
+
24
+
25
+ def test_source_attributes_change_only_business_metadata():
26
+ meta = current_clip_tables()["meta.json"]
27
+ candidate = copy.deepcopy(meta)
28
+ candidate["source_attributes"] = {"vehicle_id": "V01", "vehicle_model": "车型 A"}
29
+ parsed = parse_clip_meta(candidate, include_label_schema=True)
30
+ assert parsed == candidate
31
+ assert project_source_metadata(meta) == project_source_metadata(candidate)
32
+ assert project_business_metadata(meta) == {}
33
+ assert project_business_metadata(candidate) == {
34
+ "source_attributes": candidate["source_attributes"]
35
+ }
36
+
37
+
38
+ @pytest.mark.parametrize("attributes", [{}, [], {"a": None}, {"a": 1}, {"a": " x"}, {"a": ""}, {"Bad key": "x"}])
39
+ def test_source_attributes_reject_inexact_values(attributes):
40
+ meta = current_clip_tables()["meta.json"]
41
+ meta["source_attributes"] = attributes
42
+ with pytest.raises(DatasetContractError):
43
+ parse_clip_meta(meta, include_label_schema=True)
44
+
45
+
46
+ def test_previous_vehicle_field_and_dataset_version_are_rejected():
47
+ meta = current_clip_tables()["meta.json"]
48
+ meta["vehicle_id"] = "V01"
49
+ with pytest.raises(DatasetContractError):
50
+ parse_clip_meta(meta, include_label_schema=True)
51
+ del meta["vehicle_id"]
52
+ meta["schema_version"] = "0.17"
53
+ with pytest.raises(DatasetContractError):
54
+ parse_clip_meta(meta, include_label_schema=True)
@@ -38,7 +38,7 @@ def _clip(**overrides):
38
38
  "annotation_revision": "ann",
39
39
  "semantic_scene_revision": None,
40
40
  "label_schema": schema_identity(),
41
- "clip_schema_version": "0.17",
41
+ "clip_schema_version": "0.18",
42
42
  "materialization_policy": "keyframes_only",
43
43
  }
44
44
  data.update(overrides)
@@ -133,7 +133,7 @@ def test_training_identity_file_rejects_duplicate_json_fields(tmp_path):
133
133
 
134
134
 
135
135
  def test_training_identity_rejects_non_current_clip_schema_version():
136
- with pytest.raises(ValueError, match="clip_schema_version must be '0.17'"):
136
+ with pytest.raises(ValueError, match="clip_schema_version must be '0.18'"):
137
137
  build_training_identity_manifest(
138
138
  projects=_projects(),
139
139
  clips=[_clip(clip_schema_version="0.10")]
@@ -251,7 +251,7 @@ def test_project_training_identities_are_dataset_diff_ready(tmp_path):
251
251
  "annotation_revision": "ann",
252
252
  "semantic_scene_revision": None,
253
253
  "label_schema": schema_identity(),
254
- "clip_schema_version": "0.17",
254
+ "clip_schema_version": "0.18",
255
255
  }]
256
256
 
257
257
 
@@ -51,9 +51,8 @@ def _manifest() -> dict:
51
51
  "label_schema": clip_schema_snapshot(),
52
52
  "meta": {
53
53
  "clip_id": "clip-a",
54
- "schema_version": "0.17",
54
+ "schema_version": "0.18",
55
55
  "session_id": "session-a",
56
- "vehicle_id": "vehicle-a",
57
56
  "capture_time": {"sec": 0, "nanosec": 1000},
58
57
  "duration_s": 0.0,
59
58
  "keyframe_count": 1,
@@ -327,7 +326,7 @@ class _FakeX4DClient:
327
326
 
328
327
  def test_work_session_wire_has_one_meta_source_for_version_and_frames():
329
328
  manifest = parse_clip_work_session(_manifest())
330
- assert manifest.clip_schema_version == "0.17"
329
+ assert manifest.clip_schema_version == "0.18"
331
330
  assert manifest.annotation_frame_id == "base_link"
332
331
  assert manifest.ego_pose_frame_id == "base_link"
333
332
  assert manifest.instances == [
@@ -372,7 +371,7 @@ def test_loader_from_work_session_supports_current_transforms_and_assets():
372
371
  parse_clip_work_session(_manifest()),
373
372
  api_url="http://x4d.local",
374
373
  )
375
- assert loader.schema_version == "0.17"
374
+ assert loader.schema_version == "0.18"
376
375
  assert loader.annotation_frame_id == "base_link"
377
376
  assert loader.frame_id_for_channel("lidar") == "base_link"
378
377
  assert loader.point_format("lidar").bytes_per_point == 24
@@ -634,7 +633,7 @@ def test_adopt_work_session_cache_fails_closed_without_changing_markers(
634
633
  else:
635
634
  meta_path = tmp_path / "meta.json"
636
635
  meta = json.loads(meta_path.read_text())
637
- meta["vehicle_id"] = "different"
636
+ meta["source_attributes"] = {"vehicle_id": "different"}
638
637
  meta_path.write_text(json.dumps(meta))
639
638
 
640
639
  with pytest.raises(ValueError, match="cache adoption"):
@@ -1,4 +1,4 @@
1
- """Strict Dataset 0.17 annotation document and derived track views."""
1
+ """Strict Dataset 0.18 annotation document and derived track views."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -115,7 +115,7 @@ def build_clip_annotations(
115
115
  annotation_frame_id: str,
116
116
  annotations: list[Mapping[str, Any]],
117
117
  ) -> ClipAnnotationDocument:
118
- """Build the only canonical Dataset 0.17 annotation document."""
118
+ """Build the only canonical Dataset 0.18 annotation document."""
119
119
 
120
120
  canonical = _canonical_annotation_rows(annotations)
121
121
  parsed_clip_id = _portable_token(clip_id, path="annotation.clip_id")
@@ -242,7 +242,7 @@ def cmd_screening_plan(args):
242
242
  for clip in result["valid_clips"]:
243
243
  print(
244
244
  f" bags={clip['bag_ids']} duration={clip['duration_s']:.1f}s "
245
- f"vehicle={clip['vehicle_id']}"
245
+ f"session={clip['session_id']}"
246
246
  )
247
247
  for flagged in result["flagged"]:
248
248
  print(f" flagged bag={flagged['bag_id']} reason={flagged['reason']}")
@@ -342,7 +342,6 @@ class ClipLoader:
342
342
  clip_id=d["clip_id"],
343
343
  schema_version=d["schema_version"],
344
344
  session_id=d["session_id"],
345
- vehicle_id=d["vehicle_id"],
346
345
  capture_time=TimeNs.from_dict(d["capture_time"]),
347
346
  duration_s=d["duration_s"],
348
347
  num_keyframes=d["keyframe_count"],
@@ -351,6 +350,7 @@ class ClipLoader:
351
350
  annotation_frame_id=d["annotation_frame_id"],
352
351
  ego_pose_frame_id=d["ego_pose_frame_id"],
353
352
  label_schema=dict(d["label_schema"]),
353
+ source_attributes=d.get("source_attributes"),
354
354
  route_tag=d.get("route_tag"),
355
355
  weather=d.get("weather"),
356
356
  time_of_day=d.get("time_of_day"),
@@ -493,7 +493,7 @@ class ClipLoader:
493
493
 
494
494
  @property
495
495
  def has_semantic_scene(self) -> bool:
496
- """Whether this local Dataset 0.17 Clip contains a semantic scene."""
496
+ """Whether this local Dataset 0.18 Clip contains a semantic scene."""
497
497
 
498
498
  return (self._clip_dir / "semantic_scene" / "manifest.json").is_file()
499
499
 
@@ -550,7 +550,7 @@ class ClipLoader:
550
550
  Example::
551
551
 
552
552
  loader = ClipLoader(path)
553
- loader.require_schema_version("0.17") # raises if not 0.17
553
+ loader.require_schema_version("0.18") # raises if not 0.18
554
554
  """
555
555
  actual = self._meta.schema_version
556
556
  if isinstance(expected, str):
@@ -798,14 +798,14 @@ class ClipLoader:
798
798
  ) -> np.ndarray:
799
799
  """Reject the removed homogeneous point-cloud representation.
800
800
 
801
- Dataset 0.17 mixes ``float32`` spatial fields with an absolute
801
+ Dataset 0.18 mixes ``float32`` spatial fields with an absolute
802
802
  ``uint64 timestamp_ns``. A homogeneous NumPy matrix cannot preserve
803
803
  both contracts. Use :meth:`load_point_records` for native data or the
804
804
  explicit model materialization API for derived ``float32 xyzit``.
805
805
  """
806
806
 
807
807
  raise ValueError(
808
- "load_point_cloud() is unavailable for Dataset 0.17 because a "
808
+ "load_point_cloud() is unavailable for Dataset 0.18 because a "
809
809
  "homogeneous array loses uint64 timestamp_ns precision; use "
810
810
  "load_point_records() or transform_concat_v1()"
811
811
  )
@@ -120,7 +120,7 @@ class PointFormat:
120
120
 
121
121
  @dataclass(frozen=True)
122
122
  class PointTime:
123
- """Exact Dataset 0.17 per-point time semantics."""
123
+ """Exact Dataset 0.18 per-point time semantics."""
124
124
 
125
125
  field: str
126
126
  representation: str
@@ -136,7 +136,7 @@ class PointTime:
136
136
  "epoch": "unix",
137
137
  "timescale": "posix",
138
138
  }:
139
- raise ValueError("PointTime must match the Dataset 0.17 contract")
139
+ raise ValueError("PointTime must match the Dataset 0.18 contract")
140
140
 
141
141
  @classmethod
142
142
  def from_dict(cls, value: dict[str, Any]) -> PointTime:
@@ -195,7 +195,7 @@ class SensorInfo:
195
195
  or self.point_format.bytes_per_point != CANONICAL_POINT_BYTES
196
196
  ):
197
197
  raise ValueError(
198
- "point-cloud SensorInfo requires canonical Dataset 0.17 layout"
198
+ "point-cloud SensorInfo requires canonical Dataset 0.18 layout"
199
199
  )
200
200
  if not isinstance(self.point_time, PointTime):
201
201
  raise TypeError("point-cloud SensorInfo requires PointTime")
@@ -241,7 +241,7 @@ class ClipMeta:
241
241
  clip_id: Unique clip identifier (e.g. "20180724_n015_scene-0061_000").
242
242
  schema_version: X4D format version (e.g. "0.5").
243
243
  session_id: Recording session identifier.
244
- vehicle_id: Vehicle identifier.
244
+ source_attributes: Optional descriptive provenance, independent of identity.
245
245
  capture_time: Exact capture timestamp.
246
246
  duration_s: Clip duration in seconds.
247
247
  num_keyframes: Number of keyframes (annotated frames).
@@ -260,7 +260,6 @@ class ClipMeta:
260
260
  clip_id: str
261
261
  schema_version: str
262
262
  session_id: str
263
- vehicle_id: str
264
263
  capture_time: TimeNs
265
264
  duration_s: float
266
265
  num_keyframes: int
@@ -269,6 +268,7 @@ class ClipMeta:
269
268
  annotation_frame_id: str
270
269
  ego_pose_frame_id: str
271
270
  label_schema: dict[str, Any]
271
+ source_attributes: dict[str, str] | None = None
272
272
  route_tag: str | None = None
273
273
  weather: str | None = None
274
274
  time_of_day: str | None = None
@@ -281,7 +281,6 @@ class ClipMeta:
281
281
  "clip_id": self.clip_id,
282
282
  "schema_version": self.schema_version,
283
283
  "session_id": self.session_id,
284
- "vehicle_id": self.vehicle_id,
285
284
  "capture_time": self.capture_time.to_dict(),
286
285
  "duration_s": self.duration_s,
287
286
  "keyframe_count": self.num_keyframes,
@@ -294,6 +293,7 @@ class ClipMeta:
294
293
  "label_schema": copy.deepcopy(self.label_schema),
295
294
  }
296
295
  for key in (
296
+ "source_attributes",
297
297
  "route_tag",
298
298
  "weather",
299
299
  "time_of_day",