@sema-agent/settings-schema 1.1.0 → 1.2.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 +83 -1
- package/README.md +9 -0
- package/dist/safety-merge-spec.d.ts +40 -17
- package/dist/safety-merge-spec.js +44 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,88 @@
|
|
|
6
6
|
> `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
|
|
7
7
|
> 包名是**历史记录**,如实保留不追改。
|
|
8
8
|
|
|
9
|
+
## 1.2.0 — `MinTrust` 排序原语 + `task` 员([5796] 序题 → [5805] schema 认领 / [5807] cli 表态三点)
|
|
10
|
+
|
|
11
|
+
**新导出 `trustRank(layer)` / `isAtLeast(layer, minTrust)`——规范信任阶梯的**单源**(v2-design §1:29 逐字);
|
|
12
|
+
`MinTrust` **尾插** `task`。发布表 `SAFETY_MERGE_SPEC` **一字不动**(1.1.0 全表字面量冻结钉),枚举声明序不重排
|
|
13
|
+
(重排 = BREAKING,免裁);版号 minor = 加词([5805]/[5807] 双方口径「1.2.0 小批 additive」;codex R2 持严格 semver
|
|
14
|
+
异议,见门段——候裁项,非代码缺陷)。**
|
|
15
|
+
|
|
16
|
+
> ⚠️ **词表加宽在消费方是可见的**(codex R1-F1,措辞订正):「表不动」≠「消费方零感知」。① 类型面:持
|
|
17
|
+
> `Record<MinTrust, …>` 字面量或对 `MinTrust` 穷举 `switch` 的消费方,升级即**编译错**(响亮——这正是要的:那张表
|
|
18
|
+
> 该退役改经 `trustRank`);② 运行时:用本包 schema(`MinTrust` / `MemberAdmission` / `MergeCategorySpec`)校验
|
|
19
|
+
> **外部** spec 值的消费方,自本版起会**收下** `task`,必须能给它排位——用 `trustRank`,勿自铸五词表(五词表对
|
|
20
|
+
> `task` 取值 `undefined`,`<`/`>=` 比较静默为 `false`,方向随消费方写法而定、且不响)。发包日观察值(亲 grep,
|
|
21
|
+
> 观察 ≠ 规范):cli `src/` 对 `MinTrust` **类型/值零 import**——仅注释提及(`src/sema/settings/keyContracts.ts:14-15,36`),
|
|
22
|
+
> 其 `TrustName` / `TRUST_RANK` 自铸且已含 `task`(按 [5807] ③ 删表改 import 时才首次成为类型消费方);1.1.0 段矩阵
|
|
23
|
+
> 其余邻仓零命中。故①②今日无真实受害者,但契约句必须先说真话。
|
|
24
|
+
> 「另铸六词 schema 保旧 `MinTrust`」不采:等于第二张词表,正是 1.1.0「一枚举无第二词表」钉所禁,且 cli ① 点名要
|
|
25
|
+
> 在 `MinTrust` 加员。
|
|
26
|
+
|
|
27
|
+
### 阶梯序判定(成文理由,亲读坐标)
|
|
28
|
+
|
|
29
|
+
- 规范序 = v2-design §1:29(`sema-internal/core/research/settings-product/04-v2-design.md`)逐字:
|
|
30
|
+
`MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 > SESSION 2 > TASK 1`。
|
|
31
|
+
- `task` 位**不是本仓臆定**:§1:29 本就含 `TASK 1`(最低信任端);§4:74 `KeyContract.minTrust` 词表本就列 `'task'`
|
|
32
|
+
——它**是** floor 词(1.1.0 JSDoc「`task` 不是 floor 词」为失真句,本版改述);§2:36 SESSION/TASK = 运行期 overlay
|
|
33
|
+
非文件、TASK 单 run 清、resume 不重放;§1:31 TASK 最高 precedence 但最低 trust(两序在用户端发散)。§5:96 resolver
|
|
34
|
+
伪码本就写作 `trustRank(L) < trustRank(contract.minTrust) → throw`——原语**名**亦有真源。
|
|
35
|
+
- **数值本身入契约**(不只是序):与 cli 自铸 `TRUST_RANK`(`src/sema/settings/keyContracts.ts:37-44`,managed 6 … task 1)
|
|
36
|
+
同值,壳删表改 import 后每次比较结果逐字节不变。
|
|
37
|
+
- 声明序仍非规范:`MinTrust.options` = 1.1.0 五词原序 + `task` 尾插;阶梯**只**经 `trustRank`,不索引枚举。
|
|
38
|
+
- **不建模** v2-design §6.4:138 的 `launch-only`(比 session/task 更窄的「仅本进程显式标志」):它是 `bypassPermissions`
|
|
39
|
+
的入口限制,不是阶梯词;将来需成词另案。
|
|
40
|
+
|
|
41
|
+
### API 形(全文)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export const MinTrust = z.enum(["local", "session", "project", "global", "managed", "task"]);
|
|
45
|
+
export function trustRank(layer: MinTrust): number; // 6/5/4/3/2/1,穷举 switch
|
|
46
|
+
export function isAtLeast(layer: MinTrust, minTrust: MinTrust): boolean; // trustRank(layer) >= trustRank(minTrust)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **fail-closed**:`trustRank` 是对 `MinTrust` 的穷举 `switch`——枚举加词漏 rank = **编译错**(`never` 臂);运行时未知词
|
|
50
|
+
(JS / 反序列化调用方喂 `__proto__` / `constructor` / 大写 provenance 层词 / `launch-only` …)= **`RangeError`**,永不
|
|
51
|
+
`undefined` / `NaN`(NaN 会让每次比较静默 `false`——方向恰好安全但不响,仍属静默臂)。`isAtLeast` 两参都过 `trustRank`。
|
|
52
|
+
- 既有成员级查询族(`membersOf` / `memberAdmission` / `memberMinTrust` / `resolveMemberAdmission`)**不含比较逻辑**,
|
|
53
|
+
无需改经;测试侧原本地 `LADDER` 表删除,改用 `isAtLeast`(单源两用);`memberMinTrust` JSDoc 的
|
|
54
|
+
`rank(layer) ≥ rank(floor)` 改指 `isAtLeast`。
|
|
55
|
+
- `task` 今日**零**类目 / 成员行使用(冻结 1.1.0 schema 全表逐字节解析钉证——1.1.0 消费方永不遇到未知词);
|
|
56
|
+
`minTrust:"task"` = 最宽 floor(任何层含 task overlay 皆可 set),对 spec **值**合法(`MemberAdmission` / `MergeCategorySpec` 收)。
|
|
57
|
+
|
|
58
|
+
### 消费方接线
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { isAtLeast, memberMinTrust, membersOf } from "@sema-agent/settings-schema";
|
|
62
|
+
for (const m of membersOf("permissions")) {
|
|
63
|
+
if (!isAtLeast(layer.sourceTrust, memberMinTrust("permissions", m))) { /* loosen ⇒ 待确认建议;tighten 不会走到这 */ }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- cli:删自铸 `TRUST_RANK` 改 import(随 L-29 上收批同落,[5807] ③);四件套成员级门吃同一原语。1.1.0 段「本包尚未导出
|
|
68
|
+
排序原语」自本版起过期。
|
|
69
|
+
|
|
70
|
+
### 门
|
|
71
|
+
|
|
72
|
+
- 红先:11 条新钉 + 1 条改经原语的旧钉先红——运行时 10 红(`trustRank`/`isAtLeast is not a function` ×6、`task` 缺席 ×2、
|
|
73
|
+
声明序文本钉 ×1、单调钉 ×1),tsc 11 处红(缺导出 2 / `"task"` 不可赋 4 / `@ts-expect-error` 未命中 2 / 连带 3)→ 全绿。
|
|
74
|
+
- 变异六刀各红(主题文件 33 钉):M1 session/local 互换 → 4 红(逐字表 / 单调 / 真值表 / 准入集);M2 `isAtLeast` 用 `>` →
|
|
75
|
+
5 红(含 1.1.0 方向不变量钉——单源两用之证);M3 枚举去 `task`(switch 仍留)→ 5 红;M4 枚举重排(`task` 置首)→ 2 红
|
|
76
|
+
(尾插钉 + 文本钉,其余全绿=声明序确非阶梯);M5 未知词返 `NaN` 不抛 → 只红未知词钉(1/33,定点);M6 `task` 排 7 高于
|
|
77
|
+
managed → 5 红。源文件 sha256 复原逐字节一致。
|
|
78
|
+
- codex adversarial-review R1 三条:F1 [high]「加 `task` 非纯向后兼容」→ **部分采**:头句 / README 措辞订正为「表不动 ≠
|
|
79
|
+
消费方零感知」+ 消费方迁移句(上 ⚠️ 段);「另铸六词 schema 保旧 `MinTrust`」**驳回**(第二张词表);F2 [medium] 冻结
|
|
80
|
+
1.1.0 钉拿 `r.data` 对当前值 = 同义反复 → **采**:补独立 1.1.0 全表字面量夹具(commit `9e41eaf` 逐字),第七刀 M7
|
|
81
|
+
`hooks.minTrust` project→local **只红该钉**(1/33;修前此刀全绿);F3 [medium] README「无消费方自铸表」写成既成事实 →
|
|
82
|
+
**采**改述为迁移目标(cli 半场未落)。R1 自报 vitest 在其只读沙箱起不来(环境,非发现)。
|
|
83
|
+
- codex R2:F2 / F3 判**已解**;1.1.0 字面量判**独立且完整**(对 `9e41eaf` 逐值,16 类目);`trustRank` / `isAtLeast` /
|
|
84
|
+
JSDoc / 新钉**无新发现**。余 F1 一条 [high]:「加宽公共枚举按 minor 发,`^1.1.0` 消费方自动收到」→ 建议发 **2.0.0**
|
|
85
|
+
或另铸六词 schema。处置:另铸 schema **再驳**(第二张词表,理由同上);**major vs minor 是版号政策、不是代码缺陷**
|
|
86
|
+
——本批按 [5805]/[5807] 双方口径与任务书走 1.2.0,**候主会话 / clay 裁**;若裁 major,只需改 `package.json` /
|
|
87
|
+
`package-lock.json` 根版本 / 本段标题三处,代码零动。
|
|
88
|
+
- 全量 39 文件 / 621 用例绿(1.1.0 基线 610 + 11);tsc 0;build 绿(dist `.d.ts` 含两原语);dist 运行时冒烟
|
|
89
|
+
(`node -e import('./dist/index.js')`)六词/六序/未知词 RangeError 如述。
|
|
90
|
+
|
|
9
91
|
## 1.1.0 — `permissions` 成员级准入(权限双通道终裁四件套之④,clay 终裁 [5797];合流形 [5794])
|
|
10
92
|
|
|
11
93
|
**`SAFETY_MERGE_SPEC` 类目可声明 `members`(成员级 minTrust + 方向);首个也是当前唯一成员化的类目 = `permissions`
|
|
@@ -82,7 +164,7 @@ for (const m of membersOf("permissions")) { // ["allow","deny","ask"]
|
|
|
82
164
|
|
|
83
165
|
- `rank(...)` 仍是消费方自己的阶梯(v2-design §1 `managed > global > project > local > session > task`);本包
|
|
84
166
|
**尚未**导出排序原语——`MinTrust` 枚举的声明序在 session/local 处与 §1 倒置、且零消费方索引它(非规范),
|
|
85
|
-
排序原语随 [5796] 序题表态另车(本版只把该注释改说真话)。
|
|
167
|
+
排序原语随 [5796] 序题表态另车(本版只把该注释改说真话)。(→ 1.2.0 已导出 `trustRank` / `isAtLeast`。)
|
|
86
168
|
|
|
87
169
|
### 门
|
|
88
170
|
|
package/README.md
CHANGED
|
@@ -68,6 +68,15 @@ sound). `npm ls --prod` therefore shows only `zod`. Node built-ins only (`node:c
|
|
|
68
68
|
stays the default floor, so consumers that predate `members` behave exactly as before. This package publishes
|
|
69
69
|
the contract only: it performs no admission check and no "degrade a below-floor allow to a pending suggestion"
|
|
70
70
|
step — those live in the consumers (engine import door, shell resolver), each on its own release schedule.
|
|
71
|
+
1.2.0 adds the **trust ordering primitives**: `trustRank(layer)` (v2-design §1 verbatim, `managed 6 > global 5 >
|
|
72
|
+
project 4 > local 3 > session 2 > task 1`) and `isAtLeast(layer, minTrust)` — the ladder every resolver is to
|
|
73
|
+
compare floors against; consumers retire their own rank tables onto it (the CLI's `TRUST_RANK` migration is
|
|
74
|
+
pending on its side, board [5807] ③ — exporting the primitive does not by itself make it the single source).
|
|
75
|
+
`MinTrust` gains the `task` word (the runtime task overlay, the loosest floor; appended, declaration order
|
|
76
|
+
otherwise unchanged — the declaration order is not the ladder, `trustRank` is). The published table does not
|
|
77
|
+
use `task`; the widened vocabulary is visible to consumers that hold a `Record<MinTrust, …>` / exhaustive
|
|
78
|
+
switch (compile error on upgrade — migrate to `trustRank`) or that validate external spec values with these
|
|
79
|
+
schemas (they now accept `task` and must rank it — again `trustRank`, never a five-word table of their own).
|
|
71
80
|
- **Auth wire contract** (`api/auth.ts`, subpath `./api/auth`): the `/api/v1/auth/*` face — RFC 8628
|
|
72
81
|
device flow (code / token poll / approve consent) + rotating refresh + logout, the OAuth error envelope,
|
|
73
82
|
and the pure client helpers `normalizeUserCode` / `nextPollInterval`. Shipped M1 shapes frozen.
|
|
@@ -38,18 +38,41 @@
|
|
|
38
38
|
* silences classifier asks only; it can never silence a MANDATED ask (shellGate "always", org policy,
|
|
39
39
|
* requiresRealApproval). Consumers read admission through {@link memberAdmission} / {@link memberMinTrust} /
|
|
40
40
|
* {@link membersOf} — never through a hardcoded allow/deny/ask table of their own (single source).
|
|
41
|
+
*
|
|
42
|
+
* TRUST ORDERING PRIMITIVES (1.2.0 — board [5796] ordering question → [5805] claim / [5807] consumer statement):
|
|
43
|
+
* The floor words are only meaningful against a LADDER, and that ladder is v2-design §1:29, verbatim:
|
|
44
|
+
* `MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 > SESSION 2 > TASK 1`. {@link trustRank} publishes exactly those
|
|
45
|
+
* numbers and {@link isAtLeast} the comparison a resolver makes (`rank(layer) ≥ rank(floor)` ⇒ admitted), so no
|
|
46
|
+
* consumer keeps a rank table of its own (cli's `TRUST_RANK` retires onto these). `task` joins {@link MinTrust}
|
|
47
|
+
* (v2-design §4:74 lists it in `KeyContract.minTrust`; §2:36 — session/task are runtime overlays, never files):
|
|
48
|
+
* the loosest floor, "any layer including the task overlay may set this". No row of {@link SAFETY_MERGE_SPEC}
|
|
49
|
+
* uses it today (the frozen-1.1.0 conformance pin holds that). The enum's DECLARATION ORDER stays what 1.1.0
|
|
50
|
+
* published, `task` appended — reordering would be breaking ([5807] ②) and the declaration order is NOT the
|
|
51
|
+
* ladder anyway; only {@link trustRank} is.
|
|
41
52
|
*/
|
|
42
53
|
import { z } from "zod";
|
|
43
54
|
/** How values from different layers/principals combine for a category. */
|
|
44
55
|
export declare const MergeShape: z.ZodEnum<["denyFirst", "replace", "runAll", "overrideByName", "concat"]>;
|
|
45
56
|
export type MergeShape = z.infer<typeof MergeShape>;
|
|
46
57
|
/** The trust-tier VOCABULARY a category — or, since 1.1.0, one of its members — names as its admission floor
|
|
47
|
-
* (the MINIMUM trust a layer/principal must have to set it). The RANK is v2-design §1:
|
|
48
|
-
* `managed > global > project > local > session
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
58
|
+
* (the MINIMUM trust a layer/principal must have to set it). The RANK is v2-design §1:29,
|
|
59
|
+
* `managed 6 > global 5 > project 4 > local 3 > session 2 > task 1`, published as {@link trustRank}; compare with
|
|
60
|
+
* {@link isAtLeast}. `task` (1.2.0) is the runtime task overlay — the lowest trust, the loosest floor.
|
|
61
|
+
* ⚠️ This enum's DECLARATION ORDER is NOT the rank (it is the 1.1.0 order with `task` appended — kept byte-stable
|
|
62
|
+
* because reordering is breaking); never index it as a ladder — use {@link trustRank}. */
|
|
63
|
+
export declare const MinTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
|
|
52
64
|
export type MinTrust = z.infer<typeof MinTrust>;
|
|
65
|
+
/** The trust RANK of a floor / layer word — v2-design §1:29 verbatim (`MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 >
|
|
66
|
+
* SESSION 2 > TASK 1`), the ONE published ladder every resolver compares against (1.2.0). Higher = more trusted.
|
|
67
|
+
* The numbers themselves are contract (a consumer may persist or log them), not merely their order.
|
|
68
|
+
* Exhaustive over {@link MinTrust}: a word added to the enum without a rank is a COMPILE error here; a word that
|
|
69
|
+
* is not in the enum at runtime (a JavaScript / deserialized caller) is a loud RangeError — never `undefined` or
|
|
70
|
+
* `NaN`, which would turn every comparison into a silent `false`. */
|
|
71
|
+
export declare function trustRank(layer: MinTrust): number;
|
|
72
|
+
/** `trustRank(layer) ≥ trustRank(minTrust)` — "is a source at `layer` trusted enough to set a key / member whose
|
|
73
|
+
* floor is `minTrust`?" (1.2.0). The comparison a resolver's admission check is; reflexive (a floor admits its
|
|
74
|
+
* own tier). Both arguments are validated by {@link trustRank} (unknown word ⇒ RangeError). */
|
|
75
|
+
export declare function isAtLeast(layer: MinTrust, minTrust: MinTrust): boolean;
|
|
53
76
|
/** Which way a MEMBER moves the engine's unattended surface (1.1.0). `loosen` = admits an action without a human
|
|
54
77
|
* that would otherwise ask/deny — a privilege, so it needs trust; `tighten` = only ever narrows — restricting is
|
|
55
78
|
* safe from anyone, so any settings-file layer may add it. The word is what a consumer branches on for the
|
|
@@ -63,13 +86,13 @@ export type MemberDirection = z.infer<typeof MemberDirection>;
|
|
|
63
86
|
* only by SAYING so; omission never lowers it (fail-closed by construction). */
|
|
64
87
|
export declare const MemberAdmission: z.ZodObject<{
|
|
65
88
|
direction: z.ZodEnum<["loosen", "tighten"]>;
|
|
66
|
-
minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed"]>>;
|
|
89
|
+
minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>>;
|
|
67
90
|
}, "strip", z.ZodTypeAny, {
|
|
68
91
|
direction: "loosen" | "tighten";
|
|
69
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
92
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
70
93
|
}, {
|
|
71
94
|
direction: "loosen" | "tighten";
|
|
72
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
95
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
73
96
|
}>;
|
|
74
97
|
export type MemberAdmission = z.infer<typeof MemberAdmission>;
|
|
75
98
|
/** The RESOLVED admission a consumer branches on — the category fallback already applied, so `minTrust` is never
|
|
@@ -129,7 +152,7 @@ export declare const TightenRule: z.ZodDiscriminatedUnion<"rule", [z.ZodObject<{
|
|
|
129
152
|
export type TightenRule = z.infer<typeof TightenRule>;
|
|
130
153
|
export declare const MergeCategorySpec: z.ZodObject<{
|
|
131
154
|
mergeShape: z.ZodEnum<["denyFirst", "replace", "runAll", "overrideByName", "concat"]>;
|
|
132
|
-
minTrust: z.ZodEnum<["local", "session", "project", "global", "managed"]>;
|
|
155
|
+
minTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
|
|
133
156
|
tighten: z.ZodDiscriminatedUnion<"rule", [z.ZodObject<{
|
|
134
157
|
rule: z.ZodLiteral<"none">;
|
|
135
158
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -178,13 +201,13 @@ export declare const MergeCategorySpec: z.ZodObject<{
|
|
|
178
201
|
* category `minTrust` when the row omits one); the member set is closed — {@link membersOf} enumerates it. */
|
|
179
202
|
members: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
180
203
|
direction: z.ZodEnum<["loosen", "tighten"]>;
|
|
181
|
-
minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed"]>>;
|
|
204
|
+
minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>>;
|
|
182
205
|
}, "strip", z.ZodTypeAny, {
|
|
183
206
|
direction: "loosen" | "tighten";
|
|
184
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
207
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
185
208
|
}, {
|
|
186
209
|
direction: "loosen" | "tighten";
|
|
187
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
210
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
188
211
|
}>>>;
|
|
189
212
|
}, "strip", z.ZodTypeAny, {
|
|
190
213
|
enforcement: "gate" | "server" | "resolver" | "client";
|
|
@@ -201,13 +224,13 @@ export declare const MergeCategorySpec: z.ZodObject<{
|
|
|
201
224
|
rule: "enumRank";
|
|
202
225
|
order: string[];
|
|
203
226
|
};
|
|
204
|
-
minTrust: "local" | "session" | "global" | "project" | "managed";
|
|
227
|
+
minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
|
|
205
228
|
mergeShape: "concat" | "replace" | "denyFirst" | "runAll" | "overrideByName";
|
|
206
229
|
fail: "closed" | "open";
|
|
207
230
|
seam: string;
|
|
208
231
|
members?: Record<string, {
|
|
209
232
|
direction: "loosen" | "tighten";
|
|
210
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
233
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
211
234
|
}> | undefined;
|
|
212
235
|
coreAxis?: "permissionDecision" | "toolEffect" | "egress" | "irreversibility" | "safetyAxis" | "severity" | "shellGate" | undefined;
|
|
213
236
|
}, {
|
|
@@ -225,13 +248,13 @@ export declare const MergeCategorySpec: z.ZodObject<{
|
|
|
225
248
|
rule: "enumRank";
|
|
226
249
|
order: string[];
|
|
227
250
|
};
|
|
228
|
-
minTrust: "local" | "session" | "global" | "project" | "managed";
|
|
251
|
+
minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
|
|
229
252
|
mergeShape: "concat" | "replace" | "denyFirst" | "runAll" | "overrideByName";
|
|
230
253
|
fail: "closed" | "open";
|
|
231
254
|
seam: string;
|
|
232
255
|
members?: Record<string, {
|
|
233
256
|
direction: "loosen" | "tighten";
|
|
234
|
-
minTrust?: "local" | "session" | "global" | "project" | "managed" | undefined;
|
|
257
|
+
minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
|
|
235
258
|
}> | undefined;
|
|
236
259
|
coreAxis?: "permissionDecision" | "toolEffect" | "egress" | "irreversibility" | "safetyAxis" | "severity" | "shellGate" | undefined;
|
|
237
260
|
}>;
|
|
@@ -446,5 +469,5 @@ export declare function resolveMemberAdmission(spec: MergeCategorySpec, member:
|
|
|
446
469
|
* Unknown category or member ⇒ RangeError (never a fallback). */
|
|
447
470
|
export declare function memberAdmission<C extends SafetyMergeCategory>(category: C, member: SafetyMergeMember<C>): ResolvedMemberAdmission;
|
|
448
471
|
/** A member's admission FLOOR from the published table — the word a resolver compares the layer's trust against
|
|
449
|
-
* (`
|
|
472
|
+
* (`isAtLeast(layer, floor)` ⇒ admitted; the ladder is {@link trustRank}). Convenience over {@link memberAdmission}. */
|
|
450
473
|
export declare function memberMinTrust<C extends SafetyMergeCategory>(category: C, member: SafetyMergeMember<C>): MinTrust;
|
|
@@ -38,16 +38,54 @@
|
|
|
38
38
|
* silences classifier asks only; it can never silence a MANDATED ask (shellGate "always", org policy,
|
|
39
39
|
* requiresRealApproval). Consumers read admission through {@link memberAdmission} / {@link memberMinTrust} /
|
|
40
40
|
* {@link membersOf} — never through a hardcoded allow/deny/ask table of their own (single source).
|
|
41
|
+
*
|
|
42
|
+
* TRUST ORDERING PRIMITIVES (1.2.0 — board [5796] ordering question → [5805] claim / [5807] consumer statement):
|
|
43
|
+
* The floor words are only meaningful against a LADDER, and that ladder is v2-design §1:29, verbatim:
|
|
44
|
+
* `MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 > SESSION 2 > TASK 1`. {@link trustRank} publishes exactly those
|
|
45
|
+
* numbers and {@link isAtLeast} the comparison a resolver makes (`rank(layer) ≥ rank(floor)` ⇒ admitted), so no
|
|
46
|
+
* consumer keeps a rank table of its own (cli's `TRUST_RANK` retires onto these). `task` joins {@link MinTrust}
|
|
47
|
+
* (v2-design §4:74 lists it in `KeyContract.minTrust`; §2:36 — session/task are runtime overlays, never files):
|
|
48
|
+
* the loosest floor, "any layer including the task overlay may set this". No row of {@link SAFETY_MERGE_SPEC}
|
|
49
|
+
* uses it today (the frozen-1.1.0 conformance pin holds that). The enum's DECLARATION ORDER stays what 1.1.0
|
|
50
|
+
* published, `task` appended — reordering would be breaking ([5807] ②) and the declaration order is NOT the
|
|
51
|
+
* ladder anyway; only {@link trustRank} is.
|
|
41
52
|
*/
|
|
42
53
|
import { z } from "zod";
|
|
43
54
|
/** How values from different layers/principals combine for a category. */
|
|
44
55
|
export const MergeShape = z.enum(["denyFirst", "replace", "runAll", "overrideByName", "concat"]);
|
|
45
56
|
/** The trust-tier VOCABULARY a category — or, since 1.1.0, one of its members — names as its admission floor
|
|
46
|
-
* (the MINIMUM trust a layer/principal must have to set it). The RANK is v2-design §1:
|
|
47
|
-
* `managed > global > project > local > session
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
|
|
57
|
+
* (the MINIMUM trust a layer/principal must have to set it). The RANK is v2-design §1:29,
|
|
58
|
+
* `managed 6 > global 5 > project 4 > local 3 > session 2 > task 1`, published as {@link trustRank}; compare with
|
|
59
|
+
* {@link isAtLeast}. `task` (1.2.0) is the runtime task overlay — the lowest trust, the loosest floor.
|
|
60
|
+
* ⚠️ This enum's DECLARATION ORDER is NOT the rank (it is the 1.1.0 order with `task` appended — kept byte-stable
|
|
61
|
+
* because reordering is breaking); never index it as a ladder — use {@link trustRank}. */
|
|
62
|
+
export const MinTrust = z.enum(["local", "session", "project", "global", "managed", "task"]);
|
|
63
|
+
/** The trust RANK of a floor / layer word — v2-design §1:29 verbatim (`MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 >
|
|
64
|
+
* SESSION 2 > TASK 1`), the ONE published ladder every resolver compares against (1.2.0). Higher = more trusted.
|
|
65
|
+
* The numbers themselves are contract (a consumer may persist or log them), not merely their order.
|
|
66
|
+
* Exhaustive over {@link MinTrust}: a word added to the enum without a rank is a COMPILE error here; a word that
|
|
67
|
+
* is not in the enum at runtime (a JavaScript / deserialized caller) is a loud RangeError — never `undefined` or
|
|
68
|
+
* `NaN`, which would turn every comparison into a silent `false`. */
|
|
69
|
+
export function trustRank(layer) {
|
|
70
|
+
switch (layer) {
|
|
71
|
+
case "managed": return 6;
|
|
72
|
+
case "global": return 5;
|
|
73
|
+
case "project": return 4;
|
|
74
|
+
case "local": return 3;
|
|
75
|
+
case "session": return 2;
|
|
76
|
+
case "task": return 1;
|
|
77
|
+
default: {
|
|
78
|
+
const unknown = layer;
|
|
79
|
+
throw new RangeError(`MinTrust: unknown trust word '${String(unknown)}' (words: ${MinTrust.options.join(", ")})`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** `trustRank(layer) ≥ trustRank(minTrust)` — "is a source at `layer` trusted enough to set a key / member whose
|
|
84
|
+
* floor is `minTrust`?" (1.2.0). The comparison a resolver's admission check is; reflexive (a floor admits its
|
|
85
|
+
* own tier). Both arguments are validated by {@link trustRank} (unknown word ⇒ RangeError). */
|
|
86
|
+
export function isAtLeast(layer, minTrust) {
|
|
87
|
+
return trustRank(layer) >= trustRank(minTrust);
|
|
88
|
+
}
|
|
51
89
|
/** Which way a MEMBER moves the engine's unattended surface (1.1.0). `loosen` = admits an action without a human
|
|
52
90
|
* that would otherwise ask/deny — a privilege, so it needs trust; `tighten` = only ever narrows — restricting is
|
|
53
91
|
* safe from anyone, so any settings-file layer may add it. The word is what a consumer branches on for the
|
|
@@ -171,7 +209,7 @@ export function memberAdmission(category, member) {
|
|
|
171
209
|
return resolveMemberAdmission(categorySpec(category), member, category);
|
|
172
210
|
}
|
|
173
211
|
/** A member's admission FLOOR from the published table — the word a resolver compares the layer's trust against
|
|
174
|
-
* (`
|
|
212
|
+
* (`isAtLeast(layer, floor)` ⇒ admitted; the ladder is {@link trustRank}). Convenience over {@link memberAdmission}. */
|
|
175
213
|
export function memberMinTrust(category, member) {
|
|
176
214
|
return memberAdmission(category, member).minTrust;
|
|
177
215
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/settings-schema",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Sema settings schema — pure config contract (zod domains + effective-config + roster resolution + ref-integrity + remoteExec) shared by sema-registry, sema-server, and the TOC desktop/CLI. One source of truth. (Renamed at 1.0.0 from @sema-agent/registry-core — name and docs only, no behavior change; note the range moves 0.19.0 -> 1.0.0, so a dependency must become ^1.0.0. The old names @sema-agent/registry-core <=0.19.0 and @sema-ai/registry-core remain published, frozen, for migration.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|