@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,223 @@
1
+ import { isExecutionLane } from "../execution-lane-caps.js";
2
+ import { sessionFaceFromRow } from "../session-incarnation.js";
3
+ import { toIso } from "./sql-row-helpers.js";
4
+ import { WRITABLE, assertPlaceableLane, settledMirrorOutcome, settledPlaceOutcome, } from "../execution-placement.js";
5
+ export const SESSION_META_PLACEMENT_COLUMNS = [
6
+ { name: "execution_role", tidb: "execution_role VARCHAR(16) NULL", pg: `execution_role VARCHAR(16) COLLATE "C"` },
7
+ { name: "execution_lane", tidb: "execution_lane VARCHAR(32) NULL", pg: `execution_lane VARCHAR(32) COLLATE "C"` },
8
+ { name: "execution_device_id", tidb: "execution_device_id VARCHAR(64) NULL", pg: `execution_device_id VARCHAR(64) COLLATE "C"` },
9
+ { name: "execution_device_owner_tenant", tidb: "execution_device_owner_tenant VARCHAR(190) NULL", pg: `execution_device_owner_tenant VARCHAR(190) COLLATE "C"` },
10
+ { name: "execution_device_owner_subject", tidb: "execution_device_owner_subject VARCHAR(190) NULL", pg: `execution_device_owner_subject VARCHAR(190) COLLATE "C"` },
11
+ { name: "execution_placed_at", tidb: "execution_placed_at DATETIME(3) NULL", pg: "execution_placed_at TIMESTAMPTZ(3)" },
12
+ { name: "execution_rev", tidb: "execution_rev BIGINT NULL", pg: "execution_rev BIGINT" },
13
+ { name: "fork_key", tidb: "fork_key VARCHAR(255) NULL", pg: `fork_key VARCHAR(255) COLLATE "C"` },
14
+ ];
15
+ export function sessionMetaPlacementColumnsDdl(dialect) {
16
+ return SESSION_META_PLACEMENT_COLUMNS.map((c) => c[dialect]).join(",\n ");
17
+ }
18
+ const WRITER = "writer";
19
+ const MIRROR = "mirror";
20
+ const NOT_WRITER = "(execution_role IS NULL OR execution_role <> 'writer')";
21
+ export const MIRROR_ON_COMMIT_SET = "execution_role = 'mirror'";
22
+ export const MIRROR_ON_COMMIT_GUARD = NOT_WRITER;
23
+ export function importedRowCells(forkKey) {
24
+ return { columns: "fork_key, execution_role", values: [forkKey, MIRROR] };
25
+ }
26
+ export const SESSION_META_PLACEMENT_READ_COLUMNS = "owner, incarnation, placement_kind, execution_role, execution_lane, execution_device_id, execution_device_owner_tenant, execution_device_owner_subject, execution_placed_at, execution_rev";
27
+ function binder(dialect) {
28
+ const values = [];
29
+ return {
30
+ values,
31
+ p: (v) => {
32
+ values.push(v);
33
+ return dialect === "pg" ? `$${values.length}` : "?";
34
+ },
35
+ };
36
+ }
37
+ function occupantPredicate(dialect, p, root, occupant) {
38
+ const nullSafeEq = dialect === "pg" ? "IS NOT DISTINCT FROM" : "<=>";
39
+ return `session_id = ${p(root)} AND incarnation = ${p(occupant.incarnation)} AND owner ${nullSafeEq} ${p(occupant.owner)} AND placement_kind IS NULL`;
40
+ }
41
+ export function readPlacementRowStatement(dialect, root, opts) {
42
+ const b = binder(dialect);
43
+ return { text: `SELECT ${SESSION_META_PLACEMENT_READ_COLUMNS} FROM session_meta WHERE session_id = ${b.p(root)}${opts.lock ? " FOR UPDATE" : ""}`, values: b.values };
44
+ }
45
+ export function placeWriterStatement(dialect, root, occupant, cell, now) {
46
+ const b = binder(dialect);
47
+ const set = `execution_role = '${WRITER}', execution_lane = ${b.p(cell.lane)}, execution_device_id = ${b.p(cell.device?.id ?? null)}, ` +
48
+ `execution_device_owner_tenant = ${b.p(cell.device?.owner.tenant ?? null)}, execution_device_owner_subject = ${b.p(cell.device?.owner.subject ?? null)}, ` +
49
+ `execution_placed_at = ${b.p(now)}, execution_rev = 0`;
50
+ return { text: `UPDATE session_meta SET ${set} WHERE ${occupantPredicate(dialect, b.p, root, occupant)} AND execution_role IS NULL`, values: b.values };
51
+ }
52
+ export function bindDeviceStatement(dialect, root, occupant, device, now) {
53
+ const b = binder(dialect);
54
+ const set = `execution_device_id = ${b.p(device.id)}, execution_device_owner_tenant = ${b.p(device.owner.tenant)}, execution_device_owner_subject = ${b.p(device.owner.subject)}, execution_placed_at = ${b.p(now)}, execution_rev = 0`;
55
+ return {
56
+ text: `UPDATE session_meta SET ${set} WHERE ${occupantPredicate(dialect, b.p, root, occupant)} AND execution_role = '${WRITER}' AND execution_lane = 'device' AND execution_device_id IS NULL`,
57
+ values: b.values,
58
+ };
59
+ }
60
+ export function rebindDeviceStatement(dialect, root, occupant, owner, expectedRev, targetDeviceId, now) {
61
+ const b = binder(dialect);
62
+ const set = `execution_device_id = ${b.p(targetDeviceId)}, execution_placed_at = ${b.p(now)}, execution_rev = execution_rev + 1`;
63
+ const where = `${occupantPredicate(dialect, b.p, root, occupant)} AND execution_role = '${WRITER}' AND execution_lane = 'device' ` +
64
+ `AND execution_device_owner_tenant = ${b.p(owner.tenant)} AND execution_device_owner_subject = ${b.p(owner.subject)} AND execution_rev = ${b.p(expectedRev)}`;
65
+ return { text: `UPDATE session_meta SET ${set} WHERE ${where}`, values: b.values };
66
+ }
67
+ export function markMirrorStatement(dialect, root, occupant) {
68
+ const b = binder(dialect);
69
+ return { text: `UPDATE session_meta SET execution_role = '${MIRROR}' WHERE ${occupantPredicate(dialect, b.p, root, occupant)} AND ${NOT_WRITER}`, values: b.values };
70
+ }
71
+ export function backfillWriterStatement(dialect, lane, now) {
72
+ const b = binder(dialect);
73
+ return {
74
+ text: `UPDATE session_meta SET execution_role = '${WRITER}', execution_lane = ${b.p(lane)}, execution_placed_at = ${b.p(now)}, execution_rev = 0 ` +
75
+ "WHERE execution_role IS NULL AND placement_kind IS NULL AND EXISTS (SELECT 1 FROM task_run tr WHERE tr.session_id = session_meta.session_id)",
76
+ values: b.values,
77
+ };
78
+ }
79
+ export function migrateDeviceBindingsStatement(dialect, sourceTable) {
80
+ if (dialect === "pg") {
81
+ return {
82
+ text: `UPDATE session_meta SET execution_role = '${WRITER}', execution_lane = 'device', execution_device_id = ds.device_id, ` +
83
+ "execution_device_owner_tenant = ds.owner_tenant, execution_device_owner_subject = ds.owner_subject, execution_placed_at = ds.bound_at, execution_rev = ds.rev " +
84
+ `FROM ${sourceTable} ds WHERE ds.root_session_id = session_meta.session_id AND session_meta.placement_kind IS NULL`,
85
+ values: [],
86
+ };
87
+ }
88
+ const str = (col) => `CONVERT(ds.${col} USING utf8mb4)`;
89
+ return {
90
+ text: `UPDATE session_meta sm JOIN ${sourceTable} ds ON ${str("root_session_id")} COLLATE utf8mb4_bin = sm.session_id ` +
91
+ `SET sm.execution_role = '${WRITER}', sm.execution_lane = 'device', sm.execution_device_id = ${str("device_id")}, ` +
92
+ `sm.execution_device_owner_tenant = ${str("owner_tenant")}, sm.execution_device_owner_subject = ${str("owner_subject")}, sm.execution_placed_at = ds.bound_at, sm.execution_rev = ds.rev ` +
93
+ "WHERE sm.placement_kind IS NULL",
94
+ values: [],
95
+ };
96
+ }
97
+ export function countOrphanBindingsStatement(dialect, sourceTable) {
98
+ const rootKey = dialect === "pg" ? "ds.root_session_id" : "CONVERT(ds.root_session_id USING utf8mb4) COLLATE utf8mb4_bin";
99
+ return {
100
+ text: `SELECT COUNT(*) AS orphans FROM ${sourceTable} ds WHERE NOT EXISTS (SELECT 1 FROM session_meta sm WHERE sm.session_id = ${rootKey} AND sm.placement_kind IS NULL)`,
101
+ values: [],
102
+ };
103
+ }
104
+ export class ExecutionPlacementRowError extends Error {
105
+ sessionId;
106
+ code = "execution_placement.row_unreadable";
107
+ constructor(sessionId, detail) {
108
+ super(`session ${sessionId}: the execution placement columns do not form a placement (${detail}) — refusing to read it as any placement`);
109
+ this.sessionId = sessionId;
110
+ this.name = "ExecutionPlacementRowError";
111
+ }
112
+ }
113
+ const isNull = (v) => v === null || v === undefined;
114
+ const text = (v) => (Buffer.isBuffer(v) ? v.toString("utf8") : String(v));
115
+ export function placementCellFromRow(root, row) {
116
+ const role = row.execution_role;
117
+ const deviceCols = [row.execution_device_id, row.execution_device_owner_tenant, row.execution_device_owner_subject];
118
+ if (isNull(role) || role === MIRROR) {
119
+ if (!isNull(row.execution_lane) || deviceCols.some((v) => !isNull(v)))
120
+ throw new ExecutionPlacementRowError(root, `role ${isNull(role) ? "NULL" : MIRROR} with a lane or device`);
121
+ return isNull(role) ? { role: "absent" } : { role: "mirror" };
122
+ }
123
+ if (role !== WRITER)
124
+ throw new ExecutionPlacementRowError(root, `role ${JSON.stringify(text(role))} is not writer / mirror / NULL`);
125
+ const lane = isNull(row.execution_lane) ? "" : text(row.execution_lane);
126
+ if (!isExecutionLane(lane))
127
+ throw new ExecutionPlacementRowError(root, `writer lane ${JSON.stringify(lane)} is not an execution lane`);
128
+ if (isNull(row.execution_device_id)) {
129
+ if (deviceCols.some((v) => !isNull(v)))
130
+ throw new ExecutionPlacementRowError(root, "device owner without a device");
131
+ return { role: "writer", lane };
132
+ }
133
+ if (lane !== "device")
134
+ throw new ExecutionPlacementRowError(root, `a device on the ${lane} lane`);
135
+ if (deviceCols.some(isNull) || isNull(row.execution_rev) || isNull(row.execution_placed_at))
136
+ throw new ExecutionPlacementRowError(root, "a device without its owner, rev or placement time");
137
+ return {
138
+ role: "writer",
139
+ lane,
140
+ device: {
141
+ id: text(row.execution_device_id),
142
+ owner: { tenant: text(row.execution_device_owner_tenant), subject: text(row.execution_device_owner_subject) },
143
+ rev: Number(row.execution_rev),
144
+ placedAt: toIso(row.execution_placed_at),
145
+ },
146
+ };
147
+ }
148
+ export function placementReadingFromRow(root, row) {
149
+ if (row === undefined || !isNull(row.placement_kind))
150
+ return undefined;
151
+ return { occupant: sessionFaceFromRow(root, isNull(row.owner) ? null : text(row.owner), row.incarnation), cell: placementCellFromRow(root, row) };
152
+ }
153
+ export function rowsOnSqlExec(exec) {
154
+ return async (sql, values) => (await exec.query(sql, [...values])).rows;
155
+ }
156
+ export async function lockRootAndReadClaim(conn, dialect, root) {
157
+ const ph = dialect === "pg" ? "$1" : "?";
158
+ const row = await conn(`SELECT session_id FROM session_meta WHERE session_id = ${ph} FOR UPDATE`, [root]);
159
+ if (row.length === 0)
160
+ return { rowPresent: false, activeTaskId: null };
161
+ const claim = await conn(`SELECT task_id FROM task_active WHERE session_id = ${ph} FOR UPDATE`, [root]);
162
+ return { rowPresent: true, activeTaskId: claim[0] === undefined ? null : text(claim[0].task_id) };
163
+ }
164
+ export async function readPlacementOn(conn, dialect, root) {
165
+ const s = readPlacementRowStatement(dialect, root, { lock: true });
166
+ return placementReadingFromRow(root, (await conn(s.text, s.values))[0]);
167
+ }
168
+ function placementInvariant(root, what) {
169
+ return new Error(`execution placement of session ${root}: ${what} matched no row while a re-read finds the cell writable — engine/driver anomaly, refusing to guess`);
170
+ }
171
+ export function createSqlExecutionPlacementSeat(db) {
172
+ const read = async (root) => {
173
+ const s = readPlacementRowStatement(db.dialect, root, { lock: false });
174
+ return placementReadingFromRow(root, (await db.query(s.text, [...s.values])).rows[0]);
175
+ };
176
+ return {
177
+ read,
178
+ async place(root, occupant, cell) {
179
+ assertPlaceableLane(root, cell);
180
+ const s = placeWriterStatement(db.dialect, root, occupant, { lane: cell.lane }, new Date());
181
+ if ((await db.query(s.text, [...s.values])).affected === 1)
182
+ return { outcome: "placed" };
183
+ const settled = settledPlaceOutcome(root, await read(root), occupant, cell);
184
+ if (settled === WRITABLE)
185
+ throw placementInvariant(root, "place");
186
+ return settled;
187
+ },
188
+ async markMirror(root, occupant) {
189
+ const conn = await db.connect();
190
+ try {
191
+ await conn.begin();
192
+ const rowsOn = rowsOnSqlExec(conn);
193
+ const claim = await lockRootAndReadClaim(rowsOn, db.dialect, root);
194
+ if (!claim.rowPresent) {
195
+ await conn.rollback();
196
+ return { outcome: "gone" };
197
+ }
198
+ const settled = settledMirrorOutcome(root, await readPlacementOn(rowsOn, db.dialect, root), occupant);
199
+ if (settled !== WRITABLE) {
200
+ await conn.rollback();
201
+ return settled;
202
+ }
203
+ if (claim.activeTaskId !== null) {
204
+ await conn.rollback();
205
+ return { outcome: "active", activeTaskId: claim.activeTaskId };
206
+ }
207
+ const s = markMirrorStatement(db.dialect, root, occupant);
208
+ if ((await conn.query(s.text, [...s.values])).affected !== 1)
209
+ throw placementInvariant(root, "markMirror under a held row lock");
210
+ await conn.commit();
211
+ return { outcome: "mirrored" };
212
+ }
213
+ catch (err) {
214
+ await conn.rollback().catch(() => undefined);
215
+ throw err;
216
+ }
217
+ finally {
218
+ conn.release();
219
+ }
220
+ },
221
+ };
222
+ }
223
+ //# sourceMappingURL=execution-placement-sql.js.map
@@ -183,15 +183,16 @@ export declare class PgFileHistoryStore extends SqlFileHistoryStore {
183
183
  }
184
184
  /**
185
185
  * [ref] D1② — A7-recipe upgrade precondition assert (**refuse to start**, never a warn; the form and
186
- * rationale follow `assertPermissionRuleTicketSchema` verbatim: this repo ships no ALTER TABLE, and
186
+ * rationale follow `assertPermissionRuleTicketSchema` verbatim: the boot check never alters a table, and
187
187
  * `CREATE TABLE IF NOT EXISTS` is a no-op on an existing table whose columns predate this build).
188
188
  *
189
189
  * The probe is one always-empty `WHERE 1=0` read per table naming every column this build references.
190
- * ONLY a provable missing-column error gets the destructive recreate guidance — everything else
191
- * (timeout / reset / permission / missing table) rethrows untouched: advising `DROP TABLE` for a
192
- * connection blip is more expensive than the defect this gate exists to stop. Honest cost statement:
193
- * dropping these tables loses per-file REWIND history (working-tree convenience state) — session
194
- * transcripts and every other durable subsystem are untouched.
190
+ * ONLY a provable missing-column error gets the missing-column refusal — everything else
191
+ * (timeout / reset / permission / missing table) rethrows untouched: diagnosing a connection blip as a
192
+ * schema drift is more expensive than the defect this gate exists to stop. The refusal's ways out are the
193
+ * closed set of three shared with the whole-database check (`describeProbedTableDrift`); none of them
194
+ * is destructive. Honest cost statement: the history lives in these tables (per-file REWIND history,
195
+ * working-tree convenience state) — session transcripts and every other durable subsystem are untouched.
195
196
  */
196
197
  export declare function assertFileHistorySchema(query: (sql: string) => Promise<{
197
198
  rows: Record<string, unknown>[];
@@ -3,6 +3,7 @@ import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenD
3
3
  import { BlobTooLargeError, SqlBlobBackend } from "./blob-backend.js";
4
4
  import { mysqlDriver, pgDriver } from "./sql-driver.js";
5
5
  import { isMissingColumnError } from "./sql-errors.js";
6
+ import { describeProbedTableDrift } from "./schema-drift-sentence.js";
6
7
  import { recordFailOpen } from "../observability/fail-open.js";
7
8
  import { foldCaughtFailure } from "../file-history-disclosure.js";
8
9
  export const FILE_HISTORY_BLOB_TABLE = "file_history_blob";
@@ -721,12 +722,13 @@ export class SqlFileHistoryStore {
721
722
  bytes = await srcGetBlob(hash);
722
723
  }
723
724
  catch (err) {
724
- return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${foldCaughtFailure(err).text}` } };
725
+ const f = foldCaughtFailure(err);
726
+ return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${f.text}`, ...f.fault } };
725
727
  }
726
728
  if (bytes === undefined)
727
729
  return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
728
730
  if (sha256hex(bytes) !== hash) {
729
- return { ok: false, error: { code: "unsupported_format", message: `source blob ${hash} fails content-address integrity — refused, nothing published` } };
731
+ return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} served bytes that do not hash to its address — the source cannot supply this blob, so nothing is published` } };
730
732
  }
731
733
  await onVerified?.(hash, bytes);
732
734
  }
@@ -834,11 +836,10 @@ export async function assertFileHistorySchema(query, dialect) {
834
836
  throw err;
835
837
  throw new Error(`${table} is missing required columns — refusing to start. This build's per-file rewind history (S-15) ` +
836
838
  `references every probed column unconditionally; a partial table would fail mid-write and could publish a ` +
837
- `half-shaped history graph. This repository ships no ALTER TABLE migrations, so the table must be recreated: run ` +
838
- `\`DROP TABLE ${table};\` on the ${dialect === "pg" ? "PostgreSQL" : "MySQL-protocol"} backend and restart — the ` +
839
- `schema is recreated at boot. Cost, honestly stated: dropping file_history_* tables loses per-file REWIND history ` +
840
- `(working-tree convenience state); session transcripts and all other durable subsystems are untouched. ` +
841
- `Underlying probe error: ${err instanceof Error ? err.message : String(err)}`);
839
+ `half-shaped history graph. The file_history_* tables hold the per-file REWIND history (working-tree convenience ` +
840
+ `state); session transcripts and all other durable subsystems are untouched, and an in-place ALTER keeps the history.\n` +
841
+ `Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
842
+ (await describeProbedTableDrift(query, dialect, [table])));
842
843
  }
843
844
  }
844
845
  }
@@ -152,7 +152,7 @@ export declare class FileRunStore implements InProcessClaimFence {
152
152
  whileHoldingClaim(sessionId: string, taskId: string, write: () => FenceLanded): boolean;
153
153
  getRun(taskId: string): Promise<RunRecord | undefined>;
154
154
  /** Undo THIS submission's binding (key + body fingerprint → null) — called only where the submit surface refuses the submission
155
- * before any work and terminalizes the row it just claimed (the sync leg's zero-work refusal, a device-placement reject):
155
+ * before any work and terminalizes the row it just claimed (the sync leg's zero-work refusal, an execution-placement reject):
156
156
  * the error answer invites a retry, and a retry with the same key must run, not replay the refusal. The row stays (it
157
157
  * is the refusal's record); only the binding is freed. */
158
158
  releaseIdemKey(taskId: string): Promise<void>;
@@ -332,6 +332,11 @@ export declare class FileRunStore implements InProcessClaimFence {
332
332
  * 起服时调(`LocalBackend.runOneTimeMigrations`,任何读者之前);数据根独占 ⇒ 本车道没有滚动升级窗,不需要读侧半场。幂等:第二跑零命中零写盘。
333
333
  */
334
334
  migrateLegacyHolderDeathCodes(): number;
335
+ /**
336
+ * 一次性迁移 **M32 的 local 腿**(执行放置回填;窗、删法与删后谁接住:窗口见 `plugins/one-time-migrations.ts` 登记表):有 run 行的会话 id(去重)。
337
+ * 起服时调(`LocalBackend.runOneTimeMigrations`,任何读者之前);读内存索引(构造时已从盘上 hydrate),零写。
338
+ */
339
+ sessionIdsWithRuns(): ReadonlySet<string>;
335
340
  /** Release every open event-log fd (called by LocalBackend.close so a graceful restart can re-open the data dir). */
336
341
  dispose(): void;
337
342
  }
@@ -280,6 +280,7 @@ export class FileRunStore {
280
280
  "Refusing to boot with an EMPTY single-active claim index (every session would look unclaimed, so a delete or a fresh run could race a live/parked one). " +
281
281
  "Fix the permissions/mount on that path, point LOCAL_DATA_ROOT at a readable dir, or unset RUN_STORE_STRICT_HYDRATE to boot anyway (the pre-existing behavior).");
282
282
  }
283
+ recordFailOpen("server.run-store.file-active-claims-unreadable", detail);
283
284
  claims = [];
284
285
  }
285
286
  const nonTerminalBySanitizedSession = new Map();
@@ -1009,6 +1010,9 @@ export class FileRunStore {
1009
1010
  }
1010
1011
  return migrated;
1011
1012
  }
1013
+ sessionIdsWithRuns() {
1014
+ return new Set([...this.runs.values()].map((r) => r.sessionId));
1015
+ }
1012
1016
  dispose() {
1013
1017
  for (const log of this.eventLogs.values()) {
1014
1018
  try {
@@ -25,6 +25,8 @@
25
25
  */
26
26
  import { type SessionStore, type AcquiredSession, type SessionStoreSummary, type SessionPlacement, type PlacedSessionRow } from "@sema-agent/core";
27
27
  import { type DelegationTree } from "../delegated-session-owner.js";
28
+ import type { ExecutionPlacementSeat } from "../execution-placement.js";
29
+ import type { ForkToFn } from "./session-fork.js";
28
30
  /** acquire 选项形(core 5.48 SessionStore 契约):[ref] placement=受信 spawner 的分区建会话声明。 */
29
31
  type AcquireOpts = {
30
32
  requireExisting?: boolean;
@@ -54,6 +56,10 @@ export declare class ForkRoutingSessionStore implements SessionStore {
54
56
  olderThanMs?: number;
55
57
  scope?: string;
56
58
  }) => Promise<PlacedSessionRow[]>;
59
+ /** 执行席透传(host 有才有):执行放置是**根会话行**上的一格,根会话行住 host durable 店;transient 店没有会话行可放,也就不声明席。 */
60
+ readonly executionPlacement?: ExecutionPlacementSeat;
61
+ /** fork 续写的店契约透传(host 有才有):目标在 host 店原子新建,新 id 与源一并记 host 路由(与 {@link fork} 的 host 腿同)。 */
62
+ readonly forkTo?: ForkToFn;
57
63
  constructor(host: SessionStore, transient: SessionStore);
58
64
  private remember;
59
65
  private pick;
@@ -11,6 +11,8 @@ export class ForkRoutingSessionStore {
11
11
  placed = new Set();
12
12
  placements;
13
13
  listPlaced;
14
+ executionPlacement;
15
+ forkTo;
14
16
  constructor(host, transient) {
15
17
  this.host = host;
16
18
  this.transient = transient;
@@ -23,6 +25,20 @@ export class ForkRoutingSessionStore {
23
25
  if (host.fork === undefined && transient.fork === undefined) {
24
26
  this.fork = undefined;
25
27
  }
28
+ const hostFaces = host;
29
+ if (hostFaces.executionPlacement !== undefined)
30
+ this.executionPlacement = hostFaces.executionPlacement;
31
+ const hostForkTo = hostFaces.forkTo;
32
+ if (typeof hostForkTo === "function") {
33
+ this.forkTo = async (sourceId, owner, target) => {
34
+ const out = await hostForkTo.call(host, sourceId, owner, target);
35
+ if (out !== null && out.outcome !== "occupied") {
36
+ this.remember(sourceId, "host");
37
+ this.remember(out.id, "host");
38
+ }
39
+ return out;
40
+ };
41
+ }
26
42
  }
27
43
  remember(id, where) {
28
44
  this.route.delete(id);
@@ -7,9 +7,9 @@
7
7
  * 法(只删两形;判决链的缺省臂是「不动作」,删必须被显式选中 —— 销毁不可逆,拿不准恒不删,与 E2B 孤儿回收同一方向纪律):
8
8
  * ② `status.phase ∈ {Succeeded, Failed}` —— 容器已全部结束,删它不掐断任何东西;不看 run、不看标签;
9
9
  * ① 带 run 标签(`sema.io/run`,只有顶层 run 的 Pod 带)、run 行在 server 店里**已是终态**,且自 run 行**转终态的时刻**(行上的 `updatedAt` ——
10
- * 三只 run 店的终态写当拍盖它)起超过**这只 Pod 自带的**上界:`max(租约上限 + 宽限 = 6 min, 工作区快照时限 + 引擎拆环境放行 15 s)`
10
+ * 三只 run 店的终态写当拍盖它)起超过**这只 Pod 自带的**上界:`max(租约上限 + 宽限 = 6 min, 工作区快照时限 + 引擎拆环境放行 `teardownLegBudget()`)`
11
11
  * ({@link sandboxRunEndHoldMs};租约上限 = 凭据代理的租约律那一只 `LEASE_TTL_MAX_MS`,本模块不另立)。
12
- * 第二项是 run 收尾的 `destroy()` 在终态之后还可能在 Pod 上存快照的最长时间(引擎的拆环境腿 15 s 放行、run 随即落终态,快照按数据时限接着跑)——
12
+ * 第二项是 run 收尾的 `destroy()` 在终态之后还可能在 Pod 上存快照的最长时间(引擎的拆环境腿按 `teardownLegBudget()` 放行、run 随即落终态,快照按数据时限接着跑)——
13
13
  * 那个数据时限是**建这只 Pod 的副本**的配置,所以上界**随 Pod 走、写一次读一次**:适配器建 Pod 时按自己的快照时限算一次、写进注解
14
14
  * `sema.io/run-end-hold-ms`(`k8s-exec-protocol.ts` `SANDBOX_RUN_END_HOLD_ANNOTATION`),回收器只读 Pod 自带的这一格,**从不**读回收器所在副本的配置
15
15
  * (列举是整个命名空间的 Pod:滚动改 `WORKSPACE_SNAPSHOT_TIMEOUT_MS` 时,一个时限短的副本不得替时限长的副本判它的 Pod)。
@@ -31,12 +31,6 @@ import type { Logger } from "../observability/logger.js";
31
31
  import type { Metrics } from "../observability/metrics.js";
32
32
  /** ① 的宽限(在租约上限之外再等的一段)。常量。 */
33
33
  export declare const SANDBOX_POD_REAP_GRACE_MS = 60000;
34
- /**
35
- * 引擎在 run 收尾时给「拆执行环境」那条腿的放行时限:超过它 run 照样落终态,`destroy()` 脱离着继续跑。值 = core 的 `TEARDOWN_LEG_MAX_MS`
36
- * (`dist/core/runner/teardown-bounded.js`)—— core 不从包根导出它(包的 exports 只有 `.` / `./bench` / `./fixtures`),本仓只能照抄这一个数;
37
- * 收口 = 向 core 要一个包根读口后改读、删本常量。
38
- */
39
- export declare const ENGINE_TEARDOWN_RELEASE_MS = 15000;
40
34
  /** ① 的上界:`max(租约上限 + 宽限, 快照时限 + 引擎拆环境放行)`。唯一的调用方 = 适配器建 Pod 的那一拍(快照时限 = 建它的副本的 `dataTimeoutMs`),结果写进 Pod 的注解。 */
41
35
  export declare function sandboxRunEndHoldMs(snapshotTimeoutMs: number): number;
42
36
  /** 一个副本两轮回收之间的间隔。常量。 */
@@ -3,12 +3,12 @@ import { reportPodDeleteFailed } from "./k8s-pod-delete-failure.js";
3
3
  import { runStatusClassOf } from "./store-contracts.js";
4
4
  import { LEASE_TTL_MAX_MS } from "../broker/lease-file.js";
5
5
  import { WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE } from "../workspace-space.js";
6
+ import { teardownLegBudget } from "@sema-agent/core";
6
7
  export const SANDBOX_POD_REAP_GRACE_MS = 60_000;
7
- export const ENGINE_TEARDOWN_RELEASE_MS = 15_000;
8
8
  export function sandboxRunEndHoldMs(snapshotTimeoutMs) {
9
- return Math.max(LEASE_TTL_MAX_MS + SANDBOX_POD_REAP_GRACE_MS, snapshotTimeoutMs + ENGINE_TEARDOWN_RELEASE_MS);
9
+ return Math.max(LEASE_TTL_MAX_MS + SANDBOX_POD_REAP_GRACE_MS, snapshotTimeoutMs + teardownLegBudget());
10
10
  }
11
- const RUN_END_HOLD_READABLE = { min: LEASE_TTL_MAX_MS + SANDBOX_POD_REAP_GRACE_MS, max: WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE.max + ENGINE_TEARDOWN_RELEASE_MS };
11
+ const RUN_END_HOLD_READABLE = { min: LEASE_TTL_MAX_MS + SANDBOX_POD_REAP_GRACE_MS, max: WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE.max + teardownLegBudget() };
12
12
  function runEndHoldOf(raw) {
13
13
  if (raw === undefined || !/^[0-9]{1,16}$/.test(raw))
14
14
  return undefined;
@@ -32,17 +32,7 @@ export declare class LocalCheckpointStore {
32
32
  */
33
33
  readonly fidelity: StoreFidelity;
34
34
  /**
35
- * `CheckpointStore.redecision` 声明(core 5.22.0 F-012 L2/L3;[ref] clay 裁放行)——**如实按内核判**,
36
- * 与 durability/fidelity 同一条判据:内核 core `FileCheckpointStore` **自己**声明 `{ reopen: true }`,
37
- * 本类的 {@link LocalCheckpointStore.reopen} 纯委派给它 ⇒ 抄内核的读数是诚实的。包装类**不继承**被
38
- * 包装者的声明(委派不是子类),所以这一格必须自己写。`validatingLease` 不声明(内核也没声明)。
39
- * 翻向钉:`wiring-governance-operator.test.ts`(修前恰红,与本声明同 commit)。
40
- */
41
- readonly redecision: {
42
- readonly reopen: true;
43
- };
44
- /**
45
- * `CheckpointStore.execution` 声明(core 7.7.0 [ref];[ref])——**必填**,与上面三格同一条判据:**如实
35
+ * `CheckpointStore.execution` 声明(core 7.7.0 [ref];[ref])——**必填**,与上面两格同一条判据:**如实
46
36
  * 按内核判**。内核 core `FileCheckpointStore` 自己声明 `{ outcome: true }`,并把执行记录落成 ledger 的
47
37
  * 一个新事件种类(`execution`,与 resolve 同款「先 append+fsync 再翻内存」的崩溃序),
48
38
  * {@link LocalCheckpointStore.recordExecutionOutcome} 与 {@link LocalCheckpointStore.reopen} 都是纯委派
@@ -49,7 +49,6 @@ export class LocalCheckpointStore {
49
49
  retention = UNMANAGED_RETENTION;
50
50
  durability = "durable";
51
51
  fidelity = "json";
52
- redecision = { reopen: true };
53
52
  execution = { outcome: true };
54
53
  inner;
55
54
  scopesPath;