@sema-agent/server 7.141.0 → 7.143.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 (341) hide show
  1. package/MIGRATION.md +657 -0
  2. package/USAGE.md +102 -30
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +61 -43
  5. package/dist/approval-ask-audit-store.js +69 -44
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +126 -27
  9. package/dist/approval-card.js +103 -23
  10. package/dist/approval-crash-convergence.d.ts +17 -7
  11. package/dist/approval-crash-convergence.js +94 -22
  12. package/dist/approval-deny-reasons.d.ts +34 -30
  13. package/dist/approval-deny-reasons.js +21 -6
  14. package/dist/approval-policy-settlement.d.ts +1 -1
  15. package/dist/approval-queue-kind.d.ts +27 -0
  16. package/dist/approval-queue-kind.js +6 -0
  17. package/dist/approval-reconciler.d.ts +41 -9
  18. package/dist/approval-reconciler.js +45 -42
  19. package/dist/audit.js +4 -2
  20. package/dist/auth-bridge.d.ts +9 -6
  21. package/dist/auth-bridge.js +9 -3
  22. package/dist/boot/adoption.js +2 -1
  23. package/dist/boot/budget-tracing.d.ts +17 -1
  24. package/dist/boot/budget-tracing.js +10 -6
  25. package/dist/boot/device-lane.d.ts +1 -1
  26. package/dist/boot/execution-env.d.ts +24 -4
  27. package/dist/boot/execution-env.js +26 -23
  28. package/dist/boot/execution-lane.js +2 -1
  29. package/dist/boot/exit-boundary.js +5 -4
  30. package/dist/boot/governance-seams.d.ts +26 -41
  31. package/dist/boot/governance-seams.js +61 -28
  32. package/dist/boot/late-binds.d.ts +7 -4
  33. package/dist/boot/late-binds.js +3 -1
  34. package/dist/boot/leader.js +2 -4
  35. package/dist/boot/memory-consolidation.d.ts +0 -8
  36. package/dist/boot/memory-consolidation.js +5 -4
  37. package/dist/boot/parked-revive-gate.js +2 -1
  38. package/dist/boot/permission-rules-audit.d.ts +0 -28
  39. package/dist/boot/permission-rules-audit.js +2 -1
  40. package/dist/boot/read-deny-anchor-audit.js +2 -1
  41. package/dist/boot/reapers.js +9 -7
  42. package/dist/boot/resolve-spec.d.ts +1 -1
  43. package/dist/boot/resolve-spec.js +19 -10
  44. package/dist/boot/retention-lane.js +5 -3
  45. package/dist/boot/runner-deps.d.ts +10 -7
  46. package/dist/boot/runner-deps.js +20 -29
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.js +4 -3
  49. package/dist/boot/shutdown.d.ts +9 -0
  50. package/dist/boot/shutdown.js +19 -4
  51. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  52. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  53. package/dist/boot/stage-03-store-backend.js +1 -2
  54. package/dist/boot/stage-04-stores.d.ts +5 -2
  55. package/dist/boot/stage-04-stores.js +6 -7
  56. package/dist/boot/stage-05-execution-env.d.ts +6 -3
  57. package/dist/boot/stage-05-execution-env.js +8 -6
  58. package/dist/boot/stage-06-runners.d.ts +6 -3
  59. package/dist/boot/stage-06-runners.js +3 -4
  60. package/dist/boot/stage-07-capability-layer.d.ts +6 -3
  61. package/dist/boot/stage-07-capability-layer.js +7 -2
  62. package/dist/boot/stage-08-reapers.d.ts +6 -3
  63. package/dist/boot/stage-08-reapers.js +3 -2
  64. package/dist/boot/stage-09-leader.d.ts +6 -3
  65. package/dist/boot/stage-10-http-server.d.ts +6 -3
  66. package/dist/boot/stage-10-http-server.js +14 -5
  67. package/dist/boot/stores.d.ts +5 -2
  68. package/dist/boot/stores.js +10 -9
  69. package/dist/boot/web-admin.d.ts +5 -1
  70. package/dist/boot/web-admin.js +48 -36
  71. package/dist/boot/webfetch-summarize-lane.js +2 -1
  72. package/dist/boot/workflow-orchestration.js +3 -2
  73. package/dist/capabilities/builtin-tools.d.ts +2 -1
  74. package/dist/capabilities/builtin-tools.js +2 -4
  75. package/dist/capabilities/composite-members.d.ts +2 -1
  76. package/dist/capabilities/composite-members.js +2 -1
  77. package/dist/capabilities/hands-lane.d.ts +9 -39
  78. package/dist/capabilities/hands-lane.js +8 -13
  79. package/dist/capabilities/mcp-probe.d.ts +3 -2
  80. package/dist/capabilities/scenarios.d.ts +11 -1
  81. package/dist/capabilities/scenarios.js +1 -0
  82. package/dist/capabilities/skills.d.ts +1 -17
  83. package/dist/capabilities/skills.js +0 -8
  84. package/dist/capability-facts.d.ts +31 -7
  85. package/dist/capability-facts.js +27 -4
  86. package/dist/card-void.d.ts +6 -9
  87. package/dist/config-catalog.js +2 -1
  88. package/dist/config-dir-trust.js +58 -29
  89. package/dist/config-invariants.d.ts +7 -1
  90. package/dist/config-invariants.js +7 -0
  91. package/dist/config-provider.d.ts +10 -0
  92. package/dist/config-provider.js +15 -4
  93. package/dist/config-root-migration.d.ts +13 -0
  94. package/dist/config-root-migration.js +99 -0
  95. package/dist/config-types.d.ts +19 -8
  96. package/dist/config.d.ts +10 -3
  97. package/dist/config.js +18 -4
  98. package/dist/delegated-session-owner.d.ts +5 -3
  99. package/dist/delegated-session-owner.js +1 -1
  100. package/dist/device-ws-protocol.d.ts +1 -0
  101. package/dist/device-ws-protocol.js +2 -1
  102. package/dist/env-model-table-gate.d.ts +53 -0
  103. package/dist/env-model-table-gate.js +53 -0
  104. package/dist/execution-lane-caps.d.ts +2 -1
  105. package/dist/fleet/fleet-bus.d.ts +34 -55
  106. package/dist/fleet/fleet-bus.js +35 -100
  107. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  108. package/dist/fleet/fleet-reconciler.js +1 -1
  109. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  110. package/dist/fleet/subagent-tail-bus.js +15 -28
  111. package/dist/hooks/hook-runner.d.ts +6 -0
  112. package/dist/hooks/hook-runner.js +58 -8
  113. package/dist/host-decision.d.ts +54 -20
  114. package/dist/host-decision.js +42 -14
  115. package/dist/http/admission.d.ts +1 -1
  116. package/dist/http/admission.js +7 -3
  117. package/dist/http/approval-sweeps.js +11 -8
  118. package/dist/http/caller-trust.d.ts +1 -1
  119. package/dist/http/dispatch.js +4 -2
  120. package/dist/http/durable-run-leg.js +2 -2
  121. package/dist/http/engine-refusal.d.ts +16 -0
  122. package/dist/http/engine-refusal.js +17 -0
  123. package/dist/http/execution-context.d.ts +2 -2
  124. package/dist/http/idempotency.d.ts +1 -1
  125. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  126. package/dist/http/memory-compliance-failure-reply.js +4 -6
  127. package/dist/http/owner-access.d.ts +11 -0
  128. package/dist/http/owner-access.js +13 -0
  129. package/dist/http/principal-gate.d.ts +3 -1
  130. package/dist/http/principal-gate.js +17 -8
  131. package/dist/http/resume-legs.d.ts +21 -7
  132. package/dist/http/resume-legs.js +76 -58
  133. package/dist/http/resume-restatement.d.ts +39 -0
  134. package/dist/http/resume-restatement.js +25 -0
  135. package/dist/http/route-ctx.d.ts +35 -10
  136. package/dist/http/route-ctx.js +1 -1
  137. package/dist/http/route-table.js +2 -0
  138. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  139. package/dist/http/routes/approvals-assistant.js +142 -31
  140. package/dist/http/routes/attachments.js +18 -0
  141. package/dist/http/routes/capabilities.js +16 -4
  142. package/dist/http/routes/memory-policy.d.ts +2 -2
  143. package/dist/http/routes/memory-policy.js +27 -7
  144. package/dist/http/routes/notify-wake.js +23 -25
  145. package/dist/http/routes/rules.js +48 -13
  146. package/dist/http/routes/runs.js +12 -11
  147. package/dist/http/routes/session-memory-sync.d.ts +91 -0
  148. package/dist/http/routes/session-memory-sync.js +174 -0
  149. package/dist/http/routes/session-sync.js +13 -20
  150. package/dist/http/routes/sessions-list.d.ts +2 -1
  151. package/dist/http/routes/sessions.d.ts +2 -2
  152. package/dist/http/routes/sessions.js +22 -23
  153. package/dist/http/routes/tasks.js +34 -54
  154. package/dist/http/run-read-face.d.ts +7 -0
  155. package/dist/http/run-read-face.js +9 -3
  156. package/dist/http/send.d.ts +5 -0
  157. package/dist/http/send.js +9 -2
  158. package/dist/http/server.d.ts +27 -15
  159. package/dist/http/server.js +4 -6
  160. package/dist/http/stored-body-replay.js +15 -4
  161. package/dist/http/submit-replay.d.ts +4 -3
  162. package/dist/http/submit-replay.js +2 -2
  163. package/dist/http/sync-submit-body.d.ts +21 -4
  164. package/dist/http/sync-submit-body.js +13 -0
  165. package/dist/http/wire-types.d.ts +17 -7
  166. package/dist/identity-source.d.ts +21 -2
  167. package/dist/identity-source.js +6 -0
  168. package/dist/leader/leader.js +5 -2
  169. package/dist/leader/wire.d.ts +7 -1
  170. package/dist/leader/wire.js +6 -5
  171. package/dist/leg-facts.d.ts +37 -0
  172. package/dist/leg-facts.js +15 -0
  173. package/dist/memory-bundle-engine.d.ts +1 -4
  174. package/dist/memory-bundle-engine.js +2 -2
  175. package/dist/memory-incident-sink.d.ts +19 -6
  176. package/dist/memory-incident-sink.js +8 -4
  177. package/dist/memory-operator-faces.d.ts +30 -66
  178. package/dist/memory-operator-faces.js +17 -88
  179. package/dist/memory-scope-stores.d.ts +38 -40
  180. package/dist/memory-scope-stores.js +51 -36
  181. package/dist/memory-scope.d.ts +0 -9
  182. package/dist/memory-scope.js +0 -9
  183. package/dist/memory-sync-client.d.ts +21 -21
  184. package/dist/memory-sync-client.js +62 -43
  185. package/dist/memory-sync-identity.d.ts +24 -0
  186. package/dist/memory-sync-identity.js +57 -0
  187. package/dist/memory-sync.d.ts +27 -5
  188. package/dist/memory-sync.js +29 -7
  189. package/dist/model-plane-face.d.ts +13 -7
  190. package/dist/model-plane-face.js +2 -1
  191. package/dist/observability/fail-open.d.ts +47 -14
  192. package/dist/observability/fail-open.js +37 -11
  193. package/dist/observability/run-terminal.d.ts +92 -34
  194. package/dist/observability/run-terminal.js +171 -162
  195. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  196. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  197. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  198. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  199. package/dist/orchestration/workflow-park-decision.js +5 -3
  200. package/dist/org-delivery-gate.d.ts +11 -0
  201. package/dist/org-delivery-gate.js +19 -1
  202. package/dist/parked-decide.d.ts +13 -9
  203. package/dist/parked-decide.js +7 -7
  204. package/dist/parked-revive-surface.js +1 -1
  205. package/dist/peer-inbound-face.d.ts +127 -0
  206. package/dist/peer-inbound-face.js +158 -0
  207. package/dist/permission-rule-list.d.ts +13 -9
  208. package/dist/permission-rule-list.js +7 -3
  209. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  210. package/dist/plugins/approval-ask-store-file.js +64 -11
  211. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  212. package/dist/plugins/approval-ask-store-memory.js +17 -14
  213. package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
  214. package/dist/plugins/approval-ask-store-sql.js +79 -30
  215. package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
  216. package/dist/plugins/checkpoint-store-sql.js +9 -7
  217. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  218. package/dist/plugins/file-history-store-sql.js +24 -19
  219. package/dist/plugins/file-run-store.d.ts +35 -1
  220. package/dist/plugins/file-run-store.js +108 -9
  221. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  222. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  223. package/dist/plugins/local-checkpoint-store.d.ts +1 -1
  224. package/dist/plugins/local-checkpoint-store.js +2 -2
  225. package/dist/plugins/local-session-store.d.ts +42 -9
  226. package/dist/plugins/local-session-store.js +83 -33
  227. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  228. package/dist/plugins/local-task-attachment-store.js +67 -43
  229. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  230. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  231. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  232. package/dist/plugins/mailbox-store-sql.js +76 -7
  233. package/dist/plugins/memory-key-guards.d.ts +3 -3
  234. package/dist/plugins/memory-run-store.d.ts +6 -1
  235. package/dist/plugins/memory-run-store.js +11 -1
  236. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  237. package/dist/plugins/memory-sync-store-pg.js +21 -0
  238. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  239. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  240. package/dist/plugins/one-time-migrations.d.ts +58 -2
  241. package/dist/plugins/one-time-migrations.js +161 -4
  242. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  243. package/dist/plugins/org-delivery-quota-store.js +2 -12
  244. package/dist/plugins/park-commit-watch.d.ts +1 -1
  245. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  246. package/dist/plugins/permission-rule-store-file.js +15 -2
  247. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  248. package/dist/plugins/permission-rule-store-sql.js +35 -2
  249. package/dist/plugins/remote-env-device.d.ts +8 -11
  250. package/dist/plugins/remote-env-device.js +6 -3
  251. package/dist/plugins/remote-env-e2b.d.ts +23 -4
  252. package/dist/plugins/remote-env-e2b.js +111 -28
  253. package/dist/plugins/remote-env-k8s.d.ts +61 -22
  254. package/dist/plugins/remote-env-k8s.js +133 -33
  255. package/dist/plugins/remote-env-local-docker.d.ts +15 -3
  256. package/dist/plugins/remote-env-local-docker.js +40 -12
  257. package/dist/plugins/retention-store-sql.d.ts +2 -2
  258. package/dist/plugins/run-store-sql.d.ts +9 -1
  259. package/dist/plugins/run-store-sql.js +9 -1
  260. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  261. package/dist/plugins/sandbox-read-floor.js +2 -7
  262. package/dist/plugins/sql-errors.d.ts +10 -1
  263. package/dist/plugins/sql-errors.js +13 -0
  264. package/dist/plugins/store-backend.d.ts +33 -35
  265. package/dist/plugins/store-backend.js +10 -1
  266. package/dist/plugins/store-contracts.d.ts +50 -1
  267. package/dist/plugins/store-contracts.js +6 -0
  268. package/dist/plugins/task-attachment-store.d.ts +112 -14
  269. package/dist/plugins/task-attachment-store.js +207 -29
  270. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  271. package/dist/plugins/tool-result-store-sql.js +23 -2
  272. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  273. package/dist/plugins/wiring-section-codec.js +55 -0
  274. package/dist/plugins/workspace-fill.d.ts +60 -0
  275. package/dist/plugins/workspace-fill.js +106 -0
  276. package/dist/project-bundle.d.ts +38 -0
  277. package/dist/project-bundle.js +609 -0
  278. package/dist/rule-entry-list.d.ts +3 -2
  279. package/dist/rule-entry-list.js +5 -1
  280. package/dist/rules-consent.d.ts +28 -5
  281. package/dist/rules-consent.js +40 -28
  282. package/dist/run-local.js +11 -13
  283. package/dist/runs.d.ts +12 -8
  284. package/dist/runs.js +6 -8
  285. package/dist/runtime-governance.d.ts +1 -1
  286. package/dist/sandbox-egress-policy.d.ts +4 -1
  287. package/dist/sandbox-egress-policy.js +3 -1
  288. package/dist/sandbox-git-plane.d.ts +31 -12
  289. package/dist/sandbox-git-plane.js +24 -4
  290. package/dist/security.d.ts +9 -0
  291. package/dist/security.js +8 -0
  292. package/dist/server-secret-env.d.ts +4 -0
  293. package/dist/session-error-wire.d.ts +36 -0
  294. package/dist/session-error-wire.js +13 -0
  295. package/dist/session-incarnation.d.ts +1 -1
  296. package/dist/session-notify-door.d.ts +106 -0
  297. package/dist/session-notify-door.js +93 -0
  298. package/dist/session-sync.d.ts +9 -14
  299. package/dist/session-sync.js +5 -5
  300. package/dist/session-workspace.d.ts +3 -13
  301. package/dist/session-workspace.js +0 -9
  302. package/dist/standing-answer-grant.d.ts +5 -0
  303. package/dist/standing-answer-grant.js +10 -0
  304. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  305. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  306. package/dist/task-mcp.d.ts +1 -1
  307. package/dist/task-settings.d.ts +21 -10
  308. package/dist/task-settings.js +46 -13
  309. package/dist/terminal.d.ts +39 -19
  310. package/dist/terminal.js +65 -22
  311. package/dist/tool-approval.d.ts +56 -37
  312. package/dist/tool-approval.js +78 -71
  313. package/dist/trace/core-keyset-guard.d.ts +134 -14
  314. package/dist/trace/engine-notice-wire.d.ts +9 -3
  315. package/dist/trace/engine-notice-wire.js +7 -3
  316. package/dist/trace/exit-seat.d.ts +9 -2
  317. package/dist/trace/exit-seat.js +1 -0
  318. package/dist/trace/ledger-sink.d.ts +10 -6
  319. package/dist/trace/ledger-sink.js +2 -2
  320. package/dist/trace/model-segment.d.ts +55 -25
  321. package/dist/trace/model-segment.js +101 -33
  322. package/dist/trace/project.d.ts +25 -5
  323. package/dist/trace/project.js +22 -0
  324. package/dist/trace/redact.d.ts +61 -9
  325. package/dist/trace/redact.js +1490 -468
  326. package/dist/trace/self-minted-wire.d.ts +745 -24
  327. package/dist/trace/self-minted-wire.js +239 -9
  328. package/dist/trace/wire-projection-faces.d.ts +2 -2
  329. package/dist/trace/wire-projection-faces.js +2 -2
  330. package/dist/verifier-pause-card.d.ts +33 -5
  331. package/dist/verifier-pause-card.js +15 -10
  332. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  333. package/dist/web-admin-client/apply-effective.js +109 -9
  334. package/dist/web-admin-client/effective-keys.js +2 -0
  335. package/dist/web-admin-client/types.d.ts +4 -0
  336. package/dist/workspace-space.d.ts +19 -3
  337. package/dist/workspace-space.js +8 -4
  338. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  339. package/package.json +3 -2
  340. package/wire-changes/server@7.142.0.json +639 -0
  341. package/wire-changes/server@7.143.0.json +1167 -0
@@ -219,16 +219,24 @@ export type LocalImportIndeterminateCode =
219
219
  /** 兑付走本身没走完(本层抛出/中断)⇒ 这一条连走都没走到。 */
220
220
  | "walk_failed";
221
221
  /** prepare 面的一行。判别式联合:被收下的行**没有**拒因字段可读,被拒的行**必然**带拒因 ——
222
- * 「admitted 却带 reason」这种矛盾态在类型上不可表达。 */
222
+ * 「admitted 却带 reason」这种矛盾态在类型上不可表达。
223
+ * 收下的**收紧**(deny / ask)在 prepare 当场经直写接缝落店,行带它的结局 `outcome`(`persisted` = 这次写了 / `no-op` = 等价规则已在店);
224
+ * 收下的**放行**没有 `outcome` —— 它的结局在 redeem 回执里(放行要同意,收紧不等同意;见 `prepareLocalImport`)。 */
223
225
  export type LocalImportPreviewMember = {
224
226
  key: LocalImportRuleKey;
225
227
  admitted: true;
228
+ } | {
229
+ key: LocalImportRuleKey;
230
+ admitted: true;
231
+ outcome: LocalImportTighteningOutcome;
226
232
  } | {
227
233
  key: LocalImportRuleKey;
228
234
  admitted: false;
229
235
  reason: LocalImportRefusalCode;
230
236
  detail: string;
231
237
  };
238
+ /** 一条收紧在 prepare 当场落店的结局(与兑付回执的 `persisted` / `no-op` 同词同义;直写接缝 `addPersistedRule` 的 `added` / `no-op`)。 */
239
+ export type LocalImportTighteningOutcome = "persisted" | "no-op";
232
240
  /** 兑付回执的一行。 */
233
241
  export interface LocalImportOutcomeMember {
234
242
  key: LocalImportRuleKey;
@@ -266,6 +274,14 @@ export type LocalImportPrepared = {
266
274
  ok: false;
267
275
  reason: "batch-too-large";
268
276
  bytes: number;
277
+ }
278
+ /** 一条收紧写不进店(直写接缝答 `failed`)⇒ 这一批的放行全部扣下(不铸记录、不铸票)。`committed` 原样是 core 的两词闭集,
279
+ * wire 上与 `POST /v1/rules` 的写失败同一码同一键;此前已落的收紧留着(收紧方向),同一批重发即幂等(已落的答 `no-op`)。 */
280
+ | {
281
+ ok: false;
282
+ reason: "tightening-write-failed";
283
+ committed: RuleWriteCommitted;
284
+ detail: string;
269
285
  };
270
286
  /** A7 redeem 的结果。 */
271
287
  export type LocalImportRedeemed =
@@ -456,13 +472,20 @@ export type CardRulePersisted = {
456
472
  * 🔴 不 switch、不翻译、不折叠:词表属主是 core,本仓照转。 */
457
473
  code?: string;
458
474
  };
459
- /** 一层用户交上来的 settings(HTTP 载荷已 zod 校验过的形)。 */
460
- export interface RuleImportLayerInput {
461
- layer: ImportedSettingsLayer;
475
+ /**
476
+ * 一层用户交上来的 settings(HTTP 载荷已 zod 校验过的形)—— 按 `layer` 的联合,与引擎的 `CcImportLayer` 同形:
477
+ * 用户层**没有** `root`(它的 `/x` 在它自己的配置目录读,引擎不把它带进店;交了 root 的体在边界 400),项目层与本地层带 `root`(规则的作用域根)。
478
+ */
479
+ export type RuleImportLayerInput = {
480
+ layer: "userSettings";
481
+ path: string;
482
+ content: string;
483
+ } | {
484
+ layer: Exclude<ImportedSettingsLayer, "userSettings">;
462
485
  path: string;
463
486
  root: string;
464
487
  content: string;
465
- }
488
+ };
466
489
  /**
467
490
  * scope 的 **wire 形**:`global` | `project:<root>` 的判别式串([ref] v2 §6 F5「显式成文」)。
468
491
  *
@@ -232,25 +232,14 @@ function buildLocalImportLayers(candidates) {
232
232
  const byRoot = new Map();
233
233
  for (const c of candidates) {
234
234
  const key = c.scope.kind === "global" ? "" : c.scope.root;
235
- let bucket = byRoot.get(key);
236
- if (bucket === undefined) {
237
- bucket = { deny: [], ask: [], allow: [] };
238
- byRoot.set(key, bucket);
239
- }
240
- bucket[c.behavior].push(c.rule);
235
+ const bucket = byRoot.get(key) ?? [];
236
+ bucket.push(c.rule);
237
+ byRoot.set(key, bucket);
241
238
  }
242
- return [...byRoot].map(([root, lists]) => ({
243
- layer: root === "" ? "userSettings" : "projectSettings",
244
- path: root === "" ? LOCAL_IMPORT_LAYER_PATH : `${LOCAL_IMPORT_LAYER_PATH}:${root}`,
245
- root: root === "" ? "/" : root,
246
- readFile: async () => JSON.stringify({
247
- permissions: {
248
- ...(lists.deny.length > 0 ? { deny: lists.deny } : {}),
249
- ...(lists.ask.length > 0 ? { ask: lists.ask } : {}),
250
- ...(lists.allow.length > 0 ? { allow: lists.allow } : {}),
251
- },
252
- }),
253
- }));
239
+ return [...byRoot].map(([root, allow]) => {
240
+ const readFile = async () => JSON.stringify({ permissions: { allow } });
241
+ return root === "" ? { layer: "userSettings", path: LOCAL_IMPORT_LAYER_PATH, readFile } : { layer: "projectSettings", path: `${LOCAL_IMPORT_LAYER_PATH}:${root}`, root, readFile };
242
+ });
254
243
  }
255
244
  function buildLocalImportMembers(members) {
256
245
  return members.map((m) => {
@@ -367,12 +356,10 @@ export function createRuleConsentLane(stores, opts) {
367
356
  return { ok: true, kind: "single", rule: redeemed.rule, rev: redeemed.rev, alreadyRedeemed: redeemed.alreadyRedeemed };
368
357
  },
369
358
  async prepareImport(principal, layers) {
370
- const ccLayers = layers.map((l) => ({
371
- layer: l.layer,
372
- path: l.path,
373
- root: l.root,
374
- readFile: async () => l.content,
375
- }));
359
+ const ccLayers = layers.map((l) => {
360
+ const readFile = async () => l.content;
361
+ return l.layer === "userSettings" ? { layer: l.layer, path: l.path, readFile } : { layer: l.layer, path: l.path, root: l.root, readFile };
362
+ });
376
363
  const { preview, approvalId } = await prepareCcImport({ layers: ccLayers, principal, deps });
377
364
  if (approvalId === undefined) {
378
365
  return { ok: true, preview };
@@ -494,16 +481,41 @@ export function createRuleConsentLane(stores, opts) {
494
481
  continue;
495
482
  }
496
483
  seen.add(dedupKey);
484
+ admitted.push({ at: members.length, row: screened });
497
485
  members.push({ key, admitted: true });
498
- admitted.push(screened);
499
486
  }
500
- if (admitted.length === 0)
487
+ const allows = [];
488
+ for (const { at, row: c } of admitted) {
489
+ const key = members[at].key;
490
+ const behavior = c.behavior;
491
+ if (!isDirectWritableRuleBehavior(behavior)) {
492
+ allows.push({ ...c, behavior });
493
+ continue;
494
+ }
495
+ const added = await addPersistedRule({ behavior, rule: c.rule, scope: c.scope, principal, provider: stores.provider });
496
+ switch (added.status) {
497
+ case "added":
498
+ members[at] = { key, admitted: true, outcome: "persisted" };
499
+ break;
500
+ case "no-op":
501
+ members[at] = { key, admitted: true, outcome: "no-op" };
502
+ break;
503
+ case "failed":
504
+ localImportLogger.warn("local_import_tightening_write_failed", { behavior, scope: key.scope, committed: added.committed, note: "a deny / ask of this batch did not land — the batch's allows are withheld (no import record, no ticket); sending the same batch again is idempotent" });
505
+ return { ok: false, reason: "tightening-write-failed", committed: added.committed, detail: added.error };
506
+ default: {
507
+ const unknown = added;
508
+ throw new Error(`unknown addPersistedRule outcome: ${JSON.stringify(unknown)}`);
509
+ }
510
+ }
511
+ }
512
+ if (allows.length === 0)
501
513
  return { ok: true, preview: { members } };
502
- const { preview, approvalId } = await prepareCcImport({ layers: buildLocalImportLayers(admitted), principal, deps });
514
+ const { preview, approvalId } = await prepareCcImport({ layers: buildLocalImportLayers(allows), principal, deps });
503
515
  const engineKeys = new Set(preview.candidates.map((c) => `${c.behavior}${LOCAL_IMPORT_KEY_SEP}${serializeRuleScope(c.scope)}${LOCAL_IMPORT_KEY_SEP}${c.rule}`));
504
516
  for (let i = 0; i < members.length; i++) {
505
517
  const m = members[i];
506
- if (m === undefined || !m.admitted)
518
+ if (m === undefined || !m.admitted || "outcome" in m)
507
519
  continue;
508
520
  if (engineKeys.has(`${m.key.behavior}${LOCAL_IMPORT_KEY_SEP}${m.key.scope}${LOCAL_IMPORT_KEY_SEP}${m.key.rule}`))
509
521
  continue;
package/dist/run-local.js CHANGED
@@ -19,7 +19,7 @@ import { applyRuntimeGovernance, autonomyModeFloor, entryPermissionMode } from "
19
19
  import { ForkRoutingSessionStore } from "./plugins/fork-routing-session-store.js";
20
20
  import { taskWallClockSec } from "./task-workflow.js";
21
21
  import { applyCenterArtifact, centerSourceOnError } from "./capabilities/center-prompts.js";
22
- import { buildUnpricedCeilingNotice, loadConfig, logConfigDiagnostics, parseConfigProvider, parseNumOrFailNonNegative } from "./config.js";
22
+ import { buildUnpricedCeilingNotice, isRosterGateArmed, loadConfig, logConfigDiagnostics, parseConfigProvider, parseNumOrFailNonNegative } from "./config.js";
23
23
  import { buildStoreOpenRefusalTail } from "./plugins/store-open-refusal.js";
24
24
  import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
25
25
  import { configLocalRoot, createConfigProvider } from "./config-provider.js";
@@ -28,6 +28,7 @@ import { buildUnreadConfigFileFields, buildUnreadConfigKeyFields } from "./web-a
28
28
  import { composeExecutionLane, settleHostLaneShell, warnReadDenyFloorUnkept } from "./boot/execution-lane.js";
29
29
  import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
30
30
  import { logConfigDirMigration, migrateLocalConfigDirectory } from "./config-d-migration.js";
31
+ import { logEnvModelsMigration, runEnvModelsMigration } from "./config-root-migration.js";
31
32
  import { assertLocalConfigDirTrusted, ConfigDirUntrustedError } from "./config-dir-trust.js";
32
33
  import { applyEffective, applyCenterReadFace, applySkillsManifest, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./web-admin-client/facade.js";
33
34
  import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
@@ -42,7 +43,7 @@ import { createTaskListLane } from "./boot/task-list-lane.js";
42
43
  import { pickHandsRunner, withoutHands } from "./capabilities/hands-lane.js";
43
44
  import { HttpError, sessionIdShapeIssue } from "./security.js";
44
45
  import { createMemoryEngineIncidentSink } from "./memory-incident-sink.js";
45
- import { fileMemoryEngineRoot, memoryEngineBackendFor, memoryLayersNamedBy, memorySpecForRequest } from "./memory-scope.js";
46
+ import { fileMemoryEngineRoot, memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
46
47
  import { createMemoryScopeStores } from "./memory-scope-stores.js";
47
48
  import { createMemoryProjectLayers } from "./memory-project-layer.js";
48
49
  import { assertProjectLayerOwnable } from "./project-identity.js";
@@ -52,7 +53,7 @@ import { startMemorySyncRunner } from "./memory-sync-client.js";
52
53
  import { buildPricing, cappedCeiling, createTracer } from "./budget.js";
53
54
  import { createSharedRunnerDeps } from "./boot/runner-deps.js";
54
55
  import { createPeerDesk } from "./peer-seat.js";
55
- import { createGovernanceSeams } from "./boot/governance-seams.js";
56
+ import { assertGovernanceAssemblable, createGovernanceSeams } from "./boot/governance-seams.js";
56
57
  import { assertRetentionLaneWirable } from "./boot/retention-lane.js";
57
58
  import { createOrgMemoryAdmissionWiring } from "./boot/org-memory.js";
58
59
  import { assembleDeploymentMods } from "./boot/deployment-mods.js";
@@ -362,6 +363,8 @@ export async function runLocal(argv, deps = {}) {
362
363
  printErr(err instanceof Error ? err.message : String(err));
363
364
  return 2;
364
365
  }
366
+ const envModelsMigration = { root, env: process.env, envTableIsPlaceholder: isRosterGateArmed(config.webAdmin) };
367
+ logEnvModelsMigration(logger, envModelsMigration, await runEnvModelsMigration(envModelsMigration));
365
368
  logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
366
369
  try {
367
370
  await composeExecutionLane(config, { configSource: "local", localRoot: root, logger, drivesFromFile: ["host"] });
@@ -393,7 +396,7 @@ export async function runLocal(argv, deps = {}) {
393
396
  for (const d of r.droppedEntries ?? [])
394
397
  logger.warn("config_entry_dropped", { domain: d.domain, entry: d.entry, reasonCode: d.reasonCode, error: d.error, version: r.effective.version, phase: "boot", note: "this one entry failed its domain schema and was dropped on its own — the rest of the candidate applies (per-entry tolerance); fix the named entry to bring it back" });
395
398
  applying = true;
396
- applyEffective(config, r.effective, logger, { leg: "boot" });
399
+ applyEffective(config, r.effective, logger, { leg: "boot", catalogSource: r.catalogSource });
397
400
  effective = r.effective;
398
401
  candidatePrompts = verdict.prompts;
399
402
  if (effective?.mcp)
@@ -487,7 +490,7 @@ export async function runLocal(argv, deps = {}) {
487
490
  const engineDataRoot = fileMemoryEngineRoot(config, root);
488
491
  const fileEngine = memoryEngineBackendFor(config, root, memoryEngineIncident);
489
492
  const memoryEngine = fileEngine !== undefined
490
- ? createMemoryScopeStores({ backend: fileEngine.backend, root: engineDataRoot, namedLayers: () => memoryLayersNamedBy({ ...config, memoryScope: args.user ?? "local" }), onIncident: memoryEngineIncident })
493
+ ? createMemoryScopeStores({ backend: fileEngine.backend, root: engineDataRoot, onIncident: memoryEngineIncident })
491
494
  : undefined;
492
495
  try {
493
496
  judgeConsolidationValve({ config, memoryEngine });
@@ -582,6 +585,7 @@ export async function runLocal(argv, deps = {}) {
582
585
  ],
583
586
  retentionExecutor: null,
584
587
  });
588
+ assertGovernanceAssemblable(config);
585
589
  const { registrations: deploymentMods } = await assembleDeploymentMods({ metrics, brandIdentity: true, declaration: config.modsDeclaration, logger });
586
590
  const sharedRunnerDeps = createSharedRunnerDeps({
587
591
  metrics,
@@ -770,14 +774,8 @@ export async function runLocal(argv, deps = {}) {
770
774
  }
771
775
  if (result.terminal.kind !== "completed" || unfinishedStop !== undefined)
772
776
  exitCode = 1;
773
- if (memorySync) {
774
- try {
775
- await memorySync.syncOnce("post-task");
776
- }
777
- catch (err) {
778
- logger.warn("memory_sync_failed", { reason: "post-task", err: String(err) });
779
- }
780
- }
777
+ if (memorySync)
778
+ await memorySync.syncOnce("post-task");
781
779
  await settleSessionBackground();
782
780
  runner.sessions.dispose();
783
781
  subRunner.sessions.dispose();
package/dist/runs.d.ts CHANGED
@@ -4,6 +4,7 @@ import { type EntryProblem } from "./entry-problems.js";
4
4
  import type { SendUserFileEmitter } from "./capabilities/send-user-file-tool.js";
5
5
  import type { RunStore } from "./plugins/store-backend.js";
6
6
  import type { Metrics } from "./observability/metrics.js";
7
+ import type { RunSkillEntry } from "./capabilities/skills.js";
7
8
  import { type RunAbort } from "./run-cancel-context.js";
8
9
  import type { ModelUsageTracker, PromptManifestTracker } from "./budget.js";
9
10
  import type { ElicitationCoordinator } from "./elicitation.js";
@@ -39,16 +40,15 @@ import type { UserInputLedger } from "./user-input-ledger.js";
39
40
  * first-marker-wins guards live inside the seam.
40
41
  */
41
42
  /** [ref]③(b) + codex R2: the bg agent-handle OUTPUT read, kind-gated BEFORE any poll. `pollTask` is the
42
- * generic registry face and polling is NOT side-effect-free for other kinds — a terminal workflow poll
43
- * fires `onServedTerminal` (acknowledges the completion as served → suppresses its notification) and a
44
- * bash poll advances the output cursor. `getAccessibleTask` is a pure lookup: resolve + access-check +
43
+ * generic registry face and polling is NOT side-effect-free for other kinds — a bash poll advances the
44
+ * output cursor (and a workflow's read face is its journal, not this one). `getAccessibleTask` is a pure lookup: resolve + access-check +
45
45
  * type-check FIRST; only a `background_agent` row is ever polled (non-blocking). Everything else returns
46
46
  * the registry's own not_found shape, indistinguishable from an unknown handle (the route 404s it).
47
47
  *
48
48
  * 1.250 durable arm (core 1.364, [ref] follow-up delivered): a FULL in-process miss (`!row`) falls
49
49
  * through to `pollTask(…, { agentStore })` — core's durable arm only fires for `a*`-shaped handles
50
50
  * (DURABLE_AGENT_HANDLE_RE) behind `canAccessAgentRecord`, and with NO in-process handle the live
51
- * workflow/bash branches are unreachable, so the kind-gate's reason (onServedTerminal / cursor advance)
51
+ * workflow/bash branches are unreachable, so the kind-gate's reason (cursor advance / the journal owning workflow reads)
52
52
  * cannot trigger. Terminal rows serve the durable snapshot cross-instance/post-restart; a foreign-writer
53
53
  * running row answers the honest "outcome unknown here"; anything else is core's own not_found (byte-same
54
54
  * route 404 as today). A row that IS in-process but of the wrong type stays a hard 404 — the process
@@ -372,9 +372,8 @@ approval?: {
372
372
  executionLane: import("./execution-lane-caps.js").ExecutionLane;
373
373
  },
374
374
  /** 本腿结算用的 checkpoint 店(`deps.checkpointStore`),两件事:①[ref] park 投影腿的读口 —— 在场时 durable park 的
375
- * `suspended` 事件带 `toolCallId`(graft 见 {@link parkToolCallId});②验证门结算时作废验证器自己的停驻卡
376
- * ({@link voidVerifierPauseCard}:本服务兑现不了的卡不留在待决面上);③停驻没落定就以失败收场时作废手里那张卡({@link voidHeldParkCard})。
377
- * 缺席 ⇒ ①旧字节逐字不变;②③带凭据的停驻响亮留痕、卡由兜底收割。 */
375
+ * `suspended` 事件带 `toolCallId`(graft 见 {@link parkToolCallId});②停驻没落定就以失败收场时作废手里那张卡({@link voidHeldParkCard})。
376
+ * 缺席 ⇒ ①旧字节逐字不变;②带凭据的停驻响亮留痕、卡由兜底收割。(验证器自己的停驻卡不经本店:结算时交本腿的 Runner 动词,见 {@link voidVerifierPauseCard}。) */
378
377
  checkpointCards?: ParkCheckpointReader & CardVoidPort,
379
378
  /** [ref]:装配期(`prepareSpec` → `resolveSpec`)铸下的用户面通告 —— 那一刻本腿的通告口还没开,
380
379
  * 所以由本腿在 `registerEngineNoticeLeg` 那一拍连同 `pending` 一起投(投递单点仍是 `route()`)。
@@ -412,7 +411,12 @@ acceptance?: RunAcceptance,
412
411
  * 会话行的位置与项目那一格的记录座(`session-workspace.ts`;唯一写者):普通流形逐帧喂(这条腿自己的 `workspace_changed` 排一次写),
413
412
  * `done` 时等写落定再落终局。只回结果的 verify / cascade 形宿主手里没有流 ⇒ 不记。缺席 ⇒ 不记行(与本参数存在之前逐字相同)。
414
413
  */
415
- workspaceRecorder?: SessionWorkspaceRecorder): Promise<void>;
414
+ workspaceRecorder?: SessionWorkspaceRecorder,
415
+ /**
416
+ * 这条 run 交给引擎的技能名册(`wiring_manifest.skills` 段;部署事实 `LegFacts.skills`,`leg-facts.ts`:受理漏斗在复制之前读出)。
417
+ * 缺席 = 嵌入方自带的装配器没铸 ⇒ 账本行不带技能段。
418
+ */
419
+ runSkills?: readonly RunSkillEntry[]): Promise<void>;
416
420
  /** How often a running instance refreshes its run's updated_at (liveness, independent of events).
417
421
  * Must stay strictly below `runStaleSec` (asserted at startup AND on every hot config candidate) or the
418
422
  * reaper would race live runs. [ref]:数值的单源是 `config-invariants.ts`(那条不变量的属主),两个消费面
package/dist/runs.js CHANGED
@@ -9,7 +9,6 @@ import { isSessionErrorCode, sessionErrorHttp } from "./session-error-wire.js";
9
9
  import { redactErrorMessage } from "./observability/run-terminal.js";
10
10
  import { withPrincipal } from "./observability/principal-context.js";
11
11
  import { withModelReachScope } from "./model-reach-scope.js";
12
- import { runSkillsOf } from "./capabilities/skills.js";
13
12
  import { createInstructionSelectionLeg } from "./instruction-selection.js";
14
13
  import { redactSecrets } from "./trace/redact.js";
15
14
  import { taskNotificationEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "./trace/project.js";
@@ -18,7 +17,7 @@ import { registerEngineNoticeLeg } from "./trace/engine-notice-wire.js";
18
17
  import { recordTurnActivity } from "./turn-activity.js";
19
18
  import { buildCancelledLedgerRow, CANCELLED_CODE, createRunAbort, mintCancelledResult } from "./run-cancel-context.js";
20
19
  import { createApprovalCardEmitter, resolveApprovalLeg } from "./tool-approval.js";
21
- import { fleetRunResiduals, isFleetAgentTerminalNotification } from "./fleet/fleet-bus.js";
20
+ import { fleetRunResiduals } from "./fleet/fleet-bus.js";
22
21
  import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
23
22
  import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "./orchestration/workflow-completion-inbox.js";
24
23
  import { isParkLedgerEventType } from "./trace/ledger-events.js";
@@ -93,6 +92,7 @@ const PREPARE_REFUSAL_HTTP_STATUS = {
93
92
  "config.memory_project_marker": 409,
94
93
  "config.memory_project_marker_nested": 409,
95
94
  "config.read_deny_floor_unkept": 409,
95
+ "config.mcp_server_name_collision": 409,
96
96
  };
97
97
  export function resumeAtHttpStatus(result) {
98
98
  const code = failureCodeOf(result.terminal);
@@ -277,7 +277,7 @@ export async function voidHeldParkCard(held, hostSessionId, cards, leg) {
277
277
  return;
278
278
  await voidPendingCard({ token: held.terminal.token, sessionId: hostSessionId }, cards, "server.park.held-card-void-failed", `leg=${leg}`);
279
279
  }
280
- export async function runInBackground(runner, spec, runStore, taskId, metrics, principal, verify, cascade, instrumentDegenerate, planCacheProbe, persistThinking = false, inflight, preemptable, steerable, modelUsage, elicitation, elicitOwner, captureTurnAnchor, fleetPublisher, captureUserMessageAnchor, question, workflowCompletionInbox, subagentSteer, completionDiagLog, sendUserFile, promptManifests, approval, checkpointCards, pendingEngineNotices, trustedInternals, userInputLedger, acceptance, workspaceRecorder) {
280
+ export async function runInBackground(runner, spec, runStore, taskId, metrics, principal, verify, cascade, instrumentDegenerate, planCacheProbe, persistThinking = false, inflight, preemptable, steerable, modelUsage, elicitation, elicitOwner, captureTurnAnchor, fleetPublisher, captureUserMessageAnchor, question, workflowCompletionInbox, subagentSteer, completionDiagLog, sendUserFile, promptManifests, approval, checkpointCards, pendingEngineNotices, trustedInternals, userInputLedger, acceptance, workspaceRecorder, runSkills) {
281
281
  const startedAt = Date.now();
282
282
  metrics?.addGauge("runs_active", 1);
283
283
  fleetPublisher?.onStart();
@@ -352,7 +352,6 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
352
352
  const parkLeg = async (word, res) => {
353
353
  const grafted = await graftParkToolCallId(res, checkpointCards);
354
354
  await sink.appendParked(word, grafted);
355
- await flushModelUsage();
356
355
  const sealed = sealResultForExit(grafted);
357
356
  reached = { kind: word, result: sealed };
358
357
  await parkRowWrite[word](sealed);
@@ -376,7 +375,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
376
375
  acceptance?.settle(safe);
377
376
  };
378
377
  const instructionLeg = createInstructionSelectionLeg();
379
- const sink = createLedgerSink({ appendEvent: (seq, type, data) => runStore.appendEvent(taskId, seq, type, data), persistThinking, notifiedKeys, onActivity: (kind, statusData) => recordTurnActivity(taskId, kind, statusData), legSections: () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(spec) }) });
378
+ const sink = createLedgerSink({ appendEvent: (seq, type, data) => runStore.appendEvent(taskId, seq, type, data), persistThinking, notifiedKeys, onActivity: (kind, statusData) => recordTurnActivity(taskId, kind, statusData), legSections: () => ({ instructions: instructionLeg.segment(), skills: runSkills }), usage: { modelUsage, taskId } });
380
379
  const append = (type, data) => sink.append(type, data);
381
380
  const flush = () => sink.flush();
382
381
  const flushModelUsage = () => appendModelUsageDelta(append, modelUsage, taskId);
@@ -431,9 +430,8 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
431
430
  if (defaultSubagentTailBus.hasSubscribers(n.task_id)) {
432
431
  defaultSubagentTailBus.publish(n.task_id, { type: "task_settled", taskId: n.task_id, status: n.status, ...(typeof n.seq === "number" ? { seq: n.seq } : {}), ...(n.summary ? { summary: redactSecrets(n.summary) } : {}) });
433
432
  }
434
- const hadRow = isFleetAgentTerminalNotification(n) ? (fleetPublisher?.onChildTerminal(n.sessionId ?? n.task_id, n.status, n.task_id, n.toolUseId) ?? false) : false;
435
433
  const parked = !legLive && Boolean(workflowCompletionInbox && spec.sessionId);
436
- completionDiagLog?.("task_notification_observed", { route: "bg-run-start", taskId: n.task_id, taskType: n.task_type, status: n.status, hadFleetRow: hadRow, legLive, parkedDurable: parked });
434
+ completionDiagLog?.("task_notification_observed", { route: "bg-run-start", taskId: n.task_id, taskType: n.task_type, status: n.status, legLive, parkedDurable: parked });
437
435
  if (parked) {
438
436
  void workflowCompletionInbox.enqueue(taskNotificationInboxEntry(spec.sessionId, elicitOwner ?? owner, n, Date.now(), taskId, opts?.priority)).catch((err) => completionDiagLog?.("park_enqueue_failed", { route: "bg-run-start", taskId: n.task_id, err: err instanceof Error ? err.message : String(err) }));
439
437
  }
@@ -468,7 +466,7 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
468
466
  const result = await compositeLeg();
469
467
  observedDone = result;
470
468
  causeAtDone = cancelCtrl.cause();
471
- await voidVerifierPauseCard(result, checkpointCards);
469
+ await voidVerifierPauseCard(result, runner);
472
470
  await flush();
473
471
  await flushPromptManifest();
474
472
  await settleLegResult(result);
@@ -230,7 +230,7 @@ export interface GovernancePosture {
230
230
  * (checkpoint → ask)今天**没有读口**:两条 list 读口都硬过滤 `state='STREAM_PENDING'`,而 park 完的行是
231
231
  * `PARKED`;唯一精确的连接键是 ask 行上的 `gate_token`,要按它反查得给店加一个新读口(SQL 面 = 双库集成
232
232
  * 门)。派生 `deriveAskId(...)` 也不行:它吃 `legKey`(= 上一腿 resume token 的摘要)、`parentToolCallId` 与这一问的
233
- * 类集([ref]);前两维从 checkpoint 行推不出来,类集在 park 行上老行缺席、续跑不补 —— 二腿/子代/老行形上会算出一个
233
+ * 类集([ref])与展示的动作(工具名 + 入参摘要,7.143.0);前两维从 checkpoint 行推不出来,类集在 park 行上老行缺席、续跑不补 —— 二腿/子代/老行形上会算出一个
234
234
  * **错**的 id —— 在「等的谁」这条通道上,错 id 比缺席坏得多(`http/active-run-conflict.ts` 的 `resumeEntryForGate` 的 default 臂是同一条纪律)。故诚实缺席。
235
235
  */
236
236
  export declare function governanceOriginOf(gate: {
@@ -52,7 +52,10 @@ export interface EgressPolicyInputs {
52
52
  * 读数 → 缺口(纯函数、全函数:不抛;顺序:读不到的表 → 策略缺席 → 逐节点逐地址 → IPv6)。一张表读不到,只跳过要它的那一判;另一张照判。
53
53
  */
54
54
  export declare function sandboxEgressGaps(inputs: EgressPolicyInputs): SandboxEgressGap[];
55
- /** 读数的说法:每个缺口一行 warn `sandbox_egress_policy_gap` + 一次 `recordFailOpen`(P-DEBT);零缺口一行 info `sandbox_egress_policy_checked`。 */
55
+ /**
56
+ * 读数的说法:每个缺口一行 warn `sandbox_egress_policy_gap` + 一次 `recordFailOpen`(P-DEBT);零缺口一行 info `sandbox_egress_policy_checked`。
57
+ * `unreadable` 的 `detail` 是控制面请求的失败句(客户端异常原文)⇒ 经出口座(`operator-log-text`)出门,与起服面其余运维行里的抛出物文本同一读法。
58
+ */
56
59
  export declare function sayEgressPolicyReading(gaps: readonly SandboxEgressGap[], logger: {
57
60
  info(msg: string, fields?: Record<string, unknown>): void;
58
61
  warn(msg: string, fields?: Record<string, unknown>): void;
@@ -1,5 +1,6 @@
1
1
  import { BlockList, isIP } from "node:net";
2
2
  import { recordFailOpen } from "./observability/fail-open.js";
3
+ import { seatText } from "./trace/exit-seat.js";
3
4
  export const SANDBOX_IPV6_WORDS = ["enabled", "disabled"];
4
5
  export const SANDBOX_IPV6_DEFAULT = "enabled";
5
6
  export function sandboxPodSysctls(ipv6) {
@@ -229,7 +230,8 @@ export function sayEgressPolicyReading(gaps, logger, namespace) {
229
230
  }
230
231
  for (const gap of gaps) {
231
232
  recordFailOpen("server.sandbox-egress.policy-gap", `kind=${gap.kind}${gap.kind === "unreadable" ? ` what=${gap.what}` : ""}`);
232
- logger?.warn("sandbox_egress_policy_gap", { namespace, ...gap, effect: effectOf(gap) });
233
+ const shown = gap.kind === "unreadable" ? { ...gap, detail: seatText("operator-log-text", gap.detail) } : gap;
234
+ logger?.warn("sandbox_egress_policy_gap", { namespace, ...shown, effect: effectOf(gap) });
233
235
  }
234
236
  }
235
237
  //# sourceMappingURL=sandbox-egress-policy.js.map
@@ -38,26 +38,36 @@ export interface SandboxGitPlanePremises {
38
38
  /** The patch judge's refusal for a pod that carries the broker (`podSpecPatchBrokerRefusal`); `undefined` = the patch may land. */
39
39
  readonly patchRefusal: string | undefined;
40
40
  readonly brokerImage: string | undefined;
41
- /** The routed origins (`readSandboxGitConfig`); `null` = no `sandboxGit` block. */
41
+ /** The routed origins — the live config's `sandboxGit` block as committed (`config.sandboxGit`); `null` = no block. */
42
42
  readonly origins: readonly string[] | null;
43
43
  }
44
+ /** The boot's readings the judge needs besides config: the secret seat answer (asked once, by stage 5) and the static patch judge's refusal. */
45
+ export interface SandboxGitPlaneBootReadings {
46
+ readonly secretSeat?: SandboxSecretSeat;
47
+ readonly patchRefusal?: string;
48
+ }
44
49
  /** THE judge: the first premise that fails, in the written order; all hold ⇒ on with per-origin rows. Pure. */
45
50
  export declare function judgeSandboxGitPlane(p: SandboxGitPlanePremises): SandboxGitPlane;
46
51
  /** The secret seat is asked for the plane only when every premise before it holds (a deployment the plane is off for asks nothing for it). */
47
52
  export declare function sandboxGitPlaneAsksSecretSeat(p: Pick<SandboxGitPlanePremises, "multiTenant" | "k8sLane" | "callerCredential" | "centerUrl">): boolean;
48
- /** The premises read from config, plus the two boot readings (seat answer, patch refusal) when the boot has them. */
49
- export declare function sandboxGitPlanePremisesOf(config: ServiceConfig, readings: {
50
- readonly secretSeat?: SandboxSecretSeat;
51
- readonly patchRefusal?: string;
52
- }): SandboxGitPlanePremises;
53
+ /** The premises read from the live config, plus the two boot readings (seat answer, patch refusal) when the boot has them. */
54
+ export declare function sandboxGitPlanePremisesOf(config: ServiceConfig, readings: SandboxGitPlaneBootReadings): SandboxGitPlanePremises;
55
+ /** The plane's read-time seat (see the file head): {@link SandboxGitPlaneSeat.now} judges on every call; {@link SandboxGitPlaneSeat.settle} asks the boot's IO premise. */
56
+ export interface SandboxGitPlaneSeat {
57
+ /** The reading now — the judge over the boot readings settled so far and the live config. Synchronous; every reader calls it per read and keeps no copy. */
58
+ now(): SandboxGitPlane;
59
+ /** Asks the secret seat once (stage 5 awaits it), only when the four premises before it hold; a later call asks nothing. */
60
+ settle(): Promise<void>;
61
+ }
53
62
  /**
54
- * Wiring point — the effective `sandboxGit` block (the origins this deployment routes through the broker, canonical form, ≤ 16). Its shape
55
- * and its canonical-form judge belong to the settings-schema contract package (`SandboxGitConfig`, 14.7.0 — picked up: the block rides the effective
56
- * wire verbatim); this reader is not wired to it yet ⇒ `null` (the plane stays off, `no_origins`). To be replaced by the package reader — no local copy of the shape.
63
+ * The plane's ONE seat. `premisesOf` = the premises over the live config (the execution env hands `(r) => sandboxGitPlanePremisesOf(config, r)` — the
64
+ * config object every commit of the effective configuration mutates); `boot.patchRefusal` = the static patch judge's answer (a boot reading from the start);
65
+ * `boot.askSecretSeat` = the lane's secret-seat review (only the k8s lane has one; absent ⇒ never asked ⇒ the seat stays unverified).
57
66
  */
58
- export declare function readSandboxGitConfig(_config: ServiceConfig): {
59
- readonly origins: readonly string[];
60
- } | null;
67
+ export declare function createSandboxGitPlaneSeat(premisesOf: (readings: SandboxGitPlaneBootReadings) => SandboxGitPlanePremises, boot: {
68
+ readonly patchRefusal?: string | undefined;
69
+ readonly askSecretSeat?: (() => Promise<SandboxSecretSeat>) | undefined;
70
+ }): SandboxGitPlaneSeat;
61
71
  /**
62
72
  * Wiring point — does this worker hold the credential the console's vault admits on its resolve endpoint (the worker-assertion token)?
63
73
  * The server has no reader for it yet ⇒ `false` (the plane stays off, `no_caller_credential`). Replaced by the plane's vault client.
@@ -76,6 +86,15 @@ export interface SandboxGitRunRows {
76
86
  * `sandbox_broker_identity_unread` —— every miss reads as "not sso" ⇒ no broker (fail-closed), none of them throws into the pod's connect.
77
87
  */
78
88
  export declare function runIdentitySourceOf(runId: string | undefined, runs: SandboxGitRunRows | undefined, logger?: Pick<Logger, "warn">): Promise<IdentitySource | undefined>;
89
+ /**
90
+ * The k8s run binding's broker-seat reader (the adapter asks it once per pod, `K8sRunEnvSeats.brokerSeatOf`): reads the plane ONCE per pod, before the
91
+ * run-row read — off ⇒ none and no row read at all; on ⇒ {@link sandboxBrokerSeatOf} over that one reading and the row's recorded identity source.
92
+ * `runs` is the late-bound run store (absent ⇒ no row ⇒ not `sso` ⇒ none).
93
+ */
94
+ export declare function createSandboxBrokerSeatOf(planeNow: () => SandboxGitPlane, brokerImage: string | undefined, runs: (() => SandboxGitRunRows | undefined) | undefined, logger?: Pick<Logger, "warn">): (runId: string | undefined) => Promise<{
95
+ readonly image: string;
96
+ readonly origins: readonly string[];
97
+ } | undefined>;
79
98
  /** The broker seat for one run's pod: the plane on ∧ the image set ∧ the run's recorded identity source `sso` ⇒ the image + every origin of the reading (http too); otherwise none. */
80
99
  export declare function sandboxBrokerSeatOf(plane: SandboxGitPlane, brokerImage: string | undefined, identitySource: IdentitySource | undefined): {
81
100
  readonly image: string;
@@ -21,7 +21,7 @@ export const SANDBOX_GIT_PLANE_OFF_TEXT = {
21
21
  secret_seat_denied: `the sandbox Role does not allow secrets ${SANDBOX_SECRET_SEAT_VERBS.lease.join(" / ")} (the lease Secret) in the sandbox namespace`,
22
22
  pod_patch_reaches_broker: "the deployment's pod-spec patch could reach the broker container (a podSecurityContext, or a field outside the broker white-list)",
23
23
  broker_image_unset: "K8S_SANDBOX_BROKER_IMAGE is not set (the broker container's image; this engine's own image is the recommended value)",
24
- no_origins: "the effective configuration routes no git origins to the plane (sandboxGit.origins)",
24
+ no_origins: `the effective configuration routes no git origins to the plane (sandboxGit.origins): the console projects the block only on this worker's own pull (${WEB_ADMIN_ENV.worker}), and a block that fails its contract is read as no origins (log line web_admin_sandbox_git_refused)`,
25
25
  };
26
26
  const isHttps = (url) => url !== undefined && URL.canParse(url) && new URL(url).protocol === "https:";
27
27
  export function judgeSandboxGitPlane(p) {
@@ -73,11 +73,23 @@ export function sandboxGitPlanePremisesOf(config, readings) {
73
73
  secretSeat: readings.secretSeat,
74
74
  patchRefusal: readings.patchRefusal,
75
75
  brokerImage: lane?.provider === "k8s" ? lane.brokerImage : undefined,
76
- origins: readSandboxGitConfig(config)?.origins ?? null,
76
+ origins: config.sandboxGit?.origins.map((e) => e.origin) ?? null,
77
77
  };
78
78
  }
79
- export function readSandboxGitConfig(_config) {
80
- return null;
79
+ export function createSandboxGitPlaneSeat(premisesOf, boot) {
80
+ let readings = boot.patchRefusal !== undefined ? { patchRefusal: boot.patchRefusal } : {};
81
+ let settled = false;
82
+ return {
83
+ now: () => judgeSandboxGitPlane(premisesOf(readings)),
84
+ settle: async () => {
85
+ if (settled)
86
+ return;
87
+ settled = true;
88
+ if (boot.askSecretSeat === undefined || !sandboxGitPlaneAsksSecretSeat(premisesOf(readings)))
89
+ return;
90
+ readings = { ...readings, secretSeat: await boot.askSecretSeat() };
91
+ },
92
+ };
81
93
  }
82
94
  export function readSandboxGitCallerCredential(_config) {
83
95
  return false;
@@ -97,6 +109,14 @@ export async function runIdentitySourceOf(runId, runs, logger) {
97
109
  return undefined;
98
110
  }
99
111
  }
112
+ export function createSandboxBrokerSeatOf(planeNow, brokerImage, runs, logger) {
113
+ return async (runId) => {
114
+ const plane = planeNow();
115
+ if (plane.state !== "on")
116
+ return undefined;
117
+ return sandboxBrokerSeatOf(plane, brokerImage, await runIdentitySourceOf(runId, runs?.(), logger));
118
+ };
119
+ }
100
120
  export function sandboxBrokerSeatOf(plane, brokerImage, identitySource) {
101
121
  if (plane.state !== "on" || brokerImage === undefined || brokerImage === "" || identitySource !== "sso")
102
122
  return undefined;
@@ -6,6 +6,7 @@ import type { TaskRequestBody } from "./http/wire-types.js";
6
6
  import type { StagingHandle } from "./session-sync-kernel.js";
7
7
  import type { ClientSessionRowWrite, ReplaySessionRowWrite, ReplaySessionRowWriteOutcome, SessionRowPatch, SessionRowWriteOutcome } from "./session-row.js";
8
8
  import type { ExecutionPlacementSeat } from "./execution-placement.js";
9
+ import type { SessionUnreadable } from "./session-error-wire.js";
9
10
  import type { ForkTarget, ForkToOutcome } from "./plugins/session-fork.js";
10
11
  import { type OwnerlessClaim } from "./delegated-session-owner.js";
11
12
  /** One row of the session-list projection (CC /resume picker) — the durable session abstraction's enumeration
@@ -38,6 +39,12 @@ export interface SessionListItem {
38
39
  * primitive ∧ the row has an occupant token); additive key, passed through unprojected (`sessions-list.ts`). Same name and meaning as
39
40
  * `SessionSummary.rowTag` in `plugins/store-contracts.ts`. */
40
41
  rowTag?: string;
42
+ /** The session's archive cannot be read — present-iff the session head's leaf read throws (a list row is a session ROW: its facts live on the
43
+ * row and read fine; this says the CONTENT does not). `errorCode` = the code the session's own reads answer for it (`GET /v1/sessions/:id` /
44
+ * `…/head` / `…/events` / `PATCH` once admitted) — one table, `openFaceFaultWire` in `session-error-wire.ts`, the only minter `sessionUnreadableOf`.
45
+ * A store whose head leaf is a row column (the SQL twins) never carries it. Additive key, passed through unprojected (`sessions-list.ts`).
46
+ * Same name and meaning as `SessionSummary.unreadable` in `plugins/store-contracts.ts`. */
47
+ unreadable?: SessionUnreadable;
41
48
  }
42
49
  /**
43
50
  * 会话店的行格写原语(规则与判序:`session-row.ts` 头注「写原语」)—— 按入口分两只重载:客户端写(PATCH)的结局闭集四员;行重放(2c 导入落定后的那一笔)
@@ -456,6 +463,8 @@ export declare function setSsoScope(req: IncomingMessage, scope: string): void;
456
463
  export declare function ssoVerifiedScope(req: IncomingMessage): string | undefined;
457
464
  export declare function setSsoRole(req: IncomingMessage, role: string): void;
458
465
  export declare function ssoVerifiedRole(req: IncomingMessage): string | undefined;
466
+ export declare function setSsoPrincipalInc(req: IncomingMessage, principalInc: string): void;
467
+ export declare function ssoVerifiedPrincipalInc(req: IncomingMessage): string | undefined;
459
468
  export declare function verifiedPrincipal(req: IncomingMessage, config: ServiceConfig): string | undefined;
460
469
  export {};
461
470
  //# sourceMappingURL=security.d.ts.map
package/dist/security.js CHANGED
@@ -210,6 +210,14 @@ export function ssoVerifiedRole(req) {
210
210
  const v = SSO_ROLES.get(req);
211
211
  return v !== undefined && v.length > 0 ? v : undefined;
212
212
  }
213
+ const SSO_PRINCIPAL_INCS = new WeakMap();
214
+ export function setSsoPrincipalInc(req, principalInc) {
215
+ SSO_PRINCIPAL_INCS.set(req, principalInc);
216
+ }
217
+ export function ssoVerifiedPrincipalInc(req) {
218
+ const v = SSO_PRINCIPAL_INCS.get(req);
219
+ return v !== undefined && v.length > 0 ? v : undefined;
220
+ }
213
221
  export function verifiedPrincipal(req, config) {
214
222
  const sso = ssoVerifiedPrincipal(req);
215
223
  if (sso) {
@@ -76,6 +76,10 @@ export declare function serverCredentialValueSources(modelApiKeyEnv?: ModelApiKe
76
76
  * `holdOwnCredentialValues` 同一姿势:不收 + 说一次),经留痕座结构化点名那个变量一次 —— `warn` 行 `own_credential_value_not_withheld { name, reason }`
77
77
  * ({@link recordOwnCredentialValueNotWithheld};`reason` 是引擎拒句原文,从不回显值;起服第一步还没有 logger 时当拍经进程默认的 JSON 行日志器写 stderr,不缓冲),能力位 `inherit_env.own_credential_values_withheld`
78
78
  * 因此答 false(位真 ⇔ 值臂真扣)。引擎拒一个值时声明保持上一份,所以逐个交表的中间态都是上一份的超集。
79
+ * 🔴 **这一行是本服务唯一的写者**:值是网关密钥(`MODEL_API_KEY` / `ANTHROPIC_API_KEY`)时,进程输出里另有一行**引擎**的裸 `console.warn`(`a credential the engine was handed is …`)——
80
+ * 它写在 `createOpenAIBrain` / `createAnthropicBrain` 的收值口,那个口没有通告席(适配器配置没有 `onNotice`;`holdOwnCredentialValues` 不在 core 根导出),core 把这一形记为已知限制。
81
+ * 本仓不在引擎外面吞 console、也不拿声明口去抢引擎的「每进程每值说一次」账(下游不改上游座的语义);等 core 给席或让声明口的拒收记作已说。读数与翻面条件:
82
+ * `test/own-credential-value-boot-lines.test.ts`(真主进程;零裸行的期望以 `it.fails` 立着,core 改形那天转红再翻成常规钉)。
79
83
  * 返回声明的名单(只名、不值)。
80
84
  */
81
85
  export declare function declareServerWithheldEnv(modelApiKeyEnv?: ModelApiKeyEnvTable): readonly string[];