@sema-agent/server 7.136.0 → 7.138.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 (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  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 +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  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/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -29,4 +29,42 @@ export function readPlainStringRecord(v) {
29
29
  }
30
30
  return { ok: true, record, stripped };
31
31
  }
32
+ export function declarationKeys(table) {
33
+ return Object.freeze(Object.keys(table));
34
+ }
35
+ export function splitDeclaration(declaration, table) {
36
+ const dispositions = table;
37
+ const engine = {};
38
+ let pieces;
39
+ let seatSeen = false;
40
+ for (const [key, value] of Object.entries(declaration)) {
41
+ if (value === undefined)
42
+ continue;
43
+ const disposition = Object.hasOwn(dispositions, key) ? dispositions[key] : undefined;
44
+ switch (disposition) {
45
+ case "engine":
46
+ engine[key] = value;
47
+ break;
48
+ case "seat": {
49
+ if (seatSeen)
50
+ throw new Error("request declaration: two members are marked as pieces in one disposition table");
51
+ seatSeen = true;
52
+ const record = value;
53
+ if (Object.keys(record).length > 0)
54
+ pieces = record;
55
+ break;
56
+ }
57
+ case "withheld":
58
+ break;
59
+ case undefined:
60
+ throw new Error(`request declaration: a member the disposition table does not classify (${JSON.stringify(key.slice(0, 40))})`);
61
+ default: {
62
+ const unknownDisposition = disposition;
63
+ void unknownDisposition;
64
+ throw new Error("request declaration: a disposition outside the closed set");
65
+ }
66
+ }
67
+ }
68
+ return { engine: engine, ...(pieces === undefined ? {} : { pieces }) };
69
+ }
32
70
  //# sourceMappingURL=plain-string-record.js.map
@@ -3,6 +3,7 @@ import { pgSafeJsonStringify, pgSanitizeText } from "./pg-safe-json.js";
3
3
  import { isMysqlDupKeyError } from "./sql-errors.js";
4
4
  import { ensureIndexes } from "./ensure-index.js";
5
5
  import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
6
+ import { backgroundAgentNameOf } from "../background-agent-name.js";
6
7
  export const BACKGROUND_AGENT_TABLE = "background_agent";
7
8
  function summaryCols(dialect) {
8
9
  return ("handle, owner, session_scoped, session_id, parent_session_id, root_session_id, name, agent_type, status, " +
@@ -11,12 +12,14 @@ function summaryCols(dialect) {
11
12
  const readAgentRecordBody = createObjectColumnReader();
12
13
  const readUsageBody = createObjectColumnReader();
13
14
  function readRecordColumn(v, handle) {
15
+ let record;
14
16
  try {
15
- return decodeJsonColumn(v, readAgentRecordBody, `${BACKGROUND_AGENT_TABLE}.record_json for handle ${handle}`);
17
+ record = decodeJsonColumn(v, readAgentRecordBody, `${BACKGROUND_AGENT_TABLE}.record_json for handle ${handle}`);
16
18
  }
17
19
  catch (e) {
18
20
  throw foldJsonColumn(e, (m) => `BackgroundAgentStore: ${m} — refusing rather than serve a hollow agent record`);
19
21
  }
22
+ return { ...record, name: backgroundAgentNameOf(record) };
20
23
  }
21
24
  function readUsageColumn(v, handle) {
22
25
  try {
@@ -45,7 +48,7 @@ function projParams(stored, json, text) {
45
48
  stored.parentSessionId ?? null,
46
49
  stored.rootSessionId ?? null,
47
50
  (stored.sessionScoped ? stored.owner : stored.parentSessionId) ?? null,
48
- stored.name !== undefined ? text(stored.name).slice(0, 255) : null,
51
+ text(backgroundAgentNameOf(stored)).slice(0, 255),
49
52
  stored.agentType !== undefined ? text(stored.agentType).slice(0, 190) : null,
50
53
  stored.status,
51
54
  stored.spawnedAt,
@@ -68,7 +71,7 @@ function rowToSummary(r) {
68
71
  ...(r.session_id !== null && r.session_id !== undefined ? { sessionId: String(r.session_id) } : {}),
69
72
  ...(r.parent_session_id !== null && r.parent_session_id !== undefined ? { parentSessionId: String(r.parent_session_id) } : {}),
70
73
  ...(r.root_session_id !== null && r.root_session_id !== undefined ? { rootSessionId: String(r.root_session_id) } : {}),
71
- ...(r.name !== null && r.name !== undefined ? { name: String(r.name) } : {}),
74
+ name: backgroundAgentNameOf({ handle: String(r.handle), ...(r.name !== null && r.name !== undefined ? { name: String(r.name) } : {}) }),
72
75
  ...(r.agent_type !== null && r.agent_type !== undefined ? { agentType: String(r.agent_type) } : {}),
73
76
  status: String(r.status),
74
77
  spawnedAt: Number(r.spawned_at_ms),
@@ -3,6 +3,7 @@ import type { OwnerAwareSessionStore, SessionListItem } from "../security.js";
3
3
  import type { StagingHandle } from "../session-sync-kernel.js";
4
4
  import { type PlacementAcquireOpts } from "./session-placement.js";
5
5
  import type { InstructionSourceStore } from "../instruction-source-notice.js";
6
+ import type { SessionWorkspaceStore } from "../session-workspace.js";
6
7
  import type { OwnerlessClaim } from "../delegated-session-owner.js";
7
8
  export interface CachingOptions {
8
9
  /** Idle seconds a woken session is kept warm. 0 disables caching (pure passthrough). */
@@ -85,6 +86,10 @@ export declare class CachingSessionStore implements SessionStore {
85
86
  * 而装配点按「店上两个方法都在」判席 —— 不转发 = 默认部署上换源通告**静默不发**,且没有任何一处报错。 */
86
87
  readonly readInstructionSource?: InstructionSourceStore["readInstructionSource"];
87
88
  readonly recordInstructionSource?: InstructionSourceStore["recordInstructionSource"];
89
+ /** 会话行的位置与项目那一格(`session_meta.workspace` / local sidecar;`session-workspace.ts`),纯转发、不经暖缓存。
90
+ * 🔴 必须转发(同上一条教训):装配点与 resolveSpec 按「店上两个方法都在」判这一面 —— 不转发 = 默认部署上不记行、续跑腿不续声明项目,且没有任何一处报错。 */
91
+ readonly readSessionWorkspace?: SessionWorkspaceStore["readSessionWorkspace"];
92
+ readonly recordSessionWorkspace?: SessionWorkspaceStore["recordSessionWorkspace"];
88
93
  /** 2c session-sync — delegated export/import seam, DURABLE (bypasses the warm cache exactly like
89
94
  * list/fork: an export reads the full durable log, an import writes durable state). */
90
95
  readonly exportEntries?: (sessionId: string) => Promise<SessionTreeEntry[] | null>;
@@ -19,6 +19,8 @@ export class CachingSessionStore {
19
19
  probeTitle;
20
20
  readInstructionSource;
21
21
  recordInstructionSource;
22
+ readSessionWorkspace;
23
+ recordSessionWorkspace;
22
24
  exportEntries;
23
25
  listEntryIds;
24
26
  exportEntriesStream;
@@ -65,6 +67,10 @@ export class CachingSessionStore {
65
67
  this.readInstructionSource = ownerAware.readInstructionSource.bind(inner);
66
68
  if (ownerAware.recordInstructionSource)
67
69
  this.recordInstructionSource = ownerAware.recordInstructionSource.bind(inner);
70
+ if (ownerAware.readSessionWorkspace)
71
+ this.readSessionWorkspace = ownerAware.readSessionWorkspace.bind(inner);
72
+ if (ownerAware.recordSessionWorkspace)
73
+ this.recordSessionWorkspace = ownerAware.recordSessionWorkspace.bind(inner);
68
74
  if (ownerAware.fork)
69
75
  this.fork = ownerAware.fork.bind(inner);
70
76
  if (ownerAware.exportEntries)
@@ -3,15 +3,29 @@ import type { Pool as PgPool } from "pg";
3
3
  import { type ExecutionOutcomeRecordWord, type GateOutcome, type Checkpoint, type CheckpointGate, type CheckpointState, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type PendingSteerInput, type ResumeOutcome, type ResolvedOutcome, type ResolveExpectation, type ReopenReason, type RiskDescriptor, type StoreDurability, type StoreFidelity, type ToolApprovalCard } from "@sema-agent/core";
4
4
  import { type ParkRowFacts, type RuleOfferProjection, type SkillCardFacts } from "../approval-card.js";
5
5
  import { type SqlDialect, type SqlDriver } from "./sql-driver.js";
6
+ import type { RetentionDeclaration } from "@sema-agent/core";
6
7
  import type { SealedCheckpointCtx } from "../http/checkpoint-ctx.js";
7
- /** M28 店腿的读数(两孪生同形;随 M28 删):扫到的可读行 · 回写成的行 · 回写成的行里被改写的值 · 读不出的行 · 封好之后一行装不下的行。 */
8
- export interface CtxRowsRewriteM28 {
8
+ /** ctx 行改写店腿的读数(两孪生同形):扫到的可读行 · 回写成的行 · 回写成的行里改写函数报的改动数 · 读不出的行 · 改写之后一行装不下的行。 */
9
+ export interface CtxRowsRewrite {
9
10
  readonly scanned: number;
10
11
  readonly rewritten: number;
11
12
  readonly valuesRewritten: number;
12
13
  readonly unreadable: number;
13
14
  readonly tooLarge: number;
14
15
  }
16
+ /** 一行的改写:交回新的落盘形(只有封口模块的铸点产得出 —— 品牌型)与这一行的改动数;`undefined` = 这一行不写。 */
17
+ export type CtxRowRewrite = (sessionId: string, ctx: object) => {
18
+ readonly ctx: SealedCheckpointCtx;
19
+ readonly values: number;
20
+ } | undefined;
21
+ /**
22
+ * 🔴 **一次性迁移的 ctx 行改写店腿**(两孪生:`SqlCheckpointStore` / `LocalCheckpointStore` 的 `rewriteCtxRows`;逐行判词两孪生同):扫全部 `checkpoint_ctx` 行、
23
+ * 交给 `rewrite`、交回新体的行原地回写(续跑时钟不动)。店不知道改写是什么 —— 用它的迁移各自带行改写:M28(凭据位明文封好)、M30(退役请求键改写)。
24
+ * 窗与删法逐条在 `plugins/one-time-migrations.ts` 登记表;登记表里最后一条用它的迁移删码时,本腿、读数型与扫描页一起删。
25
+ */
26
+ export interface CheckpointCtxRowsRewriter {
27
+ rewriteCtxRows(rewrite: CtxRowRewrite): Promise<CtxRowsRewrite>;
28
+ }
15
29
  export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
16
30
  /**
17
31
  * [ref] D-1 (§3 invariant #3 — crash-safe reaper backstop): an ABSOLUTE upper bound on a pending
@@ -451,9 +465,9 @@ export declare class SqlCheckpointStore implements CheckpointStore {
451
465
  protected readonly logger?: {
452
466
  info?(msg: string, meta?: unknown): void;
453
467
  } | undefined;
454
- /** [ref] 车1:托管留存声明。读法与「为什么 SQL 店答 managed 而三方法的实现体在 `retention-store-sql.ts`」
455
- * 逐字见 {@link MANAGED_RETENTION}(本店的 `checkpoint`/`checkpoint_ctx` 两表由那只聚合店按期清)。 */
456
- readonly retention: import("@sema-agent/core").RetentionDeclaration;
468
+ /** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法与「为什么 SQL 店答 managed 而三方法的实现体在
469
+ * `retention-store-sql.ts`」逐字见 {@link MANAGED_RETENTION}(扫车道开着时本店的 `checkpoint`/`checkpoint_ctx` 两表由那只聚合店按期清)。 */
470
+ readonly retention: RetentionDeclaration;
457
471
  /**
458
472
  * `CheckpointStore.durability` 声明([ref] 欠账,[ref] 件5)—— 行落在 MySQL-protocol / PostgreSQL 的
459
473
  * `checkpoint` 表里,进程重启、副本轮换、整机重建都不丢 ⇒ `"durable"`,如实。
@@ -487,25 +501,13 @@ export declare class SqlCheckpointStore implements CheckpointStore {
487
501
  * `wiring-governance-operator.test.ts` 的 [ref] 组;已上报上游求一个能表达该宽度的词。
488
502
  */
489
503
  readonly fidelity: StoreFidelity;
490
- /**
491
- * `CheckpointStore.redecision` 声明(core 5.22.0 F-012 L2/L3;[ref] clay 裁放行)——**如实按能力判**:
492
- * 本店的 {@link SqlCheckpointStore.reopen} 是真 CAS 实现(`resolved`→`pending` 原子翻回 + `reopen_reason`
493
- * 权威列,[ref] D-1 的两条重开腿都走它),声明 `reopen: true` 是读数不是抬举。core 的沙箱准入
494
- * 模式(pre-flight 要求 `redecision.reopen === true`,declaration never duck-typing——方法在场不算数)
495
- * 由这一格武装:Kata 腿(`capabilities.isolation` 真声明)+ durable park 部署下,`sandbox_local` ask
496
- * 自动放行并以 `permission.sandbox_admitted` durable 事件披露(缺席披露=core 侧变异恰红)。
497
- * `validatingLease` **不声明**:本店没有 durable validating-lease 纪律,不承诺没有的东西。
498
- * 翻向钉:`wiring-governance-operator.test.ts`(修前恰红,与本声明同 commit)。
499
- */
500
- readonly redecision: {
501
- readonly reopen: true;
502
- };
503
504
  /**
504
505
  * `CheckpointStore.execution` 声明(core 7.7.0 [ref];[ref])——**必填**,且必须恰是 `{ outcome: true }`:
505
506
  * 店在此承诺 {@link SqlCheckpointStore.recordExecutionOutcome} 是契约描述的那条真 CAS(谓词、四词、
506
- * 冲突抛),且 {@link SqlCheckpointStore.reopen} 认这条记录。与 `durability`/`fidelity`/`redecision`
507
- * 三格同一条「声明而非鸭子判」姿势,区别只在这一格**不可缺席**:缺席的店会被 core 在 store 席的
508
- * 第一次读(`resolveCheckpointStore`)以 `config.invalid_checkpoint_store` 拒启 —— 那是契约的正确行为,
507
+ * 冲突抛),且 {@link SqlCheckpointStore.reopen} 认这条记录。与 `durability`/`fidelity` 两格同一条
508
+ * 「声明而非鸭子判」姿势,区别只在这一格**不可缺席**:缺席的店(以及缺 `reopen` 动词的店 —— core 7.57.0 起它是必备
509
+ * 动词,原先的 `redecision` 声明格随之退役)会被 core 在 store 席的第一次读(`resolveCheckpointStore`)以
510
+ * `config.invalid_checkpoint_store` 拒启、句子点名缺的每一个成员 —— 那是契约的正确行为,
509
511
  * 因为一台记不下「已决动作最后被怎么处置」的部署,它手里每一条 resolved 行在这条轴上都永远读不出来。
510
512
  */
511
513
  readonly execution: {
@@ -513,7 +515,9 @@ export declare class SqlCheckpointStore implements CheckpointStore {
513
515
  };
514
516
  constructor(db: SqlDriver, logger?: {
515
517
  info?(msg: string, meta?: unknown): void;
516
- } | undefined);
518
+ } | undefined, opts?: {
519
+ readonly retention?: RetentionDeclaration;
520
+ });
517
521
  /** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
518
522
  private q;
519
523
  /** JSON column binding. TiDB: plain `JSON.stringify`, stored verbatim. PG: `pgProtocolJsonStringify` —
@@ -832,17 +836,14 @@ export declare class SqlCheckpointStore implements CheckpointStore {
832
836
  putCtx(sessionId: string, ctx: SealedCheckpointCtx): Promise<void>;
833
837
  getCtx<T extends object = object>(sessionId: string): Promise<T | null>;
834
838
  /**
835
- * 🔴 **一次性迁移 M28 的店腿**(窗与删法见 `plugins/one-time-migrations.ts` 登记表 M28;编排 = `checkpoint-ctx-seal-m28.ts`,行改写 =
836
- * `http/checkpoint-ctx.ts` 的 `sealStoredCheckpointCtxM28`;本店不知道「封」是什么,只负责扫与回写):按 `session_id` 键集分页扫 `checkpoint_ctx`
839
+ * 🔴 **一次性迁移的 ctx 行改写店腿**({@link CheckpointCtxRowsRewriter};用它的迁移与各自的行改写见那里,窗与删法见 `plugins/one-time-migrations.ts` 登记表;
840
+ * 本店不知道改写是什么,只负责扫与回写):按 `session_id` 键集分页扫 `checkpoint_ctx`
837
841
  * (每页 {@link CTX_REWRITE_PAGE} 行,只取会话 id 与 ctx 文本),行体经读腿**同一只**判形({@link decodeCtxColumn})—— 读不出 ⇒ 计数、跳过、不动;
838
842
  * `rewrite` 交回新体 ⇒ 经写腿同一只编码与形闸,**按原文 CAS** 回写(MySQL 协议两边 `CAST(… AS BINARY)`,与 M17 / M18 同一条理由:连接排序规则大小写
839
843
  * 不敏感;PG `text` 等值)。`updated_at_ms` **不动**(收割按它判,迁移不许延长或缩短一行的寿命)。CAS 打空(扫描与回写之间这一行被续跑腿 / 别的副本写过)
840
- * ⇒ 不计、不重试(新写者是本版就已封好;是旧版副本就由之后的起服再扫到)。一行装不下(封签比明文长)⇒ 计 `tooLarge`、那一行留原样,其余照扫。
844
+ * ⇒ 不计、不重试(新写者是本版写下的、已是新形;是旧版副本就由之后的起服再扫到)。一行装不下(如封签比明文长)⇒ 计 `tooLarge`、那一行留原样,其余照扫。
841
845
  */
842
- rewriteCtxRowsM28(rewrite: (sessionId: string, ctx: object) => {
843
- readonly ctx: SealedCheckpointCtx;
844
- readonly values: number;
845
- } | undefined): Promise<CtxRowsRewriteM28>;
846
+ rewriteCtxRows(rewrite: CtxRowRewrite): Promise<CtxRowsRewrite>;
846
847
  /**
847
848
  * GC ctx rows whose lifecycle is over (bound to the checkpoint, don't leak):
848
849
  * a session with NO pending checkpoint, NO active run, AND not touched since `cutoff`.
@@ -881,12 +882,16 @@ export declare class SqlCheckpointStore implements CheckpointStore {
881
882
  export declare class TiDBCheckpointStore extends SqlCheckpointStore {
882
883
  constructor(pool: MySqlPool, logger?: {
883
884
  info?(msg: string, meta?: unknown): void;
885
+ }, opts?: {
886
+ readonly retention?: RetentionDeclaration;
884
887
  });
885
888
  }
886
889
  /** PostgreSQL binding — historical class name + ctor shape preserved. */
887
890
  export declare class PgCheckpointStore extends SqlCheckpointStore {
888
891
  constructor(pool: PgPool, logger?: {
889
892
  info?(msg: string, meta?: unknown): void;
893
+ }, opts?: {
894
+ readonly retention?: RetentionDeclaration;
890
895
  });
891
896
  }
892
897
  //# sourceMappingURL=checkpoint-store-sql.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { parkedApprovalCard } from "../approval-content-kind.js";
2
2
  import { createHash } from "node:crypto";
3
3
  import { CHECKPOINT_FACET_SQL, CHECKPOINT_SWEEP_ORDER_SQL, CheckpointIndexRefusedError, judgeCheckpointIndexCells } from "./checkpoint-index-columns.js";
4
- import { CheckpointError, isGateKind, MAX_RULE_TEXT_CHARS, validatePendingSteer, appendPendingSteer, winnerFromOutcome, summarizeCheckpoint, MAX_SUPPORTED_CHECKPOINT_VERSION, ExecutionOutcomeConflictError, executionRecordDisposition, executionVerdict, } from "@sema-agent/core";
4
+ import { CheckpointError, isGateKind, MAX_RULE_TEXT_CHARS, validatePendingSteer, appendPendingSteer, winnerFromOutcome, summarizeCheckpoint, checkpointRevOf, MAX_SUPPORTED_CHECKPOINT_VERSION, ExecutionOutcomeConflictError, executionRecordDisposition, executionVerdict, } from "@sema-agent/core";
5
5
  import { redactDeep, redactSecrets } from "../trace/redact.js";
6
6
  import { MAX_RULE_OFFERS, MAX_RULE_OFFER_BATCH_MEMBERS, parkRowCarriesSkillCardFacts, parkRowFacts, readRuleOfferList, skillCardFacts } from "../approval-card.js";
7
7
  import { assertJsonColumnWritable, createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, readJsonArrayColumn, readJsonObjectColumn, readNonNullJsonValueColumn, } from "./sql-json-column.js";
@@ -9,7 +9,7 @@ import { recordFailOpen } from "../observability/fail-open.js";
9
9
  import { durableRowIdentity, withoutCheckpointToken } from "../checkpoint-identity.js";
10
10
  import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "./sql-driver.js";
11
11
  import { isDupKeyError, isMissingColumnError, rowTooLargeOrSelf, StoreRowTooLargeError } from "./sql-errors.js";
12
- import { MANAGED_RETENTION } from "./retention-store-sql.js";
12
+ import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
13
13
  import { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
14
14
  const CTX_REWRITE_PAGE = 500;
15
15
  export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
@@ -336,14 +336,14 @@ const EXECUTION_RECORD_CAS_ATTEMPTS = 8;
336
336
  export class SqlCheckpointStore {
337
337
  db;
338
338
  logger;
339
- retention = MANAGED_RETENTION;
339
+ retention;
340
340
  durability = "durable";
341
341
  fidelity = "json";
342
- redecision = { reopen: true };
343
342
  execution = { outcome: true };
344
- constructor(db, logger) {
343
+ constructor(db, logger, opts = {}) {
345
344
  this.db = db;
346
345
  this.logger = logger;
346
+ this.retention = opts.retention ?? UNMANAGED_RETENTION;
347
347
  }
348
348
  q(tidb, pg) {
349
349
  return this.db.dialect === "tidb" ? tidb : pg;
@@ -412,7 +412,7 @@ export class SqlCheckpointStore {
412
412
  cells.risk_descriptor === null ? null : this.json(cells.risk_descriptor, "risk descriptor"),
413
413
  ruleOffers === undefined ? null : this.json(ruleOffers, "rule offers"),
414
414
  cells.has_bidi_controls,
415
- cp.rev ?? 0,
415
+ checkpointRevOf(cp),
416
416
  cp.reopenReason ?? null,
417
417
  executionOutcome,
418
418
  executionAtMs,
@@ -738,7 +738,7 @@ export class SqlCheckpointStore {
738
738
  const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("tidb", "ctx")} FROM checkpoint_ctx WHERE session_id=?`, `SELECT ${jsonColumnText("pg", "ctx")} FROM checkpoint_ctx WHERE session_id=$1`), [sessionId]);
739
739
  return rows[0] ? refusing("a resume context nobody can read", () => decodeCtxColumn(rows[0].ctx, `for session ${JSON.stringify(sessionId)}`)) : null;
740
740
  }
741
- async rewriteCtxRowsM28(rewrite) {
741
+ async rewriteCtxRows(rewrite) {
742
742
  const out = { scanned: 0, rewritten: 0, valuesRewritten: 0, unreadable: 0, tooLarge: 0 };
743
743
  let after = "";
744
744
  for (;;) {
@@ -748,7 +748,7 @@ export class SqlCheckpointStore {
748
748
  after = sessionId;
749
749
  let ctx;
750
750
  try {
751
- ctx = decodeCtxColumn(row.ctx, `for session ${JSON.stringify(sessionId)} (M28 scan)`);
751
+ ctx = decodeCtxColumn(row.ctx, `for session ${JSON.stringify(sessionId)} (ctx row rewrite scan)`);
752
752
  }
753
753
  catch {
754
754
  out.unreadable += 1;
@@ -759,13 +759,13 @@ export class SqlCheckpointStore {
759
759
  if (next === undefined)
760
760
  continue;
761
761
  const text = this.json(next.ctx, "checkpoint ctx");
762
- assertJsonColumnWritable(text, createObjectColumnReader(), `checkpoint_ctx.ctx for session ${JSON.stringify(sessionId)} (M28 write)`);
762
+ assertJsonColumnWritable(text, createObjectColumnReader(), `checkpoint_ctx.ctx for session ${JSON.stringify(sessionId)} (ctx row rewrite)`);
763
763
  let affected;
764
764
  try {
765
765
  ({ affected } = await this.db.query(this.q("UPDATE checkpoint_ctx SET ctx = ? WHERE session_id = ? AND CAST(CAST(ctx AS CHAR) AS BINARY) = CAST(? AS BINARY)", "UPDATE checkpoint_ctx SET ctx = $1::jsonb WHERE session_id = $2 AND ctx::text = $3"), [text, sessionId, String(row.ctx)]));
766
766
  }
767
767
  catch (e) {
768
- const folded = rowTooLargeOrSelf(this.db.dialect, e, `checkpoint_ctx.ctx for session ${JSON.stringify(sessionId)} (M28 write)`);
768
+ const folded = rowTooLargeOrSelf(this.db.dialect, e, `checkpoint_ctx.ctx for session ${JSON.stringify(sessionId)} (ctx row rewrite)`);
769
769
  if (!(folded instanceof StoreRowTooLargeError))
770
770
  throw folded;
771
771
  out.tooLarge += 1;
@@ -798,13 +798,13 @@ export class SqlCheckpointStore {
798
798
  }
799
799
  }
800
800
  export class TiDBCheckpointStore extends SqlCheckpointStore {
801
- constructor(pool, logger) {
802
- super(mysqlDriver(pool), logger);
801
+ constructor(pool, logger, opts) {
802
+ super(mysqlDriver(pool), logger, opts);
803
803
  }
804
804
  }
805
805
  export class PgCheckpointStore extends SqlCheckpointStore {
806
- constructor(pool, logger) {
807
- super(pgDriver(pool), logger);
806
+ constructor(pool, logger, opts) {
807
+ super(pgDriver(pool), logger, opts);
808
808
  }
809
809
  }
810
810
  //# sourceMappingURL=checkpoint-store-sql.js.map
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenDifferent, worldStillMatchesMint, boundaryPublishVerdict, fileHistoryDescribeTrackKey, fileHistoryTrackKeyOf, fileHistoryResolveTrackKey, fileHistoryExportDigest, validateFileHistoryExport, resolveFileHistoryRetention, fileHistoryBoundariesToKeep, } from "@sema-agent/core";
2
+ import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenDifferent, worldStillMatchesMint, annulProofFailure, boundaryPublishVerdict, fileHistoryDescribeTrackKey, fileHistoryTrackKeyOf, fileHistoryResolveTrackKey, fileHistoryExportDigest, validateFileHistoryExport, resolveFileHistoryRetention, fileHistoryBoundariesToKeep, } from "@sema-agent/core";
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";
@@ -149,15 +149,8 @@ export class SqlFileHistoryStore {
149
149
  const baseAvailable = truthy(t.rows[0].base_available);
150
150
  const mintedBlobHash = v1.rows[0]?.blob_hash != null ? String(v1.rows[0].blob_hash) : null;
151
151
  const proof = await worldStillMatchesMint(verify.env, absPath, root, baseAvailable, mintedBlobHash, verify.signal);
152
- if (!proof.unchanged) {
153
- return {
154
- ok: false,
155
- error: {
156
- code: "conflict",
157
- message: `first-touch record for ${absPath} is NOT retractable: ${proof.reason} — the write this retraction compensates for may have changed the file, and deleting the only baseline of a modified file is worse than keeping a stale record`,
158
- },
159
- };
160
- }
152
+ if (proof.verdict !== "unchanged")
153
+ return annulProofFailure(proof, absPath);
161
154
  }
162
155
  const conn = await this.db.connect();
163
156
  try {
@@ -441,7 +434,7 @@ export class SqlFileHistoryStore {
441
434
  let targetVersion = boundary.get(t.keyHash);
442
435
  if (targetVersion === undefined) {
443
436
  if (!t.baseAvailable) {
444
- ledger.refused.push({ path: t.trackKey, reason: "base_unavailable" });
437
+ ledger.refused.push({ path: t.trackKey, reason: "base_unavailable", class: "base_unavailable" });
445
438
  continue;
446
439
  }
447
440
  targetVersion = 1;
@@ -452,12 +445,12 @@ export class SqlFileHistoryStore {
452
445
  continue;
453
446
  }
454
447
  if (rec.mode !== undefined && !(Number.isInteger(rec.mode) && rec.mode >= 0 && rec.mode <= 0o7777)) {
455
- ledger.refused.push({ path: t.trackKey, reason: `recorded mode ${String(rec.mode)} is not a valid POSIX permission value — refusing to apply a corrupted permission record` });
448
+ ledger.failed.push({ path: t.trackKey, reason: `recorded mode ${String(rec.mode)} is not a valid POSIX permission value (store integrity) — refusing to apply a corrupted permission record` });
456
449
  continue;
457
450
  }
458
451
  const resolved = fileHistoryResolveTrackKey(root, t.trackKey, t.keyDesc);
459
452
  if (!resolved.ok) {
460
- ledger.refused.push({ path: t.trackKey, reason: resolved.reason });
453
+ ledger.refused.push({ path: t.trackKey, reason: resolved.reason, class: resolved.class });
461
454
  continue;
462
455
  }
463
456
  let applied;
@@ -488,7 +481,7 @@ export class SqlFileHistoryStore {
488
481
  else if (applied.outcome === "identical")
489
482
  ledger.identicalSkipped.push(t.trackKey);
490
483
  else if (applied.outcome === "refused")
491
- ledger.refused.push({ path: t.trackKey, reason: applied.reason });
484
+ ledger.refused.push({ path: t.trackKey, reason: applied.reason, class: applied.class });
492
485
  else
493
486
  ledger.failed.push({ path: t.trackKey, reason: applied.reason });
494
487
  if ((applied.outcome === "applied" || applied.outcome === "identical") && applied.modeNotPreserved === true)
@@ -728,12 +721,13 @@ export class SqlFileHistoryStore {
728
721
  bytes = await srcGetBlob(hash);
729
722
  }
730
723
  catch (err) {
731
- return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${foldCaughtFailure(err).text}` } };
724
+ const f = foldCaughtFailure(err);
725
+ return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${f.text}`, ...f.fault } };
732
726
  }
733
727
  if (bytes === undefined)
734
728
  return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
735
729
  if (sha256hex(bytes) !== hash) {
736
- return { ok: false, error: { code: "unsupported_format", message: `source blob ${hash} fails content-address integrity — refused, nothing published` } };
730
+ 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` } };
737
731
  }
738
732
  await onVerified?.(hash, bytes);
739
733
  }
@@ -9,6 +9,7 @@ import { recordFailOpen } from "../observability/fail-open.js";
9
9
  import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
10
10
  import { RUN_HOLDER_DEATH_CODES, RUN_ORPHANED_ERROR, RUN_STALLED_ERROR, StoreBootRefusalError, buildRunOrphanedError, readLegacyHolderDeathCode } from "./store-contracts.js";
11
11
  import { notifyRunTerminal } from "../observability/run-terminal.js";
12
+ import { readRunIdentityCells, runIdentityCells } from "../identity-source.js";
12
13
  import { createInProcessSpaceCommitTable, fenceSpaceCommitAtTerminal, SPACE_COMMIT_RECORD_SCHEMA } from "../workspace-space-commit.js";
13
14
  const ownerEq = (a, b) => (a ?? null) === (b ?? null);
14
15
  const isParseableDate = (v) => typeof v === "string" && !Number.isNaN(Date.parse(v));
@@ -140,16 +141,19 @@ export class FileRunStore {
140
141
  return this.spaceCommits.abandonSpaceCommit(spaceKey, taskId);
141
142
  }
142
143
  toRow(d) {
144
+ const { identitySource, identityScope, identityPrincipalInc, ...rest } = d;
143
145
  return {
144
- ...d,
146
+ ...rest,
145
147
  idemKey: typeof d.idemKey === "string" ? d.idemKey : null,
146
148
  idemBodyFingerprint: typeof d.idemBodyFingerprint === "string" ? d.idemBodyFingerprint : null,
149
+ identity: readRunIdentityCells(identitySource, identityScope, identityPrincipalInc),
147
150
  createdAt: new Date(d.createdAt),
148
151
  updatedAt: new Date(d.updatedAt),
149
152
  };
150
153
  }
151
154
  toDisk(r) {
152
- return { ...r, createdAt: r.createdAt.toISOString(), updatedAt: r.updatedAt.toISOString() };
155
+ const { identity, ...rest } = r;
156
+ return { ...rest, ...runIdentityCells(identity), createdAt: r.createdAt.toISOString(), updatedAt: r.updatedAt.toISOString() };
153
157
  }
154
158
  toRecord(r) {
155
159
  return {
@@ -162,6 +166,7 @@ export class FileRunStore {
162
166
  errorCode: r.errorCode,
163
167
  jobId: r.jobId,
164
168
  source: r.source,
169
+ identity: r.identity,
165
170
  instanceId: r.instanceId,
166
171
  cancelRequested: r.cancelRequested,
167
172
  objectivePreview: r.objectivePreview,
@@ -376,6 +381,7 @@ export class FileRunStore {
376
381
  objectivePreview: meta.objectivePreview ?? null,
377
382
  idemKey,
378
383
  idemBodyFingerprint: meta.idem?.bodyFingerprint ?? null,
384
+ identity: meta.identity ?? null,
379
385
  createdAt: now,
380
386
  updatedAt: now,
381
387
  cancelRequested: false,
@@ -1,9 +1,51 @@
1
1
  /**
2
- * The confined, ADDITIVE pod-spec patch ({@link PodSpecPatch}/{@link applyPodSpecPatch}) + the exec-socket TLS
3
- * shape ({@link execSocketTlsOptions}) + the v4 channel status-frame parse ({@link exitCodeFromStatus}) — the
4
- * k8s adapter's protocol/patch layer, independent of pod lifecycle. Split out of `remote-env-k8s.ts` ([ref]
5
- * A13, internal-lossless — `remote-env-k8s.ts` re-exports every symbol below unchanged).
2
+ * The identity labels every sandbox pod carries — the ONE spelling (RBAC selectors, the reaper's listing and the egress self-check key on
3
+ * them; a pod-spec patch can add labels, never set or replace one of these).
6
4
  */
5
+ export declare const SANDBOX_POD_LABELS: {
6
+ readonly app: "sema-sandbox";
7
+ readonly "managed-by": "sema-server";
8
+ };
9
+ /**
10
+ * The pod's owning run: label key, value = the server run id (the task id) of the TOP-LEVEL run whose env created the pod. Minted only by the
11
+ * adapter from `K8sEnvConfig.runId` (the per-run binding decides who has one); absent ⇒ the pod names no run, and the reaper removes it only once
12
+ * its containers have ended. An identity label: a patch can neither set nor replace it.
13
+ */
14
+ export declare const SANDBOX_RUN_LABEL = "sema.io/run";
15
+ /**
16
+ * The pod's own reaper hold: annotation key, value = the decimal milliseconds the reaper must wait after the owning run turned terminal before it
17
+ * removes the pod (`k8s-pod-reaper.ts` `sandboxRunEndHoldMs` of the CREATING replica's data bound). Written once, by the adapter, on every pod that
18
+ * carries {@link SANDBOX_RUN_LABEL} (the hold is only read for those); the reaper reads this and nothing else — never its own replica's config, so a
19
+ * rolling change of the snapshot bound never shortens another replica's pod. A pod-spec patch reaches labels only, never annotations.
20
+ */
21
+ export declare const SANDBOX_RUN_END_HOLD_ANNOTATION = "sema.io/run-end-hold-ms";
22
+ /** The two per-pod Secret seats: `env` = the pod's env Secret (the values `K8S_SANDBOX_ENV` names); `lease` = the member-credential broker's lease Secret. */
23
+ export type SandboxSecretSeatKind = "env" | "lease";
24
+ /**
25
+ * Per seat, the secrets verbs the adapter sends for it in the sandbox namespace — the ONE table, and each row is exactly that seat's calls:
26
+ * `env` = `create` (the env Secret, POSTed after its pod, never touched again); `lease` = `create` (the lease Secret) + `patch` (the lease rewrite,
27
+ * a merge-patch of `broker.json`). Nothing else: the adapter never reads a Secret back (no `get` — which would also let the service account read
28
+ * every Secret in the namespace) and never deletes one (no `delete`) — each Secret is owned by its pod (`ownerReferences`, `blockOwnerDeletion:
29
+ * false`), so the cluster's garbage collector removes it with the pod under its own identity. A seat in play asks only its own row: the boot gate
30
+ * (`K8S_SANDBOX_ENV` non-empty) asks `env`, the member-credential plane judge asks `lease` — an env-only deployment is never asked for `patch`.
31
+ * Readers: the SelfSubjectAccessReview (`readSandboxSecretSeat`), the refusal sentences that name the Role rule, the plane's off-reason text, the
32
+ * catalog sentence. `test/k8s-sandbox-secret.test.ts` pins row ≡ calls per seat, both directions.
33
+ */
34
+ export declare const SANDBOX_SECRET_SEAT_VERBS: {
35
+ readonly env: readonly ["create"];
36
+ readonly lease: readonly ["create", "patch"];
37
+ };
38
+ export type SandboxSecretVerb = (typeof SANDBOX_SECRET_SEAT_VERBS)[SandboxSecretSeatKind][number];
39
+ export declare function isLabelValue(v: string): boolean;
40
+ /**
41
+ * The volume names the adapter itself mints on a sandbox pod — the ONE table (a patch volume / volumeMount must not reuse one: it would collide
42
+ * with, or mount, the adapter's own volume). Today: the space's build-cache claim and the member-credential broker's lease volume. A volume the
43
+ * adapter adds later is added HERE, and the patch judge below refuses it with no second guard.
44
+ */
45
+ export declare const ADAPTER_VOLUME_NAMES: {
46
+ readonly cache: "ws-cache";
47
+ readonly brokerLease: "sema-broker-lease";
48
+ };
7
49
  /**
8
50
  * The confined, ADDITIVE pod-spec patch. Every field is purely additive —
9
51
  * none can override the hard isolation invariants. This is the seam the RSI L8 immutable-mount probe + the
@@ -22,19 +64,32 @@ export interface PodSpecPatch {
22
64
  /** Extra labels merged into metadata.labels (e.g. a grader/probe tag). */
23
65
  labels?: Record<string, string>;
24
66
  }
25
- /**
26
- * Apply a {@link PodSpecPatch} to a sandbox pod object IN PLACE — purely ADDITIVE. Volumes + volumeMounts are
27
- * APPENDED (never replaced); securityContext objects are shallow-MERGED onto any existing; labels are merged. It
28
- * deliberately touches ONLY spec.volumes / spec.securityContext / containers[0].{volumeMounts,securityContext} /
29
- * metadata.labels — so the hard isolation invariants (runtimeClassName, automountServiceAccountToken,
30
- * restartPolicy, activeDeadlineSeconds, image, command) are preserved by construction. Pure + exported for testing.
31
- */
32
- export declare function applyPodSpecPatch(pod: {
67
+ type SandboxPodShape = {
33
68
  metadata: {
34
69
  labels?: Record<string, string>;
35
70
  };
36
71
  spec: Record<string, unknown>;
37
- }, patch: PodSpecPatch): void;
72
+ };
73
+ /** Which pod a patch lands on: one that carries the broker container or not. */
74
+ export interface PodPatchPresence {
75
+ readonly broker: boolean;
76
+ }
77
+ /**
78
+ * Apply a {@link PodSpecPatch} to a sandbox pod object IN PLACE — purely ADDITIVE, through the one field table
79
+ * ({@link POD_SPEC_PATCH_FIELDS}): a key outside the table is refused; EVERY present field is judged before ANY lands (a refusal leaves the pod
80
+ * byte-identical). Volumes + volumeMounts are APPENDED (never replaced); securityContext objects are shallow-MERGED onto any existing; labels are
81
+ * merged under the identity keys. It touches ONLY spec.volumes / spec.securityContext / containers[0].{volumeMounts,securityContext} /
82
+ * metadata.labels — so the hard isolation invariants (runtimeClassName, automountServiceAccountToken, restartPolicy, activeDeadlineSeconds, image,
83
+ * command) are preserved by construction. Throws (the caller surfaces it as a provisioning failure). Pure + exported for testing.
84
+ * `presence.broker` ⇒ the table's broker column judges first (see {@link POD_SPEC_PATCH_FIELDS}).
85
+ */
86
+ export declare function applyPodSpecPatch(pod: SandboxPodShape, patch: PodSpecPatch, presence?: PodPatchPresence): void;
87
+ /**
88
+ * The patch judge alone — the same one {@link applyPodSpecPatch} runs — for a pod that carries the broker: the refusal sentence, or `undefined`
89
+ * when the patch may land. The boot reads it on the deployment's static patch (a refusal turns the member-credential plane off,
90
+ * `pod_patch_reaches_broker`); the adapter runs it again on every pod it builds with the broker.
91
+ */
92
+ export declare function podSpecPatchBrokerRefusal(patch: PodSpecPatch | undefined): string | undefined;
38
93
  /**
39
94
  * TLS options for the exec WebSocket, shaped for BOTH runtimes (2026-06-11 in-cluster drill finding):
40
95
  * Bun's `ws` shim IGNORES node-ws's top-level `ca`/`rejectUnauthorized` (handshake fails against a
@@ -50,4 +105,5 @@ export declare function exitCodeFromStatus(statusJson: string): {
50
105
  } | {
51
106
  error: string;
52
107
  };
108
+ export {};
53
109
  //# sourceMappingURL=k8s-exec-protocol.d.ts.map