@sema-agent/server 7.137.0 → 7.139.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 +600 -142
  2. package/README.md +7 -3
  3. package/README.zh-CN.md +6 -3
  4. package/USAGE.md +132 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/wire.d.ts +3 -3
  8. package/dist/approval-card.d.ts +23 -16
  9. package/dist/approval-card.js +1 -0
  10. package/dist/audit.js +1 -0
  11. package/dist/background-agent-name.d.ts +5 -0
  12. package/dist/background-agent-name.js +5 -0
  13. package/dist/bench/s1/arms.d.ts +1 -1
  14. package/dist/bench/s1/arms.js +1 -3
  15. package/dist/bench/s1/run-firm.js +2 -2
  16. package/dist/boot/budget-tracing.d.ts +1 -12
  17. package/dist/boot/deployment-mods.d.ts +46 -16
  18. package/dist/boot/deployment-mods.js +82 -6
  19. package/dist/boot/device-lane.d.ts +8 -3
  20. package/dist/boot/device-lane.js +7 -2
  21. package/dist/boot/execution-env.d.ts +4 -2
  22. package/dist/boot/execution-env.js +16 -24
  23. package/dist/boot/execution-lane.d.ts +1 -1
  24. package/dist/boot/governance-seams.d.ts +12 -18
  25. package/dist/boot/governance-seams.js +10 -24
  26. package/dist/boot/leader.d.ts +3 -0
  27. package/dist/boot/leader.js +1 -0
  28. package/dist/boot/memory-consolidation.js +2 -2
  29. package/dist/boot/org-delivery.js +15 -2
  30. package/dist/boot/resolve-spec.d.ts +4 -1
  31. package/dist/boot/resolve-spec.js +29 -19
  32. package/dist/boot/retention-lane.d.ts +14 -8
  33. package/dist/boot/retention-lane.js +2 -8
  34. package/dist/boot/runner-deps.d.ts +10 -4
  35. package/dist/boot/runner-deps.js +2 -0
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-04-stores.d.ts +1 -12
  40. package/dist/boot/stage-05-execution-env.d.ts +3 -12
  41. package/dist/boot/stage-05-execution-env.js +8 -5
  42. package/dist/boot/stage-06-runners.d.ts +3 -12
  43. package/dist/boot/stage-06-runners.js +5 -3
  44. package/dist/boot/stage-07-capability-layer.d.ts +3 -12
  45. package/dist/boot/stage-07-capability-layer.js +2 -2
  46. package/dist/boot/stage-08-reapers.d.ts +3 -12
  47. package/dist/boot/stage-09-leader.d.ts +3 -12
  48. package/dist/boot/stage-09-leader.js +2 -3
  49. package/dist/boot/stage-10-http-server.d.ts +3 -12
  50. package/dist/boot/stage-10-http-server.js +5 -3
  51. package/dist/boot/stores.js +4 -4
  52. package/dist/boot/web-admin.d.ts +5 -2
  53. package/dist/boot/web-admin.js +5 -5
  54. package/dist/brain.js +5 -5
  55. package/dist/budget.d.ts +17 -15
  56. package/dist/budget.js +2 -2
  57. package/dist/capabilities/mcp-probe.d.ts +36 -11
  58. package/dist/capabilities/mcp-probe.js +44 -5
  59. package/dist/capabilities/scenarios.d.ts +1 -1
  60. package/dist/capability-facts.d.ts +21 -7
  61. package/dist/capability-facts.js +13 -3
  62. package/dist/checkpoint-identity.d.ts +13 -6
  63. package/dist/config-catalog.js +14 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +19 -24
  67. package/dist/config-provider.js +27 -12
  68. package/dist/config-types.d.ts +25 -12
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +52 -20
  71. package/dist/delegated-session-owner.d.ts +2 -2
  72. package/dist/deployment-shape.d.ts +7 -7
  73. package/dist/device-enrollment.d.ts +41 -2
  74. package/dist/device-enrollment.js +27 -12
  75. package/dist/device-store.d.ts +58 -85
  76. package/dist/device-store.js +19 -49
  77. package/dist/device-ws-hub.js +2 -1
  78. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  79. package/dist/exec-cut.d.ts +60 -0
  80. package/dist/exec-cut.js +36 -0
  81. package/dist/execution-lane-caps.d.ts +19 -0
  82. package/dist/execution-lane-caps.js +10 -0
  83. package/dist/execution-placement.d.ts +259 -0
  84. package/dist/execution-placement.js +199 -0
  85. package/dist/field-conflict.d.ts +3 -2
  86. package/dist/field-conflict.js +1 -0
  87. package/dist/gate-settlement.d.ts +71 -0
  88. package/dist/gate-settlement.js +40 -0
  89. package/dist/hooks/classic-stations.d.ts +1 -0
  90. package/dist/hooks/classic-stations.js +1 -0
  91. package/dist/hooks/command-spawn.d.ts +2 -2
  92. package/dist/hooks/hook-runner.js +14 -14
  93. package/dist/hosted-posture.d.ts +2 -2
  94. package/dist/http/admission.js +10 -19
  95. package/dist/http/checkpoint-ctx.d.ts +21 -12
  96. package/dist/http/checkpoint-ctx.js +4 -2
  97. package/dist/http/claimed-run.d.ts +1 -1
  98. package/dist/http/dispatch.d.ts +4 -0
  99. package/dist/http/dispatch.js +3 -0
  100. package/dist/http/durable-run-leg.js +12 -6
  101. package/dist/http/execution-context.d.ts +218 -0
  102. package/dist/http/execution-context.js +330 -0
  103. package/dist/http/memory-compliance-failure-reply.js +3 -0
  104. package/dist/http/resume-legs.d.ts +5 -11
  105. package/dist/http/resume-legs.js +179 -104
  106. package/dist/http/route-ctx.d.ts +44 -59
  107. package/dist/http/route-ctx.js +2 -5
  108. package/dist/http/routes/a2a-serve.js +10 -4
  109. package/dist/http/routes/agents-roster.d.ts +1 -1
  110. package/dist/http/routes/agents-roster.js +5 -1
  111. package/dist/http/routes/approvals-assistant.js +6 -6
  112. package/dist/http/routes/background.d.ts +29 -1
  113. package/dist/http/routes/background.js +29 -2
  114. package/dist/http/routes/capabilities.js +12 -10
  115. package/dist/http/routes/devices.d.ts +13 -19
  116. package/dist/http/routes/devices.js +21 -26
  117. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  118. package/dist/http/routes/mcp-reconnect.js +7 -5
  119. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  120. package/dist/http/routes/memory-origin.d.ts +1 -1
  121. package/dist/http/routes/rules.js +3 -3
  122. package/dist/http/routes/runs.js +11 -7
  123. package/dist/http/routes/session-sync.js +110 -15
  124. package/dist/http/routes/sessions.d.ts +6 -0
  125. package/dist/http/routes/sessions.js +119 -13
  126. package/dist/http/routes/side-query.d.ts +12 -4
  127. package/dist/http/routes/side-query.js +6 -8
  128. package/dist/http/routes/tasks.js +800 -782
  129. package/dist/http/server.d.ts +61 -39
  130. package/dist/http/server.js +11 -0
  131. package/dist/http/session-inherit-env.d.ts +3 -4
  132. package/dist/http/session-inherit-env.js +1 -1
  133. package/dist/http/wire-types.d.ts +22 -18
  134. package/dist/identity-source.d.ts +1 -1
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.js +1 -0
  137. package/dist/leader/wire.d.ts +7 -0
  138. package/dist/leader/wire.js +5 -4
  139. package/dist/mcp-assertion-header.d.ts +51 -40
  140. package/dist/mcp-assertion-header.js +10 -11
  141. package/dist/mcp-authorization-face.d.ts +27 -0
  142. package/dist/mcp-authorization-face.js +15 -0
  143. package/dist/memory-operator-faces.d.ts +13 -4
  144. package/dist/memory-operator-faces.js +1 -17
  145. package/dist/memory-sync-client.d.ts +53 -14
  146. package/dist/memory-sync-client.js +187 -92
  147. package/dist/memory-sync.d.ts +1 -1
  148. package/dist/memory-sync.js +3 -2
  149. package/dist/model-route-gap.d.ts +6 -22
  150. package/dist/model-route-gap.js +7 -5
  151. package/dist/mods-declaration.d.ts +110 -0
  152. package/dist/mods-declaration.js +109 -0
  153. package/dist/observability/cost-taxonomy.d.ts +2 -2
  154. package/dist/observability/err-text.d.ts +5 -0
  155. package/dist/observability/err-text.js +9 -0
  156. package/dist/observability/fail-open.d.ts +17 -1
  157. package/dist/observability/fail-open.js +17 -1
  158. package/dist/observability/run-terminal.js +0 -1
  159. package/dist/observability/secret-env-scrub.d.ts +1 -1
  160. package/dist/observability/secret-env-scrub.js +1 -1
  161. package/dist/orchestration/workflow-notify-journal.js +4 -4
  162. package/dist/org-memory-admission.d.ts +4 -3
  163. package/dist/org-memory-admission.js +6 -6
  164. package/dist/parked-decide.d.ts +49 -11
  165. package/dist/parked-decide.js +25 -26
  166. package/dist/parked-revive-surface.d.ts +12 -15
  167. package/dist/parked-revive-surface.js +3 -6
  168. package/dist/peer-seat.d.ts +156 -0
  169. package/dist/peer-seat.js +273 -0
  170. package/dist/permission-rule-vocab.d.ts +7 -7
  171. package/dist/permission-rule-vocab.js +3 -3
  172. package/dist/plain-string-record.d.ts +38 -0
  173. package/dist/plain-string-record.js +38 -0
  174. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  175. package/dist/plugins/approval-ask-store-file.js +11 -0
  176. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  177. package/dist/plugins/approval-ask-store-memory.js +12 -0
  178. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  179. package/dist/plugins/approval-ask-store-sql.js +30 -12
  180. package/dist/plugins/background-agent-store-sql.js +6 -3
  181. package/dist/plugins/caching-session-store.d.ts +11 -2
  182. package/dist/plugins/caching-session-store.js +15 -3
  183. package/dist/plugins/checkpoint-store-sql.d.ts +21 -25
  184. package/dist/plugins/checkpoint-store-sql.js +13 -15
  185. package/dist/plugins/device-store-sql.d.ts +25 -51
  186. package/dist/plugins/device-store-sql.js +49 -103
  187. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  188. package/dist/plugins/execution-placement-sql.js +223 -0
  189. package/dist/plugins/file-history-store-sql.d.ts +7 -6
  190. package/dist/plugins/file-history-store-sql.js +8 -7
  191. package/dist/plugins/file-run-store.d.ts +6 -1
  192. package/dist/plugins/file-run-store.js +4 -0
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  194. package/dist/plugins/fork-routing-session-store.js +16 -0
  195. package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
  196. package/dist/plugins/k8s-pod-reaper.js +3 -3
  197. package/dist/plugins/local-checkpoint-store.d.ts +1 -11
  198. package/dist/plugins/local-checkpoint-store.js +0 -1
  199. package/dist/plugins/local-session-store.d.ts +183 -45
  200. package/dist/plugins/local-session-store.js +412 -105
  201. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  202. package/dist/plugins/mailbox-store-sql.js +103 -15
  203. package/dist/plugins/memory-key-guards.d.ts +4 -0
  204. package/dist/plugins/memory-key-guards.js +1 -0
  205. package/dist/plugins/memory-run-store.d.ts +1 -1
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +117 -6
  209. package/dist/plugins/one-time-migrations.js +383 -14
  210. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
  212. package/dist/plugins/permission-rule-store-sql.js +34 -29
  213. package/dist/plugins/pg-pool.d.ts +7 -3
  214. package/dist/plugins/pg-session-storage.d.ts +41 -22
  215. package/dist/plugins/pg-session-storage.js +136 -55
  216. package/dist/plugins/remote-env-adb.d.ts +22 -4
  217. package/dist/plugins/remote-env-adb.js +70 -62
  218. package/dist/plugins/remote-env-device.d.ts +32 -12
  219. package/dist/plugins/remote-env-device.js +18 -17
  220. package/dist/plugins/remote-env-e2b.d.ts +19 -3
  221. package/dist/plugins/remote-env-e2b.js +41 -42
  222. package/dist/plugins/remote-env-file-error.d.ts +2 -0
  223. package/dist/plugins/remote-env-file-error.js +1 -1
  224. package/dist/plugins/remote-env-host.d.ts +23 -8
  225. package/dist/plugins/remote-env-host.js +66 -70
  226. package/dist/plugins/remote-env-k8s.d.ts +13 -16
  227. package/dist/plugins/remote-env-k8s.js +61 -54
  228. package/dist/plugins/remote-env-local-docker.d.ts +30 -5
  229. package/dist/plugins/remote-env-local-docker.js +46 -59
  230. package/dist/plugins/remote-env-ssh.d.ts +18 -4
  231. package/dist/plugins/remote-env-ssh.js +72 -56
  232. package/dist/plugins/remote-shell.d.ts +100 -3
  233. package/dist/plugins/remote-shell.js +166 -2
  234. package/dist/plugins/retention-store-sql.d.ts +23 -8
  235. package/dist/plugins/retention-store-sql.js +13 -1
  236. package/dist/plugins/run-store-sql.d.ts +13 -3
  237. package/dist/plugins/run-store-sql.js +5 -0
  238. package/dist/plugins/schema-consistency.d.ts +15 -5
  239. package/dist/plugins/schema-consistency.js +14 -8
  240. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  241. package/dist/plugins/schema-drift-sentence.js +38 -0
  242. package/dist/plugins/session-fork.d.ts +63 -12
  243. package/dist/plugins/session-fork.js +38 -21
  244. package/dist/plugins/session-ownership.d.ts +7 -0
  245. package/dist/plugins/session-ownership.js +5 -0
  246. package/dist/plugins/session-row-sql.d.ts +22 -0
  247. package/dist/plugins/session-row-sql.js +81 -0
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  250. package/dist/plugins/session-workspace-cell.js +38 -0
  251. package/dist/plugins/store-backend.d.ts +1 -1
  252. package/dist/plugins/store-backend.js +26 -14
  253. package/dist/plugins/store-contracts.d.ts +25 -5
  254. package/dist/plugins/tidb-pool.d.ts +12 -7
  255. package/dist/plugins/tidb-pool.js +15 -3
  256. package/dist/plugins/tidb-session-store.d.ts +74 -28
  257. package/dist/plugins/tidb-session-store.js +132 -53
  258. package/dist/plugins/tool-result-store-sql.d.ts +16 -8
  259. package/dist/plugins/tool-result-store-sql.js +26 -17
  260. package/dist/plugins/worktree-isolation.d.ts +3 -2
  261. package/dist/plugins/worktree-isolation.js +1 -7
  262. package/dist/project-identity.d.ts +1 -14
  263. package/dist/project-identity.js +0 -4
  264. package/dist/project-memory.d.ts +9 -15
  265. package/dist/project-memory.js +5 -4
  266. package/dist/request-key-closure.js +1 -1
  267. package/dist/request-value-closure.d.ts +6 -7
  268. package/dist/request-value-closure.js +1 -3
  269. package/dist/rules-consent.js +6 -4
  270. package/dist/run-local.d.ts +6 -0
  271. package/dist/run-local.js +36 -26
  272. package/dist/runs.d.ts +9 -2
  273. package/dist/runs.js +9 -2
  274. package/dist/sandbox-git-plane.d.ts +2 -2
  275. package/dist/security.d.ts +38 -12
  276. package/dist/security.js +8 -2
  277. package/dist/server-secret-env.d.ts +15 -8
  278. package/dist/server-secret-env.js +4 -2
  279. package/dist/session-children-retire.d.ts +27 -9
  280. package/dist/session-children-retire.js +9 -5
  281. package/dist/session-incarnation.d.ts +19 -10
  282. package/dist/session-incarnation.js +5 -3
  283. package/dist/session-row.d.ts +114 -5
  284. package/dist/session-row.js +55 -5
  285. package/dist/session-titler.d.ts +2 -2
  286. package/dist/session-workspace.d.ts +130 -0
  287. package/dist/session-workspace.js +83 -0
  288. package/dist/spec-fields.d.ts +1 -1
  289. package/dist/standing-answer-grant.d.ts +2 -13
  290. package/dist/standing-answer-grant.js +0 -7
  291. package/dist/task-a2a.d.ts +44 -14
  292. package/dist/task-a2a.js +46 -20
  293. package/dist/task-cwd.d.ts +6 -1
  294. package/dist/task-mcp.d.ts +33 -20
  295. package/dist/task-mcp.js +46 -22
  296. package/dist/tool-approval.d.ts +38 -8
  297. package/dist/tool-approval.js +57 -13
  298. package/dist/trace/core-keyset-guard.d.ts +33 -18
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +2 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +3 -0
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/project.d.ts +26 -7
  306. package/dist/trace/project.js +30 -3
  307. package/dist/trace/redact.js +42 -13
  308. package/dist/trace/self-minted-wire.d.ts +240 -12
  309. package/dist/trace/self-minted-wire.js +100 -4
  310. package/dist/trace/wire-projection-faces.d.ts +6 -6
  311. package/dist/trace/wire-projection-faces.js +6 -5
  312. package/dist/url-refusal.d.ts +1 -1
  313. package/dist/user-authored-text.d.ts +2 -2
  314. package/dist/user-authored-text.js +16 -1
  315. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  316. package/dist/web-admin-client/apply-effective.js +20 -10
  317. package/dist/web-admin-client/center-request.d.ts +3 -2
  318. package/dist/web-admin-client/center-request.js +2 -3
  319. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  320. package/dist/web-admin-client/skills-mcp.js +32 -18
  321. package/dist/web-admin-client/types.d.ts +11 -0
  322. package/package.json +3 -3
  323. package/wire-changes/server@7.138.0.json +446 -0
  324. package/wire-changes/server@7.139.0.json +348 -0
  325. package/dist/http/device-placement.d.ts +0 -175
  326. package/dist/http/device-placement.js +0 -145
  327. package/dist/http/mcp-remote-text.d.ts +0 -5
  328. package/dist/http/mcp-remote-text.js +0 -7
@@ -0,0 +1,259 @@
1
+ /**
2
+ * **执行放置** —— 根会话行上「这一位住客」的一格(叶模块:型 + 纯函数 + 测试走廊的内存参照实现;运行期只依赖 core 的住客判官)。
3
+ *
4
+ * ## 规则(全仓唯一处写)
5
+ * · **一格四态**:`absent`(这一位住客还没有放置)| `writer(L[, D])`(本引擎声明在车道 L 上写;device 车道带设备 D,D 缺 = 迁移回填的
6
+ * 「有 run、设备未知」)| `mirror`(写者在别处,本处只读)| `forking`(只 local:fork 的目标格已写、存档未落 —— 崩溃中间态,SQL 单事务不可达)。
7
+ * 载体:SQL `session_meta` 的 `execution_*` 七列(列定义与语句的唯一属主 = `plugins/execution-placement-sql.ts`);local = 会话元数据边档那一格的
8
+ * `execution` 位(`plugins/local-session-store.ts`)。处处 `execution` 限定,与同行 `placement_*`(委派分区)不同义;执行格只在 `placement_kind IS NULL` 的行上 ——
9
+ * 委派分区行读作「不在」。
10
+ * · **读只有一只**:会话店的执行席 {@link ExecutionPlacementSeat.read}(一次行读:住客 + 格;行不在 / 委派分区行 ⇒ `undefined`;读故障抛,不吞成 `absent`)。
11
+ * · **写只按住客谓词** `(root, incarnation, owner) ∧ placement_kind IS NULL`:住客换了(删后重建,哪怕同一属主;local M10 窗内的认领)= 这一格不在 ⇒ 落空;
12
+ * 0 行一律按住客复读分类({@link settledPlaceOutcome} / {@link settledMirrorOutcome} / {@link settledDeviceBindOutcome}),**永不对现住客重试**。
13
+ * · **没有的转换**:writer ↔ mirror、writer(L) → writer(L')(device 车道的换绑 writer(device, D) → writer(device, D') 除外,它有自己的语句与门)。
14
+ * · **放置存在 ⇒ 住客存在**:放置是行的列 / 格,删会话即删放置;建行恒 absent(SQL 建行 INSERT 列名显式;local 新格整格新铸),导入新建的行同锁落 mirror。
15
+ *
16
+ * ## 测试走廊的会话行(不是第二只生产店)
17
+ * {@link InMemoryExecutionPlacementSeat} 是**语义参照实现**(与 `InMemoryDeviceStore` 同一身份):持「会话行」(root → 住客 + 格),给只用 `Map` 会话店的
18
+ * 测试走廊与 `InMemoryDeviceStore` 共用。**生产装配零引用** —— `src/` 非测试路径里只许 `device-store.ts` 与本模块提到它。
19
+ */
20
+ import { type SessionHead } from "@sema-agent/core";
21
+ import type { DeviceOwner } from "./device-store.js";
22
+ import type { ExecutionLane } from "./execution-lane-caps.js";
23
+ import type { SessionFace } from "./session-incarnation.js";
24
+ /** writer(device, D) 的 D:设备、绑定属主(= 设备属主)、换绑序号、放下时刻(ISO)。 */
25
+ export interface ExecutionDeviceCell {
26
+ readonly id: string;
27
+ readonly owner: DeviceOwner;
28
+ readonly rev: number;
29
+ readonly placedAt: string;
30
+ }
31
+ /** `lane = "device"` ∧ `device` 缺 = writer(device, ∅)(只来自迁移回填:有 run 而设备未知)。 */
32
+ export type ExecutionWriterCell = {
33
+ readonly role: "writer";
34
+ readonly lane: ExecutionLane;
35
+ readonly device?: ExecutionDeviceCell;
36
+ };
37
+ export type ExecutionPlacementCell = {
38
+ readonly role: "absent";
39
+ } | ExecutionWriterCell | {
40
+ readonly role: "mirror";
41
+ } | {
42
+ readonly role: "forking";
43
+ };
44
+ /** 一次行读的答案:这一位住客 + 它的格(同一行、同一次读)。 */
45
+ export interface ExecutionPlacementReading {
46
+ readonly occupant: SessionFace;
47
+ readonly cell: ExecutionPlacementCell;
48
+ }
49
+ /** place 的结果(0 行按住客复读分类;`gone` = 行不在或住客不是判过的那一位)。 */
50
+ export type PlaceOutcome = {
51
+ readonly outcome: "placed";
52
+ } | {
53
+ readonly outcome: "same";
54
+ } | {
55
+ readonly outcome: "tree_bound";
56
+ readonly boundLane: ExecutionLane;
57
+ } | {
58
+ readonly outcome: "mirror";
59
+ } | {
60
+ readonly outcome: "gone";
61
+ };
62
+ /** identical 臂补 mirror 的结果(`active` = 写事务内(SQL)/ 写锁内(local)读到认领,带那只认领的 task id;判官的答案先于它,只拦「absent → mirror」这一笔写)。 */
63
+ export type MarkMirrorOutcome = {
64
+ readonly outcome: "mirrored";
65
+ } | {
66
+ readonly outcome: "writer";
67
+ } | {
68
+ readonly outcome: "gone";
69
+ } | {
70
+ readonly outcome: "active";
71
+ readonly activeTaskId: string;
72
+ };
73
+ /**
74
+ * 「谁带执行席」的唯一一句(要求会话店带席的装配拒句引它,不另抄):三店都带(SQL 两孪生 + local,即 `StoreBackend` 交出的会话店),两只包装原样转发;
75
+ * 只用 `Map` 会话店的测试走廊 / 内存嵌入给参照实现。
76
+ */
77
+ export declare const EXECUTION_PLACEMENT_SEAT_CARRIERS = "every built-in session store carries one (the MySQL-protocol and PostgreSQL stores and the local store, i.e. the session store a StoreBackend hands out; the caching and fork-routing wrappers forward it), and an in-memory test or embedding passes InMemoryExecutionPlacementSeat";
78
+ /** 会话店的执行席(三店 + 两只包装原样转发)。 */
79
+ export interface ExecutionPlacementSeat {
80
+ /** 一次行读:行不在 / 委派分区行 ⇒ `undefined`;读故障抛(不吞成 absent)。 */
81
+ read(root: string): Promise<ExecutionPlacementReading | undefined>;
82
+ /** absent → writer(L)(非 device 车道;device 车道的首绑走设备店,同一只 SQL 语句模块)。传 device 车道 ⇒ 响亮抛(装配缝)。 */
83
+ place(root: string, occupant: SessionFace, cell: ExecutionWriterCell): Promise<PlaceOutcome>;
84
+ /** identical 臂补 mirror:WHERE 住客谓词 ∧ 不是 writer;写事务内先锁根行读认领(SQL),local 在这只会话的写锁里读同一个认领。 */
85
+ markMirror(root: string, occupant: SessionFace): Promise<MarkMirrorOutcome>;
86
+ }
87
+ /**
88
+ * 读不出的存档的故障词(闭集;一次性迁移 M32 的 local 腿点名用 —— 随 M32 · 窗口见 `plugins/one-time-migrations.ts` 登记表,窗关后随迁移码删):
89
+ * · `corrupt_session` —— 存档在,会话头读不出 / 截断;`invalid_session` —— 读得出而日志结构走不通(两个都是 core 的 `SessionError` 词,原样);
90
+ * · `storage` —— 读的时候抛了**别的**故障(I/O 级:权限 / 磁盘 I/O / 超大 —— core 的 `readJsonlRecords` 只吞 ENOENT,其余 errno 原样抛,不是 `SessionError`),
91
+ * 说不出在不在也说不出内容;{@link UnusableArchive.errno} 带那只故障的 `code`。
92
+ */
93
+ export type UnusableArchiveWord = "corrupt_session" | "invalid_session" | "storage";
94
+ /**
95
+ * local 的会话存档**读不出**(会话头读不出 / 日志结构走不通 / 读的时候抛了别的故障):盘上有这只会话的存档,只是读不出它 —— 与「不在」是两件事。
96
+ * (本型与 {@link isUnusableArchive} 随 M32 · 窗口见 `plugins/one-time-migrations.ts` 登记表。)
97
+ * local 店对存档的**唯一探针**答三态(不在 · 在而读得出 · 本型),要对存档动手的读者看到本型就把 {@link UnusableArchive.fault}(抛出来的那只故障,**原样**)上抛,
98
+ * 只问「有没有」的读者不上抛(见 `plugins/local-session-store.ts` 的 `probeArchive`)。
99
+ */
100
+ export interface UnusableArchive {
101
+ readonly state: "unusable";
102
+ readonly word: UnusableArchiveWord;
103
+ /** `word === "storage"` 且那只故障带字符串 `code` 时:该 `code`(`EACCES` / `EIO` / `ERR_STRING_TOO_LONG` ……);其余缺席。盘上路径与故障句不进这一格。 */
104
+ readonly errno?: string;
105
+ /** 探针抛出来的那只故障,原样(上抛的读者抛的就是它)。 */
106
+ readonly fault: unknown;
107
+ }
108
+ export declare function isUnusableArchive(x: object | undefined): x is UnusableArchive;
109
+ /**
110
+ * 一次性迁移 M32 **local 腿**的席(随 M32 · 窗口见 `plugins/one-time-migrations.ts` 登记表;只 local 有:SQL 的行就是会话,没有「会话元数据格缺 ∧ 存档读不出」这一形)。`read` 与 {@link ExecutionPlacementSeat.read} 是
111
+ * **同一读**(同一只实现的本体),只差一点:这只会话的存档读不出(格缺而探针读不出,或 fork 创建的格而探针读不出)⇒ **答 {@link UnusableArchive} 而不抛** —— 开机回填不动存档、
112
+ * 只补一格放置,读不出的会话由它点名跳过(该会话的请求照旧答存档的故障);席的 `read` 对同一形照旧抛。`place` 就是席的 `place`。
113
+ */
114
+ export interface LocalPlacementBackfillSeat extends Pick<ExecutionPlacementSeat, "place"> {
115
+ read(root: string): Promise<ExecutionPlacementReading | UnusableArchive | undefined>;
116
+ }
117
+ /** wire 投影(新读面 + 受理回声共用)。 */
118
+ export type ExecutionPlacementView = {
119
+ readonly role: "absent";
120
+ } | {
121
+ readonly role: "writer";
122
+ readonly lane: ExecutionLane;
123
+ readonly device?: {
124
+ readonly deviceId: string;
125
+ readonly rev: number;
126
+ };
127
+ } | {
128
+ readonly role: "mirror";
129
+ } | {
130
+ readonly role: "forking";
131
+ };
132
+ /** 格 → wire 投影(唯一一只;设备只投 id 与 rev,属主与时刻不上 wire)。 */
133
+ export declare function executionPlacementView(cell: ExecutionPlacementCell): ExecutionPlacementView;
134
+ /**
135
+ * 住客谓词的 JS 读法(SQL `incarnation = ? AND owner <=> ?` 的对位)= core 的行期望判官 `sessionRowMatches`(会话行格写原语锁内判的也是它,
136
+ * `session-row.ts` 的 `judgeSessionRowWrite`):属主与化身两样都没变才是判过的那一位 —— 同一化身的属主会变(local M10 认领、identical 重戳、
137
+ * SQL 导入提交点改属主)。两侧收「属主 + 化身」那一读:活住客(`SessionFace`)与店的头(`SessionHead`,门判过的那一读);调用方一侧恒是执行席的读数
138
+ * (住客经 `sessionFaceFromRow` 解码,令牌非空),所以「两侧都没有令牌」这一形在这里不可达。写口的判官与执行上下文解析器步 ① 的 `judged` 复核都经它。
139
+ */
140
+ export declare function sameOccupant(a: Pick<SessionHead, "owner" | "incarnation">, b: Pick<SessionHead, "owner" | "incarnation">): boolean;
141
+ /**
142
+ * 写口撞上本处写者 —— 三个导入写口(staged 提交点 / 整段 `importEntries` / `replaceEntries`)在写事务内(local:写锁内、写格之前)复读到 `writer`
143
+ * ⇒ 回滚、目的端零字节、抛它。具名类型:会话同步路由按类型把它答 409 `conflict.session_writer`;不是 core `SessionError`(那张闭集的 `conflict` 在导入面另有固定答复)。
144
+ */
145
+ export declare class SessionWriterPresentError extends Error {
146
+ readonly sessionId: string;
147
+ readonly lane: ExecutionLane;
148
+ readonly code = "conflict.session_writer";
149
+ constructor(sessionId: string, lane: ExecutionLane);
150
+ }
151
+ /**
152
+ * local 的 `forking` 中间态(fork 创建的格 —— 带 fork 键、执行位没人写过 —— 而存档不在)上的普通取用 —— 引擎 acquire 的缺档新建臂、登记、三个导入写口、执行席的写一律抛它;
153
+ * 只有同键的 `forkTo` 重试在两把写锁内补拷存档。具名类型:路由层按类型答 409 `conflict.fork_in_progress`。
154
+ */
155
+ export declare class SessionForkInProgressError extends Error {
156
+ readonly sessionId: string;
157
+ readonly code = "conflict.fork_in_progress";
158
+ constructor(sessionId: string);
159
+ }
160
+ /**
161
+ * 写事务内的认领读命中(读写序律,`plugins/execution-placement-sql.ts` 的 `lockRootAndReadClaim`):改根住客 / 放置的写者在自己的事务里先锁根
162
+ * `session_meta` 行、再锁定读 `task_active(root)`,读到认领 ⇒ 回滚、一个字节不写、抛它。只 SQL 后端(local 不立此律:没有 device 工厂)。
163
+ * 具名类型、**不带 wire 码**:各门按自己的既有码答(导入 409 `session_active`、删除 409 `conflict.session_active_run`),体带 `activeTaskId`。
164
+ */
165
+ export declare class SessionActiveRunError extends Error {
166
+ readonly sessionId: string;
167
+ readonly activeTaskId: string;
168
+ constructor(sessionId: string, activeTaskId: string);
169
+ }
170
+ /** 0 行分类的「这一格此刻可写」答案(只给锁内读写的实现用:local 与内存参照实现写它;SQL 在 0 行之后读到它 = 不变量破,响亮抛)。 */
171
+ export declare const WRITABLE: "writable";
172
+ /**
173
+ * place 的唯一判官(三店 + 内存参照实现同调):对一次按根的读数判「判过的住客 + 想要的格」此刻是什么结果。
174
+ * 行不在 / 住客不同 ⇒ `gone`;writer 同车道 ⇒ `same`;writer 异车道 ⇒ `tree_bound`;mirror ⇒ `mirror`;absent ⇒ {@link WRITABLE};forking ⇒ 抛 {@link SessionForkInProgressError}。
175
+ * 想要的格只认非 device 车道(device 首绑的判官是 {@link settledDeviceBindOutcome})。
176
+ */
177
+ export declare function settledPlaceOutcome(root: string, reading: ExecutionPlacementReading | undefined, occupant: SessionFace, wanted: ExecutionWriterCell): PlaceOutcome | typeof WRITABLE;
178
+ /** markMirror 的唯一判官(认领那一半在本判官之后,SQL 与 local 各在自己的写事务 / 写锁内判):行不在 / 住客不同 ⇒ `gone`;writer ⇒ `writer`;mirror ⇒ `mirrored`(幂等,零写);absent ⇒ {@link WRITABLE};forking ⇒ 抛。 */
179
+ export declare function settledMirrorOutcome(root: string, reading: ExecutionPlacementReading | undefined, occupant: SessionFace): MarkMirrorOutcome | typeof WRITABLE;
180
+ /** device 车道首绑(absent → writer(device, D) 或 writer(device, ∅) → writer(device, D))的结果(设备店的事务 / 内存参照实现同调)。 */
181
+ export type DeviceBindOutcome = {
182
+ readonly outcome: "bound";
183
+ readonly device: ExecutionDeviceCell;
184
+ } | {
185
+ readonly outcome: "same";
186
+ readonly device: ExecutionDeviceCell;
187
+ } | {
188
+ readonly outcome: "device_conflict";
189
+ readonly device: ExecutionDeviceCell;
190
+ } | {
191
+ readonly outcome: "tree_bound";
192
+ readonly boundLane: ExecutionLane;
193
+ } | {
194
+ readonly outcome: "mirror";
195
+ } | {
196
+ readonly outcome: "gone";
197
+ };
198
+ /**
199
+ * device 首绑的唯一判官:行不在 / 住客不同 ⇒ `gone`;absent 或 writer(device, ∅) ⇒ {@link WRITABLE};writer(device, D):D = 想要的设备 ⇒ `same`、否则 `device_conflict`;
200
+ * writer 异车道 ⇒ `tree_bound`;mirror ⇒ `mirror`;forking ⇒ 抛。
201
+ */
202
+ export declare function settledDeviceBindOutcome(root: string, reading: ExecutionPlacementReading | undefined, occupant: SessionFace, deviceId: string): Exclude<DeviceBindOutcome, {
203
+ outcome: "bound";
204
+ }> | typeof WRITABLE;
205
+ /**
206
+ * device 换绑 writer(device, D) → writer(device, D') 的结果(按住客 ∧ 两属主列 ∧ rev 定址;0 行按住客复读分 `rev_conflict` / `gone`)。
207
+ * `rebound` 带被换下的那台(`from`,审计行 `session_rebound` 的 detail 要它);`idempotent` = 目标就是格上那台且前态 rev 对得上 ⇒ 零写、rev 不加、不写审计。
208
+ */
209
+ export type DeviceRebindOutcome = {
210
+ readonly outcome: "rebound";
211
+ readonly device: ExecutionDeviceCell;
212
+ readonly from: string;
213
+ } | {
214
+ readonly outcome: "idempotent";
215
+ readonly device: ExecutionDeviceCell;
216
+ } | {
217
+ readonly outcome: "rev_conflict";
218
+ readonly device: ExecutionDeviceCell;
219
+ } | {
220
+ readonly outcome: "gone";
221
+ };
222
+ /**
223
+ * device 换绑的唯一判官(设备店的事务 / 内存参照实现同调,在锁住的那一读上判):行不在 / 住客不同 / 不是 writer(device, D) / 绑定属主不是判过的那一位 ⇒ `gone`;
224
+ * rev 不等 ⇒ `rev_conflict`;rev 对得上而目标就是格上那台 ⇒ `idempotent`(必须先于写判 —— `execution_rev + 1` 恒变列会把一次无操作也推进一格);否则 {@link WRITABLE}。
225
+ */
226
+ export declare function settledDeviceRebindOutcome(reading: ExecutionPlacementReading | undefined, occupant: SessionFace, owner: DeviceOwner, expectedRev: number, targetDeviceId: string): Exclude<DeviceRebindOutcome, {
227
+ outcome: "rebound";
228
+ }> | typeof WRITABLE;
229
+ /**
230
+ * 「这一格把这棵树放在哪台设备上」的**唯一读法**(准入链、device 工厂、换绑门与上面的换绑判官同调):writer(device, D) ⇒ D;其余一律 `undefined` ——
231
+ * absent(还没放)、mirror(写者在别处)、forking(local 中间态)、writer(device, ∅)(迁移回填的「有 run、设备未知」)、writer(别的车道)。
232
+ * 读者把 `undefined` 答成各自的「没有设备绑定」(`device.not_bound` / 设备 404);穷举 switch,新角色 = 编译红。
233
+ */
234
+ export declare function boundDeviceOf(cell: ExecutionPlacementCell): ExecutionDeviceCell | undefined;
235
+ /** seat.place 只认非 device 车道(device 首绑走设备店);传 device ⇒ 响亮抛 —— 这是装配缝,不是一个答案。 */
236
+ export declare function assertPlaceableLane(root: string, cell: ExecutionWriterCell): void;
237
+ /**
238
+ * **测试走廊的会话行**(语义参照实现,与 `InMemoryDeviceStore` 同一身份 —— 生产装配零引用,见头注):root → 住客 + 格。
239
+ * 只用 `Map` 会话店的测试走廊经 {@link seatRow} / {@link dropRow} 模拟会话行的生灭(= SQL 店的建行 / 删行),`InMemoryDeviceStore` 在它上面做设备首绑 / 换绑。
240
+ * 语义与 SQL 语句模块逐格同:同一组判官({@link settledPlaceOutcome} 等),写只按住客谓词。
241
+ */
242
+ export declare class InMemoryExecutionPlacementSeat implements ExecutionPlacementSeat {
243
+ private readonly rows;
244
+ /** 建行(会话店建行的对位):行不在 ⇒ 建一只 absent 行;在 ⇒ 不动(与 SQL `ON CONFLICT DO NOTHING` 同一条 first-write 律)。 */
245
+ seatRow(root: string, occupant: SessionFace): void;
246
+ /** 删行(删会话的对位):放置随行消失。 */
247
+ dropRow(root: string): void;
248
+ read(root: string): Promise<ExecutionPlacementReading | undefined>;
249
+ place(root: string, occupant: SessionFace, cell: ExecutionWriterCell): Promise<PlaceOutcome>;
250
+ markMirror(root: string, occupant: SessionFace): Promise<MarkMirrorOutcome>;
251
+ /** device 首绑(SQL `placeDeviceStatement` / `bindDeviceStatement` 的对位):absent 或 writer(device, ∅) ⇒ writer(device, D)、rev 0。 */
252
+ bindDevice(root: string, occupant: SessionFace, device: {
253
+ readonly id: string;
254
+ readonly owner: DeviceOwner;
255
+ }, placedAt: string): DeviceBindOutcome;
256
+ /** device 换绑(SQL `rebindDeviceStatement` 的对位):按住客 ∧ 两属主列 ∧ rev 定址,rev + 1;目标就是格上那台 ⇒ `idempotent` 零写。 */
257
+ rebindDevice(root: string, occupant: SessionFace, owner: DeviceOwner, expectedRev: number, targetDeviceId: string, placedAt: string): DeviceRebindOutcome;
258
+ }
259
+ //# sourceMappingURL=execution-placement.d.ts.map
@@ -0,0 +1,199 @@
1
+ import { sessionRowMatches } from "@sema-agent/core";
2
+ export const EXECUTION_PLACEMENT_SEAT_CARRIERS = "every built-in session store carries one (the MySQL-protocol and PostgreSQL stores and the local store, i.e. the session store a StoreBackend hands out; the caching and fork-routing wrappers forward it), and an in-memory test or embedding passes InMemoryExecutionPlacementSeat";
3
+ export function isUnusableArchive(x) {
4
+ return x !== undefined && x.state === "unusable";
5
+ }
6
+ export function executionPlacementView(cell) {
7
+ switch (cell.role) {
8
+ case "absent":
9
+ return { role: "absent" };
10
+ case "writer":
11
+ return cell.device === undefined ? { role: "writer", lane: cell.lane } : { role: "writer", lane: cell.lane, device: { deviceId: cell.device.id, rev: cell.device.rev } };
12
+ case "mirror":
13
+ return { role: "mirror" };
14
+ case "forking":
15
+ return { role: "forking" };
16
+ default: {
17
+ const unknownRole = cell;
18
+ throw new Error(`executionPlacementView: no projection for ${JSON.stringify(unknownRole)}`);
19
+ }
20
+ }
21
+ }
22
+ export function sameOccupant(a, b) {
23
+ return sessionRowMatches({ row: { owner: a.owner ?? null, incarnation: a.incarnation } }, b, noLogMark);
24
+ }
25
+ function noLogMark() {
26
+ throw new Error("sameOccupant: an occupant check carries no log mark, yet the judge asked for one");
27
+ }
28
+ export class SessionWriterPresentError extends Error {
29
+ sessionId;
30
+ lane;
31
+ code = "conflict.session_writer";
32
+ constructor(sessionId, lane) {
33
+ super(`session ${sessionId} is written here on the ${lane} lane — an import cannot turn it into a mirror; nothing was written`);
34
+ this.sessionId = sessionId;
35
+ this.lane = lane;
36
+ this.name = "SessionWriterPresentError";
37
+ }
38
+ }
39
+ export class SessionForkInProgressError extends Error {
40
+ sessionId;
41
+ code = "conflict.fork_in_progress";
42
+ constructor(sessionId) {
43
+ super(`session ${sessionId} is the target of a fork that has not finished copying — retry that fork with the same key, or delete the session`);
44
+ this.sessionId = sessionId;
45
+ this.name = "SessionForkInProgressError";
46
+ }
47
+ }
48
+ export class SessionActiveRunError extends Error {
49
+ sessionId;
50
+ activeTaskId;
51
+ constructor(sessionId, activeTaskId) {
52
+ super(`session ${sessionId} has an active run (${activeTaskId}) — this write was refused inside its transaction; nothing was written`);
53
+ this.sessionId = sessionId;
54
+ this.activeTaskId = activeTaskId;
55
+ this.name = "SessionActiveRunError";
56
+ }
57
+ }
58
+ export const WRITABLE = "writable";
59
+ export function settledPlaceOutcome(root, reading, occupant, wanted) {
60
+ if (reading === undefined || !sameOccupant(reading.occupant, occupant))
61
+ return { outcome: "gone" };
62
+ const cell = reading.cell;
63
+ switch (cell.role) {
64
+ case "absent":
65
+ return WRITABLE;
66
+ case "writer":
67
+ return cell.lane === wanted.lane ? { outcome: "same" } : { outcome: "tree_bound", boundLane: cell.lane };
68
+ case "mirror":
69
+ return { outcome: "mirror" };
70
+ case "forking":
71
+ throw new SessionForkInProgressError(root);
72
+ default: {
73
+ const unknownRole = cell;
74
+ throw new Error(`settledPlaceOutcome: no arm for ${JSON.stringify(unknownRole)}`);
75
+ }
76
+ }
77
+ }
78
+ export function settledMirrorOutcome(root, reading, occupant) {
79
+ if (reading === undefined || !sameOccupant(reading.occupant, occupant))
80
+ return { outcome: "gone" };
81
+ const cell = reading.cell;
82
+ switch (cell.role) {
83
+ case "absent":
84
+ return WRITABLE;
85
+ case "writer":
86
+ return { outcome: "writer" };
87
+ case "mirror":
88
+ return { outcome: "mirrored" };
89
+ case "forking":
90
+ throw new SessionForkInProgressError(root);
91
+ default: {
92
+ const unknownRole = cell;
93
+ throw new Error(`settledMirrorOutcome: no arm for ${JSON.stringify(unknownRole)}`);
94
+ }
95
+ }
96
+ }
97
+ export function settledDeviceBindOutcome(root, reading, occupant, deviceId) {
98
+ if (reading === undefined || !sameOccupant(reading.occupant, occupant))
99
+ return { outcome: "gone" };
100
+ const cell = reading.cell;
101
+ switch (cell.role) {
102
+ case "absent":
103
+ return WRITABLE;
104
+ case "writer":
105
+ if (cell.lane !== "device")
106
+ return { outcome: "tree_bound", boundLane: cell.lane };
107
+ if (cell.device === undefined)
108
+ return WRITABLE;
109
+ return cell.device.id === deviceId ? { outcome: "same", device: cell.device } : { outcome: "device_conflict", device: cell.device };
110
+ case "mirror":
111
+ return { outcome: "mirror" };
112
+ case "forking":
113
+ throw new SessionForkInProgressError(root);
114
+ default: {
115
+ const unknownRole = cell;
116
+ throw new Error(`settledDeviceBindOutcome: no arm for ${JSON.stringify(unknownRole)}`);
117
+ }
118
+ }
119
+ }
120
+ export function settledDeviceRebindOutcome(reading, occupant, owner, expectedRev, targetDeviceId) {
121
+ if (reading === undefined || !sameOccupant(reading.occupant, occupant))
122
+ return { outcome: "gone" };
123
+ const device = boundDeviceOf(reading.cell);
124
+ if (device === undefined)
125
+ return { outcome: "gone" };
126
+ if (device.owner.tenant !== owner.tenant || device.owner.subject !== owner.subject)
127
+ return { outcome: "gone" };
128
+ if (device.rev !== expectedRev)
129
+ return { outcome: "rev_conflict", device };
130
+ return device.id === targetDeviceId ? { outcome: "idempotent", device } : WRITABLE;
131
+ }
132
+ export function boundDeviceOf(cell) {
133
+ switch (cell.role) {
134
+ case "writer":
135
+ return cell.lane === "device" ? cell.device : undefined;
136
+ case "absent":
137
+ case "mirror":
138
+ case "forking":
139
+ return undefined;
140
+ default: {
141
+ const unknownRole = cell;
142
+ throw new Error(`boundDeviceOf: no arm for ${JSON.stringify(unknownRole)}`);
143
+ }
144
+ }
145
+ }
146
+ export function assertPlaceableLane(root, cell) {
147
+ if (cell.lane === "device" || cell.device !== undefined) {
148
+ throw new Error(`execution placement of session ${root}: the device lane is placed by the device store (it judges the device row in the same transaction), not by the session store's seat`);
149
+ }
150
+ }
151
+ export class InMemoryExecutionPlacementSeat {
152
+ rows = new Map();
153
+ seatRow(root, occupant) {
154
+ if (!this.rows.has(root))
155
+ this.rows.set(root, { occupant, cell: { role: "absent" } });
156
+ }
157
+ dropRow(root) {
158
+ this.rows.delete(root);
159
+ }
160
+ async read(root) {
161
+ return this.rows.get(root);
162
+ }
163
+ async place(root, occupant, cell) {
164
+ assertPlaceableLane(root, cell);
165
+ const settled = settledPlaceOutcome(root, this.rows.get(root), occupant, cell);
166
+ if (settled !== WRITABLE)
167
+ return settled;
168
+ this.rows.set(root, { occupant, cell: { role: "writer", lane: cell.lane } });
169
+ return { outcome: "placed" };
170
+ }
171
+ async markMirror(root, occupant) {
172
+ const settled = settledMirrorOutcome(root, this.rows.get(root), occupant);
173
+ if (settled !== WRITABLE)
174
+ return settled;
175
+ this.rows.set(root, { occupant, cell: { role: "mirror" } });
176
+ return { outcome: "mirrored" };
177
+ }
178
+ bindDevice(root, occupant, device, placedAt) {
179
+ const settled = settledDeviceBindOutcome(root, this.rows.get(root), occupant, device.id);
180
+ if (settled !== WRITABLE)
181
+ return settled;
182
+ const placed = { id: device.id, owner: device.owner, rev: 0, placedAt };
183
+ this.rows.set(root, { occupant, cell: { role: "writer", lane: "device", device: placed } });
184
+ return { outcome: "bound", device: placed };
185
+ }
186
+ rebindDevice(root, occupant, owner, expectedRev, targetDeviceId, placedAt) {
187
+ const row = this.rows.get(root);
188
+ const settled = settledDeviceRebindOutcome(row, occupant, owner, expectedRev, targetDeviceId);
189
+ if (settled !== WRITABLE)
190
+ return settled;
191
+ const from = row !== undefined ? boundDeviceOf(row.cell)?.id : undefined;
192
+ if (from === undefined)
193
+ throw new Error(`execution placement of session ${root}: the rebind judge found a device cell that is no longer there — refusing to guess`);
194
+ const placed = { id: targetDeviceId, owner, rev: expectedRev + 1, placedAt };
195
+ this.rows.set(root, { occupant, cell: { role: "writer", lane: "device", device: placed } });
196
+ return { outcome: "rebound", device: placed, from };
197
+ }
198
+ }
199
+ //# sourceMappingURL=execution-placement.js.map
@@ -1,5 +1,5 @@
1
1
  /** 冲突的类(闭集)。同一个约束的几个拒点同一个词;新增一类见文件头。 */
2
- export declare const FIELD_CONFLICT_KINDS: readonly ["cascade_verify", "image_profile", "resume_anchor", "system_prompt_fold", "file_history_restore", "skills_disabled", "existing_session", "scratchpad_root", "ask_answer", "policy_person_ask", "plan_edit", "plan_mode_after", "bound_call_door", "remember_decision", "approval_feedback"];
2
+ export declare const FIELD_CONFLICT_KINDS: readonly ["cascade_verify", "image_profile", "resume_anchor", "system_prompt_fold", "file_history_restore", "skills_disabled", "existing_session", "fork_target", "scratchpad_root", "ask_answer", "policy_person_ask", "plan_edit", "plan_mode_after", "bound_call_door", "remember_decision", "approval_feedback"];
3
3
  /** 冲突的类(闭集词)。 */
4
4
  export type FieldConflictKind = (typeof FIELD_CONFLICT_KINDS)[number];
5
5
  /**
@@ -11,9 +11,10 @@ export interface FieldConflictCoordinates {
11
11
  readonly image_profile: "capabilitiesNeeded" | "sandboxImageProfile";
12
12
  readonly resume_anchor: "resumeAtMode" | "resumeAt";
13
13
  readonly system_prompt_fold: "appendSystemPrompt" | "settings.outputStyle";
14
- readonly file_history_restore: "fileHistory" | "restoreFiles" | "rewindFilesTo" | "rewindFiles";
14
+ readonly file_history_restore: "fileHistory" | "restoreFiles" | "rewindFilesTo";
15
15
  readonly skills_disabled: "disableSkills" | "skills" | `agents[${number}].skills`;
16
16
  readonly existing_session: "requireExistingSession" | "sessionId";
17
+ readonly fork_target: "forkId" | "forkNonce";
17
18
  readonly scratchpad_root: "cwd" | "scratchpadDir";
18
19
  readonly ask_answer: "decision" | "answer";
19
20
  readonly policy_person_ask: "decision" | "decidedBy";
@@ -6,6 +6,7 @@ export const FIELD_CONFLICT_KINDS = [
6
6
  "file_history_restore",
7
7
  "skills_disabled",
8
8
  "existing_session",
9
+ "fork_target",
9
10
  "scratchpad_root",
10
11
  "ask_answer",
11
12
  "policy_person_ask",
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 回决门族 200 体上的**结清证据**(`decisionCommitted` / `checkpointId`)—— 唯一铸点与唯一读法。
3
+ *
4
+ * ## 律(一条)
5
+ * `decisionCommitted: true` = 「本请求点名的那道门,已以本请求的决定被耐久地结清过」的**历史证据**。它只在下面五个执行 / 回放边界之一
6
+ * 被跨过的那一拍、由 {@link buildSettlementEvidence} 铸(闭集 {@link SettlementCrossing},`switch` 穷尽):
7
+ * ① `engine_accepted` —— 引擎续跑腿的受理点(`resumeStream` 解析 = 引擎的 pre-CAS 守卫与 checkpoint resolve CAS 都过了);
8
+ * ② `engine_terminal` —— 引擎续跑腿交回结果之后的终局体(同步长调用形 / verify 臂;含「已提交、又重开同一张卡」的 `retriable:true` 那一形);
9
+ * ③ `replay_matched` —— `/decide` 幂等回放比对通过(同一决定早已与 resolve 原子地落在行上;回放不起续跑);
10
+ * ④ `agent_revived` —— 停驻后台子代复活成功(引擎以选中的 token 续跑、attach 之后才交回);
11
+ * ⑤ `card_voided` —— 复活不了的停驻子代被 deny 作废成功(这道门以本 deny **经作废结清**:卡 pending → expired;没有 resolve、没有 deny 结果行)。
12
+ * 调用方对一条引擎续跑腿的分类({@link GateCommitment})只说「这条腿到边界时能证什么」,**从不单独铸位** —— 位要有边界作证。
13
+ * 不铸的出口(都在调用点成文):`checkpoint.resume_aborted` 取消(拿不到 resolve 的返回值 ⇒ 证不出)、抛出臂的取消(受理之后也可能走到 ⇒
14
+ * **刻意不带**证据,fail-closed)、4xx、交给宿主 / 新铸一跑 / 同一决定重投的回执(`delivered`,门由别人结清或仍待决)、停驻子代认领到的
15
+ * token 不是选中的那一张(⇒ `409 decide.gate_moved`,不复活)。证据只随**同一次决定**的回放走:停驻赎回席的反向重试回放摘掉它
16
+ * ({@link withoutSettlementEvidence})。
17
+ *
18
+ * ## 读法(三句,契约 §4a「结清证据」同句)
19
+ * · 位在场 ⇒ 门已以此决定结清过(历史证据;与 `errorCode:"cancelled"` 或 `retriable:true` 并存时同样成立 —— 它不证明卡的**当前**状态、
20
+ * 不证明批过的动作执行了);
21
+ * · 位缺席 ⇒ 证不出或刻意不带,按「没提交」读;
22
+ * · `checkpointId` = 执行**前**从选中的那一行捕获、过信任边界(`checkpoint-identity.ts` 的 `durableRowIdentity`,face `decision-receipt`)
23
+ * 的门身份,只随位出现;缺席 = 身份不可用(老行 / 没过边界)或不适用(回放的投影不带门身份),不推断任何事。
24
+ *
25
+ * ## 读者
26
+ * 本仓两个:`/decide` 的 [ref] 迟到结算留痕与 remember 豁免落店,都经 {@link decisionCommittedOf} 读体上的位(一处读法;不读 `errorCode`)。
27
+ * 纯数据、零运行时依赖(停驻子代腿与 HTTP 层共用)。
28
+ */
29
+ import type { GateIdentity } from "./checkpoint-identity.js";
30
+ /**
31
+ * 一条**引擎续跑腿**到达边界时能证什么(调用方声明;闭集)。`DriveResumeArgs` 的必填位 —— 同一条驱动路径既续本请求点名的门,也替宿主投递。
32
+ * · `gate_resolved` —— 这条腿 resolve 的就是本请求点名的那道门(`/decide` 引擎臂、`/resume`、`/plan_review`);`checkpointId` = 执行前捕获的身份片段。
33
+ * · `delivered` —— 这条腿 resolve 的是宿主的门(wake;含 `/decide` workflow 车道的 wake 投递腿):本请求点名的那道门由别人结清或仍待决 ⇒ 到任何边界都不铸。
34
+ */
35
+ export type GateCommitment = {
36
+ readonly kind: "gate_resolved";
37
+ readonly checkpointId?: string;
38
+ } | {
39
+ readonly kind: "delivered";
40
+ };
41
+ /** 五个边界(铸点穷尽)。引擎两边界按腿的分类铸;回放不带身份;停驻子代两边界的门恒是本请求点名的那道,身份取执行前捕获的那一份。 */
42
+ export type SettlementCrossing = {
43
+ readonly at: "engine_accepted" | "engine_terminal";
44
+ readonly commitment: GateCommitment;
45
+ } | {
46
+ readonly at: "replay_matched";
47
+ } | {
48
+ readonly at: "agent_revived" | "card_voided";
49
+ readonly gate: GateIdentity;
50
+ };
51
+ /** 体上的结清证据(两键都可缺席;wire 只加)。由调用方原样展开进它自己的体形(各体形保持各自的键集,不并进一张受理形)。 */
52
+ export interface GateSettlementEvidence {
53
+ readonly decisionCommitted?: true;
54
+ readonly checkpointId?: string;
55
+ }
56
+ /** 没有跨过任何边界的回执(`/decide` workflow 车道的宿主新一跑、同一决定重投)带的证据:无。 */
57
+ export declare const NO_SETTLEMENT_EVIDENCE: GateSettlementEvidence;
58
+ /** **唯一铸点**:一次边界跨越 → 体上的证据片段。 */
59
+ export declare function buildSettlementEvidence(crossing: SettlementCrossing): GateSettlementEvidence;
60
+ /**
61
+ * 一张已带证据的回执被拿去答**另一个**决定(停驻赎回席的反向重试:回放首次受理的那一向、不改判)⇒ 证据两键都摘掉 ——
62
+ * 证据说的是当初被结清的那次决定,这一次请求的决定从没被结清。同向重试是同一次请求的回放,体原样(证据随它)。
63
+ * 只摘、不铸:本模块之外没有第二个写这两键的地方。
64
+ */
65
+ export declare function withoutSettlementEvidence<B extends Record<string, unknown>>(body: B): Omit<B, keyof GateSettlementEvidence>;
66
+ /** **唯一读法**:这张回决应答说「门已以此决定结清过」吗(`200` 且体上的位为真)。两个读者同调这一只。 */
67
+ export declare function decisionCommittedOf(out: {
68
+ readonly status: number;
69
+ readonly body: object;
70
+ }): boolean;
71
+ //# sourceMappingURL=gate-settlement.d.ts.map
@@ -0,0 +1,40 @@
1
+ export const NO_SETTLEMENT_EVIDENCE = Object.freeze({});
2
+ const settled = (gate) => ({
3
+ decisionCommitted: true,
4
+ ...(gate.checkpointId !== undefined ? { checkpointId: gate.checkpointId } : {}),
5
+ });
6
+ export function buildSettlementEvidence(crossing) {
7
+ switch (crossing.at) {
8
+ case "engine_accepted":
9
+ case "engine_terminal": {
10
+ const c = crossing.commitment;
11
+ switch (c.kind) {
12
+ case "gate_resolved":
13
+ return settled(c);
14
+ case "delivered":
15
+ return NO_SETTLEMENT_EVIDENCE;
16
+ default: {
17
+ const unhandled = c;
18
+ throw new Error(`unhandled gate commitment: ${JSON.stringify(unhandled)}`);
19
+ }
20
+ }
21
+ }
22
+ case "replay_matched":
23
+ return settled({});
24
+ case "agent_revived":
25
+ case "card_voided":
26
+ return settled(crossing.gate);
27
+ default: {
28
+ const unhandled = crossing;
29
+ throw new Error(`unhandled settlement crossing: ${JSON.stringify(unhandled)}`);
30
+ }
31
+ }
32
+ }
33
+ export function withoutSettlementEvidence(body) {
34
+ const { decisionCommitted: _committed, checkpointId: _identity, ...rest } = body;
35
+ return rest;
36
+ }
37
+ export function decisionCommittedOf(out) {
38
+ return out.status === 200 && out.body.decisionCommitted === true;
39
+ }
40
+ //# sourceMappingURL=gate-settlement.js.map
@@ -25,6 +25,7 @@ export declare const CLASSIC_STATION_ROLE: {
25
25
  readonly "classic.UserPromptSubmit": "chain";
26
26
  readonly "classic.Stop": "chain";
27
27
  readonly "classic.SubagentStop": "chain";
28
+ readonly "classic.SubagentStart": "chain";
28
29
  readonly "classic.StopFailure": "observe";
29
30
  readonly "classic.PreCompact": "chain";
30
31
  readonly "classic.PostCompact": "observe";
@@ -6,6 +6,7 @@ export const CLASSIC_STATION_ROLE = {
6
6
  "classic.UserPromptSubmit": "chain",
7
7
  "classic.Stop": "chain",
8
8
  "classic.SubagentStop": "chain",
9
+ "classic.SubagentStart": "chain",
9
10
  "classic.StopFailure": "observe",
10
11
  "classic.PreCompact": "chain",
11
12
  "classic.PostCompact": "observe",
@@ -26,7 +26,7 @@ export declare function commandLineChars(entry: {
26
26
  export declare function hookPluginEnv(p: HookPluginContext | undefined): Record<string, string>;
27
27
  /**
28
28
  * 起法:shell 形交回命令串(shell 由调用点落定),exec 形交回可执行名与参数,起不来交回真因(进调用点的 `spawnError`)。
29
- * `env` = 这条 hook 的**有效环境层**({@link composeHookEnvLayer} 的产物;调用点铺在基础 allowlist 之上,不再自己合并任何一层)。
29
+ * `env` = 这条 hook 的**有效环境层**({@link composeHookEnvLayer} 的产物;调用点把它作为授予交给宿主子进程的唯一组合,不再自己合并任何一层)。
30
30
  */
31
31
  export type CommandSpawnPlan = {
32
32
  readonly kind: "shell";
@@ -42,7 +42,7 @@ export type CommandSpawnPlan = {
42
42
  readonly error: string;
43
43
  };
44
44
  /**
45
- * 一条 command hook 的**有效环境层**(基础 allowlist 之上的那一层)—— **唯一铺法**,后铺者赢:`CLAUDE_PROJECT_DIR` 的缺省(`cwd`,hook 的工作目录;请求没写它才取)< 请求 `settings.env`(`requestEnv`;
45
+ * 一条 command hook 的**有效环境层**(继承之上的那一层授予)—— **唯一铺法**,后铺者赢:`CLAUDE_PROJECT_DIR` 的缺省(`cwd`,hook 的工作目录;请求没写它才取)< 请求 `settings.env`(`requestEnv`;
46
46
  * 请求自己写了 `CLAUDE_PROJECT_DIR` 就是它,空串也照用)< 条目自己的插件上下文({@link hookPluginEnv})。键的枚举顺序 = 请求的键在前、`CLAUDE_PROJECT_DIR` 缺省时接后、插件键最后。调用点传**原料**(工作目录与请求 env),不预先取舍 `CLAUDE_PROJECT_DIR`。
47
47
  * 「有没有值」的判据、exec 形的占位替换、shell 形子进程的环境都读这一个对象(见文件头);http 条目的 `$NAME` 插值取环境也走这一只(无插件上下文)。
48
48
  */