@zhuoyuezs/ml-platform 0.2.2 → 0.2.3-alpha.1

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.
package/DEVELOPMENT.md CHANGED
@@ -10,7 +10,7 @@
10
10
  - Skill 直接调用正式命令 `ml-platform`,不嵌入 CLI runtime。
11
11
  - 正式 npm 包只有 `@zhuoyuezs/ml-platform`,正式 bin 只有 `ml-platform`。
12
12
  - `business-client-js/src-ts/` 是 business CLI 的唯一 TypeScript 源码,`src/` 是供 Node.js 和
13
- release payload 使用的编译输出;仓库 `skills/` 下四个受支持 Skill 是各自唯一源码。
13
+ release payload 使用的编译输出;仓库 `skills/` 下五个受支持 Skill 是各自唯一源码。
14
14
  - `npx @zhuoyuezs/ml-platform@<version> install` 是面向用户的统一安装入口;默认目标是 Codex
15
15
  用户级 Skill,不要求额外安装参数。
16
16
  - 管理命令默认输出简洁结果;Agent 和 CI 显式使用 `--json` 获取稳定结构化输出。
@@ -34,6 +34,7 @@ skills/feature-management/
34
34
  skills/data-source-exploration/
35
35
  skills/model-lifecycle-management/
36
36
  skills/model-deployment-management/
37
+ skills/prediction-report-management/
37
38
  npm/ml-platform/
38
39
  npm/scripts/build_ml_platform_release.py
39
40
  agent_poc/codex-host/
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # ML Platform
2
2
 
3
3
  ML Platform 的 TypeScript CLI(编译为 Node.js JavaScript runtime)、`feature-management`、
4
- `data-source-exploration`、`model-lifecycle-management` 与 `model-deployment-management`
4
+ `data-source-exploration`、`model-lifecycle-management`、`model-deployment-management` 与
5
+ `prediction-report-management`
5
6
  Agent Skill。CLI 与 Skill 由同一个 npm
6
7
  release 安装和升级,运行时不需要 Python 或 `uv`。
7
8
 
@@ -19,7 +20,7 @@ release 安装和升级,运行时不需要 Python 或 `uv`。
19
20
  npx @zhuoyuezs/ml-platform@latest install
20
21
  ```
21
22
 
22
- 这条命令不需要额外参数。默认安装持久化的 `ml-platform` 命令,并将四个 Skill 安装到
23
+ 这条命令不需要额外参数。默认安装持久化的 `ml-platform` 命令,并将五个 Skill 安装到
23
24
  `~/.codex/skills/`,供当前用户的 Codex 使用。安装后重启终端和 Agent 会话。
24
25
 
25
26
  只在当前项目使用 Skill 时,在项目根目录运行:
@@ -131,8 +132,9 @@ npx --yes --registry=https://registry.npmjs.org/ \
131
132
  ## 包内容
132
133
 
133
134
  - 一份由 TypeScript 编译的 business CLI;
134
- - 四份纯 Skill:`feature-management`、`data-source-exploration`、
135
- `model-lifecycle-management` 与 `model-deployment-management`;
135
+ - 五份纯 Skill:`feature-management`、`data-source-exploration`、
136
+ `model-lifecycle-management`、`model-deployment-management` 与
137
+ `prediction-report-management`;
136
138
  - 显式安装、升级、状态、校验和回滚逻辑。
137
139
 
138
140
  不包含 Codex CLI、Python business-client wheel、Agent Host、平台服务端、模型训练或 Kubernetes
package/checksums.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "files": [
3
3
  {
4
4
  "path": "runtime/business-client/README.md",
5
- "sha256": "sha256:30d921fabf5bc0339eda60169a1865f6007807b1d9a8d3e646b42f68cd563240",
6
- "size_bytes": 8125
5
+ "sha256": "sha256:f03d10f0de78e4ff456a6718b5b74b7fd001598f5a5963985d97d0b99403c0a5",
6
+ "size_bytes": 12756
7
7
  },
8
8
  {
9
9
  "path": "runtime/business-client/package-lock.json",
@@ -17,13 +17,13 @@
17
17
  },
18
18
  {
19
19
  "path": "runtime/business-client/src/catalog.js",
20
- "sha256": "sha256:9ace0708c04aed8876e8d5b8eba9241f32e98757ca19d14fb00c30ba2de662cf",
21
- "size_bytes": 58679
20
+ "sha256": "sha256:369259ccfef1b079acf616eca1dc0040dda61cfb4b69941d0fcca30a658cd549",
21
+ "size_bytes": 58749
22
22
  },
23
23
  {
24
24
  "path": "runtime/business-client/src/cli.js",
25
- "sha256": "sha256:c1beda5fd4e2d6f23f81529017679d85c0703d6859cfa0155a8597e50b7b6cdf",
26
- "size_bytes": 60617
25
+ "sha256": "sha256:ecdc7d2e93323a4dd04514573219061f54db6583d955dfa82afc482abcd3335a",
26
+ "size_bytes": 66532
27
27
  },
28
28
  {
29
29
  "path": "runtime/business-client/src/config.js",
@@ -32,13 +32,13 @@
32
32
  },
33
33
  {
34
34
  "path": "runtime/business-client/src/http.js",
35
- "sha256": "sha256:4ae9e9ec10a74f36ed19ca7a63b0ba58a34cedea13ed95131ef1d07cd7d9e674",
36
- "size_bytes": 17176
35
+ "sha256": "sha256:517ad46944f3a4068a00a570dc09975c5b59de61b730e0acf8e009ee1f18c89d",
36
+ "size_bytes": 18865
37
37
  },
38
38
  {
39
39
  "path": "skills/data-source-exploration/SKILL.md",
40
- "sha256": "sha256:3b609d61f3c73da3657ce2e6bb4d1eff95a90e4ac5e5445b8513536438b26b0b",
41
- "size_bytes": 3853
40
+ "sha256": "sha256:11b20671ad81b42cd2ddb1cb146196b9f5ab15e962249e7e07cfa148c601e881",
41
+ "size_bytes": 4172
42
42
  },
43
43
  {
44
44
  "path": "skills/data-source-exploration/agents/openai.yaml",
@@ -47,8 +47,8 @@
47
47
  },
48
48
  {
49
49
  "path": "skills/feature-management/SKILL.md",
50
- "sha256": "sha256:88898ea83ff339512d5512537db485a2764420abb67afceb9dd090cc780c00e0",
51
- "size_bytes": 33021
50
+ "sha256": "sha256:1118aef3734fe14fd8f7d1074ff730340663e42565155bde984ab5b397c2da77",
51
+ "size_bytes": 33777
52
52
  },
53
53
  {
54
54
  "path": "skills/feature-management/agents/openai.yaml",
@@ -97,8 +97,8 @@
97
97
  },
98
98
  {
99
99
  "path": "skills/feature-management/assets/catalog-template/parameters/example_temperature.v1.json",
100
- "sha256": "sha256:28c7d3576c4b7e94c1e9db7f95f26d83ee2e10dc9f81ec6223f4fbd9b2f5eeda",
101
- "size_bytes": 1488
100
+ "sha256": "sha256:b7e25965b0dc2d65a935b67d5f10d1192ad550ba90bae25d550bfdb5736b0d2d",
101
+ "size_bytes": 1523
102
102
  },
103
103
  {
104
104
  "path": "skills/feature-management/references/commands.md",
@@ -107,8 +107,8 @@
107
107
  },
108
108
  {
109
109
  "path": "skills/feature-management/references/contracts.md",
110
- "sha256": "sha256:ef582d4ee9ade16de2a5f97b8bf9546969b6f2859eb020986bf25952993df402",
111
- "size_bytes": 30483
110
+ "sha256": "sha256:a9f6c8d6c8b1220a26a282f3ff73db54c6359372df02c322159087507ca0318d",
111
+ "size_bytes": 30894
112
112
  },
113
113
  {
114
114
  "path": "skills/feature-management/references/operator-authoring.md",
@@ -127,8 +127,8 @@
127
127
  },
128
128
  {
129
129
  "path": "skills/model-deployment-management/SKILL.md",
130
- "sha256": "sha256:d50f64fa709c8ff36da97c60ce0d20b1217d1d9f78f602048f49c0c4bbab7ea2",
131
- "size_bytes": 3927
130
+ "sha256": "sha256:e8419e4d83031248b40783674813bf3f5a98544f05ea3fbe056547ae47632016",
131
+ "size_bytes": 4397
132
132
  },
133
133
  {
134
134
  "path": "skills/model-deployment-management/agents/openai.yaml",
@@ -152,8 +152,8 @@
152
152
  },
153
153
  {
154
154
  "path": "skills/model-lifecycle-management/SKILL.md",
155
- "sha256": "sha256:4ea40815d73b3a470b2572874dcad63640cbdd53d3c10293d7a5ce8621a13b96",
156
- "size_bytes": 4272
155
+ "sha256": "sha256:9ad2428621b52a15a83dce34a2a95606d7d979017a227c0aeb8fe5c8acd5faa3",
156
+ "size_bytes": 5442
157
157
  },
158
158
  {
159
159
  "path": "skills/model-lifecycle-management/agents/openai.yaml",
@@ -162,8 +162,8 @@
162
162
  },
163
163
  {
164
164
  "path": "skills/model-lifecycle-management/references/discovery.md",
165
- "sha256": "sha256:184472a79fb217dd8c74dffab20e75285b0c8f69207dc593ae3099b8a2b6d6d5",
166
- "size_bytes": 5381
165
+ "sha256": "sha256:ad4623e84b8d972357497a55df0aed84be5ada59ef197f6a217f19ce97821195",
166
+ "size_bytes": 5789
167
167
  },
168
168
  {
169
169
  "path": "skills/model-lifecycle-management/references/evaluation.md",
@@ -177,13 +177,28 @@
177
177
  },
178
178
  {
179
179
  "path": "skills/model-lifecycle-management/references/training-contracts.md",
180
- "sha256": "sha256:4cecf5f90464640d063ca721fded1c27b46bb79daa0f67c78a8fb6b0e3e60b3b",
181
- "size_bytes": 14747
180
+ "sha256": "sha256:26ca0f0b8bc212bd30ea69b0a0afc169554681a16317ebb054d9147ae9c0587a",
181
+ "size_bytes": 14994
182
182
  },
183
183
  {
184
184
  "path": "skills/model-lifecycle-management/references/training.md",
185
- "sha256": "sha256:97de7894da24a07b4146d6de5e00a0cf17166654fb219a145f35adff5e8a7f99",
186
- "size_bytes": 7980
185
+ "sha256": "sha256:ae87837e5c315aa0fc9c02575213e1fd293f192ed43a1c68e9f8d08407becc48",
186
+ "size_bytes": 8235
187
+ },
188
+ {
189
+ "path": "skills/model-lifecycle-management/references/zero-shot-inference.md",
190
+ "sha256": "sha256:4ea224be54a7b0fc7754bdaa41df0f3b14c56f5134afc3951e91e59844108f90",
191
+ "size_bytes": 2350
192
+ },
193
+ {
194
+ "path": "skills/prediction-report-management/SKILL.md",
195
+ "sha256": "sha256:32abad9d9a152680d126cf1fa3df921a367a9ad9eb0aaaf3ce48b05538b4fbd5",
196
+ "size_bytes": 4365
197
+ },
198
+ {
199
+ "path": "skills/prediction-report-management/agents/openai.yaml",
200
+ "sha256": "sha256:fd86629700aa9a4f1ab985d87883162ab260f469d5059a516abcd1e3273d89fa",
201
+ "size_bytes": 241
187
202
  }
188
203
  ],
189
204
  "schema_version": "data_platform.ml_platform_checksums/v1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform",
3
- "version": "0.2.2",
3
+ "version": "0.2.3-alpha.1",
4
4
  "description": "ML 数据平台 business CLI 与 Agent Skills 管理工具",
5
5
  "bin": {
6
6
  "ml-platform": "scripts/main.js"
package/release.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "entrypoint": "src/cli.js",
14
14
  "name": "ml-platform",
15
15
  "path": "runtime/business-client",
16
- "sha256": "sha256:4e06df68d4f849eae92d1fcfb57f1a3b9e949f97ed8042ec549c8b460f3736c8",
16
+ "sha256": "sha256:eaa88929b414e386294287009b4ecb25e26d1eb39403469ef649af145b2208de",
17
17
  "version": "0.8.3"
18
18
  },
19
19
  "policy_sha256": "sha256:02fbde0134696b78c0c365d6e0b76c9814227208da5b2b3d4e5dbd82dc4a3606",
@@ -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.2",
28
+ "release_version": "0.2.3-alpha.1",
29
29
  "runtime_requirements": {
30
30
  "node": ">=18",
31
31
  "os": [
@@ -38,27 +38,33 @@
38
38
  "data-source-exploration": {
39
39
  "path": "skills/data-source-exploration",
40
40
  "requires_cli": ">=0.8.3 <0.9.0",
41
- "revision": "0.2.2",
42
- "sha256": "sha256:ae3cfc88f8f3f46a5b7e0179d850b2216bc37275f34679dbea1ff2ba99875a96"
41
+ "revision": "0.2.3-alpha.1",
42
+ "sha256": "sha256:2fa1e1802d799ee0c47b10263f2fde57b604e505fea5c98bfa23f51f382bbf69"
43
43
  },
44
44
  "feature-management": {
45
45
  "path": "skills/feature-management",
46
46
  "requires_cli": ">=0.8.3 <0.9.0",
47
- "revision": "0.2.2",
48
- "sha256": "sha256:d32f0306f129d7bf76eb037fe239c84dd3c29c64b61600799d6e40320784bb10"
47
+ "revision": "0.2.3-alpha.1",
48
+ "sha256": "sha256:6dfa708172c3b5b23af75997c82a6d43bc2eb8ca67cc2275c8b95022455b0c42"
49
49
  },
50
50
  "model-deployment-management": {
51
51
  "path": "skills/model-deployment-management",
52
52
  "requires_cli": ">=0.8.3 <0.9.0",
53
- "revision": "0.2.2",
54
- "sha256": "sha256:e7d87c272a0dcc028ea628d5e36f5b7e52ed27cb9c1bc17ea76527478e28b46d"
53
+ "revision": "0.2.3-alpha.1",
54
+ "sha256": "sha256:d3f3fe0e4a11b93d8f6f57758164aa236b84a49c1b9f0d0b700fd9d6d615a8d7"
55
55
  },
56
56
  "model-lifecycle-management": {
57
57
  "path": "skills/model-lifecycle-management",
58
58
  "requires_cli": ">=0.8.3 <0.9.0",
59
- "revision": "0.2.2",
60
- "sha256": "sha256:ec6ebb2587fd7acd024def75a8c0e9cd94b6cdd8ee6df439609291b496751b91"
59
+ "revision": "0.2.3-alpha.1",
60
+ "sha256": "sha256:8822fbec7037c2312d18b1d18648b60757fc569e6bf5f2856ea41592f3ba987d"
61
+ },
62
+ "prediction-report-management": {
63
+ "path": "skills/prediction-report-management",
64
+ "requires_cli": ">=0.8.3 <0.9.0",
65
+ "revision": "0.2.3-alpha.1",
66
+ "sha256": "sha256:a0210cd93244bce41e5b71f8dc70c6c4a79973968cd22af7e0e0102eae3efaa3"
61
67
  }
62
68
  },
63
- "source_commit": "03bf8af26abcf13a95dc41d2637598a8f0233552"
69
+ "source_commit": "07c13464f3ed2c10644ba6707d329b54f48e725d"
64
70
  }
@@ -73,6 +73,91 @@ ml-platform get-deployment-events <deployment-id> --limit 100 --offset 0
73
73
  `list-deployments` 也支持按 `service`、`environment`、`state` 和自由文本 `q` 过滤,返回平台
74
74
  Deployment Controller 管理的部署,不把模型中心回写的 delivery 状态当作平台部署。
75
75
 
76
+ ## Prediction reporting
77
+
78
+ 定时预测上报通过业务 CLI 管理版本化推送目标、计划与运行记录。下面的 JSON 是字段示例,
79
+ 不是现网配置;替换目标地址、响应字段和占位凭据后,把实际配置文件放在仓库外并限制读取权限。
80
+ 不要把认证信息写入 Kubernetes Secret、命令行参数或 Git。`validate-destination-profile`
81
+ 仅做服务端合同校验,不会访问 Token 或推送接口。
82
+
83
+ `PROFILE_JSON` 示例:
84
+
85
+ ```json
86
+ {
87
+ "schema_version": "ml_data_platform.destination_profile/v1",
88
+ "name": "forecast_sink",
89
+ "version": "v1",
90
+ "environment": "test",
91
+ "base_url": "https://integration.example.invalid/api",
92
+ "path": "/forecast/report",
93
+ "payload_mapping": "forecast-report-v1",
94
+ "authentication": {
95
+ "kind": "token_endpoint",
96
+ "token_request": {
97
+ "method": "GET",
98
+ "path": "/auth/getToken",
99
+ "parameters": [
100
+ {"name": "appKey", "value": "<app-key>", "location": "query"},
101
+ {"name": "appSecurity", "value": "<app-secret>", "location": "query"}
102
+ ]
103
+ },
104
+ "success": {"http_status": [200], "body_code_path": "code", "body_code_values": [200]},
105
+ "token_path": "data.token",
106
+ "header_name": "Authorization",
107
+ "header_scheme": "Bearer"
108
+ },
109
+ "response_success": {"http_status": [200], "body_code_path": "code", "body_code_values": [200]},
110
+ "max_token_refreshes_per_day": 20
111
+ }
112
+ ```
113
+
114
+ `token_path`、业务成功码和 `/forecast/report` 只是示例,必须按目标接口的真实响应和路径配置。
115
+ 若响应提供有效期,可设置 `expires_in_path` 与 `expires_in_unit`;否则服务端默认按 7200 秒缓存,
116
+ 并在 `refresh_skew_seconds` 前刷新。不同环境应使用不同 Profile 版本或名称;修改目标地址、
117
+ 认证规则或凭据时创建新版本。`get`/`list` 只返回凭据已配置的脱敏标记,无法取回明文。
118
+
119
+ ```bash
120
+ ml-platform --profile server validate-destination-profile /absolute/path/to/profile.json
121
+ ml-platform --profile server create-destination-profile /absolute/path/to/profile.json
122
+ ml-platform --profile server list-destination-profiles --limit 50 --offset 0
123
+ ml-platform --profile server get-destination-profile forecast_sink v1
124
+ ```
125
+
126
+ 计划引用已有 Profile,不复制凭据。`SCHEDULE_JSON` 示例:
127
+
128
+ ```json
129
+ {
130
+ "schema_version": "ml_data_platform.prediction_report_schedule/v1",
131
+ "schedule_id": "forecast_hourly",
132
+ "name": "Hourly forecast report",
133
+ "deployment_id": "<deployment-id>",
134
+ "enabled": false,
135
+ "cron": "0 * * * *",
136
+ "timezone": "Asia/Shanghai",
137
+ "request": {"entity": {"site": "site-1"}, "horizon": "1h"},
138
+ "destination": {"name": "forecast_sink", "version": "v1"}
139
+ }
140
+ ```
141
+
142
+ 计划要求部署的模型支持 `feature_lookup`;部署必须有可用推理策略,或在计划请求中提供
143
+ `horizon`。五段 cron 至少间隔五分钟。`enabled: false` 用于先创建但不发送的计划;
144
+ 确认目标接口可用且部署 READY 后再恢复。计划创建或 Profile 校验成功均不等于已推送成功。
145
+
146
+ ```bash
147
+ ml-platform --profile server create-prediction-report-schedule /absolute/path/to/schedule.json
148
+ ml-platform --profile server list-prediction-report-schedules --limit 50 --offset 0
149
+ ml-platform --profile server get-prediction-report-schedule forecast_hourly
150
+ ml-platform --profile server update-prediction-report-schedule forecast_hourly /absolute/path/to/changes.json
151
+ ml-platform --profile server pause-prediction-report-schedule forecast_hourly
152
+ ml-platform --profile server resume-prediction-report-schedule forecast_hourly
153
+ ml-platform --profile server list-prediction-report-runs forecast_hourly --limit 50 --offset 0
154
+ ml-platform --profile server get-prediction-report-run <run-id>
155
+ ```
156
+
157
+ `CHANGES_JSON` 是仅含变更字段的对象,例如
158
+ `{"destination":{"name":"forecast_sink","version":"v2"}}`。更新不会改写历史运行;
159
+ 是否已投递成功以 Run 的 `status`、`destination_status_code` 和错误码为准。
160
+
76
161
  `READY` 必须同时包含 `ReplicasReady=true`、`ArtifactsVerified=true` 和
77
162
  `SmokePredictionPassed=true`。`get-deployment` 返回控制器实际观察到的 endpoint 元数据;
78
163
  本地 CLI 不推测 Kubernetes Service 名称。部署后验证优先使用控制面代理:
@@ -117,6 +202,21 @@ ml-platform predict-model /absolute/path/to/request.json \
117
202
  --serving-url https://storage-forecast.example
118
203
  ```
119
204
 
205
+ 同步零样本预测使用平台控制面提供的模型名称入口,不要求用户传入 `project`、合同版本或普通
206
+ 请求的 `release_id`:
207
+
208
+ ```bash
209
+ ml-platform list-foundation-models
210
+ ml-platform get-foundation-model chronos2_forecaster
211
+ ml-platform predict-foundation chronos2_forecaster /absolute/path/to/request.json
212
+ ml-platform predict-foundation-csv chronos2_forecaster /absolute/path/to/input.csv \
213
+ --schema /absolute/path/to/schema.json \
214
+ --forecast /absolute/path/to/forecast.json
215
+ ```
216
+
217
+ `--release-id` 仅用于精确回放。零样本请求是同步、有界的 JSON 或 multipart CSV,不创建预测任务
218
+ 或结果资源。
219
+
120
220
  训练历史必须使用各个历史 cutoff 当时可取得的天气预报,不得以事后实测天气替代。
121
221
 
122
222
  Parameter、Feature、FeatureSet 的删除命令执行软删除,并支持带 actor、reason 和幂等键的
@@ -126,7 +126,7 @@ function normalizeSource(value, label) {
126
126
  throw new Error(`${label} uses unsupported field 'parameters'; use 'params'`);
127
127
  if (source.mode === "sql" && typeof source.sql === "string" && source.sql.trimEnd().endsWith(";"))
128
128
  throw new Error(`SQL ${label}.sql must not end with a semicolon`);
129
- return { adapter: pythonString(defaultIfAbsent(source, "adapter", "synthetic")), mode: choice(defaultIfAbsent(source, "mode", "direct_column"), ["direct_column", "sql", "derived"], `${label} mode`), source_metric: optionalString(source.source_metric, "source_metric"), source_group: optionalString(source.source_group, "source_group"), measurement: optionalString(source.measurement, "measurement"), field: optionalString(source.field, "field"), tags: stringMap(defaultIfAbsent(source, "tags", {}), `${label} tags`), schema: optionalString(aliasIfAbsent(source, "schema", "schema_name"), "schema"), table: optionalString(source.table, "table"), time_column: optionalString(source.time_column, "time_column"), value_column: optionalString(source.value_column, "value_column"), metric_name_column: optionalString(source.metric_name_column, "metric_name_column"), metric_name: optionalString(source.metric_name, "metric_name"), unit_column: optionalString(source.unit_column, "unit_column"), unit: optionalString(aliasIfAbsent(source, "unit", "source_unit"), "source unit"), filters: stringMap(defaultIfAbsent(source, "filters", {}), `${label} filters`), sql: optionalString(source.sql, "source sql"), params: object(defaultIfAbsent(source, "params", {}), `${label} params`) };
129
+ return { adapter: pythonString(defaultIfAbsent(source, "adapter", "synthetic")), connection_id: optionalString(source.connection_id, "connection_id"), mode: choice(defaultIfAbsent(source, "mode", "direct_column"), ["direct_column", "sql", "derived"], `${label} mode`), source_metric: optionalString(source.source_metric, "source_metric"), source_group: optionalString(source.source_group, "source_group"), measurement: optionalString(source.measurement, "measurement"), field: optionalString(source.field, "field"), tags: stringMap(defaultIfAbsent(source, "tags", {}), `${label} tags`), schema: optionalString(aliasIfAbsent(source, "schema", "schema_name"), "schema"), table: optionalString(source.table, "table"), time_column: optionalString(source.time_column, "time_column"), value_column: optionalString(source.value_column, "value_column"), metric_name_column: optionalString(source.metric_name_column, "metric_name_column"), metric_name: optionalString(source.metric_name, "metric_name"), unit_column: optionalString(source.unit_column, "unit_column"), unit: optionalString(aliasIfAbsent(source, "unit", "source_unit"), "source unit"), filters: stringMap(defaultIfAbsent(source, "filters", {}), `${label} filters`), sql: optionalString(source.sql, "source sql"), params: object(defaultIfAbsent(source, "params", {}), `${label} params`) };
130
130
  }
131
131
  function normalizeParameter(payload) {
132
132
  const source = normalizeSource(payload.source, "parameter source");
@@ -29,6 +29,7 @@ const BUSINESS_COMMANDS = new Set([
29
29
  "add-dataset", "update-dataset", "delete-dataset", "list-dataset-artifacts",
30
30
  "register-operator", "show-operator-specs", "delete-operator", "run-operator",
31
31
  "get-job", "wait-job", "retry-job", "cancel-job", "get-dataset-artifact", "download-dataset-artifact", "fetch-inference-data", "fetch-inference-context", "predict-model", "apply",
32
+ "list-foundation-models", "get-foundation-model", "predict-foundation", "predict-foundation-csv",
32
33
  "list-system-models", "get-system-model", "register-training-run", "validate-training-run", "submit-training-job", "get-training-job", "retry-training-job", "cancel-training-job",
33
34
  "register-evaluation-config", "get-evaluation-config", "register-metric-definition", "get-metric-definition",
34
35
  "register-executable-package", "verify-executable-package", "publish-executable-package",
@@ -39,6 +40,10 @@ const BUSINESS_COMMANDS = new Set([
39
40
  "get-deployment", "wait-deployment", "reconcile-deployment", "approve-deployment",
40
41
  "promote-deployment", "rollback-deployment", "suspend-deployment", "resume-deployment",
41
42
  "undeploy-deployment", "get-deployment-events", "predict-deployment",
43
+ "validate-destination-profile", "create-destination-profile", "list-destination-profiles", "get-destination-profile",
44
+ "create-prediction-report-schedule", "list-prediction-report-schedules", "get-prediction-report-schedule",
45
+ "update-prediction-report-schedule", "pause-prediction-report-schedule", "resume-prediction-report-schedule",
46
+ "list-prediction-report-runs", "get-prediction-report-run",
42
47
  ]);
43
48
  const COMMAND_USAGE = {
44
49
  ...Object.fromEntries([...LIFECYCLE_COLLECTIONS].map((name) => [`list-${name}`, `list-${name} [--limit N] [--offset N] [-q QUERY]`])),
@@ -114,6 +119,10 @@ const COMMAND_USAGE = {
114
119
  "fetch-inference-data": "fetch-inference-data MANIFEST --cutoff-time TIMESTAMP [--max-workers N] [--max-source-lag-hours HOURS] [--no-validate-freshness] [--allow-missing]",
115
120
  "fetch-inference-context": "fetch-inference-context REQUEST_JSON",
116
121
  "predict-model": "predict-model REQUEST_JSON --serving-url URL",
122
+ "list-foundation-models": "list-foundation-models",
123
+ "get-foundation-model": "get-foundation-model NAME",
124
+ "predict-foundation": "predict-foundation NAME REQUEST_JSON [--release-id ID]",
125
+ "predict-foundation-csv": "predict-foundation-csv NAME CSV_FILE --schema SCHEMA_JSON --forecast FORECAST_JSON [--release-id ID]",
117
126
  "list-system-models": "list-system-models",
118
127
  "get-system-model": "get-system-model NAME VERSION [--project PROJECT]",
119
128
  "register-training-run": "register-training-run RUN_JSON",
@@ -161,6 +170,18 @@ const COMMAND_USAGE = {
161
170
  "undeploy-deployment": "undeploy-deployment DEPLOYMENT_ID --actor NAME --reason TEXT",
162
171
  "get-deployment-events": "get-deployment-events DEPLOYMENT_ID [--limit N] [--offset N]",
163
172
  "predict-deployment": "predict-deployment DEPLOYMENT_ID REQUEST_JSON",
173
+ "create-destination-profile": "create-destination-profile PROFILE_JSON",
174
+ "validate-destination-profile": "validate-destination-profile PROFILE_JSON",
175
+ "list-destination-profiles": "list-destination-profiles [--limit N] [--offset N]",
176
+ "get-destination-profile": "get-destination-profile NAME VERSION",
177
+ "create-prediction-report-schedule": "create-prediction-report-schedule SCHEDULE_JSON",
178
+ "list-prediction-report-schedules": "list-prediction-report-schedules [--limit N] [--offset N]",
179
+ "get-prediction-report-schedule": "get-prediction-report-schedule SCHEDULE_ID",
180
+ "update-prediction-report-schedule": "update-prediction-report-schedule SCHEDULE_ID CHANGES_JSON",
181
+ "pause-prediction-report-schedule": "pause-prediction-report-schedule SCHEDULE_ID",
182
+ "resume-prediction-report-schedule": "resume-prediction-report-schedule SCHEDULE_ID",
183
+ "list-prediction-report-runs": "list-prediction-report-runs SCHEDULE_ID [--limit N] [--offset N]",
184
+ "get-prediction-report-run": "get-prediction-report-run RUN_ID",
164
185
  apply: "apply CATALOG_DIRECTORY [--dry-run] [--project PROJECT]",
165
186
  };
166
187
  function usage(command) {
@@ -720,6 +741,33 @@ async function runBusinessCli(argv) {
720
741
  throw new Error("--serving-url is required");
721
742
  result = await new PlatformApiClient(servingUrl, options.timeout).post("/v1/inference", request);
722
743
  }
744
+ else if (options.command === "list-foundation-models") {
745
+ result = await client(options).get("/foundation-models");
746
+ }
747
+ else if (options.command === "get-foundation-model") {
748
+ const name = positional(rest, "foundation model name");
749
+ result = await client(options).get(`/foundation-models/${encodeURIComponent(name)}`);
750
+ }
751
+ else if (options.command === "predict-foundation") {
752
+ const name = positional(rest, "foundation model name");
753
+ const request = readSpec(positional(rest, "request JSON"));
754
+ const releaseId = take(rest, "--release-id");
755
+ const headers = releaseId ? { "X-ITSMP-Foundation-Release": releaseId } : {};
756
+ result = await client(options).postWithHeaders(`/foundation-models/${encodeURIComponent(name)}/predict`, request, headers);
757
+ }
758
+ else if (options.command === "predict-foundation-csv") {
759
+ const name = positional(rest, "foundation model name");
760
+ const csvFile = positional(rest, "CSV file");
761
+ const schemaFile = take(rest, "--schema");
762
+ const forecastFile = take(rest, "--forecast");
763
+ if (!schemaFile)
764
+ throw new Error("--schema is required");
765
+ if (!forecastFile)
766
+ throw new Error("--forecast is required");
767
+ const releaseId = take(rest, "--release-id");
768
+ const headers = releaseId ? { "X-ITSMP-Foundation-Release": releaseId } : {};
769
+ result = await client(options).uploadFoundationCsv(`/foundation-models/${encodeURIComponent(name)}/predict-file`, readSpec(schemaFile), readSpec(forecastFile), csvFile, headers);
770
+ }
723
771
  else if (options.command === "list-deployment-targets") {
724
772
  result = await client(options).get("/deployment-targets");
725
773
  }
@@ -826,6 +874,40 @@ async function runBusinessCli(argv) {
826
874
  const request = readSpec(positional(rest, "request JSON"));
827
875
  result = await client(options).post(`/deployments/${encodeURIComponent(deploymentId)}/predict`, request);
828
876
  }
877
+ else if (["create-destination-profile", "validate-destination-profile"].includes(options.command)) {
878
+ result = await client(options).post(options.command === "create-destination-profile" ? "/destination-profiles" : "/destination-profiles/validate", readSpec(positional(rest, "profile JSON")));
879
+ }
880
+ else if (options.command === "list-destination-profiles") {
881
+ result = await listCollection(client(options), "/destination-profiles", {}, rest);
882
+ }
883
+ else if (options.command === "get-destination-profile") {
884
+ const name = positional(rest, "profile name");
885
+ const version = positional(rest, "profile version");
886
+ result = await client(options).get(`/destination-profiles/${encodeURIComponent(name)}/versions/${encodeURIComponent(version)}`);
887
+ }
888
+ else if (options.command === "create-prediction-report-schedule") {
889
+ result = await client(options).post("/prediction-report-schedules", readSpec(positional(rest, "schedule JSON")));
890
+ }
891
+ else if (options.command === "list-prediction-report-schedules") {
892
+ result = await listCollection(client(options), "/prediction-report-schedules", {}, rest);
893
+ }
894
+ else if (["get-prediction-report-schedule", "update-prediction-report-schedule", "pause-prediction-report-schedule", "resume-prediction-report-schedule", "list-prediction-report-runs"].includes(options.command)) {
895
+ const scheduleId = positional(rest, "schedule id");
896
+ const endpoint = `/prediction-report-schedules/${encodeURIComponent(scheduleId)}`;
897
+ if (options.command === "update-prediction-report-schedule")
898
+ result = await client(options).patch(endpoint, readSpec(positional(rest, "changes JSON")));
899
+ else if (options.command === "pause-prediction-report-schedule")
900
+ result = await client(options).post(`${endpoint}/pause`);
901
+ else if (options.command === "resume-prediction-report-schedule")
902
+ result = await client(options).post(`${endpoint}/resume`);
903
+ else if (options.command === "list-prediction-report-runs")
904
+ result = await listCollection(client(options), `${endpoint}/runs`, {}, rest);
905
+ else
906
+ result = await client(options).get(endpoint);
907
+ }
908
+ else if (options.command === "get-prediction-report-run") {
909
+ result = await client(options).get(`/prediction-report-runs/${encodeURIComponent(positional(rest, "run id"))}`);
910
+ }
829
911
  else if (options.command === "get-model-runtime-release") {
830
912
  result = await client(options).get("/model-runtime-release");
831
913
  }
@@ -22,10 +22,11 @@ class PlatformApiClient {
22
22
  }
23
23
  return url;
24
24
  }
25
- async request(method, endpoint, { params, payload, body, contentType } = {}) {
25
+ async request(method, endpoint, { params, payload, body, contentType, requestHeaders } = {}) {
26
26
  const controller = new AbortController();
27
27
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
28
28
  const headers = { Accept: "application/json" };
29
+ Object.assign(headers, requestHeaders || {});
29
30
  let requestBody = body;
30
31
  if (payload !== undefined) {
31
32
  headers["Content-Type"] = "application/json";
@@ -59,8 +60,33 @@ class PlatformApiClient {
59
60
  }
60
61
  get(endpoint, params) { return this.request("GET", endpoint, { params }); }
61
62
  post(endpoint, payload, params) { return this.request("POST", endpoint, { payload, params }); }
63
+ postWithHeaders(endpoint, payload, requestHeaders) { return this.request("POST", endpoint, { payload, requestHeaders }); }
62
64
  put(endpoint, payload, params) { return this.request("PUT", endpoint, { payload, params }); }
65
+ patch(endpoint, payload, params) { return this.request("PATCH", endpoint, { payload, params }); }
63
66
  delete(endpoint, params) { return this.request("DELETE", endpoint, { params }); }
67
+ uploadFoundationCsv(endpoint, schema, forecast, filePath, requestHeaders = {}) {
68
+ const resolved = path.resolve(expandHome(filePath));
69
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile())
70
+ throw new Error(`CSV file not found: ${resolved}`);
71
+ const boundary = `itsmp-${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
72
+ const parts = [];
73
+ const field = (name, value, contentType) => {
74
+ parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="${name}"\r\nContent-Type: ${contentType}\r\n\r\n`));
75
+ parts.push(Buffer.from(value));
76
+ parts.push(Buffer.from("\r\n"));
77
+ };
78
+ field("schema", JSON.stringify(schema), "application/json");
79
+ field("forecast", JSON.stringify(forecast), "application/json");
80
+ const filename = path.basename(resolved).replace(/["\r\n]/g, "_");
81
+ parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${filename}"\r\nContent-Type: text/csv\r\n\r\n`));
82
+ parts.push(fs.readFileSync(resolved));
83
+ parts.push(Buffer.from(`\r\n--${boundary}--\r\n`));
84
+ return this.request("POST", endpoint, {
85
+ body: Buffer.concat(parts),
86
+ contentType: `multipart/form-data; boundary=${boundary}`,
87
+ requestHeaders,
88
+ });
89
+ }
64
90
  uploadOperatorPackage(project, name, version, packagePath) {
65
91
  const resolved = path.resolve(expandHome(packagePath));
66
92
  if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile())
@@ -88,3 +88,8 @@ After a human confirms source mapping, event time, entity keys, units, availabil
88
88
  horizon, and feature formulas, use `$feature-management` to create governed assets and build a
89
89
  DatasetArtifact. Use `$model-lifecycle-management` only after that artifact exists. Exploration does not
90
90
  authorize publishing assets, building datasets, or submitting training jobs.
91
+
92
+ At the end of an exploration task, offer the next relevant option: confirm the
93
+ unresolved business semantics with an owner, or, when they are already confirmed,
94
+ define governed assets with `$feature-management`. Name the evidence that makes
95
+ the option available; do not present exploratory rows as a finished dataset.
@@ -259,7 +259,7 @@ unit, time/availability semantics and missing policy in the semantic review.
259
259
  Never infer a source table, column, measurement, tag, unit or timezone from a
260
260
  Parameter name.
261
261
 
262
- Create one stable, versioned source contract for each independently readable value. Keep credentials out of JSON. Use only supported direct adapters (`postgresql_direct`, `mysql_direct`, `sqlserver_direct`, and `influxdb_direct`) and explicit source identity. The server supplies database DSNs from managed Secrets; never add them to CLI arguments or Catalog JSON. Put source data validity in `quality_rules`; put dataset-specific transformations in preprocess Operators.
262
+ Create one stable, versioned source contract for each independently readable value. Keep credentials out of JSON. Use only supported direct adapters (`postgresql_direct`, `mysql_direct`, `sqlserver_direct`, and `influxdb_direct`) and explicit source identity. For PostgreSQL, keep `source.adapter=postgresql_direct` and put the configured alias in `source.connection_id` (for example `postgresql_bf_monitoring`); never put the connection alias in `source.adapter`. The server supplies database DSNs from managed Secrets; never add them to CLI arguments or Catalog JSON. A missing `connection_id` on a historical PostgreSQL Parameter uses the compatibility default `postgresql`. Put source data validity in `quality_rules`; put dataset-specific transformations in preprocess Operators.
263
263
 
264
264
  When historical and live systems expose the same value, keep one Parameter and add an optional
265
265
  `online_source`. Batch/as-of reads always use `source`; realtime causal reads use `online_source`
@@ -503,3 +503,10 @@ actual compute backend
503
503
  ```
504
504
 
505
505
  If the work stops before publication, distinguish generated files, locally validated files, dry-run validation, and remotely published assets.
506
+
507
+ Close with at most two optional next steps tied to the actual checkpoint. For
508
+ example, after a dry-run, offer publication only with separate approval; after
509
+ a verified DatasetArtifact, offer training or evaluation through
510
+ `$model-lifecycle-management`. If the artifact is missing or validation failed,
511
+ name that blocker instead of suggesting model training. A suggested step does
512
+ not authorize publishing, building, or submitting a workload.
@@ -9,6 +9,7 @@
9
9
  "expected_frequency": "1min",
10
10
  "source": {
11
11
  "adapter": "postgresql_direct",
12
+ "connection_id": "postgresql",
12
13
  "mode": "direct_column",
13
14
  "schema": "process_data",
14
15
  "table": "sensor_readings",
@@ -105,6 +105,7 @@ adapter;凭据不进入 JSON。Feature/Operator/FeatureSet 不需要复制一
105
105
  {
106
106
  "source": {
107
107
  "adapter": "postgresql_direct",
108
+ "connection_id": "postgresql_bf_monitoring",
108
109
  "schema": "process_data",
109
110
  "table": "pressure_history",
110
111
  "time_column": "event_time",
@@ -168,11 +169,16 @@ requires a new Parameter version and the affected reverse-dependency closure.
168
169
 
169
170
  PostgreSQL, MySQL, and SQL Server direct-column Parameters share this source
170
171
  shape. Set `adapter` to `postgresql_direct`, `mysql_direct`, or
171
- `sqlserver_direct`; keep database-specific DSNs in server-managed Secrets.
172
+ `sqlserver_direct`; keep database-specific DSNs in server-managed Secrets. For
173
+ PostgreSQL, use `connection_id` to select a configured connection alias, for
174
+ example `postgresql_bf_monitoring`. `connection_id` is not an adapter name and
175
+ must not replace `postgresql_direct`. If omitted on a historical PostgreSQL
176
+ Parameter, the runtime uses the compatibility default connection `postgresql`.
172
177
 
173
178
  ```json
174
179
  {
175
180
  "adapter": "postgresql_direct",
181
+ "connection_id": "postgresql_bf_monitoring",
176
182
  "mode": "direct_column",
177
183
  "schema": "process_data",
178
184
  "table": "sensor_readings",
@@ -63,3 +63,10 @@ deployment does not reach `READY` or an operation is rejected.
63
63
  Report the deployment ID, revision, immutable image digest, desired and
64
64
  observed state, failed conditions, endpoint reachability, and event evidence.
65
65
  Do not claim a deployment is usable merely because its Pod is running.
66
+
67
+ Close with an optional next step based on observed state: resolve failed READY
68
+ conditions before prediction; once READY, offer `predict-deployment` to verify
69
+ the model. After a successful deployment-bound prediction, offer scheduled
70
+ delivery through `$prediction-report-management` only when recurring reporting
71
+ is relevant and the package supports `feature_lookup`. Do not create a report
72
+ schedule or imply that READY alone proves delivery to an external destination.
@@ -18,6 +18,12 @@ Read [references/discovery.md](references/discovery.md) before locating existing
18
18
  resources or selecting runtime bindings. It also defines Job/package preflight
19
19
  and version-skew handling.
20
20
 
21
+ Read [references/zero-shot-inference.md](references/zero-shot-inference.md) when
22
+ the user wants synchronous zero-shot forecasting from JSON or CSV. This path
23
+ uses the platform-owned `chronos2_forecaster` model name, not a public project
24
+ or contract version, and does not create a TrainingRun, ModelArtifact,
25
+ PredictionJob or prediction result record.
26
+
21
27
  ## Shared Gates
22
28
 
23
29
  Before training a model that will be evaluated, also read
@@ -38,8 +44,22 @@ evidence when deployment differs.
38
44
  - Do not register caller-computed evaluation results. Workers produce predictions, metrics, decisions, and summaries from frozen DatasetArtifact rowsets.
39
45
  - Keep credentials, registry secrets, Kubernetes details, and model binaries out of request JSON and reports.
40
46
 
47
+ For zero-shot inference, the public identity is only `chronos2_forecaster`.
48
+ Internal contract versions, canonical project keys, runtime bindings and
49
+ historical aliases are resolved by the server. Do not construct a URL
50
+ containing `v1`, `project` or `release_id`.
51
+
41
52
  Report immutable input identities, returned run/job/package IDs, status, validation or gate failures, and the next authorized action. Never claim deployment; it is outside this Skill.
42
53
 
43
54
  Route deployment validation, creation, rollout state, approval, promotion,
44
55
  rollback, offline operations, and deployment-bound prediction to the separate
45
56
  `model-deployment-management` Skill.
57
+
58
+ At task completion, suggest only the next gate supported by the observed
59
+ evidence: a valid DatasetArtifact can lead to training, a valid ModelArtifact
60
+ to evaluation, a PASS evaluation to registration and packaging, and a READY
61
+ package with immutable digest to `$model-deployment-management`. If a gate
62
+ failed, suggest inspection or correction of that gate instead. A zero-shot
63
+ prediction is complete on its own; do not imply it produced an artifact or
64
+ requires training. These are optional next actions, not authorization to
65
+ submit or mutate resources.
@@ -28,6 +28,17 @@ it does not mean every model/device is approved by a release.
28
28
  `worker_dependencies_verified=false` explicitly means discovery has not tested
29
29
  imports, image pulls or model prediction in the Worker.
30
30
 
31
+ For zero-shot model discovery, use the separate foundation-model endpoints:
32
+
33
+ ```bash
34
+ ml-platform --profile server list-foundation-models
35
+ ml-platform --profile server get-foundation-model chronos2_forecaster
36
+ ```
37
+
38
+ These endpoints intentionally do not expose the SystemModel `project` or
39
+ contract version. Do not use `get-system-model` or Runtime Release binding keys
40
+ as the public zero-shot model identifier.
41
+
31
42
  ## Resource lookup and pagination
32
43
 
33
44
  ```bash
@@ -11,7 +11,7 @@ Example forecasting sequence run:
11
11
 
12
12
  ```json
13
13
  {
14
- "schema_version": "ml_data_platform.training_run/v3",
14
+ "schema_version": "ml_data_platform.training_run/v4",
15
15
  "run_id": "pressure_forecast_run_01",
16
16
  "experiment": "pressure_forecast",
17
17
  "task": {"kind": "forecasting", "objective": "regression"},
@@ -183,9 +183,12 @@ weather observations.
183
183
 
184
184
  Inspect `data_schema.json`, `resolved_manifest.json` and the feature Parquet via
185
185
  `download-dataset-artifact DATASET_ID MANIFEST_HASH --project PROJECT --out-dir DIR`
186
- (repeat `--file` for selective downloads). The FeatureSet reference must match
187
- the artifact; the full ordered FeatureSet determines model channels. There is
188
- no documented `data.features.columns` shortcut for choosing a subset.
186
+ (repeat `--file` for selective downloads). In TrainingRun v4, the FeatureSet
187
+ reference defines the ordered model inputs. It may be a registered exact-version
188
+ subset of the DatasetArtifact's materialized FeatureSet, in its own order. The
189
+ platform freezes both identities and the projected dependency contract in the
190
+ TrainingJob and ModelArtifact. There is no `data.features.columns` shortcut:
191
+ create a new immutable FeatureSet version for each distinct model input contract.
189
192
 
190
193
  `identity:v1` leaves labels unchanged. `difference` requires a baseline Feature
191
194
  in `required_inputs` and at least one `online_inputs` entry, which must be a
@@ -286,7 +289,7 @@ null Features or labels also skip samples. Candidate row counts therefore are
286
289
  not training/evaluation sample counts. Report the materialized population and
287
290
  coverage instead of assuming all Parquet rows were used.
288
291
 
289
- For `continuous_target_series`, TrainingRun v3 derives the fixed maximum
292
+ For `continuous_target_series`, TrainingRun v4 derives the fixed maximum
290
293
  `prediction_length` as `data.temporal.horizon / data.temporal.frequency`; the
291
294
  horizon must be a positive exact multiple of the frequency. The target input
292
295
  must be a numeric, at-prediction Feature and the output label must be the sole
@@ -21,7 +21,7 @@ FeatureSet order and evaluation runtime before the first Job. See
21
21
  `label_time - prediction_time`, and validate the complete TrainingRun before
22
22
  registration/submission. Validation may not catch undeclared plugin limits or
23
23
  missing dependencies in the eventual Worker.
24
- - For a continuous future trajectory, use TrainingRun v3. Use
24
+ - For a continuous future trajectory, use TrainingRun v4. Use
25
25
  `continuous_target_series` for legacy v1 or
26
26
  `continuous_target_series_with_covariates` for v2. Its fixed maximum
27
27
  prediction length comes from temporal horizon divided by frequency; do not
@@ -75,7 +75,7 @@ ml-platform --profile server submit-training-job training-job-request.json
75
75
  ml-platform --profile server get-training-job <job-id>
76
76
  ```
77
77
 
78
- The TrainingRun binds immutable DatasetArtifact identities, DataSchema, ordered inputs, targets, InputAdapter, canonical SystemModel `v1`, reproducibility controls, and runtime identity. Job resolution freezes the SystemModel and approved runtime image as an internal TrainerDefinition snapshot. Validation proves compatibility only. Submit the run and Job separately after authorization and record spec hash and Job ID. Terminal success must expose a ModelArtifact ID; validate it before evaluation or packaging.
78
+ The TrainingRun binds immutable DatasetArtifact identities, DataSchema, an ordered registered model FeatureSet, targets, InputAdapter, canonical SystemModel `v1`, reproducibility controls, and runtime identity. The model FeatureSet may be an exact-version subset of the Artifact's materialized FeatureSet; changing only the subset or order does not require rebuilding the wide DatasetArtifact. Job resolution freezes both FeatureSet identities, selected columns and projected lineage contract together with the SystemModel and approved runtime image. Validation proves compatibility only. Submit the run and Job separately after authorization and record spec hash and Job ID. Terminal success must expose a ModelArtifact ID; validate it before evaluation or packaging.
79
79
 
80
80
  ```bash
81
81
  ml-platform --profile server validate-model-artifact <artifact-id>
@@ -0,0 +1,67 @@
1
+ # Synchronous zero-shot inference
2
+
3
+ Use this workflow for platform-approved Chronos-2 forecasting without a
4
+ TrainingRun or ModelArtifact. The public model identity is the name
5
+ `chronos2_forecaster`; internal contract versions and runtime bindings are
6
+ server-side compatibility details.
7
+
8
+ ## Discovery
9
+
10
+ ```bash
11
+ ml-platform --profile server list-foundation-models
12
+ ml-platform --profile server get-foundation-model chronos2_forecaster
13
+ ```
14
+
15
+ The response contains the active `release_id`, checkpoint digest, Serving image
16
+ digest and bounded input capabilities. Normal prediction does not require the
17
+ caller to look up or submit that release ID.
18
+
19
+ ## JSON prediction
20
+
21
+ The request contains `schema`, `records` and `forecast`. Column roles are
22
+ explicit; the server does not infer target, timestamp or covariate columns from
23
+ their names.
24
+
25
+ ```bash
26
+ ml-platform --profile server predict-foundation \
27
+ chronos2_forecaster /absolute/path/to/request.json
28
+ ```
29
+
30
+ The endpoint is `POST /foundation-models/chronos2_forecaster/predict`.
31
+
32
+ ## CSV prediction
33
+
34
+ CSV uses the same schema and forecast JSON as the JSON path. The CLI sends one
35
+ bounded multipart request and does not upload the file to object storage.
36
+
37
+ ```bash
38
+ ml-platform --profile server predict-foundation-csv \
39
+ chronos2_forecaster /absolute/path/to/input.csv \
40
+ --schema /absolute/path/to/schema.json \
41
+ --forecast /absolute/path/to/forecast.json
42
+ ```
43
+
44
+ The endpoint is `POST /foundation-models/chronos2_forecaster/predict-file`.
45
+ JSON and CSV are normalized to the same canonical rows and should produce the
46
+ same `input_hash` for equivalent input.
47
+
48
+ ## Exact replay
49
+
50
+ Use `--release-id` only for replay or incident comparison:
51
+
52
+ ```bash
53
+ ml-platform --profile server predict-foundation \
54
+ chronos2_forecaster /absolute/path/to/request.json \
55
+ --release-id chronos2-base-2026-08
56
+ ```
57
+
58
+ The server validates that the release belongs to the named model and is
59
+ eligible for replay. A normal request always resolves the active release.
60
+
61
+ ## Runtime boundary
62
+
63
+ Foundation Serving is a long-running CPU workload. It loads and verifies the
64
+ immutable checkpoint at startup and does not connect to PostgreSQL during a
65
+ request. Synchronous requests are bounded by release byte, row, series,
66
+ context, horizon and timeout limits. There is no JSONL, asynchronous task,
67
+ PredictionRun or prediction-result persistence in this MVP.
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: prediction-report-management
3
+ description: Manage versioned business-owned prediction report destinations, schedules, and run diagnostics through the ITSMP ml-platform CLI. Use for configuring HTTP delivery and token acquisition, creating or changing scheduled reports, pausing or resuming them, or inspecting report runs. Do not use for model deployment, direct prediction, Kubernetes administration, or image releases.
4
+ ---
5
+
6
+ # Prediction Report Management
7
+
8
+ Use the `ml-platform` CLI installed with this Skill's npm release. Reporting is a
9
+ control-plane workflow: the API runs schedules and sends predictions from a
10
+ READY deployment; model Serving does not receive destination credentials.
11
+
12
+ ## Read-only checks
13
+
14
+ ```bash
15
+ ml-platform --profile server health
16
+ ml-platform --profile server list-destination-profiles
17
+ ml-platform --profile server get-destination-profile NAME v1
18
+ ml-platform --profile server list-prediction-report-schedules
19
+ ml-platform --profile server get-prediction-report-schedule SCHEDULE_ID
20
+ ml-platform --profile server list-prediction-report-runs SCHEDULE_ID
21
+ ml-platform --profile server get-prediction-report-run RUN_ID
22
+ ```
23
+
24
+ Check the deployment with `get-deployment DEPLOYMENT_ID` before creating a
25
+ schedule. The deployment must support `feature_lookup` and have a usable
26
+ inference horizon, supplied by either the schedule request or deployment
27
+ policy. A report run may be `SKIPPED` when the selected revision is not READY.
28
+
29
+ ## Configure a destination
30
+
31
+ The `PROFILE_JSON` argument is a local JSON file, not inline JSON. Include
32
+ `schema_version`, `name`, `version`, `base_url`, `path`, authentication, and
33
+ response success rules as required by the target. For token-based auth, set
34
+ `authentication.token_request` parameters and `token_path`; configure both
35
+ token and report business success rules when HTTP 2xx alone is insufficient.
36
+
37
+ ```bash
38
+ ml-platform --profile server validate-destination-profile PROFILE_JSON
39
+ ml-platform --profile server create-destination-profile PROFILE_JSON
40
+ ml-platform --profile server get-destination-profile NAME v1
41
+ ```
42
+
43
+ Validation checks schema and local policy; it does **not** call the token or
44
+ report endpoint. Versions are immutable. Changes to URL, auth, token extraction,
45
+ or success rules require a new profile version and a schedule update to point
46
+ to it. `get` and `list` redact credential values; they cannot reconstruct the
47
+ original file. Keep credential-bearing JSON outside the repository, restrict
48
+ file access, and do not print its contents or put secrets in shell arguments,
49
+ logs, examples, or Agent answers. Destination URL and token credentials are
50
+ business configuration submitted through this API, not Kubernetes Secrets.
51
+
52
+ ## Manage a schedule
53
+
54
+ Creating a schedule starts reporting when `enabled` is true. Obtain explicit
55
+ authorization for the exact destination and deployment before creation, update,
56
+ pause, or resume. Use `enabled: false` for a staged schedule that should not
57
+ run yet. `SCHEDULE_JSON` contains `deployment_id`, five-field `cron`, IANA
58
+ `timezone`, `request.entity`, and `destination: {"name":"...","version":"v1"}`.
59
+ Do not assume that an existing destination profile is bound to any schedule.
60
+
61
+ ```bash
62
+ ml-platform --profile server create-prediction-report-schedule SCHEDULE_JSON
63
+ ml-platform --profile server update-prediction-report-schedule SCHEDULE_ID CHANGES_JSON
64
+ ml-platform --profile server pause-prediction-report-schedule SCHEDULE_ID
65
+ ml-platform --profile server resume-prediction-report-schedule SCHEDULE_ID
66
+ ```
67
+
68
+ Updates accept only `name`, `cron`, `timezone`, `request`, `destination`,
69
+ `max_attempts`, and `timeout_seconds`; pause/resume control `enabled`.
70
+ After mutation, fetch the schedule and its runs. Report the schedule ID,
71
+ revision, destination name/version, next run time, latest run status, and
72
+ redacted error code. Do not claim delivery succeeded based only on validation
73
+ or schedule creation.
74
+
75
+ At completion, offer a next step only when it fits the observed state: after a
76
+ profile is created, optionally bind it to a schedule for a suitable deployment;
77
+ after a disabled schedule is verified, optionally resume it with explicit
78
+ authorization; after a run, inspect failure evidence or confirm `SUCCEEDED`.
79
+ Do not suggest another configuration step merely to keep the workflow going,
80
+ and do not treat a suggestion as permission to enable external delivery.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "定时预测上报管理"
3
+ short_description: "管理预测上报目标、计划及运行记录"
4
+ default_prompt: "使用 $prediction-report-management 管理定时预测上报配置、计划和运行记录。"