@sema-agent/server 7.122.0 → 7.124.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 (256) hide show
  1. package/MIGRATION.md +209 -0
  2. package/README.md +7 -2
  3. package/README.zh-CN.md +5 -2
  4. package/USAGE.md +76 -56
  5. package/dist/approval-ask-audit-store.d.ts +27 -32
  6. package/dist/approval-ask-audit-store.js +10 -9
  7. package/dist/approval-crash-convergence.d.ts +2 -2
  8. package/dist/approval-crash-convergence.js +5 -5
  9. package/dist/approval-deny-reasons.d.ts +163 -51
  10. package/dist/approval-deny-reasons.js +79 -8
  11. package/dist/approval-policy-settlement.d.ts +4 -1
  12. package/dist/approval-policy-settlement.js +3 -2
  13. package/dist/approval-reconciler.d.ts +3 -3
  14. package/dist/approval-reconciler.js +10 -10
  15. package/dist/approval.d.ts +1 -1
  16. package/dist/approval.js +1 -1
  17. package/dist/audit.d.ts +1 -1
  18. package/dist/audit.js +53 -23
  19. package/dist/auth-bridge.d.ts +8 -8
  20. package/dist/auth-bridge.js +6 -6
  21. package/dist/auth-keys.d.ts +2 -2
  22. package/dist/auto-mode-face.d.ts +13 -9
  23. package/dist/auto-mode-face.js +8 -7
  24. package/dist/boot/budget-tracing.js +1 -1
  25. package/dist/boot/execution-env.js +1 -0
  26. package/dist/boot/leader.d.ts +1 -1
  27. package/dist/boot/memory-consolidation.d.ts +4 -4
  28. package/dist/boot/org-memory.d.ts +3 -3
  29. package/dist/boot/org-memory.js +5 -5
  30. package/dist/boot/resolve-spec.js +7 -7
  31. package/dist/boot/runner-deps.d.ts +1 -1
  32. package/dist/boot/runtime-caps.d.ts +1 -1
  33. package/dist/boot/runtime-caps.js +10 -10
  34. package/dist/boot/shutdown.d.ts +2 -2
  35. package/dist/boot/shutdown.js +2 -2
  36. package/dist/boot/side-query-lane.d.ts +3 -3
  37. package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
  38. package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
  39. package/dist/boot/stage-03-store-backend.d.ts +2 -2
  40. package/dist/boot/stage-04-stores.d.ts +1 -1
  41. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  42. package/dist/boot/stage-06-runners.d.ts +2 -2
  43. package/dist/boot/stage-06-runners.js +6 -6
  44. package/dist/boot/stage-07-capability-layer.d.ts +2 -2
  45. package/dist/boot/stage-07-capability-layer.js +6 -5
  46. package/dist/boot/stage-08-reapers.d.ts +3 -3
  47. package/dist/boot/stage-08-reapers.js +3 -3
  48. package/dist/boot/stage-09-leader.d.ts +3 -3
  49. package/dist/boot/stage-09-leader.js +7 -7
  50. package/dist/boot/stage-10-http-server.d.ts +3 -3
  51. package/dist/boot/stage-10-http-server.js +19 -19
  52. package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
  53. package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
  54. package/dist/boot/{config-center.js → web-admin.js} +39 -20
  55. package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
  56. package/dist/brain.d.ts +1 -1
  57. package/dist/brain.js +1 -1
  58. package/dist/budget.d.ts +3 -3
  59. package/dist/canonical-json.d.ts +2 -2
  60. package/dist/capabilities/center-plugins.d.ts +1 -1
  61. package/dist/capabilities/center-wiring.d.ts +12 -5
  62. package/dist/capabilities/center-wiring.js +11 -2
  63. package/dist/capabilities/composite-members.d.ts +1 -1
  64. package/dist/capabilities/composite-members.js +1 -1
  65. package/dist/capabilities/scenarios.js +2 -2
  66. package/dist/capabilities/team.d.ts +1 -1
  67. package/dist/capabilities/tool-defer.d.ts +1 -1
  68. package/dist/center-credential-renewer.d.ts +1 -1
  69. package/dist/center-credential-renewer.js +7 -7
  70. package/dist/center-credential.d.ts +9 -9
  71. package/dist/center-credential.js +6 -6
  72. package/dist/config-catalog.d.ts +7 -10
  73. package/dist/config-catalog.js +16 -16
  74. package/dist/config-d-migration.d.ts +32 -0
  75. package/dist/config-d-migration.js +59 -0
  76. package/dist/config-invariants.d.ts +14 -4
  77. package/dist/config-invariants.js +31 -2
  78. package/dist/config-lkg.d.ts +34 -11
  79. package/dist/config-lkg.js +76 -48
  80. package/dist/config-provider.d.ts +26 -21
  81. package/dist/config-provider.js +25 -27
  82. package/dist/config-types.d.ts +59 -50
  83. package/dist/config.d.ts +17 -54
  84. package/dist/config.js +99 -181
  85. package/dist/execution-lane-caps.d.ts +1 -1
  86. package/dist/fleet/drain-entry.d.ts +1 -1
  87. package/dist/fleet/engine-signal.d.ts +61 -30
  88. package/dist/fleet/engine-signal.js +29 -5
  89. package/dist/fleet/fleet-bus.d.ts +12 -3
  90. package/dist/fleet/fleet-bus.js +13 -9
  91. package/dist/fleet/serving-lease.d.ts +3 -3
  92. package/dist/fleet/serving-lease.js +1 -1
  93. package/dist/fleet-client.d.ts +15 -13
  94. package/dist/fleet-client.js +9 -7
  95. package/dist/fleet-lease.d.ts +3 -3
  96. package/dist/fleet-lease.js +2 -2
  97. package/dist/host-lsp-manager.d.ts +1 -1
  98. package/dist/hosted-posture.d.ts +4 -4
  99. package/dist/http/admission.js +4 -4
  100. package/dist/http/checkpoint-ctx.d.ts +20 -3
  101. package/dist/http/checkpoint-ctx.js +13 -5
  102. package/dist/http/dispatch.js +7 -16
  103. package/dist/http/durable-run-leg.js +2 -1
  104. package/dist/http/health-self-report.d.ts +7 -4
  105. package/dist/http/health-self-report.js +3 -3
  106. package/dist/http/idempotency.d.ts +1 -1
  107. package/dist/http/resume-legs.d.ts +4 -3
  108. package/dist/http/resume-legs.js +31 -18
  109. package/dist/http/route-ctx.d.ts +8 -0
  110. package/dist/http/routes/admin-config-refresh.d.ts +1 -1
  111. package/dist/http/routes/admin-config-refresh.js +1 -1
  112. package/dist/http/routes/admin-drain.d.ts +1 -1
  113. package/dist/http/routes/admin-drain.js +5 -4
  114. package/dist/http/routes/approvals-assistant.js +4 -4
  115. package/dist/http/routes/capabilities.js +6 -5
  116. package/dist/http/routes/config-catalog.js +2 -3
  117. package/dist/http/routes/diagnostics.js +1 -1
  118. package/dist/http/routes/runs.js +8 -4
  119. package/dist/http/routes/sessions-list.js +2 -1
  120. package/dist/http/routes/sessions.js +2 -5
  121. package/dist/http/routes/side-query.js +3 -3
  122. package/dist/http/routes/tasks.js +3 -2
  123. package/dist/http/run-meta.d.ts +1 -1
  124. package/dist/http/run-meta.js +2 -2
  125. package/dist/http/server.d.ts +7 -7
  126. package/dist/http/server.js +1 -1
  127. package/dist/http/stored-body-replay.d.ts +4 -3
  128. package/dist/http/stored-body-replay.js +5 -5
  129. package/dist/index.d.ts +2 -1
  130. package/dist/index.js +1 -1
  131. package/dist/key-resolver.d.ts +1 -1
  132. package/dist/leader/leader.d.ts +7 -6
  133. package/dist/leader/leader.js +3 -1
  134. package/dist/leader/run-entry.d.ts +2 -2
  135. package/dist/leader/run-entry.js +3 -3
  136. package/dist/leader/wire.d.ts +4 -4
  137. package/dist/leader/wire.js +2 -1
  138. package/dist/main.js +1 -1
  139. package/dist/mcp-tool-faces.d.ts +2 -2
  140. package/dist/model-entry-refusal.d.ts +20 -11
  141. package/dist/model-entry-refusal.js +22 -17
  142. package/dist/model-provider.d.ts +2 -2
  143. package/dist/model-route-endpoint.d.ts +22 -2
  144. package/dist/model-route-endpoint.js +9 -3
  145. package/dist/model-route-gap.d.ts +103 -0
  146. package/dist/model-route-gap.js +80 -0
  147. package/dist/model-route-url.d.ts +1 -1
  148. package/dist/model-route-url.js +2 -1
  149. package/dist/model-select.d.ts +24 -21
  150. package/dist/model-select.js +22 -17
  151. package/dist/namespaced-rule-name.d.ts +16 -30
  152. package/dist/namespaced-rule-name.js +2 -20
  153. package/dist/observability/fail-open.d.ts +0 -4
  154. package/dist/observability/fail-open.js +0 -4
  155. package/dist/observability/metrics.d.ts +1 -1
  156. package/dist/org-memory-admission.d.ts +1 -1
  157. package/dist/plugins/approval-ask-store-file.d.ts +4 -2
  158. package/dist/plugins/approval-ask-store-file.js +3 -3
  159. package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
  160. package/dist/plugins/approval-ask-store-memory.js +10 -4
  161. package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
  162. package/dist/plugins/approval-ask-store-sql.js +20 -13
  163. package/dist/plugins/caching-session-store.d.ts +0 -10
  164. package/dist/plugins/caching-session-store.js +0 -3
  165. package/dist/plugins/file-run-store.js +9 -3
  166. package/dist/plugins/leader-run-store-sql.d.ts +3 -2
  167. package/dist/plugins/leader-run-store-sql.js +3 -2
  168. package/dist/plugins/local-session-store.d.ts +20 -27
  169. package/dist/plugins/local-session-store.js +19 -17
  170. package/dist/plugins/memory-run-store.js +9 -3
  171. package/dist/plugins/one-time-migrations.js +51 -0
  172. package/dist/plugins/scheduler-support.d.ts +26 -7
  173. package/dist/plugins/scheduler-support.js +96 -53
  174. package/dist/plugins/session-policy-store-sql.js +1 -2
  175. package/dist/plugins/store-backend.js +1 -1
  176. package/dist/plugins/store-contracts.d.ts +20 -4
  177. package/dist/plugins/web-search.d.ts +1 -1
  178. package/dist/plugins/web-search.js +2 -1
  179. package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
  180. package/dist/posture-source.d.ts +1 -1
  181. package/dist/read-face-posture.d.ts +3 -3
  182. package/dist/read-face-posture.js +1 -1
  183. package/dist/rule-entry-list.d.ts +3 -13
  184. package/dist/rule-entry-list.js +1 -12
  185. package/dist/run-local.js +10 -7
  186. package/dist/runtime-caps-resolver.d.ts +4 -4
  187. package/dist/runtime-caps-resolver.js +2 -2
  188. package/dist/runtime-governance.d.ts +36 -13
  189. package/dist/runtime-governance.js +7 -2
  190. package/dist/sealed-key.d.ts +4 -4
  191. package/dist/sealed-key.js +3 -2
  192. package/dist/security.d.ts +3 -3
  193. package/dist/service-version.d.ts +1 -1
  194. package/dist/service-version.js +5 -0
  195. package/dist/session-policy-wire.d.ts +47 -49
  196. package/dist/session-policy-wire.js +41 -36
  197. package/dist/session-sync.d.ts +5 -1
  198. package/dist/session-sync.js +2 -1
  199. package/dist/session-titler.d.ts +0 -11
  200. package/dist/session-titler.js +3 -5
  201. package/dist/shared-memory-scope-authorizer.d.ts +4 -4
  202. package/dist/spec-fields.d.ts +4 -4
  203. package/dist/spec-fields.js +1 -4
  204. package/dist/task-a2a.d.ts +1 -1
  205. package/dist/task-settings.d.ts +4 -5
  206. package/dist/task-settings.js +5 -8
  207. package/dist/tool-approval.d.ts +43 -4
  208. package/dist/tool-approval.js +147 -98
  209. package/dist/trace/core-keyset-guard.d.ts +1 -1
  210. package/dist/trace/project.d.ts +3 -3
  211. package/dist/trace/redact.d.ts +2 -23
  212. package/dist/trace/redact.js +1 -6
  213. package/dist/trace/self-minted-wire.d.ts +147 -3
  214. package/dist/trace/self-minted-wire.js +50 -9
  215. package/dist/unattended-permission-mode.d.ts +3 -3
  216. package/dist/unattended-permission-mode.js +2 -2
  217. package/dist/url-refusal.d.ts +35 -0
  218. package/dist/url-refusal.js +15 -0
  219. package/dist/user-authored-text.d.ts +31 -0
  220. package/dist/user-authored-text.js +18 -0
  221. package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
  222. package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
  223. package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
  224. package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
  225. package/dist/{config-center → web-admin-client}/center-request.js +5 -4
  226. package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
  227. package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
  228. package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
  229. package/dist/{config-center → web-admin-client}/facade.js +2 -2
  230. package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
  231. package/dist/{config-center → web-admin-client}/http-client.js +15 -15
  232. package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
  233. package/dist/{config-center → web-admin-client}/read-face.js +4 -4
  234. package/dist/web-admin-client/read-warnings.d.ts +137 -0
  235. package/dist/web-admin-client/read-warnings.js +168 -0
  236. package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
  237. package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
  238. package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
  239. package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
  240. package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
  241. package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
  242. package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
  243. package/package.json +3 -3
  244. package/skills/find-skills.md +2 -2
  245. package/dist/config-center/read-warnings.d.ts +0 -109
  246. package/dist/config-center/read-warnings.js +0 -110
  247. package/dist/url-shape.d.ts +0 -31
  248. package/dist/url-shape.js +0 -41
  249. /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
  250. /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
  251. /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
  252. /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
  253. /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
  254. /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
  255. /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
  256. /package/dist/{config-center → web-admin-client}/types.js +0 -0
@@ -1,6 +1,5 @@
1
- import { PROTOCOL_TABLE, SessionPolicyError, assertSessionRuleNamesCurrent } from "@sema-agent/core";
1
+ import { PROTOCOL_TABLE, SessionPolicyError, assertSessionRuleNamesCurrent, normalizeRules } from "@sema-agent/core";
2
2
  import { displayListEntry } from "./list-entry-display.js";
3
- import { describeEmptyToolSegment, emptyToolSegmentOf } from "./namespaced-rule-name.js";
4
3
  const RULE_FIELDS = {
5
4
  toolAllow: true,
6
5
  toolDeny: true,
@@ -20,33 +19,18 @@ function legacyToolNameRefusalOf(rules) {
20
19
  throw e;
21
20
  }
22
21
  }
23
- const TOOL_NAME_FIELD_TABLE = { toolAllow: "toolAllow", toolDeny: "toolDeny" };
24
- const TOOL_NAME_FIELDS = Object.values(TOOL_NAME_FIELD_TABLE);
25
- export function unreachableSessionRuleNameOf(rules) {
26
- for (const field of TOOL_NAME_FIELDS) {
27
- for (const name of rules[field] ?? []) {
28
- const ns = emptyToolSegmentOf(name);
29
- if (ns !== undefined)
30
- return { field, name, ns };
31
- }
32
- }
33
- return undefined;
34
- }
35
- export function assertSessionRuleNamesReachable(rules) {
36
- const unreachable = unreachableSessionRuleNameOf(rules);
37
- if (unreachable !== undefined)
38
- throw new Error(describeUnreachableSessionRuleName(unreachable));
39
- }
40
22
  function protocolToolNameShapes() {
41
23
  return PROTOCOL_TABLE.map((ns) => `${ns.prefix}<peer>__<tool>`).join(" or ");
42
24
  }
25
+ function isRulesObject(raw) {
26
+ return raw !== null && typeof raw === "object" && !Array.isArray(raw);
27
+ }
43
28
  export function readSessionPermissionRules(raw) {
44
- if (raw === null || typeof raw !== "object" || Array.isArray(raw))
29
+ if (!isRulesObject(raw))
45
30
  return { problem: { kind: "not-an-object" } };
46
- const src = raw;
47
31
  const rules = {};
48
32
  for (const field of SESSION_PERMISSION_RULE_FIELDS) {
49
- const v = src[field];
33
+ const v = raw[field];
50
34
  if (v === undefined)
51
35
  continue;
52
36
  if (!Array.isArray(v) || !v.every((x) => typeof x === "string"))
@@ -55,17 +39,42 @@ export function readSessionPermissionRules(raw) {
55
39
  }
56
40
  return { rules };
57
41
  }
42
+ function engineRuleListOf(field, value) {
43
+ let normalized;
44
+ try {
45
+ normalized = normalizeRules({ [field]: value });
46
+ }
47
+ catch (e) {
48
+ if (e instanceof TypeError)
49
+ return { refusal: e.message };
50
+ throw e;
51
+ }
52
+ const list = normalized[field];
53
+ return list === undefined ? {} : { list };
54
+ }
55
+ export function unwritableRuleListOf(rules) {
56
+ for (const field of SESSION_PERMISSION_RULE_FIELDS) {
57
+ const judged = engineRuleListOf(field, rules[field]);
58
+ if ("refusal" in judged)
59
+ return { field, refusal: judged.refusal };
60
+ }
61
+ return undefined;
62
+ }
58
63
  export function readWritableSessionPermissionRules(raw) {
59
- const read = readSessionPermissionRules(raw);
60
- if (read.problem !== undefined)
61
- return read;
62
- const refusal = legacyToolNameRefusalOf(read.rules);
64
+ if (!isRulesObject(raw))
65
+ return { problem: { kind: "not-an-object" } };
66
+ const rules = {};
67
+ for (const field of SESSION_PERMISSION_RULE_FIELDS) {
68
+ const judged = engineRuleListOf(field, raw[field]);
69
+ if ("refusal" in judged)
70
+ return { problem: { kind: "field-not-rule-list", field, refusal: judged.refusal } };
71
+ if (judged.list !== undefined)
72
+ rules[field] = judged.list;
73
+ }
74
+ const refusal = legacyToolNameRefusalOf(rules);
63
75
  if (refusal !== undefined)
64
76
  return { problem: { kind: "legacy-tool-name", refusal } };
65
- const unreachable = unreachableSessionRuleNameOf(read.rules);
66
- if (unreachable !== undefined)
67
- return { problem: { kind: "unreachable-tool-name", unreachable } };
68
- return read;
77
+ return { rules };
69
78
  }
70
79
  export function readSessionRulesRecords(raw) {
71
80
  if (!Array.isArray(raw))
@@ -91,17 +100,14 @@ export function describeSessionPermissionRulesProblem(p) {
91
100
  switch (p.kind) {
92
101
  case "not-an-object": return "rules must be a SessionPermissionRules object";
93
102
  case "field-not-string-array": return `${p.field} must be an array of strings`;
103
+ case "field-not-rule-list": return p.refusal;
94
104
  case "legacy-tool-name": return describeLegacyToolName(p.refusal);
95
- case "unreachable-tool-name": return describeUnreachableSessionRuleName(p.unreachable);
96
105
  default: {
97
106
  const unhandled = p;
98
107
  throw new Error(`unhandled SessionPermissionRules problem: ${JSON.stringify(unhandled)}`);
99
108
  }
100
109
  }
101
110
  }
102
- function describeUnreachableSessionRuleName(u) {
103
- return `${u.field} names ${displayListEntry(u.name)}, which can never match a tool (${describeEmptyToolSegment(u.ns)}), so nothing was written`;
104
- }
105
111
  function describeLegacyToolName(r) {
106
112
  const why = r.guidance !== undefined ? ` (${r.guidance})` : "";
107
113
  switch (r.verdict) {
@@ -126,8 +132,7 @@ export function legacyToolNameProblemOf(p) {
126
132
  case "rules":
127
133
  switch (p.problem.kind) {
128
134
  case "not-an-object":
129
- case "field-not-string-array":
130
- case "unreachable-tool-name":
135
+ case "field-not-rule-list":
131
136
  return undefined;
132
137
  case "legacy-tool-name":
133
138
  return p.problem.refusal;
@@ -159,7 +159,11 @@ export declare function planSync(sessionId: string, srcBackend: StoreBackend, ds
159
159
  * 无条件写都 rev+1,而 rev 是 operator 乐观锁的 CAS 令牌(`PutRulesOptions.expectedRev`),
160
160
  * 幂等重试/无害重复同步不该把在途 CAS 打失败。归一化用 core 的 `normalizeRules`(store 落盘
161
161
  * 前走同一函数 ⇒ 两侧同坐标);`stripRev` 去掉记录内嵌的 rev(`listBySession` 的 rules 含 rev,
162
- * 它不是内容)。 */
162
+ * 它不是内容)。
163
+ * 🔴 core 7.48.0 起 `normalizeRules` 对「不是一列非空字符串」的桶抛 `TypeError`。`incoming` 由写口读者保证是引擎肯写的
164
+ * (`session-policy-wire.ts` `readSessionRulesRecords`);`stored` 可能是 7.47.x 及以前写下的空串项存量行 —— 读得出、引擎却不肯再写。
165
+ * 这种行与任何肯写的 `incoming` 都**不同内容**(它多一个空项),所以答 `false`(判官 = 写口读者那一只 `unwritableRuleListOf`,不拿它跑 normalize):
166
+ * 写照常交给店 —— 店的收紧门对它照常判(operator 照写,是清旧行的出路;非 operator 删空串 deny 项被读成放宽 ⇒ 403,与 7.122.0 同答)。 */
163
167
  export declare function sameRulesContent(stored: StoredSessionRules | null, incoming: SessionPermissionRules): boolean;
164
168
  /** [ref] ① 的重放腿共享实现:PUSH 路由的两条 policy 重放腿(Phase A identical 短路支 / Phase B
165
169
  * commit 后支)都从这里走 —— 等内容跳过(rev 零漂移),真变更照常落地(E6 tighten-only 门在
@@ -1,5 +1,6 @@
1
1
  import { classifySyncRelationship } from "./session-sync-kernel.js";
2
2
  import { normalizeRules, stripRev } from "@sema-agent/core";
3
+ import { unwritableRuleListOf } from "./session-policy-wire.js";
3
4
  export function fileHistoryImportFace(fs) {
4
5
  const candidate = fs?.importHistory;
5
6
  if (typeof candidate !== "function")
@@ -54,7 +55,7 @@ export async function planSync(sessionId, srcBackend, dstBackend) {
54
55
  return classifySyncRelationship(srcEntries, dstEntries);
55
56
  }
56
57
  export function sameRulesContent(stored, incoming) {
57
- if (stored === null)
58
+ if (stored === null || unwritableRuleListOf(stored) !== undefined)
58
59
  return false;
59
60
  const norm = (r) => JSON.stringify(normalizeRules(stripRev(r)));
60
61
  return norm(stored) === norm(incoming);
@@ -54,17 +54,6 @@ export interface SessionTitler {
54
54
  export declare const TITLE_MAX_CHARS = 80;
55
55
  /** Single line, control chars stripped, hard cap; surrounding quotes (a common LLM tic) trimmed. */
56
56
  export declare function sanitizeTitle(raw: string): string;
57
- /**
58
- * S-236 ②(7.106.0,cli L-687)—— objective 里**用户自己写的**那部分:剥掉全部 `<system-reminder>…</system-reminder>` 块(跨行、
59
- * 多块、夹在正文中间都剥;**未闭合**的块剥到末尾 —— 被截断的附件同样不是用户写的)后 trim。
60
- *
61
- * 为什么:壳把附件(技能清单一类的 `<system-reminder>` 块)拼在正文**之前**提交,标题器取前 {@link OBJECTIVE_SNIPPET_CHARS} 字
62
- * 去起名 ⇒ 标题成了技能清单。判据只认这一个**字面标签**(CC 的附件信封),不按内容猜「像不像用户写的」——
63
- * 正文里提到这个词的普通文字不是块,原样保留。剥完是空串 ⇒ 调用方走「空 objective 不起名」的既有臂。
64
- * ⚠️ 只治这一类:S-236 原件(fresh `/decide` 腿把指路文本当 objective 提交)是另一类非用户文本,没有信封可剥,本函数刻意不加
65
- * 按内容猜的第二臂(要么 fresh 腿传席,要么另立一臂 —— 候裁,见车RA 收车档)。
66
- */
67
- export declare function userAuthoredObjectiveText(objective: string): string;
68
57
  export declare function buildTitlePrompt(objective: string): string;
69
58
  export declare function createSessionTitler(deps: SessionTitlerDeps): SessionTitler;
70
59
  //# sourceMappingURL=session-titler.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
2
2
  import { recordFailOpen } from "./observability/fail-open.js";
3
3
  import { redactSecrets } from "./trace/redact.js";
4
+ import { userAuthoredText } from "./user-authored-text.js";
4
5
  export const TITLE_MAX_CHARS = 80;
5
6
  const OBJECTIVE_SNIPPET_CHARS = 600;
6
7
  const LLM_TIMEOUT_MS = 15_000;
@@ -12,11 +13,8 @@ export function sanitizeTitle(raw) {
12
13
  const unquoted = oneLine.replace(/^["'「『]+/, "").replace(/["'」』]+$/, "").trim();
13
14
  return unquoted.length > TITLE_MAX_CHARS ? `${unquoted.slice(0, TITLE_MAX_CHARS - 1)}…` : unquoted;
14
15
  }
15
- export function userAuthoredObjectiveText(objective) {
16
- return objective.replace(/<system-reminder>[\s\S]*?(?:<\/system-reminder>|$)/g, "").trim();
17
- }
18
16
  export function buildTitlePrompt(objective) {
19
- const text = userAuthoredObjectiveText(objective);
17
+ const text = userAuthoredText(objective);
20
18
  const snippet = text.length > OBJECTIVE_SNIPPET_CHARS ? `${text.slice(0, OBJECTIVE_SNIPPET_CHARS)}…` : text;
21
19
  const fenced = snippet.replace(/<(\/?)request>/gi, "<\u200b$1request>");
22
20
  return ("Write a short title (at most 8 words) summarizing the user request below. " +
@@ -38,7 +36,7 @@ export function createSessionTitler(deps) {
38
36
  .catch(() => ({ state: continueWord, unreadable: true }));
39
37
  return {
40
38
  maybeTitle(sessionId, objective, model) {
41
- if (!sessionId || !userAuthoredObjectiveText(objective))
39
+ if (!sessionId || !userAuthoredText(objective))
42
40
  return;
43
41
  if (seen.has(sessionId))
44
42
  return;
@@ -25,7 +25,7 @@ export interface SharedMemoryScopeAuthorizerOptions {
25
25
  * 部署自证的 org scope —— **取值口而非值**([ref])。
26
26
  *
27
27
  * 🔴 类型上是函数是刻意的,不是风格:这组 scope 的真源是 `config.projects` 的 `defaultScopes`,
28
- * 而 `config.projects` 被 config-center **就地热应用**(`mutateInPlace`,整表替换),env 腿恒空
28
+ * 而 `config.projects` 被 web-admin **就地热应用**(`mutateInPlace`,整表替换),env 腿恒空
29
29
  * ⇒ 这一域的**常态**就是运行期变更。此前这里收的是一个数组(装配点在 boot 期算一次),而且本模块
30
30
  * 还 `[...new Set(...)]` 又复制一层,连「换引用」这条后路都封死 ⇒ 两个方向都错到进程重启为止:
31
31
  * · **新登记**一个带 `org:` 的项目 ⇒ 该 org 的共享库在快照里没有 ⇒ 折成 `{state:"connected",
@@ -33,7 +33,7 @@ export interface SharedMemoryScopeAuthorizerOptions {
33
33
  * unavailable),运维以为配好了;
34
34
  * · **撤销**方向更糟:项目/scope 下架后,principal-less 的单用户请求仍按旧快照继续被放行 ——
35
35
  * 一次运维撤销动作**静默不生效**([ref] 点名的静默类型),方向是 fail-OPEN。
36
- * 而且它没被登进 `config-center/restart-signal.ts` 的 `RESTART_SLICES` ⇒ `/health` 连一句
36
+ * 而且它没被登进 `web-admin-client/restart-signal.ts` 的 `RESTART_SLICES` ⇒ `/health` 连一句
37
37
  * 「该重启了」都不会说。⇒ 收口是把读取时机对齐消费时机:每次 `resolve` 现取。
38
38
  * (缺席 = 部署没有任何自证 scope,与传 `() => []` 等价。)
39
39
  *
@@ -51,8 +51,8 @@ export interface SharedMemoryScopeAuthorizerOptions {
51
51
  * Set 建、交回来已去重,这里再包一层是纯浪费。**去重责任因此上移到取值口**(契约见下面那个字段的注),
52
52
  * principal 在场那支的合并 Set 保留(它要与目录 scope 求并,那一次是真需要的)。
53
53
  * · **具名保留**(不做 generation 缓存):`config.projects` 由 `mutateInPlace` **就地**改,对象身份恒定,
54
- * 没有可用的失效信号;而 config-center 的 `appliedGeneration` 是那个模块的私有 WeakMap,不在公面上。
55
- * 要缓存就得先给 config-center 开一只「已提交世代」读口 —— 那是别人模块的接缝件,且**缓存失效写错
54
+ * 没有可用的失效信号;而 web-admin 的 `appliedGeneration` 是那个模块的私有 WeakMap,不在公面上。
55
+ * 要缓存就得先给 web-admin 开一只「已提交世代」读口 —— 那是别人模块的接缝件,且**缓存失效写错
56
56
  * 一次,就恰好把本条 finding 刚关掉的那个陈旧窗原样放回来**(还多一层代码)。规模面亦不支持先做:
57
57
  * projects 是运维手写的登记簿(量级十几~百),而这条腿的**同一次**调用里,principal 在场那支还要
58
58
  * `await directory.lookup()`(网络/缓存),扫表在它旁边不构成瓶颈。⇒ 若哪天登记簿真长到会阻塞事件循环,
@@ -51,16 +51,16 @@ export declare const MAX_TASK_AGENTS = 32;
51
51
  * `ruleEntryListShapeOk`):引擎直接 `for (const entry of list)` —— 一个裸字符串 `"Bash"` 会被逐字符迭代成 `B` / `a` / `s` / `h` 四条
52
52
  * (deny 侧 = 意图静默落空,安全轴上的放宽方向)。条目的**文法与名字**是引擎的读法:允侧读不出的条目(`*` / 写路径 / 域名 / 退役名 …)引擎在开跑时发
53
53
  * `permission.allowed_tool_not_granted`(受众 = 用户);拒侧读成空的条目(文法或名字层)在 `resolveSpec` 拒(提交 400 / 续跑 409,`rule-entry-list.ts` 的
54
- * `skillDenyInertEntryOf`,判据 = 引擎的条目读法)。形对之后两道门再问 {@link skillToolListRefusal}(条数帽 + 引擎读不到的那一形 ⇒ 400)。
54
+ * `skillDenyInertEntryOf`,判据 = 引擎的条目读法)。形对之后两道门再问 {@link skillToolListRefusal}(条数帽 ⇒ 400)。
55
55
  * 条数帽 = 条目表那一只(`rule-entry-list.ts` `allowLayerEntryCountIssue`,准备开销的界;与请求 allow 桶、运维表同一只),
56
56
  * 在 {@link skillToolListRefusal} 里判;无长度帽([ref])。
57
57
  */
58
58
  export declare const skillToolListOk: (v: unknown) => v is readonly string[];
59
59
  /**
60
60
  * 一条技能(形已过两道门的字符串数组判)的两只清单在受理口的拒因 —— 都过 ⇒ `undefined`。两处受理口同调:顶层 `skills[]`
61
- * (`http/admission.ts` 的 `validateUserSkills`)、子代 `agents[].skills[]`({@link validateTaskAgents})。两问:条数帽;引擎读不到、却永远匹配不到的
62
- * 条目(工具段为空的协议名,`rule-entry-list.ts` 那一份,与配置表、会话规则写口同一只)。退役名 / 对端段铸不出 / 读成空的条目是引擎的读法(见上):
63
- * 允侧交引擎通告,拒侧由 `resolveSpec` 拒。
61
+ * (`http/admission.ts` 的 `validateUserSkills`)、子代 `agents[].skills[]`({@link validateTaskAgents})。一问:条数帽。退役名 / 对端段或工具段铸不出、为空 /
62
+ * 读成空的条目是引擎的读法(见上):允侧交引擎通告,拒侧由 `resolveSpec` 拒(7.116.0–7.122.x 本仓在这里另拒工具段为空的协议名,core 7.48.0 #1400 起
63
+ * 它是引擎判官的判词,随之退役)。
64
64
  */
65
65
  export declare function skillToolListRefusal(skill: Record<string, unknown>): string | undefined;
66
66
  /** [ref] 单条 agent 定义的形状裁决:null=合法;否则一句可 400 的英文错误(不带索引,调用方自己加)。
@@ -1,7 +1,7 @@
1
1
  import { isThinkingLevel } from "@sema-agent/core";
2
2
  import { taskWallClockSec } from "./task-workflow.js";
3
3
  import { isValidCwd } from "./task-cwd.js";
4
- import { allowLayerEntryCountIssue, describeEmptyToolSegmentEntry, emptyToolSegmentEntryOf, ruleEntryListShapeOk } from "./rule-entry-list.js";
4
+ import { allowLayerEntryCountIssue, ruleEntryListShapeOk } from "./rule-entry-list.js";
5
5
  export function normalizeSuggestNextPrompts(v) {
6
6
  if (v === true)
7
7
  return true;
@@ -76,9 +76,6 @@ export function skillToolListRefusal(skill) {
76
76
  const over = allowLayerEntryCountIssue(`skill.${key}`, list);
77
77
  if (over !== undefined)
78
78
  return over.message;
79
- const empty = emptyToolSegmentEntryOf(list);
80
- if (empty !== undefined)
81
- return describeEmptyToolSegmentEntry(`skill.${key}`, empty);
82
79
  }
83
80
  return undefined;
84
81
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * [DESIGN-269 车1 §2.2/§2.3 — A2A client seam] — project a caller's per-request A2A peers
3
3
  * (`TaskRequest.a2aPeers`) into the engine, so a `sema` run can talk to the agents the USER declares,
4
- * not only the ones the deployment's config center declares. Point-for-point mirror of `task-mcp.ts`
4
+ * not only the ones the deployment's web-admin declares. Point-for-point mirror of `task-mcp.ts`
5
5
  * (the MCP seam), because the trust question is the same question — and deliberately NOT a copy where
6
6
  * the two protocols differ (see 「A2A 比 MCP 窄」 below).
7
7
  *
@@ -108,13 +108,12 @@ export declare function planReviewDecisionExitsPlan(decision: "approve" | "edit"
108
108
  /**
109
109
  * 运维 `AUTONOMY=plan` 的**入口词地板**盖进提交体 —— 此后一条 run 的模式词只有存储体顶层 `permissionMode` 一个源。
110
110
  *
111
- * 规则:入口词 = core `clampPermissionMode(体的生效词, 地板).effective`(体无词 ⇒ 地板;比地板松的词 ⇒ 钳成地板;秩是 core 的,本仓不另写)。
112
- * 地板缺席 ⇒ 体**原物**交回(零字节变化)。盖章 = 新体 `{ ...body, permissionMode: 入口词 }`:调用方的对象不改;bundle 的
111
+ * 入口词 = `runtime-governance.ts` `entryPermissionMode(体的生效词, 地板).effective`(「词在地板下变成什么」的唯一一只函数;秩是 core 的)。本函数只加
112
+ * 「写进体」这一半:地板缺席 ⇒ 体**原物**交回(零字节变化);地板在场 ⇒ 新体 `{ ...body, permissionMode: 入口词 }`,调用方的对象不改;bundle 的
113
113
  * `settings.permissions.defaultMode` 不动 —— 顶层赢过它({@link effectivePermissionMode} 的优先序),再改它就是同一语义的第二个写者。
114
114
  *
115
- * 调用点两个:提交入口(`http/admission.ts` 的 `prepareSpec`:值形门全部判完之后、`resolveSpec` 之前)与 leader run 的入口体(`leader/wire.ts`:
116
- * leader 请求不带模式词,盖的是一份空体 ⇒ 入口词 = 地板本身;本车道的每一条 spec 与 worker 的续跑体都从它取词)。提交入口那一份体就是首跑装配读的体,也是 `buildCheckpointCtx` 持久化的体 ⇒ 一处盖章同时覆盖首跑与每一次续跑重建;
117
- * 装配腿与续跑腿都不读地板(两处读 = 两个源)。run-local 自建 spec、收不到客户端表态,在它的出生点直接写地板本身(同一个入口词)。
115
+ * 调用点一个:提交入口(`http/admission.ts` 的 `prepareSpec`:值形门全部判完之后、`resolveSpec` 之前)。那一份体就是首跑装配读的体,也是
116
+ * `buildCheckpointCtx` 持久化的体 ⇒ 一处盖章同时覆盖首跑与每一次续跑重建;装配腿与续跑腿都不读地板(两处读 = 两个源)。
118
117
  * 另一个写者是 `plan_review` 写回(`http/resume-legs.ts` `drivePlanReview`,判据 {@link planReviewDecisionExitsPlan})。
119
118
  * 热改 `AUTONOMY` 只影响之后提交的任务:在飞的 run 保持它出生时盖下的词。地板的属主是 `runtime-governance.ts` 的 `autonomyModeFloor`。
120
119
  */
@@ -1,11 +1,12 @@
1
- import { clampPermissionMode, combinePolicies, createFsWriteGatePolicy, parseRuleText, resolveReasoningProfile, rankOf, isThinkingLevel, CYBER_RISK, URL_SAFETY, HARNESS_SECTION_ANCHOR, RUN_WORKFLOW_TOOL_NAME, PERMISSION_MODES, isPermissionMode, ruleToolGrammarOf, } from "@sema-agent/core";
1
+ import { combinePolicies, createFsWriteGatePolicy, parseRuleText, resolveReasoningProfile, rankOf, isThinkingLevel, CYBER_RISK, URL_SAFETY, HARNESS_SECTION_ANCHOR, RUN_WORKFLOW_TOOL_NAME, PERMISSION_MODES, isPermissionMode, ruleToolGrammarOf, } from "@sema-agent/core";
2
2
  import { unmatchableToolNamesRefusal } from "./config.js";
3
3
  import { MAX_PERMISSION_RULES_PER_LIST, createRuleListPolicy } from "./permission-rule-list.js";
4
- import { allowLayerEntryCountIssue, describeAllowLayerOverCap, describeEmptyToolSegmentEntry, emptyToolSegmentEntryOf, ruleEntryListShapeOk } from "./rule-entry-list.js";
4
+ import { allowLayerEntryCountIssue, describeAllowLayerOverCap, ruleEntryListShapeOk } from "./rule-entry-list.js";
5
5
  import { tightenGoverned } from "./governance-overrides.js";
6
6
  import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "./request-key-closure.js";
7
7
  import { parseHooksConfig } from "./hooks/hook-runner.js";
8
8
  import { heldRuleName } from "./tool-rule-names.js";
9
+ import { entryPermissionMode } from "./runtime-governance.js";
9
10
  import { policyAskStandingAnswerFacts, standingAnswerDurablyRecordable } from "./tool-approval.js";
10
11
  export const PERMISSION_MODE_WORDS = PERMISSION_MODES.map((m) => `"${m}"`).join(" | ");
11
12
  export function coercePermissionMode(raw) {
@@ -33,9 +34,8 @@ export function planReviewDecisionExitsPlan(decision) {
33
34
  }
34
35
  }
35
36
  export function stampEntryPermissionMode(body, floor) {
36
- if (floor === undefined)
37
- return body;
38
- return { ...body, permissionMode: clampPermissionMode(storedBodyPermissionMode(body), floor).effective };
37
+ const entry = entryPermissionMode(storedBodyPermissionMode(body), floor);
38
+ return entry.floor === undefined ? body : { ...body, permissionMode: entry.effective };
39
39
  }
40
40
  export function storedBodyPermissionMode(body) {
41
41
  return effectivePermissionMode(body, parseTaskSettings(body.settings).settings);
@@ -347,9 +347,6 @@ function rejectUnmatchableSettingsNames(perms, pathBases) {
347
347
  if (unmatchable !== undefined)
348
348
  throw new Error(unmatchable.message);
349
349
  }
350
- const emptyAllow = perms.allow !== undefined ? emptyToolSegmentEntryOf(perms.allow) : undefined;
351
- if (emptyAllow !== undefined)
352
- throw new Error(describeEmptyToolSegmentEntry("permissions.allow", emptyAllow));
353
350
  }
354
351
  export function deriveSettingsPolicy(settings, gate, workflowGate) {
355
352
  const perms = settings.permissions;
@@ -5,6 +5,7 @@ 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";
7
7
  import type { ApprovalAskAuditSink } from "./approval-ask-audit-store.js";
8
+ import { type AskRowEndingCause, type SettleCause, type SettleOutcome } from "./approval-deny-reasons.js";
8
9
  import type { ParkCommitWatch } from "./plugins/park-commit-watch.js";
9
10
  import { type GovernanceAskMarks } from "./governance-ask-marks.js";
10
11
  import { type GovernancePosture } from "./runtime-governance.js";
@@ -25,6 +26,38 @@ export declare const APPROVAL_GATE_KINDS_SQL_IN: string;
25
26
  * (`test/parked-late-decision.test.ts` G3-c:本函数的输出经 `lookupRoute` 落 `approval-decide`)。会话段按路由的 `safeDecode` 对称编码。
26
27
  */
27
28
  export declare function approvalDecidePath(sessionId: string): string;
29
+ /**
30
+ * [ref] 随批小件:`tool_approval.not_pending` 404 的**判别位**([ref] 排障代价实证 —— 三因合并成一句人话,现场分不出「答案没地方兑」与「打错副本了」)。
31
+ * DECIDED/PARKED 已从 404 分流(DECIDED ⇒ 200 回放首决,回执带 `decidedBy`,**不是**成因;PARKED ⇒ 赎回席),残余两类:
32
+ * · 行 `VOID` / `DENIED`(没有人决过它)—— `cause` = **行上记的那个成因词**(问账 `denied_reason` 列;与决断口 410 `gone.ask` 体的 `cause`、审计 settle 行
33
+ * 的 `cause` 同一个词,闭集 {@link SettleCause});行上没写归因(存量行)⇒ 缺席,不替没写的行编一个词;
34
+ * · {@link NOT_PENDING_UNKNOWN_CAUSE} —— 无墓碑 / 无行 / 行仍在别处活着:换副本或换端点重试才有意义(这个词只属于 404 面,不是结局成因)。
35
+ * 对齐 [ref] 反枚举语义:cause 只在**已过属主门**的面上出,不扩枚举面(属主门不过 = 与未知 id 同形)。
36
+ * **无持久店的部署上恒不带**:那台机器压根没有行可判,编一个 cause 是撒谎(D1 体逐字不变)。
37
+ */
38
+ export declare const NOT_PENDING_UNKNOWN_CAUSE: "unknown_or_other_replica";
39
+ export type NotPendingCause = AskRowEndingCause | typeof NOT_PENDING_UNKNOWN_CAUSE;
40
+ /**
41
+ * 结算一张卡的**判决** —— 判别联合,逼每个调用点说清「这次等待是怎么结束的」:
42
+ * · `by:"human"` —— 一次**决议**到了(人答,或从问账行读回来的决议,含部署政策拒落成的 `DECIDED` 行,`hostSettledBy` 记它的来源词):`allowed` 说方向;审计 settle 行
43
+ * `outcome` = `allowed` / `denied`,**没有 `cause`**;
44
+ * · `by:"system"` —— 这次等待**没有等到决议就结束了**(非人结局):必须点名一个 {@link SettleCause};审计 settle 行 `outcome:"expired"` + 该 `cause`。
45
+ * 成因**只从事实读**(窗钟到 / 中止信号 / emit 零接收 / 腿作用域退出 / 兄弟被原子撤卡 / 有序关停锁存位 / 问账行的列),不从拒句散文判;
46
+ * 没有「裸 `settle(false, "expired")`」这一形。
47
+ */
48
+ export type SettleVerdict = {
49
+ readonly by: "human";
50
+ readonly allowed: boolean;
51
+ readonly updatedInput?: unknown;
52
+ /** 宿主自报来源(见 {@link HostSettledBy};缺席 = 人)。 */
53
+ readonly hostSettledBy?: HostSettledBy;
54
+ readonly denyReason?: string;
55
+ readonly readRootGrant?: string;
56
+ } | {
57
+ readonly by: "system";
58
+ readonly cause: SettleCause;
59
+ readonly hostSettledBy?: HostSettledBy;
60
+ };
28
61
  /**
29
62
  * 🔴 [ref](案A)追记 F6 —— durable 回决口(`POST /v1/tasks/:taskId/asks/:askId/decision`)的 **200 体
30
63
  * additive 判别位**:这次决议在**本副本**上有没有被一条活着的腿消费掉。
@@ -597,7 +630,13 @@ export interface ToolApprovalFrame {
597
630
  * 成因表也补了第四支:`settleVoidedSiblings` 的撤卡兄弟走的同样是这个词,那既不是 TTL 也不是断连。
598
631
  * Cosmetic dialog-dismiss(这句仍成立——它讲的是**帧的角色**,不是终局)。
599
632
  */
600
- outcome?: "allowed" | "denied" | "expired";
633
+ outcome?: SettleOutcome;
634
+ /**
635
+ * "tool_approval_complete" only(**ADDITIVE**):`outcome:"expired"` 的**成因** —— 与审计 settle 行 `cause` 是同一个词(闭集 {@link SettleCause}:窗到期 / 广播全灭 /
636
+ * 断连 / 呈不出去 / run 取消 / run 退出 / 批撤 / 兄弟被撤 / 崩溃 / 关停 ……)。**在场 ⇔ 非人结局**;人答(`allowed` / `denied`)不带。壳据它把「卡消失了」渲成具体的话
637
+ * (「已取消」「已到期」「断连」各自一句),而不再只有 `expired` 一个词。⚠️ 缺席不是证据:旧 server 从不发这个键,人答也不发。
638
+ */
639
+ cause?: SettleCause;
601
640
  }
602
641
  /** The per-run context `ask` recovers via ALS (mirrors QuestionRunContext + sessionId, which keys the allow-all). */
603
642
  /** [ref]:`GET /v1/approvals` 第二顶层键 `livePending` 的行形(与 durable `pending` 行**分数组不混编**
@@ -1363,7 +1402,7 @@ export declare class ToolApprovalCoordinator {
1363
1402
  * 三步:
1364
1403
  * ① 本进程握着的**每一张**未决卡(可达 / 悬挂 / 委派子代,不挑)按**断连同路**收场 —— {@link PendingApproval.forceParkNow}(park 路由;
1365
1404
  * `deny` 政策下是部署政策拒;有持久 ask 店时走同一把终局 claim)。有序关停与断连是同一件事:投递面要没了,**不是**有人拒了
1366
- * (不交裸 `false`,S-689 同律)。审计 settle 行携 `cause:"shutdown_before_park"`(成因在 `settle` 咽喉读锁存位,F10);
1405
+ * (不交裸 `false`,S-689 同律)。审计 settle 行携 `cause:"shutdown_before_park"`(`forceParkNow` 的调用点点名它);
1367
1406
  * ② 在 `deadlineMs` 之前等:未决卡结清、在飞腿闭合(闭了的腿照常落 `leg_closed`)、**本次路由到 park 的卡全部结清**
1368
1407
  * (F1:观察到 core 已处置这次调用 —— 停车行提交或承载它的腿退场 ⇒ 那张卡的审计 settle 行此刻才写,见 {@link settleParksAwaitingCommit})、
1369
1408
  * 店里在飞的 `put` 静默;
@@ -1427,7 +1466,7 @@ export declare class ToolApprovalCoordinator {
1427
1466
  *
1428
1467
  * 🔴 **本口只收「行真的没了」那一类**([ref] codex R3-F2,验真后拆分;红先钉在
1429
1468
  * `test/unattended-approval-policy.test.ts`):`expireAsk` 返回的 `voidedSiblings` 的行是 **VOID**,
1430
- * 裸 `(false,"expired")` 正是它们的真终局。而**调用方自己那个 askId** 的行是 **PARKING**(已转投递
1469
+ * 非人结局的判决(`{by:"system", cause}`)正是它们的真终局。而**调用方自己那个 askId** 的行是 **PARKING**(已转投递
1431
1470
  * 面)—— 把它混进本名单会让「同 askId 的重复本地注册」拿到裸 deny,而赢家拿的是 park 路由:同一条
1432
1471
  * 持久行、两种 live 终局。那一支改走 {@link settleSameAskIdParkRoute}。 */
1433
1472
  private settleVoidedSiblings;
@@ -1592,7 +1631,7 @@ export declare class ToolApprovalCoordinator {
1592
1631
  * 条目(跨副本/无流内窗)= 正常,返回 `{ settled: 0 }`,调用方据此诚实回显 `updatedInputForwarded`。
1593
1632
  *
1594
1633
  * 🔴 与 {@link settleVoidedSiblings} 是**两个语义,禁合并**(F29):那边是撤卡收尾,结算值恒
1595
- * `(false, "expired")`——批内兄弟被原子撤卡,它们的终局就是「没了」;这边是「同一只 askId 已经有了
1634
+ * `{by:"system", cause}`(`batch_sibling_withdrawn` 等)——批内兄弟被原子撤卡,它们的终局就是「没了」;这边是「同一只 askId 已经有了
1596
1635
  * 真决议」,重复注册必须拿到**同一个**决议(approve 就是 approve)——合并会把外部批准的重复条目错
1597
1636
  * 结算成拒绝。已被结算过的条目再调 settle 天然无操作(幂等),所以本口对「赢家自己已 settle」安全。
1598
1637
  */