@sema-agent/server 7.139.0 → 7.141.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 (328) hide show
  1. package/MIGRATION.md +471 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +94 -26
  5. package/dist/adoption/runner.js +1 -1
  6. package/dist/adoption/sql.js +1 -1
  7. package/dist/approval-batch-census.d.ts +27 -0
  8. package/dist/approval-batch-census.js +27 -0
  9. package/dist/approval-card.d.ts +37 -22
  10. package/dist/approval-card.js +6 -3
  11. package/dist/approval.d.ts +15 -0
  12. package/dist/approval.js +10 -0
  13. package/dist/audit.d.ts +4 -2
  14. package/dist/audit.js +2 -2
  15. package/dist/bench/s1/live-deps.js +3 -2
  16. package/dist/bench/s1/row.d.ts +5 -2
  17. package/dist/bench/s1/row.js +2 -22
  18. package/dist/boot/adoption.js +1 -1
  19. package/dist/boot/device-lane.d.ts +11 -0
  20. package/dist/boot/device-lane.js +16 -0
  21. package/dist/boot/engine-lease.d.ts +24 -3
  22. package/dist/boot/engine-lease.js +9 -2
  23. package/dist/boot/execution-env.js +18 -12
  24. package/dist/boot/execution-lane.d.ts +8 -0
  25. package/dist/boot/execution-lane.js +6 -1
  26. package/dist/boot/memory-boundary.d.ts +16 -53
  27. package/dist/boot/memory-boundary.js +10 -20
  28. package/dist/boot/memory-consolidation.d.ts +16 -12
  29. package/dist/boot/memory-consolidation.js +24 -13
  30. package/dist/boot/reapers.d.ts +2 -2
  31. package/dist/boot/resolve-spec.d.ts +3 -5
  32. package/dist/boot/resolve-spec.js +9 -8
  33. package/dist/boot/runner-deps.d.ts +3 -3
  34. package/dist/boot/runner-deps.js +1 -0
  35. package/dist/boot/session-faces.d.ts +1 -1
  36. package/dist/boot/session-faces.js +4 -3
  37. package/dist/boot/shutdown.js +5 -0
  38. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  39. package/dist/boot/stage-03-store-backend.js +2 -3
  40. package/dist/boot/stage-04-stores.d.ts +2 -6
  41. package/dist/boot/stage-04-stores.js +5 -5
  42. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  43. package/dist/boot/stage-05-execution-env.js +3 -1
  44. package/dist/boot/stage-06-runners.d.ts +2 -8
  45. package/dist/boot/stage-06-runners.js +3 -3
  46. package/dist/boot/stage-07-capability-layer.d.ts +2 -7
  47. package/dist/boot/stage-07-capability-layer.js +8 -10
  48. package/dist/boot/stage-08-reapers.d.ts +2 -7
  49. package/dist/boot/stage-09-leader.d.ts +2 -7
  50. package/dist/boot/stage-10-http-server.d.ts +2 -7
  51. package/dist/boot/stage-10-http-server.js +6 -4
  52. package/dist/boot/stores.d.ts +3 -6
  53. package/dist/boot/stores.js +37 -44
  54. package/dist/boot/task-list-lane.d.ts +1 -1
  55. package/dist/boot/task-list-lane.js +1 -1
  56. package/dist/boot/web-admin.js +36 -9
  57. package/dist/capabilities/execution-lane.d.ts +2 -2
  58. package/dist/capabilities/scenarios.d.ts +1 -1
  59. package/dist/capability-facts.d.ts +9 -0
  60. package/dist/capability-facts.js +9 -0
  61. package/dist/card-void.d.ts +38 -0
  62. package/dist/card-void.js +23 -0
  63. package/dist/config-catalog.js +12 -8
  64. package/dist/config-provider.d.ts +18 -17
  65. package/dist/config-provider.js +28 -36
  66. package/dist/config-types.d.ts +36 -9
  67. package/dist/config.js +56 -46
  68. package/dist/delegated-session-owner.d.ts +23 -20
  69. package/dist/delegated-session-owner.js +2 -2
  70. package/dist/deployment-shape.d.ts +9 -8
  71. package/dist/deployment-shape.js +4 -4
  72. package/dist/device-store.d.ts +7 -0
  73. package/dist/device-store.js +3 -0
  74. package/dist/execution-config-root.d.ts +22 -0
  75. package/dist/execution-config-root.js +35 -0
  76. package/dist/execution-lane-caps.d.ts +145 -107
  77. package/dist/execution-lane-caps.js +144 -83
  78. package/dist/execution-placement.d.ts +3 -0
  79. package/dist/execution-placement.js +7 -0
  80. package/dist/fleet/drain-entry.d.ts +3 -0
  81. package/dist/hosted-posture.d.ts +8 -0
  82. package/dist/hosted-posture.js +4 -0
  83. package/dist/http/admission.js +3 -3
  84. package/dist/http/caller-trust.d.ts +3 -2
  85. package/dist/http/caller-trust.js +2 -1
  86. package/dist/http/dispatch.js +4 -0
  87. package/dist/http/live-frame.d.ts +24 -0
  88. package/dist/http/live-frame.js +16 -0
  89. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  90. package/dist/http/memory-compliance-failure-reply.js +5 -0
  91. package/dist/http/memory-layer-reply.d.ts +30 -0
  92. package/dist/http/memory-layer-reply.js +24 -0
  93. package/dist/http/resume-legs.js +49 -35
  94. package/dist/http/retired-service-deps.d.ts +1 -1
  95. package/dist/http/retired-service-deps.js +1 -1
  96. package/dist/http/route-table.js +2 -0
  97. package/dist/http/routes/adoption.js +1 -1
  98. package/dist/http/routes/approvals-assistant.js +1 -0
  99. package/dist/http/routes/capabilities.js +5 -4
  100. package/dist/http/routes/diagnostics.d.ts +0 -19
  101. package/dist/http/routes/diagnostics.js +16 -2
  102. package/dist/http/routes/memory-bundle.d.ts +2 -2
  103. package/dist/http/routes/memory-bundle.js +4 -1
  104. package/dist/http/routes/memory-compliance.js +9 -2
  105. package/dist/http/routes/memory-consolidation.js +12 -1
  106. package/dist/http/routes/memory-origin.js +14 -2
  107. package/dist/http/routes/memory-policy.js +7 -2
  108. package/dist/http/routes/run-permission-mode.d.ts +75 -0
  109. package/dist/http/routes/run-permission-mode.js +170 -0
  110. package/dist/http/routes/session-sync.d.ts +3 -6
  111. package/dist/http/routes/session-sync.js +7 -2
  112. package/dist/http/routes/sessions.js +33 -15
  113. package/dist/http/routes/tasks.js +67 -68
  114. package/dist/http/run-read-face.js +3 -3
  115. package/dist/http/send.d.ts +1 -1
  116. package/dist/http/send.js +2 -2
  117. package/dist/http/server.d.ts +14 -27
  118. package/dist/http/server.js +2 -2
  119. package/dist/http/sse-log.d.ts +3 -8
  120. package/dist/http/stored-body-replay.d.ts +3 -3
  121. package/dist/http/stored-body-replay.js +3 -1
  122. package/dist/identity-source.d.ts +1 -1
  123. package/dist/identity-source.js +1 -1
  124. package/dist/instruction-source-notice.d.ts +7 -0
  125. package/dist/instruction-source-notice.js +6 -6
  126. package/dist/lane-home-probe.d.ts +68 -42
  127. package/dist/lane-home-probe.js +53 -30
  128. package/dist/leader/wire.js +5 -4
  129. package/dist/mcp-assertion-header.d.ts +4 -0
  130. package/dist/mcp-assertion-header.js +5 -0
  131. package/dist/memory-bundle-engine.d.ts +16 -9
  132. package/dist/memory-bundle-engine.js +29 -6
  133. package/dist/memory-operator-faces.d.ts +85 -30
  134. package/dist/memory-operator-faces.js +136 -30
  135. package/dist/memory-posture.d.ts +1 -1
  136. package/dist/memory-project-layer.d.ts +3 -21
  137. package/dist/memory-project-layer.js +11 -8
  138. package/dist/memory-scope-stores.d.ts +73 -0
  139. package/dist/memory-scope-stores.js +86 -0
  140. package/dist/memory-scope.d.ts +33 -9
  141. package/dist/memory-scope.js +17 -5
  142. package/dist/memory-sync-client.d.ts +34 -9
  143. package/dist/memory-sync-client.js +108 -28
  144. package/dist/observability/fail-open.d.ts +30 -2
  145. package/dist/observability/fail-open.js +30 -2
  146. package/dist/observability/metrics.js +0 -1
  147. package/dist/observability/run-terminal.d.ts +6 -2
  148. package/dist/observability/run-terminal.js +25 -26
  149. package/dist/observability/secret-env-scrub.d.ts +20 -1
  150. package/dist/observability/secret-env-scrub.js +14 -0
  151. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
  152. package/dist/orchestration/workflow-completion-inbox.js +13 -5
  153. package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
  154. package/dist/orchestration/workflow-notify-journal.js +2 -1
  155. package/dist/permission-mode-admission.d.ts +68 -0
  156. package/dist/permission-mode-admission.js +23 -0
  157. package/dist/permission-rule-list.d.ts +55 -6
  158. package/dist/permission-rule-list.js +52 -5
  159. package/dist/plugins/adoption-log-sql.js +4 -4
  160. package/dist/plugins/approval-ask-store-sql.js +14 -14
  161. package/dist/plugins/approval-nonce-store.js +4 -4
  162. package/dist/plugins/blob-backend.d.ts +4 -4
  163. package/dist/plugins/blob-backend.js +7 -7
  164. package/dist/plugins/breaker-state-sql.js +2 -2
  165. package/dist/plugins/caching-session-store.d.ts +6 -0
  166. package/dist/plugins/caching-session-store.js +3 -0
  167. package/dist/plugins/checkpoint-index-columns.js +2 -2
  168. package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
  169. package/dist/plugins/checkpoint-store-sql.js +90 -19
  170. package/dist/plugins/device-store-sql.d.ts +5 -2
  171. package/dist/plugins/device-store-sql.js +23 -20
  172. package/dist/plugins/ensure-index.d.ts +1 -2
  173. package/dist/plugins/execution-placement-sql.d.ts +19 -9
  174. package/dist/plugins/execution-placement-sql.js +20 -9
  175. package/dist/plugins/file-history-store-sql.d.ts +2 -2
  176. package/dist/plugins/file-history-store-sql.js +4 -4
  177. package/dist/plugins/file-run-store.d.ts +2 -2
  178. package/dist/plugins/file-run-store.js +1 -1
  179. package/dist/plugins/fork-routing-session-store.d.ts +10 -32
  180. package/dist/plugins/fork-routing-session-store.js +2 -61
  181. package/dist/plugins/image-bake-store-sql.js +9 -9
  182. package/dist/plugins/image-index-sql.js +11 -11
  183. package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
  184. package/dist/plugins/k8s-exec-protocol.js +6 -1
  185. package/dist/plugins/leader-run-store-sql.js +4 -4
  186. package/dist/plugins/local-checkpoint-store.d.ts +10 -1
  187. package/dist/plugins/local-checkpoint-store.js +22 -0
  188. package/dist/plugins/local-session-store.d.ts +227 -35
  189. package/dist/plugins/local-session-store.js +518 -37
  190. package/dist/plugins/local-session-window.d.ts +17 -3
  191. package/dist/plugins/local-session-window.js +7 -13
  192. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  193. package/dist/plugins/mailbox-store-sql.js +4 -4
  194. package/dist/plugins/memory-engine-tidb.js +5 -5
  195. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  196. package/dist/plugins/memory-run-store.d.ts +2 -2
  197. package/dist/plugins/memory-run-store.js +1 -1
  198. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  199. package/dist/plugins/one-time-migrations.d.ts +52 -11
  200. package/dist/plugins/one-time-migrations.js +101 -39
  201. package/dist/plugins/org-delivery-quota-store.js +2 -2
  202. package/dist/plugins/outcome-ledger-sql.js +2 -2
  203. package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
  204. package/dist/plugins/permission-rule-store-sql.js +16 -16
  205. package/dist/plugins/pg-pool.js +3 -2
  206. package/dist/plugins/pg-session-storage.d.ts +2 -0
  207. package/dist/plugins/pg-session-storage.js +3 -2
  208. package/dist/plugins/remote-env-adb.d.ts +7 -24
  209. package/dist/plugins/remote-env-adb.js +22 -5
  210. package/dist/plugins/remote-env-device.d.ts +2 -28
  211. package/dist/plugins/remote-env-device.js +2 -1
  212. package/dist/plugins/remote-env-e2b.d.ts +40 -27
  213. package/dist/plugins/remote-env-e2b.js +180 -20
  214. package/dist/plugins/remote-env-file-error.d.ts +1 -1
  215. package/dist/plugins/remote-env-file-error.js +8 -2
  216. package/dist/plugins/remote-env-host.d.ts +19 -35
  217. package/dist/plugins/remote-env-host.js +26 -3
  218. package/dist/plugins/remote-env-k8s.d.ts +22 -14
  219. package/dist/plugins/remote-env-k8s.js +150 -26
  220. package/dist/plugins/remote-env-local-docker.d.ts +27 -24
  221. package/dist/plugins/remote-env-local-docker.js +91 -24
  222. package/dist/plugins/remote-env-ssh.d.ts +4 -24
  223. package/dist/plugins/remote-env-ssh.js +4 -3
  224. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  225. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  226. package/dist/plugins/retention-lane-store-sql.js +2 -2
  227. package/dist/plugins/retention-store-sql.d.ts +1 -1
  228. package/dist/plugins/retention-store-sql.js +6 -6
  229. package/dist/plugins/run-store-sql.d.ts +3 -3
  230. package/dist/plugins/run-store-sql.js +19 -18
  231. package/dist/plugins/sandbox-read-floor.d.ts +273 -0
  232. package/dist/plugins/sandbox-read-floor.js +608 -0
  233. package/dist/plugins/schema-consistency.d.ts +6 -6
  234. package/dist/plugins/schema-consistency.js +1 -1
  235. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  236. package/dist/plugins/schema-ensure-legs.js +2 -2
  237. package/dist/plugins/schema-live-columns.d.ts +1 -1
  238. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  239. package/dist/plugins/session-ownership.d.ts +2 -1
  240. package/dist/plugins/session-placement.d.ts +17 -4
  241. package/dist/plugins/session-placement.js +2 -1
  242. package/dist/plugins/session-rules-column.d.ts +1 -1
  243. package/dist/plugins/session-rules-column.js +1 -1
  244. package/dist/plugins/session-store.d.ts +18 -20
  245. package/dist/plugins/session-store.js +4 -12
  246. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  247. package/dist/plugins/session-workspace-cell.js +1 -1
  248. package/dist/plugins/shared-memory-store-sql.js +2 -2
  249. package/dist/plugins/sql-driver.d.ts +10 -5
  250. package/dist/plugins/sql-driver.js +6 -6
  251. package/dist/plugins/sql-errors.js +1 -1
  252. package/dist/plugins/store-backend.d.ts +35 -6
  253. package/dist/plugins/store-backend.js +27 -10
  254. package/dist/plugins/store-contracts.d.ts +9 -2
  255. package/dist/plugins/task-list-store-sql.js +11 -11
  256. package/dist/plugins/tidb-pool.js +7 -6
  257. package/dist/plugins/tidb-session-storage.js +4 -4
  258. package/dist/plugins/tidb-session-store.d.ts +4 -1
  259. package/dist/plugins/tidb-session-store.js +16 -15
  260. package/dist/plugins/tool-result-store-sql.d.ts +2 -2
  261. package/dist/plugins/tool-result-store-sql.js +3 -3
  262. package/dist/plugins/user-input-ledger-sql.js +2 -2
  263. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  264. package/dist/plugins/workflow-run-store-sql.js +19 -19
  265. package/dist/plugins/write-behind-counter.d.ts +2 -3
  266. package/dist/plugins/write-behind-counter.js +5 -5
  267. package/dist/resource-suspend.d.ts +14 -12
  268. package/dist/resource-suspend.js +1 -1
  269. package/dist/resource-window.d.ts +4 -3
  270. package/dist/run-cancel-context.d.ts +34 -0
  271. package/dist/run-cancel-context.js +7 -0
  272. package/dist/run-local.js +14 -19
  273. package/dist/runs.d.ts +47 -16
  274. package/dist/runs.js +112 -113
  275. package/dist/security.d.ts +2 -2
  276. package/dist/server-secret-env.d.ts +2 -1
  277. package/dist/server-secret-env.js +2 -4
  278. package/dist/session-error-wire.d.ts +22 -4
  279. package/dist/session-error-wire.js +16 -0
  280. package/dist/session-incarnation.d.ts +10 -4
  281. package/dist/session-incarnation.js +1 -1
  282. package/dist/session-policy-wire.d.ts +1 -1
  283. package/dist/session-sync-kernel.d.ts +42 -1
  284. package/dist/session-sync-kernel.js +17 -0
  285. package/dist/session-sync.js +16 -4
  286. package/dist/sql-engine-coordinates.d.ts +49 -0
  287. package/dist/sql-engine-coordinates.js +27 -0
  288. package/dist/sql-engine-posture.d.ts +1 -1
  289. package/dist/sql-engine-posture.js +1 -1
  290. package/dist/standing-answer-grant.d.ts +31 -2
  291. package/dist/standing-answer-grant.js +14 -2
  292. package/dist/store-posture.d.ts +1 -1
  293. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  294. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  295. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  296. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  297. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  298. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  299. package/dist/task-a2a.d.ts +1 -1
  300. package/dist/task-a2a.js +5 -6
  301. package/dist/task-mcp.d.ts +21 -8
  302. package/dist/task-mcp.js +17 -9
  303. package/dist/task-settings.d.ts +52 -25
  304. package/dist/task-settings.js +91 -28
  305. package/dist/terminal.d.ts +103 -19
  306. package/dist/terminal.js +72 -20
  307. package/dist/trace/core-keyset-guard.d.ts +79 -2
  308. package/dist/trace/exit-seat.d.ts +7 -0
  309. package/dist/trace/exit-seat.js +1 -0
  310. package/dist/trace/model-segment.d.ts +2 -2
  311. package/dist/trace/redact.d.ts +3 -1
  312. package/dist/trace/redact.js +395 -110
  313. package/dist/trace/self-minted-wire.d.ts +226 -2
  314. package/dist/trace/self-minted-wire.js +79 -0
  315. package/dist/verifier-pause-card.d.ts +8 -0
  316. package/dist/verifier-pause-card.js +19 -0
  317. package/dist/web-admin-client/apply-effective.d.ts +5 -7
  318. package/dist/web-admin-client/apply-effective.js +2 -2
  319. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  320. package/dist/web-admin-client/candidate-gate.js +1 -1
  321. package/dist/web-admin-client/http-client.d.ts +5 -4
  322. package/dist/web-admin-client/http-client.js +2 -2
  323. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  324. package/dist/web-admin-client/read-warnings.js +5 -9
  325. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
  326. package/package.json +2 -2
  327. package/wire-changes/server@7.140.0.json +184 -0
  328. package/wire-changes/server@7.141.0.json +367 -0
@@ -1,7 +1,7 @@
1
1
  import { join } from "node:path";
2
2
  import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, InMemoryUsageWindowStore, mailboxCrossProcessMountVerdict } from "@sema-agent/core";
3
3
  import { createCorruptReadFailOpenSeat } from "../observability/corrupt-read-seat.js";
4
- import { buildMemorySyncEnabledFields, createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
4
+ import { startMemorySyncRunner } from "../memory-sync-client.js";
5
5
  import { memoryEmbedderFor } from "../plugins/memory-embedder.js";
6
6
  import { ensurePgMemoryEmbedderMetaSchema, reconcileEmbedderFingerprint } from "../plugins/memory-embedder-fingerprint.js";
7
7
  import { PgMemoryEngineBackend, ensurePgMemoryEngineSchema } from "../plugins/memory-engine-pg.js";
@@ -10,14 +10,16 @@ import { PgMemoryHistoryStore, PgMemorySyncStore, ensurePgMemoryHistorySchema, e
10
10
  import { TiDBMemoryHistoryStore, TiDBMemorySyncStore, ensureTiDBMemoryHistorySchema, ensureTiDBMemorySyncSchema } from "../plugins/memory-sync-store-tidb.js";
11
11
  import { MinioBlobBackend } from "../plugins/blob-backend.js";
12
12
  import { ensureSnapshotBuckets } from "../plugins/snapshot-bucket-presence.js";
13
- import { PgBackgroundAgentStore, TiDBBackgroundAgentStore, ensurePgBackgroundAgentSchema, ensureTiDBBackgroundAgentSchema } from "../plugins/background-agent-store-sql.js";
13
+ import { PgBackgroundAgentStore, TiDBBackgroundAgentStore, ensurePgBackgroundAgentSchema, ensureTiDBBackgroundAgentSchema } from "../stores-sql/background-agent-store-sql.js";
14
14
  import { PgMailboxStore, TiDBMailboxStore, ensurePgMailboxSchema, ensureTiDBMailboxSchema } from "../plugins/mailbox-store-sql.js";
15
15
  import { createDropOnlyRecipientLifecycle } from "../plugins/mailbox-recipient-lifecycle.js";
16
- import { PgUsageWindowStore, TiDBUsageWindowStore, ensurePgUsageWindowSchema, ensureTiDBUsageWindowSchema } from "../plugins/usage-window-store-sql.js";
16
+ import { PgUsageWindowStore, TiDBUsageWindowStore, ensurePgUsageWindowSchema, ensureTiDBUsageWindowSchema } from "../stores-sql/usage-window-store-sql.js";
17
17
  import { PgRosterStore, TiDBRosterStore, ensurePgRosterSchema, ensureTiDBRosterSchema } from "../plugins/roster-store-sql.js";
18
18
  import { LocalTaskAttachmentStore } from "../plugins/local-task-attachment-store.js";
19
19
  import { PgTaskAttachmentStore, TiDBTaskAttachmentStore, ensurePgTaskAttachmentSchema, ensureTiDBTaskAttachmentSchema } from "../plugins/task-attachment-store.js";
20
20
  import { createSessionStore } from "../plugins/session-store.js";
21
+ import { buildSqlPoolMissingRefusal, missingSqlCoordinateKeys } from "../sql-engine-coordinates.js";
22
+ import { runApprovalBatchKindlessCensus } from "../approval-batch-census.js";
21
23
  import { runAndLogOneTimeMigrations } from "../plugins/one-time-migrations.js";
22
24
  import { createTaskListLane } from "./task-list-lane.js";
23
25
  import { ensurePgTaskListSchema, ensureTiDBTaskListSchema } from "../plugins/task-list-store-sql.js";
@@ -27,21 +29,22 @@ import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "..
27
29
  import { createMemoryEngineIncidentSink } from "../memory-incident-sink.js";
28
30
  import { announceLockedLegacyMemoryLayers } from "../memory-layer-legacy-lock.js";
29
31
  import { createEngineNoticeForwarder } from "./runner-deps.js";
30
- import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture, memoryEngineRootFor, memoryMountRootOf } from "../memory-scope.js";
32
+ import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture, memoryEngineRootFor, memoryLayersNamedBy, memoryMountRootOf } from "../memory-scope.js";
33
+ import { createMemoryScopeStores } from "../memory-scope-stores.js";
31
34
  import { assertToolResultProvenanceSchema } from "../plugins/tool-result-store-sql.js";
32
35
  import { assertPermissionRuleApprovalSchema, assertPermissionRuleTicketSchema } from "../plugins/permission-rule-store-sql.js";
33
36
  import { assertApprovalAskRuleMaterialSchema } from "../plugins/approval-ask-store-sql.js";
34
37
  import { assertSchemaMatchesCode } from "../plugins/schema-consistency.js";
35
- import { assertCheckpointColumnSchema } from "../plugins/checkpoint-store-sql.js";
38
+ import { SqlCheckpointStore, assertCheckpointColumnSchema } from "../plugins/checkpoint-store-sql.js";
36
39
  import { assertFileHistorySchema } from "../plugins/file-history-store-sql.js";
37
- import { buildMemoryBoundaryLaneFacts, buildMemoryWriteBoundaryAudit, effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
40
+ import { buildMemoryBoundaryLaneFacts, buildMemoryWriteBoundaryAudit } from "./memory-boundary.js";
38
41
  import { buildMemoryPosture } from "../memory-posture.js";
39
42
  import { headReadOf } from "../session-incarnation.js";
40
43
  import { establishSqlEnginePosture, sqlPoolsOf } from "../sql-engine-posture.js";
41
44
  import { buildStorePosture } from "../store-posture.js";
42
45
  const DARK_REASON_PROSE = {
43
46
  engine_off: () => "MEMORY_ENGINE=off",
44
- multi_tenant_file_backend: () => "multi-tenant on the FILE backend (no tenant isolation; set MEMORY_ENGINE_BACKEND=pg|tidb to light up)",
47
+ multi_tenant_file_backend: () => "multi-tenant on the FILE backend (no tenant isolation; set MEMORY_ENGINE_BACKEND=pg|mysql to light up)",
45
48
  remote_lane_split: (lane) => `remote exec lane "${lane}" (worker/sandbox file planes split; MEMORY_ENGINE_REMOTE_LANE=allow overrides)`,
46
49
  };
47
50
  export async function assertApprovalAskRuleMaterialOnBackend(backend) {
@@ -50,7 +53,7 @@ export async function assertApprovalAskRuleMaterialOnBackend(backend) {
50
53
  if (pgPool)
51
54
  await assertApprovalAskRuleMaterialSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
52
55
  else if (mysqlPool)
53
- await assertApprovalAskRuleMaterialSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
56
+ await assertApprovalAskRuleMaterialSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
54
57
  }
55
58
  export async function openStores(ctx) {
56
59
  const { config, logger, metrics, localRoot } = ctx;
@@ -74,28 +77,32 @@ export async function openStores(ctx) {
74
77
  if (pgPool)
75
78
  await assertToolResultProvenanceSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
76
79
  else if (mysqlPool)
77
- await assertToolResultProvenanceSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
80
+ await assertToolResultProvenanceSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
78
81
  if (pgPool)
79
82
  await assertCheckpointColumnSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
80
83
  else if (mysqlPool)
81
- await assertCheckpointColumnSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
84
+ await assertCheckpointColumnSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
82
85
  if (config.permissionRulesEnabled) {
83
86
  if (pgPool)
84
87
  await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
85
88
  else if (mysqlPool)
86
- await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
89
+ await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
87
90
  if (pgPool)
88
91
  await assertPermissionRuleTicketSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
89
92
  else if (mysqlPool)
90
- await assertPermissionRuleTicketSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
93
+ await assertPermissionRuleTicketSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
91
94
  }
92
95
  if (pgPool)
93
96
  await assertFileHistorySchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
94
97
  else if (mysqlPool)
95
- await assertFileHistorySchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
98
+ await assertFileHistorySchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "mysql");
96
99
  }
97
100
  if (backend)
98
101
  await runAndLogOneTimeMigrations(logger, backend);
102
+ {
103
+ const censusStore = backend !== undefined && backend.kind !== "local" ? backend.checkpoint?.() : undefined;
104
+ void runApprovalBatchKindlessCensus(censusStore instanceof SqlCheckpointStore ? censusStore : undefined, logger);
105
+ }
99
106
  if ((process.env.REWIND_SNAPSHOT_MAX_MB ?? "") !== "") {
100
107
  logger.warn("rewind_snapshot_max_mb_retired", {
101
108
  note: "REWIND_SNAPSHOT_MAX_MB no longer has an effect: the whole-tree snapshot epoch is retired (S-15); per-edited-file history captures only files the agent touches, with no tree walk and no size gate. Remove the env var. Per-blob SQL sizing is governed by SNAPSHOT_BLOB_SQL_MAX_BYTES / object storage as before.",
@@ -115,6 +122,8 @@ export async function openStores(ctx) {
115
122
  config.sessionBackend = "tidb";
116
123
  let memoryEngine;
117
124
  const engineDataRoot = memoryEngineRootFor(config, localRoot);
125
+ const memoryEngineIncident = createMemoryEngineIncidentSink({ logger, metrics });
126
+ const scopeStoresOver = (deployment) => createMemoryScopeStores({ backend: deployment, root: engineDataRoot, namedLayers: () => memoryLayersNamedBy(config), onIncident: memoryEngineIncident });
118
127
  let memorySyncCursors;
119
128
  let vectorMode;
120
129
  if (config.memoryEngineBackend !== "file" && config.memoryEngineEnabled) {
@@ -133,7 +142,7 @@ export async function openStores(ctx) {
133
142
  if (dialect === "pg") {
134
143
  const pool = backend?.pgPool();
135
144
  if (!pool)
136
- throw new Error("MEMORY_ENGINE_BACKEND=pg requires DB_BACKEND=pg (the memory engine binds the same PG pool) — refusing to start half-configured");
145
+ throw new Error(buildSqlPoolMissingRefusal({ engine: dialect, declared: config.dbBackend === dialect, missing: missingSqlCoordinateKeys(dialect, process.env) }));
137
146
  const q = async (text, params) => { const r = await pool.query(text, params); return { rows: r.rows }; };
138
147
  await ensurePgMemoryEngineSchema(q);
139
148
  await ensurePgMemoryHistorySchema(q);
@@ -165,19 +174,19 @@ export async function openStores(ctx) {
165
174
  ...(embedder !== undefined ? { embedder } : {}),
166
175
  });
167
176
  vectorMode = pgMem.vectorMode;
168
- memoryEngine = { backend: pgMem, root: engineDataRoot };
177
+ memoryEngine = scopeStoresOver(pgMem);
169
178
  }
170
179
  else {
171
180
  const pool = backend?.mysqlPool();
172
181
  if (!pool)
173
- throw new Error("MEMORY_ENGINE_BACKEND=tidb requires DB_BACKEND=mysql — refusing to start half-configured");
182
+ throw new Error(buildSqlPoolMissingRefusal({ engine: dialect, declared: config.dbBackend === dialect, missing: missingSqlCoordinateKeys(dialect, process.env) }));
174
183
  await ensureTiDBMemoryEngineSchema(pool);
175
184
  await ensureTiDBMemoryHistorySchema(pool);
176
185
  await ensureTiDBMemorySyncSchema(pool);
177
186
  memorySyncCursors = new TiDBMemorySyncStore(pool);
178
187
  const tidbMem = new TiDBMemoryEngineBackend(pool, { history: countedHistorySink(new TiDBMemoryHistoryStore(pool)) });
179
188
  vectorMode = tidbMem.vectorMode;
180
- memoryEngine = { backend: tidbMem, root: engineDataRoot };
189
+ memoryEngine = scopeStoresOver(tidbMem);
181
190
  }
182
191
  logger.info("memory_engine_enabled", {
183
192
  enabled: true,
@@ -189,7 +198,8 @@ export async function openStores(ctx) {
189
198
  });
190
199
  }
191
200
  else {
192
- memoryEngine = memoryEngineBackendFor(config, undefined, createMemoryEngineIncidentSink({ logger, metrics }));
201
+ const fileEngine = memoryEngineBackendFor(config, undefined, memoryEngineIncident);
202
+ memoryEngine = fileEngine !== undefined ? scopeStoresOver(fileEngine.backend) : undefined;
193
203
  if (memoryEngine)
194
204
  announceLockedLegacyMemoryLayers(memoryMountRootOf(memoryEngine.backend, memoryEngine.root), createEngineNoticeForwarder(logger));
195
205
  if (memoryEngine && process.env.LOCAL_DATA_ROOT && !config.memoryEngineDir) {
@@ -205,17 +215,11 @@ export async function openStores(ctx) {
205
215
  const audit = buildMemoryWriteBoundaryAudit({
206
216
  memoryRoot: memoryMountRoot,
207
217
  ...laneFacts,
208
- declaredCapable: effectiveMemoryPersistenceCapable(config),
218
+ declaredCapable: config.memoryPersistenceCapable,
209
219
  engineBackend: config.memoryEngineBackend,
210
220
  });
211
221
  for (const w of audit.warnings)
212
222
  logger.warn(w.tag, { detail: w.detail, lane: laneFacts.lane, root: memoryMountRoot ?? null });
213
- if (config.memoryPersistenceCapable === undefined && effectiveMemoryPersistenceCapable(config) === true) {
214
- logger.info?.("memory_persistence_capable_auto_declared", {
215
- lane: laneFacts.lane,
216
- detail: "REMOTE_EXEC=host: file tools run on this machine's filesystem, so the assembler declares memoryPersistenceCapable=true (the core-side remote-env withhold would otherwise silently drop the memory WRITE instruction on this lane). Override with MEMORY_PERSISTENCE_CAPABLE=true|false.",
217
- });
218
- }
219
223
  }
220
224
  let rosterStore;
221
225
  {
@@ -236,7 +240,7 @@ export async function openStores(ctx) {
236
240
  });
237
241
  }
238
242
  if (rosterStore)
239
- logger.info("roster_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
243
+ logger.info("roster_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "mysql" : "file" });
240
244
  }
241
245
  let backgroundAgentStore;
242
246
  {
@@ -255,7 +259,7 @@ export async function openStores(ctx) {
255
259
  backgroundAgentStore = new FileBackgroundAgentStore(config.localDataRoot ?? localRoot);
256
260
  }
257
261
  if (backgroundAgentStore)
258
- logger.info("background_agent_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
262
+ logger.info("background_agent_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "mysql" : "file" });
259
263
  }
260
264
  let taskAttachmentStore;
261
265
  {
@@ -285,7 +289,7 @@ export async function openStores(ctx) {
285
289
  taskAttachmentStore = new LocalTaskAttachmentStore(config.localDataRoot ?? localRoot);
286
290
  }
287
291
  if (taskAttachmentStore)
288
- logger.info("task_attachment_store_enabled", { backend: pgPool ? "pg+minio" : mysqlPool ? "tidb+minio" : "file", maxBytes: config.attachmentMaxBytes });
292
+ logger.info("task_attachment_store_enabled", { backend: pgPool ? "pg+minio" : mysqlPool ? "mysql+minio" : "file", maxBytes: config.attachmentMaxBytes });
289
293
  }
290
294
  let mailboxStore;
291
295
  let mailboxRecipientLifecycle;
@@ -313,7 +317,7 @@ export async function openStores(ctx) {
313
317
  if (mailboxStore) {
314
318
  const laneVerdict = mailboxCrossProcessMountVerdict(mailboxStore);
315
319
  logger.info("mailbox_store_enabled", {
316
- backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file",
320
+ backend: pgPool ? "pg" : mysqlPool ? "mysql" : "file",
317
321
  crossProcessSafe: mailboxStore.crossProcessSafe,
318
322
  recipientTombstones: pgPool !== undefined || mysqlPool !== undefined,
319
323
  peerLaneMountable: laneVerdict.ok,
@@ -339,9 +343,9 @@ export async function openStores(ctx) {
339
343
  else {
340
344
  usageWindowStore = new InMemoryUsageWindowStore();
341
345
  }
342
- logger.info("usage_window_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : backend?.fileUsageWindowStore !== undefined ? "file" : "memory", windows: config.usageWindows.length });
346
+ logger.info("usage_window_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "mysql" : backend?.fileUsageWindowStore !== undefined ? "file" : "memory", windows: config.usageWindows.length });
343
347
  }
344
- const memoryExportBackend = config.memoryEngineBackend !== "file" ? memoryEngine?.backend : undefined;
348
+ const memoryExportStores = config.memoryEngineBackend !== "file" ? memoryEngine : undefined;
345
349
  const memoryLane = memoryEngineRemoteLanePosture(config);
346
350
  const memoryPosture = buildMemoryPosture({
347
351
  config,
@@ -363,18 +367,7 @@ export async function openStores(ctx) {
363
367
  let memorySyncRunner;
364
368
  if (config.memorySync) {
365
369
  if (memoryEngine) {
366
- const transport = createMemorySyncTransport({ url: config.memorySync.url, token: config.memorySync.token });
367
- memorySyncRunner = createMemorySyncRunner({
368
- backend: memoryEngine.backend,
369
- scope: config.memorySync.scope,
370
- memoryRoot: memoryEngine.root,
371
- transport,
372
- log: logger,
373
- ...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
374
- ...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
375
- });
376
- logger.info("memory_sync_enabled", buildMemorySyncEnabledFields(transport.peer, config.memorySync.scope, memorySyncRunner.cursorPathFor(config.memorySync.scope)));
377
- memorySyncRunner.trigger("boot");
370
+ memorySyncRunner = startMemorySyncRunner({ sync: config.memorySync, stores: memoryEngine, log: logger });
378
371
  }
379
372
  else {
380
373
  logger.warn("memory_sync_configured_but_memory_dark", { note: "MEMORY_SYNC_URL is set but the file memory engine is dark (multi-tenant / MEMORY_ENGINE=off / remote exec lane) — no sync rounds will run" });
@@ -444,7 +437,7 @@ export async function openStores(ctx) {
444
437
  : undefined;
445
438
  return {
446
439
  backend, storePosture, memoryEngine, engineDataRoot, memorySyncCursors, rosterStore, backgroundAgentStore, mailboxRecipientLifecycle,
447
- taskAttachmentStore, mailboxStore, memoryExportBackend, memorySyncRunner, sessionStore, breakerState,
440
+ taskAttachmentStore, mailboxStore, memoryExportStores, memorySyncRunner, sessionStore, breakerState,
448
441
  usageWindowStore, memoryPosture, taskListLane, sqlEngine,
449
442
  };
450
443
  }
@@ -38,7 +38,7 @@ import type { Logger } from "../observability/logger.js";
38
38
  /** 同时活着的会话清单实例上限(LRU,逐最老)。与 perSessionCwd/perSessionShellEnv 同量级。 */
39
39
  export declare const MAX_TASK_LIST_SESSIONS = 4096;
40
40
  /** 车道实际落到哪个后端(启动日志 + 测试对表)。 */
41
- export type TaskListLaneBackend = "tidb" | "pg" | "memory";
41
+ export type TaskListLaneBackend = "mysql" | "pg" | "memory";
42
42
  export interface TaskListLane {
43
43
  /** `sessionId ↦ 该会话的任务清单店`。同 sessionId 恒解析到同一份清单(SQL 形 = 同一批行;
44
44
  * memory 形 = 同一只实例)。 */
@@ -16,7 +16,7 @@ export function createTaskListLane(opts = {}) {
16
16
  purge = (sessionId) => deletePgTaskList(pgPool, taskListKeyFor(sessionId));
17
17
  }
18
18
  else if (mysqlPool) {
19
- backend = "tidb";
19
+ backend = "mysql";
20
20
  mint = (sessionId) => createTiDBTaskListStore(mysqlPool, taskListKeyFor(sessionId));
21
21
  purge = (sessionId) => deleteTiDBTaskList(mysqlPool, taskListKeyFor(sessionId));
22
22
  }
@@ -31,6 +31,15 @@ import { SHA256_HEX_RE } from "../digest-form.js";
31
31
  import { BOOT_REJUDGE_OF_REFUSED_GROUP, createConfigApplyLedger, modelPlaneCommitted, refusedGroups } from "../web-admin-client/apply-ledger.js";
32
32
  import { announceReadDenyRows, buildDeploymentPostureSeats } from "./runner-deps.js";
33
33
  import { echoCallerText } from "../caller-text-echo.js";
34
+ const MODELS_REJECTION_PHRASE = {
35
+ domain_invalid: "models 域判形失败",
36
+ empty: "读不出(空 / 纯空白:半写或截断)",
37
+ invalid_json: "读不出(不是合法的 JSON)",
38
+ not_object: "读不出(解析出来不是 JSON 对象:null / 数组 / 标量)",
39
+ io: "读不出(文件读失败:权限、路径是目录或 I/O 错误)",
40
+ too_deep: "读不出(嵌套过深:深过整棵目录的内容版本能算的层数)",
41
+ retired_domain: "是带事实的退役域文档",
42
+ };
34
43
  function lkgReadNote(scope) {
35
44
  switch (scope) {
36
45
  case "whole":
@@ -202,6 +211,22 @@ export async function createWebAdminRuntime(ctx) {
202
211
  noteCandidateVerdict(ordinal, candidateRejectionOf(r, verdict, candidateSource().kind, Date.now()));
203
212
  logger.warn("config_candidate_rejected", buildCandidateRejectedFields(r, verdict, leg, { lkgVersion: latestEffective?.version ?? "(env)", ...localDirField }));
204
213
  };
214
+ const noteSourceAtApplied = () => {
215
+ const rejected = candidateRejection;
216
+ const appliedVersion = applyLedger.view().configAppliedVersion;
217
+ if (rejected === undefined || rejected.version === appliedVersion)
218
+ return;
219
+ const gen = generationOf(appliedVersion);
220
+ noteCandidateVerdict(gen, undefined);
221
+ if (!cc?.dryRun)
222
+ applyLedger.applied(gen, appliedVersion);
223
+ logger.info("config_source_back_to_applied", {
224
+ appliedVersion,
225
+ rejectedVersion: rejected.version,
226
+ domains: rejected.domains.join(","),
227
+ note: "the config source serves the applied generation again (unchanged-since-applied reply) — the rejected candidate is no longer its current one: candidateRejected cleared, target back to applied; the same breakage again is announced again",
228
+ });
229
+ };
205
230
  const selfReportListeners = [];
206
231
  const notifySelfReport = (changed) => {
207
232
  for (const listener of selfReportListeners) {
@@ -540,18 +565,18 @@ export async function createWebAdminRuntime(ctx) {
540
565
  logger.warn("config_lkg_apply_failed", { err: String(applyErr), note: "persisted LKG failed to apply — env fallback serves; the cache rewrites on the next clean candidate" });
541
566
  }
542
567
  };
543
- const warnLocalNoModels = (r, rejected) => {
544
- const modelsDomainErr = (r.domainErrors ?? []).find((de) => de.domain === "models");
568
+ const warnLocalNoModels = (r, verdict) => {
569
+ const modelsRejection = verdict.verdict === "rejected" ? verdict.errors.find((e) => e.domain === "models") : undefined;
545
570
  const modelsDropped = (r.droppedEntries ?? []).filter((d) => d.domain === "models");
546
571
  const totalModels = (r.effective.models?.models ?? []).length;
547
572
  logger.warn("config_local_no_models", {
548
573
  ...localDirField,
549
- ...(modelsDomainErr ? { domainError: modelsDomainErr.error } : {}),
574
+ ...(modelsRejection ? { reason: modelsRejection.reason, domainError: modelsRejection.error } : {}),
550
575
  ...(modelsDropped.length > 0 ? { droppedEntries: modelsDropped.map((d) => d.entry) } : {}),
551
- hint: rejected && modelsDomainErr
552
- ? "config.d/models.json 在场但 models 域判形失败,整份本地候选被拒(真因见本行 domainError)— 模型继续走 env 兜底"
553
- : rejected
554
- ? "config.d 里别的域让整份本地候选被拒(判形失败,或带事实的退役域文档;坏域与真因见 config_candidate_rejected)— config.d/models.json 的模型不用,继续走 env 兜底"
576
+ hint: modelsRejection
577
+ ? `config.d/models.json 在场但${MODELS_REJECTION_PHRASE[modelsRejection.reason]},整份本地候选被拒(成因词见本行 reason,真因见本行 domainError)— 模型继续走 env 兜底`
578
+ : verdict.verdict === "rejected"
579
+ ? "config.d 里别的域让整份本地候选被拒(坏域、成因词与真因见 config_candidate_rejected)— config.d/models.json 的模型不用,继续走 env 兜底"
555
580
  : modelsDropped.length > 0 && totalModels === 0
556
581
  ? "config.d/models.json 的条目全部被逐条丢弃(逐条真因见 config_entry_dropped)— 模型继续走 env 兜底"
557
582
  : totalModels > 0
@@ -600,7 +625,7 @@ export async function createWebAdminRuntime(ctx) {
600
625
  applyLedger.seenTarget(rejectedGen, r.effective.version);
601
626
  announceCandidateRejected(r, bootVerdict, "boot", rejectedGen);
602
627
  if (configProvider.kind === "local")
603
- warnLocalNoModels(r, true);
628
+ warnLocalNoModels(r, bootVerdict);
604
629
  }
605
630
  else {
606
631
  warnReadNotices(r, "boot");
@@ -645,7 +670,7 @@ export async function createWebAdminRuntime(ctx) {
645
670
  const cfgModels = (r.effective.models?.models ?? []).filter((m) => m.enabled !== false).length;
646
671
  logger.info("config_loaded", { source: configProvider.kind, version: r.effective.version, worker: cc?.worker ?? "(global)", models: cfgModels, ...localDirField });
647
672
  if (configProvider.kind === "local" && cfgModels === 0)
648
- warnLocalNoModels(r, false);
673
+ warnLocalNoModels(r, bootVerdict);
649
674
  }
650
675
  }
651
676
  if (configProvider.kind === "remote")
@@ -959,6 +984,8 @@ export async function createWebAdminRuntime(ctx) {
959
984
  logger.warn("models_tiers_deferred_no_handoff", { version: planeDeferredNoHandoff.version, since: planeDeferredNoHandoff.since, note: "candidate still retained without a next-boot handoff — mount restart-surviving LKG storage + CONFIG_LKG_DURABLE=true, or restart manually after ensuring the candidate is re-pulled at boot" });
960
985
  }
961
986
  const r = arrival !== undefined ? arrival.result : await pullEffective(configProvider, ccEtag);
987
+ if (r === null)
988
+ noteSourceAtApplied();
962
989
  if (r === null && planeDeferredNoHandoff) {
963
990
  const skillsDebt = (planeDeferredNoHandoff.blocked ?? []).includes("skills");
964
991
  const promoted = lkgSurvivesRestart || skillsDebt ? await persistLkgDurable(planeDeferredNoHandoff.candidate, planeDeferredNoHandoff.candidateEtag) : false;
@@ -5,8 +5,8 @@ export interface ExecutionLaneCapability {
5
5
  /** 工具跑的那台机器就是本进程这台吗(= server 盘上的绝对路径对模型的工具有没有意义)。
6
6
  * 属主 = 部署形表行 `toolsOnThisHost`,与 `skills[].baseDir` 的铸点同一行。 */
7
7
  readonly toolsOnThisHost: boolean;
8
- /** [ref]:手在不在 OS 级隔离边界里(容器 / microVM / Kata pod)。**present-iff 本车道有手**(能力表 `coreRemoteExecutionEnv`);
9
- * 值 = {@link laneIsolated}(能力表 `isolation` 位,与 boot `remote_exec_enabled.isolated` 同一只)。见头注 [ref] 段。 */
8
+ /** 手在不在 OS 级隔离边界里(容器 / microVM / Kata pod)。**present-iff 本车道有手**(执行环境块 `io`);
9
+ * 值 = {@link laneIsolated}(执行环境块 `isolation`,与 boot `remote_exec_enabled.isolated` 同一只)。见头注第三键段。 */
10
10
  readonly isolated?: boolean;
11
11
  }
12
12
  /**
@@ -87,7 +87,7 @@ export interface ScenarioContext {
87
87
  * 由**每一个**接了停驻挂点的取用方显式交出(一条读法,没有回落):请求腿 = 本请求经鉴权解析的会话与受理时那一读(`boot/resolve-spec.ts`);`/decide` 赎回面 = 行上的
88
88
  * `rootSessionId` 与赎回腿写口放行的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它**只**喂停驻挂点,不挂任何会话级设施(那是 {@link sessionId} 的事,
89
89
  * 判据是「这只 bundle 是不是在那只会话上取用的」,与属主来源是两个独立判据)。缺席 = 没有根可交(boot 期探针、run-local、行上没有根)⇒ 律给哨兵。
90
- * 挂点在停驻那一刻再读一次根行:住客不是见证的那一位(删了、同 id 被重新登记)⇒ 停驻否决 —— 不按新住客晋升或认领。
90
+ * 挂点在停驻那一刻再读一次根行:住客不是见证的那一位(删了、同 id 被重新登记)⇒ 停驻否决 —— 不按新住客认领。
91
91
  */
92
92
  delegationRoot?: DelegationRootWitness;
93
93
  }
@@ -140,6 +140,15 @@ export declare function mcpReconnect(d: Pick<Deps, "runStore" | "sessionStorage"
140
140
  runStore: Store<"runStore">;
141
141
  sessionStorage: HeadReadingSessionStore;
142
142
  }>;
143
+ /**
144
+ * 在飞 run 的切档口(`POST /v1/runs/:id/permission-mode`)= 持久 run 账面 ∧ checkpoint 店(ctx 面)。后一格是承重的:切档要读这条 run 的
145
+ * **存储体**(本任务 settings 的 kill-switch 由受理判官折,与提交口同一份事实),也要把准入的词写回存储体(run 模式词的唯一来源,续跑腿读它);
146
+ * 没有 ctx 面的部署两件都做不了 ⇒ 不提供这一口(能力位 `permissionModeWrite` 同读本事实)。
147
+ */
148
+ export declare function permissionModeWrite(d: Pick<Deps, "runStore" | "checkpointStore">): Fact<"run_store_absent" | "checkpoint_store_absent", {
149
+ runStore: Store<"runStore">;
150
+ checkpointStore: Store<"checkpointStore">;
151
+ }>;
143
152
  export declare function sessionAuditView(d: Pick<Deps, "sessionAudit">): Fact<"session_audit_absent", {
144
153
  sessionAudit: Store<"sessionAudit">;
145
154
  }>;
@@ -113,6 +113,15 @@ export function mcpReconnect(d) {
113
113
  return owned;
114
114
  return yes({ runStore: runs.runStore, sessionStorage: owned.sessionStorage });
115
115
  }
116
+ export function permissionModeWrite(d) {
117
+ const runs = durableRuns(d);
118
+ if (!runs.available)
119
+ return runs;
120
+ const park = checkpointPark(d);
121
+ if (!park.available)
122
+ return park;
123
+ return yes({ runStore: runs.runStore, checkpointStore: park.checkpointStore });
124
+ }
116
125
  export function sessionAuditView(d) {
117
126
  return d.sessionAudit !== undefined ? yes({ sessionAudit: d.sessionAudit }) : no("session_audit_absent");
118
127
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * **结算时作废一张本服务兑现不了的卡** —— 全仓「结算作废」的唯一动词:读卡 → 卡仍 pending ∧ 卡在调用方说的那只会话上 ⇒
3
+ * 按卡**自己的** scope 走 checkpoint 店的 `expire`(与引擎的本进程仲裁器、续跑的 resolve 同一只 CAS,恰一个赢家)。不新增任何持久态。
4
+ *
5
+ * 规则只有一条:**本服务兑现不了的卡不留在待决面上**。两个产地读这一只动词,各自只答「手里是哪一张卡、它该在哪只会话上」:
6
+ * · 验证器自己的停驻(`verifier-pause-card.ts`):卡在验证器现铸的会话上,本服务的续跑链连不回它;
7
+ * · 停驻没落定就以失败收场的腿(`runs.ts` 的 `voidHeldParkCard`:后台腿与续跑腿):卡在本 run 的会话上,但兑现它的那条 run 已经
8
+ * `failed`、认领已放 —— 卡的命运先于认领释放(调用方先调本动词、再放认领)。
9
+ *
10
+ * 不抛:作废没做成(店读 / 作废抛错、卡的会话对不上、没接店)⇒ 卡回到「留在待决面上、由审批兜底收割收走」的形,按产地登记的 tag
11
+ * 响亮留痕(计数 + 探针行 + 一次 warn),结算照常往下走。卡已不 pending / 已不在 ⇒ 什么都不做(CAS 输给了别的结算者,结局相同)。
12
+ *
13
+ * ## 🚧 过渡(引擎动词到货即改调)
14
+ * 店级 `expire` 只作废卡,**不释放**引擎为这张卡钉住的会话(引擎在停驻时 pin 会话,只在续跑终局 / 续跑失败臂 unpin):
15
+ * 被作废的卡的会话在本副本内存里一直常驻到进程重启。引擎给出「作废停驻卡并释放其会话」的动词之后,本动词改调它(两个产地一字不改)。
16
+ */
17
+ import type { CheckpointToken } from "@sema-agent/core";
18
+ import { type FailOpenTag } from "./observability/fail-open.js";
19
+ /** 结算点手里那只 checkpoint 店的两个动词:读卡(取它自己的 scope / 会话 / 状态)→ 按卡自己的 scope CAS 作废。 */
20
+ export interface CardVoidPort {
21
+ get(token: CheckpointToken): Promise<{
22
+ readonly scope?: string;
23
+ readonly sessionId?: string;
24
+ readonly status?: string;
25
+ } | null>;
26
+ expire(token: CheckpointToken, scope: string): Promise<boolean>;
27
+ }
28
+ /** 要作废的那一张:停驻带回的凭据 + 它应在的会话(对不上就不动它 —— 只作废**这一张**)。 */
29
+ export interface CardRef {
30
+ readonly token: CheckpointToken;
31
+ readonly sessionId: string | undefined;
32
+ }
33
+ /**
34
+ * 作废 `card`(见模块头注)。`tag` = 产地登记的 F 类 tag;`at` = 探针行上的产地现场(例 `leg=bg`),接在 `reason=` 之后;
35
+ * detail 形 `reason=<词>[ <at>][ err=<原句>]`,不含凭据。
36
+ */
37
+ export declare function voidPendingCard(card: CardRef, cards: CardVoidPort | undefined, tag: FailOpenTag, at?: string): Promise<void>;
38
+ //# sourceMappingURL=card-void.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { errorText } from "./observability/err-text.js";
2
+ import { recordFailOpen } from "./observability/fail-open.js";
3
+ export async function voidPendingCard(card, cards, tag, at) {
4
+ const miss = (reason, err) => recordFailOpen(tag, `reason=${reason}${at === undefined ? "" : ` ${at}`}${err === undefined ? "" : ` err=${err}`}`);
5
+ if (cards === undefined) {
6
+ miss("no_checkpoint_store");
7
+ return;
8
+ }
9
+ try {
10
+ const live = await cards.get(card.token);
11
+ if (live === null || live.status !== "pending")
12
+ return;
13
+ if (card.sessionId === undefined || live.sessionId !== card.sessionId || typeof live.scope !== "string") {
14
+ miss("card_mismatch");
15
+ return;
16
+ }
17
+ await cards.expire(card.token, live.scope);
18
+ }
19
+ catch (e) {
20
+ miss("store_error", errorText(e));
21
+ }
22
+ }
23
+ //# sourceMappingURL=card-void.js.map
@@ -1,6 +1,6 @@
1
1
  import { CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES } from "@sema-agent/core";
2
2
  import { GLOBAL_SCOPE } from "@sema-agent/settings-schema/api/scopes";
3
- import { WEB_ADMIN_ENV, DOMAIN_SCHEMAS, buildRetiredEnvWire } from "@sema-agent/settings-schema";
3
+ import { DEVICE_RELAY_NONE, WEB_ADMIN_ENV, DOMAIN_SCHEMAS, buildRetiredEnvWire } from "@sema-agent/settings-schema";
4
4
  import { CENTER_CREDENTIAL_RENEW_LEAD_DEFAULT_MS, CENTER_CREDENTIAL_RENEW_LEAD_MAX_MS, CENTER_CREDENTIAL_RENEW_LEAD_MIN_MS } from "./center-credential-renewer.js";
5
5
  import { SANDBOX_IPV6_DEFAULT, SANDBOX_IPV6_WORDS } from "./sandbox-egress-policy.js";
6
6
  import { WORKSPACE_CACHE_DEFAULT, WORKSPACE_CACHE_MOUNT_DEFAULT, WORKSPACE_CACHE_SIZE_DEFAULT, WORKSPACE_CACHE_WORDS } from "./workspace-cache.js";
@@ -14,7 +14,7 @@ import { AUTO_MODE_CLASSIFIER_TIMEOUT_BOUNDS, CENTER_BASE_URL_RULE, CONFIG_PROVI
14
14
  import { DEVICE_HELLO_ACK_BOUNDS } from "./device-ws-protocol.js";
15
15
  import { webSearchProviderFromEnv, WEB_SEARCH_PROVIDERS } from "./plugins/web-search.js";
16
16
  import { AUTONOMY_MODES } from "./runtime-governance.js";
17
- import { REMOTE_EXEC_PROVIDER_WORDS } from "./execution-lane-caps.js";
17
+ import { REMOTE_EXEC_PROVIDER_WORDS, SANDBOX_READ_FLOOR_DEFAULT, SANDBOX_READ_FLOOR_WORDS } from "./execution-lane-caps.js";
18
18
  import { MEMORY_ENGINE_BACKENDS, SESSION_BACKENDS, STORE_BACKENDS } from "@sema-agent/settings-schema/execution-lanes";
19
19
  import { MODEL_PROVIDER_WORDS } from "./model-provider.js";
20
20
  import { buildDisplaySafeUrlChecked } from "./trace/redact.js";
@@ -126,7 +126,7 @@ export const CONFIG_CATALOG = [
126
126
  r("DEVICE_MAX_INFLIGHT_PER_DEVICE", "orchestration", "number", `per-device 在途上限(超额云侧排队;原值进 helloAck.maxInflight;须为 ≥ ${DEVICE_HELLO_ACK_BOUNDS.maxInflight.min} 的规范十进制整数,其余拒启 —— 0 会让每次派发都 device.busy)`, { derivedDefaultNote: "缺席 ⇒ 4(§11-O3 裁定值)" }),
127
127
  r("DEVICE_MAX_PREAUTH_PER_REMOTE", "orchestration", "number", "未鉴权握手的 per-remote 并发帽(正整数或字面 off;XFF/NAT 形用 off+全局帽)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ 8" }),
128
128
  r("DEVICE_RECONNECT_GRACE_MS", "orchestration", "number", `device 断连后在途不判丢的窗(ms;同 epoch 重连续接;原值进 helloAck.reconnectGraceMs;须为 [${DEVICE_HELLO_ACK_BOUNDS.reconnectGraceMs.min}, ${DEVICE_HELLO_ACK_BOUNDS.reconnectGraceMs.max}] 内规范十进制整数,其余拒启)`, { derivedDefaultNote: "缺席 ⇒ adapter 默认 120s" }),
129
- r("DEVICE_RELAY_URL", "orchestration", "url", "设备直达入口:设备连不到本引擎自己的地址(引擎在中继 / 网关之后)时拨的那一个 ws(s) URL,逐字上 /v1/capabilities 的 deviceExecutor.relayUrl;须为无 userinfo / query / fragment、不带凭据形的 ws:// 或 wss:// 绝对地址,其余拒启。不从 FLEET_ADVERTISE_ADDRESS 派生(那是对中心公告的地址,受众不是设备)", { derivedDefaultNote: "缺席 ⇒ 能力面不带 relayUrl,设备按引擎地址 + deviceExecutor.wsPath 拨号" }),
129
+ r("DEVICE_RELAY_URL", "orchestration", "url", "设备入口(REMOTE_EXEC=device 必填):设备连不到本引擎自己的地址(引擎在中继 / 网关之后)时拨的那一个 ws(s) URL,逐字上 /v1/capabilities 的 deviceExecutor.relayUrl;或字面 none = 没有中继,设备按引擎地址 + deviceExecutor.wsPath 拨号(能力面不带 relayUrl;有设备绑定时起服 warn 点名绑定数)。URL 须为无 userinfo / query / fragment、不带凭据形的 ws:// 或 wss:// 绝对地址,其余拒启。不从 FLEET_ADVERTISE_ADDRESS 派生(那是对中心公告的地址,受众不是设备)", { enumValues: [DEVICE_RELAY_NONE], derivedDefaultNote: "无缺省:device 车道的必需键 —— 缺席 / 空串 / 只含空白拒起(撤中继声明的回滚序 = 先恢复引擎自己的入口,再写 none)" }),
130
130
  r("DEVICE_SUPERSEDE", "orchestration", "enum", "同 deviceId 二连的顶替策略", { enumValues: ["stale_only", "deny"], staticDefault: "stale_only", danger: SEC }),
131
131
  r("DIRECT_APPROVAL_DOOR", "approval", "boolean", "直连 /decide 门(无 BFF 的桌面/CLI 客户端;开 ⇒ 要求签名 JWT+HMAC 信封,principal 头降级不可信)", { staticDefault: "false", danger: SEC, configKey: "directApprovalDoor" }),
132
132
  r("DOCKER_COMMAND_TIMEOUT_MS", "orchestration", "number", "local-docker 车道单命令超时(ms)"),
@@ -250,7 +250,7 @@ export const CONFIG_CATALOG = [
250
250
  r("MCP_ELICITATION_TTL_MS", "approval", "number", "elicitation 无人应答释放窗(ms)", { derivedDefaultNote: "缺席 ⇒ 本服务出厂窗(DEFAULT_ELICITATION_THROTTLE)" }),
251
251
  r("MEMORY_AUTO_CONSOLIDATION", "memory", "enum", "记忆自动整理部署席(on=每个建议任务后整库整理跑,记忆内容自动外流到整理模型;off=显式关,胜过引擎缺省;未设=读引擎具名缺省)", { enumValues: ["on", "off"], derivedDefaultNote: "缺席 ⇒ 引擎具名缺省(**本版装的引擎是开**)——不配不等于关;前置=整理阀门开着(MEMORY_CONSOLIDATION_DRIVER=on,或未设而出厂缺省派生成开)", danger: SEC, resolve: (c) => c.memoryConsolidationDriver.autoRunOnRecommendation, booleanEnum: { true: "on", false: "off" } }),
252
252
  r("MEMORY_CAPTURE_POLICY", "memory", "enum", "记忆 capture 姿态(open=声明按面值;governed=按 per-principal verdict;capture-required=恒采)", { enumValues: ["open", "governed", "capture-required"], staticDefault: "open", danger: SEC, configKey: "memoryCapturePolicy" }),
253
- r("MEMORY_CONSOLIDATION_DRIVER", "memory", "enum", "记忆折叠阀门(off=零装配零探针,两 admin 口 404 族;on=座解析 + 两 admin 口 + 引擎面整理两席)", { enumValues: ["on", "off"], derivedDefaultNote: "缺席 ⇒ 起服时派生:整理座不落主模型(MODEL_CHEAP_ID 在场且异于 MODEL_ID,或目录给 consolidate / summarize / flash 档位绑了别的模型)⇒ on;落主模型 ⇒ off + 起服 warn memory_consolidation_default_off_no_cheap_model;结构上跑不起来(无记忆引擎 / pg·tidb 记忆后端 / MEMORY_PROVENANCE=off)⇒ 恒 off 零提示。显式 on 而落主模型 ⇒ 照开 + warn memory_consolidation_on_main_model(按主模型计费)", danger: BILL, resolve: (_c, _env, boot) => (boot.memoryConsolidationValve === undefined ? undefined : boot.memoryConsolidationValve.enabled ? "on" : "off") }),
253
+ r("MEMORY_CONSOLIDATION_DRIVER", "memory", "enum", "记忆折叠阀门(off=零装配零探针,两 admin 口 404 族;on=座解析 + 两 admin 口 + 引擎面整理两席)", { enumValues: ["on", "off"], derivedDefaultNote: "缺席 ⇒ 起服时派生:整理座不落主模型(MODEL_CHEAP_ID 在场且异于 MODEL_ID,或目录给 consolidate / summarize / flash 档位绑了别的模型)⇒ on;落主模型 ⇒ off + 起服 warn memory_consolidation_default_off_no_cheap_model;结构上跑不起来(无记忆引擎 / pg·mysql 记忆后端 / MEMORY_PROVENANCE=off)⇒ 恒 off 零提示。显式 on 而落主模型 ⇒ 照开 + warn memory_consolidation_on_main_model(按主模型计费)", danger: BILL, resolve: (_c, _env, boot) => (boot.memoryConsolidationValve === undefined ? undefined : boot.memoryConsolidationValve.enabled ? "on" : "off") }),
254
254
  r("MEMORY_CONSOLIDATION_INTERVAL_SEC", "memory", "number", "折叠周期腿节律(秒;本 build 任何正值拒启 —— 周期腿未落地,恒 0)", { staticDefault: "0" }),
255
255
  r("MEMORY_CONSOLIDATION_SCOPES", "memory", "csv", "折叠阀门 scope 表(恰一条时=admin 口缺省;不是授权边界)"),
256
256
  r("MEMORY_DELEGATION_EVIDENCE", "memory", "enum", "委派臂污染标记的证据标准", { enumValues: ["static-face", "attested-only"], staticDefault: "static-face", danger: SEC, configKey: "memoryDelegationEvidence" }),
@@ -260,7 +260,7 @@ export const CONFIG_CATALOG = [
260
260
  r("MEMORY_EMBEDDER_MODEL", "memory", "string", "embeddings 模型名"),
261
261
  r("MEMORY_EMBEDDER_TIMEOUT_MS", "memory", "number", "单次 embed 活性上限(ms)", { staticDefault: "30000" }),
262
262
  r("MEMORY_ENGINE", "memory", "enum", "记忆引擎总开关(注入式文件记忆面;双族词表,未知词拒启)", { enumValues: ["on", "off"], staticDefault: "on", configKey: "memoryEngineEnabled", booleanEnum: { true: "on", false: "off" } }),
263
- r("MEMORY_ENGINE_BACKEND", "memory", "enum", "记忆持久面方言(file=现状;pg/tidb=DB 真身,多租户点亮的唯一门)", { enumValues: MEMORY_ENGINE_BACKENDS, staticDefault: "file", danger: DATA, configKey: "memoryEngineBackend" }),
263
+ r("MEMORY_ENGINE_BACKEND", "memory", "enum", "记忆持久面方言(file=现状;pg/mysql=DB 真身,多租户点亮的唯一门;方言与 DB_BACKEND 同字)", { enumValues: MEMORY_ENGINE_BACKENDS, staticDefault: "file", danger: DATA, configKey: "memoryEngineBackend" }),
264
264
  r("MEMORY_ENGINE_DIR", "memory", "path", "记忆引擎根覆写", { derivedDefaultNote: "缺席 ⇒ core 默认链(AGENT_DATA_DIR → ~/.ai-agent)", configKey: "memoryEngineDir" }),
265
265
  r("MEMORY_ENGINE_REMOTE_LANE", "memory", "enum", "远端执行车道上放行 file 记忆引擎的 plane-split 覆写", { enumValues: ["allow"] }),
266
266
  r("MEMORY_ORG_ADMISSION_MODE", "memory", "enum", "org 记忆准入模式(audit=判决照算纯观察)", { enumValues: ["audit", "enforce"], staticDefault: "enforce", danger: SEC, configKey: "memoryOrgAdmissionMode" }),
@@ -395,12 +395,13 @@ export const CONFIG_CATALOG = [
395
395
  r("RATE_LIMIT_RPM", "limitsHttp", "number", "计费提交每分钟限流(0=关)", { staticDefault: "0", danger: BILL, configKey: "rateLimitPerMin", center: cLimits("rateLimitPerMin") }),
396
396
  r("READ_DENY_BUILTIN_EXCLUDE", "orchestration", "csv", "按行名删内建 deny 条目(档位之后生效;绝不削任务显式 deny)", { danger: SEC, configKey: "readDenyBuiltinExclude" }),
397
397
  r("READ_DENY_BUILTIN_TIERS", "orchestration", "csv", "内建 deny 表档位选择(闭集五档 credentials/shell-history/browser/wallet/agent-config;none=显式空姿态)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ 出厂两档在岗 **credentials,agent-config**(core 7.34.0 R-2 起;7.22.0–7.33.x 曾为 OFF)。要全关显式写 none;要全五档显式写 credentials,shell-history,browser,wallet,agent-config;空值拒启(手滑与显式意图不许同形)", configKey: "readDenyBuiltinTiers" }),
398
+ r("READ_DENY_FLOOR_REQUIRED", "orchestration", "boolean", "要求读拒表的字节地板:true ⇒ 读拒表有行而执行环境不守地板(起服行 remote_exec_enabled.keepsReadFloor=false;此时另有起服 warn read_deny_floor_required_unkept)的 run 在准备期拒(config.read_deny_floor_unkept,一个命令都不起;同步提交 409)。出厂读拒档在岗 ⇒ 不守地板的车道(主机 / ssh / adb / device,以及读地板模块尚未服务或 SANDBOX_READ_FLOOR=off 的沙箱车道)上带手的 run 一律拒起", { staticDefault: "false", danger: SEC, derivedDefaultNote: "缺席 ⇒ 不要求:run 照跑,每 run 一条 operator 通告 config.read_deny_floor_unkept(engine_notice 日志;递归读照读表里的文件,通告不是保护)", configKey: "readDenyFloorRequired" }),
398
399
  r("READ_DENY_PATTERNS", "orchestration", "csv", "READ 面额外 deny pattern 表", { danger: SEC, configKey: "readDenyPatterns" }),
399
400
  r("READ_FACE", "orchestration", "enum", "READ 容纳面档位(env 逐键恒赢 center —— 部署主权表达)", { enumValues: ["open", "roots"], danger: SEC, derivedDefaultNote: "缺席 ⇒ 按 posture 派生(S-167):单用户 turnkey(REQUIRE_PRINCIPAL 未设)铸 open;多租户不铸键、core 默认 roots。生效来源见 GET /v1/diagnostics/wiring 的 readFace.source 四词", configKey: "readFace" }),
400
401
  r("REAP_INTERVAL_SEC", "limitsHttp", "number", "reaper 周期(秒)", { staticDefault: "60", configKey: "reapIntervalSec" }),
401
402
  r("REAP_RUN_STALE_SEC", "limitsHttp", "number", "run 活性判陈旧阈(秒)", { staticDefault: "120", configKey: "runStaleSec", center: cLimits("runStaleSec") }),
402
- r("REMOTE_EXEC", "orchestration", "enum", "执行车道选择(点名而配不齐/认不出 ⇒ 拒启,绝不静默降级到 host/stub)", { enumValues: REMOTE_EXEC_PROVIDER_WORDS, danger: SEC, derivedDefaultNote: "缺席:CONFIG_PROVIDER=local ⇒ host;其余 ⇒ 进程内 stub(手带整族不挂;残余名册看活体 wiring_manifest 里 mountedBy=hands 的条目数,不按工具名点。想让这一形拒启见 REQUIRE_EXECUTION_LANE)", configKey: "remoteExec", resolve: (c) => c.remoteExec?.provider ?? null }),
403
- r("REMOTE_EXEC_HOME_DIR", "orchestration", "path", "执行环境的 home 目录(`~/` 形权限规则的基、引擎家锚拒读行的落点;core ExecutionEnv.homeDir 座)。声明优先:不声明时 k8s / local-docker / ssh / adb 车道建环境那一拍实测执行环境自己的 $HOME 填引擎手里的座(`~/` 形规则的下单门仍只认声明);k8s / local-docker / ssh 车道的声明会在每只执行环境开起来时与它的 $HOME 对证(同一只判官、同一句拒),不一致或问不出 ⇒ 那只环境不开", { danger: SEC, derivedDefaultNote: "缺席:host/in-process ⇒ os.homedir();e2b ⇒ /home/user;k8s/local-docker/ssh/adb ⇒ 建环境时实测 $HOME(实测缺席 ⇒ 那只环境的座缺席:泄内容的递归读全 shell 面真人问、只读面拒,并响 warn execution_lane_home_undeclared);device ⇒ 无(设备协议没有家目录读数:起服 warn execution_lane_home_undeclared);`~/` 形规则的下单门恒只认声明(无声明即 422 响亮拒)", configKey: "remoteExecHomeDir", resolve: (c) => c.remoteExecHomeDir ?? null }),
403
+ r("REMOTE_EXEC", "orchestration", "enum", "执行车道选择(点名而配不齐/认不出 ⇒ 拒启,绝不静默降级到 host/stub)。形 = 部署声明的有序车道表(逗号分隔、首项缺省,契约 runtime.execution.lanes 的渲染形);本引擎每个进程只装一条车道 ⇒ 表里不止一条拒启,单词照旧", { enumValues: REMOTE_EXEC_PROVIDER_WORDS, danger: SEC, derivedDefaultNote: "缺席:CONFIG_PROVIDER=local ⇒ host;其余 ⇒ 进程内 stub(手带整族不挂;残余名册看活体 wiring_manifest 里 mountedBy=hands 的条目数,不按工具名点。想让这一形拒启见 REQUIRE_EXECUTION_LANE)", configKey: "remoteExec", resolve: (c) => c.remoteExec?.provider ?? null }),
404
+ r("REMOTE_EXEC_HOME_DIR", "orchestration", "path", "执行环境的 home 目录(`~/` 形权限规则的基、引擎家锚拒读行的落点;core ExecutionEnv.homeDir 座)。声明与车道出厂答案(host ⇒ 本进程家目录,e2b ⇒ /home/user)都是主张:读得出家目录的车道(k8s / local-docker / ssh / adb / e2b / host)在每只执行环境开起来时拿环境里命令看到的 $HOME 证它(同一只判官、同一句拒),不一致或问不出 ⇒ 那只环境不开;不声明且车道没有出厂答案时,建环境那一拍实测 $HOME 填引擎手里的座(`~/` 形规则的下单门仍只认 boot 期答案);device 读不了 ⇒ 声明即座、起服 warn execution_lane_home_unmeasured 披露未实测", { danger: SEC, derivedDefaultNote: "缺席:host/in-process ⇒ os.homedir();e2b ⇒ /home/user(两者都在环境开起来时与 $HOME 对证);k8s/local-docker/ssh/adb ⇒ 建环境时实测 $HOME(实测缺席 ⇒ 那只环境的座缺席:泄内容的递归读全 shell 面真人问、只读面拒,并响 warn execution_lane_home_undeclared);device ⇒ 无(设备协议没有家目录读数:起服 warn execution_lane_home_undeclared);`~/` 形规则的下单门恒只认声明(无声明即 422 响亮拒)", configKey: "remoteExecHomeDir", resolve: (c) => c.remoteExecHomeDir ?? null }),
404
405
  r("REQUIRE_EXECUTION_LANE", "orchestration", "boolean", "开了之后:REMOTE_EXEC 未点名 ∧ CONFIG_PROVIDER≠local ⇒ **拒启**并点名该设什么。默认关 = 照旧启动,但执行环境是进程内 stub、**零手带工具**(手带整族不挂;活体读数:mountedBy=hands 条目 10 → 0),名册里其余工具照常执行,任务仍回 status=completed —— 凡需要手的请求,与「模型不肯用工具」在用户面同形。判据 = 活体 wiring_manifest 里 mountedBy=hands 的条目数,不按工具名点;名册总条数随 core 版本走,不写死。托管/云部署推荐开(docs/DEPLOY-PREREQS.md)", { staticDefault: "false", danger: SEC, configKey: "requireExecutionLane" }),
405
406
  r("REQUIRE_PRINCIPAL", "auth", "boolean", "多租户开关(posture 判别位:true ⇒ CC 能力族默认收紧)", { staticDefault: "false", danger: SEC, configKey: "requirePrincipal" }),
406
407
  r("RESOURCE_SUSPEND", "approval", "boolean", "durable 路径 opt-in core resourceSuspend(预算/preempt ⇒ 可恢复挂起)", { staticDefault: "false", configKey: "resourceSuspend" }),
@@ -421,6 +422,7 @@ export const CONFIG_CATALOG = [
421
422
  r("SANDBOX_BASE_REF", "orchestration", "string", "bake 缺省 base ref(缺席回落 index 最新 sandbox-base)"),
422
423
  r("SANDBOX_ENV_FACTS", "orchestration", "boolean", "沙箱事实注入(# Environment 块的 profile/capabilities/pkgSource/egress/resume 事实);会话 scratchpad 的宣告不归本键管(S-842:它是写面的宣告,关事实不关 scratchpad)", { staticDefault: "true", configKey: "envFactsEnabled" }),
423
424
  r("SANDBOX_PKG_SOURCE", "orchestration", "enum", "沙箱包源选择(cn/global/custom;none=完全不注入)", { enumValues: ["global", "cn", "custom", "none"], staticDefault: "global" }),
425
+ r("SANDBOX_READ_FLOOR", "orchestration", "enum", "沙箱三车道(e2b / k8s / local-docker)的读拒表字节地板:keep = 沙箱读地板模块服务该车道时守地板(命令跑的每个程序都打不开读拒表判拒的路径,做不到就拒起该命令:spawn_error 首句点名原因词);off = 不守(车道块 keepsReadFloor=false,起动与没有模块时逐字同)。起服行 remote_exec_enabled.sandboxReadFloor 报生效状态(kept / off / unserved);别的车道上无作用;词表外 / 空串拒启", { enumValues: SANDBOX_READ_FLOOR_WORDS, staticDefault: SANDBOX_READ_FLOOR_DEFAULT, danger: SEC, derivedDefaultNote: "缺席 ⇒ keep;本版模块尚未服务任何沙箱车道(状态 unserved),三条沙箱车道照旧不守地板", configKey: "sandboxReadFloor" }),
424
426
  r("SCHEDULER_ENABLED", "orchestration", "boolean", "自唤醒 scheduler(host 车道单用户形)", { derivedDefaultNote: "posture 三态:缺席 = 单用户 ⇒ on / 多租户 ⇒ off(调度归 center)", configKey: "schedulerEnabled" }),
425
427
  r("SCHEDULER_SESSION_LIFETIME", "orchestration", "boolean", "session-lifetime 记录 host-signal(headless 壳注 false ⇒ CronCreate 前门拒)", { staticDefault: "true", configKey: "schedulerSessionLifetime" }),
426
428
  r("SCHEDULER_SESSION_WAKEUP", "orchestration", "boolean", "session 唤醒 host-signal(无常驻 daemon 的壳注 false)", { staticDefault: "true", configKey: "schedulerSessionWakeup" }),
@@ -450,7 +452,7 @@ export const CONFIG_CATALOG = [
450
452
  r(WEB_ADMIN_ENV.worker, "integrations", "string", "本 worker 在 web-admin 上的名字(per-worker effective)"),
451
453
  r("SEND_USER_FILE_SANDBOX_PUT_ENDPOINT", "store", "url", "沙箱侧 presigned PUT Host 绑定 endpoint(in-cluster 可用内网面)", { derivedDefaultNote: "缺席 ⇒ publicEndpoint" }),
452
454
  r("SEND_USER_FILE_URL_TTL", "store", "number", "公链 TTL(秒;非法值回 0=永久轨,绝不 NaN 进签名)", { staticDefault: "0" }),
453
- r("SENSITIVE_WRITE_PATTERNS", "approval", "csv", "敏感路径写 deny 集(unset=core 推荐集;显式值整表替换;off/空=关 —— 真放松杆)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ core RECOMMENDED_SENSITIVE_PATTERNS", configKey: "sensitiveWritePatterns" }),
455
+ r("SENSITIVE_WRITE_PATTERNS", "approval", "csv", "敏感路径写 deny 集(unset=core 推荐集;显式值整表替换;off/空=关 —— 真放松杆)。拒的是文件工具(Write / Edit / NotebookEdit,按路径);shell 命令写同一路径(重定向 / tee / cp …)不被这个集拒绝,走普通审批问", { danger: SEC, derivedDefaultNote: "缺席 ⇒ core RECOMMENDED_SENSITIVE_PATTERNS", configKey: "sensitiveWritePatterns" }),
454
456
  r("SERVICE_AUTH_TOKEN", "auth", "secret", "共享 service token(写面门;缺席且未开 ALLOW_UNAUTHED_WRITES ⇒ 拒提交)", { danger: SEC }),
455
457
  r("SERVICE_AUTH_TOKENS", "auth", "secret", "per-system 凭据表(tok=system CSV;source 从凭据派生,绝不自报)", { danger: SEC }),
456
458
  r("SESSION_AUTO_TITLE", "orchestration", "boolean", "首次提交自动铸 session 标题(一次 cheap 调用)", { staticDefault: "true", danger: BILL, configKey: "sessionAutoTitle" }),
@@ -641,6 +643,8 @@ function sanitizeValue(spec, v) {
641
643
  const type = spec.type;
642
644
  if (type === "url") {
643
645
  if (typeof v === "string") {
646
+ if (spec.enumValues?.includes(v) === true)
647
+ return { value: v };
644
648
  if (v.includes(","))
645
649
  return displayUrlItems(v.split(",").map((s) => s.trim()), true);
646
650
  const shown = buildDisplaySafeUrlChecked(v);