@sema-agent/server 7.117.0 → 7.119.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 (159) hide show
  1. package/MIGRATION.md +182 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +58 -28
  5. package/deploy/sema-up/README.md +2 -0
  6. package/deploy/sema-up/chart/templates/minio.yaml +2 -1
  7. package/deploy/sema-up/chart/templates/server-v4pro.yaml +1 -0
  8. package/deploy/sema-up/chart/templates/server.yaml +1 -0
  9. package/deploy/sema-up/chart/values.yaml +7 -1
  10. package/deploy/sema-up/cluster-up.sh +20 -8
  11. package/deploy/sema-up/kube-up.sh +29 -16
  12. package/deploy/sema-up/lib/buckets.sh +21 -0
  13. package/deploy/sema-up/lib/health.sh +33 -0
  14. package/deploy/sema-up/sema-up.sh +14 -9
  15. package/deploy/sema-up/smoke.sh +16 -6
  16. package/deploy/sema-up/stack/compose.yaml +1 -1
  17. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -1
  18. package/dist/approval-ask-audit-store.js +2 -7
  19. package/dist/approval-card.d.ts +40 -10
  20. package/dist/approval-card.js +11 -1
  21. package/dist/approval.d.ts +55 -17
  22. package/dist/approval.js +74 -33
  23. package/dist/audit.d.ts +12 -1
  24. package/dist/audit.js +62 -2
  25. package/dist/auto-mode-face.d.ts +2 -3
  26. package/dist/bake-runner/main.js +1 -6
  27. package/dist/bake-runner/protocol.d.ts +18 -0
  28. package/dist/bake-runner/protocol.js +22 -2
  29. package/dist/bake-runner/runner.d.ts +12 -8
  30. package/dist/bake-runner/runner.js +5 -9
  31. package/dist/boot/config-center.js +1 -1
  32. package/dist/boot/coordinators.js +4 -1
  33. package/dist/boot/device-lane.d.ts +3 -3
  34. package/dist/boot/device-lane.js +1 -2
  35. package/dist/boot/leader.d.ts +4 -4
  36. package/dist/boot/leader.js +1 -2
  37. package/dist/boot/parked-revive-gate.d.ts +4 -6
  38. package/dist/boot/parked-revive-gate.js +2 -6
  39. package/dist/boot/resolve-spec.js +9 -11
  40. package/dist/boot/runner-deps.js +2 -2
  41. package/dist/boot/stage-07-capability-layer.js +7 -3
  42. package/dist/boot/stage-10-http-server.js +3 -2
  43. package/dist/boot/stores.js +12 -7
  44. package/dist/capabilities/center-plugins.d.ts +2 -0
  45. package/dist/capabilities/center-plugins.js +24 -6
  46. package/dist/capabilities/code-review-council.js +8 -11
  47. package/dist/capabilities/hands-lane.d.ts +25 -0
  48. package/dist/capabilities/hands-lane.js +1 -1
  49. package/dist/capabilities/mcp-probe.d.ts +2 -2
  50. package/dist/capabilities/scenarios.d.ts +34 -7
  51. package/dist/capabilities/scenarios.js +33 -6
  52. package/dist/config-catalog.js +3 -3
  53. package/dist/config.d.ts +14 -18
  54. package/dist/config.js +15 -26
  55. package/dist/deployment-governance.d.ts +5 -7
  56. package/dist/deployment-governance.js +4 -5
  57. package/dist/host-decision.d.ts +114 -31
  58. package/dist/host-decision.js +39 -2
  59. package/dist/http/admission.js +12 -6
  60. package/dist/http/approval-sweeps.js +1 -1
  61. package/dist/http/mcp-dial-deadline.d.ts +35 -0
  62. package/dist/http/mcp-dial-deadline.js +21 -0
  63. package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
  64. package/dist/http/memory-compliance-failure-reply.js +17 -8
  65. package/dist/http/memory-store-refusal-reply.d.ts +14 -11
  66. package/dist/http/memory-store-refusal-reply.js +16 -5
  67. package/dist/http/resume-legs.js +8 -3
  68. package/dist/http/routes/approvals-assistant.d.ts +25 -3
  69. package/dist/http/routes/approvals-assistant.js +27 -26
  70. package/dist/http/routes/capabilities.js +6 -3
  71. package/dist/http/routes/mcp-reconnect.d.ts +17 -0
  72. package/dist/http/routes/mcp-reconnect.js +6 -1
  73. package/dist/http/routes/memory-bundle.js +1 -1
  74. package/dist/http/routes/memory-compliance.js +1 -1
  75. package/dist/http/routes/memory-origin.d.ts +1 -1
  76. package/dist/http/routes/memory-origin.js +1 -1
  77. package/dist/http/routes/runs.js +47 -33
  78. package/dist/http/routes/sessions.d.ts +1 -1
  79. package/dist/http/routes/sessions.js +23 -22
  80. package/dist/http/routes/workflows.js +2 -0
  81. package/dist/http/wire-types.d.ts +17 -13
  82. package/dist/images/manifest.d.ts +7 -1
  83. package/dist/images/manifest.js +18 -16
  84. package/dist/memory-store-refusal.d.ts +38 -18
  85. package/dist/memory-store-refusal.js +25 -7
  86. package/dist/model-unreachable-notice.d.ts +1 -1
  87. package/dist/namespaced-rule-name.d.ts +46 -41
  88. package/dist/namespaced-rule-name.js +36 -22
  89. package/dist/observability/corrupt-read-seat.d.ts +4 -0
  90. package/dist/observability/corrupt-read-seat.js +1 -0
  91. package/dist/observability/fail-open.d.ts +19 -3
  92. package/dist/observability/fail-open.js +19 -3
  93. package/dist/operator-ask.d.ts +6 -2
  94. package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
  95. package/dist/orchestration/workflow-agent-session-index.js +80 -14
  96. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
  97. package/dist/orchestration/workflow-completion-inbox.js +39 -17
  98. package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
  99. package/dist/orchestration/workflow-notify-journal.js +7 -2
  100. package/dist/outbound-dispatcher.d.ts +29 -20
  101. package/dist/outbound-dispatcher.js +105 -16
  102. package/dist/parked-decide.d.ts +43 -48
  103. package/dist/parked-decide.js +54 -16
  104. package/dist/permission-rule-vocab.d.ts +4 -3
  105. package/dist/permission-rule-vocab.js +1 -1
  106. package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
  107. package/dist/plugins/approval-ask-store-sql.js +0 -3
  108. package/dist/plugins/approval-exemption-store.d.ts +4 -0
  109. package/dist/plugins/approval-exemption-store.js +1 -0
  110. package/dist/plugins/blob-backend.d.ts +13 -0
  111. package/dist/plugins/blob-backend.js +26 -0
  112. package/dist/plugins/local-session-store.d.ts +78 -47
  113. package/dist/plugins/local-session-store.js +152 -122
  114. package/dist/plugins/one-time-migrations.d.ts +11 -0
  115. package/dist/plugins/one-time-migrations.js +128 -4
  116. package/dist/plugins/pg-pool.js +1 -1
  117. package/dist/plugins/snapshot-bucket-presence.d.ts +36 -0
  118. package/dist/plugins/snapshot-bucket-presence.js +40 -0
  119. package/dist/plugins/store-backend.d.ts +17 -6
  120. package/dist/plugins/store-backend.js +46 -16
  121. package/dist/plugins/store-open-wait.d.ts +33 -0
  122. package/dist/plugins/store-open-wait.js +73 -0
  123. package/dist/plugins/tidb-pool.js +1 -1
  124. package/dist/plugins/web-search.d.ts +20 -1
  125. package/dist/plugins/web-search.js +39 -10
  126. package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
  127. package/dist/plugins/workflow-run-store-sql.js +5 -7
  128. package/dist/request-key-closure.js +1 -1
  129. package/dist/request-value-closure.d.ts +1 -1
  130. package/dist/rule-entry-list.d.ts +35 -46
  131. package/dist/rule-entry-list.js +18 -26
  132. package/dist/rules-consent.js +3 -0
  133. package/dist/run-local.js +5 -3
  134. package/dist/runs.d.ts +1 -1
  135. package/dist/security.d.ts +5 -3
  136. package/dist/security.js +4 -0
  137. package/dist/session-policy-wire.d.ts +13 -12
  138. package/dist/session-policy-wire.js +11 -11
  139. package/dist/spec-fields.d.ts +13 -11
  140. package/dist/spec-fields.js +4 -7
  141. package/dist/standing-answer-grant.d.ts +14 -2
  142. package/dist/standing-answer-grant.js +8 -1
  143. package/dist/store-posture.d.ts +14 -6
  144. package/dist/store-posture.js +7 -4
  145. package/dist/task-settings.d.ts +27 -55
  146. package/dist/task-settings.js +13 -21
  147. package/dist/tool-approval.d.ts +133 -138
  148. package/dist/tool-approval.js +175 -66
  149. package/dist/trace/core-keyset-guard.d.ts +5 -5
  150. package/dist/trace/redact.d.ts +6 -0
  151. package/dist/trace/redact.js +9 -9
  152. package/dist/trace/self-minted-wire.d.ts +16 -2
  153. package/dist/trace/self-minted-wire.js +7 -0
  154. package/dist/user-input-ledger.d.ts +30 -14
  155. package/dist/user-input-ledger.js +25 -14
  156. package/package.json +2 -2
  157. package/scripts/drain-check-local.mjs +74 -3
  158. package/scripts/drain-check.mysql.sql +43 -17
  159. package/scripts/drain-check.pg.sql +46 -20
@@ -1,6 +1,6 @@
1
- import type { HostDecidedBy, HostSettledBy } from "./host-decision.js";
1
+ import { type ApprovalDecidedBy, type HostSettledBy, type RetiredDecisionKeyFacts } from "./host-decision.js";
2
2
  import type { IncomingMessage } from "node:http";
3
- import { type AskClass, type AskRequest, type AskOutcome, type CheckpointGate, type PendingAction, type PersistedRuleMandate, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
3
+ import { type AskClass, type AskRequest, type AskOutcome, type PermissionResult, type CheckpointGate, type PendingAction, type PersistedRuleMandate, type ReadRootGrantCandidate, type RuleOffer, type AutoModeFallbackCause, type BoundSkillGrants } from "@sema-agent/core";
4
4
  import { type CardRulePersisted, type RuleConsentLane } from "./rules-consent.js";
5
5
  import { type AllowRuleShadowProjection, type DenialLimitFallback, type RuleOffersAbsence, type ApprovalRequestFrame, type ApprovalRevokeFrame, type RuleEvidenceProjection } from "./approval-card.js";
6
6
  import { type ApprovalAskStore, type AskRow } from "./plugins/approval-ask-store-sql.js";
@@ -8,6 +8,8 @@ import type { ApprovalAskAuditSink } from "./approval-ask-audit-store.js";
8
8
  import type { ParkCommitWatch } from "./plugins/park-commit-watch.js";
9
9
  import { type GovernanceAskMarks } from "./governance-ask-marks.js";
10
10
  import { type GovernancePosture } from "./runtime-governance.js";
11
+ import { type GrantBinding, type StandingAnswerGrantCarrier } from "./standing-answer-grant.js";
12
+ import { type ApprovalExemptionStore } from "./plugins/approval-exemption-store.js";
11
13
  /** [ref]:审批 gate kind 闭集(core gateMatch 的 `human`/`irreversible_ask` ↔ outcome.gate "policy_ask")。
12
14
  * 此前 7 份手写副本散在两只 checkpoint store 的数组/SQL 字面与 /decide 守卫——core 加审批味 kind 时
13
15
  * 全部静默漂移。core 无导出词表(全大写导出面零命中,2026-08-09 亲验),属主落此;SQL IN 片段从
@@ -56,13 +58,10 @@ export interface ParkedAskRedeemRequest {
56
58
  decision: "approve" | "deny";
57
59
  /** [ref] 同源的人写理由(deny 时 core 把它交给模型;allow 只进审计面)。 */
58
60
  note?: string;
59
- /** #1016:回决体自报的**结算来源**,原样过境到耐久腿的 `hostDecision.decidedBy`(缺席 ⇒ `"person"`)。
60
- * live 命中臂与本 PARKED 臂读**同一格** —— 同一份体落在哪条臂上只取决于副本与时序。
61
- * 型 = `string`(本层证得出的全部);判词的是耐久座的属主 core,cast 在 `hostDecisionFacts` 那一处。
62
- * ⚠️ 两座的**词表并不相同**(live = `human`/`timeout`/`policy`,耐久 = `person`/`sla_timeout`/`policy`,
63
- * 只在 `policy` 上相交)—— 这正是这条 wire 键只开 `"policy"` 一个词的原因,也是它不能声明成其中任何
64
- * 一只闭集的原因:同一个串要落到两个不同词表的座上。 */
65
- settledBy?: string;
61
+ /** S-1154:决定体的**出处位**(已过 `readDecidedBy` 的 wire 词,缺席已落成 `"person"`),经 `hostDecisionFacts` 落到停驻座的
62
+ * `hostDecision.decidedBy`。live 命中臂与本 PARKED 臂读**同一格** —— 同一份体落在哪条臂上只取决于副本与时序;两臂各走自己座的
63
+ * 那一只映射(live = `liveSettledBy`,停驻 = 恒等),词表只有一份。 */
64
+ decidedBy: ApprovalDecidedBy;
66
65
  /** [ref] ctrl+g 编辑放行的实参整体替换(approve 才有意义)。 */
67
66
  updatedInput?: unknown;
68
67
  /** 发起本次 respond 的**已验证**调用方(live 腿 `gatedPrincipal` 的那一把)。席在赎回之前拿它与
@@ -78,12 +77,30 @@ export type ParkedAskRedeem = (req: ParkedAskRedeemRequest) => Promise<{
78
77
  status: number;
79
78
  body: Record<string, unknown>;
80
79
  }>;
80
+ /** 阶梯里**重发**一把 claim 的墙钟上限(ms;首把用 `DURABLE_CALL_TIMEOUT_MS`)。🔴 codex 交叉复审 C5
81
+ * (2026-08-06 真缺陷):只数重试次数是**不够**的 —— 次数只约束「已经返回或已经 reject 的调用」,一次
82
+ * **挂住不返回**的店调用(DB 连接黑洞、池饿死)会让整个退避循环连一格都走不完,`onAsk` 的 promise 于是永久
83
+ * 悬挂 —— 正是这段代码要消灭的那个形。每把都与这个 deadline 显式 race,超时算一次 reject 继续阶梯;全部用尽
84
+ * 走意图投影。[ref] 前它给恢复读口的 `getAsk` 用,取值不变(轮询节奏)。 */
85
+ export declare const DURABLE_CONVERGE_READ_TIMEOUT_MS = 2000;
86
+ /** 这张卡上有没有名单自己的那一问:名单门问这只调用 ∧ 卡上带着名单那一问的类(名单门因豁免行没出问时,卡上的问是引擎自己的 —— 比如服务器工具的 `unstated`)。 */
87
+ export declare function carriesDeploymentListQuestion(deploymentListAsks: boolean, classes: readonly AskClass[] | undefined): boolean;
81
88
  /**
82
- * 一问身上与「站着的答案」有关的三个事实位 —— {@link standingAnswerMayRetire} 的全部入参。
89
+ * 本仓**策略层自己交出去的一问**的 {@link StandingAnswerFacts}。读者两个:部署名单门(`approval.ts`,`deploymentListQuestion: true`)与 workflow 问句门
90
+ * (`task-settings.ts`,`false`)—— 它们在交出这一问之前先读按工具名记的耐久豁免店(「本会话不再询问」在本层兑现,继承链上的同一问才够得着;审批席依约不退役
91
+ * 继承问),而**能不能读**与审批席 / 回决写侧是同一只判据({@link standingAnswerDurablyRecordable}):记得下的才代答,记不下的(带授予绑定的问 ……)不代答,
92
+ * 存量行也不例外 —— 一事一读。事实取自**这一问本身**:类集经 core 包根唯一的类派生 `classifyAsk`({@link NO_GATE_FACTS});`requiresRealApproval` /
93
+ * `mandated` 读这一问自报的成员;治理位恒假(本层不是治理层);授予绑定读调用(`grantBindingOf`)。
94
+ */
95
+ export declare function policyAskStandingAnswerFacts(req: StandingAnswerGrantCarrier, ask: Extract<PermissionResult, {
96
+ action: "ask";
97
+ }>, deploymentListQuestion: boolean): StandingAnswerFacts;
98
+ /**
99
+ * 一问身上与「站着的答案」有关的事实位 —— {@link standingAnswerHome} 的全部入参。
83
100
  *
84
- * 🔴 **三格全必填布尔**,刻意不做 `?: true` 的「只记真」形:判据哪天多一位,每个读者都要当场编译红,
101
+ * 🔴 **全必填**,刻意不做 `?: true` 的「只记真」形:判据哪天多一位,每个读者都要当场编译红,
85
102
  * 而不是漏传一格被静默读成 `false`(那是安全轴上的 fail-open)。读者各自从自己手里的形折成这三格,
86
- * 然后交**同一只** {@link standingAnswerMayRetire}(判据只有一份,折法各归读者):
103
+ * 然后交**同一只** {@link standingAnswerHome}(判据只有一份,折法各归读者):
87
104
  * · live 读侧取 `req` + 本地治理 peek;live 写侧取 pending 条目;
88
105
  * · 耐久 `/decide` 腿(S-663 → NP-1,7.100.0)取 park 行,经 {@link parkRowStandingAnswerFacts}(三格全从行上读)。
89
106
  * 本型**不绑** live 条目。
@@ -95,20 +112,38 @@ export interface StandingAnswerFacts {
95
112
  readonly requiresRealApproval: boolean;
96
113
  /** core 闸站盖的强制位([ref]):规则清不掉、站着的答案退不掉,只有对**这一次调用**的应答能答。 */
97
114
  readonly mandated: boolean;
98
- /** 7.116.0(审计修复批 S4,core 7.41.0 `Skill` 卡):这一问的应答**还授予**这一次调用之外的东西(批准 `Skill` = 激活技能 + 本 run 内
99
- * 清单免问)。站着的答案要代答它必须读得出授予绑定、且绑定相同;core 7.41.0 在活的问上不给绑定 ⇒ 两侧都读不出 ⇒ 不可记、不被代答。
100
- * 读者一律经 `standing-answer-grant.ts` 的 `answerGrantsBeyondCall`(唯一读口)折这一位。 */
101
- readonly grantsBeyondCall: boolean;
115
+ /** 这一问的应答**授不授予**这一次调用之外的东西、授予的话绑定是什么(批准引擎的 `Skill` = 激活技能 + 本 run 内清单免问)。
116
+ * `bound` ⇒ 站着的答案按「工具 + 绑定」记、只代答绑定相同的问(core 7.43.0 #1348 / #1357:活的问与停驻行同带 `boundGrantDigest`);
117
+ * `unreadable` ⇒ 不可记、不被代答(fail-closed)。读者一律经 `standing-answer-grant.ts` 的 `grantBindingOf`(唯一读口)折这一位。 */
118
+ readonly grantBinding: GrantBinding;
119
+ /** 引擎盖在这一问上的**类集**(`AskRequest.classes` / 停驻行孪生座;经 core 的屏 `screenAskClassMembers` 读)。`undefined` = 卡上没有类
120
+ * (老引擎 / 不盖类的站)或屏拒 —— 读不出的类不是「无类」。 */
121
+ readonly classes: readonly AskClass[] | undefined;
122
+ /**
123
+ * **问的属主**:这张卡上有没有部署审批名单(`APPROVAL_REQUIRE`)**自己的**那一问 —— 名单门(铸点)对这只调用出它的问 ∧ 卡上带着那一问的类
124
+ * (`carriesDeploymentListQuestion`;名单门的判词由 `approval.ts` 的 `deploymentListAsks` 读,不另造一张表)。名单的问是 server 铸的,它的站着的
125
+ * 答案记在 server 的会话豁免店、由名单门在出问**之前**读;其余每一问由引擎铸,引擎的类表裁它退不退得掉。
126
+ */
127
+ readonly deploymentListQuestion: boolean;
102
128
  }
103
129
  /**
104
- * 🔴 **S-660 —— 会话级放行的唯一判据:站着的答案能不能退掉这一问。** 纯谓词,三个读者:
105
- * · **读侧**(`askBroadcast` 的会话授权短路):`true` 才可能由既有 grant 代答,否则往下走真出卡;
106
- * · **写侧**(`finishRespond` 的 `grantable`):`true` 才可能把这张卡上的 `allow_session` 铸成 grant,
107
- * 否则只放行这一次、`rememberApplied:false`;
108
- * · **耐久 `/decide` 腿**(NP-1,`http/resume-legs.ts` 的 remember 可记性):入参由 {@link parkRowStandingAnswerFacts}
109
- * 从 park 行铸 —— `false` ⇒ 可记工具名 `null` ⇒ 放行本次、不落豁免、回执 `rememberApplied:false`。
110
- * 两臂读同一份事实、说同一句话:一问若不许被记住的放行答掉,它的应答也不许变成一条记住的放行 —— 否则
111
- * 同一只卡「重跑一遍」就被自己上一次的回答代答(test [ref] U1s-off 的真形)。
130
+ * 站着的答案(「本会话放行」/ 耐久 `remember:"session"`)对一问**记在哪、由谁读**(闭集;读者一律穷举):
131
+ * · `none` —— 退不掉这一问:不许被记住的放行答掉,它的应答也不许变成一条记住的放行(只放行这一次,`rememberApplied:false`);
132
+ * · `seat` —— **引擎铸的问**,引擎的规则车道清得掉它:审批席读进程内授权 / 耐久豁免店代答,`allow_session` 铸进程内授权,
133
+ * `/decide` 的 remember 落耐久豁免店(没有授予绑定时);
134
+ * · `server_store` —— **部署名单(`APPROVAL_REQUIRE`)自己的问**:它的答案只记在 server 的会话豁免店(按会话 × 工具名),由名单门在出问**之前**读;
135
+ * 审批席不代答它(问到了席上 = 店里没有),`allow_session` 不铸进程内授权、只经 {@link ToolApprovalCoordinator.recordDeploymentListAnswer} 落店。
136
+ */
137
+ export type StandingAnswerHome = "none" | "seat" | "server_store";
138
+ /**
139
+ * 🔴 **S-660 —— 会话级放行的唯一判据:站着的答案能不能退掉这一问,能的话它记在哪({@link StandingAnswerHome})。** 纯函数,读者:
140
+ * · **读侧**(`askBroadcast` 的会话授权短路 {@link ToolApprovalCoordinator.standingGrantSettles}):`seat` 才可能由既有授权代答,否则往下走真出卡;
141
+ * · **写侧**(`finishRespond` 的 `grantable` 与 `recordDeploymentListAnswer`):`seat` 把 `allow_session` 铸成进程内授权;`server_store` 落 server 的会话豁免店;
142
+ * `none` 只放行这一次、`rememberApplied:false`;
143
+ * · **卡面提示位**(活卡帧 / 条目 / `livePending` 行的 `rememberRefused`):在场 ⇔ `none`;
144
+ * · **耐久可记性**({@link standingAnswerDurablyRecordable}:`/decide` 的 remember、运维队列行、策略层两只豁免读面)。
145
+ * 各读者读同一份事实、说同一句话:一问若不许被记住的放行答掉,它的应答也不许变成一条记住的放行 —— 否则
146
+ * 同一只卡「重跑一遍」就被自己上一次的回答代答(test [ref] U1s-off 的真形)。读者侧没有任何按「问的属主」另判的臂:属主只在本函数里读一次。
112
147
  *
113
148
  * **为什么三位是同一类**(「站着的答案退不掉的一问」):会话授权 = **上一次**应答记下的一揽子放行,不是对
114
149
  * **这一次**调用的应答 —— 与持久 allow 规则同族,只是更短命(`askBroadcast` 短路处的注早已这么定性)。
@@ -132,11 +167,19 @@ export interface StandingAnswerFacts {
132
167
  * 存着落库那一刻的判定。(那张「行」是本仓的 ask 账本行,不是 core 的 park 行;core 7.31.0 #1079 起 park 行上的
133
168
  * `mandated` 孪生座由**耐久** `/decide` 腿读,见 {@link parkRowStandingAnswerFacts}。)
134
169
  */
135
- export declare function standingAnswerMayRetire(facts: StandingAnswerFacts): boolean;
170
+ export declare function standingAnswerHome(facts: StandingAnswerFacts): StandingAnswerHome;
171
+ /**
172
+ * **耐久**豁免店能不能记下这一问的答案 —— {@link standingAnswerHome} 的一个读者(不是第二只判据):`server_store` 记得住(那一臂本就要求没有授予绑定);
173
+ * `seat` 还得没有授予绑定 —— 耐久店按 `(会话, 工具名)` 记,没有绑定这一维,记下一张带绑定的答案就会代答同名工具的每一种绑定
174
+ * (`plugins/approval-exemption-store.ts`);`none` 记不住。读者:耐久 `/decide` 腿的 remember 可记性(`http/resume-legs.ts`)与运维队列行的
175
+ * `rememberRefused`(`http/routes/approvals-assistant.ts`)—— 两处同答;策略层的豁免读面(部署名单门、workflow 问句门)经本函数 + {@link policyAskStandingAnswerFacts}
176
+ * 决定读不读店。读侧同理:耐久店不代答带绑定的问(`standingGrantSettles` 经 `answerGrantsBeyondCall`)。
177
+ */
178
+ export declare function standingAnswerDurablyRecordable(facts: StandingAnswerFacts): boolean;
136
179
  /**
137
180
  * 🔴 **S-663 → NP-1(7.100.0 合并复审 [ref] 交叉表 #2)—— 耐久 `/decide` 腿的 {@link StandingAnswerFacts}:从 park 行铸三位。**
138
- * 纯投影,**不判**:判据是同一只 {@link standingAnswerMayRetire}(唯一读点 = `http/resume-legs.ts` 的 remember 可记性,
139
- * `standingAnswerMayRetire(parkRowStandingAnswerFacts(…))`)。修前耐久腿自成一只谓词、只读 `ruleOffersAbsence` 一词,同一行上
181
+ * 纯投影,**不判**:判据是同一只 {@link standingAnswerHome}(唯一读点 = `http/resume-legs.ts` 的 remember 可记性,
182
+ * `standingAnswerDurablyRecordable(parkRowStandingAnswerFacts(…))`)。修前耐久腿自成一只谓词、只读 `ruleOffersAbsence` 一词,同一行上
140
183
  * core 盖好的 `requiresRealApproval` 与治理出身都不读 ⇒ 那两类卡的 `remember:"session"` 照旧铸会话免询问,而 live 腿对同一张卡
141
184
  * 答 `false`(两腿同一个问题、两份事实覆盖;两腿复审同报)。三格各自的来源(全在**这一条**已属主校验的载入行上,不另读):
142
185
  * · `governanceForced` —— 行上的治理标:`gate.riskDescriptor.shellGateDoctrine` × 本部署治理姿态,经 **同一只**
@@ -163,7 +206,9 @@ export declare function standingAnswerMayRetire(facts: StandingAnswerFacts): boo
163
206
  */
164
207
  export declare function parkRowStandingAnswerFacts(pending: Extract<PendingAction, {
165
208
  kind: "tool_approval";
166
- }>, gate: CheckpointGate, governance: GovernancePosture | undefined): StandingAnswerFacts;
209
+ }>, gate: CheckpointGate, governance: GovernancePosture | undefined,
210
+ /** 部署名单门对这一行的调用出不出它自己的问(`approval.ts` 的 `deploymentListAsks`,调用方现读活配置;停驻行上只有 wire 名)。 */
211
+ deploymentListAsks: boolean): StandingAnswerFacts;
167
212
  /** A live approval frame delivered to whoever tails this run's stream. `type` IS the SSE event name (named-event
168
213
  * convention, same as question). The shell renders `tool_approval` as the CC three-choice card and dismisses on
169
214
  * `tool_approval_complete`. */
@@ -244,14 +289,14 @@ export interface ToolApprovalFrame {
244
289
  * (`ApprovalCardSchema` 没有这一位,`.strict()`)⇒ 断连重放的 `approval_request` 帧(`buildReplayFrame` 只回放卡)上它恒缺席,
245
290
  * 消费方读队列行 / 活卡帧 / `livePending` 行(8D-6:此前这里写的「`card_json` 只读 `AskRequest.mandated`」是错句,T4② 车OC 改真)。
246
291
  * 🔴 **server 不判「是不是强制」**(判定属主在 core 的闸站),只**读**闸站盖好的这一位 —— 读者恰一个:
247
- * S-660 起的会话级放行判据 {@link standingAnswerMayRetire}(会话授权是**上一次**应答记下的站着的答案,
292
+ * S-660 起的会话级放行判据 {@link standingAnswerHome}(会话授权是**上一次**应答记下的站着的答案,
248
293
  * 不是对这一次调用的应答 ⇒ 强制卡上既不被既有 grant 代答、也不铸 grant)。上一段「一揽子 `onAsk:"allow"`
249
294
  * 席照常答得了」说的是**这一次调用的应答者**,本仓不改它。
250
295
  */
251
296
  mandated?: true;
252
297
  /**
253
298
  * **7.116.0(审计修复批 S4;ADDITIVE,`"tool_approval"` only)—— 这张卡上的「本会话放行」只放行这一次、不会被记住。**
254
- * 值 = 同一只判据 {@link standingAnswerMayRetire} 的否定(四位:治理强制 / 必须真人 / 强制 / 应答还授予别的东西),回决侧写授权
299
+ * 在场 ⇔ 同一只判据 {@link standingAnswerHome} 答 `none`(治理强制 / 必须真人 / 强制 / 应答还授予别的东西 / 类集清不掉),回决侧写授权
255
300
  * (`finishRespond`)读的是同一份事实 ⇒ 帧说不可记 ⇔ 点了 `allow_session` 回执 `rememberApplied:false`。壳读这一位决定渲不渲
256
301
  * 「本会话放行」,不再从 `requiresRealApproval` / `mandated` / `governanceForced` 三位自己推断(那一推断漏掉第四个理由:core 7.41.0
257
302
  * 的 `Skill` 卡批准即授予清单,三位全无)。`card_json` 卡面、`livePending` 行、运维队列行同名同义。
@@ -311,6 +356,18 @@ export interface ToolApprovalFrame {
311
356
  /** S-934 ②:这一问属于的**全部**类(core `ASK_CLASSES` 序,`classes[0] === askClass`,非空)—— 读整只集合,别只读 {@link askClass}(一问可同属
312
357
  * 几类)。与 `askClass` 同在同缺、同一只窄读;逐字同序过境,不排序不去重。 */
313
358
  classes?: AskClass[];
359
+ /**
360
+ * core 7.43.0 #1348 / #1357(**ADDITIVE**,`"tool_approval"` only)—— 对引擎 `Skill` 工具的调用,批准它**还授予**的东西的摘要
361
+ * (`AskRequest.boundGrantDigest`,技能名 + 两只清单规范拼写的哈希);别的卡缺席。与停驻行 / inbox 行的同名位同值(core:同一只工厂铸,
362
+ * 活卡与它的停驻孪生按 `(toolCallId, boundGrantDigest)` 对账)。逐字过境,本仓不重算;站着的答案按「工具 + 它」记(S-1115)。
363
+ */
364
+ boundGrantDigest?: string;
365
+ /** 上一位哈希的那一份值:`{ skill, allowedTools, disallowedTools }`(`skill: null` = 调用没点名任何已载技能)。与摘要同在同缺;**部署文本**,
366
+ * 壳按上下文转义渲染(core:display metadata)。逐字过境。 */
367
+ boundGrants?: BoundSkillGrants;
368
+ /** core 7.43.0 #1353:分类器没给判词的成因词(`error` / `timeout` / `parse_error`;只在类 `classifier_no_ruling` 的卡上)。闭集经 core 的
369
+ * `readClosedWordSeat(req, "classifierNoRuling")` 窄读(筛 = core `isAutoModeFallbackCause`),集外 ⇒ 缺席 + 计一次。display:本仓不按它裁决。 */
370
+ classifierNoRuling?: AutoModeFallbackCause;
314
371
  /**
315
372
  * **[ref]**(core 7.19.0;**ADDITIVE**,`"tool_approval"` only)—— 这只**根外读** ask 的**清障目录**:
316
373
  * 把 `dir` 加进本会话的读目录(壳侧既有的 `/add-dir` 口),同一条调用就不会再问。
@@ -713,117 +770,33 @@ export declare const PERSIST_RULE_BATCH_EXCLUSIVE_ERROR = "persistRule.batchOffe
713
770
  * 指定 scope = 让一次「在项目 A 里点的同意」写成一条覆盖项目 B(或全局)的常驻放行 —— 那是这条轴上
714
771
  * 最贵的一次扩权。静默忽略同样不行:客户端会以为自己设上了。响亮拒,一句话说清谁拥有这一格。
715
772
  */
716
- /**
717
- * #1016 —— `settledBy` 与 allow 族**互斥**的那一句(两条回决腿共用一份文本:同一个体在两条口上必须
718
- * 拿到同一句话)。判的是**键在不在**,不是它是什么词。
719
- */
720
- /**
721
- * #1016 —— `settledBy` 的**形**拒句(两条回决腿共用一份文本,与 {@link SETTLED_BY_DENY_ONLY} 同姿势)。
722
- *
723
- * 🔴 **判形 ≠ 判词**:本层证得出的只有「它是个串」;「它是不是词表里的那个串」由**引擎**判(两条腿各有
724
- * 一处响亮拒,读数在收车档)。加这道形门的理由是**类型必须说真话**(wire 边界强类型宪法):
725
- * 一个非串值往下会落进 `AskOutcome.settledBy`(core 的串闭集)与本仓审计账本的 `settledBy?: string` 席 ——
726
- * 两处都声明成串,而运行期塞进去一个数字。引擎对它照样响亮拒(实测三形一致:`"bogus"` / `1` / `null`
727
- * 都是 `approver_contract` 的 fail-closed deny),所以这不是在补一个 fail-open,而是**不让本层的类型撒谎**;
728
- * 顺带把「一个非串永远不可能是闭集成员」这件必然的事拒在最早的地方,与同一只 parser 里 `note` /
729
- * `persistRule.rule` / `persistRule.edited` 三道既有形门**同族**(那三道在,只有本格没有 = 本格才是特例)。
730
- */
731
- export declare const SETTLED_BY_MUST_BE_STRING = "settledBy must be a string \u2014 the settlement source is one word from the engine's closed set, and this layer judges only the SHAPE (which word it is, the engine decides)";
732
- /**
733
- * #1016 / S-558 —— **live 座的那一次边界 cast,全仓只此一处**(耐久座的那一次在 `hostDecisionFacts` 里,
734
- * 一座一次)。它说的是「我把一个**未判词**的串放到只收词的座上」:判词的是 core —— `resolveAsk` 对词表外
735
- * 是 `approver_contract` 的响亮 fail-closed deny,不是静默当人拒(实测三形同判,特征钉在
736
- * `test/tool-approval.test.ts` 的 #1016 组)。本层判过的只有**形**(是个串、只与 deny 同行,见
737
- * {@link SETTLED_BY_MUST_BE_STRING} / {@link SETTLED_BY_DENY_ONLY}),而形不是词。
738
- *
739
- * 两个座位读它:这次回决的**即时结算**(`entry.settle` 的自报参)与**持久行**(`decideAsk` 的
740
- * `settledBy` 列)。S-558 之前只有前者 —— 于是同一个事实在「当次」与「重放」上是两个答案。
741
- * S-843:耐久 ask 回决口(`POST /v1/tasks/:taskId/asks/:askId/decision`)写的是**同一个座**(同一列,经
742
- * `outcomeOfDecidedRow` 交给同一个 `AskOutcome.settledBy`),所以它也走这一只 —— cast 仍是一座一次。
743
- */
744
- export declare function respondSettledBy(parsed: Pick<ParsedApprovalResponse, "settledBy">): HostSettledBy | undefined;
745
- export declare const SETTLED_BY_DENY_ONLY = "settledBy is only meaningful with decision \"deny\" \u2014 only a person approves an action that EXECUTES, so a self-reported settlement source on an allow is a contradiction the engine refuses; the refusal would arrive too late to undo this door's own side effects (a session allow-all grant, a persisted rule, a DECIDED row that replays as a plain approval), so it is refused here, before the decision";
746
- /**
747
- * S-843 / 车QK F7 —— `settledBy` 的**宽**拒句(三条回决腿共用一份文本,与 {@link SETTLED_BY_DENY_ONLY} 同姿势)。句子逐字是 S-843 在
748
- * 耐久 ask 回决口路由里写下的那一句(车QK F7 起搬到判官旁,路由不再自己写),尺 = 店的同一个常量({@link MAX_SETTLED_BY_CHARS})。
749
- */
750
- export declare const SETTLED_BY_TOO_WIDE = "settledBy must be 1-16 characters \u2014 the settlement source is one word from the engine's closed set and lands in a fixed-width column on the decision row";
751
- /**
752
- * S-843 —— 决议体上 `settledBy` 的判据,**一处成形**。三条 HTTP 回决腿共读:
753
- * `POST /v1/approvals/:sessionId/decide`(耐久 park 腿)、`POST /v1/tasks/:taskId/asks/:askId/decision`(耐久 ask 腿)与
754
- * live `POST /v1/tool-approvals/:id/respond`(经 {@link parseToolApprovalResponse};车QK F7 起 —— 此前那只 parser 手写了 ②③ 两臂、
755
- * 没有 ④,是这条判据的第二个写者)。
756
- *
757
- * 次序即契约(①–③ = decide 腿修前那三道 if 的原序,逐字搬来,不是新判据):
758
- * ① 直连门在场 ⇒ `not_in_proof` —— 键不在决策证明的签名载荷里(§6.3 同族第四条,理由在 approvals-assistant 的
759
- * `DECIDE_NOT_IN_PROOF_KEYS` 注);
760
- * ② 不是 deny ⇒ `deny_only` —— {@link SETTLED_BY_DENY_ONLY};
761
- * ③ 不是串 ⇒ `not_string` —— {@link SETTLED_BY_MUST_BE_STRING};
762
- * ④ 长度不在 1..{@link MAX_SETTLED_BY_CHARS} ⇒ `too_wide` —— {@link SETTLED_BY_TOO_WIDE}(车QK F7 / A3,7.104.0 合并复审)。
763
- * 尺与店门口的形门同一只谓词({@link settledByFitsColumn}):`/respond` 与耐久 ask 口写的是**同一列**
764
- * (`approval_ask.settled_by`,`VARCHAR(16)`),列宽是列的事实,不是某一条腿的事实。修前这一道只长在耐久 ask 口的路由里:
765
- * `/respond` 上一只超宽 / 空串的来源位要到 CAS 里才被店门抛,落进 D5「店抖动不挡真实回决」臂 —— 行没决,决议照样交给了引擎,200。
766
- * `/decide` 的来源位不落这一列(交给 core 的 checkpoint,core 在 CAS 之前按词表拒),这一道对它同样成立:core 的闭集词
767
- * (`human` / `timeout` / `policy`)都远短于这把尺,尺外的串不可能是一个词 ⇒ 三条口对同一个体同判同句,不为一条腿开特例。
768
- * 判的是**键在不在 / 配不配这个决议 / 形**,**从不判词**(词表属主是 core;三条腿的词都由引擎响亮拒)。
769
- *
770
- * 返回判决而不是直接回 400:各条腿在调用点按自己的码约定发出(错误文案冻结门按字面站点采集,码是 wire 契约);
771
- * 调用点对判决做穷举 `switch` + `never` 兜底(加一臂 = 编译红,[ref])。`accepted` 臂带着已证形的串 —— 调用点拿它往下传,
772
- * 不再对 `body.settledBy` 做第二次窄化。第三参给字面 `false` 的调用点(live `/respond`:那条口没有直连门证明)拿到的判决型里
773
- * **没有** `not_in_proof` 臂(重载),不必为一条结构上不可达的臂写兜底。
774
- */
775
- export type SettledByBodyVerdict = {
776
- kind: "absent";
777
- } | {
778
- kind: "accepted";
779
- settledBy: string;
780
- } | {
781
- kind: "not_in_proof";
782
- } | {
783
- kind: "deny_only";
784
- } | {
785
- kind: "not_string";
786
- } | {
787
- kind: "too_wide";
788
- };
789
- export declare function judgeSettledByBody(settledBy: unknown, decision: string, directDoorActive: false): Exclude<SettledByBodyVerdict, {
790
- kind: "not_in_proof";
791
- }>;
792
- export declare function judgeSettledByBody(settledBy: unknown, decision: string, directDoorActive: boolean): SettledByBodyVerdict;
793
773
  /** S-720(core 7.32.0 #1093)—— `readRootGrant` 只随 `decision:"allow"`(CC 卡的第三选项「Yes, and add directory」= 放行这一次
794
774
  * + 加目录;`allow_session` 不是那一个选项,`deny` 上它没有意义)。裁决之前响亮拒,不静默丢。 */
795
775
  export declare const READ_ROOT_GRANT_ALLOW_ONLY = "readRootGrant is only meaningful with decision \"allow\" \u2014 it is the card's \"Yes, and add directory\" answer (allow this call and add the card's readRootCandidate.dir to this run's read directories)";
796
776
  /** S-720:`readRootGrant` 的形 —— 卡上 `readRootCandidate.dir` 的原串(非空,≤ core `READ_ROOT_CANDIDATE_DIR_MAX`;超限整只拒,不截:截过的目录是另一个目录)。 */
797
777
  export declare const READ_ROOT_GRANT_SHAPE = "readRootGrant must be the card's readRootCandidate.dir sent back byte for byte \u2014 a non-empty string of at most 1024 characters";
798
778
  export declare const PERSIST_RULE_SCOPE_REFUSED = "this endpoint does not accept a rule scope \u2014 the server mints it from where the approval happened (send neither `scope` nor `persistRule.scope`)";
799
- /** Validate the respond body — the closed three-choice enum (rationale in the module header). */
800
- export declare function parseToolApprovalResponse(body: unknown): {
779
+ /** {@link parseToolApprovalResponse} 的成功分支形(`respond()` 拆分出的私有收尾方法复用,避免裸内联匿名类型重复三处)。 */
780
+ type ParsedToolApproval = {
801
781
  ok: true;
802
782
  value: ToolApprovalDecision;
803
783
  updatedInput?: unknown;
804
784
  persistRule?: ParsedPersistRule;
805
785
  note?: string;
806
- settledBy?: string;
786
+ decidedBy: ApprovalDecidedBy;
807
787
  readRootGrant?: string;
808
- } | {
809
- ok: false;
810
- error: string;
811
788
  };
812
- /** [ref] 车2:`parseToolApprovalResponse` 的成功分支形——`respond()` 拆分出的私有收尾方法(`finishRespond`/
813
- * `respondWithCas`)复用,避免裸内联匿名类型重复三处。 */
814
- type ParsedApprovalResponse = Extract<ReturnType<typeof parseToolApprovalResponse>, {
815
- ok: true;
816
- }>;
817
789
  /**
818
- * #1016 —— wire 上**开给调用方**的那一个词,从 core 的两只闭集里取**交集**。
790
+ * Validate the respond body — the closed three-choice enum (rationale in the module header).
819
791
  *
820
- * 🔴 它是一条**文档钉**,不是过境值的型(过境值是 `string`,理由在 `parseToolApprovalResponse` 那处注):
821
- * `"human"` 与缺席同义、`"timeout"` 是本仓自己观察到的窗(客户端说出来就是替服务端伪证一件只有服务端
822
- * 看得见的事),而耐久座那边的 `"person"` / `"sla_timeout"` 同理。两只词表**只在 `"policy"` 上相交** ——
823
- * 这条 wire 键因此恰好只开那一个词。core 哪天退役它,这里**编译期先红**,而不是在 wire 上静默留一个
824
- * 两个座都已经不收的词;`test/tool-approval.test.ts` 的 #1016 那组按它写判据。
792
+ * 失败形的机读位:体里带着退役键 `settledBy` 的任何一次拒(无论这次拒的**句子**说的是它还是体里别的毛病 —— 校验是顺序短路的,先撞上谁谁说话)都另带
793
+ * 机读位 `field`({@link retiredDecisionKeyFacts} 的 `extra`,三条决定口同一只铸点;`respond()` 映射 400 时带出);拒的成因就是退役键时,**句**也取自同一铸点。
794
+ * 铸在**这一层**而不是散在下面每个失败 return 上:一个事实一处读。
825
795
  */
826
- export type RespondSettledBy = Extract<HostSettledBy, HostDecidedBy>;
796
+ export declare function parseToolApprovalResponse(body: unknown): ParsedToolApproval | ({
797
+ ok: false;
798
+ error: string;
799
+ } & Partial<RetiredDecisionKeyFacts["extra"]>);
827
800
  /**
828
801
  * [ref] R-13 C —— `UNATTENDED_APPROVAL_POLICY` 的**闭集**词表([ref]Q1「裁2:A+C」/[ref] 裁②)。
829
802
  *
@@ -868,10 +841,9 @@ export declare function buildUnattendedPolicyRefusal(reason: string): Unattended
868
841
  * 铸:park 政策的路由答 `"unavailable"`,deny 政策的 {@link UnattendedPolicyRefusal}。没有布尔臂(S-689:裸 `false`
869
842
  * 是人的拒绝,这个口从不替人说话)。 */
870
843
  export type UnattendedAskOutcome = Extract<AskOutcome, "unavailable"> | UnattendedPolicyRefusal;
871
- /** S-877 候裁 16:耐久会话授权店的读面(`src/plugins/approval-exemption-store.ts` 的 `has`,结构型 —— 协调器不值引店模块)。 */
872
- export interface SessionGrantReader {
873
- has(sessionId: string, canonicalToolName: string): Promise<boolean>;
874
- }
844
+ /** S-877 候裁 16:耐久会话授权店(`src/plugins/approval-exemption-store.ts` 的同一只店):审批席读它(引擎的问),活卡上部署名单那一问的
845
+ * 「本会话放行」写它(名单门在出问之前读同一行)。 */
846
+ export type SessionGrantStore = Pick<ApprovalExemptionStore, "has" | "grant">;
875
847
  /**
876
848
  * [ref] 车3 刀 3b —— 「流内审批协议到底上不上场」的**单一谓词**(设计稿 §2.3 注入 / §2.4 能力面 /
877
849
  * §8.4 park 设施自检,三处同一份判据)。
@@ -1038,9 +1010,9 @@ type DecidedRowFacts = Pick<AskRow, "decision" | "settledBy"> & {
1038
1010
  * · **结算来源**(S-558)—— 行上非 null 即宿主自报的那个词(`null` = 人决,与「不铸这个键」同义;
1039
1011
  * 语义属主 = `AskRow.settledBy` 顶注)。
1040
1012
  *
1041
- * 🔴 approve 臂**不读**来源位,而且那不是「静默丢」:store 的入店形门(`assertDecideSettledBy`)让
1042
- * 「approve 行带来源位」在**写面不可表示** —— core 对 `{allow:true, settledBy}` 是 fail-closed 拒,
1043
- * 一条那样的行没有任何读回路径能诚实地交还给引擎,所以它在落库那一刻就被拒掉了,而不是在这里被吞掉。
1013
+ * 🔴 S-1154:来源位**两向都读**。决定体的出处位 `decidedBy:"policy"` 在 allow 与 deny 上都会落列(引擎 7.39.0 起铸
1014
+ * `policy_allowed`),所以 approve 行带来源位是一条合法的行,它的每条读回路径交还 `{allow:true, settledBy:"policy", updatedInput?}`
1015
+ * —— 与当次回决交给引擎的那一只逐字同形。
1044
1016
  */
1045
1017
  export declare function outcomeOfDecidedRow(row: DecidedRowFacts): DecidedAskOutcome;
1046
1018
  /**
@@ -1085,7 +1057,7 @@ export declare class ToolApprovalCoordinator {
1085
1057
  * askId 下全部本地条目(自己 + 兄弟 + 重复注册),直接调用它们各自的 `settle`,而不是被动等一个永远
1086
1058
  * 不会来的本地信号。 */
1087
1059
  private readonly pendingByAskId;
1088
- /** Per-capability session grants — keys = sessionAllowKey(owner, sessionId, category) (修2; bounded). */
1060
+ /** Per-capability session grants — keys = sessionAllowKey(owner, sessionId, category, grant binding) (修2; bounded). */
1089
1061
  private readonly allowAllSessions;
1090
1062
  /** [ref] HIGH-1(broker)→[ref]四 core 产品裁定「多活集合+广播+首决胜出」:per-(owner, host-session)
1091
1063
  * 的**当前活跃连接集合**——boundAsk 闭包只携身份,emit 时广播给该 key 下**全部**活连接(宿主重连/
@@ -1163,9 +1135,14 @@ export declare class ToolApprovalCoordinator {
1163
1135
  * 腿闭(`runWithContext` finally)。**纯观察面**:sink 自己吞写失败并 `recordFailOpen`,任何一次审计
1164
1136
  * 写都不得改变审批终局(店头注成文)。SQL 车道恒缺席(那里有真 ask 店)。 */
1165
1137
  private readonly askAudit;
1166
- /** S-877 候裁 16 → A:耐久会话授权店的**读面**(`/decide` 的 `remember:"session"` 写、本席读)。在场 ⇔ 部署有 store backend
1167
- * (装配点 `boot/coordinators.ts`,与 `/decide` 写的是**同一只**店)。读口唯一 = {@link standingGrantSettles}。 */
1138
+ /** S-877 候裁 16 → A:耐久会话授权店(`/decide` 的 `remember:"session"` 写、本席读)。在场 ⇔ 部署有 store backend
1139
+ * (装配点 `boot/coordinators.ts`,与 `/decide` 写的是**同一只**店)。读口唯一 = {@link standingGrantSettles};写口唯一 = {@link recordDeploymentListAnswer}
1140
+ * (活卡上部署名单那一问的「本会话放行」)。 */
1168
1141
  private readonly sessionGrants;
1142
+ /** **问的属主**的读法:部署名单门对这只调用出不出它自己的问(`approval.ts` 的 `deploymentListAsks` 对活配置现读,装配点 `boot/coordinators.ts`)。
1143
+ * 缺席(没有豁免店的装配)⇒ 没有一张卡读作名单的问 —— 名单那一问的答案没有地方记,它就按引擎的类表读(记不住)。
1144
+ * 活的一问(`AskRequest`)上只有 wire 名(没有调用的别名面)⇒ 名单靠别名命中的调用读不出属主,按引擎的问读(记不住;方向是多问)。 */
1145
+ private readonly deploymentListAsks;
1169
1146
  /** S-929:有序关停已开始(`drainForShutdown` 锁存,不复位 —— 进程正在退出)。之后登记的每一张卡在登记那一刻按关停收场。 */
1170
1147
  private shutdownDraining;
1171
1148
  /** S-929:此刻在 `askBroadcast` 里的 ask 数(进出成对,见那里的 try/finally)—— 关停等待「还没登记进 `pending` 的卡」的计数。 */
@@ -1202,8 +1179,12 @@ export declare class ToolApprovalCoordinator {
1202
1179
  parkTombstonePerPrincipalMax?: number;
1203
1180
  /** [ref] (c):local 车道审计 sink(见 {@link ToolApprovalCoordinator.askAudit})。 */
1204
1181
  askAudit?: ApprovalAskAuditSink;
1205
- /** S-877 候裁 16:耐久会话授权店的读面(见 {@link ToolApprovalCoordinator.sessionGrants})。 */
1206
- sessionGrants?: SessionGrantReader;
1182
+ /** S-877 候裁 16:耐久会话授权店(见 {@link ToolApprovalCoordinator.sessionGrants})。 */
1183
+ sessionGrants?: SessionGrantStore;
1184
+ /** 问的属主的读法(见 {@link ToolApprovalCoordinator.deploymentListAsks})。只能与 `sessionGrants` 同在:名单那一问的答案就记在那只店里。 */
1185
+ deploymentListAsks?: (call: {
1186
+ readonly toolName: string;
1187
+ }) => boolean;
1207
1188
  /** S-929 F1:park 提交的观察面(见 {@link ToolApprovalCoordinator.parkCommits})。 */
1208
1189
  parkCommits?: ParkCommitWatch;
1209
1190
  });
@@ -1444,7 +1425,7 @@ export declare class ToolApprovalCoordinator {
1444
1425
  * 🔴 **S-877 候裁 16 → A —— 站着的答案(会话授权)的唯一兑现口**(主会话裁定 2026-09-29;core 7.34.0 wire 段逐字指定的兑现位:
1445
1426
  * 「a host approval seat that settles asks from a session grant reads it [`authoredBy`] to keep its hands off」)。
1446
1427
  *
1447
- * **一条判据**:一只 ask 由会话授权代答 ⇔ ① 它是站着的答案退得掉的一问({@link standingAnswerMayRetire} —— 治理强制 /
1428
+ * **一条判据**:一只 ask 由会话授权代答 ⇔ ① 判据说它的站着的答案在本席({@link standingAnswerHome} 答 `seat` —— 治理强制 /
1448
1429
  * `requiresRealApproval` / `mandated` 三位的既有排除一字不动;运维「恒问人」的卡(`APPROVAL_NEVER_AUTO` / 耐久预算耗尽)
1449
1430
  * 自 S-877 起盖部署出身 ⇒ core 盖 `mandated`,同落这一臂)∧ ② 有真会话 ∧ ③ 两只授权店任一命中:live `allow_session` 的
1450
1431
  * 进程内表(按能力桶,[ref]② 修2)或耐久 `/decide` `remember:"session"` 的豁免店(按 canonical 工具名,`/decide` 写的同一只店;
@@ -1456,6 +1437,8 @@ export declare class ToolApprovalCoordinator {
1456
1437
  * 盖 `mandated`(`ruleClearanceOf` 的 inheritedUnresolved / ancestorResolved 门),本席依约不退役 —— 只有策略层的「不问」够得着继承链
1457
1438
  * (主会话裁定原想退役那三只探针,施工中被 test/parked-decide-leg.test.ts「[候裁② 修]remember 全链行为」证伪,收车档 ⑩ 16-⑤)。
1458
1439
  * 本席的两个入口(`askBroadcast` 开头、窗 0 / 无活流身份席 {@link boundUnattendedAsk})都只调这一只。
1440
+ * 本席只代答判据说 `seat` 的问({@link standingAnswerHome});部署名单自己的问(`server_store`)的站着的答案由名单门在出问之前读过了
1441
+ * (问到了这里 = 店里没有),本席手里的授权是引擎那些问的答案;本席代答还会被记成一个人的应答。
1459
1442
  */
1460
1443
  private standingGrantSettles;
1461
1444
  /** 耐久豁免店的一次读(fail-closed:读抛 **或超时** ⇒ 不命中 + warn)。只由 {@link standingGrantSettles} 调。
@@ -1699,6 +1682,18 @@ export declare class ToolApprovalCoordinator {
1699
1682
  status: number;
1700
1683
  body: unknown;
1701
1684
  }>;
1685
+ /**
1686
+ * **部署名单(`APPROVAL_REQUIRE`)那一问的「本会话放行」只落 server 的会话豁免店**(谁问的,谁的站着的答案算数):名单的问是 server 铸的,
1687
+ * 名单门在出问之前读这只店(键 = 会话 × wire 工具名,与耐久 `/decide` 的 `remember:"session"` 写下的同形),命中就不出问 —— 引擎看到的
1688
+ * 是「这次调用没出问」。不铸进程内授权(那是审批席替引擎的问记的答案;本席不代答名单的问),不交任何东西给引擎的规则店。
1689
+ *
1690
+ * 只在这次回决**真成了终局、而且终局是本请求写的**之后写(200 那一支 ∧ {@link RulePersistEligibility} 合格;CAS 输 / 条目已被别人结算 ⇒ 不写;
1691
+ * 提交歧义臂 —— 行上只证得出「有一条同向决议」,可能是并发的另一路「只批这一次」写的 —— 撤销资格 ⇒ 不写):一次不是自己的放行不留站着的答案。写在结算之后,
1692
+ * 所以同一条腿紧跟着的下一问若先于这次写落到名单门,会多出一张卡(方向是多问,不是静默放行)。回执 `rememberApplied` 按这次写的真实结果说:
1693
+ * 写成 ⇒ `true`;写失败 / 超时 ⇒ `false` + 一行 warn(这一次照旧放行,与 `/decide` 腿「grant 失败不回滚 approve」同向)。
1694
+ * 不是名单的问、记不住的卡(卡上还带着别人的问、强制、授予绑定 ……)、没有会话 ⇒ 原样交回(那几形的回执已由 {@link finishRespond} 定)。
1695
+ */
1696
+ private recordDeploymentListAnswer;
1702
1697
  /**
1703
1698
  * [ref]:自由文本规则的**裁决前**文本预检 —— 回 `undefined` = 放行(继续正常回决),回一个响应 = 400。
1704
1699
  *