@sema-agent/server 7.116.1 → 7.118.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.
Files changed (131) hide show
  1. package/MIGRATION.md +195 -0
  2. package/USAGE.md +65 -41
  3. package/dist/approval-card.d.ts +82 -18
  4. package/dist/approval-card.js +46 -4
  5. package/dist/approval.d.ts +4 -12
  6. package/dist/approval.js +4 -26
  7. package/dist/boot/budget-tracing.js +2 -3
  8. package/dist/boot/config-center.d.ts +2 -2
  9. package/dist/boot/config-center.js +5 -7
  10. package/dist/boot/parked-revive-gate.d.ts +1 -7
  11. package/dist/boot/parked-revive-gate.js +2 -12
  12. package/dist/boot/resolve-spec.js +18 -16
  13. package/dist/boot/runner-deps.d.ts +5 -3
  14. package/dist/boot/runner-deps.js +6 -4
  15. package/dist/boot/stage-07-capability-layer.js +2 -2
  16. package/dist/brain.d.ts +17 -8
  17. package/dist/brain.js +10 -7
  18. package/dist/capabilities/hands-lane.d.ts +25 -0
  19. package/dist/capabilities/hands-lane.js +1 -1
  20. package/dist/capabilities/mcp-probe.d.ts +2 -2
  21. package/dist/config-catalog.js +3 -2
  22. package/dist/config-center/apply-effective.d.ts +6 -16
  23. package/dist/config-center/apply-effective.js +0 -6
  24. package/dist/config-center/facade.d.ts +1 -1
  25. package/dist/config-center/facade.js +1 -1
  26. package/dist/config-center/restart-signal.d.ts +1 -1
  27. package/dist/config-types.d.ts +12 -16
  28. package/dist/config.d.ts +32 -29
  29. package/dist/config.js +20 -27
  30. package/dist/deployment-governance.d.ts +13 -19
  31. package/dist/deployment-governance.js +7 -14
  32. package/dist/governance-overrides.d.ts +20 -0
  33. package/dist/governance-overrides.js +8 -0
  34. package/dist/host-decision.d.ts +83 -25
  35. package/dist/host-decision.js +31 -1
  36. package/dist/http/admission.js +13 -7
  37. package/dist/http/approval-sweeps.js +16 -13
  38. package/dist/http/checkpoint-ctx.d.ts +83 -24
  39. package/dist/http/checkpoint-ctx.js +68 -8
  40. package/dist/http/mcp-dial-deadline.d.ts +35 -0
  41. package/dist/http/mcp-dial-deadline.js +21 -0
  42. package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
  43. package/dist/http/memory-compliance-failure-reply.js +17 -8
  44. package/dist/http/memory-store-refusal-reply.d.ts +14 -11
  45. package/dist/http/memory-store-refusal-reply.js +16 -5
  46. package/dist/http/resume-legs.js +18 -18
  47. package/dist/http/retired-skill-manifest.d.ts +1 -1
  48. package/dist/http/route-ctx.d.ts +3 -3
  49. package/dist/http/routes/approvals-assistant.js +21 -24
  50. package/dist/http/routes/capabilities.js +5 -3
  51. package/dist/http/routes/mcp-reconnect.d.ts +17 -0
  52. package/dist/http/routes/mcp-reconnect.js +6 -1
  53. package/dist/http/routes/memory-bundle.js +1 -1
  54. package/dist/http/routes/memory-compliance.js +1 -1
  55. package/dist/http/routes/memory-origin.js +1 -1
  56. package/dist/http/routes/runs.js +53 -33
  57. package/dist/http/routes/sessions.d.ts +1 -1
  58. package/dist/http/routes/sessions.js +3 -6
  59. package/dist/http/routes/workflows.js +2 -0
  60. package/dist/http/wire-types.d.ts +6 -1
  61. package/dist/memory-store-refusal.d.ts +42 -17
  62. package/dist/memory-store-refusal.js +25 -6
  63. package/dist/model-select.d.ts +16 -5
  64. package/dist/model-select.js +7 -3
  65. package/dist/model-unreachable-notice.d.ts +1 -1
  66. package/dist/namespaced-rule-name.d.ts +45 -39
  67. package/dist/namespaced-rule-name.js +36 -22
  68. package/dist/observability/corrupt-read-seat.d.ts +4 -0
  69. package/dist/observability/corrupt-read-seat.js +1 -0
  70. package/dist/observability/fail-open.d.ts +15 -3
  71. package/dist/observability/fail-open.js +15 -3
  72. package/dist/observability/permission-rule-events.d.ts +3 -0
  73. package/dist/observability/permission-rule-events.js +4 -0
  74. package/dist/observability/run-terminal.js +21 -1
  75. package/dist/operator-ask.d.ts +4 -1
  76. package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
  77. package/dist/orchestration/workflow-agent-session-index.js +80 -14
  78. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
  79. package/dist/orchestration/workflow-completion-inbox.js +39 -17
  80. package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
  81. package/dist/orchestration/workflow-notify-journal.js +7 -2
  82. package/dist/outbound-dispatcher.d.ts +47 -20
  83. package/dist/outbound-dispatcher.js +198 -23
  84. package/dist/parked-decide.d.ts +43 -48
  85. package/dist/parked-decide.js +54 -16
  86. package/dist/permission-rule-list.d.ts +20 -31
  87. package/dist/permission-rule-vocab.d.ts +4 -3
  88. package/dist/permission-rule-vocab.js +1 -1
  89. package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
  90. package/dist/plugins/approval-ask-store-sql.js +0 -3
  91. package/dist/plugins/one-time-migrations.d.ts +25 -0
  92. package/dist/plugins/one-time-migrations.js +192 -6
  93. package/dist/plugins/pg-pool.js +1 -1
  94. package/dist/plugins/tidb-pool.js +1 -1
  95. package/dist/plugins/web-search.d.ts +20 -1
  96. package/dist/plugins/web-search.js +39 -10
  97. package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
  98. package/dist/plugins/workflow-run-store-sql.js +5 -7
  99. package/dist/request-key-closure.js +1 -1
  100. package/dist/request-value-closure.d.ts +1 -1
  101. package/dist/router/route-orchestration.d.ts +2 -23
  102. package/dist/rule-entry-list.d.ts +88 -0
  103. package/dist/rule-entry-list.js +102 -0
  104. package/dist/rules-consent.js +3 -0
  105. package/dist/run-local.d.ts +4 -2
  106. package/dist/run-local.js +4 -3
  107. package/dist/runs.d.ts +1 -1
  108. package/dist/runs.js +1 -0
  109. package/dist/runtime-governance.d.ts +5 -21
  110. package/dist/runtime-governance.js +4 -8
  111. package/dist/session-policy-wire.d.ts +13 -12
  112. package/dist/session-policy-wire.js +11 -6
  113. package/dist/spec-fields.d.ts +13 -24
  114. package/dist/spec-fields.js +13 -17
  115. package/dist/standing-answer-grant.d.ts +14 -2
  116. package/dist/standing-answer-grant.js +8 -1
  117. package/dist/task-settings.d.ts +18 -18
  118. package/dist/task-settings.js +63 -32
  119. package/dist/tool-approval.d.ts +77 -145
  120. package/dist/tool-approval.js +80 -62
  121. package/dist/trace/core-keyset-guard.d.ts +6 -6
  122. package/dist/trace/engine-notice-wire.d.ts +4 -6
  123. package/dist/trace/engine-notice-wire.js +14 -1
  124. package/dist/trace/self-minted-wire.d.ts +16 -2
  125. package/dist/trace/self-minted-wire.js +7 -0
  126. package/dist/user-input-ledger.d.ts +24 -12
  127. package/dist/user-input-ledger.js +33 -14
  128. package/package.json +2 -2
  129. package/scripts/drain-check-local.mjs +103 -7
  130. package/scripts/drain-check.mysql.sql +59 -8
  131. package/scripts/drain-check.pg.sql +66 -10
@@ -21,7 +21,7 @@
21
21
  * 没有方法、没有捕获的行为。
22
22
  */
23
23
  import { z } from "zod";
24
- import { READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
24
+ import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer, type SteerReplayFacet } from "@sema-agent/core";
25
25
  import type { AskRow } from "./plugins/approval-ask-store-sql.js";
26
26
  /** 模型自由文本(`sourceAgentName` / `delegation.agentName`)的限长(设计稿 §6.2)。设计 §3.1 把
27
27
  * 「限长 + 脱敏」写成 **server 新增责任**(引擎无此层):spawning model 挑的名字是自由文本,
@@ -81,11 +81,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
81
81
  kind: z.ZodLiteral<"single">;
82
82
  rule: z.ZodString;
83
83
  match: z.ZodEnum<{
84
+ name: "name";
84
85
  path: "path";
85
86
  exact: "exact";
86
87
  prefix: "prefix";
87
88
  wildcard: "wildcard";
88
89
  subpath: "subpath";
90
+ name_prefix: "name_prefix";
89
91
  }>;
90
92
  command: z.ZodString;
91
93
  }, z.core.$strict>, z.ZodObject<{
@@ -94,11 +96,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
94
96
  kind: z.ZodLiteral<"command">;
95
97
  rule: z.ZodString;
96
98
  match: z.ZodEnum<{
99
+ name: "name";
97
100
  path: "path";
98
101
  exact: "exact";
99
102
  prefix: "prefix";
100
103
  wildcard: "wildcard";
101
104
  subpath: "subpath";
105
+ name_prefix: "name_prefix";
102
106
  }>;
103
107
  command: z.ZodString;
104
108
  segment: z.ZodString;
@@ -126,7 +130,7 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
126
130
  * `password=…` 换成更长的遮蔽标记)。拿带 `.max()` 的形去校验**脱敏前**的原文,再脱敏,产出的就可能是
127
131
  * 一条超限的文本;而任何**回读**路径若再跑一遍同一个函数,那一条会在第二次校验时被整条丢掉 —— 于是
128
132
  * 「落库时在、读回时不在」,并且**只发生在有回读的那条腿上**(SQL 有列回读、LOCAL 直接从 blob 投),
129
- * 两个后端对同一份素材给出不同的卡面。同族先例逐字在 `tool-approval.ts` 的 `persistedRuleShadowed`
133
+ * 两个后端对同一份素材给出不同的卡面。同族先例逐字在 `tool-approval.ts` 的 `allowRuleShadowed`(7.41.x 时代叫 `persistedRuleShadowed`)
130
134
  * 发帧点(「先脱敏再截,一次算定」)。
131
135
  *
132
136
  * ⇒ 正确顺序:**结构判(本 schema)→ 脱敏 → 截长 → 结果按 {@link RuleOfferSchema} 必然合形**。
@@ -158,11 +162,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
158
162
  kind: z.ZodLiteral<"single">;
159
163
  rule: z.ZodString;
160
164
  match: z.ZodEnum<{
165
+ name: "name";
161
166
  path: "path";
162
167
  exact: "exact";
163
168
  prefix: "prefix";
164
169
  wildcard: "wildcard";
165
170
  subpath: "subpath";
171
+ name_prefix: "name_prefix";
166
172
  }>;
167
173
  command: z.ZodString;
168
174
  }, z.core.$strip>, z.ZodObject<{
@@ -171,11 +177,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
171
177
  kind: z.ZodLiteral<"command">;
172
178
  rule: z.ZodString;
173
179
  match: z.ZodEnum<{
180
+ name: "name";
174
181
  path: "path";
175
182
  exact: "exact";
176
183
  prefix: "prefix";
177
184
  wildcard: "wildcard";
178
185
  subpath: "subpath";
186
+ name_prefix: "name_prefix";
179
187
  }>;
180
188
  command: z.ZodString;
181
189
  segment: z.ZodString;
@@ -282,7 +290,7 @@ export declare function readProbeCause(req: unknown): ProbeCauseProjection | und
282
290
  * · 长度:超过 {@link MAX_PROBE_REASON_CODEPOINTS} ⇒ **整只丢,不截**(判据与 `probeCause.code` 超限同形);
283
291
  * 先判长度再脱敏 ⇒ 喂给脱敏器的永远是个短串(脱敏器的 RangeError 面是超大输入)。
284
292
  * · 内容族(部署自写的探针散文,人眼信任边界上的文本)⇒ `redactSecrets`。脱敏后**不再截**:耐久面同样不截,
285
- * 两面逐字节同值比「帧上短一截」重要(`persistedRuleShadowed` R2-[medium] 的反面:那里有卡面要对齐,这里没有)。
293
+ * 两面逐字节同值比「帧上短一截」重要(allow 层披露那一格 R2-[medium] 的反面:那里有卡面要对齐,这里没有)。
286
294
  * · 缺席 ≠「没有原因」:只有 maybe 档收紧且探针真给了 reason 的 ask 才有它。
287
295
  */
288
296
  export declare function readProbeReason(req: unknown): string | undefined;
@@ -337,6 +345,23 @@ export declare const RuleEvidenceSchema: z.ZodObject<{
337
345
  personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
338
346
  }, z.core.$strict>;
339
347
  export type RuleEvidenceProjection = z.infer<typeof RuleEvidenceSchema>;
348
+ /** 一条披露记录列出的条目上限 —— 防御值(引擎自己的上限更小,超出部分它计进 `omitted`);本层超出同样计进 `omitted`,不丢、不截条目个数以外的东西。 */
349
+ export declare const MAX_ALLOW_RULE_SHADOW_ENTRIES = 32;
350
+ /** 一条 allow 层披露记录的投影形(core `AllowRuleShadow` 的值形,条目已脱敏截长)。 */
351
+ export interface AllowRuleShadowProjection {
352
+ member: (typeof ALLOW_RULE_MEMBERS)[number];
353
+ entries: string[];
354
+ omitted?: number;
355
+ }
356
+ /**
357
+ * `AskRequest.allowRuleShadowed`(core 7.42.0 #1327)的**边界窄读** —— 活卡帧(`ToolApprovalFrame.allowRuleShadowed`)与 `card_json`
358
+ * (`buildApprovalCard`)的**唯一**铸造点,两面结构性同值(与 {@link readRuleEvidence} 同款分工)。姿势:
359
+ * · 整只形不合(不是数组 / 某条成员不在 core 闭集 / 条目不是字符串表 / `omitted` 不是正整数)⇒ 按缺席处置(半解上卡比缺席更坏);空数组 = 缺席;
360
+ * · 条目 = 内容族 ⇒ `redactSecrets` 后截 `MAX_RULE_TEXT_CHARS`,**先脱敏再截一次算定**(redact 会变长,两面各截会漂);超过
361
+ * {@link MAX_ALLOW_RULE_SHADOW_ENTRIES} 的条目计进 `omitted`(与引擎的计数相加);
362
+ * · 不包 try / catch:值来自引擎(已过引擎自己的 `readAllowRuleShadows` 判形),是纯数据;一只抛错的 getter 在这里抛 = 响亮失败,不是静默缺席。
363
+ */
364
+ export declare function readAllowRuleShadowed(req: unknown): AllowRuleShadowProjection[] | undefined;
340
365
  /**
341
366
  * `AskRequest.ruleEvidence`(core 5.35.0 [ref] G-2)的**边界窄读**——活卡帧(`ToolApprovalFrame.
342
367
  * ruleEvidence`)与 `card_json`(`buildApprovalCard`)的**唯一**铸造点,两面结构性同值(与
@@ -345,7 +370,7 @@ export type RuleEvidenceProjection = z.infer<typeof RuleEvidenceSchema>;
345
370
  * · **恰一不变量**:一对成员(值 / 缺席词)**双在场** ⇒ 整只丢——那是矛盾证据(引擎盖章的恰一,
346
371
  * 双在场只可能是第三方 producer 的坏行),半解上卡比缺席更坏。双缺席**容忍**(老 producer 行)。
347
372
  * · `orgRule` 内容族(管理员写的规则文本)⇒ `redactSecrets` 后截 `MAX_RULE_TEXT_CHARS`,**先脱敏
348
- * 再截一次算定**(`persistedRuleShadowed` R2-[medium] 教训:redact 会变长,两面各截会漂);空串丢整只。
373
+ * 再截一次算定**(allow 层披露那一格 R2-[medium] 教训:redact 会变长,两面各截会漂);空串丢整只。
349
374
  * · `dots.actor` 身份串 ⇒ `redactSecrets`(对正常 id 恒等);超限**整只丢**(见上限顶注,身份不可截)。
350
375
  * · `orgRevision` / 缺席词 verbatim(数值 / 闭集词,非内容)。
351
376
  */
@@ -420,7 +445,7 @@ type ToolApprovalPark = Extract<CorePendingAction, {
420
445
  kind: "tool_approval";
421
446
  }>;
422
447
  /**
423
- * 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`)—— 一座一只 core 成员筛,**名字是参数**(与
448
+ * 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`;S-1170 起 `classifierNoRuling` / `differs`)—— 一座一只成员筛,**名字是参数**(与
424
449
  * {@link readParkRowTrueSeat} 同一条:一处解析,不是两只各写一遍的函数)。
425
450
  * · `mandate`(core 7.32.0 #1092)—— 一问**站在哪一个 mandate 词上**(`mandated` 说「站在强制上」,本座说是 core
426
451
  * `PERSISTED_RULE_MANDATES` 六词里的哪一个;core 只在强制位的**整因**是那一个词时铸 —— 治理 / hook / 祖先,或不止一个理由
@@ -429,6 +454,11 @@ type ToolApprovalPark = Extract<CorePendingAction, {
429
454
  * · `origin`(core 7.5.0 [ref] 的 park 孪生座;S-755)—— **谁提的这一问**,core `ASK_ORIGINS` 闭集一词。读者:运维队列行读寄存行
430
455
  * 孪生座 `PendingAction.tool_approval.origin`({@link parkRowFacts})。活卡帧**不经**本函数:它读引擎在门上刚盖好的
431
456
  * `AskRequest.origin`(盖章点即 core 的筛点),照旧只过「非空串」形门(`tool-approval.ts` 帧键 `origin` 顶注)。
457
+ * · `classifierNoRuling`(core 7.43.0 #1353)—— 分类器没给判词的成因词,core `AUTO_MODE_FALLBACK_CAUSES` 闭集一词(筛 = `isAutoModeFallbackCause`)。
458
+ * 读者:活卡帧读 `AskRequest.classifierNoRuling`(`tool-approval.ts`);inbox 行读 core `CheckpointSummary` 已筛过的同名位、直投不经本函数。
459
+ * · `differs`(core 7.44.0 #1374)—— **载体是引擎拒 steer 重放那只错的 `detail`**(不是 ask 的三个载体之一),值是 core `STEER_REPLAY_FACETS` 的**非空子集**
460
+ * (core:「恒非空」;筛 = 本文件 {@link isSteerReplayDiffers},成员表取 core 常量)。读者:`runs.ts` 的 409 `steering.duplicate_input_id` 体(`detail.differs`)。
461
+ * 集外成员 / 空数组 / 非数组 ⇒ 按缺席(不铸 `detail`,码仍是契约)+ 计一次;detail 只报形名(`differs=<array>` —— 数组从不展开成员,见 {@link outOfSetDetail})。
432
462
  *
433
463
  * 什么时候经本函数 —— 一句话:**筛点在 core;server 只在「读的是持久层原字节、中间没有 core 投影」的地方亲手调 core 的那一只筛**。
434
464
  * inbox 行读 core `CheckpointSummary.{mandate,origin}`(core `summarizeCheckpoint` 已用同一只 `isPersistedRuleMandate` / `isAskOrigin`
@@ -442,10 +472,12 @@ type ToolApprovalPark = Extract<CorePendingAction, {
442
472
  * 只读值不调用值)。
443
473
  */
444
474
  export declare function readClosedWordSeat<S extends ClosedWordSeat>(carrier: object, seat: S): ClosedWordOf<S> | undefined;
445
- /** 闭集词座的名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。 */
446
- type ClosedWordSeat = "mandate" | "origin";
447
- /** 一座的值型 = core 寄存行上那一座的型(去掉可选位的 `undefined`)。 */
448
- type ClosedWordOf<S extends ClosedWordSeat> = NonNullable<ToolApprovalPark[S]>;
475
+ /** ask 载体上的闭集词座名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。 */
476
+ type AskClosedWordSeat = "mandate" | "origin" | "classifierNoRuling";
477
+ /** 闭集词座的名 = ask 载体上的三座 + 引擎拒 steer 重放那只错的 `detail.differs`(载体不同、读法同一只)。 */
478
+ type ClosedWordSeat = AskClosedWordSeat | "differs";
479
+ /** 一座的值型:ask 三座 = core 寄存行上那一座的型(去掉可选位的 `undefined`);`differs` = core 闭集 `SteerReplayFacet` 的数组(core `detail.differs` 的型)。 */
480
+ type ClosedWordOf<S extends ClosedWordSeat> = S extends AskClosedWordSeat ? NonNullable<ToolApprovalPark[S]> : readonly SteerReplayFacet[];
449
481
  /**
450
482
  * 🔴 **S-934 ②(core 7.37.0 #1214)—— ask 类对的唯一窄读**:`askClass`(一问的类 = `classes` 的首员)与 `classes`(这一问属于的全部类,core
451
483
  * `ASK_CLASSES` 序)。三个载体上同名:`AskRequest`(活卡帧 / 呈卡帧的卡读它)、寄存行 `PendingAction.tool_approval`(运维队列行经
@@ -568,16 +600,28 @@ export declare const ApprovalCardSchema: z.ZodObject<{
568
600
  governanceForced: z.ZodOptional<z.ZodLiteral<true>>;
569
601
  rememberRefused: z.ZodOptional<z.ZodLiteral<true>>;
570
602
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
571
- persistedRuleShadowed: z.ZodOptional<z.ZodString>;
603
+ allowRuleShadowed: z.ZodOptional<z.ZodArray<z.ZodObject<{
604
+ member: z.ZodEnum<{
605
+ hook: "hook";
606
+ skill: "skill";
607
+ deployment: "deployment";
608
+ request: "request";
609
+ persisted: "persisted";
610
+ }>;
611
+ entries: z.ZodArray<z.ZodString>;
612
+ omitted: z.ZodOptional<z.ZodNumber>;
613
+ }, z.core.$strict>>>;
572
614
  ruleOffers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
573
615
  kind: z.ZodLiteral<"single">;
574
616
  rule: z.ZodString;
575
617
  match: z.ZodEnum<{
618
+ name: "name";
576
619
  path: "path";
577
620
  exact: "exact";
578
621
  prefix: "prefix";
579
622
  wildcard: "wildcard";
580
623
  subpath: "subpath";
624
+ name_prefix: "name_prefix";
581
625
  }>;
582
626
  command: z.ZodString;
583
627
  }, z.core.$strict>, z.ZodObject<{
@@ -586,11 +630,13 @@ export declare const ApprovalCardSchema: z.ZodObject<{
586
630
  kind: z.ZodLiteral<"command">;
587
631
  rule: z.ZodString;
588
632
  match: z.ZodEnum<{
633
+ name: "name";
589
634
  path: "path";
590
635
  exact: "exact";
591
636
  prefix: "prefix";
592
637
  wildcard: "wildcard";
593
638
  subpath: "subpath";
639
+ name_prefix: "name_prefix";
594
640
  }>;
595
641
  command: z.ZodString;
596
642
  segment: z.ZodString;
@@ -649,8 +695,8 @@ export declare const ApprovalCardSchema: z.ZodObject<{
649
695
  }, z.core.$strict>>>;
650
696
  personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
651
697
  }, z.core.$strict>>;
652
- askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
653
- classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
698
+ askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
699
+ classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
654
700
  fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
655
701
  sourceTaskId: z.ZodOptional<z.ZodString>;
656
702
  sourceAgentName: z.ZodOptional<z.ZodString>;
@@ -684,16 +730,28 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
684
730
  governanceForced: z.ZodOptional<z.ZodLiteral<true>>;
685
731
  rememberRefused: z.ZodOptional<z.ZodLiteral<true>>;
686
732
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
687
- persistedRuleShadowed: z.ZodOptional<z.ZodString>;
733
+ allowRuleShadowed: z.ZodOptional<z.ZodArray<z.ZodObject<{
734
+ member: z.ZodEnum<{
735
+ hook: "hook";
736
+ skill: "skill";
737
+ deployment: "deployment";
738
+ request: "request";
739
+ persisted: "persisted";
740
+ }>;
741
+ entries: z.ZodArray<z.ZodString>;
742
+ omitted: z.ZodOptional<z.ZodNumber>;
743
+ }, z.core.$strict>>>;
688
744
  ruleOffers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
689
745
  kind: z.ZodLiteral<"single">;
690
746
  rule: z.ZodString;
691
747
  match: z.ZodEnum<{
748
+ name: "name";
692
749
  path: "path";
693
750
  exact: "exact";
694
751
  prefix: "prefix";
695
752
  wildcard: "wildcard";
696
753
  subpath: "subpath";
754
+ name_prefix: "name_prefix";
697
755
  }>;
698
756
  command: z.ZodString;
699
757
  }, z.core.$strict>, z.ZodObject<{
@@ -702,11 +760,13 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
702
760
  kind: z.ZodLiteral<"command">;
703
761
  rule: z.ZodString;
704
762
  match: z.ZodEnum<{
763
+ name: "name";
705
764
  path: "path";
706
765
  exact: "exact";
707
766
  prefix: "prefix";
708
767
  wildcard: "wildcard";
709
768
  subpath: "subpath";
769
+ name_prefix: "name_prefix";
710
770
  }>;
711
771
  command: z.ZodString;
712
772
  segment: z.ZodString;
@@ -765,8 +825,8 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
765
825
  }, z.core.$strict>>>;
766
826
  personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
767
827
  }, z.core.$strict>>;
768
- askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
769
- classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
828
+ askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
829
+ classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
770
830
  fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
771
831
  sourceTaskId: z.ZodOptional<z.ZodString>;
772
832
  sourceAgentName: z.ZodOptional<z.ZodString>;
@@ -807,9 +867,6 @@ export interface ApprovalCardSource {
807
867
  /** E-14:bidi 在场位 —— 与 wire 帧**同一份素材**(`ToolApprovalFrame` 结构上满足本接口)⇒ live 帧 /
808
868
  * `approval_request` / `card_json` / 重放帧四面同源,不是四处各扫一遍。 */
809
869
  inputHasBidi?: true;
810
- /** [ref](core 5.25.0):被越级的持久规则原文 —— **已 redactSecrets**(发帧点做,本模块只 clip)。
811
- * 与 wire 帧**同一份素材**(`ToolApprovalFrame` 结构上满足本接口)⇒ live 帧 / `card_json` / 重放帧三面同源。 */
812
- persistedRuleShadowed?: string;
813
870
  /** [ref](core 5.58.0):引擎铸的「不再询问」OFFER(**只在规则店装配时**由发帧点填;语义与在场性契约见
814
871
  * `ApprovalCardSchema.ruleOffers`)。与 wire 帧**同一份素材** ⇒ live 帧 / `card_json` / 重放帧
815
872
  * 三面同源。 */
@@ -942,6 +999,13 @@ export declare function buildRevokeFrame(batchId: string, askIds: readonly strin
942
999
  * 竞争者;收敛是车2 的窗到期竞争者与车5 恢复扫描的职责)。
943
1000
  */
944
1001
  export declare function buildReplayFrame(row: AskRow, nowMs: number): ApprovalRequestFrame | undefined;
1002
+ /**
1003
+ * S-1154 —— 持久行上那张卡**要不要人**:卡面 `risk.requiresRealApproval`(铸卡时取自引擎在 `AskRequest` 上盖的同一位,
1004
+ * {@link buildApprovalCard} 第三参)。读者 = 耐久 ask 回决口在裁决之前判「策略的放行」(`host-decision.ts` 的 `policyCannotAllow`)。
1005
+ * 🔴 读不出卡(`card_json` 形不合)⇒ **按要人读**(fail-closed):这一位只用来**拒**策略的放行,读坏的行上拒一次可以改成人答 / 策略拒
1006
+ * 再来;反方向(读坏当不要人)会让一次引擎终将拒掉的放行先落成一条宣称 approve 的行。
1007
+ */
1008
+ export declare function storedCardDemandsAPerson(cardJson: unknown): boolean;
945
1009
  /** {@link buildApprovalPreamble} 的返回形——帧 + 两个**计数**(调用方按自己的 logger 记 warn;本模块
946
1010
  * 保持纯函数,不吃 logger:那会让一个 `build*` 捕获行为)。 */
947
1011
  export interface ApprovalPreamble {
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, isAskClass, isAskOrigin, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
2
+ import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, STEER_REPLAY_FACETS, isAskClass, isAskOrigin, isAutoModeFallbackCause, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
3
3
  import { redactSecrets } from "./trace/redact.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
5
  import { PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS } from "./permission-rule-vocab.js";
@@ -211,6 +211,28 @@ const RuleEvidenceEnvelopeSchema = z.object({
211
211
  })
212
212
  .optional(),
213
213
  });
214
+ export const MAX_ALLOW_RULE_SHADOW_ENTRIES = 32;
215
+ const ALLOW_RULE_MEMBER_SET = new Set(ALLOW_RULE_MEMBERS);
216
+ export function readAllowRuleShadowed(req) {
217
+ const raw = req !== null && typeof req === "object" ? req.allowRuleShadowed : undefined;
218
+ if (!Array.isArray(raw) || raw.length === 0 || raw.length > ALLOW_RULE_MEMBERS.length)
219
+ return undefined;
220
+ const list = raw;
221
+ const out = [];
222
+ for (const r of list) {
223
+ if (r === null || typeof r !== "object")
224
+ return undefined;
225
+ const { member, entries, omitted } = r;
226
+ if (!ALLOW_RULE_MEMBER_SET.has(member) || !Array.isArray(entries) || !entries.every((e) => typeof e === "string"))
227
+ return undefined;
228
+ if (omitted !== undefined && !(typeof omitted === "number" && Number.isInteger(omitted) && omitted > 0))
229
+ return undefined;
230
+ const shown = entries.slice(0, MAX_ALLOW_RULE_SHADOW_ENTRIES).map((e) => redactSecrets(e).slice(0, MAX_RULE_TEXT_CHARS));
231
+ const extra = entries.length - shown.length + (omitted ?? 0);
232
+ out.push({ member: member, entries: shown, ...(extra > 0 ? { omitted: extra } : {}) });
233
+ }
234
+ return out;
235
+ }
214
236
  export function readRuleEvidence(req) {
215
237
  const parsed = RuleEvidenceEnvelopeSchema.safeParse(req);
216
238
  const raw = parsed.success ? parsed.data.ruleEvidence : undefined;
@@ -292,9 +314,15 @@ export function readClosedWordSeat(carrier, seat) {
292
314
  recordFailOpen("server.approval-card.closed-word-out-of-set", `${seat}=${outOfSetDetail(raw)}`);
293
315
  return undefined;
294
316
  }
317
+ function isSteerReplayDiffers(v) {
318
+ const facets = STEER_REPLAY_FACETS;
319
+ return Array.isArray(v) && v.length > 0 && v.every((f) => facets.includes(f));
320
+ }
295
321
  const CLOSED_WORD_SEAT_GUARDS = {
296
322
  mandate: isPersistedRuleMandate,
297
323
  origin: isAskOrigin,
324
+ classifierNoRuling: isAutoModeFallbackCause,
325
+ differs: isSteerReplayDiffers,
298
326
  };
299
327
  export function readAskClassPair(carrier) {
300
328
  const askClass = "askClass" in carrier ? carrier.askClass : undefined;
@@ -356,7 +384,17 @@ export const ApprovalCardSchema = z
356
384
  governanceForced: z.literal(true).optional(),
357
385
  rememberRefused: z.literal(true).optional(),
358
386
  inputHasBidi: z.literal(true).optional(),
359
- persistedRuleShadowed: z.string().max(MAX_RULE_TEXT_CHARS).optional(),
387
+ allowRuleShadowed: z
388
+ .array(z
389
+ .object({
390
+ member: z.enum(ALLOW_RULE_MEMBERS),
391
+ entries: z.array(z.string().max(MAX_RULE_TEXT_CHARS)).max(MAX_ALLOW_RULE_SHADOW_ENTRIES),
392
+ omitted: z.number().int().positive().optional(),
393
+ })
394
+ .strict())
395
+ .min(1)
396
+ .max(ALLOW_RULE_MEMBERS.length)
397
+ .optional(),
360
398
  ruleOffers: z.array(RuleOfferSchema).max(MAX_RULE_OFFERS).optional(),
361
399
  ruleOffersAbsence: RuleOffersAbsenceSchema.optional(),
362
400
  denialLimitFallback: DenialLimitFallbackSchema.optional(),
@@ -416,7 +454,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
416
454
  const toolCallId = clip(source.toolCallId, MAX_IDENT);
417
455
  const sourceTaskId = clip(source.sourceTaskId, MAX_IDENT);
418
456
  const sourceAgentName = clip(source.sourceAgentName, MAX_AGENT_NAME);
419
- const shadowedRule = clip(source.persistedRuleShadowed, MAX_RULE_TEXT_CHARS);
457
+ const allowRuleShadowed = readAllowRuleShadowed(req);
420
458
  return {
421
459
  toolName: clip(source.toolName, MAX_IDENT) ?? "",
422
460
  message: clip(source.message, MAX_MESSAGE) ?? "",
@@ -430,7 +468,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
430
468
  ...(source.governanceForced === true ? { governanceForced: true } : {}),
431
469
  ...(source.rememberRefused === true ? { rememberRefused: true } : {}),
432
470
  ...(source.inputHasBidi === true ? { inputHasBidi: true } : {}),
433
- ...(shadowedRule !== undefined && shadowedRule !== "" ? { persistedRuleShadowed: shadowedRule } : {}),
471
+ ...(allowRuleShadowed !== undefined ? { allowRuleShadowed } : {}),
434
472
  ...(probeCause !== undefined ? { probeCause } : {}),
435
473
  ...(ruleEvidence !== undefined ? { ruleEvidence } : {}),
436
474
  ...(source.ruleOffers !== undefined && source.ruleOffers.length > 0 ? { ruleOffers: source.ruleOffers.map(copyRuleOffer) } : {}),
@@ -488,6 +526,10 @@ export function buildReplayFrame(row, nowMs) {
488
526
  approvalId: parsed.data.approvalId,
489
527
  };
490
528
  }
529
+ export function storedCardDemandsAPerson(cardJson) {
530
+ const parsed = ApprovalCardEnvelopeSchema.safeParse(cardJson);
531
+ return !parsed.success || parsed.data.card.risk.requiresRealApproval;
532
+ }
491
533
  export function buildApprovalPreamble(rows, nowMs, replayMax) {
492
534
  const frames = [];
493
535
  let skipped = 0;
@@ -52,7 +52,7 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
52
52
  readonly requirePrincipal: boolean;
53
53
  }): boolean;
54
54
  /**
55
- * 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)。**全仓唯一一份**,两处调用、处置不同:
55
+ * 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)。**全仓唯一一份**,三处调用、处置不同:
56
56
  * · **boot**(`boot/stage-07-capability-layer.ts`):对装配完的整份 config 判,拒因 ⇒ **拒启**(全窗复审 D3-F1,
57
57
  * HIGH;与 env 墓碑族同谱系)。v4.3.0 的轮询门形(APPROVAL_REQUIRE + DB backend + DURABLE_APPROVAL 未设)在
58
58
  * 5.0.0 只剩 core 每任务 warn——**原先拦、现在放**(方向反转)。「留 undefined 让 core warn」对新配置是
@@ -60,6 +60,9 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
60
60
  * · **热路径**(S-668 波 2 ④,`config-center/apply-effective.ts` 的审批组 stage):对**候选视图**
61
61
  * (活配置 + 候选名单)判,拒因 ⇒ 审批组**整组拒**、活配置零变化、世代账停旧代。进程在跑,拒启不是选项;
62
62
  * 而放行一份「没有 checkpoint 店可停车」的名单 = 单用户 auto-accept 基线仍在、名单静默不生效。
63
+ * · **每个任务的装配**(S-1144,`boot/resolve-spec.ts` 的 `resolveSpec` 头一道):对**活配置**判,拒因 ⇒ 请求 501
64
+ * `capability.checkpoint_store_required`。部署形到不了(boot 已拒启);可达的是嵌入方装配 / 直调 `resolveSpec`(自己递 ctx、没经 stage-07)。
65
+ * 修前这一形把审批基线静默铸成 `undefined`,请求的 allow 清「普通问」后任务零卡落盘 —— 同一条规则在起服层拒、在装配层静默 = 一事两读。
63
66
  * `checkpointStorePresent` 是**部署事实**(本进程建没建出 checkpoint 店),不在 `ServiceConfig` 里 ⇒ 调用方显式递。
64
67
  * 放这文件与 hasOperatorGateIntent/inv#2 同源(意图判据再漂要同时改两段)。
65
68
  */
@@ -134,17 +137,6 @@ export interface DurableAskOptions {
134
137
  deny?: string[];
135
138
  autoBudget?: number;
136
139
  neverAuto?: string[];
137
- /** Per-session approval-exemption probe ("本会话不再询问"): consulted ONLY for require-listed
138
- * tools, AFTER deny/neverAuto (both always win) and BEFORE the budget path. Canonical-space toolName.
139
- * A rejected promise is treated as NOT exempt (fail-closed → ask) at the call site below.
140
- * 🔴 S-877 候裁 16:会话授权**两个读位、一只店、按问句的作者分**(收车档 ⑩ 16):本探针兑现**本仓自己的问**(名单门)
141
- * —— 在它自己的层上「不问」,于是委派子代经父约束链继承到的同一问也不问;引擎自装的问(模式写门 / 形状层)由审批席
142
- * (`ToolApprovalCoordinator.standingGrantSettles`)兑现。本探针**不能**退役:子代的继承问到达祖先审批席时 core 盖
143
- * `mandated`(`ruleClearanceOf` 的 inheritedUnresolved / ancestorResolved 门),席的判据依约不退役它 —— 只有本层的
144
- * 「不问」够得着继承链(钉 test/parked-decide-leg.test.ts「[候裁② 修]remember 全链行为」)。 */
145
- exempt?: (canonicalToolName: string) => Promise<boolean>;
146
- /** Audit hook — fired when an exemption short-circuits the ask (the `approval_exempted` log line). */
147
- onExempted?: (canonicalToolName: string, rawToolName: string) => void;
148
140
  }
149
141
  export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
150
142
  //# sourceMappingURL=approval.d.ts.map
package/dist/approval.js CHANGED
@@ -4,7 +4,6 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
4
4
  import { isExplicitPosture } from "./posture-source.js";
5
5
  import { handsOnWorkerFilePlane } from "./execution-lane-caps.js";
6
6
  import { heldRuleName } from "./tool-rule-names.js";
7
- import { answerGrantsBeyondCall } from "./standing-answer-grant.js";
8
7
  export function hasApprovalListIntent(config) {
9
8
  return (config.approvalRequire.length > 0 ||
10
9
  config.approvalDeny.length > 0 ||
@@ -93,33 +92,12 @@ export function createDurableAskPolicy(opts) {
93
92
  if (neverAutoHit !== undefined)
94
93
  return operatorAlwaysHumanAsk(`APPROVAL_NEVER_AUTO(${neverAutoHit})`, `human approval required to run "${req.toolName}"`);
95
94
  const requireHit = heldRuleName(req, require);
96
- if (requireHit !== undefined) {
97
- const remEarly = req.budget?.resourceRemainingMicroUsd;
98
- if (remEarly !== undefined && remEarly <= 0) {
99
- return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
100
- }
101
- if (opts.exempt && heldRuleName(req, isQuestionTool) === undefined && !answerGrantsBeyondCall(req)) {
102
- return (async () => {
103
- let exempted = false;
104
- try {
105
- exempted = (await opts.exempt(req.toolName)) === true;
106
- }
107
- catch {
108
- exempted = false;
109
- }
110
- if (exempted) {
111
- opts.onExempted?.(req.toolName, req.toolName);
112
- return grantedByRule();
113
- }
114
- return decideRequired(req, requireHit);
115
- })();
116
- }
117
- return decideRequired(req, requireHit);
118
- }
95
+ if (requireHit !== undefined)
96
+ return decideRequired(req, operatorAsk(`APPROVAL_REQUIRE(${requireHit})`, `approval required to run "${req.toolName}"`));
119
97
  return { action: "allow" };
120
98
  },
121
99
  };
122
- function decideRequired(req, requireHit) {
100
+ function decideRequired(req, ask) {
123
101
  const rem = req.budget?.resourceRemainingMicroUsd;
124
102
  if (rem !== undefined && rem <= 0) {
125
103
  return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
@@ -128,7 +106,7 @@ export function createDurableAskPolicy(opts) {
128
106
  autoApproved++;
129
107
  return grantedByRule();
130
108
  }
131
- return operatorAsk(`APPROVAL_REQUIRE(${requireHit})`, `approval required to run "${req.toolName}"`);
109
+ return ask;
132
110
  }
133
111
  }
134
112
  //# sourceMappingURL=approval.js.map
@@ -1,4 +1,4 @@
1
- import { createBrain, createDegradeRouteWatch } from "../brain.js";
1
+ import { createBrainAssembly } from "../brain.js";
2
2
  import { ModelUsageTracker, PromptManifestTracker, buildPricing, createSideQueryAccountant, createTracer } from "../budget.js";
3
3
  import { FleetUsageAccumulator } from "../fleet-client.js";
4
4
  import { createFleetLeaseFromEnv } from "../fleet-lease.js";
@@ -8,8 +8,7 @@ import { buildQuotaBounds } from "./limit-sync.js";
8
8
  import { assembleFileHistory } from "../file-history-capture.js";
9
9
  export function createBudgetAndTracing(ctx) {
10
10
  const { config, logger, metrics, backend, breakerState } = ctx;
11
- const brain = createBrain(config, { breakerState });
12
- const degradeRouteWatch = createDegradeRouteWatch(config);
11
+ const { brain, degradeRoute: degradeRouteWatch } = createBrainAssembly(config, { breakerState });
13
12
  const pricing = buildPricing(config.models);
14
13
  const counterDegradeHook = (info) => {
15
14
  metrics.setGauge("counter_flush_fail_streak", info.streak, { table: info.table, kind: info.kind });
@@ -63,8 +63,8 @@ export interface ConfigCenterRuntime {
63
63
  * CLI 之后不再有刷新拍,它继续用纯判据判一次)。
64
64
  * `consolidationSeat`(S-668 波 0,过渡)= 整理驱动席的两侧读数口,喂 `memory-consolidation` 重启片;
65
65
  * 缺席 = 阀门关着(没有 boot 烤死的席)。
66
- * `degradeRoute`(S-794,**必填**)= 反应式降级壳的两侧读数口(brain.ts `createDegradeRouteWatch`,与 createBrain 同一时刻
67
- * 捕获),喂 `degrade-route` 重启片。必填而不是可选:车道没开 / 没焊壳由席自己答「两侧同为 null」,缺席没有合法含义 ——
66
+ * `degradeRoute`(S-794,**必填**)= 反应式降级壳的两侧读数口(brain.ts `createBrainAssembly` 的产物 `degradeRoute`,`baked` 在焊壳处
67
+ * 算好随装配交出),喂 `degrade-route` 重启片。必填而不是可选:车道没开 / 没焊壳由席自己答「两侧同为 null」,缺席没有合法含义 ——
68
68
  * 可选就是一条「接线漏了 ⇒ 片永远不签」的静默路([ref])。
69
69
  * `checkpointStorePresent`(S-668 波 2,**必填**)= 部署事实「本进程建没建出 checkpoint 店」(stage-06 的产物,
70
70
  * 不在 ServiceConfig 里)。审批名单转热之后,热腿要用它判 ④「门意图不可服务」(与 boot 拒启同一只判据);
@@ -19,7 +19,7 @@ import { centerManagedConfigKeys } from "../config-center/apply-effective.js";
19
19
  import { createConfigProvider, raceBootFetch, serviceConfigSourceKind, BOOT_FETCH_DEFERRED } from "../config-provider.js";
20
20
  import { createKeyResolver } from "../key-resolver.js";
21
21
  import { buildSealedKeyPublicFace, ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
22
- import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, withModelPlaneOf, bootSnapshotOf, fullyLandedForLkg, fetchPromptArtifact } from "../config-center/facade.js";
22
+ import { applyEffective, applyCenterReadFace, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, withModelPlaneOf, fullyLandedForLkg, fetchPromptArtifact } from "../config-center/facade.js";
23
23
  import { createMcpRevocationLedger, enabledMcpEntries } from "../config-center/mcp-revocation.js";
24
24
  import { SHA256_HEX_RE } from "../digest-form.js";
25
25
  import { BOOT_REJUDGE_OF_REFUSED_GROUP, createConfigApplyLedger, modelPlaneCommitted, refusedGroups } from "../config-center/apply-ledger.js";
@@ -422,7 +422,7 @@ export async function createConfigCenterRuntime(ctx) {
422
422
  const lkgPlane = modelPlaneCommitted(lkgReport);
423
423
  if (lkgPlane)
424
424
  markRosterLanded(lkgR.effective);
425
- effective = bootSnapshotOf(lkgR.effective, lkgPlane ? lkgR.effective : undefined);
425
+ effective = lkgR.effective;
426
426
  if (lkgPlane)
427
427
  appliedPlaneEff = lkgR.effective;
428
428
  if (fullyLandedForLkg(lkgR, lkgReport)) {
@@ -504,7 +504,7 @@ export async function createConfigCenterRuntime(ctx) {
504
504
  }
505
505
  if (bootPlaneEff !== undefined)
506
506
  markRosterLanded(bootPlaneEff);
507
- effective = bootSnapshotOf(r.effective, bootPlaneEff);
507
+ effective = r.effective;
508
508
  if (bootPlaneEff !== undefined)
509
509
  appliedPlaneEff = bootPlaneEff;
510
510
  if (bootClean)
@@ -858,8 +858,7 @@ export async function createConfigCenterRuntime(ctx) {
858
858
  await adoptCenterPrompts(r.effective, "refresh");
859
859
  if (tickPlane)
860
860
  markRosterLanded(r.effective);
861
- const fullyApplied = applyReport?.fullyApplied !== false;
862
- if (!fullyApplied) {
861
+ if (!fullyLandedForLkg(r, applyReport)) {
863
862
  ccEtag = undefined;
864
863
  const refused = applyReport ? refusedGroups(applyReport) : [];
865
864
  logger.warn("config_candidate_partially_applied", {
@@ -972,8 +971,7 @@ export async function createConfigCenterRuntime(ctx) {
972
971
  await adoptCenterPrompts(r.effective, "boot-deferred");
973
972
  if (latePlane)
974
973
  markRosterLanded(r.effective);
975
- const fullyAppliedLate = applyReportLate?.fullyApplied !== false;
976
- if (!fullyAppliedLate) {
974
+ if (!fullyLandedForLkg(r, applyReportLate)) {
977
975
  ccEtag = undefined;
978
976
  const refusedLate = applyReportLate ? refusedGroups(applyReportLate) : [];
979
977
  logger.warn("config_candidate_partially_applied", {
@@ -11,10 +11,6 @@ export interface ParkedReviveGateConfigView extends DeploymentGovernanceConfigVi
11
11
  /** host 腿裁决 env 的 cwd 占位根(见下方 `hostGateCwd`)。 */
12
12
  readonly localDataRoot?: ServiceConfig["localDataRoot"];
13
13
  }
14
- /** 会话豁免探针店的所需切面(canonical toolName 键空间;`StoreBackend.approvalExemption()` 结构满足)。 */
15
- export interface ApprovalExemptionProbe {
16
- has(sessionId: string, toolName: string): Promise<boolean>;
17
- }
18
14
  export interface ParkedReviveGateDeps {
19
15
  /** ⚠️ **活引用**:热改字段(autonomy/commandPolicy/守卫集/审批四旋钮)每次赎回现读,见下方「禁 memoize」。 */
20
16
  readonly config: ParkedReviveGateConfigView;
@@ -47,7 +43,6 @@ export interface ParkedReviveGateDeps {
47
43
  * headless auto-deny,比「再问人一次」严且哑。交了之后最坏也是 park,方向 fail-safe。
48
44
  */
49
45
  readonly approverSeat: RunnerDepsOnAsk | undefined;
50
- readonly approvalExemptionStore: ApprovalExemptionProbe | undefined;
51
46
  /**
52
47
  * [ref] —— core `RunnerDeps.runtimeCapsResolver` 的**同一只**(main.ts 的 `runtimeCapsResolver`,
53
48
  * 单一属主同 `boot/runtime-caps.ts`)。重建条目的第三位决议链元数据 `autoModeArmed` 的唯一判据是
@@ -69,7 +64,6 @@ export interface ParkedReviveGateDeps {
69
64
  * 这一座可改读它 —— 接线不在本次提货单内,见 7.106.0 收车档「未闭环」。 */
70
65
  readonly parentAutoModeIntent?: ((row: BackgroundAgentRecord) => boolean) | undefined;
71
66
  readonly logger: {
72
- info(event: string, fields?: Record<string, unknown>): void;
73
67
  warn(event: string, fields?: Record<string, unknown>): void;
74
68
  };
75
69
  /** host 腿 cwd 占位的落地根(main.ts 的 `localRoot`;`config.localDataRoot` 优先)。 */
@@ -96,7 +90,7 @@ export type RebuiltParentConstraint = NonNullable<RebuiltInheritedGate["parentCo
96
90
  * 赎回腿的父约束链重建([ref] 件二)。
97
91
  *
98
92
  * 语义:**同/跨副本一致地重建「部署 ⊇ 操作员」两层完整链**——审批基线(durable question 门 + F4 高危写
99
- * 审批门 + 会话豁免探针)作 base 的 `toolPolicy` 座,经**折叠属主** `applyRuntimeGovernance`
93
+ * 审批门)作 base 的 `toolPolicy` 座,经**折叠属主** `applyRuntimeGovernance`
100
94
  * (→ core `tightenTaskSpec`)叠上部署治理段(autonomy / commandPolicy / MANUAL_MODE_SHELL_GATE /
101
95
  * 守卫集),取其 `toolPolicy` 装进单层 `parentConstraints`。
102
96
  *