@zhuoyuezs/ml-platform 0.2.2-alpha.3 → 0.2.2-alpha.5

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` 获取稳定结构化输出。
@@ -31,6 +31,7 @@ business-client-js/
31
31
  └── src/ generated Node.js runtime
32
32
  npm/ml-platform/src/ TypeScript installer and dispatcher source
33
33
  skills/feature-management/
34
+ skills/data-source-exploration/
34
35
  skills/model-lifecycle-management/
35
36
  skills/model-deployment-management/
36
37
  npm/ml-platform/
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # ML Platform
2
2
 
3
- ML Platform 的 TypeScript CLI(编译为 Node.js JavaScript runtime)、`feature-management`、`model-lifecycle-management` 与
4
- `model-deployment-management` Agent Skill。CLI 与 Skill 由同一个 npm
3
+ ML Platform 的 TypeScript CLI(编译为 Node.js JavaScript runtime)、`feature-management`、
4
+ `data-source-exploration`、`model-lifecycle-management` 与 `model-deployment-management`
5
+ Agent Skill。CLI 与 Skill 由同一个 npm
5
6
  release 安装和升级,运行时不需要 Python 或 `uv`。
6
7
 
7
8
  ## 环境要求
@@ -18,7 +19,7 @@ release 安装和升级,运行时不需要 Python 或 `uv`。
18
19
  npx @zhuoyuezs/ml-platform@latest install
19
20
  ```
20
21
 
21
- 这条命令不需要额外参数。默认安装持久化的 `ml-platform` 命令,并将三个 Skill 安装到
22
+ 这条命令不需要额外参数。默认安装持久化的 `ml-platform` 命令,并将四个 Skill 安装到
22
23
  `~/.codex/skills/`,供当前用户的 Codex 使用。安装后重启终端和 Agent 会话。
23
24
 
24
25
  只在当前项目使用 Skill 时,在项目根目录运行:
@@ -94,6 +95,7 @@ Skill。`status --json` 中 `installed_release` 是当前 scope 的 Skill releas
94
95
 
95
96
  ```bash
96
97
  ml-platform list-parameters
98
+ ml-platform list-datasource-connections
97
99
  ml-platform list-datasets --project <project>
98
100
  ml-platform get-dataset <dataset_id> <dataset_version> --project <project>
99
101
  ml-platform resolve-dataset <dataset_id> <dataset_version> --project <project>
@@ -129,8 +131,8 @@ npx --yes --registry=https://registry.npmjs.org/ \
129
131
  ## 包内容
130
132
 
131
133
  - 一份由 TypeScript 编译的 business CLI;
132
- - 三份纯 Skill:`feature-management`、`model-lifecycle-management` 与
133
- `model-deployment-management`;
134
+ - 四份纯 Skill:`feature-management`、`data-source-exploration`、
135
+ `model-lifecycle-management` 与 `model-deployment-management`;
134
136
  - 显式安装、升级、状态、校验和回滚逻辑。
135
137
 
136
138
  不包含 Codex CLI、Python business-client wheel、Agent Host、平台服务端、模型训练或 Kubernetes
package/checksums.json CHANGED
@@ -2,28 +2,28 @@
2
2
  "files": [
3
3
  {
4
4
  "path": "runtime/business-client/README.md",
5
- "sha256": "sha256:30d921fabf5bc0339eda60169a1865f6007807b1d9a8d3e646b42f68cd563240",
6
- "size_bytes": 8125
5
+ "sha256": "sha256:c263ebe1591d38d90fb68227f42c6de43014a05e98b736d2e3363e19545676d9",
6
+ "size_bytes": 8779
7
7
  },
8
8
  {
9
9
  "path": "runtime/business-client/package-lock.json",
10
- "sha256": "sha256:1e364f51be2b6df7ab5f27b72aa04cb499d9d191a321ab669bba011555e659e7",
10
+ "sha256": "sha256:ebc31820ae0d2985879efd87ba4b0d8843e44a175d4c9e1dc557737893f8bdae",
11
11
  "size_bytes": 1628
12
12
  },
13
13
  {
14
14
  "path": "runtime/business-client/package.json",
15
- "sha256": "sha256:45545a61753cc889a1d578266634f0720423895e0693fa4911e0fdd3c0957f69",
15
+ "sha256": "sha256:4685ca172b5b23bd5de53bcccbd7f7412df281eff67533d72d1b598c63a28b47",
16
16
  "size_bytes": 671
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:7ddd434c1e8ee64d8a6de9005e4f6b440197eafab021071b9e4a8af340d4e23a",
26
- "size_bytes": 57877
25
+ "sha256": "sha256:739be8665f611802d9196ba84566578fbfc6544c6907af165edbaf115d9d1998",
26
+ "size_bytes": 62651
27
27
  },
28
28
  {
29
29
  "path": "runtime/business-client/src/config.js",
@@ -32,13 +32,23 @@
32
32
  },
33
33
  {
34
34
  "path": "runtime/business-client/src/http.js",
35
- "sha256": "sha256:4ae9e9ec10a74f36ed19ca7a63b0ba58a34cedea13ed95131ef1d07cd7d9e674",
36
- "size_bytes": 17176
35
+ "sha256": "sha256:3c8b40b0da0bb87c95f1367f540cd08a7ec28e0d5fe8e52a0367fecb5ae4094c",
36
+ "size_bytes": 18763
37
+ },
38
+ {
39
+ "path": "skills/data-source-exploration/SKILL.md",
40
+ "sha256": "sha256:3b609d61f3c73da3657ce2e6bb4d1eff95a90e4ac5e5445b8513536438b26b0b",
41
+ "size_bytes": 3853
42
+ },
43
+ {
44
+ "path": "skills/data-source-exploration/agents/openai.yaml",
45
+ "sha256": "sha256:5c7f7d497ad7738c672b8ee906d514284a2f2583a854f8fa487708a75836256f",
46
+ "size_bytes": 299
37
47
  },
38
48
  {
39
49
  "path": "skills/feature-management/SKILL.md",
40
- "sha256": "sha256:88898ea83ff339512d5512537db485a2764420abb67afceb9dd090cc780c00e0",
41
- "size_bytes": 33021
50
+ "sha256": "sha256:309d2ae292113f99bd17b6865b87bbe793809c88005458f477fa1e80c41b1523",
51
+ "size_bytes": 33334
42
52
  },
43
53
  {
44
54
  "path": "skills/feature-management/agents/openai.yaml",
@@ -87,8 +97,8 @@
87
97
  },
88
98
  {
89
99
  "path": "skills/feature-management/assets/catalog-template/parameters/example_temperature.v1.json",
90
- "sha256": "sha256:28c7d3576c4b7e94c1e9db7f95f26d83ee2e10dc9f81ec6223f4fbd9b2f5eeda",
91
- "size_bytes": 1488
100
+ "sha256": "sha256:b7e25965b0dc2d65a935b67d5f10d1192ad550ba90bae25d550bfdb5736b0d2d",
101
+ "size_bytes": 1523
92
102
  },
93
103
  {
94
104
  "path": "skills/feature-management/references/commands.md",
@@ -97,8 +107,8 @@
97
107
  },
98
108
  {
99
109
  "path": "skills/feature-management/references/contracts.md",
100
- "sha256": "sha256:ef582d4ee9ade16de2a5f97b8bf9546969b6f2859eb020986bf25952993df402",
101
- "size_bytes": 30483
110
+ "sha256": "sha256:a9f6c8d6c8b1220a26a282f3ff73db54c6359372df02c322159087507ca0318d",
111
+ "size_bytes": 30894
102
112
  },
103
113
  {
104
114
  "path": "skills/feature-management/references/operator-authoring.md",
@@ -142,8 +152,8 @@
142
152
  },
143
153
  {
144
154
  "path": "skills/model-lifecycle-management/SKILL.md",
145
- "sha256": "sha256:4ea40815d73b3a470b2572874dcad63640cbdd53d3c10293d7a5ce8621a13b96",
146
- "size_bytes": 4272
155
+ "sha256": "sha256:1f2174fac7f82e7539c781b1c7bc4164a8adc393acb33b3b2165408b25600135",
156
+ "size_bytes": 4888
147
157
  },
148
158
  {
149
159
  "path": "skills/model-lifecycle-management/agents/openai.yaml",
@@ -152,8 +162,8 @@
152
162
  },
153
163
  {
154
164
  "path": "skills/model-lifecycle-management/references/discovery.md",
155
- "sha256": "sha256:184472a79fb217dd8c74dffab20e75285b0c8f69207dc593ae3099b8a2b6d6d5",
156
- "size_bytes": 5381
165
+ "sha256": "sha256:ad4623e84b8d972357497a55df0aed84be5ada59ef197f6a217f19ce97821195",
166
+ "size_bytes": 5789
157
167
  },
158
168
  {
159
169
  "path": "skills/model-lifecycle-management/references/evaluation.md",
@@ -167,13 +177,18 @@
167
177
  },
168
178
  {
169
179
  "path": "skills/model-lifecycle-management/references/training-contracts.md",
170
- "sha256": "sha256:4cecf5f90464640d063ca721fded1c27b46bb79daa0f67c78a8fb6b0e3e60b3b",
171
- "size_bytes": 14747
180
+ "sha256": "sha256:26ca0f0b8bc212bd30ea69b0a0afc169554681a16317ebb054d9147ae9c0587a",
181
+ "size_bytes": 14994
172
182
  },
173
183
  {
174
184
  "path": "skills/model-lifecycle-management/references/training.md",
175
- "sha256": "sha256:97de7894da24a07b4146d6de5e00a0cf17166654fb219a145f35adff5e8a7f99",
176
- "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
177
192
  }
178
193
  ],
179
194
  "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-alpha.3",
3
+ "version": "0.2.2-alpha.5",
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:ceb3fdabf57044a5bf8d54baf04ab10327cb896e4eaff3897c18e08e96e5336a",
17
- "version": "0.8.2"
16
+ "sha256": "sha256:ff1b5f6de8111ac9dea00701afadbb6e47cc14937fa78b958ec8a3b777a4ecb9",
17
+ "version": "0.8.3"
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.2-alpha.3",
28
+ "release_version": "0.2.2-alpha.5",
29
29
  "runtime_requirements": {
30
30
  "node": ">=18",
31
31
  "os": [
@@ -35,24 +35,30 @@
35
35
  },
36
36
  "schema_version": "data_platform.ml_platform_release/v2",
37
37
  "skills": {
38
+ "data-source-exploration": {
39
+ "path": "skills/data-source-exploration",
40
+ "requires_cli": ">=0.8.3 <0.9.0",
41
+ "revision": "0.2.2-alpha.5",
42
+ "sha256": "sha256:ae3cfc88f8f3f46a5b7e0179d850b2216bc37275f34679dbea1ff2ba99875a96"
43
+ },
38
44
  "feature-management": {
39
45
  "path": "skills/feature-management",
40
- "requires_cli": ">=0.8.2 <0.9.0",
41
- "revision": "0.2.2-alpha.3",
42
- "sha256": "sha256:d32f0306f129d7bf76eb037fe239c84dd3c29c64b61600799d6e40320784bb10"
46
+ "requires_cli": ">=0.8.3 <0.9.0",
47
+ "revision": "0.2.2-alpha.5",
48
+ "sha256": "sha256:63e3bc337bc4cc4cdd38bfdd99ff9d8fd6c7d57d24aec1b7f70101ce38b1f599"
43
49
  },
44
50
  "model-deployment-management": {
45
51
  "path": "skills/model-deployment-management",
46
- "requires_cli": ">=0.8.2 <0.9.0",
47
- "revision": "0.2.2-alpha.3",
52
+ "requires_cli": ">=0.8.3 <0.9.0",
53
+ "revision": "0.2.2-alpha.5",
48
54
  "sha256": "sha256:e7d87c272a0dcc028ea628d5e36f5b7e52ed27cb9c1bc17ea76527478e28b46d"
49
55
  },
50
56
  "model-lifecycle-management": {
51
57
  "path": "skills/model-lifecycle-management",
52
- "requires_cli": ">=0.8.2 <0.9.0",
53
- "revision": "0.2.2-alpha.3",
54
- "sha256": "sha256:ec6ebb2587fd7acd024def75a8c0e9cd94b6cdd8ee6df439609291b496751b91"
58
+ "requires_cli": ">=0.8.3 <0.9.0",
59
+ "revision": "0.2.2-alpha.5",
60
+ "sha256": "sha256:13f94cb0928d15a83b8bb10195dc3a83c28c4bb7723bc8a35e262b6c1ba46b0d"
55
61
  }
56
62
  },
57
- "source_commit": "e713953153439c28680b60b56f57d3b9679ff49a"
63
+ "source_commit": "90c4934f435a97b21428bad189f85a9a0d5dc643"
58
64
  }
@@ -117,6 +117,21 @@ ml-platform predict-model /absolute/path/to/request.json \
117
117
  --serving-url https://storage-forecast.example
118
118
  ```
119
119
 
120
+ 同步零样本预测使用平台控制面提供的模型名称入口,不要求用户传入 `project`、合同版本或普通
121
+ 请求的 `release_id`:
122
+
123
+ ```bash
124
+ ml-platform list-foundation-models
125
+ ml-platform get-foundation-model chronos2_forecaster
126
+ ml-platform predict-foundation chronos2_forecaster /absolute/path/to/request.json
127
+ ml-platform predict-foundation-csv chronos2_forecaster /absolute/path/to/input.csv \
128
+ --schema /absolute/path/to/schema.json \
129
+ --forecast /absolute/path/to/forecast.json
130
+ ```
131
+
132
+ `--release-id` 仅用于精确回放。零样本请求是同步、有界的 JSON 或 multipart CSV,不创建预测任务
133
+ 或结果资源。
134
+
120
135
  训练历史必须使用各个历史 cutoff 当时可取得的天气预报,不得以事后实测天气替代。
121
136
 
122
137
  Parameter、Feature、FeatureSet 的删除命令执行软删除,并支持带 actor、reason 和幂等键的
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform-business-client",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
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.2",
9
+ "version": "0.8.3",
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.2",
3
+ "version": "0.8.3",
4
4
  "private": true,
5
5
  "description": "JavaScript implementation of the ML Platform business client",
6
6
  "bin": {
@@ -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");
@@ -13,7 +13,10 @@ const BUSINESS_COMMANDS = new Set([
13
13
  "get-model-runtime-release", "get-training-run", "get-model-artifact", "get-executable-package",
14
14
  "validate-training-job", "validate-model-package",
15
15
  "version", "create-project", "list-projects", "get-project", "delete-project",
16
- "configure", "show-config", "health", "list-parameters", "list-operators", "list-features",
16
+ "configure", "show-config", "health",
17
+ "list-datasource-connections", "list-datasource-namespaces", "list-datasource-objects",
18
+ "list-datasource-fields", "query-datasource-object",
19
+ "list-parameters", "list-operators", "list-features",
17
20
  "list-feature-sets", "list-datasets", "get-dataset", "list-jobs", "resolve-manifest",
18
21
  "resolve-dataset", "build-dataset", "build-registered-dataset",
19
22
  "get-parameter", "get-feature", "get-feature-set", "get-operator",
@@ -26,6 +29,7 @@ const BUSINESS_COMMANDS = new Set([
26
29
  "add-dataset", "update-dataset", "delete-dataset", "list-dataset-artifacts",
27
30
  "register-operator", "show-operator-specs", "delete-operator", "run-operator",
28
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",
29
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",
30
34
  "register-evaluation-config", "get-evaluation-config", "register-metric-definition", "get-metric-definition",
31
35
  "register-executable-package", "verify-executable-package", "publish-executable-package",
@@ -49,6 +53,11 @@ const COMMAND_USAGE = {
49
53
  configure: "configure --api-url URL",
50
54
  "show-config": "show-config",
51
55
  health: "health",
56
+ "list-datasource-connections": "list-datasource-connections [--limit N] [--cursor CURSOR]",
57
+ "list-datasource-namespaces": "list-datasource-namespaces CONNECTION_ID [--limit N] [--cursor CURSOR]",
58
+ "list-datasource-objects": "list-datasource-objects CONNECTION_ID NAMESPACE_ID [--limit N] [--cursor CURSOR]",
59
+ "list-datasource-fields": "list-datasource-fields CONNECTION_ID OBJECT_ID [--limit N] [--cursor CURSOR]",
60
+ "query-datasource-object": "query-datasource-object CONNECTION_ID OBJECT_ID SPEC_JSON [--cursor CURSOR]",
52
61
  "create-project": "create-project NAME [--display-name TEXT] [--description TEXT] [--owner OWNER]",
53
62
  "list-projects": "list-projects",
54
63
  "get-project": "get-project NAME",
@@ -106,6 +115,10 @@ const COMMAND_USAGE = {
106
115
  "fetch-inference-data": "fetch-inference-data MANIFEST --cutoff-time TIMESTAMP [--max-workers N] [--max-source-lag-hours HOURS] [--no-validate-freshness] [--allow-missing]",
107
116
  "fetch-inference-context": "fetch-inference-context REQUEST_JSON",
108
117
  "predict-model": "predict-model REQUEST_JSON --serving-url URL",
118
+ "list-foundation-models": "list-foundation-models",
119
+ "get-foundation-model": "get-foundation-model NAME",
120
+ "predict-foundation": "predict-foundation NAME REQUEST_JSON [--release-id ID]",
121
+ "predict-foundation-csv": "predict-foundation-csv NAME CSV_FILE --schema SCHEMA_JSON --forecast FORECAST_JSON [--release-id ID]",
109
122
  "list-system-models": "list-system-models",
110
123
  "get-system-model": "get-system-model NAME VERSION [--project PROJECT]",
111
124
  "register-training-run": "register-training-run RUN_JSON",
@@ -238,6 +251,13 @@ function readObject(file) {
238
251
  }
239
252
  function readDataset(file) { return normalizeDataset(readObject(file)); }
240
253
  function readSpec(file) { return readObject(file); }
254
+ function datasourcePageParams(rest) {
255
+ const rawLimit = take(rest, "--limit");
256
+ const limit = rawLimit === undefined ? 100 : integer(rawLimit, "--limit");
257
+ if (limit < 1 || limit > 500)
258
+ throw new Error("--limit must be between 1 and 500");
259
+ return { limit, cursor: take(rest, "--cursor") };
260
+ }
241
261
  function datasetEndpoint(project, datasetId, datasetVersion) {
242
262
  return `/datasets/${encodeURIComponent(project)}/${encodeURIComponent(datasetId)}/${encodeURIComponent(datasetVersion)}`;
243
263
  }
@@ -382,6 +402,32 @@ async function runBusinessCli(argv) {
382
402
  }
383
403
  else if (options.command === "health")
384
404
  result = await client(options).get("/health");
405
+ else if (options.command === "list-datasource-connections") {
406
+ result = await client(options).get("/datasource-connections", datasourcePageParams(rest));
407
+ }
408
+ else if (options.command === "list-datasource-namespaces") {
409
+ const connectionId = positional(rest, "connection id");
410
+ result = await client(options).get(`/datasource-connections/${encodeURIComponent(connectionId)}/namespaces`, datasourcePageParams(rest));
411
+ }
412
+ else if (options.command === "list-datasource-objects") {
413
+ const connectionId = positional(rest, "connection id");
414
+ const namespaceId = positional(rest, "namespace id");
415
+ result = await client(options).get(`/datasource-connections/${encodeURIComponent(connectionId)}/namespaces/${encodeURIComponent(namespaceId)}/objects`, datasourcePageParams(rest));
416
+ }
417
+ else if (options.command === "list-datasource-fields") {
418
+ const connectionId = positional(rest, "connection id");
419
+ const objectId = positional(rest, "object id");
420
+ result = await client(options).get(`/datasource-connections/${encodeURIComponent(connectionId)}/objects/${encodeURIComponent(objectId)}/fields`, datasourcePageParams(rest));
421
+ }
422
+ else if (options.command === "query-datasource-object") {
423
+ const connectionId = positional(rest, "connection id");
424
+ const objectId = positional(rest, "object id");
425
+ const spec = readSpec(positional(rest, "query spec JSON"));
426
+ const cursor = take(rest, "--cursor");
427
+ if (cursor !== undefined)
428
+ spec.cursor = cursor;
429
+ result = await client(options).post(`/datasource-connections/${encodeURIComponent(connectionId)}/objects/${encodeURIComponent(objectId)}/query`, spec);
430
+ }
385
431
  else if (options.command === "create-project") {
386
432
  const name = positional(rest, "project name");
387
433
  result = await client(options).post("/projects", { schema_version: "ml_data_platform.project/v1", name, display_name: take(rest, "--display-name", name), description: take(rest, "--description", ""), owner: take(rest, "--owner", "demo") });
@@ -679,6 +725,33 @@ async function runBusinessCli(argv) {
679
725
  throw new Error("--serving-url is required");
680
726
  result = await new PlatformApiClient(servingUrl, options.timeout).post("/v1/inference", request);
681
727
  }
728
+ else if (options.command === "list-foundation-models") {
729
+ result = await client(options).get("/foundation-models");
730
+ }
731
+ else if (options.command === "get-foundation-model") {
732
+ const name = positional(rest, "foundation model name");
733
+ result = await client(options).get(`/foundation-models/${encodeURIComponent(name)}`);
734
+ }
735
+ else if (options.command === "predict-foundation") {
736
+ const name = positional(rest, "foundation model name");
737
+ const request = readSpec(positional(rest, "request JSON"));
738
+ const releaseId = take(rest, "--release-id");
739
+ const headers = releaseId ? { "X-ITSMP-Foundation-Release": releaseId } : {};
740
+ result = await client(options).postWithHeaders(`/foundation-models/${encodeURIComponent(name)}/predict`, request, headers);
741
+ }
742
+ else if (options.command === "predict-foundation-csv") {
743
+ const name = positional(rest, "foundation model name");
744
+ const csvFile = positional(rest, "CSV file");
745
+ const schemaFile = take(rest, "--schema");
746
+ const forecastFile = take(rest, "--forecast");
747
+ if (!schemaFile)
748
+ throw new Error("--schema is required");
749
+ if (!forecastFile)
750
+ throw new Error("--forecast is required");
751
+ const releaseId = take(rest, "--release-id");
752
+ const headers = releaseId ? { "X-ITSMP-Foundation-Release": releaseId } : {};
753
+ result = await client(options).uploadFoundationCsv(`/foundation-models/${encodeURIComponent(name)}/predict-file`, readSpec(schemaFile), readSpec(forecastFile), csvFile, headers);
754
+ }
682
755
  else if (options.command === "list-deployment-targets") {
683
756
  result = await client(options).get("/deployment-targets");
684
757
  }
@@ -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,32 @@ 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 }); }
63
65
  delete(endpoint, params) { return this.request("DELETE", endpoint, { params }); }
66
+ uploadFoundationCsv(endpoint, schema, forecast, filePath, requestHeaders = {}) {
67
+ const resolved = path.resolve(expandHome(filePath));
68
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile())
69
+ throw new Error(`CSV file not found: ${resolved}`);
70
+ const boundary = `itsmp-${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
71
+ const parts = [];
72
+ const field = (name, value, contentType) => {
73
+ parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="${name}"\r\nContent-Type: ${contentType}\r\n\r\n`));
74
+ parts.push(Buffer.from(value));
75
+ parts.push(Buffer.from("\r\n"));
76
+ };
77
+ field("schema", JSON.stringify(schema), "application/json");
78
+ field("forecast", JSON.stringify(forecast), "application/json");
79
+ const filename = path.basename(resolved).replace(/["\r\n]/g, "_");
80
+ parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${filename}"\r\nContent-Type: text/csv\r\n\r\n`));
81
+ parts.push(fs.readFileSync(resolved));
82
+ parts.push(Buffer.from(`\r\n--${boundary}--\r\n`));
83
+ return this.request("POST", endpoint, {
84
+ body: Buffer.concat(parts),
85
+ contentType: `multipart/form-data; boundary=${boundary}`,
86
+ requestHeaders,
87
+ });
88
+ }
64
89
  uploadOperatorPackage(project, name, version, packagePath) {
65
90
  const resolved = path.resolve(expandHome(packagePath));
66
91
  if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile())
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: data-source-exploration
3
+ description: Discover platform-configured PostgreSQL, MySQL, SQL Server, or InfluxDB objects and run bounded structured reads for local data and feature exploration. Use when an algorithm engineer wants to inspect visible databases, schemas, tables, measurements, fields, or limited rows before defining governed feature assets. Do not use for free-form SQL, bulk export, asset publication, dataset builds, or model training.
4
+ ---
5
+
6
+ # Data Source Exploration
7
+
8
+ Use the platform API through `ml-platform`; never connect to a business database directly and
9
+ never request credentials. The platform exposes configured connections and their discoverable objects.
10
+
11
+ ## Establish The Target
12
+
13
+ Before discovery, verify the installed client and server target:
14
+
15
+ ```bash
16
+ command -v ml-platform
17
+ ml-platform health
18
+ ```
19
+
20
+ If the server target is missing or unhealthy, stop. Do not fall back to a DSN, database client, SQL,
21
+ Flux, or a repository-local source adapter.
22
+
23
+ ## Discover Hierarchically
24
+
25
+ Read one level at a time and preserve the returned opaque IDs:
26
+
27
+ ```bash
28
+ ml-platform list-datasource-connections
29
+ ml-platform list-datasource-namespaces <connection_id>
30
+ ml-platform list-datasource-objects <connection_id> <namespace_id>
31
+ ml-platform list-datasource-fields <connection_id> <object_id>
32
+ ```
33
+
34
+ Follow `next_cursor` with `--cursor` until it is null when complete traversal is needed. Do not derive an
35
+ ID from a database, schema, table, measurement, or field name. An absent object means it is unavailable
36
+ or no longer present; do not probe alternate names.
37
+
38
+ ## Query One Object
39
+
40
+ Create a `DatasourceQuerySpec` JSON in the user's workspace. Select only fields needed for the current
41
+ question, use bounded time filters for time-series data, and start with a small `limit`:
42
+
43
+ ```json
44
+ {
45
+ "schema_version": "ml_data_platform.datasource_query/v1",
46
+ "field_ids": ["fld_time", "fld_entity", "fld_value"],
47
+ "filters": [
48
+ {
49
+ "field_id": "fld_time",
50
+ "operator": "between",
51
+ "values": ["2026-09-01T00:00:00+08:00", "2026-09-02T00:00:00+08:00"]
52
+ }
53
+ ],
54
+ "order_by": [{"field_id": "fld_time", "direction": "asc"}],
55
+ "limit": 200,
56
+ "cursor": null
57
+ }
58
+ ```
59
+
60
+ Run it with:
61
+
62
+ ```bash
63
+ ml-platform query-datasource-object \
64
+ <connection_id> <object_id> datasource-query.json
65
+ ```
66
+
67
+ Supported filters are `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `between`, and `is_null`. Only fields marked
68
+ filterable or sortable may be used in those positions. InfluxDB reads require bounded `_time` start and
69
+ end filters. For the next page, keep projection, filters, ordering, and `limit` unchanged and pass the
70
+ returned cursor with `--cursor`.
71
+
72
+ ## Explore In The Workspace
73
+
74
+ Analyze returned rows with local code such as pandas or DuckDB. Keep these outputs outside the platform
75
+ repository unless the user explicitly asks for a repository-owned fixture. Record:
76
+
77
+ - the connection, namespace, object, field IDs, query spec, `audit_ref`, and response hash;
78
+ - observed facts such as dtypes, missingness, frequency, ranges, duplicates, and candidate entity/time keys;
79
+ - hypotheses about business meaning, target suitability, leakage, transformations, and model features;
80
+ - unresolved items that require a data owner or business owner to confirm.
81
+
82
+ Do not present inferred semantics as facts. Query results are exploratory evidence, not training data and
83
+ not a substitute for Parameter, Feature, FeatureSet, DatasetManifest, or DatasetArtifact.
84
+
85
+ ## Hand Off Confirmed Work
86
+
87
+ After a human confirms source mapping, event time, entity keys, units, availability, quality rules, target,
88
+ horizon, and feature formulas, use `$feature-management` to create governed assets and build a
89
+ DatasetArtifact. Use `$model-lifecycle-management` only after that artifact exists. Exploration does not
90
+ authorize publishing assets, building datasets, or submitting training jobs.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "数据源与特征探索"
3
+ short_description: "逐层发现已连接数据源并执行受限数据查询"
4
+ default_prompt: "使用 $data-source-exploration 从平台已连接数据源中发现可见库表字段,执行有限查询,并整理数据与特征假设。"
@@ -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`
@@ -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",
@@ -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,6 +44,11 @@ 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,
@@ -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.