@zhuoyuezs/ml-platform 0.2.8 → 0.2.10

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 (36) hide show
  1. package/CI-ARTIFACT.md +2 -2
  2. package/checksums.json +74 -54
  3. package/package.json +1 -1
  4. package/release.json +19 -19
  5. package/runtime/business-client/README.md +64 -4
  6. package/runtime/business-client/package-lock.json +2 -2
  7. package/runtime/business-client/package.json +1 -1
  8. package/runtime/business-client/src/catalog.js +25 -6
  9. package/runtime/business-client/src/cli.js +177 -7
  10. package/runtime/business-client/src/http.js +192 -32
  11. package/skills/data-source-exploration/SKILL.md +12 -1
  12. package/skills/data-source-exploration/agents/openai.yaml +2 -2
  13. package/skills/data-source-exploration/references/data-platform.md +83 -0
  14. package/skills/feature-management/SKILL.md +29 -11
  15. package/skills/feature-management/agents/openai.yaml +2 -2
  16. package/skills/feature-management/references/commands.md +64 -7
  17. package/skills/feature-management/references/contracts.md +124 -6
  18. package/skills/feature-management/references/data-platform-mapping.md +104 -0
  19. package/skills/feature-management/references/operator-authoring.md +116 -8
  20. package/skills/feature-management/references/platform-capability-guide.md +6 -0
  21. package/skills/feature-management/references/supervised-datasets.md +13 -0
  22. package/skills/model-deployment-management/SKILL.md +7 -0
  23. package/skills/model-deployment-management/references/contracts.md +6 -0
  24. package/skills/model-deployment-management/references/operations.md +28 -1
  25. package/skills/model-deployment-management/references/troubleshooting.md +8 -0
  26. package/skills/model-lifecycle-management/SKILL.md +27 -5
  27. package/skills/model-lifecycle-management/agents/openai.yaml +2 -2
  28. package/skills/model-lifecycle-management/references/ablation.md +111 -0
  29. package/skills/model-lifecycle-management/references/discovery.md +18 -3
  30. package/skills/model-lifecycle-management/references/evaluation.md +188 -1
  31. package/skills/model-lifecycle-management/references/experiment-runs.md +59 -0
  32. package/skills/model-lifecycle-management/references/model-comparison.md +11 -9
  33. package/skills/model-lifecycle-management/references/packaging.md +46 -0
  34. package/skills/model-lifecycle-management/references/training-contracts.md +172 -1
  35. package/skills/model-lifecycle-management/references/training.md +60 -0
  36. package/skills/prediction-report-management/SKILL.md +43 -8
package/CI-ARTIFACT.md CHANGED
@@ -17,5 +17,5 @@ npm install --global ./zhuoyuezs-ml-platform-*.tgz
17
17
  ml-platform version
18
18
  ```
19
19
 
20
- 运行已安装的 CLI 不需要 Python、`uv`、Git 仓库或平台源码。`uv` 只在 CI 构建阶段用于
21
- 执行现有的 release staging 脚本。
20
+ 运行已安装的 CLI 不需要 Python、`uv`、Git 仓库或平台源码。CI 构建阶段使用
21
+ `node:22-bookworm` 中的 Python 3.11 运行 release staging 脚本。
package/checksums.json CHANGED
@@ -2,23 +2,23 @@
2
2
  "files": [
3
3
  {
4
4
  "path": "runtime/business-client/README.md",
5
- "sha256": "sha256:ef7aabd0a1434dbf5d60018e357b018eeb08099de32a9b6a01a89d1f6764bc20",
6
- "size_bytes": 17026
5
+ "sha256": "sha256:9f81e4400f46c53952a0df6f7442d4c0b58cff4ca1be61f1daf785e111b3f8eb",
6
+ "size_bytes": 20557
7
7
  },
8
8
  {
9
9
  "path": "runtime/business-client/package-lock.json",
10
- "sha256": "sha256:706e7515b082fe20d4ad482347e222e41e34cd153c50bb947dc14f795cd5efb6",
10
+ "sha256": "sha256:9d19700ee4b348406bd0134f0539c37c2800e41a87dc130c1b0476eb2d23b931",
11
11
  "size_bytes": 1628
12
12
  },
13
13
  {
14
14
  "path": "runtime/business-client/package.json",
15
- "sha256": "sha256:6462d955b53f556056493bb6ee7acb506ced249e58d44532b9395cd8e1be684f",
15
+ "sha256": "sha256:d967d64289276cf1ce94f826a138f60fc93982b7478c1fb9f78f068f47f9d803",
16
16
  "size_bytes": 671
17
17
  },
18
18
  {
19
19
  "path": "runtime/business-client/src/catalog.js",
20
- "sha256": "sha256:369259ccfef1b079acf616eca1dc0040dda61cfb4b69941d0fcca30a658cd549",
21
- "size_bytes": 58749
20
+ "sha256": "sha256:94e4b43f248b752d9a9cec42e1f705849f01e4167bb570b9557b556c5be12c19",
21
+ "size_bytes": 59791
22
22
  },
23
23
  {
24
24
  "path": "runtime/business-client/src/cli-arguments.js",
@@ -27,8 +27,8 @@
27
27
  },
28
28
  {
29
29
  "path": "runtime/business-client/src/cli.js",
30
- "sha256": "sha256:cfabcb75a2e2b4e694c9c36390589299abcca3c0fd87e7171ea40b4a29d4e4eb",
31
- "size_bytes": 73361
30
+ "sha256": "sha256:143ce6e82d861fae647384e3617ec0f0222fef7c8e7b546ca67393fba8bd08b5",
31
+ "size_bytes": 85198
32
32
  },
33
33
  {
34
34
  "path": "runtime/business-client/src/config.js",
@@ -37,28 +37,33 @@
37
37
  },
38
38
  {
39
39
  "path": "runtime/business-client/src/http.js",
40
- "sha256": "sha256:088ef5fa067cc830a95db7d8ad3887ae58276179b524533f338daa781e243979",
41
- "size_bytes": 19452
40
+ "sha256": "sha256:91dc66d086deb5b5c0fd016560e6fddd369ccce9d430ce8f926bcae3f324cc86",
41
+ "size_bytes": 29035
42
42
  },
43
43
  {
44
44
  "path": "skills/data-source-exploration/SKILL.md",
45
- "sha256": "sha256:1f1f89d4ca41c3f7b206287e983027f50f65e462897584511259067fe94f2707",
46
- "size_bytes": 5631
45
+ "sha256": "sha256:63086689eac598ba9683d8dc63921b6ce13780973870e5ec346f69918892c5ed",
46
+ "size_bytes": 6260
47
47
  },
48
48
  {
49
49
  "path": "skills/data-source-exploration/agents/openai.yaml",
50
- "sha256": "sha256:5c7f7d497ad7738c672b8ee906d514284a2f2583a854f8fa487708a75836256f",
51
- "size_bytes": 299
50
+ "sha256": "sha256:15c93196536ff0eef2cf63940bee5eee852c9ccd55f394253fd98647f235b2eb",
51
+ "size_bytes": 348
52
+ },
53
+ {
54
+ "path": "skills/data-source-exploration/references/data-platform.md",
55
+ "sha256": "sha256:f65ff27fcd3f2e18baa34ae103984bc3a0adbf9fbbcf28d652ed41f89c11e44a",
56
+ "size_bytes": 5865
52
57
  },
53
58
  {
54
59
  "path": "skills/feature-management/SKILL.md",
55
- "sha256": "sha256:6b16afd7fde7949879a9277e29268c203fd42ac1bd630108d3c0101a56db1558",
56
- "size_bytes": 34392
60
+ "sha256": "sha256:f7777f43adf83cf4ee663c1e993f2f3d6221054f02e3cdcd24e65db36990141e",
61
+ "size_bytes": 36116
57
62
  },
58
63
  {
59
64
  "path": "skills/feature-management/agents/openai.yaml",
60
- "sha256": "sha256:a4c69cb062dc52749f0c0c96ad2d16f91f83ecedb44f78dcf662ef220273f24d",
61
- "size_bytes": 325
65
+ "sha256": "sha256:db2a9ebc7926370264e06b8e5767105415bb8a09a2dda08a7cf418a6e3b39bb0",
66
+ "size_bytes": 366
62
67
  },
63
68
  {
64
69
  "path": "skills/feature-management/assets/catalog-template/catalog.json",
@@ -107,33 +112,38 @@
107
112
  },
108
113
  {
109
114
  "path": "skills/feature-management/references/commands.md",
110
- "sha256": "sha256:bb6d8508bad62db6987df7d97802a679d5ccfc1fd7eb00f47b61b28396452be6",
111
- "size_bytes": 15872
115
+ "sha256": "sha256:248721ee995ebb20ea44a263f528e1af6004f7af55d31503185f6269744dee8d",
116
+ "size_bytes": 18829
112
117
  },
113
118
  {
114
119
  "path": "skills/feature-management/references/contracts.md",
115
- "sha256": "sha256:a9f6c8d6c8b1220a26a282f3ff73db54c6359372df02c322159087507ca0318d",
116
- "size_bytes": 30894
120
+ "sha256": "sha256:717b81364f8508cd73d52f18d7b5dd012a3f3638921a8a5a93c41991a4f27998",
121
+ "size_bytes": 38182
122
+ },
123
+ {
124
+ "path": "skills/feature-management/references/data-platform-mapping.md",
125
+ "sha256": "sha256:fef06e1e1918132336789aa6d430a501324fc3f3f2241817322740a8dd20054a",
126
+ "size_bytes": 7421
117
127
  },
118
128
  {
119
129
  "path": "skills/feature-management/references/operator-authoring.md",
120
- "sha256": "sha256:2ecfccbc9fe771bc1103db679d67af78847307eeb440f680f4055c35405ac923",
121
- "size_bytes": 6089
130
+ "sha256": "sha256:68ec5861800a6623db8e3cfae8e3363493c54772c4719d60dc66e4f4f0d3a347",
131
+ "size_bytes": 12570
122
132
  },
123
133
  {
124
134
  "path": "skills/feature-management/references/platform-capability-guide.md",
125
- "sha256": "sha256:6acb35f57e1bd6385702b6114e96c0ed1db34c9650d18658f74f212af9f91d14",
126
- "size_bytes": 4423
135
+ "sha256": "sha256:64874764924929421c294e7a421d546aba245d8f8bc40caba32d889f557c1906",
136
+ "size_bytes": 4850
127
137
  },
128
138
  {
129
139
  "path": "skills/feature-management/references/supervised-datasets.md",
130
- "sha256": "sha256:2c23ed96c49af1954864660bf8d13f3114bb03a6598e20df6abbc191c5986e2b",
131
- "size_bytes": 10024
140
+ "sha256": "sha256:a12ef5c26bc206507679e60fbecfa8bc1f5cfeb357e428b9dc8d1cdac6458a8a",
141
+ "size_bytes": 10886
132
142
  },
133
143
  {
134
144
  "path": "skills/model-deployment-management/SKILL.md",
135
- "sha256": "sha256:e4ec21765e23a02ad86bd6b0c92414eee182d74a9f7032e738711c823478ecfe",
136
- "size_bytes": 4960
145
+ "sha256": "sha256:5e1f92a03584df4631e896754b9b91012678b2358c1df7df55aa610fd527bf1d",
146
+ "size_bytes": 5505
137
147
  },
138
148
  {
139
149
  "path": "skills/model-deployment-management/agents/openai.yaml",
@@ -142,58 +152,68 @@
142
152
  },
143
153
  {
144
154
  "path": "skills/model-deployment-management/references/contracts.md",
145
- "sha256": "sha256:967d70e1d162ce0f8736683fd82009c7aa4227a309f38de14199469bb3bfe52c",
146
- "size_bytes": 6722
155
+ "sha256": "sha256:10a86a5f0ba36546c8487ea0bf78366f9034c9f713b80bb76a4fdb39aed67957",
156
+ "size_bytes": 7178
147
157
  },
148
158
  {
149
159
  "path": "skills/model-deployment-management/references/operations.md",
150
- "sha256": "sha256:2eb0fb62d971e21bfbdc1f398a5dcb91916dfccec35e7cbfa4a6404799bfdfb3",
151
- "size_bytes": 6165
160
+ "sha256": "sha256:ee98dbd02d84318108c157913e19353d1a6931cbe647af4125cffecbca155fea",
161
+ "size_bytes": 7854
152
162
  },
153
163
  {
154
164
  "path": "skills/model-deployment-management/references/troubleshooting.md",
155
- "sha256": "sha256:a1eb8f9419f9b05ccc92344f9050c4dfa91635284e3a19139afe2127706fa40f",
156
- "size_bytes": 3771
165
+ "sha256": "sha256:1d727c2e76fdbe361bdd5199bc63377feea9564b6b4d41842250bce1f23447f5",
166
+ "size_bytes": 4331
157
167
  },
158
168
  {
159
169
  "path": "skills/model-lifecycle-management/SKILL.md",
160
- "sha256": "sha256:5880a2f7dc5077767c05f3c2e34be30699d63ea620a08b7ed6944c6b5b29f801",
161
- "size_bytes": 6482
170
+ "sha256": "sha256:099973e2dd334beac12e275ee184d3ce500f6c307ae339e3400e585d8ad88a8e",
171
+ "size_bytes": 7833
162
172
  },
163
173
  {
164
174
  "path": "skills/model-lifecycle-management/agents/openai.yaml",
165
- "sha256": "sha256:37857849a8baa6b06b6d5d07ae6036080239356fcccd36f77bbdc52c1dfa283f",
166
- "size_bytes": 249
175
+ "sha256": "sha256:096bb0bca665622326b214a4d88d5b6807b50cf143b8a2e05528256fc3568f58",
176
+ "size_bytes": 258
177
+ },
178
+ {
179
+ "path": "skills/model-lifecycle-management/references/ablation.md",
180
+ "sha256": "sha256:41182c0c356626b04387c4b613cf293528187a98bc7d05b12f3d379ac51ad0ab",
181
+ "size_bytes": 5581
167
182
  },
168
183
  {
169
184
  "path": "skills/model-lifecycle-management/references/discovery.md",
170
- "sha256": "sha256:ad4623e84b8d972357497a55df0aed84be5ada59ef197f6a217f19ce97821195",
171
- "size_bytes": 5789
185
+ "sha256": "sha256:6ae9afc7169f4e51eefa8ac124b2fa5d9d26bed13ebbc57ec9fbbbcdc6b1960c",
186
+ "size_bytes": 6643
172
187
  },
173
188
  {
174
189
  "path": "skills/model-lifecycle-management/references/evaluation.md",
175
- "sha256": "sha256:e5c82007aa19632565ac3b9862b2c12e896c08f21171985795d342992324a683",
176
- "size_bytes": 10310
190
+ "sha256": "sha256:124c938f8ab633d6851357add501dd8e5defdfa2c81e8305b045f93656e6236e",
191
+ "size_bytes": 18889
192
+ },
193
+ {
194
+ "path": "skills/model-lifecycle-management/references/experiment-runs.md",
195
+ "sha256": "sha256:43360b72f2f9565640241450be01d95b44ebd5750d13c0ea9af47158bda35ccc",
196
+ "size_bytes": 2719
177
197
  },
178
198
  {
179
199
  "path": "skills/model-lifecycle-management/references/model-comparison.md",
180
- "sha256": "sha256:cb97b16476e28d3ca6f984ef2a964f936227bbb28a11570bbcd86f6ea51bccba",
181
- "size_bytes": 9359
200
+ "sha256": "sha256:13eeb1226effffc4eee1cacdb4ea04f4f61bc31874190046b6634e8e7bb49703",
201
+ "size_bytes": 9391
182
202
  },
183
203
  {
184
204
  "path": "skills/model-lifecycle-management/references/packaging.md",
185
- "sha256": "sha256:10a30f3408c1c387c215603db4d4aa436ce3bdb925e060139c3283653dd18505",
186
- "size_bytes": 7949
205
+ "sha256": "sha256:da2bde7db390643efbf7a3c8dbb668b0ffe69a1d62ec2dd6436cec5b05cc14ec",
206
+ "size_bytes": 9921
187
207
  },
188
208
  {
189
209
  "path": "skills/model-lifecycle-management/references/training-contracts.md",
190
- "sha256": "sha256:eb774709bc94e07a51a539e1a871202bd7569ae2c4a3d0fa4ebd2b1784ee08a6",
191
- "size_bytes": 17803
210
+ "sha256": "sha256:45568961f933b134e912a20b4ad37d435616d44c3159f302fbccaff2ffe16389",
211
+ "size_bytes": 27143
192
212
  },
193
213
  {
194
214
  "path": "skills/model-lifecycle-management/references/training.md",
195
- "sha256": "sha256:6732128fd6e0ef1fd1d40340bccd4ef555936c9050a7ccbf5ccbfc6c5854a8c3",
196
- "size_bytes": 8369
215
+ "sha256": "sha256:3ebf309ff7ede6b38dcb5b9afd75d282d29e91d768b9926808687c58434f88c9",
216
+ "size_bytes": 11419
197
217
  },
198
218
  {
199
219
  "path": "skills/model-lifecycle-management/references/zero-shot-inference.md",
@@ -202,8 +222,8 @@
202
222
  },
203
223
  {
204
224
  "path": "skills/prediction-report-management/SKILL.md",
205
- "sha256": "sha256:7c751b1c6176a807f287095ece6463747007f9277afa82abad0c6035f7cbdca5",
206
- "size_bytes": 6489
225
+ "sha256": "sha256:e7ad90295929b01dc6640a6a5fe42b0dcbfd56c52fb329a05875bf1a706e7874",
226
+ "size_bytes": 8894
207
227
  },
208
228
  {
209
229
  "path": "skills/prediction-report-management/agents/openai.yaml",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "ML 数据平台 business CLI 与 Agent Skills 管理工具",
5
5
  "bin": {
6
6
  "ml-platform": "scripts/main.js"
package/release.json CHANGED
@@ -13,8 +13,8 @@
13
13
  "entrypoint": "src/cli.js",
14
14
  "name": "ml-platform",
15
15
  "path": "runtime/business-client",
16
- "sha256": "sha256:eec6e0e65cf300d6fbfbddcc13bdee6af324409567222454c9ba7abc812a79f3",
17
- "version": "0.8.6"
16
+ "sha256": "sha256:5b83423598eb2c8afae8765e4315a9432cc026d1779348808c6516432820e67e",
17
+ "version": "0.8.7"
18
18
  },
19
19
  "policy_sha256": "sha256:02fbde0134696b78c0c365d6e0b76c9814227208da5b2b3d4e5dbd82dc4a3606",
20
20
  "public_schema_versions": [
@@ -25,7 +25,7 @@
25
25
  "ml_data_platform.feature_set/v1",
26
26
  "ml_data_platform.dataset_manifest/v1"
27
27
  ],
28
- "release_version": "0.2.8",
28
+ "release_version": "0.2.10",
29
29
  "runtime_requirements": {
30
30
  "node": ">=18",
31
31
  "os": [
@@ -37,34 +37,34 @@
37
37
  "skills": {
38
38
  "data-source-exploration": {
39
39
  "path": "skills/data-source-exploration",
40
- "requires_cli": ">=0.8.6 <0.9.0",
41
- "revision": "0.2.8",
42
- "sha256": "sha256:6cb1cad3e9531e5098582c532288edd9838c2acab2b324794ec99d2550418f32"
40
+ "requires_cli": ">=0.8.7 <0.9.0",
41
+ "revision": "0.2.10",
42
+ "sha256": "sha256:9614e6901fcfeac7e0779caee7a8ab1df40b39d08161967e51b459c266b82f90"
43
43
  },
44
44
  "feature-management": {
45
45
  "path": "skills/feature-management",
46
- "requires_cli": ">=0.8.6 <0.9.0",
47
- "revision": "0.2.8",
48
- "sha256": "sha256:91c59ad073fc6d13ae024ba3f2f5652742ebb7dbee8a0ad4573332e8f009a580"
46
+ "requires_cli": ">=0.8.7 <0.9.0",
47
+ "revision": "0.2.10",
48
+ "sha256": "sha256:c2f109d11ddfdfe9deaa2da077cd11f374bc8cef0db6155572fbb24defab39f7"
49
49
  },
50
50
  "model-deployment-management": {
51
51
  "path": "skills/model-deployment-management",
52
- "requires_cli": ">=0.8.6 <0.9.0",
53
- "revision": "0.2.8",
54
- "sha256": "sha256:a83471a2914210065b4354c50b9ddb8f6e4be582739636a116b9098524948a11"
52
+ "requires_cli": ">=0.8.7 <0.9.0",
53
+ "revision": "0.2.10",
54
+ "sha256": "sha256:ef13c737a098e9a582dfa6f7c54777c00a9efbc7af894c7aea35b9db4a97aa15"
55
55
  },
56
56
  "model-lifecycle-management": {
57
57
  "path": "skills/model-lifecycle-management",
58
- "requires_cli": ">=0.8.6 <0.9.0",
59
- "revision": "0.2.8",
60
- "sha256": "sha256:113c673d383cdfb191d3c0efbc91aa0f950e2db0ca03a163209680c6dc1683a0"
58
+ "requires_cli": ">=0.8.7 <0.9.0",
59
+ "revision": "0.2.10",
60
+ "sha256": "sha256:02fc9451ae888bec7ae1aa38bf51c3c8f657c6f899506ce323f17552b2dd31a0"
61
61
  },
62
62
  "prediction-report-management": {
63
63
  "path": "skills/prediction-report-management",
64
- "requires_cli": ">=0.8.6 <0.9.0",
65
- "revision": "0.2.8",
66
- "sha256": "sha256:671f65e54bf464c7fa46398d4fae31a6317290cf0987fc5c886e56a89309fafc"
64
+ "requires_cli": ">=0.8.7 <0.9.0",
65
+ "revision": "0.2.10",
66
+ "sha256": "sha256:399e5838604b5ce0248be702b70be2deaaf8f644e5518c91c45d21e0d2f43e53"
67
67
  }
68
68
  },
69
- "source_commit": "f05d2c98eddd9a4d2cdf47a1d7a3133fc421ffc9"
69
+ "source_commit": "b9b4ec03474a9ff7b11bae35eacf8302bcb97d0c"
70
70
  }
@@ -81,8 +81,10 @@ ml-platform get-deployment <deployment-id>
81
81
  ml-platform get-deployment-events <deployment-id> --limit 100 --offset 0
82
82
  ```
83
83
 
84
- `list-deployments` 也支持按 `service`、`environment`、`state` 和自由文本 `q` 过滤,返回平台
85
- Deployment Controller 管理的部署,不把模型中心回写的 delivery 状态当作平台部署。
84
+ `list-deployments` 支持 `--service` 对 service 名称做不区分大小写的子串匹配(忽略首尾空白),
85
+ 也支持按 `environment`、`state` 和跨字段自由文本 `q` 过滤,返回平台
86
+ Deployment Controller 管理的部署,不把模型中心回写的 delivery 状态当作平台部署。列表支持
87
+ `--sort-by created_at|updated_at` 和 `--sort-order asc|desc`,默认按 `deployment_id` 升序。
86
88
 
87
89
  部署业务分类由平台控制面管理。领域固定为 `power`(电力)、`blast_furnace`(高炉)和
88
90
  `other`(其他),场景可按领域自定义:
@@ -126,8 +128,11 @@ ml-platform list-deployments --business-domain-id power --scenario-id energy_sto
126
128
  "values": {
127
129
  "source": "predictions", "type": "array",
128
130
  "items": {"fields": {
131
+ "date": {"source": "target_time", "format": "%Y-%m-%d", "timezone": "Asia/Shanghai",
132
+ "midnight_as_24": true, "type": "string"},
129
133
  "time": {"source": "target_time", "format": "%H:%M", "timezone": "Asia/Shanghai",
130
134
  "midnight_as_24": true, "type": "string"},
135
+ "timestamp": {"source": "target_time", "type": "string"},
131
136
  "value": {"source": "value", "type": "number", "scale": 1.0, "offset": 0.0}
132
137
  }}
133
138
  }
@@ -159,8 +164,11 @@ ml-platform list-deployments --business-domain-id power --scenario-id energy_sto
159
164
  `target_time`。`source` 引用平台标准预测结果中的字段;`fields` 生成嵌套对象,`items` 将数组逐项转换,
160
165
  `constant` 写入固定值,`template` 可拼接已存在的字符串字段。`format` 可格式化时间;需要按业务时区格式化时,
161
166
  同时设置 `timezone`(IANA 名称),例如 `2026-09-10T16:00:00Z` 配置 `Asia/Shanghai` 后得到 `2026-09-11`;
162
- 如果目标接口把本地日界的午夜表达为 `24:00`,在包含 `%H` 的时间格式上设置 `midnight_as_24: true`,例如
163
- `%H:%M` 会将本地 `00:00` 映射为 `24:00`,其他时刻保持不变;
167
+ 如果目标接口把本地日界的午夜表达为前一日的 `24:00`,在业务日期和时间两个字段上均设置
168
+ `midnight_as_24: true` 和 `timezone: "Asia/Shanghai"`:`%Y-%m-%d` 输出前一日,`%H:%M` 输出 `24:00`。
169
+ 例如 `2026-10-31T00:00:00+08:00` 对应 `date=2026-10-30`、`time=24:00`,其他时刻保持不变。
170
+ `timestamp` 直接引用 `target_time`,MW 数值直接引用 `value`,不添加格式化或数值换算即可保持原值。
171
+ 表示起报本地日期的 `origin_date` 不设置 `midnight_as_24`;
164
172
  `scale` 和 `offset` 可执行受控数值换算,`type` 校验最终类型。`token_path`、业务成功码和
165
173
  `/forecast/report` 只是示例,必须按目标接口的真实响应和路径配置。
166
174
  映射字段缺失或类型不匹配时不会发送请求,Run 会记录 `payload_mapping_failed`。若响应提供有效期,可设置 `expires_in_path` 与 `expires_in_unit`;否则服务端默认按 7200 秒缓存,
@@ -304,10 +312,62 @@ Training Run and Job validation also return `effective_trainer_parameters`;
304
312
  for Job preflight it must match `job_spec.trainer_parameters` and represents
305
313
  the complete mapping delivered to the Worker after defaults are resolved.
306
314
 
315
+ ## Artifact file downloads
316
+
317
+ ```bash
318
+ ml-platform download-model-artifact <artifact_id> --out-dir /tmp/model [--file runtime.json] [--project <project>]
319
+ ml-platform download-evaluation-result-artifact <result_id> --out-dir /tmp/eval [--file predictions.parquet]
320
+ ml-platform download-dataset-artifact <dataset_id> <artifact_manifest_hash> --project <project> --out-dir /tmp/ds
321
+ ```
322
+
323
+ The lifecycle commands read the registry file index (`get-model-artifact` /
324
+ `get-evaluation-result-artifacts`), download every indexed file or each
325
+ repeated `--file`, and keep a file only when its sha256 equals the registry
326
+ record; a mismatch removes the output directory. Names outside the index fail
327
+ before any file request. They call the read-only
328
+ `GET /model-artifacts/{id}/files/{path}` and
329
+ `GET /evaluation-results/{id}/files/{path}` routes, which verify the sha256
330
+ server-side, accept an optional `project` scope, and refuse files above
331
+ `DATA_PLATFORM_LIFECYCLE_ARTIFACT_FILE_MAX_BYTES` (default 2 GiB).
332
+
333
+ A DatasetArtifact is keyed by the artifact manifest hash, not the registered
334
+ manifest hash. `build-dataset --wait`, `build-registered-dataset --wait` and
335
+ `wait-job` add an `artifact` object (`project`, `dataset_id`,
336
+ `dataset_version`, `manifest_hash`, `artifact_uri`, `row_count`) to a succeeded
337
+ build Job; use `artifact.manifest_hash` for downloads and dataset bindings. The
338
+ Job's top-level `manifest_hash` is unchanged.
339
+
340
+ `--idempotency-key` on `create-project`, `register-training-run`,
341
+ `submit-training-job`, `register-evaluation-config`, `submit-evaluation` and
342
+ `create-model-package` is sent as the `Idempotency-Key` header, which the
343
+ current server does not enforce. Inspect platform state before retrying an
344
+ uncertain submission.
345
+
307
346
  Maintainers can export the current API, including uncommitted schema changes,
308
347
  with `uv run python scripts/generate_openapi_schema.py --working-tree` from the
309
348
  repository root; use `--check` with it to verify the committed snapshot.
310
349
 
350
+ ## Connection handling
351
+
352
+ Every request is sent with `Connection: close`, so the CLI never writes a new
353
+ request onto a pooled keep-alive socket that the API (uvicorn closes idle
354
+ sockets after 5 s) or a slow VPN path has already dropped. Connection errors
355
+ report the underlying cause, for example
356
+ `fetch failed (UND_ERR_SOCKET: other side closed)` or
357
+ `request timed out after 30s (...)`.
358
+
359
+ Automatic retry (at most 3 retries, 0.5 s / 1 s / 2 s backoff, each attempt
360
+ with its own `--timeout`) happens only before response headers arrive:
361
+
362
+ - `GET`/`HEAD` (including `wait-job` polling and downloads): connection
363
+ errors such as `ECONNREFUSED`, `ECONNRESET`, `UND_ERR_SOCKET`,
364
+ `UND_ERR_CONNECT_TIMEOUT`, and the request timeout.
365
+ - `POST`/`PUT`/`PATCH`/`DELETE`: only `ECONNREFUSED` and
366
+ `UND_ERR_CONNECT_TIMEOUT`, where no TCP connection existed and the request
367
+ cannot have reached the server. Any other failure is reported once with
368
+ `not retried because the server may have received it`; inspect platform
369
+ state before resubmitting.
370
+
311
371
  ## Agent 宿主接入
312
372
 
313
373
  Coding agent 加载已安装的 Skills 后,通过原生 shell/exec 直接运行普通 `ml-platform` 命令。
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform-business-client",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@zhuoyuezs/ml-platform-business-client",
9
- "version": "0.8.6",
9
+ "version": "0.8.7",
10
10
  "license": "UNLICENSED",
11
11
  "bin": {
12
12
  "ml-platform": "src/cli.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform-business-client",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "private": true,
5
5
  "description": "JavaScript implementation of the ML Platform business client",
6
6
  "bin": {
@@ -454,11 +454,27 @@ function canonical(value) { if (Array.isArray(value))
454
454
  return value.map(canonical); if (value && typeof value === "object")
455
455
  return Object.fromEntries(Object.keys(value).sort().map((name) => [name, canonical(value[name])])); return value; }
456
456
  function equal(left, right) { return JSON.stringify(canonical(left)) === JSON.stringify(canonical(right)); }
457
- function assertImmutable(label, assetKey, candidate, existing) { if (existing && !equal(candidate, existing)) {
458
- const error = new Error(`${label} version is immutable: ${assetKey}`);
459
- error.code = "EEXIST";
460
- throw error;
461
- } }
457
+ function immutableError(label, assetKey) { const error = new Error(`${label} version is immutable: ${assetKey}`); error.code = "EEXIST"; return error; }
458
+ function assertImmutable(label, assetKey, candidate, existing) { if (existing && !equal(candidate, existing))
459
+ throw immutableError(label, assetKey); }
460
+ // A registered DatasetManifest carries server-filled defaults, including nested ones, that a catalog may
461
+ // omit. A raw mismatch is therefore settled by the server's normalized contract hash; servers without
462
+ // /datasets/validate keep the raw-comparison conflict.
463
+ async function assertDatasetImmutable(client, assetKey, candidate, existing) {
464
+ if (!existing || equal(candidate, existing))
465
+ return;
466
+ let result;
467
+ try {
468
+ result = await client.post("/datasets/validate", candidate);
469
+ }
470
+ catch (error) {
471
+ if (/HTTP 40[45]\b/.test(String(error.message)))
472
+ throw immutableError("datasets", assetKey);
473
+ throw error;
474
+ }
475
+ if (!result?.registered_manifest_hash || result.manifest_hash !== result.registered_manifest_hash)
476
+ throw immutableError("datasets", assetKey);
477
+ }
462
478
  function sha256File(file) { return `sha256:${crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex")}`; }
463
479
  async function applyCatalog(catalog, client, dryRun, targetProject) {
464
480
  validateCatalogProject(catalog, targetProject);
@@ -483,7 +499,10 @@ async function applyCatalog(catalog, client, dryRun, targetProject) {
483
499
  }
484
500
  const plain = async (assets, existing, label, endpoint, keyFn = key, params) => { for (const asset of assets) {
485
501
  const assetKey = keyFn(asset);
486
- assertImmutable(label, assetKey, asset, existing.get(assetKey));
502
+ if (label === "datasets")
503
+ await assertDatasetImmutable(client, assetKey, asset, existing.get(assetKey));
504
+ else
505
+ assertImmutable(label, assetKey, asset, existing.get(assetKey));
487
506
  if (existing.has(assetKey))
488
507
  summary[label].unchanged += 1;
489
508
  else if (dryRun)