x4d-devkit 0.16.0__tar.gz → 0.22.0rc1__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 (124) hide show
  1. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/PKG-INFO +89 -134
  2. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/README.md +78 -132
  3. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/pyproject.toml +17 -4
  4. x4d_devkit-0.22.0rc1/tests/test_assets_client.py +124 -0
  5. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_boundary.py +23 -0
  6. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_box.py +17 -10
  7. x4d_devkit-0.22.0rc1/tests/test_client_json_contract.py +42 -0
  8. x4d_devkit-0.22.0rc1/tests/test_contract_validation.py +413 -0
  9. x4d_devkit-0.22.0rc1/tests/test_coordinate_frames.py +82 -0
  10. x4d_devkit-0.22.0rc1/tests/test_current_state.py +202 -0
  11. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_current_state_identity_consumers_example.py +1 -1
  12. x4d_devkit-0.22.0rc1/tests/test_dataset_contract.py +66 -0
  13. x4d_devkit-0.22.0rc1/tests/test_dataset_identity.py +1026 -0
  14. x4d_devkit-0.22.0rc1/tests/test_detection_eval.py +23 -0
  15. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_evaluate.py +4 -5
  16. x4d_devkit-0.22.0rc1/tests/test_export_bundle.py +358 -0
  17. x4d_devkit-0.22.0rc1/tests/test_label_schemas.py +757 -0
  18. x4d_devkit-0.22.0rc1/tests/test_loader.py +125 -0
  19. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_matching.py +1 -1
  20. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_metrics.py +5 -5
  21. x4d_devkit-0.22.0rc1/tests/test_models.py +167 -0
  22. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_nuscenes_converter.py +267 -48
  23. x4d_devkit-0.22.0rc1/tests/test_platform_pose.py +136 -0
  24. x4d_devkit-0.22.0rc1/tests/test_release_gate.py +50 -0
  25. x4d_devkit-0.22.0rc1/tests/test_sdk_api.py +55 -0
  26. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_token.py +35 -3
  27. x4d_devkit-0.22.0rc1/tests/test_training_identity.py +384 -0
  28. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_transform.py +0 -1
  29. x4d_devkit-0.22.0rc1/tests/test_transform_chain.py +53 -0
  30. x4d_devkit-0.22.0rc1/tests/test_validation.py +225 -0
  31. x4d_devkit-0.22.0rc1/tests/test_work_session.py +462 -0
  32. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/__init__.py +30 -1
  33. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/cli.py +41 -340
  34. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/__init__.py +3 -0
  35. x4d_devkit-0.22.0rc1/x4d_devkit/client/_origin.py +41 -0
  36. x4d_devkit-0.22.0rc1/x4d_devkit/client/assets.py +97 -0
  37. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/client.py +15 -22
  38. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/clip_work_sessions.py +10 -10
  39. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/dataset_identity.py +12 -2
  40. x4d_devkit-0.22.0rc1/x4d_devkit/client/label_schemas.py +130 -0
  41. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/projects.py +0 -15
  42. x4d_devkit-0.22.0rc1/x4d_devkit/consumer_identity.py +219 -0
  43. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/converters/nuscenes.py +243 -155
  44. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/core/__init__.py +8 -2
  45. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/core/loader.py +159 -158
  46. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/core/models.py +173 -54
  47. x4d_devkit-0.22.0rc1/x4d_devkit/core/token.py +49 -0
  48. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/core/transform.py +36 -92
  49. x4d_devkit-0.22.0rc1/x4d_devkit/current_state.py +299 -0
  50. x4d_devkit-0.22.0rc1/x4d_devkit/dataset_contract.py +437 -0
  51. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/dataset_identity.py +402 -135
  52. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/api.py +2 -2
  53. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/box.py +27 -18
  54. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/detection.py +2 -7
  55. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/metrics.py +6 -4
  56. x4d_devkit-0.22.0rc1/x4d_devkit/export_bundle.py +502 -0
  57. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/service.py +2 -19
  58. x4d_devkit-0.22.0rc1/x4d_devkit/json_contract.py +58 -0
  59. x4d_devkit-0.22.0rc1/x4d_devkit/label_schema.py +2135 -0
  60. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/materialize.py +40 -34
  61. x4d_devkit-0.22.0rc1/x4d_devkit/training_identity.py +650 -0
  62. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/validation/__init__.py +8 -1
  63. x4d_devkit-0.22.0rc1/x4d_devkit/validation/contract.py +1544 -0
  64. x4d_devkit-0.22.0rc1/x4d_devkit/validation/platform_pose.py +136 -0
  65. x4d_devkit-0.22.0rc1/x4d_devkit/validation/validator.py +925 -0
  66. x4d_devkit-0.22.0rc1/x4d_devkit/work_session.py +569 -0
  67. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit.egg-info/PKG-INFO +89 -134
  68. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit.egg-info/SOURCES.txt +14 -5
  69. x4d_devkit-0.22.0rc1/x4d_devkit.egg-info/requires.txt +27 -0
  70. x4d_devkit-0.16.0/tests/test_contract_validation.py +0 -537
  71. x4d_devkit-0.16.0/tests/test_coordinate_frames.py +0 -501
  72. x4d_devkit-0.16.0/tests/test_current_state.py +0 -83
  73. x4d_devkit-0.16.0/tests/test_dataset_identity.py +0 -724
  74. x4d_devkit-0.16.0/tests/test_detection_eval.py +0 -195
  75. x4d_devkit-0.16.0/tests/test_label_schemas.py +0 -565
  76. x4d_devkit-0.16.0/tests/test_loader.py +0 -254
  77. x4d_devkit-0.16.0/tests/test_models.py +0 -232
  78. x4d_devkit-0.16.0/tests/test_training_identity.py +0 -194
  79. x4d_devkit-0.16.0/tests/test_training_manifest.py +0 -824
  80. x4d_devkit-0.16.0/tests/test_transform_chain.py +0 -88
  81. x4d_devkit-0.16.0/tests/test_v06_api_additions.py +0 -161
  82. x4d_devkit-0.16.0/tests/test_v06_schema.py +0 -414
  83. x4d_devkit-0.16.0/tests/test_v10_schema.py +0 -379
  84. x4d_devkit-0.16.0/tests/test_validation.py +0 -421
  85. x4d_devkit-0.16.0/tests/test_work_session.py +0 -601
  86. x4d_devkit-0.16.0/x4d_devkit/client/label_schemas.py +0 -65
  87. x4d_devkit-0.16.0/x4d_devkit/core/token.py +0 -26
  88. x4d_devkit-0.16.0/x4d_devkit/current_state.py +0 -203
  89. x4d_devkit-0.16.0/x4d_devkit/label_schema.py +0 -1451
  90. x4d_devkit-0.16.0/x4d_devkit/manifest.py +0 -932
  91. x4d_devkit-0.16.0/x4d_devkit/training_identity.py +0 -337
  92. x4d_devkit-0.16.0/x4d_devkit/validation/contract.py +0 -954
  93. x4d_devkit-0.16.0/x4d_devkit/validation/validator.py +0 -587
  94. x4d_devkit-0.16.0/x4d_devkit/work_session.py +0 -388
  95. x4d_devkit-0.16.0/x4d_devkit.egg-info/requires.txt +0 -14
  96. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/LICENSE +0 -0
  97. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/setup.cfg +0 -0
  98. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_build_info.py +0 -0
  99. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_cli_auth.py +0 -0
  100. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_client_projects.py +0 -0
  101. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_clip_archives.py +0 -0
  102. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_inference_builders.py +0 -0
  103. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_inference_schemas.py +0 -0
  104. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/tests/test_inference_service.py +0 -0
  105. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/build_info.py +0 -0
  106. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/bags.py +0 -0
  107. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/capabilities.py +0 -0
  108. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/checkpoints.py +0 -0
  109. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/clips.py +0 -0
  110. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/services.py +0 -0
  111. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/client/test_sets.py +0 -0
  112. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/converters/__init__.py +0 -0
  113. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/coordinate_contract.py +0 -0
  114. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/__init__.py +0 -0
  115. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/eval/matching.py +0 -0
  116. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/__init__.py +0 -0
  117. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/builders.py +0 -0
  118. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/models.py +0 -0
  119. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/schemas.py +0 -0
  120. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/inference/tasks.py +0 -0
  121. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit/validation/report.py +0 -0
  122. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit.egg-info/dependency_links.txt +0 -0
  123. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/x4d_devkit.egg-info/entry_points.txt +0 -0
  124. {x4d_devkit-0.16.0 → x4d_devkit-0.22.0rc1}/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.16.0
3
+ Version: 0.22.0rc1
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
@@ -21,8 +21,9 @@ Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: numpy>=1.24
23
23
  Requires-Dist: httpx>=0.27
24
+ Requires-Dist: rfc8785==0.1.4
24
25
  Provides-Extra: converters
25
- Requires-Dist: nuscenes-devkit>=1.1.0; extra == "converters"
26
+ Requires-Dist: nuscenes-devkit>=1.2.0; extra == "converters"
26
27
  Provides-Extra: inference
27
28
  Requires-Dist: pydantic>=2.0; extra == "inference"
28
29
  Requires-Dist: fastapi>=0.110; extra == "inference"
@@ -30,6 +31,14 @@ Requires-Dist: uvicorn>=0.27; extra == "inference"
30
31
  Provides-Extra: dev
31
32
  Requires-Dist: pytest>=7.0; extra == "dev"
32
33
  Requires-Dist: pytest-cov; extra == "dev"
34
+ Requires-Dist: ruff>=0.9; extra == "dev"
35
+ Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
38
+ Requires-Dist: mkdocstrings[python]>=0.27; extra == "docs"
39
+ Provides-Extra: release
40
+ Requires-Dist: build>=1.2; extra == "release"
41
+ Requires-Dist: twine>=6.0; extra == "release"
33
42
  Dynamic: license-file
34
43
 
35
44
  # x4d-devkit
@@ -51,19 +60,20 @@ modules or mutate DB/MinIO internals.
51
60
  Design decisions for this boundary are tracked in GitHub issues, starting with:
52
61
 
53
62
  - [#42](https://github.com/windzu/x4d-devkit/issues/42) - official external SDK and CLI boundary
54
- - [#43](https://github.com/windzu/x4d-devkit/issues/43) - private source install in X-4D runtime
63
+ - [#43](https://github.com/windzu/x4d-devkit/issues/43) - historical private-source runtime integration
55
64
  - [#44](https://github.com/windzu/x4d-devkit/issues/44) - capability registry and CLI sync
56
65
 
57
66
  ## Installation
58
67
 
59
68
  ```bash
60
- pip install x4d-devkit
69
+ pip install x4d-devkit==0.22.0rc1
61
70
  ```
62
71
 
63
- X-4D platform runtime installs this package from the checked-out private source
64
- repo/submodule, not from an unconstrained package-index version. External
65
- environments may install from a pinned package release or directly from GitHub,
66
- depending on deployment policy.
72
+ Devkit is released independently as an immutable wheel. X-4D, XPoints, and
73
+ other consumers must install one exact package version during image builds.
74
+ Runtime source copies, submodule installs, editable installs, VCS `main`
75
+ installs, and fallback dependency paths are not supported deployment modes.
76
+ Use a published prerelease for coordinated cross-repository development.
67
77
 
68
78
  Optional heavy dependencies:
69
79
 
@@ -76,6 +86,8 @@ pip install x4d-devkit[inference]
76
86
  ```
77
87
 
78
88
  The platform API client and `x4d-devkit` CLI are base package features.
89
+ See [the release process](docs/release-process.md) for the immutable artifact
90
+ and consumer cutover rules.
79
91
 
80
92
  ## Scope
81
93
 
@@ -87,24 +99,27 @@ platform-to-platform data flow. See
87
99
  [docs/current-state-identity.md](docs/current-state-identity.md) for the
88
100
  generic identity model, and
89
101
  [docs/training-current-state-data.md](docs/training-current-state-data.md) for
90
- diff/sync, work-session materialization, training manifests, and conditional
91
- annotation writeback flows built on that model.
102
+ work-session materialization and conditional annotation writeback. Label-schema
103
+ bodies are resolved from X-4D and passed explicitly at every clip loading and
104
+ validation boundary.
92
105
  Shared validation rules for platform submit, X-Points preflight, local clip
93
106
  validation, and training consumers are documented in
94
107
  [docs/shared-contract-validation.md](docs/shared-contract-validation.md).
108
+ Portable export producers and consumers share the exact `0.11` manifest
109
+ parser documented in
110
+ [docs/export-bundle-contract.md](docs/export-bundle-contract.md).
95
111
  `examples/current_state_identity_consumers.py` provides an offline downstream
96
- fixture for OpenPCDet-style, mmdetection3d-style, and annotation/review
97
- consumers.
112
+ fixture for read-only, read-write, and materialization consumers.
98
113
 
99
114
  Included:
100
115
 
101
116
  - Local X-4D dataset loading, validation, transforms, annotations, calibration,
102
- ego pose, manifests, converters, and evaluation helpers.
117
+ ego pose, converters, and evaluation helpers.
103
118
  - Platform API client and public `x4d-devkit` CLI commands for external
104
119
  workflows such as clip listing/download, screening preview, model/checkpoint
105
120
  registration, status queries, and capability discovery.
106
- - Training bridge workflows such as multi-project manifests, archive download,
107
- split validation, and dataloader-friendly metadata.
121
+ - Strict validation of `x4d-training-identity-v1` manifests.
122
+ - Strict producer-option and manifest parsing for export bundle `0.11`.
108
123
  - External inference service wrappers for third-party model-serving projects.
109
124
 
110
125
  Excluded:
@@ -165,93 +180,27 @@ complete clip payload including `sweeps/`. If the requested profile has not been
165
180
  built, is stale, or failed to build, the devkit reports that profile-specific
166
181
  reason instead of falling back to another tar.
167
182
 
168
- ### Create a multi-project training manifest
183
+ ### Validate a training identity manifest
169
184
 
170
- Training projects can combine multiple X-4D projects by downloading standard
171
- clip archives and generating one local manifest. The downstream training
172
- framework consumes only the manifest and local clip files; it does not need
173
- database, MinIO, or platform-private file paths.
185
+ The `manifest` command has one contract and one operation. It validates an
186
+ exact `x4d-training-identity-v1` record; it does not create datasets, download
187
+ clips, or translate earlier manifest shapes.
174
188
 
175
189
  ```bash
176
- x4d-devkit manifest create \
177
- --projects hg1.0 hg1.5 \
178
- --data-root /data/x4d/cache/hg_mix \
179
- --output /data/x4d/cache/hg_mix/manifest.json \
180
- --download-missing \
181
- --archive-profile keyframes_only \
182
- --split-policy by_clip \
183
- --val-ratio 0.2 \
184
- --seed 42
185
-
186
190
  x4d-devkit manifest validate \
187
- --manifest /data/x4d/cache/hg_mix/manifest.json \
188
- --data-root /data/x4d/cache/hg_mix
189
- ```
190
-
191
- Internal current-state consumers can snapshot remote clip identity before
192
- reviewing diffs or syncing local caches:
193
-
194
- ```bash
195
- x4d-devkit dataset inspect \
196
- --project-name hg1.5 \
197
- --include-asset-revision \
198
- --out remote_identity.json
199
- ```
200
-
201
- Training runs can validate their consumed-data identity record:
202
-
203
- ```bash
204
- x4d-devkit manifest identity-validate --manifest training_identity.json
205
- ```
206
-
207
- Dataset update planning can also compare consumer-owned training identity
208
- fields, such as split membership, class-mapping fingerprint, data policy, or a
209
- generic consumer identity fingerprint:
210
-
211
- ```bash
212
- x4d-devkit dataset diff \
213
- --local-manifest current_training_identity.json \
214
- --previous-training-identity previous_training_identity.json \
215
- --out update_plan.json
216
- ```
217
-
218
- `manifest validate` prints bounded warning output by default. It reports
219
- warning totals grouped by type, category, and project/category, then shows a
220
- small set of examples. Use `--max-warnings`, `--all-warnings`, or
221
- `--warnings-output warnings.jsonl` when full warning details are needed.
222
-
223
- Downloaded clips are stored under
224
- `projects/<project-name>/clips/<clip-id>/`. Manifest file paths are relative to
225
- `--data-root`, so the dataset can be moved as a directory.
226
-
227
- The platform is expected to assign globally unique `clip_id` values. The devkit
228
- validator checks duplicate clip identities and split leakage, but it does not
229
- perform expensive semantic near-duplicate detection across projects.
230
-
231
- ```python
232
- from x4d_devkit import X4DClient
233
-
234
- client = X4DClient.from_config()
235
- manifest = client.create_training_manifest(
236
- projects=["hg1.0", "hg1.5"],
237
- data_root="/data/x4d/cache/hg_mix",
238
- output="/data/x4d/cache/hg_mix/manifest.json",
239
- download_missing=True,
240
- split_policy="by_clip",
241
- val_ratio=0.2,
242
- seed=42,
243
- )
191
+ --manifest training_identity.json \
192
+ --format json
244
193
  ```
245
194
 
246
- The detection manifest keeps boxes in their native X-4D annotation frame
247
- (`meta.sensors[meta.annotation_source_channel].frame_id`). It does not align
248
- poses across clips; each clip's `clip_world` remains local to that clip.
195
+ Unsupported versions, removed aliases, and malformed clip/schema identities
196
+ fail validation. Producers own manifest construction and must emit the current
197
+ contract directly.
249
198
 
250
199
  ### Consume the project label schema
251
200
 
252
- X-4D is the source of truth for label schemas. External training and inference
253
- projects should read the effective project schema from the platform instead of
254
- maintaining their own category list.
201
+ X-4D is the only source of truth for label-schema bodies. Consumers resolve the
202
+ effective project record from the platform instead of maintaining their own
203
+ category list or copying the record into each clip.
255
204
 
256
205
  ```bash
257
206
  x4d-devkit label-schemas project-get --project-id 1 --format json
@@ -268,11 +217,13 @@ from x4d_devkit.label_schema import compare_project_label_schema_snapshot
268
217
  client = X4DClient.from_config()
269
218
  project = client.projects.resolve(project_name="nuscenes-mini")
270
219
  project_schema = client.label_schemas.resolve_project(project_name="nuscenes-mini")
220
+ project_schema_view = client.label_schemas.get_project_view(project["id"])
271
221
  label_schema = project_schema.label_schema
272
222
 
273
223
  print(project["id"], project["name"])
274
224
  print(project_schema.binding.to_dict())
275
225
  print(sorted(label_schema.class_ids))
226
+ print([category["id"] for category in project_schema_view.to_dict()["categories"]])
276
227
 
277
228
  label_schema.validate_category("tanker_truck")
278
229
 
@@ -282,40 +233,35 @@ comparison = compare_project_label_schema_snapshot(stored_snapshot, current)
282
233
  assert comparison.status == "same"
283
234
  ```
284
235
 
285
- The registry schema is the fine-grained annotation contract. Training code may
286
- still define experiment-specific class mappings, but those mappings should be
287
- validated against the project schema before a job starts.
236
+ The native `0.11` clip stores only the immutable identity in
237
+ `meta.label_schema`. It must not contain `label_schema.json`. The complete
238
+ registry record is explicit runtime context for `ClipLoader`, `validate_clip`,
239
+ conversion, and work-session parsing; its identity must exactly match
240
+ `meta.label_schema`.
288
241
 
289
- Training manifests keep the immutable project contract separate from the
290
- observed/configured class catalog:
242
+ Training code may still define experiment-specific class mappings, but those
243
+ mappings must be validated against the resolved project record before use.
291
244
 
292
- ```text
293
- label_schema.projects.<project>.contract # binding + full registry record
294
- label_schema.projects.<project>.class_catalog # training/observed class catalog
295
- ```
296
-
297
- The deprecated per-project `classes`, `source`, and `schema_version` aliases
298
- remain in manifest v0.1 for existing consumers. New consumers must parse
299
- `contract` with `parse_project_label_schema_snapshot()` and treat
300
- `class_catalog` as non-authoritative observation metadata.
245
+ ### Inspect or diff current state
301
246
 
302
- This strict parser/view contract is introduced in x4d-devkit `0.16.0`.
303
- Consumers tracking `main` should still record `get_build_info()["source"]` in
304
- training identity so an untagged development run remains reproducible by exact
305
- commit. Deployments that copy a source tree without its Git directory must set
306
- `X4D_DEVKIT_COMMIT` to the copied 40- or 64-hex commit; `get_build_info()` records
307
- that value with `commit_source=environment`.
247
+ Dataset identity clients, local manifests, portable cache identities, remote
248
+ identity manifests, and update plans use one schema field only:
249
+ `label_schema`, containing the complete
250
+ `x4d-label-schema-identity-v1` object. `label_schema_fingerprint` and
251
+ `clip_label_schema` are not aliases and are rejected. A ready platform record
252
+ without the complete identity is also rejected.
308
253
 
309
- Project resolution by name/key is exact and handles platform pagination
310
- internally; ambiguous or missing project references raise structured resolver
311
- errors instead of requiring callers to scan project lists themselves.
254
+ `x4d-devkit dataset inspect` writes `x4d-remote-identity-v2`, and
255
+ `x4d-devkit dataset diff` writes `x4d-update-plan-v2`. These artifacts contain
256
+ normalized clip records once; they do not embed a duplicate raw platform
257
+ response. V1 artifacts are rejected rather than migrated.
312
258
 
313
259
  ### Load a clip
314
260
 
315
261
  ```python
316
262
  from x4d_devkit import ClipLoader
317
263
 
318
- loader = ClipLoader("/path/to/clip")
264
+ loader = ClipLoader("/path/to/clip", label_schema=label_schema)
319
265
  print(loader.meta)
320
266
 
321
267
  for sample in loader.samples:
@@ -339,7 +285,7 @@ materialize_work_session_clip(
339
285
  manifest,
340
286
  output_dir="/data/x4d_cache/clips/clip-id",
341
287
  client=client,
342
- asset_policy="keyframes_only",
288
+ materialization_policy="keyframes_only",
343
289
  )
344
290
 
345
291
  loader = ClipLoader.from_work_session(manifest, api_url=client.api_url)
@@ -358,20 +304,21 @@ except WorkSessionConflictError as exc:
358
304
  raise
359
305
  ```
360
306
 
361
- Materialization preserves both schema facts atomically: the clip's recorded
362
- identity remains in `meta.label_schema`, while the effective full registry
363
- record is written to `label_schema.json`. Full and annotation-only refreshes
364
- write the same schema snapshot, so local validation does not require a live
365
- registry lookup.
307
+ The work-session envelope may carry the complete registry record so
308
+ `ClipLoader.from_work_session()` can validate without another request. That
309
+ record is transient request context, not a second persisted schema source.
310
+ Materialization writes the native tables with the identity in
311
+ `meta.label_schema` and never writes `label_schema.json`. Loading or validating
312
+ the materialized directory later therefore requires the caller to resolve and
313
+ pass the complete registry record explicitly.
366
314
 
367
- A ready work session is accepted only when `label_schema_fingerprint`, the full
368
- registry record, `clip_label_schema`, and `meta.label_schema` declare the same
369
- identity. A not-ready session may expose a stale clip identity alongside the
370
- current project schema so migration tooling can report the mismatch, but it
371
- cannot be materialized.
315
+ A ready work session is accepted only when its full registry record,
316
+ `clip_label_schema`, and the resulting native `meta.label_schema` declare the
317
+ same identity. A mismatch fails closed; there is no legacy work-session shape
318
+ or schema-file fallback.
372
319
 
373
320
  Submit is conditional on the manifest's `source_revision`,
374
- `annotation_revision`, and `label_schema_fingerprint`. If the platform state
321
+ `annotation_revision`, and `base_label_schema_fingerprint`. If the platform state
375
322
  changed after the session was opened, the client raises
376
323
  `WorkSessionConflictError` with machine-readable `conflicts`,
377
324
  `base_identities`, and `current_identities`.
@@ -404,7 +351,7 @@ from x4d_devkit import COORDINATE_CONTRACT_VERSION, get_training_coordinate_cont
404
351
  from x4d_devkit import ClipLoader
405
352
  from x4d_devkit.core.loader import CLIP_WORLD_FRAME_ID
406
353
 
407
- loader = ClipLoader("/path/to/clip")
354
+ loader = ClipLoader("/path/to/clip", label_schema=label_schema)
408
355
  sd = loader.sample_data_for_channel("LIDAR_TOP")[0]
409
356
 
410
357
  # Load point cloud in different frames
@@ -426,16 +373,20 @@ pts_world = T.apply(pts_sensor[:, :3]) # or use T.as_matrix for 4x4
426
373
  ### Validate a clip
427
374
 
428
375
  ```bash
429
- x4d-devkit validate /path/to/clip
376
+ x4d-devkit validate /path/to/clip --label-schema project_schema_record.json
430
377
  ```
431
378
 
432
379
  ```python
433
380
  from x4d_devkit import validate_clip
434
381
 
435
- report = validate_clip("/path/to/clip")
382
+ report = validate_clip("/path/to/clip", label_schema=label_schema)
436
383
  print(report)
437
384
  ```
438
385
 
386
+ For a remote clip, call `validate_clip_payload(..., asset_sizes=...)` with a
387
+ mapping of clip-relative object paths to byte sizes. This applies the same
388
+ asset existence and point-cloud layout checks without downloading the assets.
389
+
439
390
  ### Serve an external inference backend
440
391
 
441
392
  Third-party model projects should use `x4d-devkit[inference]` instead of
@@ -463,7 +414,11 @@ class MyDetector(DetectionModel):
463
414
  ]
464
415
 
465
416
 
466
- InferenceService(service_name="my-detector", models=[MyDetector()]).run(port=9000)
417
+ InferenceService(
418
+ service_name="my-detector",
419
+ models=[MyDetector()],
420
+ clip_resolver=resolve_clip,
421
+ ).run(port=9000)
467
422
  ```
468
423
 
469
424
  See [docs/external-inference.md](docs/external-inference.md) and
@@ -525,7 +480,7 @@ converter.convert_scene("scene-0001", output_dir="/path/to/output")
525
480
  | `core` | Data models, token generation, coordinate transforms, clip loader |
526
481
  | `eval` | Detection evaluation (mAP, TP metrics, NDS) |
527
482
  | `converters` | Format converters (NuScenes → X4D) |
528
- | `manifest` | Training manifest creation, validation, and clip archive download |
483
+ | `training_identity` | Strict `x4d-training-identity-v1` parsing and validation |
529
484
  | `validation` | Clip structure and data validation |
530
485
  | `client` | X-4D platform API client |
531
486