@sema-agent/settings-schema 15.2.0 → 17.0.0
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/CHANGELOG.md +183 -0
- package/README.md +71 -46
- package/conformance/VERSION +1 -1
- package/conformance/cases/c16-deep-nesting-205/expected.json +2 -2
- package/conformance/cases/c16-deep-nesting-205/meta.json +1 -1
- package/conformance/cases/c50-s784-lane-host-legal/expected.json +6 -2
- package/conformance/cases/c50-s784-lane-host-legal/input.json +3 -1
- package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +6 -2
- package/conformance/cases/c51-s784-lane-e2b-legal/input.json +3 -1
- package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +6 -2
- package/conformance/cases/c52-s784-lane-k8s-legal/input.json +3 -1
- package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +6 -2
- package/conformance/cases/c53-s784-lane-ssh-legal/input.json +3 -1
- package/conformance/cases/c54-s784-lane-adb-legal/expected.json +6 -2
- package/conformance/cases/c54-s784-lane-adb-legal/input.json +3 -1
- package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +6 -2
- package/conformance/cases/c55-s784-lane-local-docker-legal/input.json +3 -1
- package/conformance/cases/c56-s784-lane-device-legal/expected.json +8 -2
- package/conformance/cases/c56-s784-lane-device-legal/input.json +5 -2
- package/conformance/cases/c57-s784-g1-enabled-no-lane/meta.json +1 -1
- package/conformance/cases/c58-s784-g2-multitenant-host/input.json +3 -1
- package/conformance/cases/c59-s784-g3-k8s-missing-image/input.json +3 -1
- package/conformance/cases/c60-s784-g3-e2b-missing-key/input.json +3 -1
- package/conformance/cases/c61-s784-g3-other-lane-key/input.json +3 -1
- package/conformance/cases/c62-s784-g7a-session-tidb/input.json +3 -1
- package/conformance/cases/c63-s784-host-two-replicas/input.json +3 -1
- package/conformance/cases/c64-s784-multitenant-local-store/input.json +3 -1
- package/conformance/cases/c65-s784-pg-without-db/input.json +3 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/input.json +3 -1
- package/conformance/cases/c66-s784-memory-backend-mismatch/meta.json +1 -1
- package/conformance/cases/c68-s784-device-local-store/input.json +6 -1
- package/conformance/cases/cli04-env-value-with-newline/expected.json +6 -2
- package/conformance/cases/cli04-env-value-with-newline/input.json +3 -1
- package/dist/atomic-write.d.ts +4 -0
- package/dist/atomic-write.js +20 -0
- package/dist/bundle.d.ts +0 -18
- package/dist/bundle.js +1 -54
- package/dist/cli.d.ts +1 -1
- package/dist/config-d-file.d.ts +13 -12
- package/dist/config-d-file.js +72 -27
- package/dist/config-document-refusal.d.ts +9 -7
- package/dist/config-document-refusal.js +2 -2
- package/dist/device-relay.d.ts +21 -0
- package/dist/device-relay.js +23 -0
- package/dist/env-model-table.d.ts +2 -9
- package/dist/env-model-table.js +6 -14
- package/dist/execution-lane-index.d.ts +19 -7
- package/dist/execution-lane-index.js +26 -8
- package/dist/execution-lanes.d.ts +9 -4
- package/dist/execution-lanes.js +18 -6
- package/dist/file-store.d.ts +31 -4
- package/dist/file-store.js +78 -11
- package/dist/fleet.d.ts +6 -8
- package/dist/fleet.js +5 -7
- package/dist/hooks.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/local-load.d.ts +12 -4
- package/dist/local-load.js +20 -31
- package/dist/migration-receipt.d.ts +1 -1
- package/dist/migration-receipt.js +1 -1
- package/dist/one-time-migrations.d.ts +1 -1
- package/dist/one-time-migrations.js +166 -45
- package/dist/remote-exec.js +11 -4
- package/dist/types.d.ts +15 -11
- package/dist/types.js +99 -48
- package/dist/url-shape.d.ts +18 -0
- package/dist/url-shape.js +22 -0
- package/docs/API-SURFACE.md +12 -8
- package/docs/CONFORMANCE.md +1 -7
- package/docs/CONSUMER-INTEGRATION.md +3 -3
- package/llms-full.txt +25 -29
- package/llms.txt +9 -8
- package/package.json +1 -1
package/dist/types.js
CHANGED
|
@@ -30,12 +30,13 @@ import { PREVIOUS_WEB_ADMIN_ENV } from "./previous-web-admin-env.js"; // the pre
|
|
|
30
30
|
import { retiredEnvRefusal } from "./retired-envs.js"; // the worker env write gate asks the retired-env tombstone table too (one table, one refusal sentence)
|
|
31
31
|
import { Sha256Digest } from "./sha256.js"; // the one `sha256:<hex>` digest form
|
|
32
32
|
import { EXECUTION_LANES, EXECUTION_LANE_WORDS, MEMORY_ENGINE_BACKENDS, SESSION_BACKENDS, STORE_BACKENDS, isBlankCoordinate, retiredLaneWordRefusal } from "./execution-lanes.js"; // 7.0.0 M-R2: the lane / store vocabulary (one exported table)
|
|
33
|
-
import { LANE_ENV_OWNER,
|
|
33
|
+
import { LANE_ENV_OWNER, envKeyMigration, laneEnvSeat, laneRowOf } from "./execution-lane-index.js"; // package-private indexes derived from that table (none of them is in the barrel)
|
|
34
34
|
import { migrationSignpost, retiredFormSentence, retiredKey } from "./retired-form.js"; // 11.0.0: the ONE retired-form sentence + key tombstone (package-private)
|
|
35
35
|
import { retiredRoleWordsRefusal } from "./retired-role-words.js"; // 12.0.0: the retired role-word tombstone (package-private; SS-M8)
|
|
36
36
|
import { buildQuotedIssue, fixed } from "./quoted-issue.js"; // THE minting point of custom issues (package-private)
|
|
37
37
|
import { AbsoluteHostPath } from "./host-path.js"; // the one host-path shape judge (a task's cwd and a project's folder / file entries)
|
|
38
38
|
import { RFC3339_DATE_TIME } from "./rfc3339.js"; // the package's one RFC 3339 date-time judge (package-private)
|
|
39
|
+
import { DEVICE_RELAY_RULE, deviceRelayFlaws } from "./device-relay.js"; // 16.0.0: the value grammar of the device lane's DEVICE_RELAY_URL (ws(s) URL or the literal none)
|
|
39
40
|
// COARSE, best-effort literal-secret SHAPE detector (NOT exhaustive — the real boundary is the env-NAME schema
|
|
40
41
|
// on structured fields). Rejected in free-form value fields (worker `env`, model `extraBody`), URL components,
|
|
41
42
|
// AND as an env-NAME value (an AWS key id is a valid env-NAME charset yet is a secret VALUE, not a NAME). Case-
|
|
@@ -1842,7 +1843,7 @@ const RESERVED_ENV_FIELD = Object.freeze({
|
|
|
1842
1843
|
PG_HOST: "runtime.store.db.host", PG_PORT: "runtime.store.db.port", PG_USER: "runtime.store.db.user",
|
|
1843
1844
|
PG_DATABASE: "runtime.store.db.database", PG_PASSWORD: "secretRefs.dbPasswordEnv",
|
|
1844
1845
|
// ── runtime.execution(7.0.0):车道词两键 + 车道表里每个名(派生,不手抄)
|
|
1845
|
-
REMOTE_EXEC: "runtime.execution.
|
|
1846
|
+
REMOTE_EXEC: "runtime.execution.lanes",
|
|
1846
1847
|
// ── fleet 成员身份两键:渲染器按该 worker 的代际写 generation(引擎读回并回声成 EngineSignal.generation)、按该 worker 令牌绑定的 scope 写 scope(引擎读作自身身份的 scope)—— 没有 WorkerSpec 字段能写它们
|
|
1847
1848
|
[FLEET_GENERATION_ENV]: "(set by the config renderer from the worker's generation — not configurable)",
|
|
1848
1849
|
[FLEET_SCOPE_ENV]: "(set by the config renderer from the worker's scope — not configurable)",
|
|
@@ -1856,7 +1857,7 @@ const RESERVED_ENV_FIELD = Object.freeze({
|
|
|
1856
1857
|
[WEB_ADMIN_ENV.tokenFile]: WEB_ADMIN_OPERATOR_FILE_SEAT, [PREVIOUS_WEB_ADMIN_ENV.tokenFile]: WEB_ADMIN_OPERATOR_FILE_SEAT,
|
|
1857
1858
|
[WEB_ADMIN_ENV.assertionToken]: WEB_ADMIN_ASSERTION_SEAT.token,
|
|
1858
1859
|
[WEB_ADMIN_ENV.assertionTokenFile]: WEB_ADMIN_OPERATOR_FILE_SEAT,
|
|
1859
|
-
REQUIRE_EXECUTION_LANE: "runtime.execution.
|
|
1860
|
+
REQUIRE_EXECUTION_LANE: "runtime.execution.lanes (the renderer emits REQUIRE_EXECUTION_LANE=true for every declared lane set)",
|
|
1860
1861
|
...Object.fromEntries([...LANE_ENV_OWNER].map(([name, owner]) => [name, laneEnvSeat(name, owner)])),
|
|
1861
1862
|
});
|
|
1862
1863
|
/** 结构化 WorkerSpec 字段已经产出的 env 名 —— 通用 `env` / `secretEnv` 逃生口**不许**设它们(用专属字段)。由
|
|
@@ -1864,11 +1865,13 @@ const RESERVED_ENV_FIELD = Object.freeze({
|
|
|
1864
1865
|
export const RESERVED_WORKER_ENV = new Set(Object.keys(RESERVED_ENV_FIELD));
|
|
1865
1866
|
/**
|
|
1866
1867
|
* 保留名被 `env` / `secretEnv` 逃生口设置时的拒因:点名键 + 它的唯一写位。句尾恒是「set it via <字段>」(下游按它抽归属字段,不动)。
|
|
1867
|
-
* **迁移指路只有一条规则(7.0.1)**:这个键「旧形 ⇒ 迁移能搬」(
|
|
1868
|
-
*
|
|
1868
|
+
* **迁移指路只有一条规则(7.0.1;16.0.0 起点名哪一条)**:这个键「旧形 ⇒ 迁移能搬」(`envKeyMigration`,与迁移自己识别的键集同一只函数)就在键名后
|
|
1869
|
+
* 带搬它那一条迁移的指路句(`migrationSignpost`:6.x 行的键 ⇒ SS-M4;7.0.0 之后才进车道表的键 ⇒ 登记它那一版的迁移);搬不了的保留名(`PORT` / `MODEL_*` / `MYSQL_*` …)
|
|
1870
|
+
* 不带 —— 指一条跑了也没用的迁移比不指更糟。
|
|
1869
1871
|
*/
|
|
1870
1872
|
function reservedKeyIssue(slot, key) {
|
|
1871
|
-
const
|
|
1873
|
+
const migration = envKeyMigration(key);
|
|
1874
|
+
const signpost = migration !== undefined ? " (" + migrationSignpost(migration.migration, migration.before) + ")" : "";
|
|
1872
1875
|
return buildQuotedIssue `${fixed(slot)} cannot set reserved key "${key}"${fixed(signpost)} — set it via ${fixed(RESERVED_ENV_FIELD[key])}`;
|
|
1873
1876
|
}
|
|
1874
1877
|
/** 逃生口里有墓碑表的旧名 ⇒ 一条 issue,句子是墓碑句本身(`retiredEnvRefusal` —— 唯一铸点,本包不另拼;句里只有表里的名,不回显值)。 */
|
|
@@ -1887,63 +1890,101 @@ const nonSecretLiteral = (minLength) => z
|
|
|
1887
1890
|
.max(2048)
|
|
1888
1891
|
.refine((s) => !containsSecretToken(s), buildQuotedIssue `looks like a literal secret — a credential goes in a secretRefs field as an env-NAME, never a value here`);
|
|
1889
1892
|
/**
|
|
1890
|
-
*
|
|
1891
|
-
*
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1893
|
+
* 有文法的车道坐标 → 它的值判官(16.0.0;今天一行)。判的是**在场、非空白**的值(缺席 / 空白归必需栏那两句,所有车道同一只);判官交拒因词,规则句随行。
|
|
1894
|
+
* 键都在车道表的非密坐标栏里(`test/device-relay-16.0.0.test.ts` 钉 device 那一行)。
|
|
1895
|
+
*/
|
|
1896
|
+
const COORDINATE_VALUE_GRAMMAR = new Map([
|
|
1897
|
+
["DEVICE_RELAY_URL", { flaws: deviceRelayFlaws, rule: DEVICE_RELAY_RULE }],
|
|
1898
|
+
]);
|
|
1899
|
+
/** 车道集缺席时的那一句(块在而缺 `lanes`,与 enabled 的 worker 根本没有车道块,同一句)。 */
|
|
1900
|
+
const LANES_REQUIRED = `runtime.execution.lanes must be a non-empty list — the worker's ordered execution lane set (the first one is the default) of ${EXECUTION_LANE_WORDS.join(" | ")}, each at most once. There is no "no hands" lane — disable the worker instead`;
|
|
1901
|
+
/**
|
|
1902
|
+
* `runtime.execution` —— 这台 worker 的执行车道集(16.0.0;渲染:车道表 `lanes` + `REQUIRE_EXECUTION_LANE=true` + coords / secretRefs 逐键)。
|
|
1903
|
+
* - `lanes`:**有序、去重、非空**的车道表({@link EXECUTION_LANE_WORDS} 的词),首项 = 缺省。没有「无手」词。
|
|
1904
|
+
* - `coords`:声明的车道的**非密坐标**(服务变量名 → 字面值),每个键归表里的某一条车道(车道表 `requiredEnv ∪ optionalEnv`);每条声明的车道的必需键都在场且不是空白
|
|
1905
|
+
* (空串或只含空白按缺 —— 唯一判官 `isBlankCoordinate`);有文法的键({@link COORDINATE_VALUE_GRAMMAR})值还要合它的文法。可选键的空串照收(例:`K8S_RUNTIME_CLASS=""` 在引擎里是「不用 Kata」)。
|
|
1906
|
+
* - `secretRefs`:声明的车道的**密钥**(服务变量名 → 宿主 env-NAME),每个键归表里的某一条车道,每条声明的车道的必需键在场。
|
|
1907
|
+
* 归表外车道的键 ⇒ 拒并点名它属于哪条车道;密钥写进 coords / 坐标写进 secretRefs ⇒ 拒并指路另一栏。
|
|
1908
|
+
* `lane`(15.x 的单值)是墓碑:读写两面拒,指路一次性迁移 SS-M12(`lane: L` ⇒ `lanes: [L]`)。
|
|
1896
1909
|
*/
|
|
1897
1910
|
const ExecutionBlock = z
|
|
1898
1911
|
.object({
|
|
1899
|
-
lane:
|
|
1912
|
+
lane: retiredKey("runtime.execution.lane", { retiredIn: "16.0.0", now: "runtime.execution.lanes (an ordered lane set; the first one is the default)", migration: "SS-M12" }),
|
|
1913
|
+
lanes: z
|
|
1914
|
+
.array(z.enum(EXECUTION_LANE_WORDS, { error: (iss) => retiredLaneWordRefusal(iss.input) }), { error: (iss) => (iss.input === undefined ? LANES_REQUIRED : undefined) }) // a retired lane word gets its way out
|
|
1915
|
+
.min(1, { error: LANES_REQUIRED }),
|
|
1900
1916
|
coords: z.record(ENV_NAME, nonSecretLiteral(0)).prefault({}),
|
|
1901
1917
|
secretRefs: z.record(ENV_NAME, ENV_NAME).prefault({}),
|
|
1902
1918
|
})
|
|
1903
1919
|
.superRefine((x, ctx) => {
|
|
1904
|
-
|
|
1920
|
+
// 去重:每条车道至多一次,重复的那一格(第二次出现)一条
|
|
1921
|
+
const declared = [];
|
|
1922
|
+
x.lanes.forEach((lane, i) => {
|
|
1923
|
+
if (declared.includes(lane))
|
|
1924
|
+
ctx.addIssue({ code: "custom", path: ["lanes", i], ...buildQuotedIssue `lane "${lane}" is declared twice in runtime.execution.lanes — each lane appears once (the first one is the default)` });
|
|
1925
|
+
else
|
|
1926
|
+
declared.push(lane);
|
|
1927
|
+
});
|
|
1928
|
+
const rows = declared.map(laneRowOf);
|
|
1905
1929
|
const issue = (slot, key, q) => ctx.addIssue({ code: "custom", path: [slot, key], ...q });
|
|
1906
|
-
const owned = (secret) => (secret ? [...row.requiredSecretEnv, ...row.optionalSecretEnv] : [...row.requiredEnv, ...row.optionalEnv]);
|
|
1930
|
+
const owned = (secret) => rows.flatMap((row) => (secret ? [...row.requiredSecretEnv, ...row.optionalSecretEnv] : [...row.requiredEnv, ...row.optionalEnv]));
|
|
1907
1931
|
const judgeKey = (slot, key) => {
|
|
1908
1932
|
const wantSecret = slot === "secretRefs";
|
|
1909
1933
|
const owner = LANE_ENV_OWNER.get(key);
|
|
1910
1934
|
if (owner === undefined) {
|
|
1911
1935
|
const allowed = owned(wantSecret);
|
|
1912
|
-
issue(slot, key, buildQuotedIssue `${key} is not ${fixed(wantSecret ? "a secret" : "a coordinate")} of any execution lane —
|
|
1936
|
+
issue(slot, key, buildQuotedIssue `${key} is not ${fixed(wantSecret ? "a secret" : "a coordinate")} of any execution lane — the declared lanes take ${fixed(slot)} ${fixed(allowed.length > 0 ? allowed.join(", ") : "(none)")}`);
|
|
1913
1937
|
return false;
|
|
1914
1938
|
}
|
|
1915
|
-
if (owner.lane
|
|
1916
|
-
issue(slot, key, buildQuotedIssue `${key} belongs to lane "${fixed(owner.lane)}", not
|
|
1939
|
+
if (!declared.includes(owner.lane)) {
|
|
1940
|
+
issue(slot, key, buildQuotedIssue `${key} belongs to lane "${fixed(owner.lane)}", which is not in runtime.execution.lanes — remove it, or add "${fixed(owner.lane)}" to runtime.execution.lanes`);
|
|
1917
1941
|
return false;
|
|
1918
1942
|
}
|
|
1919
1943
|
if (owner.secret !== wantSecret) {
|
|
1920
1944
|
issue(slot, key, owner.secret
|
|
1921
|
-
? buildQuotedIssue `${key} is a secret of lane "${
|
|
1922
|
-
: buildQuotedIssue `${key} is a non-secret coordinate of lane "${
|
|
1945
|
+
? buildQuotedIssue `${key} is a secret of lane "${fixed(owner.lane)}" — put it in runtime.execution.secretRefs as an env-NAME (never a value in coords)`
|
|
1946
|
+
: buildQuotedIssue `${key} is a non-secret coordinate of lane "${fixed(owner.lane)}" — write its value in runtime.execution.coords`);
|
|
1923
1947
|
return false;
|
|
1924
1948
|
}
|
|
1925
1949
|
return true;
|
|
1926
1950
|
};
|
|
1927
1951
|
for (const [key, value] of Object.entries(x.coords)) {
|
|
1928
|
-
if (judgeKey("coords", key)
|
|
1929
|
-
|
|
1952
|
+
if (!judgeKey("coords", key))
|
|
1953
|
+
continue;
|
|
1954
|
+
const owner = LANE_ENV_OWNER.get(key);
|
|
1955
|
+
if (isBlankCoordinate(value)) {
|
|
1956
|
+
if (owner?.required === true)
|
|
1957
|
+
issue("coords", key, buildQuotedIssue `required coordinate ${key} of lane "${fixed(owner.lane)}" is empty or whitespace-only — it counts as absent, and the engine refuses to start without it`);
|
|
1958
|
+
continue;
|
|
1930
1959
|
}
|
|
1960
|
+
const grammar = COORDINATE_VALUE_GRAMMAR.get(key);
|
|
1961
|
+
const flaws = grammar?.flaws(value) ?? [];
|
|
1962
|
+
if (grammar !== undefined && flaws.length > 0)
|
|
1963
|
+
issue("coords", key, buildQuotedIssue `coords.${key} ${fixed(grammar.rule)} — found: ${fixed(flaws.join(", "))}`);
|
|
1931
1964
|
}
|
|
1932
1965
|
for (const key of Object.keys(x.secretRefs))
|
|
1933
1966
|
judgeKey("secretRefs", key);
|
|
1934
|
-
for (const
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1967
|
+
for (const row of rows) {
|
|
1968
|
+
for (const key of row.requiredEnv)
|
|
1969
|
+
if (!Object.hasOwn(x.coords, key))
|
|
1970
|
+
issue("coords", key, buildQuotedIssue `lane "${fixed(row.lane)}" requires coords.${key} (the engine refuses to start without it)`);
|
|
1971
|
+
for (const key of row.requiredSecretEnv)
|
|
1972
|
+
if (!Object.hasOwn(x.secretRefs, key))
|
|
1973
|
+
issue("secretRefs", key, buildQuotedIssue `lane "${fixed(row.lane)}" requires secretRefs.${key} — the host env-NAME holding it`);
|
|
1974
|
+
}
|
|
1940
1975
|
});
|
|
1941
1976
|
/** `MEMORY_ENGINE` 的两个词(引擎目录行的 `enumValues`;引擎还认 true/false/1/0… 两族同义词,结构位只收规范词)。 */
|
|
1942
1977
|
const MEMORY_ENGINE_SWITCH = ["on", "off"];
|
|
1943
1978
|
/** 店词 → 是不是 SQL 店。SQL 坐标(`runtime.store.db` + `secretRefs.dbPasswordEnv`)在场 ⇔ 是。穷举表:店词加词 ⇒ 编译红。 */
|
|
1944
1979
|
const STORE_IS_SQL = { mysql: true, pg: true, local: false, memory: false };
|
|
1945
|
-
/** 记忆持久面方言 → 它要求的店(`file` 不要求)。穷举表:方言加词 ⇒ 编译红。 */
|
|
1946
|
-
const MEMORY_BACKEND_NEEDS_STORE = { file: undefined, pg: "pg",
|
|
1980
|
+
/** 记忆持久面方言 → 它要求的店(`file` 不要求)。穷举表:方言加词 ⇒ 编译红。16.0.0 起 MySQL 族方言与店同字(`mysql`)。 */
|
|
1981
|
+
const MEMORY_BACKEND_NEEDS_STORE = { file: undefined, pg: "pg", mysql: "mysql" };
|
|
1982
|
+
/** 15.x 的记忆方言字 `tidb` 的拒句(16.0.0 换成 `mysql`,零别名;读写两面拒,指路一次性迁移 SS-M12)。 */
|
|
1983
|
+
const RETIRED_MEMORY_BACKEND_TIDB = retiredFormSentence(`runtime.store.memory.backend "tidb"`, {
|
|
1984
|
+
retiredIn: "16.0.0",
|
|
1985
|
+
now: `"mysql" (the same MySQL-family store; one word with store.backend)`,
|
|
1986
|
+
migration: "SS-M12",
|
|
1987
|
+
});
|
|
1947
1988
|
/**
|
|
1948
1989
|
* `runtime.store` —— 这台 worker 的持久化(取代 6.x 散落的 `sessionBackend` / `memoryBackend` / `db` / `coords.tidb*` /
|
|
1949
1990
|
* `secretRefs.tidbPasswordEnv`)。渲染(唯一写者):`DB_BACKEND` / `SESSION_BACKEND` / `MEMORY_ENGINE` / `MEMORY_ENGINE_BACKEND` 恒渲;
|
|
@@ -1956,7 +1997,7 @@ const StoreBlock = z.object({
|
|
|
1956
1997
|
memory: z
|
|
1957
1998
|
.object({
|
|
1958
1999
|
engine: z.enum(MEMORY_ENGINE_SWITCH).default("on"),
|
|
1959
|
-
backend: z.enum(MEMORY_ENGINE_BACKENDS).default("file"),
|
|
2000
|
+
backend: z.enum(MEMORY_ENGINE_BACKENDS, { error: (iss) => (iss.input === "tidb" ? RETIRED_MEMORY_BACKEND_TIDB : undefined) }).default("file"),
|
|
1960
2001
|
})
|
|
1961
2002
|
.prefault({}),
|
|
1962
2003
|
/** SQL 服务器坐标(中立,一份;名族由 `backend` 决定)。 */
|
|
@@ -2133,29 +2174,35 @@ const WorkerSpecObject = z.object({
|
|
|
2133
2174
|
signature: z.string().optional(),
|
|
2134
2175
|
notes: z.string().optional(),
|
|
2135
2176
|
});
|
|
2136
|
-
/** 跨字段判据(G1 / G2 /
|
|
2177
|
+
/** 跨字段判据(G1 / G2 逐车道 / 单副本车道∧多副本 / store 四条)。每条一个 issue,`path` 指到要改的字段。 */
|
|
2137
2178
|
function workerSpecIssues(w, ctx) {
|
|
2138
2179
|
const issue = (path, q) => ctx.addIssue({ code: "custom", path, ...q });
|
|
2139
2180
|
const { execution, store, requirePrincipal } = w.runtime;
|
|
2140
|
-
// G1:enabled 的 worker
|
|
2181
|
+
// G1:enabled 的 worker 必须声明车道集与店(停用的不渲染,可缺)。
|
|
2141
2182
|
if (w.enabled && execution === undefined) {
|
|
2142
|
-
issue(["runtime", "execution", "
|
|
2183
|
+
issue(["runtime", "execution", "lanes"], buildQuotedIssue `an enabled worker must declare its execution lanes (without them it would boot with no hands and still report tasks completed) — ${fixed(LANES_REQUIRED)}`);
|
|
2143
2184
|
}
|
|
2144
2185
|
if (w.enabled && store === undefined) {
|
|
2145
2186
|
issue(["runtime", "store", "backend"], buildQuotedIssue `an enabled worker must declare its store — runtime.store.backend: ${fixed(STORE_BACKENDS.join(" | "))}`);
|
|
2146
2187
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2188
|
+
// 每条车道只判第一次出现的那一格(重复那一格已由车道块拒)。
|
|
2189
|
+
const declared = execution === undefined ? [] : execution.lanes.flatMap((lane, i) => (execution.lanes.indexOf(lane) === i ? [{ lane, i, row: laneRowOf(lane) }] : []));
|
|
2190
|
+
// G2:多租户姿态不许跑不分租户的车道 —— 逐车道判,每条一个 issue 落在它那一格;出路按表现算(不手写第五份词表)。
|
|
2191
|
+
if (requirePrincipal) {
|
|
2192
|
+
const outlets = EXECUTION_LANES.filter((r) => r.tenantSeparation === "supported").map((r) => r.lane);
|
|
2193
|
+
for (const { lane, i, row } of declared) {
|
|
2194
|
+
if (row.tenantSeparation !== "single-user-only")
|
|
2195
|
+
continue;
|
|
2196
|
+
issue(["runtime", "execution", "lanes", i], buildQuotedIssue `runtime.requirePrincipal=true (multi-tenant posture) with the "${fixed(lane)}" execution lane runs every tenant's Bash on one shared target — this lane does not separate tenants; remove it from runtime.execution.lanes (lanes that separate tenants: ${fixed(outlets.join(" / "))}), or set runtime.requirePrincipal=false for a single-user worker`);
|
|
2152
2197
|
}
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2198
|
+
}
|
|
2199
|
+
// 单副本车道 ∧ 多副本:读车道表的 `singleReplica` 列(不点名车道词)。副本数有两个旋钮(replicas / autoscaling.maxReplicas,二者互斥),一条规则看「最多几个副本」;
|
|
2200
|
+
// 表里所有单副本车道合成一条 issue。
|
|
2201
|
+
const singleReplica = declared.filter(({ row }) => row.singleReplica).map(({ lane }) => JSON.stringify(lane));
|
|
2202
|
+
if (singleReplica.length > 0) {
|
|
2203
|
+
const [path, replicas] = w.autoscaling !== undefined ? [["autoscaling", "maxReplicas"], w.autoscaling.maxReplicas] : [["replicas"], w.replicas ?? 1];
|
|
2204
|
+
if (replicas > 1) {
|
|
2205
|
+
issue(path, buildQuotedIssue `runtime.execution.lanes declares ${fixed(singleReplica.join(", "))}, which hold a session's work on one replica (that replica's own filesystem, or the replica its device is connected to) — ${replicas} replicas behind one route would let a session's next turn land on a replica that does not hold it. Keep a single replica, or remove ${fixed(singleReplica.join(", "))} from runtime.execution.lanes`);
|
|
2159
2206
|
}
|
|
2160
2207
|
}
|
|
2161
2208
|
// store 四条:① SQL 店 ⇒ db + dbPasswordEnv 在场;② 非 SQL 店 ⇒ 两者都不在场(①② 是一条规则:SQL 坐标 ⇔ SQL 店);
|
|
@@ -2168,7 +2215,7 @@ function workerSpecIssues(w, ctx) {
|
|
|
2168
2215
|
// device 车道 ⇒ SQL 池必须开(引擎 `config-invariants.ts:318` `device-durable-store`:设备注册簿 / session↔设备绑定 / 审计都在 SQL 里)。
|
|
2169
2216
|
// 与 G2 同族(gpt-6 腿 F2)。同族的 `device-durable-approval` 读的是 `DURABLE_APPROVAL`(逃生口里的 env + 姿态缺省),不在结构字段上,
|
|
2170
2217
|
// 写闸判不了 —— 那一条只在起服拒。
|
|
2171
|
-
if (
|
|
2218
|
+
if (declared.some(({ lane }) => lane === "device") && store !== undefined && !sqlPoolOpens) {
|
|
2172
2219
|
if (!sql) {
|
|
2173
2220
|
issue(["runtime", "store", "backend"], buildQuotedIssue `the "device" execution lane keeps its device registry, session↔device binding and audit trail in SQL — store.backend "${store.backend}" has none (the engine refuses to start: device-durable-store); set store.backend to mysql | pg`);
|
|
2174
2221
|
}
|
|
@@ -2339,8 +2386,12 @@ export const HostStatus = z.object({
|
|
|
2339
2386
|
host: z.string().min(1).max(HOST_NAME_MAX).regex(/^[a-z0-9][a-z0-9-]*$/, "lowercase letters/digits/-, no spaces"),
|
|
2340
2387
|
backend: z.enum(["docker", "k8s"]),
|
|
2341
2388
|
probes: HostProbes,
|
|
2342
|
-
/**
|
|
2343
|
-
|
|
2389
|
+
/** 探测时刻,RFC 3339(秒必备、带 `Z` / `±hh:mm` 偏移;16.0.0 起判形,此前只判非空串 —— 注释说时刻而不判,读方 `Date.parse` 读成 NaN 的串也收)。
|
|
2390
|
+
* 机器视图 hover 注明数据口径与此时间(§2-5:是分配额口径的底数,非实时负载)。 */
|
|
2391
|
+
ts: RFC3339_DATE_TIME,
|
|
2392
|
+
/** 16.0.0:上报方声明的心跳节律(毫秒,正整数)—— 与实例公告 `InstanceAnnouncement.heartbeatMs` 同一个词、同一个义。缺席 = 没声明(**没有缺省**:
|
|
2393
|
+
* 不替上报方铸一个它没说过的节律)。多久没报算不新鲜是中心的判(窗公式归中心;本包只给字段,不给公式)。 */
|
|
2394
|
+
heartbeatMs: INTEGER.positive().optional(),
|
|
2344
2395
|
});
|
|
2345
2396
|
// ── Domain: skills (中心化 skill 分发 — the mcp/skills design note, Roadmap B1) ─────────
|
|
2346
2397
|
// A skill is a prompt-level capability: frontmatter (name/description/scenarios) + markdown `content`
|
package/dist/url-shape.d.ts
CHANGED
|
@@ -50,6 +50,14 @@ export declare function httpUrlFlaws<P extends HttpUrlPart>(raw: string, forbid:
|
|
|
50
50
|
* 按座位的本质命名,不按某个消费键名:谁的座位是「后面要拼路径的基址」,谁读它,不各自抄词。
|
|
51
51
|
*/
|
|
52
52
|
export declare const PATH_BASE_URL_FORBIDDEN_PARTS: readonly ["userinfo", "query", "fragment"];
|
|
53
|
+
/**
|
|
54
|
+
* **「逐字发给拨号方的地址」座位禁用的部件**(闭集、冻结、判序;16.0.0)。一个值若是被**逐字发布**、由别人原样去拨的地址(device 车道的设备入口
|
|
55
|
+
* `DEVICE_RELAY_URL`:引擎把它原样放上能力面,设备拨它):`userinfo` 把凭据发给每个读得到那张能力面的人;`query` / `fragment` 是令牌最常落的位置 ——
|
|
56
|
+
* 拨号方凭签名鉴权,发布出去的地址里没有凭据的位置。**路径不禁**(中继 / 网关按路径分流)。
|
|
57
|
+
* 与 {@link PATH_BASE_URL_FORBIDDEN_PARTS} 今天同三词,但理由不同、各自裁:那一张管「往后拼路径会落错位」,这一张管「发布出去的地址里不留凭据位」——
|
|
58
|
+
* 一个座位改禁哪件,不连带另一个。策略集独立于判官词表 {@link HTTP_URL_PARTS},同上一张的规矩。
|
|
59
|
+
*/
|
|
60
|
+
export declare const DIAL_ADDRESS_URL_FORBIDDEN_PARTS: readonly ["userinfo", "query", "fragment"];
|
|
53
61
|
/**
|
|
54
62
|
* 「后面要拼路径的基址」座位的判:`[]` = 合格,否则按判序交回规则词 —— 就是 {@link httpUrlFlaws} 配 {@link PATH_BASE_URL_FORBIDDEN_PARTS},
|
|
55
63
|
* 不另写判法;规则词的句子取 {@link httpUrlRule}。答案只有词,不含值的任何片段。判**占位展开之后**的值:`http://$(POD_IP):8090` 过
|
|
@@ -57,6 +65,16 @@ export declare const PATH_BASE_URL_FORBIDDEN_PARTS: readonly ["userinfo", "query
|
|
|
57
65
|
* 缺席 / 空串由调用方在判之前处理(对 `""` 本函数答 `not-http-url`)。
|
|
58
66
|
*/
|
|
59
67
|
export declare function pathBaseUrlFlaws(url: string): ReadonlyArray<HttpUrlFlaw>;
|
|
68
|
+
/** ws(s) 判官的拒因词(闭集):形不对(`not-ws-url`),或一件被禁的部件在场(与 http(s) 判官同一套部件词)。 */
|
|
69
|
+
export type WsUrlFlaw = "not-ws-url" | HttpUrlPart;
|
|
70
|
+
/** 「不是一个 ws(s) URL」的规则句 —— 只点名规则,不回显值。 */
|
|
71
|
+
export declare const WS_URL_SHAPE_RULE = "is not a parseable ws(s) URL (scheme must be ws or wss, written in full; it must look like ws(s)://host[:port][/path])";
|
|
72
|
+
/**
|
|
73
|
+
* **ws(s) URL 的形判官**(16.0.0;lift 自 server `parseDeviceRelayUrlEnv` 的形门,规则逐字搬)。ws(s) 是 http(s) 的升级形,层级式 URL 的规则同一套、只换 scheme:
|
|
74
|
+
* 值必须**照字面**以 `ws://` / `wss://` 起头(大小写不敏感;`wss:host`、前导空白都不算 —— WHATWG 会把它们修成合法 URL,这里按字面拒),
|
|
75
|
+
* 然后映射成 http(s) 问 {@link httpUrlFlaws} 那一只(本模块不写第二份形规则);它答的 `not-http-url` 在这里读作 `not-ws-url`。合格 ⇒ `[]`。
|
|
76
|
+
*/
|
|
77
|
+
export declare function wsUrlFlaws<P extends HttpUrlPart>(raw: string, forbid: readonly P[]): ReadonlyArray<"not-ws-url" | P>;
|
|
60
78
|
/** 以 `http://` / `https://` 起头(大小写不敏感)—— 一道**语法前缀**守卫,不是形判官:不解析、不看 host / 部件,所以 `https://` 这样的裸 scheme 它也收(见头注「第二个答案」)。
|
|
61
79
|
* 唯一读者是请求面 MCP 传输读器(`readRequestMcpTransport`);S-2106 收口时它退成那个读器座位的「照字面写全」规则,与形判官合取。 */
|
|
62
80
|
export declare function startsWithHttpScheme(raw: string): boolean;
|
package/dist/url-shape.js
CHANGED
|
@@ -66,6 +66,14 @@ export function httpUrlFlaws(raw, forbid) {
|
|
|
66
66
|
* 按座位的本质命名,不按某个消费键名:谁的座位是「后面要拼路径的基址」,谁读它,不各自抄词。
|
|
67
67
|
*/
|
|
68
68
|
export const PATH_BASE_URL_FORBIDDEN_PARTS = Object.freeze(["userinfo", "query", "fragment"]);
|
|
69
|
+
/**
|
|
70
|
+
* **「逐字发给拨号方的地址」座位禁用的部件**(闭集、冻结、判序;16.0.0)。一个值若是被**逐字发布**、由别人原样去拨的地址(device 车道的设备入口
|
|
71
|
+
* `DEVICE_RELAY_URL`:引擎把它原样放上能力面,设备拨它):`userinfo` 把凭据发给每个读得到那张能力面的人;`query` / `fragment` 是令牌最常落的位置 ——
|
|
72
|
+
* 拨号方凭签名鉴权,发布出去的地址里没有凭据的位置。**路径不禁**(中继 / 网关按路径分流)。
|
|
73
|
+
* 与 {@link PATH_BASE_URL_FORBIDDEN_PARTS} 今天同三词,但理由不同、各自裁:那一张管「往后拼路径会落错位」,这一张管「发布出去的地址里不留凭据位」——
|
|
74
|
+
* 一个座位改禁哪件,不连带另一个。策略集独立于判官词表 {@link HTTP_URL_PARTS},同上一张的规矩。
|
|
75
|
+
*/
|
|
76
|
+
export const DIAL_ADDRESS_URL_FORBIDDEN_PARTS = Object.freeze(["userinfo", "query", "fragment"]);
|
|
69
77
|
/**
|
|
70
78
|
* 「后面要拼路径的基址」座位的判:`[]` = 合格,否则按判序交回规则词 —— 就是 {@link httpUrlFlaws} 配 {@link PATH_BASE_URL_FORBIDDEN_PARTS},
|
|
71
79
|
* 不另写判法;规则词的句子取 {@link httpUrlRule}。答案只有词,不含值的任何片段。判**占位展开之后**的值:`http://$(POD_IP):8090` 过
|
|
@@ -75,6 +83,20 @@ export const PATH_BASE_URL_FORBIDDEN_PARTS = Object.freeze(["userinfo", "query",
|
|
|
75
83
|
export function pathBaseUrlFlaws(url) {
|
|
76
84
|
return httpUrlFlaws(url, PATH_BASE_URL_FORBIDDEN_PARTS);
|
|
77
85
|
}
|
|
86
|
+
/** 「不是一个 ws(s) URL」的规则句 —— 只点名规则,不回显值。 */
|
|
87
|
+
export const WS_URL_SHAPE_RULE = "is not a parseable ws(s) URL (scheme must be ws or wss, written in full; it must look like ws(s)://host[:port][/path])";
|
|
88
|
+
/**
|
|
89
|
+
* **ws(s) URL 的形判官**(16.0.0;lift 自 server `parseDeviceRelayUrlEnv` 的形门,规则逐字搬)。ws(s) 是 http(s) 的升级形,层级式 URL 的规则同一套、只换 scheme:
|
|
90
|
+
* 值必须**照字面**以 `ws://` / `wss://` 起头(大小写不敏感;`wss:host`、前导空白都不算 —— WHATWG 会把它们修成合法 URL,这里按字面拒),
|
|
91
|
+
* 然后映射成 http(s) 问 {@link httpUrlFlaws} 那一只(本模块不写第二份形规则);它答的 `not-http-url` 在这里读作 `not-ws-url`。合格 ⇒ `[]`。
|
|
92
|
+
*/
|
|
93
|
+
export function wsUrlFlaws(raw, forbid) {
|
|
94
|
+
const scheme = /^wss?:\/\//i.exec(raw)?.[0];
|
|
95
|
+
if (scheme === undefined)
|
|
96
|
+
return ["not-ws-url"];
|
|
97
|
+
const asHttp = `${scheme.length === "wss://".length ? "https" : "http"}://${raw.slice(scheme.length)}`;
|
|
98
|
+
return httpUrlFlaws(asHttp, forbid).map((f) => (f === "not-http-url" ? "not-ws-url" : f));
|
|
99
|
+
}
|
|
78
100
|
/** 以 `http://` / `https://` 起头(大小写不敏感)—— 一道**语法前缀**守卫,不是形判官:不解析、不看 host / 部件,所以 `https://` 这样的裸 scheme 它也收(见头注「第二个答案」)。
|
|
79
101
|
* 唯一读者是请求面 MCP 传输读器(`readRequestMcpTransport`);S-2106 收口时它退成那个读器座位的「照字面写全」规则,与形判官合取。 */
|
|
80
102
|
export function startsWithHttpScheme(raw) {
|
package/docs/API-SURFACE.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
> 每次全量重算并逐名比对 —— 加 / 删 / 改形一个导出而不重生成本档 ⇒ 红。导出面的每次变动因此以本档的 diff 出现在评审里。
|
|
5
5
|
> 形:`value` = 运行期拿得到的值;`type` = 只在类型层;`value+type` = 同名的值与类型(zod schema 与它推出的类型)。
|
|
6
6
|
|
|
7
|
-
子路径 24 条(资产出口 `./package.json` / `./fleet-paths.json` 不是模块,不列),导出名合计
|
|
7
|
+
子路径 24 条(资产出口 `./package.json` / `./fleet-paths.json` 不是模块,不列),导出名合计 1472 个(同名在多条子路径上各计一次)。
|
|
8
8
|
|
|
9
|
-
## `.`(
|
|
9
|
+
## `.`(772)
|
|
10
10
|
|
|
11
11
|
- `ABSOLUTE_HOST_PATH_MAX` — value
|
|
12
12
|
- `ACCESS_TOKEN_TTL_SECONDS` — value
|
|
@@ -94,8 +94,11 @@
|
|
|
94
94
|
- `DEVICE_CODE_TTL_SECONDS` — value
|
|
95
95
|
- `DEVICE_GRANT_TYPE` — value
|
|
96
96
|
- `DEVICE_POLL_INTERVAL_SECONDS` — value
|
|
97
|
+
- `DEVICE_RELAY_NONE` — value
|
|
98
|
+
- `DEVICE_RELAY_RULE` — value
|
|
97
99
|
- `DIALOG_EXPIRY_DEFAULT` — value
|
|
98
100
|
- `DIALOG_EXPIRY_VALUES` — value
|
|
101
|
+
- `DIAL_ADDRESS_URL_FORBIDDEN_PARTS` — value
|
|
99
102
|
- `DIRECTORY_ADDED_SOURCES` — value
|
|
100
103
|
- `DISCLOSABLE_IDENTITY_RE` — value
|
|
101
104
|
- `DISPATCH_STRATEGIES` — value
|
|
@@ -457,7 +460,6 @@
|
|
|
457
460
|
- `STALE_SESSION_RECORD_MS` — value
|
|
458
461
|
- `STORE_BACKENDS` — value
|
|
459
462
|
- `SUBMIT_IDEMPOTENCY_KEY` — value
|
|
460
|
-
- `SUMMARIZE_MODEL_MISSING_CODE` — value
|
|
461
463
|
- `SafetyMergeCategory` — type
|
|
462
464
|
- `SafetyMergeMember` — type
|
|
463
465
|
- `SandboxGitConfig` — value+type
|
|
@@ -581,6 +583,7 @@
|
|
|
581
583
|
- `WORKER_PULL_TOKEN` — value
|
|
582
584
|
- `WORKER_RESOURCE_PRESETS` — value
|
|
583
585
|
- `WORKSPACE_TRUST_STATES` — value
|
|
586
|
+
- `WS_URL_SHAPE_RULE` — value
|
|
584
587
|
- `WarningKind` — type
|
|
585
588
|
- `WarningProjection` — type
|
|
586
589
|
- `WebAdminCapabilities` — value+type
|
|
@@ -602,6 +605,7 @@
|
|
|
602
605
|
- `WorkspaceTrustState` — type
|
|
603
606
|
- `WorktreeCreateHookInput` — value
|
|
604
607
|
- `WorktreeRemoveHookInput` — value
|
|
608
|
+
- `WsUrlFlaw` — type
|
|
605
609
|
- `aggregateUsage` — value
|
|
606
610
|
- `applyProjectPatch` — value
|
|
607
611
|
- `buildEffective` — value
|
|
@@ -624,6 +628,7 @@
|
|
|
624
628
|
- `describeNotStringArray` — value
|
|
625
629
|
- `describeNotStringRecord` — value
|
|
626
630
|
- `describeValueShape` — value
|
|
631
|
+
- `deviceRelayFlaws` — value
|
|
627
632
|
- `domainWriteRole` — value
|
|
628
633
|
- `drainVerdict` — value
|
|
629
634
|
- `effectiveScopeRole` — value
|
|
@@ -774,6 +779,7 @@
|
|
|
774
779
|
- `withheldNameToken` — value
|
|
775
780
|
- `workerRouteKey` — value
|
|
776
781
|
- `workersReferencingSecret` — value
|
|
782
|
+
- `wsUrlFlaws` — value
|
|
777
783
|
|
|
778
784
|
## `./types`(147)
|
|
779
785
|
|
|
@@ -1170,9 +1176,8 @@
|
|
|
1170
1176
|
- `tightenVerdict` — value
|
|
1171
1177
|
- `trustRank` — value
|
|
1172
1178
|
|
|
1173
|
-
## `./node`(
|
|
1179
|
+
## `./node`(49)
|
|
1174
1180
|
|
|
1175
|
-
- `BundleInspection` — type
|
|
1176
1181
|
- `ConfigBundle` — type
|
|
1177
1182
|
- `ConfigDirectoryDocument` — type
|
|
1178
1183
|
- `ConfigDirectoryIo` — type
|
|
@@ -1184,6 +1189,7 @@
|
|
|
1184
1189
|
- `EnvModelsDecisionWrite` — type
|
|
1185
1190
|
- `EnvModelsMigration` — type
|
|
1186
1191
|
- `EnvModelsMint` — type
|
|
1192
|
+
- `FileConfigRead` — type
|
|
1187
1193
|
- `FileConfigStore` — value+type
|
|
1188
1194
|
- `LocalConfig` — type
|
|
1189
1195
|
- `MigrateConfigDirectoryOptions` — type
|
|
@@ -1199,7 +1205,6 @@
|
|
|
1199
1205
|
- `createFileSchedulerStore` — value
|
|
1200
1206
|
- `domainFilePath` — value
|
|
1201
1207
|
- `exportBundle` — value
|
|
1202
|
-
- `inspectBundle` — value
|
|
1203
1208
|
- `listRequiredEnvNames` — value
|
|
1204
1209
|
- `loadEnvFile` — value
|
|
1205
1210
|
- `loadLocalConfig` — value
|
|
@@ -1354,7 +1359,7 @@
|
|
|
1354
1359
|
- `interpolateHookEnvVars` — value
|
|
1355
1360
|
- `stopAttributionText` — value
|
|
1356
1361
|
|
|
1357
|
-
## `./fleet`(
|
|
1362
|
+
## `./fleet`(85)
|
|
1358
1363
|
|
|
1359
1364
|
- `AggregatedPrincipalUsage` — type
|
|
1360
1365
|
- `CATALOG_REPLACES_ENV_MODELS_CODE` — value
|
|
@@ -1411,7 +1416,6 @@
|
|
|
1411
1416
|
- `SERVING_LEASE_VERDICTS` — value
|
|
1412
1417
|
- `STALE_HEARTBEAT_MULTIPLIER` — value
|
|
1413
1418
|
- `SUBMIT_IDEMPOTENCY_KEY` — value
|
|
1414
|
-
- `SUMMARIZE_MODEL_MISSING_CODE` — value
|
|
1415
1419
|
- `ServingLeaseDeniedReason` — value+type
|
|
1416
1420
|
- `ServingLeaseReading` — type
|
|
1417
1421
|
- `ServingLeaseRequest` — value+type
|
package/docs/CONFORMANCE.md
CHANGED
|
@@ -181,15 +181,9 @@ conformance/
|
|
|
181
181
|
input.json # { meta:{version,updatedAt}, domains:{…}, wirePayload?, localFiles? }
|
|
182
182
|
expected.json # 每条腿一格(四条一条不少):显式 golden / {derive:true}(只 wire / localRoot)/ {applicable:false,why}
|
|
183
183
|
meta.json # { contributor, claim, secrets?, firstRedOn, note? }
|
|
184
|
-
migrate-workers/<id>/ # 7.0.0:workers 域一次性迁移的冻结金样(不是读腿语料,kit 不跑它)
|
|
185
|
-
input.json # 原始 6.x workers 文档 { workers:[…] }(`meta.inputFrom` 在场 ⇒ 由加冕脚本取那条的输出生成)
|
|
186
|
-
expected.json # migrateWorkersDomain(input) = { doc, changed, dropped, refused }(refused[].original = 输入那一行逐字)
|
|
187
|
-
meta.json # { contributor, claim, inputFrom? }
|
|
188
184
|
```
|
|
189
185
|
|
|
190
|
-
-
|
|
191
|
-
对拍用:把 `input.json` 喂进你的读口,`doc` / `changed` / `dropped` / `refused` 应逐字等于 `expected.json`,再对 `doc` 跑一次应零变化。
|
|
192
|
-
本仓 `test/conformance-workers-7.0.0.test.ts` 钉着这三件;`npm run conformance:bless`(全量)同时加冕它们。迁移窗口关闭时整个目录随迁移代码删除。
|
|
186
|
+
- **迁移金样**:7.0.0 的 workers 迁移金样目录随那只迁移函数在 11.0.0 删了(树里没有它);一次性迁移族的对拍读 `./one-time-migrations` 的收据与本仓的迁移钉。
|
|
193
187
|
|
|
194
188
|
- **真源是 `domains`**(各域原始文档)。`wire` / `local-root` 两腿的**入参与期望**都由变换表派生;
|
|
195
189
|
派生解释不了的腿写显式期望并带 `why`。`strictWrite` 的入参与真源恒等、期望恒为显式金样(§6 的「期望从哪来」表)。
|
|
@@ -130,9 +130,9 @@
|
|
|
130
130
|
|
|
131
131
|
| import | 内容 | 浏览器安全 |
|
|
132
132
|
|---|---|---|
|
|
133
|
-
| `@sema-agent/settings-schema` | 纯契约+resolver:zod 域类型 / `EffectiveConfig`·`EffectiveWire` / `buildEffective` / `resolveEffectiveForWorker` / `ConfigReader` / `isDomainName` / `NON_SECRET_URL` / `RemoteExecSpec` / `ConfigPath`·`formatConfigPath`(3.0.0,§0.1)/ `EXECUTION_LANES`
|
|
133
|
+
| `@sema-agent/settings-schema` | 纯契约+resolver:zod 域类型 / `EffectiveConfig`·`EffectiveWire` / `buildEffective` / `resolveEffectiveForWorker` / `ConfigReader` / `isDomainName` / `NON_SECRET_URL` / `RemoteExecSpec` / `ConfigPath`·`formatConfigPath`(3.0.0,§0.1)/ `EXECUTION_LANES` 等六个词表常量(7.0.0,§0.2;车道集 16.0.0)与设备入口的值判官 `deviceRelayFlaws`(16.0.0) | ✅ |
|
|
134
134
|
| `@sema-agent/settings-schema/execution-lanes` | 7.0.0 车道 / 店词表正本(`EXECUTION_LANES` 等,与主桶同一模块实例),给只要词表的客户端组件;15.2.0 起另含车道坐标「空白按缺」的判官 `isBlankCoordinate`(与包根同一个函数对象,零依赖叶模块) | ✅ |
|
|
135
|
-
| `@sema-agent/settings-schema/node` | node-only:`FileConfigStore` / `loadLocalConfig`·`loadRemoteExec`·`writeRemoteExec`·`loadEnvFile` / `writeBundle`·`readBundle`·`exportBundle
|
|
135
|
+
| `@sema-agent/settings-schema/node` | node-only:`FileConfigStore` / `loadLocalConfig`·`loadRemoteExec`·`writeRemoteExec`·`loadEnvFile` / `writeBundle`·`readBundle`·`exportBundle`;单读口 `FileConfigStore.read()`(16.0.0:effective + 告警,或 `config.d` 文件层的类型化拒单 + 版本;词表 `CONFIG_DOCUMENT_REFUSAL_REASONS` 在包根) / `validateDomain`·`writeDomainFile`·`listRequiredEnvNames` | ❌(node) |
|
|
136
136
|
| `@sema-agent/settings-schema/conformance` | 跨仓一致性门 kit(3.0.0 新增;8.0.0 四条腿 + 表态律):金样语料 + 比对器,见 §11 | ❌(node,语料落盘) |
|
|
137
137
|
|
|
138
138
|
## 2. 单机(本地)模式 —— `FileConfigStore` 是真实接线,`loadLocalConfig(root)` 是便捷一把梭
|
|
@@ -248,7 +248,7 @@ server 直接拒启,不是静默降级。上一代 `SEMA_REGISTRY_*` 八名(`URL
|
|
|
248
248
|
同一只读口**:`readModelRefusals(body)`,`body` 传 `/health` 体或已 parse 的公告都行(它只读 `modelRefusals` 键);别直接
|
|
249
249
|
读公告上的字段 —— 字段是 wire 形 `ModelRefusalsWire`(码是开放串),读口才按本包闭集收窄成 `ModelRefusalsSignal`。
|
|
250
250
|
形 = `{ entries: { <条目名>: <码> }, plane?: <组拒码> }`,**名 → 码就是全部**:不带上游 id / provider / 坏字段 / 拒因句
|
|
251
|
-
(那些留在引擎日志里)。码是本包的**闭集**(`MODEL_ENTRY_REFUSAL_CODES` 两码 / `MODEL_PLANE_REFUSAL_CODES`
|
|
251
|
+
(那些留在引擎日志里)。码是本包的**闭集**(`MODEL_ENTRY_REFUSAL_CODES` 两码 / `MODEL_PLANE_REFUSAL_CODES` 五码,各有
|
|
252
252
|
`z.enum` 与型)—— 渲染按码穷举 `switch`,别手抄词表。**集外码 = 没说**:本包版本不认识的码,读口把那一条(或 `plane`)
|
|
253
253
|
丢掉,丢到空就回 `undefined`;心跳照收、存行照存 wire 形(web-admin 升级本包后同一行读出新码)—— 版本错位不会拖垮心跳。心跳上
|
|
254
254
|
`modelRefusals` 形坏(比如空信号)同样只降为缺席,不拒整条心跳。web-admin 若要给形坏留痕,自己对**请求原体**的 `modelRefusals`
|