@zhuoyuezs/ml-platform 0.2.2 → 0.2.3-alpha

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/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:c263ebe1591d38d90fb68227f42c6de43014a05e98b736d2e3363e19545676d9",
6
+ "size_bytes": 8779
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:739be8665f611802d9196ba84566578fbfc6544c6907af165edbaf115d9d1998",
26
+ "size_bytes": 62651
27
27
  },
28
28
  {
29
29
  "path": "runtime/business-client/src/config.js",
@@ -32,8 +32,8 @@
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
37
  },
38
38
  {
39
39
  "path": "skills/data-source-exploration/SKILL.md",
@@ -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:309d2ae292113f99bd17b6865b87bbe793809c88005458f477fa1e80c41b1523",
51
+ "size_bytes": 33334
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",
@@ -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:1f2174fac7f82e7539c781b1c7bc4164a8adc393acb33b3b2165408b25600135",
156
+ "size_bytes": 4888
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,18 @@
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
187
192
  }
188
193
  ],
189
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",
3
+ "version": "0.2.3-alpha",
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:ff1b5f6de8111ac9dea00701afadbb6e47cc14937fa78b958ec8a3b777a4ecb9",
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",
29
29
  "runtime_requirements": {
30
30
  "node": ">=18",
31
31
  "os": [
@@ -38,27 +38,27 @@
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",
41
+ "revision": "0.2.3-alpha",
42
42
  "sha256": "sha256:ae3cfc88f8f3f46a5b7e0179d850b2216bc37275f34679dbea1ff2ba99875a96"
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",
48
+ "sha256": "sha256:63e3bc337bc4cc4cdd38bfdd99ff9d8fd6c7d57d24aec1b7f70101ce38b1f599"
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",
53
+ "revision": "0.2.3-alpha",
54
54
  "sha256": "sha256:e7d87c272a0dcc028ea628d5e36f5b7e52ed27cb9c1bc17ea76527478e28b46d"
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",
60
+ "sha256": "sha256:13f94cb0928d15a83b8bb10195dc3a83c28c4bb7723bc8a35e262b6c1ba46b0d"
61
61
  }
62
62
  },
63
- "source_commit": "03bf8af26abcf13a95dc41d2637598a8f0233552"
63
+ "source_commit": "42714d93a4fdcc29fce8d98bc8e17823535cb56f"
64
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 和幂等键的
@@ -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",
@@ -114,6 +115,10 @@ const COMMAND_USAGE = {
114
115
  "fetch-inference-data": "fetch-inference-data MANIFEST --cutoff-time TIMESTAMP [--max-workers N] [--max-source-lag-hours HOURS] [--no-validate-freshness] [--allow-missing]",
115
116
  "fetch-inference-context": "fetch-inference-context REQUEST_JSON",
116
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]",
117
122
  "list-system-models": "list-system-models",
118
123
  "get-system-model": "get-system-model NAME VERSION [--project PROJECT]",
119
124
  "register-training-run": "register-training-run RUN_JSON",
@@ -720,6 +725,33 @@ async function runBusinessCli(argv) {
720
725
  throw new Error("--serving-url is required");
721
726
  result = await new PlatformApiClient(servingUrl, options.timeout).post("/v1/inference", request);
722
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
+ }
723
755
  else if (options.command === "list-deployment-targets") {
724
756
  result = await client(options).get("/deployment-targets");
725
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())
@@ -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.