@sema-agent/server 7.142.0 → 7.144.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 (301) hide show
  1. package/MIGRATION.md +608 -0
  2. package/USAGE.md +63 -36
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +7 -5
  5. package/dist/approval-ask-audit-store.js +12 -6
  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 +155 -39
  9. package/dist/approval-card.js +111 -31
  10. package/dist/approval-queue-kind.d.ts +27 -0
  11. package/dist/approval-queue-kind.js +6 -0
  12. package/dist/approval-reconciler.d.ts +8 -8
  13. package/dist/approval-reconciler.js +3 -3
  14. package/dist/audit.js +4 -2
  15. package/dist/boot/budget-tracing.d.ts +1 -1
  16. package/dist/boot/execution-env.js +1 -1
  17. package/dist/boot/governance-seams.d.ts +26 -41
  18. package/dist/boot/governance-seams.js +61 -28
  19. package/dist/boot/late-binds.d.ts +7 -4
  20. package/dist/boot/late-binds.js +3 -1
  21. package/dist/boot/leader.js +2 -4
  22. package/dist/boot/memory-consolidation.d.ts +0 -8
  23. package/dist/boot/memory-consolidation.js +3 -3
  24. package/dist/boot/reapers.js +5 -4
  25. package/dist/boot/resolve-spec.d.ts +1 -1
  26. package/dist/boot/resolve-spec.js +8 -8
  27. package/dist/boot/runner-deps.d.ts +14 -6
  28. package/dist/boot/runner-deps.js +6 -17
  29. package/dist/boot/shutdown.d.ts +9 -0
  30. package/dist/boot/shutdown.js +18 -2
  31. package/dist/boot/stage-01-config.js +2 -0
  32. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  33. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  34. package/dist/boot/stage-03-store-backend.js +1 -2
  35. package/dist/boot/stage-04-stores.d.ts +5 -2
  36. package/dist/boot/stage-04-stores.js +3 -5
  37. package/dist/boot/stage-05-execution-env.d.ts +5 -2
  38. package/dist/boot/stage-06-runners.d.ts +5 -2
  39. package/dist/boot/stage-06-runners.js +1 -3
  40. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  41. package/dist/boot/stage-07-capability-layer.js +6 -2
  42. package/dist/boot/stage-08-reapers.d.ts +5 -2
  43. package/dist/boot/stage-09-leader.d.ts +5 -2
  44. package/dist/boot/stage-10-http-server.d.ts +5 -2
  45. package/dist/boot/stage-10-http-server.js +4 -1
  46. package/dist/boot/stores.d.ts +5 -2
  47. package/dist/boot/stores.js +7 -7
  48. package/dist/boot/web-admin.d.ts +5 -1
  49. package/dist/boot/web-admin.js +31 -19
  50. package/dist/capabilities/hands-lane.d.ts +9 -39
  51. package/dist/capabilities/hands-lane.js +8 -13
  52. package/dist/capabilities/mcp-probe.d.ts +3 -2
  53. package/dist/capabilities/scenarios.d.ts +23 -17
  54. package/dist/capabilities/scenarios.js +2 -2
  55. package/dist/capabilities/skills.d.ts +1 -17
  56. package/dist/capabilities/skills.js +0 -8
  57. package/dist/capability-facts.d.ts +8 -8
  58. package/dist/capability-facts.js +4 -4
  59. package/dist/card-void.d.ts +6 -9
  60. package/dist/config-catalog.js +1 -1
  61. package/dist/config-d-migration.d.ts +2 -0
  62. package/dist/config-dir-trust.js +58 -29
  63. package/dist/config-invariants.d.ts +7 -1
  64. package/dist/config-invariants.js +7 -0
  65. package/dist/config-provider.d.ts +10 -0
  66. package/dist/config-provider.js +15 -4
  67. package/dist/config-root-migration.d.ts +13 -0
  68. package/dist/config-root-migration.js +99 -0
  69. package/dist/config-types.d.ts +5 -5
  70. package/dist/config.d.ts +4 -3
  71. package/dist/config.js +1 -1
  72. package/dist/delegated-session-owner.d.ts +35 -151
  73. package/dist/delegated-session-owner.js +1 -83
  74. package/dist/device-ws-protocol.d.ts +1 -0
  75. package/dist/device-ws-protocol.js +2 -1
  76. package/dist/entry-mode-clamp-notice.d.ts +1 -1
  77. package/dist/env-model-table-gate.d.ts +53 -0
  78. package/dist/env-model-table-gate.js +53 -0
  79. package/dist/execution-placement.d.ts +7 -4
  80. package/dist/fleet/fleet-bus.d.ts +28 -52
  81. package/dist/fleet/fleet-bus.js +35 -100
  82. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  83. package/dist/fleet/fleet-reconciler.js +1 -1
  84. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  85. package/dist/fleet/subagent-tail-bus.js +15 -28
  86. package/dist/hooks/classic-stations.d.ts +3 -1
  87. package/dist/hooks/classic-stations.js +2 -0
  88. package/dist/hooks/hook-runner.js +28 -7
  89. package/dist/host-decision.d.ts +54 -20
  90. package/dist/host-decision.js +42 -14
  91. package/dist/http/admission.d.ts +1 -1
  92. package/dist/http/admission.js +7 -3
  93. package/dist/http/approval-sweeps.js +11 -8
  94. package/dist/http/caller-trust.d.ts +1 -1
  95. package/dist/http/durable-run-leg.js +2 -2
  96. package/dist/http/engine-refusal.d.ts +16 -0
  97. package/dist/http/engine-refusal.js +17 -0
  98. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  99. package/dist/http/memory-compliance-failure-reply.js +4 -6
  100. package/dist/http/owner-access.d.ts +11 -0
  101. package/dist/http/owner-access.js +13 -0
  102. package/dist/http/principal-gate.d.ts +1 -1
  103. package/dist/http/refusal-body.d.ts +7 -3
  104. package/dist/http/refusal-body.js +1 -0
  105. package/dist/http/resume-legs.d.ts +21 -7
  106. package/dist/http/resume-legs.js +82 -53
  107. package/dist/http/resume-restatement.d.ts +39 -0
  108. package/dist/http/resume-restatement.js +25 -0
  109. package/dist/http/route-ctx.d.ts +35 -10
  110. package/dist/http/route-ctx.js +1 -1
  111. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  112. package/dist/http/routes/approvals-assistant.js +143 -31
  113. package/dist/http/routes/capabilities.js +11 -2
  114. package/dist/http/routes/memory-policy.d.ts +2 -2
  115. package/dist/http/routes/memory-policy.js +1 -1
  116. package/dist/http/routes/notify-wake.js +23 -25
  117. package/dist/http/routes/rules.js +48 -13
  118. package/dist/http/routes/runs.js +9 -8
  119. package/dist/http/routes/session-memory-sync.d.ts +34 -6
  120. package/dist/http/routes/session-memory-sync.js +27 -10
  121. package/dist/http/routes/session-sync.js +13 -20
  122. package/dist/http/routes/sessions.d.ts +2 -2
  123. package/dist/http/routes/sessions.js +22 -23
  124. package/dist/http/routes/tasks.js +27 -49
  125. package/dist/http/server.d.ts +13 -7
  126. package/dist/http/server.js +2 -2
  127. package/dist/http/stored-body-replay.js +15 -4
  128. package/dist/http/wire-types.d.ts +17 -7
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js +1 -0
  131. package/dist/lane-home-probe.d.ts +15 -0
  132. package/dist/lane-home-probe.js +4 -0
  133. package/dist/leader/leader.js +5 -2
  134. package/dist/leader/wire.d.ts +7 -1
  135. package/dist/leader/wire.js +6 -5
  136. package/dist/leg-facts.d.ts +37 -0
  137. package/dist/leg-facts.js +15 -0
  138. package/dist/memory-bundle-engine.d.ts +1 -4
  139. package/dist/memory-bundle-engine.js +2 -2
  140. package/dist/memory-operator-faces.d.ts +30 -66
  141. package/dist/memory-operator-faces.js +17 -88
  142. package/dist/memory-scope-stores.d.ts +38 -40
  143. package/dist/memory-scope-stores.js +51 -36
  144. package/dist/memory-scope.d.ts +0 -9
  145. package/dist/memory-scope.js +0 -9
  146. package/dist/memory-sync-client.js +14 -3
  147. package/dist/memory-sync.d.ts +20 -4
  148. package/dist/memory-sync.js +23 -4
  149. package/dist/model-plane-face.d.ts +13 -7
  150. package/dist/model-plane-face.js +2 -1
  151. package/dist/observability/corrupt-read-seat.d.ts +5 -9
  152. package/dist/observability/corrupt-read-seat.js +1 -2
  153. package/dist/observability/fail-open.d.ts +30 -10
  154. package/dist/observability/fail-open.js +27 -10
  155. package/dist/observability/run-terminal.d.ts +1 -1
  156. package/dist/observability/run-terminal.js +6 -2
  157. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  158. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  159. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  160. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  161. package/dist/orchestration/workflow-park-decision.js +5 -3
  162. package/dist/org-delivery-gate.d.ts +11 -0
  163. package/dist/org-delivery-gate.js +19 -1
  164. package/dist/parked-decide.d.ts +13 -9
  165. package/dist/parked-decide.js +7 -7
  166. package/dist/parked-revive-surface.d.ts +6 -7
  167. package/dist/parked-revive-surface.js +1 -1
  168. package/dist/peer-inbound-face.d.ts +122 -0
  169. package/dist/peer-inbound-face.js +123 -0
  170. package/dist/permission-rule-list.d.ts +13 -9
  171. package/dist/permission-rule-list.js +7 -3
  172. package/dist/plugins/approval-ask-store-file.js +18 -6
  173. package/dist/plugins/approval-ask-store-memory.js +8 -6
  174. package/dist/plugins/approval-ask-store-sql.d.ts +28 -13
  175. package/dist/plugins/approval-ask-store-sql.js +30 -11
  176. package/dist/plugins/caching-session-store.d.ts +0 -3
  177. package/dist/plugins/caching-session-store.js +0 -3
  178. package/dist/plugins/checkpoint-store-sql.d.ts +45 -38
  179. package/dist/plugins/checkpoint-store-sql.js +108 -45
  180. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  181. package/dist/plugins/file-history-store-sql.js +24 -19
  182. package/dist/plugins/file-run-store.d.ts +29 -0
  183. package/dist/plugins/file-run-store.js +97 -8
  184. package/dist/plugins/fork-routing-session-store.d.ts +8 -1
  185. package/dist/plugins/fork-routing-session-store.js +6 -0
  186. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  187. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  188. package/dist/plugins/local-checkpoint-store.d.ts +6 -8
  189. package/dist/plugins/local-checkpoint-store.js +5 -4
  190. package/dist/plugins/local-session-store.d.ts +69 -30
  191. package/dist/plugins/local-session-store.js +133 -57
  192. package/dist/plugins/local-session-window.d.ts +4 -2
  193. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  194. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  195. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  196. package/dist/plugins/mailbox-store-sql.js +76 -7
  197. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  198. package/dist/plugins/memory-sync-store-pg.js +21 -0
  199. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  200. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  201. package/dist/plugins/one-time-migrations.d.ts +44 -14
  202. package/dist/plugins/one-time-migrations.js +118 -15
  203. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  204. package/dist/plugins/org-delivery-quota-store.js +2 -12
  205. package/dist/plugins/park-commit-watch.d.ts +1 -1
  206. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  207. package/dist/plugins/permission-rule-store-file.js +15 -2
  208. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  209. package/dist/plugins/permission-rule-store-sql.js +35 -2
  210. package/dist/plugins/pg-session-storage.d.ts +1 -9
  211. package/dist/plugins/pg-session-storage.js +2 -19
  212. package/dist/plugins/remote-env-device.d.ts +8 -11
  213. package/dist/plugins/remote-env-device.js +6 -3
  214. package/dist/plugins/remote-env-host.d.ts +8 -4
  215. package/dist/plugins/remote-env-host.js +7 -9
  216. package/dist/plugins/remote-env-k8s.d.ts +37 -24
  217. package/dist/plugins/remote-env-k8s.js +50 -17
  218. package/dist/plugins/remote-shell.js +12 -2
  219. package/dist/plugins/retention-store-sql.d.ts +2 -2
  220. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  221. package/dist/plugins/sandbox-read-floor.js +2 -7
  222. package/dist/plugins/schema-consistency.d.ts +5 -1
  223. package/dist/plugins/session-fork.d.ts +1 -1
  224. package/dist/plugins/session-ownership.d.ts +9 -0
  225. package/dist/plugins/session-ownership.js +6 -0
  226. package/dist/plugins/session-store.d.ts +13 -16
  227. package/dist/plugins/session-store.js +9 -10
  228. package/dist/plugins/sql-errors.d.ts +10 -1
  229. package/dist/plugins/sql-errors.js +13 -0
  230. package/dist/plugins/sql-json-column.d.ts +24 -2
  231. package/dist/plugins/sql-json-column.js +38 -3
  232. package/dist/plugins/store-backend.d.ts +23 -28
  233. package/dist/plugins/store-backend.js +12 -3
  234. package/dist/plugins/store-contracts.d.ts +29 -5
  235. package/dist/plugins/store-contracts.js +4 -1
  236. package/dist/plugins/task-attachment-store.d.ts +2 -2
  237. package/dist/plugins/task-attachment-store.js +37 -52
  238. package/dist/plugins/tidb-session-store.d.ts +2 -14
  239. package/dist/plugins/tidb-session-store.js +2 -20
  240. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  241. package/dist/plugins/tool-result-store-sql.js +23 -2
  242. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  243. package/dist/plugins/wiring-section-codec.js +55 -0
  244. package/dist/plugins/workspace-fill.d.ts +1 -1
  245. package/dist/rule-entry-list.d.ts +3 -2
  246. package/dist/rule-entry-list.js +5 -1
  247. package/dist/rules-consent.d.ts +28 -5
  248. package/dist/rules-consent.js +40 -28
  249. package/dist/run-local.js +11 -6
  250. package/dist/runs.d.ts +12 -8
  251. package/dist/runs.js +10 -7
  252. package/dist/runtime-governance.d.ts +1 -1
  253. package/dist/security.d.ts +0 -4
  254. package/dist/server-secret-env.d.ts +4 -0
  255. package/dist/session-error-wire.d.ts +34 -23
  256. package/dist/session-error-wire.js +8 -3
  257. package/dist/session-incarnation.d.ts +3 -3
  258. package/dist/session-notify-door.d.ts +106 -0
  259. package/dist/session-notify-door.js +97 -0
  260. package/dist/session-sync.d.ts +9 -14
  261. package/dist/session-sync.js +5 -5
  262. package/dist/session-workspace.d.ts +3 -13
  263. package/dist/session-workspace.js +0 -9
  264. package/dist/standing-answer-grant.d.ts +5 -0
  265. package/dist/standing-answer-grant.js +10 -0
  266. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  267. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  268. package/dist/task-mcp.d.ts +1 -1
  269. package/dist/task-settings.d.ts +11 -8
  270. package/dist/task-settings.js +31 -11
  271. package/dist/tool-approval.d.ts +55 -35
  272. package/dist/tool-approval.js +112 -74
  273. package/dist/trace/core-keyset-guard.d.ts +12 -9
  274. package/dist/trace/engine-notice-wire.d.ts +1 -1
  275. package/dist/trace/engine-notice-wire.js +4 -2
  276. package/dist/trace/exit-seat.d.ts +7 -1
  277. package/dist/trace/exit-seat.js +1 -0
  278. package/dist/trace/ledger-sink.d.ts +2 -2
  279. package/dist/trace/ledger-sink.js +12 -4
  280. package/dist/trace/model-segment.d.ts +74 -25
  281. package/dist/trace/model-segment.js +141 -32
  282. package/dist/trace/project.d.ts +15 -6
  283. package/dist/trace/project.js +12 -4
  284. package/dist/trace/redact.d.ts +72 -9
  285. package/dist/trace/redact.js +1509 -471
  286. package/dist/trace/self-minted-wire.d.ts +598 -47
  287. package/dist/trace/self-minted-wire.js +190 -20
  288. package/dist/trace/wire-projection-faces.d.ts +1 -1
  289. package/dist/trace/wire-projection-faces.js +1 -1
  290. package/dist/verifier-pause-card.d.ts +33 -5
  291. package/dist/verifier-pause-card.js +15 -10
  292. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  293. package/dist/web-admin-client/apply-effective.js +90 -10
  294. package/dist/workspace-space.d.ts +19 -3
  295. package/dist/workspace-space.js +8 -4
  296. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  297. package/package.json +3 -2
  298. package/wire-changes/server@7.143.0.json +1167 -0
  299. package/wire-changes/server@7.144.0.json +291 -0
  300. package/dist/session-records-skipped-notice.d.ts +0 -21
  301. package/dist/session-records-skipped-notice.js +0 -27
@@ -2,7 +2,7 @@ import { MemoryEngine } from "@sema-agent/core";
2
2
  import { memoryMountRootOf } from "./memory-scope.js";
3
3
  import { memoryStoreForRequest } from "./memory-scope-stores.js";
4
4
  import { captureRecordStoreOf } from "./memory-operator-faces.js";
5
- export function createMemoryBundleFaces(stores, opts) {
5
+ export function createMemoryBundleFaces(stores) {
6
6
  if (!carriesBundleComposite(stores.backend))
7
7
  return undefined;
8
8
  const engines = new Map();
@@ -12,7 +12,7 @@ export function createMemoryBundleFaces(stores, opts) {
12
12
  return known;
13
13
  if (!carriesBundleComposite(store))
14
14
  throw new Error("the memory store that holds these layers implements no v2-c bundle composite (exportSnapshotOf / importBundleCommit) — a bundle is never assembled outside one");
15
- const records = captureRecordStoreOf(opts?.captureRecords, store);
15
+ const records = captureRecordStoreOf(stores.captureRecords, store);
16
16
  const engine = new MemoryEngine({ backend: store, memoryDir: memoryMountRootOf(store, stores.root), ...(records !== undefined ? { captureRecordStore: records } : {}) });
17
17
  engines.set(store, engine);
18
18
  return engine;
@@ -16,15 +16,11 @@
16
16
  * 修前三只工厂各在**部署的店**上建一只引擎 —— 目录钉住的部署上,类型化个人层(`user:` / `userproj:` / `org:`)的会话条目在个人挂载上的
17
17
  * 另一只店里,擦的、查的、清标的都是会话不读的那只店。
18
18
  *
19
- * 会话 id 的两只动词不点名层(会话的写家在哪只店由它各条腿的任务根定,服务端没有存;一只会话可以跨两只店):
20
- * · 会话记忆状态读**本部署的每一只店**(`memoryStoresOfDeployment`,至多两只),逐店的答案按 {@link foldPlaneStatuses} 折成一份;
21
- * · 按会话抹除(`{ sessionId }` 选择子)落部署的店,见下一节的护栏。
22
- *
23
- * ## 抹除只在部署的店上执行({@link MemoryErasureStoreUnjudged})
24
- * 抹除 `requestId` 的幂等判(重放收敛、同 id 换了选择子 ⇒ `memory.erasure_selector_mismatch`)记在**每只店自己的**证据链上,引擎今天没有
25
- * 跨店的请求身份、也没有按 `requestId` 读锚的公开面;本层不另记一本请求账(第二真源)。所以本服务只在**一只**店上执行抹除 —— 部署的店,
26
- * 它的证据链就是本部署唯一的判官:请求落到别的店(点名的层住在个人挂载那只店),或按会话抹除而这只会话在别的店里有贡献(或那只店的账读不出)
27
- * ⇒ 409 拒,什么都不删。🚧 引擎给出部署级的抹除请求身份后,这条护栏删除、各店照常执行(钉在 `test/memory-project-scope.test.ts` ⑩)。
19
+ * 抹除与会话记忆状态答的是**整个部署**(记忆作用域店的部署对象,引擎的 `createMemoryDeployment`):
20
+ * · 抹除 —— operator 面与会话自助面同一只部署对象的 `eraseMemoryEntries`:一个 `requestId` 在整个部署里只名一次请求,引擎在任何一只店执行之前
21
+ * 读遍每只店的锚(同一个 id 换了选择子、或落到另一只店 ⇒ `memory.erasure_selector_mismatch`,什么都没删);`{ scope }` / `expectedScopes`
22
+ * 落那几层住的店,`{ ids }` / `{ sessionId }` 不带授权集 ⇒ 每只店各擦各的那一份,收执合成一份。本层不定店、不另记请求账;
23
+ * · 会话记忆状态 —— 不带层座 ⇒ 部署对象的答案(引擎在每只店上折成一份;折叠律只在引擎里);带层座 ⇒ 那一层住的那只店上的引擎答案。
28
24
  *
29
25
  * ## 控制面归属:为什么 `controlPlaneRoot` 缺席就整口不挂(F-9 裁)
30
26
  *
@@ -62,17 +58,9 @@
62
58
  * core 自己响亮拒(`memory.erasure_evidence_unavailable`),那是**运行期**的诚实拒,与「换部署形态才行」
63
59
  * 不是一回事(附录 A 两条分列)。
64
60
  */
65
- import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin, type MemoryErasureAttestation, type OriginClearanceRow, type SessionCaptureRecordStore, type SessionMemoryStatus } from "@sema-agent/core";
61
+ import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin, type MemoryErasureAttestation, type OriginClearanceRow, type DeploymentSessionMemoryStatus, type SessionCaptureRecordStore } from "@sema-agent/core";
66
62
  import { type MemoryScopeStores } from "./memory-scope-stores.js";
67
63
  import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
68
- /**
69
- * 控制面归属判据 —— 三个记忆操作面(合规两口 / 外源标记三口 / consolidation 阀门的 D1 拒启门)共用的
70
- * **同一只**谓词:backend 的面上带**非空** `controlPlaneRoot` 才算归属在案。空串与缺席同判「不归属」:
71
- * core 对空串会 truthy-回退到本副本盘上派生控制面(engine 构造里的 `backendControl ? … : derive(…)`),
72
- * 对无状态多副本部署这正是 D1 要拒的那台机器(折叠账随 pod 一起死)。抽成单点导出是为了让三处
73
- * 「逐字同源」成为结构事实而不是手抄承诺(merge-rescan 746 C-1:main.ts 手抄版漏了空串臂)。
74
- */
75
- export declare function backendOwnsControlPlane(backend: unknown): boolean;
76
64
  /**
77
65
  * 一只店的 capture opt-out 记录店 —— 按**这只店的控制面**向记录源取(`StoreBackend.sessionCaptureRecords()` 的按平面取用;
78
66
  * 会话装配向同一只源问的也是它那只平面的控制面,core `prepare-memory` 的 `memoryCaptureRecordStore({ controlDir })`)。
@@ -99,23 +87,14 @@ export interface MemoryComplianceFaces {
99
87
  * 都得是集内成员,判在解析之后、店锁之内;违者整单拒 `config.memory_erasure_scope`,拒句不带数、不带 id、不带 scope(集外 id
100
88
  * 与从没存在过的 id 同句,不是存在性神谕)。本层不另设信封:一只只读得到 `{ scope }` 选择子字面量的信封判不了 `ids` /
101
89
  * `sessionId` 两腿、只能整拒,而且让「哪些 scope 能删」有两个答者。集随**入参**走(与 `requestId` / `select` 同一个对象),
102
- * 授权集也是定店的那一只读数之一(选择子不点名 scope 时,集里的层共住的那只店;见文件头「引擎建在哪只店上」)。
90
+ * 授权集也是部署对象定店的那一只读数之一(选择子不点名 scope 时,集里的层共住的那只店;两只店 ⇒ 引擎拒 `config.memory_erasure_scope`)。
103
91
  *
104
92
  * 今天谁传集:operator 面原样递交调用方的体(调用方自己写的 `expectedScopes` = 它自己收窄自己);路由不替 operator 铸集 ——
105
93
  * 本仓没有任何授权源能对一个 operator 说「你只能动这些 scope」(`routes/memory-policy.ts` 的 `gateMemoryScope`:operator 支在查
106
94
  * 目录之前就 allow;`org-memory-admission.ts`:v1 不中央收窄 operator 声明的 scope)。拿 org 目录的 grant 集去凑一个集就是在本层
107
- * 发明第二套授权语义,与 `gateMemoryScope` 对同一个身份给出相反答案。会话自助面的选择子由路径铸,不带集。
95
+ * 发明第二套授权语义,与 `gateMemoryScope` 对同一个身份给出相反答案。会话自助面的选择子由路径铸(`{ sessionId }`),不带集 ⇒ 每只店各擦这只会话的那一份。
108
96
  */
109
- erase: (input: unknown, at?: MemoryLayerSeat) => Promise<MemoryErasureAttestation>;
110
- }
111
- /**
112
- * 本服务的「这次抹除不在本版受理的那只店上」拒(409 `memory.erasure_store_unjudged`):请求本身合法,是本部署此刻判不了同一个 `requestId`
113
- * 跨店的幂等(见文件头「抹除只在部署的店上执行」)。什么都没删、什么都没记。句子不带层键、路径或任何值(两受众同一句;会话所有者受众另有固定句)。
114
- * 🚧 引擎的部署级抹除请求身份到货后,本类连同抛它的两处删除。
115
- */
116
- export declare class MemoryErasureStoreUnjudged extends Error {
117
- readonly code: "memory.erasure_store_unjudged";
118
- constructor();
97
+ erase: (input: unknown) => Promise<MemoryErasureAttestation>;
119
98
  }
120
99
  /**
121
100
  * **选择子替身**的拦截谓词(codex 交叉复审 [critical],亲验复现后修 —— 复现器与结论逐条在
@@ -152,8 +131,8 @@ export declare function erasureInputSmugglesPrototypeKey(input: unknown): boolea
152
131
  /**
153
132
  * 在**记忆作用域店**上建合规两面。命名照 CLAUDE.md 工厂律:返回的是带行为的活对象 ⇒ `create*`。
154
133
  *
155
- * 店:出处按层座定;抹除按选择子的 `scope` / `expectedScopes` 定(会话自助面由路径铸选择子,用层座)—— 见文件头。
156
- * `memoryDir` = 那只店的**挂载平面**(`memoryMountRootOf(store, root)` 单铸点:店钉了 `directoryRoot`
134
+ * 店:出处按层座定;抹除交部署对象(整个部署一只判官,店由它按选择子 / 授权集定)—— 见文件头。
135
+ * 出处引擎的 `memoryDir` = 那只店的**挂载平面**(`memoryMountRootOf(store, root)` 单铸点:店钉了 `directoryRoot`
157
136
  * 就是它 —— file 腿 = `<配置根>/memory`,个人店 = 个人挂载;两只 SQL 孪生不钉 ⇒ 回到配置根,读数逐字节不变)。
158
137
  *
159
138
  * 🔴 **不是 `memoryEngine.root`**(2026 提货批订正,亲读 core 推翻旧注):旧注写着「这两条路径不读它」,
@@ -165,7 +144,8 @@ export declare function erasureInputSmugglesPrototypeKey(input: unknown): boolea
165
144
  */
166
145
  export declare function createMemoryComplianceFaces(stores: MemoryScopeStores,
167
146
  /**
168
- * 引擎的 **advisory incident 座**(core `MemoryEngineOptions.onIncident`)。接它不是锦上添花:
147
+ * 出处引擎的 **advisory incident 座**(core `MemoryEngineOptions.onIncident`)。抹除腿不走这只座:抹除交部署对象,它的座是记忆作用域店起服时接的
148
+ * 引擎事故汇点(`memory_engine_incident`,带码位与计数)—— 下面这段说的那条码今天从那里出来,理由同样成立。接它不是锦上添花:
169
149
  * 抹除腿上有一条**只走这个座**的码 —— `memory.erasure_index_residue`(engine.js)。它说的是
170
150
  * 「这次抹除的**索引残留披露**没能写进收执」:于是 operator 归档的那份凭据里少了一句「MEMORY.md
171
151
  * 里可能还留着被删条目的名字」,而收执**看上去是干净的**。座不接 ⇒ 这句话在本部署上无声消失,正是
@@ -180,7 +160,6 @@ opts?: {
180
160
  onIncident?: (err: Error & {
181
161
  code?: string;
182
162
  }) => void;
183
- captureRecords?: SessionCaptureRecordSource;
184
163
  }): MemoryComplianceFaces | undefined;
185
164
  /** 件② 三口 HTTP 面消费的窄能力面(`ServiceDeps.memoryOriginFace` 的实参来源)。 */
186
165
  export interface MemoryOriginFaces {
@@ -257,55 +236,40 @@ opts?: {
257
236
  onIncident?: (err: Error & {
258
237
  code?: string;
259
238
  }) => void;
260
- captureRecords?: SessionCaptureRecordSource;
261
239
  }): MemoryOriginFaces | undefined;
262
240
  /** [ref] seam① 的窄能力面(`ServiceDeps.sessionMemoryStatus` 的实参来源)。 */
263
241
  export interface SessionMemoryStatusFace {
264
242
  /**
265
- * 这次状态请求读的店:层座点名 ⇒ 那一层住的那一只;不带 ⇒ 本部署的每一只店(部署的店在前,至多两只;单店部署恰一只)——
266
- * 路由逐店读,再按 {@link foldPlaneStatuses} 折成一份(会话 id 不点名层,一只会话可以跨两只店,见文件头)。每次请求都现定 ——
267
- * 登记簿热换当场生效,路由的短窗缓存只缓存逐店的扫描,不缓存定店。唯一的拒:点名的层 / 本部署点名的层引擎读不出 ⇒ 同步抛 `request.memory_layer`。
243
+ * 这次状态请求读的那一份(每次请求现定):不带层座 ⇒ 部署对象的答案(引擎在本部署每一只店上折成一份 —— 店集是盘上的,折叠律只在引擎里);
244
+ * 带层座 ⇒ 那一层住的那只店上的引擎答案。`key` = 这一份在路由短窗缓存里的格(部署那一份一格;每只店一格,落同一只店的层座别名同一格)。
245
+ * 唯一的拒:层座读不出 ⇒ 同步抛 `request.memory_layer`。
268
246
  */
269
- storesAt: (at?: MemoryLayerSeat) => readonly SessionMemoryStatusStore[];
247
+ readingAt: (at?: MemoryLayerSeat) => SessionMemoryStatusReading;
270
248
  }
271
- /** 一只店上的会话记忆状态读。 */
272
- export interface SessionMemoryStatusStore {
273
- /** 这只店的控制面根(引擎自己的读数)—— 状态读扫的就是它;路由的短窗缓存按(会话, 它)分:落同一只店的层键别名是同一格。 */
274
- readonly controlPlane: string;
275
- status: (sessionId: string) => Promise<SessionMemoryStatus>;
249
+ /** 一份会话记忆状态的读法(见 {@link SessionMemoryStatusFace.readingAt})。 */
250
+ export interface SessionMemoryStatusReading {
251
+ readonly key: string;
252
+ /** 引擎的答案,原样(引擎不抛:读不出的源 = 缺席的键)。路由只投 wire 的五键。 */
253
+ status: (sessionId: string) => Promise<SessionMemoryView>;
276
254
  }
277
- /** 状态面上 wire 的五键(引擎答案里其余的键不上 wire,也就不折)。 */
278
- export type FoldedSessionMemoryStatus = Pick<SessionMemoryStatus, "captureOptedOut" | "committedCount" | "foldedCount" | "optOutSource" | "lastCaptureAt">;
279
- /**
280
- * 逐店的会话记忆状态 → 一份(**折叠律在代码里只写这一处**;契约 §9 开头同句)。每只店的答案都来自引擎,本函数只按键合,不补任何替身值:
281
- * · `committedCount` / `foldedCount`:各店相加;任一店缺席(那只店的账读不出)⇒ 缺席。
282
- * · `lastCaptureAt`:各店取最大;任一店的 `committedCount` 缺席(同一次账读失败)⇒ 缺席;都没有贡献 ⇒ 缺席(与引擎单店同义)。
283
- * · `captureOptedOut` / `optOutSource`:任一店有记录 ⇒ `true`,带那只店的 `optOutSource`(引擎恒是 `"record"`;一只店上的单向记录就是这只会话的记录);否则全部店答 `false` ⇒ `false`;
284
- * 否则(有店故障)⇒ `captureOptedOut` 缺席,有店说 `"fault"` 就带 `optOutSource: "fault"`。
285
- * 一只店 ⇒ 逐键与那只店的答案同(单店部署的应答字节不变)。🚧 引擎的部署级会话记忆状态到货后,本函数删除、路由直接投那一份。
286
- */
287
- export declare function foldPlaneStatuses(statuses: readonly SessionMemoryStatus[]): FoldedSessionMemoryStatus;
255
+ /** 状态面上 wire 的五键所在的那一份:部署对象答案去掉逐店明细 `planes`(逐店明细不上 wire,见 `core-keyset-guard.ts`)。 */
256
+ export type SessionMemoryView = Omit<DeploymentSessionMemoryStatus, "planes">;
288
257
  /**
289
258
  * [ref] seam①([ref] §S-7,core 7.0.2 [ref] 件1)—— `GET /v1/sessions/:id/memory-status` 的引擎面。
290
259
  * 命名照 CLAUDE.md 工厂律:返回带行为的活对象 ⇒ `create*`。
291
260
  *
292
- * 挂载判据与合规/清标两族**同一条 F-9 裁**(`backendOwnsControlPlane`,理由见文件头):
261
+ * 挂载判据与合规/清标两族**同一条 F-9 裁**(`backendOwnsControlPlane`,理由见文件头;部署对象读同一只谓词):
293
262
  * `committedCount` / `foldedCount` / `lastCaptureAt` 读的是引擎控制面的 lineage 台账 ——
294
263
  * 控制面归属缺席的部署上(两只 SQL 记忆孪生),core 会把控制面落到**副本本地盘**,一个「可读的空目录」
295
264
  * 让 core 面答出 `committedCount: 0`(readLineageRecord 对空目录**不抛**,亲读 engine.js)——
296
265
  * 那是**说谎的 0**,比缺席更坏(S-7 的诚实键律:可读零必须是真零)。⇒ 归属缺席 ⇒ 工厂返 undefined,
297
266
  * HTTP 面诚实 501,与 erase/origin 同码同分支。
298
267
  *
299
- * `captureRecords` = [ref]② 的按平面取用源(main.ts 取一次,与 Runner/其余引擎同源 —— 全站同批注入律,
300
- * 机器钉 capture-optout-lane ②;引擎按它那只店的控制面取,{@link captureRecordStoreOf}):`captureOptedOut` / `optOutSource`
301
- * 两键经它读,多副本部署上答的才是跨副本的真记录。[ref] 起 local 车道在引擎接线时也供(core 文件三腿);缺席 ⇒ 记忆面暗。
268
+ * capture opt-out 记录源 = 记忆作用域店的那一格(`stores.captureRecords`,[ref]② 的按平面取用源):带层座那一读的引擎按它那只店的控制面取
269
+ * ({@link captureRecordStoreOf}),部署对象在构造时拿的是同一格 —— 两读一个源。`captureOptedOut` / `optOutSource` 两键经它读,多副本部署上答的才是跨副本的真记录。
302
270
  *
303
- * 引擎**不抛**(core 契约:sessionMemoryStatus never throws —— 每个事实源各自 catch 折缺席键);面唯一的拒是定店那一步的
304
- * `request.memory_layer`(点名的层 / 本部署点名的层读不出)。不点名层 ⇒ 读本部署的每一只店、路由按 {@link foldPlaneStatuses} 折
305
- * (只读一只店而它不装这只会话,答出来的就是一个说谎的 0)。
306
- * 不接 onIncident:这条只读路径上今天零 sink 站点,而且缺席键本身就是它的披露形。
271
+ * 引擎**不抛**(core 契约:sessionMemoryStatus / 部署对象的 sessionMemoryStatus never throw —— 每个事实源各自 catch 折缺席键);
272
+ * 面唯一的拒是带层座那一读定店时的 `request.memory_layer`。不接 onIncident:这条只读路径上今天零 sink 站点,而且缺席键本身就是它的披露形。
307
273
  */
308
- export declare function createSessionMemoryStatusFace(stores: MemoryScopeStores, opts?: {
309
- captureRecords?: SessionCaptureRecordSource;
310
- }): SessionMemoryStatusFace | undefined;
274
+ export declare function createSessionMemoryStatusFace(stores: MemoryScopeStores): SessionMemoryStatusFace | undefined;
311
275
  //# sourceMappingURL=memory-operator-faces.d.ts.map
@@ -1,13 +1,6 @@
1
1
  import { MemoryEngine, } from "@sema-agent/core";
2
2
  import { memoryMountRootOf } from "./memory-scope.js";
3
- import { memoryStoreForRequest, memoryStoresOfDeployment } from "./memory-scope-stores.js";
4
- export function backendOwnsControlPlane(backend) {
5
- return controlPlaneRootOf(backend) !== undefined;
6
- }
7
- function controlPlaneRootOf(backend) {
8
- const root = backend?.controlPlaneRoot;
9
- return typeof root === "string" && root !== "" ? root : undefined;
10
- }
3
+ import { backendOwnsControlPlane, controlPlaneRootOf, memoryStoreForRequest } from "./memory-scope-stores.js";
11
4
  export function captureRecordStoreOf(source, store) {
12
5
  if (source === undefined)
13
6
  return undefined;
@@ -28,33 +21,6 @@ function createEngineSeat(build) {
28
21
  return engine;
29
22
  };
30
23
  }
31
- function erasureLayersOf(input) {
32
- if (typeof input !== "object" || input === null)
33
- return [];
34
- const { select, expectedScopes } = input;
35
- const scope = typeof select === "object" && select !== null ? select.scope : undefined;
36
- if (typeof scope === "string" && scope.length > 0)
37
- return [scope];
38
- if (Array.isArray(expectedScopes) && expectedScopes.length > 0 && expectedScopes.every((s) => typeof s === "string" && s.length > 0))
39
- return expectedScopes;
40
- return [];
41
- }
42
- function erasureSessionOf(input) {
43
- if (typeof input !== "object" || input === null)
44
- return undefined;
45
- const { select } = input;
46
- const sessionId = typeof select === "object" && select !== null ? select.sessionId : undefined;
47
- return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : undefined;
48
- }
49
- export class MemoryErasureStoreUnjudged extends Error {
50
- code = "memory.erasure_store_unjudged";
51
- constructor() {
52
- super("memory erasure refused: this erasure reaches a memory store other than the deployment's store (this deployment keeps the typed personal memory layers in a second store), " +
53
- "and this build judges an erasure requestId on the deployment's store only, so it cannot tell whether the same requestId already erased under another selector there — " +
54
- "erasures that reach the second store are not taken in this build, and nothing was erased; the way out is the engine's deployment-wide erasure request identity, due with the next engine update");
55
- this.name = "MemoryErasureStoreUnjudged";
56
- }
57
- }
58
24
  export function erasureInputSmugglesPrototypeKey(input) {
59
25
  const stack = [input];
60
26
  while (stack.length > 0) {
@@ -76,10 +42,11 @@ export function erasureInputSmugglesPrototypeKey(input) {
76
42
  return false;
77
43
  }
78
44
  export function createMemoryComplianceFaces(stores, opts) {
79
- if (!backendOwnsControlPlane(stores.backend))
45
+ const deployment = stores.deployment();
46
+ if (deployment === undefined)
80
47
  return undefined;
81
48
  const engineOf = createEngineSeat((store) => {
82
- const records = captureRecordStoreOf(opts?.captureRecords, store);
49
+ const records = captureRecordStoreOf(stores.captureRecords, store);
83
50
  return new MemoryEngine({
84
51
  backend: store,
85
52
  memoryDir: memoryMountRootOf(store, stores.root),
@@ -87,34 +54,15 @@ export function createMemoryComplianceFaces(stores, opts) {
87
54
  ...(records !== undefined ? { captureRecordStore: records } : {}),
88
55
  });
89
56
  });
90
- const erasureStoreOf = async (input, at) => {
91
- const seat = at !== undefined ? "`scope`" : "`select.scope`, or `expectedScopes` next to `select.ids` / `select.sessionId`";
92
- const layers = at !== undefined ? seatLayers(at) : erasureLayersOf(input);
93
- const sessionId = layers.length === 0 ? erasureSessionOf(input) : undefined;
94
- if (sessionId === undefined) {
95
- const store = memoryStoreForRequest(stores, layers, seat);
96
- if (store !== stores.backend)
97
- throw new MemoryErasureStoreUnjudged();
98
- return store;
99
- }
100
- for (const other of memoryStoresOfDeployment(stores, seat)) {
101
- if (other === stores.backend)
102
- continue;
103
- if ((await engineOf(other).sessionMemoryStatus(sessionId)).committedCount !== 0)
104
- throw new MemoryErasureStoreUnjudged();
105
- }
106
- return stores.backend;
107
- };
108
57
  return {
109
58
  provenanceOf: async (entryId, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).provenanceOf(entryId),
110
- erase: async (input, at) => {
59
+ erase: async (input) => {
111
60
  if (erasureInputSmugglesPrototypeKey(input)) {
112
61
  const e = new Error("memory erasure refused: the request carries a key that rewrites an object's prototype — such a key is not a selector, and core's selector dispatch would read it in preference to the declared one");
113
62
  e.code = "memory.erasure_selector_unsafe";
114
63
  throw e;
115
64
  }
116
- const store = await erasureStoreOf(input, at);
117
- return engineOf(store).eraseMemoryEntries(input);
65
+ return deployment.eraseMemoryEntries(input);
118
66
  },
119
67
  };
120
68
  }
@@ -122,7 +70,7 @@ export function createMemoryOriginFaces(stores, opts) {
122
70
  if (!backendOwnsControlPlane(stores.backend))
123
71
  return undefined;
124
72
  const engineOf = createEngineSeat((store) => {
125
- const records = captureRecordStoreOf(opts?.captureRecords, store);
73
+ const records = captureRecordStoreOf(stores.captureRecords, store);
126
74
  return new MemoryEngine({
127
75
  backend: store,
128
76
  memoryDir: memoryMountRootOf(store, stores.root),
@@ -136,44 +84,25 @@ export function createMemoryOriginFaces(stores, opts) {
136
84
  clear: async (entryId, input, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).clearEntryOrigin(entryId, input),
137
85
  };
138
86
  }
139
- export function foldPlaneStatuses(statuses) {
140
- const sum = (key) => statuses.every((s) => s[key] !== undefined) ? statuses.reduce((n, s) => n + s[key], 0) : undefined;
141
- const committedCount = sum("committedCount");
142
- const foldedCount = sum("foldedCount");
143
- const captures = statuses.flatMap((s) => (s.lastCaptureAt !== undefined ? [s.lastCaptureAt] : []));
144
- const lastCaptureAt = committedCount !== undefined && captures.length > 0 ? Math.max(...captures) : undefined;
145
- const recorded = statuses.find((s) => s.captureOptedOut === true);
146
- const capture = recorded !== undefined
147
- ? { captureOptedOut: true, ...(recorded.optOutSource !== undefined ? { optOutSource: recorded.optOutSource } : {}) }
148
- : statuses.every((s) => s.captureOptedOut === false)
149
- ? { captureOptedOut: false }
150
- : statuses.some((s) => s.optOutSource === "fault")
151
- ? { optOutSource: "fault" }
152
- : {};
153
- return {
154
- ...capture,
155
- ...(committedCount !== undefined ? { committedCount } : {}),
156
- ...(foldedCount !== undefined ? { foldedCount } : {}),
157
- ...(lastCaptureAt !== undefined ? { lastCaptureAt } : {}),
158
- };
159
- }
160
- export function createSessionMemoryStatusFace(stores, opts) {
161
- if (!backendOwnsControlPlane(stores.backend))
87
+ export function createSessionMemoryStatusFace(stores) {
88
+ const deployment = stores.deployment();
89
+ if (deployment === undefined)
162
90
  return undefined;
163
91
  const engineOf = createEngineSeat((store) => {
164
- const records = captureRecordStoreOf(opts?.captureRecords, store);
92
+ const records = captureRecordStoreOf(stores.captureRecords, store);
165
93
  return new MemoryEngine({
166
94
  backend: store,
167
95
  memoryDir: memoryMountRootOf(store, stores.root),
168
96
  ...(records !== undefined ? { captureRecordStore: records } : {}),
169
97
  });
170
98
  });
171
- const storeOf = (store) => {
172
- const engine = engineOf(store);
173
- return { controlPlane: engine.controlPlaneRoot, status: (sessionId) => engine.sessionMemoryStatus(sessionId) };
174
- };
175
99
  return {
176
- storesAt: (at) => (at !== undefined ? [storeOf(memoryStoreForRequest(stores, seatLayers(at)))] : memoryStoresOfDeployment(stores).map(storeOf)),
100
+ readingAt: (at) => {
101
+ if (at === undefined)
102
+ return { key: "deployment", status: (sessionId) => deployment.sessionMemoryStatus(sessionId) };
103
+ const engine = engineOf(memoryStoreForRequest(stores, seatLayers(at)));
104
+ return { key: engine.controlPlaneRoot, status: (sessionId) => engine.sessionMemoryStatus(sessionId) };
105
+ },
177
106
  };
178
107
  }
179
108
  //# sourceMappingURL=memory-operator-faces.js.map
@@ -1,56 +1,59 @@
1
1
  /**
2
- * 记忆作用域店 —— 「一层住在哪只店」在本宿主的**唯一读者**。
2
+ * 记忆作用域店 —— 本部署的记忆在本宿主的**唯一持有者**:「一层住在哪只店」与「本部署有哪些店」都只在这里答。
3
3
  *
4
4
  * ## 规则(一条)
5
- * 一层(scope)的条目住哪只店,只有引擎的 `resolveMemoryScopeStore` 答;本服务在会话之外读写某一层的每一条腿(同步执行器、项目层折叠、
6
- * 中心侧导出 / 同步、bundle 导出导入、合规抹除 / 出处、外源标记、会话记忆状态、整理)一律问**本对象**,不再自持「部署的店」当某一层的答案。
7
- * 本对象就是起服装配出来的那只记忆引擎对象(`boot/stores.ts` 的 `memoryEngine`、`run-local.ts` 的同名量):它的 `backend` / `root`
8
- * 正是交给 Runner 的两件事实(`RunnerDeps.memoryBackend` / `RunnerDeps.memoryEngineDir`),会话装配解析一层的店读的也是这两件 ——
9
- * 所以宿主腿与会话对同一层答同一只店。每进程一只,所有腿共用(引擎的话:每层解析一次、留着用)。
5
+ * 一层(scope)的平面只有引擎的纯分类函数答(`scopePlanesOf`,契约 = 本服务铸 spec 时盖在会话上的同一只判据 {@link memoryScopeContractOf});
6
+ * 一层的店 = 它那只平面的店(项目平面 = 部署的店;目录钉住的部署上个人平面是个人挂载上的另一只店,引擎的 `resolveMemoryScopeStore` 开它)。
7
+ * **本部署有哪些店**只有引擎的部署对象答(`createMemoryDeployment(…).stores()`):项目店,再加上个人挂载**在盘上**的那只个人店 ——
8
+ * 盘的集合,不是配置点名的层推出来的集合(配置只决定会话往哪写;换了 `MEMORY_SCOPE` 之后个人挂载上留下的那只店照样在集合里)。
9
+ * 本服务在会话之外读写某一层的每一条腿(同步执行器、项目层折叠、中心侧导出 / 同步、bundle 导出导入、合规抹除 / 出处、外源标记、会话记忆状态、整理)
10
+ * 一律问**本对象**。本对象就是起服装配出来的那只记忆引擎对象(`boot/stores.ts` 的 `memoryEngine`、`run-local.ts` 的同名量):它的 `backend` / `root`
11
+ * 正是交给 Runner 的两件事实(`RunnerDeps.memoryBackend` / `RunnerDeps.memoryEngineDir`)—— 宿主腿与会话对同一层答同一只店。每进程一只,所有腿共用。
10
12
  *
11
- * ## 喂给引擎的契约
12
- * `scopeContract` = 本服务铸 spec 时给会话盖的同一只判据 {@link memoryScopeContractOf}(按层问与按会话问答同一只店,理由见该函数注)。
13
- *
14
- * ## 先判平面,再建店;一只平面一只实例
15
- * 目录钉住的部署上,引擎对个人平面的答案是在个人挂载上**新开**的一只 File 店(契约原话:一只挂载;打开 = 建目录、收尾中断的事务、读台账)。
16
- * 层键是调用方给的串,所以本对象**先**问平面、**再**按平面取店:
17
- * · 平面 = 引擎同一只读法 `resolveMemoryScopeStore` 在一只**不钉目录**的探针店上的答案。引擎契约:不钉目录的店对个人平面原样答回
18
- * 入参店(「the personal plane shares a backend without a directory」)、项目平面恒答部署的店 ⇒ 这一问只得平面、零建店零读盘,
19
- * 层键读不出照样抛引擎的 `config.memory_scope_key`(同一只校验)。不在本层另写分类(另写就是第二个读者)。
20
- * · 店 = 每个平面第一次用到时问引擎一次(真店入参),留下这一只;同平面的后来层复用它 —— 每个本对象至多两只店(项目 / 个人),
21
- * 「两层同店」按实例判(下面的路由读它)。不按层键缓存:任意多把新层键不建店、不读盘、本对象不长。
22
- * 🚧 平面的读法待引擎导出纯分类函数(`classifyScopePlanes` / `scopePlanesOf`)后改读它、删探针店;钉在 `test/memory-layer-seat-http.test.ts`。
13
+ * ## 部署对象({@link MemoryScopeStores.deployment})
14
+ * 会话 id 的两只动词(会话记忆状态、按会话 / 按请求身份的抹除)答的是**整个部署**:一个抹除 `requestId` 在整个部署里只名一次请求
15
+ * (引擎在执行任何一只店之前读遍每只店的锚,同一个 id 换了选择子或落到别的店 ⇒ `memory.erasure_selector_mismatch`),会话记忆状态由引擎在每只店上
16
+ * 折成一份(折叠律只在引擎里)。所以这两只动词不再由本服务定店:直接交部署对象。部署对象只在部署的店自带控制面归属(`controlPlaneRoot`)时存在
17
+ * (引擎拒没有控制面的店;两只 SQL 记忆孪生没有 ⇒ 缺席,读它的操作面在那些部署上本就不挂),第一次用到时建、留着用(它自己按需开个人店并留着)。
23
18
  *
24
19
  * ## 请求的店({@link memoryStoreForRequest})
25
- * 动词按它的请求**点名的层**取店;点名的几层不在同一只店 ⇒ 响亮拒(一次请求只落一只店)。请求不点名层的动词(条目 id、店级账本)
26
- * 答在**本部署点名的层与部署的店共处的那一只店**上(`memoryLayersNamedBy`:全局层 / 同步层 / 登记簿种子 / 整理层);它们分住两只店时
27
- * 不猜,响亮拒并指路「在请求里点名层」。单店部署(缺省 `local`、SQL 记忆后端、配置不点名个人平面键)上无层请求的答法与上一版逐字同。
28
- *
29
- * ## 本部署的店({@link memoryStoresOfDeployment})
30
- * 部署的店 + 本部署点名的每一层住的店,去重、部署的店在前 —— 至多两只。会话 id 的动词读它:一只会话的记忆事实住在它各条腿写进的那只店
31
- * (写家所在的平面),而单用户部署上会话的写家只会是项目层(部署的店)或全局层(点名的层),所以这张表就是「这只会话可能住的店」的全集。
20
+ * 点名层的动词按点名的层取店;点名的几层不在同一只店 ⇒ 响亮拒(一次请求只落一只店)。不点名层的条目 id / 店级账本动词答在**本部署唯一的那只店**上;
21
+ * 部署有两只店(盘上有个人店)⇒ 不猜,响亮拒并指路「在请求里点名层」。没有部署对象的部署(SQL 记忆孪生,不钉目录 ⇒ 两个平面同一只店)恒是一只店。
32
22
  */
33
- import { type MemoryBackend } from "@sema-agent/core";
23
+ import { type MemoryBackend, type MemoryDeployment } from "@sema-agent/core";
24
+ import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
34
25
  export interface MemoryScopeStores {
35
- /** 部署的记忆后端 —— 交给 Runner 的那一只(`RunnerDeps.memoryBackend`)。它是「层在哪只店」那只读法的输入、项目平面的店本身,
36
- * 不是任何一层的答案(层的答案只出自 {@link MemoryScopeStores.storeOf})。 */
26
+ /** 部署的记忆后端 —— 交给 Runner 的那一只(`RunnerDeps.memoryBackend`):项目平面的店本身,也是部署对象的输入。 */
37
27
  readonly backend: MemoryBackend;
38
- /** 引擎根 —— 交给 Runner 的那一个值(`RunnerDeps.memoryEngineDir`):读法的另一件输入(个人挂载在它下面),也是同步游标的根。 */
28
+ /** 引擎根 —— 交给 Runner 的那一个值(`RunnerDeps.memoryEngineDir`):个人挂载在它下面,也是同步游标的根。 */
39
29
  readonly root: string;
40
- /** 层 `layer` 住的那只店(引擎的唯一读法;先判平面、每个平面一只实例)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
30
+ /** capture opt-out 记录源(起服取一次的那一只;缺席 ⇒ 引擎各自的文件缺省)。本部署每一只记忆引擎 —— 部署对象、各操作面按店构造的引擎 —— 都只读这一格。 */
31
+ readonly captureRecords: SessionCaptureRecordSource | undefined;
32
+ /** 层 `layer` 的平面(引擎的规范化 + 纯分类函数,与引擎的店解析同一读法;零建店、零读盘)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
33
+ planeOf(layer: string): "project" | "personal";
34
+ /** 层 `layer` 住的那只店(先判平面、每个平面一只实例)。读不出的层键 ⇒ 同 {@link MemoryScopeStores.planeOf}。 */
41
35
  storeOf(layer: string): MemoryBackend;
42
- /** 本部署配置点名的层(每次现读 —— 登记簿热换)。 */
43
- namedLayers(): readonly string[];
36
+ /** 本部署的记忆(引擎的部署对象,见文件头)。部署的店不带控制面归属 ⇒ `undefined`。 */
37
+ deployment(): MemoryDeployment | undefined;
44
38
  }
39
+ /**
40
+ * 控制面归属判据 —— 记忆操作面(合规 / 外源标记 / 会话记忆状态 / consolidation 阀门的 D1 拒启门)与部署对象共用的**同一只**谓词:
41
+ * backend 的面上带**非空** `controlPlaneRoot` 才算归属在案。空串与缺席同判「不归属」:core 对空串会 truthy-回退到本副本盘上派生控制面
42
+ * (engine 构造里的 `backendControl ? … : derive(…)`),对无状态多副本部署这正是 D1 要拒的那台机器(折叠账随 pod 一起死)。
43
+ */
44
+ export declare function backendOwnsControlPlane(backend: unknown): boolean;
45
+ /** 店自己发布的控制面根(`controlPlaneRoot`,非空串);不带 ⇒ `undefined`。读这一位只走这里。 */
46
+ export declare function controlPlaneRootOf(backend: unknown): string | undefined;
45
47
  /** 命名照工厂律:返回带行为的活对象 ⇒ `create*`。 */
46
48
  export declare function createMemoryScopeStores(input: {
47
49
  backend: MemoryBackend;
48
50
  root: string;
49
- namedLayers: () => readonly string[];
50
- /** 本对象为一层开出的店(个人平面的 File 店)的构造期 incident 座(与部署的店那只同一只汇点;缺席合法)。 */
51
+ /** 本对象(与部署对象)为一层开出的店与引擎的 incident 座(与部署的店那只同一只汇点;缺席合法)。 */
51
52
  onIncident?: (err: Error & {
52
53
  code?: string;
53
54
  }) => void;
55
+ /** capture opt-out 记录源(`StoreBackend.sessionCaptureRecords()`,起服取一次的那一只):部署对象按每只店的控制面问它。缺席 ⇒ 引擎各自的文件缺省。 */
56
+ captureRecords?: SessionCaptureRecordSource;
54
57
  }): MemoryScopeStores;
55
58
  /** 本服务的「这次请求落不到一只记忆店」拒(400 `request.memory_layer`):点名的层读不出 / 点名的几层分住两只店 / 两店部署上没点名层。 */
56
59
  export declare class MemoryLayerRefusal extends Error {
@@ -60,14 +63,9 @@ export declare class MemoryLayerRefusal extends Error {
60
63
  /**
61
64
  * 一次请求的记忆店。`layers` = 请求点名的层(空 = 没点名):
62
65
  * · 点名 ⇒ 它们共住的那一只店;分住两只 ⇒ 拒(一次请求只落一只店,按店拆成几次请求)。
63
- * · 没点名 ⇒ 本部署点名的层与部署的店共处的那一只(= 部署的店);它们分住两只 ⇒ 拒,指路在请求里点名层。
66
+ * · 没点名 ⇒ 本部署唯一的那只店(= 部署的店);部署有两只店(盘上有个人店,{@link MemoryScopeStores.deployment})⇒ 拒,指路在请求里点名层。
64
67
  * `seat` = 这个动词点名层的那一处(拒句里指路用,如 `` `scope` ``;缺省 = 层座 `scope`)。
65
68
  * 拒一律 {@link MemoryLayerRefusal}(读不出的层键同码,引擎原句随句)。
66
69
  */
67
70
  export declare function memoryStoreForRequest(stores: MemoryScopeStores, layers: readonly string[], seat?: string): MemoryBackend;
68
- /**
69
- * 本部署的店:部署的店在前,其后是本部署点名的层住的其余店(去重)—— 单店部署恰一只(部署的店本身)。点名的层读不出 ⇒ {@link MemoryLayerRefusal}(同无层那一臂)。
70
- * 每次现算(登记簿热换当场生效);只问平面与每平面一只的店,不建多余的店。
71
- */
72
- export declare function memoryStoresOfDeployment(stores: MemoryScopeStores, seat?: string): readonly MemoryBackend[];
73
71
  //# sourceMappingURL=memory-scope-stores.d.ts.map
@@ -1,30 +1,63 @@
1
- import { resolveMemoryScopeStore } from "@sema-agent/core";
1
+ import { createMemoryDeployment, normalizeMemorySpec, resolveMemoryScopeStore, scopePlanesOf } from "@sema-agent/core";
2
2
  import { memoryScopeContractOf } from "./memory-scope.js";
3
+ export function backendOwnsControlPlane(backend) {
4
+ return controlPlaneRootOf(backend) !== undefined;
5
+ }
6
+ export function controlPlaneRootOf(backend) {
7
+ const root = backend?.controlPlaneRoot;
8
+ return typeof root === "string" && root !== "" ? root : undefined;
9
+ }
3
10
  export function createMemoryScopeStores(input) {
4
- const byPlane = new Map();
5
- const resolve = (layer, backend) => resolveMemoryScopeStore({
11
+ let personal;
12
+ const resolve = (layer) => resolveMemoryScopeStore({
6
13
  scope: layer,
7
14
  scopeContract: memoryScopeContractOf([layer]),
8
- backend,
15
+ backend: input.backend,
9
16
  memoryEngineDir: input.root,
10
17
  ...(input.onIncident !== undefined ? { onIncident: input.onIncident } : {}),
11
18
  });
19
+ const planeOf = (layer) => {
20
+ const contract = memoryScopeContractOf([layer]);
21
+ let spec;
22
+ try {
23
+ spec = normalizeMemorySpec({ scopes: [layer], writeScope: layer, ...(contract !== undefined ? { scopeContract: contract } : {}) });
24
+ }
25
+ catch {
26
+ spec = undefined;
27
+ }
28
+ if (spec === undefined || spec.writeScope === null)
29
+ return resolve(layer).plane;
30
+ return scopePlanesOf(spec.scopes, spec.writeScope, spec.scopeContract)?.writePlane ?? "project";
31
+ };
32
+ let deployment;
12
33
  return {
13
34
  backend: input.backend,
14
35
  root: input.root,
15
- namedLayers: input.namedLayers,
36
+ captureRecords: input.captureRecords,
37
+ planeOf,
16
38
  storeOf(layer) {
17
- const { plane } = resolve(layer, PLANE_PROBE);
18
- const known = byPlane.get(plane);
19
- if (known !== undefined)
20
- return known;
21
- const store = resolve(layer, input.backend).backend;
22
- byPlane.set(plane, store);
39
+ const plane = planeOf(layer);
40
+ if (plane === "personal" && personal !== undefined)
41
+ return personal;
42
+ const store = resolve(layer).backend;
43
+ if (plane === "personal")
44
+ personal = store;
23
45
  return store;
24
46
  },
47
+ deployment() {
48
+ if (deployment !== undefined || !backendOwnsControlPlane(input.backend))
49
+ return deployment;
50
+ deployment = createMemoryDeployment({
51
+ backend: input.backend,
52
+ memoryEngineDir: input.root,
53
+ scopeContract: "v2",
54
+ ...(input.onIncident !== undefined ? { onIncident: input.onIncident } : {}),
55
+ ...(input.captureRecords !== undefined ? { memoryCaptureRecordStore: input.captureRecords } : {}),
56
+ });
57
+ return deployment;
58
+ },
25
59
  };
26
60
  }
27
- const PLANE_PROBE = Object.freeze({});
28
61
  export class MemoryLayerRefusal extends Error {
29
62
  code = "request.memory_layer";
30
63
  constructor(message, cause) {
@@ -33,7 +66,7 @@ export class MemoryLayerRefusal extends Error {
33
66
  }
34
67
  }
35
68
  const quoted = (layers) => layers.map((l) => JSON.stringify(l)).join(", ");
36
- function storeOfNamed(stores, layer, whose, seat) {
69
+ function storeOfNamed(stores, layer) {
37
70
  try {
38
71
  return stores.storeOf(layer);
39
72
  }
@@ -41,16 +74,14 @@ function storeOfNamed(stores, layer, whose, seat) {
41
74
  if (err?.code !== "config.memory_scope_key")
42
75
  throw err;
43
76
  const why = err instanceof Error ? err.message : String(err);
44
- throw new MemoryLayerRefusal(whose === "request"
45
- ? `the memory layer ${JSON.stringify(layer)} cannot be read: ${why}`
46
- : `this deployment's configured memory layer ${JSON.stringify(layer)} cannot be read (${why}), so the store a request that names no layer belongs to cannot be told — name the layer in the request (${seat})`, err);
77
+ throw new MemoryLayerRefusal(`the memory layer ${JSON.stringify(layer)} cannot be read: ${why}`, err);
47
78
  }
48
79
  }
49
80
  export function memoryStoreForRequest(stores, layers, seat = "`scope`") {
50
81
  if (layers.length > 0) {
51
82
  const groups = new Map();
52
83
  for (const layer of layers) {
53
- const store = storeOfNamed(stores, layer, "request", seat);
84
+ const store = storeOfNamed(stores, layer);
54
85
  const group = groups.get(store);
55
86
  if (group === undefined)
56
87
  groups.set(store, [layer]);
@@ -62,25 +93,9 @@ export function memoryStoreForRequest(stores, layers, seat = "`scope`") {
62
93
  const split = [...groups.values()].map((g) => `[${quoted(g)}]`).join(" / ");
63
94
  throw new MemoryLayerRefusal(`the memory layers ${quoted(layers)} live in ${groups.size} different memory stores on this deployment and one request reaches one store — send one request per store: ${split}`);
64
95
  }
65
- const groups = deploymentStoreGroups(stores, seat);
66
- if (groups.size === 1)
96
+ const census = stores.deployment()?.stores() ?? [];
97
+ if (census.length <= 1)
67
98
  return stores.backend;
68
- const elsewhere = [...groups.entries()].filter(([store]) => store !== stores.backend).flatMap(([, g]) => g);
69
- throw new MemoryLayerRefusal(`this deployment keeps memory layers in ${groups.size} stores — the project layers${groups.get(stores.backend).length > 0 ? ` and ${quoted(groups.get(stores.backend))}` : ""} in the deployment's store, ${quoted(elsewhere)} in another — so a request that names no layer cannot be told which store it means; name the layer in the request (${seat})`);
70
- }
71
- export function memoryStoresOfDeployment(stores, seat = "`scope`") {
72
- return [...deploymentStoreGroups(stores, seat).keys()];
73
- }
74
- function deploymentStoreGroups(stores, seat) {
75
- const groups = new Map([[stores.backend, []]]);
76
- for (const layer of stores.namedLayers()) {
77
- const store = storeOfNamed(stores, layer, "deployment", seat);
78
- const group = groups.get(store);
79
- if (group === undefined)
80
- groups.set(store, [layer]);
81
- else
82
- group.push(layer);
83
- }
84
- return groups;
99
+ throw new MemoryLayerRefusal(`this deployment keeps memory in ${census.length} stores (the project store and the personal store under the memory engine root), so a request that names no layer cannot be told which store it means; name the layer in the request (${seat})`);
85
100
  }
86
101
  //# sourceMappingURL=memory-scope-stores.js.map
@@ -28,15 +28,6 @@ export declare function isV2ScopeKey(key: string): boolean;
28
28
  * 同步执行器无从同时对上两者),收口点在配置边界(拒或规范化这一形,后者会挪存量记忆的平面),不在本谓词;未闭环。
29
29
  */
30
30
  export declare function memoryScopeContractOf(scopes: readonly string[]): "v2" | undefined;
31
- /**
32
- * 本部署**自己点名**的记忆层 —— 配置里写着的每一层(去重、去空串、保序):单用户的全局层(`MEMORY_SCOPE`,{@link memoryScopeFor} 单用户臂的答案)、
33
- * 同步层(`MEMORY_SYNC_SCOPE`,缺省即全局层)、项目登记簿的种子层(`config.projects[*].defaultScopes`,{@link memorySpecForRequest} 盖进会话的读列表)、
34
- * 整理层(`MEMORY_CONSOLIDATION_SCOPES`)。项目层(`userrepo:…`)按任务根铸、不在配置里,也就不在这里 —— 它们住部署的店。
35
- *
36
- * 唯一读者:记忆作用域店的「不点名层的动词答在哪只店」(`memory-scope-stores.ts` 的 {@link memoryStoreForRequest} 无层那一臂)。
37
- * 登记簿随中心配置热换(`applyEffective` 在同一只 `config.projects` 对象上原地整表换内容),所以读者每次现调本函数,不在起服时冻一份。
38
- */
39
- export declare function memoryLayersNamedBy(config: Pick<ServiceConfig, "requirePrincipal" | "memoryScope" | "memorySync" | "projects" | "memoryConsolidationDriver">): string[];
40
31
  /** Resolve the memory scope for a request —— {@link memoryScopeFor} 的三形(按实现逐臂写;[ref] 合并前主会话点名:
41
32
  * 旧版这里写「多租户恒 `undefined` ⇒ 记忆暗」,与下面 DB 后端那一臂正好相反,test [ref] 就是被这句带偏的)。
42
33
  *