@sema-agent/server 7.142.0 → 7.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/MIGRATION.md +608 -0
  2. package/USAGE.md +63 -36
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +7 -5
  5. package/dist/approval-ask-audit-store.js +12 -6
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +155 -39
  9. package/dist/approval-card.js +111 -31
  10. package/dist/approval-queue-kind.d.ts +27 -0
  11. package/dist/approval-queue-kind.js +6 -0
  12. package/dist/approval-reconciler.d.ts +8 -8
  13. package/dist/approval-reconciler.js +3 -3
  14. package/dist/audit.js +4 -2
  15. package/dist/boot/budget-tracing.d.ts +1 -1
  16. package/dist/boot/execution-env.js +1 -1
  17. package/dist/boot/governance-seams.d.ts +26 -41
  18. package/dist/boot/governance-seams.js +61 -28
  19. package/dist/boot/late-binds.d.ts +7 -4
  20. package/dist/boot/late-binds.js +3 -1
  21. package/dist/boot/leader.js +2 -4
  22. package/dist/boot/memory-consolidation.d.ts +0 -8
  23. package/dist/boot/memory-consolidation.js +3 -3
  24. package/dist/boot/reapers.js +5 -4
  25. package/dist/boot/resolve-spec.d.ts +1 -1
  26. package/dist/boot/resolve-spec.js +8 -8
  27. package/dist/boot/runner-deps.d.ts +14 -6
  28. package/dist/boot/runner-deps.js +6 -17
  29. package/dist/boot/shutdown.d.ts +9 -0
  30. package/dist/boot/shutdown.js +18 -2
  31. package/dist/boot/stage-01-config.js +2 -0
  32. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  33. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  34. package/dist/boot/stage-03-store-backend.js +1 -2
  35. package/dist/boot/stage-04-stores.d.ts +5 -2
  36. package/dist/boot/stage-04-stores.js +3 -5
  37. package/dist/boot/stage-05-execution-env.d.ts +5 -2
  38. package/dist/boot/stage-06-runners.d.ts +5 -2
  39. package/dist/boot/stage-06-runners.js +1 -3
  40. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  41. package/dist/boot/stage-07-capability-layer.js +6 -2
  42. package/dist/boot/stage-08-reapers.d.ts +5 -2
  43. package/dist/boot/stage-09-leader.d.ts +5 -2
  44. package/dist/boot/stage-10-http-server.d.ts +5 -2
  45. package/dist/boot/stage-10-http-server.js +4 -1
  46. package/dist/boot/stores.d.ts +5 -2
  47. package/dist/boot/stores.js +7 -7
  48. package/dist/boot/web-admin.d.ts +5 -1
  49. package/dist/boot/web-admin.js +31 -19
  50. package/dist/capabilities/hands-lane.d.ts +9 -39
  51. package/dist/capabilities/hands-lane.js +8 -13
  52. package/dist/capabilities/mcp-probe.d.ts +3 -2
  53. package/dist/capabilities/scenarios.d.ts +23 -17
  54. package/dist/capabilities/scenarios.js +2 -2
  55. package/dist/capabilities/skills.d.ts +1 -17
  56. package/dist/capabilities/skills.js +0 -8
  57. package/dist/capability-facts.d.ts +8 -8
  58. package/dist/capability-facts.js +4 -4
  59. package/dist/card-void.d.ts +6 -9
  60. package/dist/config-catalog.js +1 -1
  61. package/dist/config-d-migration.d.ts +2 -0
  62. package/dist/config-dir-trust.js +58 -29
  63. package/dist/config-invariants.d.ts +7 -1
  64. package/dist/config-invariants.js +7 -0
  65. package/dist/config-provider.d.ts +10 -0
  66. package/dist/config-provider.js +15 -4
  67. package/dist/config-root-migration.d.ts +13 -0
  68. package/dist/config-root-migration.js +99 -0
  69. package/dist/config-types.d.ts +5 -5
  70. package/dist/config.d.ts +4 -3
  71. package/dist/config.js +1 -1
  72. package/dist/delegated-session-owner.d.ts +35 -151
  73. package/dist/delegated-session-owner.js +1 -83
  74. package/dist/device-ws-protocol.d.ts +1 -0
  75. package/dist/device-ws-protocol.js +2 -1
  76. package/dist/entry-mode-clamp-notice.d.ts +1 -1
  77. package/dist/env-model-table-gate.d.ts +53 -0
  78. package/dist/env-model-table-gate.js +53 -0
  79. package/dist/execution-placement.d.ts +7 -4
  80. package/dist/fleet/fleet-bus.d.ts +28 -52
  81. package/dist/fleet/fleet-bus.js +35 -100
  82. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  83. package/dist/fleet/fleet-reconciler.js +1 -1
  84. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  85. package/dist/fleet/subagent-tail-bus.js +15 -28
  86. package/dist/hooks/classic-stations.d.ts +3 -1
  87. package/dist/hooks/classic-stations.js +2 -0
  88. package/dist/hooks/hook-runner.js +28 -7
  89. package/dist/host-decision.d.ts +54 -20
  90. package/dist/host-decision.js +42 -14
  91. package/dist/http/admission.d.ts +1 -1
  92. package/dist/http/admission.js +7 -3
  93. package/dist/http/approval-sweeps.js +11 -8
  94. package/dist/http/caller-trust.d.ts +1 -1
  95. package/dist/http/durable-run-leg.js +2 -2
  96. package/dist/http/engine-refusal.d.ts +16 -0
  97. package/dist/http/engine-refusal.js +17 -0
  98. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  99. package/dist/http/memory-compliance-failure-reply.js +4 -6
  100. package/dist/http/owner-access.d.ts +11 -0
  101. package/dist/http/owner-access.js +13 -0
  102. package/dist/http/principal-gate.d.ts +1 -1
  103. package/dist/http/refusal-body.d.ts +7 -3
  104. package/dist/http/refusal-body.js +1 -0
  105. package/dist/http/resume-legs.d.ts +21 -7
  106. package/dist/http/resume-legs.js +82 -53
  107. package/dist/http/resume-restatement.d.ts +39 -0
  108. package/dist/http/resume-restatement.js +25 -0
  109. package/dist/http/route-ctx.d.ts +35 -10
  110. package/dist/http/route-ctx.js +1 -1
  111. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  112. package/dist/http/routes/approvals-assistant.js +143 -31
  113. package/dist/http/routes/capabilities.js +11 -2
  114. package/dist/http/routes/memory-policy.d.ts +2 -2
  115. package/dist/http/routes/memory-policy.js +1 -1
  116. package/dist/http/routes/notify-wake.js +23 -25
  117. package/dist/http/routes/rules.js +48 -13
  118. package/dist/http/routes/runs.js +9 -8
  119. package/dist/http/routes/session-memory-sync.d.ts +34 -6
  120. package/dist/http/routes/session-memory-sync.js +27 -10
  121. package/dist/http/routes/session-sync.js +13 -20
  122. package/dist/http/routes/sessions.d.ts +2 -2
  123. package/dist/http/routes/sessions.js +22 -23
  124. package/dist/http/routes/tasks.js +27 -49
  125. package/dist/http/server.d.ts +13 -7
  126. package/dist/http/server.js +2 -2
  127. package/dist/http/stored-body-replay.js +15 -4
  128. package/dist/http/wire-types.d.ts +17 -7
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js +1 -0
  131. package/dist/lane-home-probe.d.ts +15 -0
  132. package/dist/lane-home-probe.js +4 -0
  133. package/dist/leader/leader.js +5 -2
  134. package/dist/leader/wire.d.ts +7 -1
  135. package/dist/leader/wire.js +6 -5
  136. package/dist/leg-facts.d.ts +37 -0
  137. package/dist/leg-facts.js +15 -0
  138. package/dist/memory-bundle-engine.d.ts +1 -4
  139. package/dist/memory-bundle-engine.js +2 -2
  140. package/dist/memory-operator-faces.d.ts +30 -66
  141. package/dist/memory-operator-faces.js +17 -88
  142. package/dist/memory-scope-stores.d.ts +38 -40
  143. package/dist/memory-scope-stores.js +51 -36
  144. package/dist/memory-scope.d.ts +0 -9
  145. package/dist/memory-scope.js +0 -9
  146. package/dist/memory-sync-client.js +14 -3
  147. package/dist/memory-sync.d.ts +20 -4
  148. package/dist/memory-sync.js +23 -4
  149. package/dist/model-plane-face.d.ts +13 -7
  150. package/dist/model-plane-face.js +2 -1
  151. package/dist/observability/corrupt-read-seat.d.ts +5 -9
  152. package/dist/observability/corrupt-read-seat.js +1 -2
  153. package/dist/observability/fail-open.d.ts +30 -10
  154. package/dist/observability/fail-open.js +27 -10
  155. package/dist/observability/run-terminal.d.ts +1 -1
  156. package/dist/observability/run-terminal.js +6 -2
  157. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  158. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  159. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  160. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  161. package/dist/orchestration/workflow-park-decision.js +5 -3
  162. package/dist/org-delivery-gate.d.ts +11 -0
  163. package/dist/org-delivery-gate.js +19 -1
  164. package/dist/parked-decide.d.ts +13 -9
  165. package/dist/parked-decide.js +7 -7
  166. package/dist/parked-revive-surface.d.ts +6 -7
  167. package/dist/parked-revive-surface.js +1 -1
  168. package/dist/peer-inbound-face.d.ts +122 -0
  169. package/dist/peer-inbound-face.js +123 -0
  170. package/dist/permission-rule-list.d.ts +13 -9
  171. package/dist/permission-rule-list.js +7 -3
  172. package/dist/plugins/approval-ask-store-file.js +18 -6
  173. package/dist/plugins/approval-ask-store-memory.js +8 -6
  174. package/dist/plugins/approval-ask-store-sql.d.ts +28 -13
  175. package/dist/plugins/approval-ask-store-sql.js +30 -11
  176. package/dist/plugins/caching-session-store.d.ts +0 -3
  177. package/dist/plugins/caching-session-store.js +0 -3
  178. package/dist/plugins/checkpoint-store-sql.d.ts +45 -38
  179. package/dist/plugins/checkpoint-store-sql.js +108 -45
  180. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  181. package/dist/plugins/file-history-store-sql.js +24 -19
  182. package/dist/plugins/file-run-store.d.ts +29 -0
  183. package/dist/plugins/file-run-store.js +97 -8
  184. package/dist/plugins/fork-routing-session-store.d.ts +8 -1
  185. package/dist/plugins/fork-routing-session-store.js +6 -0
  186. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  187. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  188. package/dist/plugins/local-checkpoint-store.d.ts +6 -8
  189. package/dist/plugins/local-checkpoint-store.js +5 -4
  190. package/dist/plugins/local-session-store.d.ts +69 -30
  191. package/dist/plugins/local-session-store.js +133 -57
  192. package/dist/plugins/local-session-window.d.ts +4 -2
  193. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  194. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  195. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  196. package/dist/plugins/mailbox-store-sql.js +76 -7
  197. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  198. package/dist/plugins/memory-sync-store-pg.js +21 -0
  199. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  200. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  201. package/dist/plugins/one-time-migrations.d.ts +44 -14
  202. package/dist/plugins/one-time-migrations.js +118 -15
  203. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  204. package/dist/plugins/org-delivery-quota-store.js +2 -12
  205. package/dist/plugins/park-commit-watch.d.ts +1 -1
  206. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  207. package/dist/plugins/permission-rule-store-file.js +15 -2
  208. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  209. package/dist/plugins/permission-rule-store-sql.js +35 -2
  210. package/dist/plugins/pg-session-storage.d.ts +1 -9
  211. package/dist/plugins/pg-session-storage.js +2 -19
  212. package/dist/plugins/remote-env-device.d.ts +8 -11
  213. package/dist/plugins/remote-env-device.js +6 -3
  214. package/dist/plugins/remote-env-host.d.ts +8 -4
  215. package/dist/plugins/remote-env-host.js +7 -9
  216. package/dist/plugins/remote-env-k8s.d.ts +37 -24
  217. package/dist/plugins/remote-env-k8s.js +50 -17
  218. package/dist/plugins/remote-shell.js +12 -2
  219. package/dist/plugins/retention-store-sql.d.ts +2 -2
  220. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  221. package/dist/plugins/sandbox-read-floor.js +2 -7
  222. package/dist/plugins/schema-consistency.d.ts +5 -1
  223. package/dist/plugins/session-fork.d.ts +1 -1
  224. package/dist/plugins/session-ownership.d.ts +9 -0
  225. package/dist/plugins/session-ownership.js +6 -0
  226. package/dist/plugins/session-store.d.ts +13 -16
  227. package/dist/plugins/session-store.js +9 -10
  228. package/dist/plugins/sql-errors.d.ts +10 -1
  229. package/dist/plugins/sql-errors.js +13 -0
  230. package/dist/plugins/sql-json-column.d.ts +24 -2
  231. package/dist/plugins/sql-json-column.js +38 -3
  232. package/dist/plugins/store-backend.d.ts +23 -28
  233. package/dist/plugins/store-backend.js +12 -3
  234. package/dist/plugins/store-contracts.d.ts +29 -5
  235. package/dist/plugins/store-contracts.js +4 -1
  236. package/dist/plugins/task-attachment-store.d.ts +2 -2
  237. package/dist/plugins/task-attachment-store.js +37 -52
  238. package/dist/plugins/tidb-session-store.d.ts +2 -14
  239. package/dist/plugins/tidb-session-store.js +2 -20
  240. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  241. package/dist/plugins/tool-result-store-sql.js +23 -2
  242. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  243. package/dist/plugins/wiring-section-codec.js +55 -0
  244. package/dist/plugins/workspace-fill.d.ts +1 -1
  245. package/dist/rule-entry-list.d.ts +3 -2
  246. package/dist/rule-entry-list.js +5 -1
  247. package/dist/rules-consent.d.ts +28 -5
  248. package/dist/rules-consent.js +40 -28
  249. package/dist/run-local.js +11 -6
  250. package/dist/runs.d.ts +12 -8
  251. package/dist/runs.js +10 -7
  252. package/dist/runtime-governance.d.ts +1 -1
  253. package/dist/security.d.ts +0 -4
  254. package/dist/server-secret-env.d.ts +4 -0
  255. package/dist/session-error-wire.d.ts +34 -23
  256. package/dist/session-error-wire.js +8 -3
  257. package/dist/session-incarnation.d.ts +3 -3
  258. package/dist/session-notify-door.d.ts +106 -0
  259. package/dist/session-notify-door.js +97 -0
  260. package/dist/session-sync.d.ts +9 -14
  261. package/dist/session-sync.js +5 -5
  262. package/dist/session-workspace.d.ts +3 -13
  263. package/dist/session-workspace.js +0 -9
  264. package/dist/standing-answer-grant.d.ts +5 -0
  265. package/dist/standing-answer-grant.js +10 -0
  266. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  267. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  268. package/dist/task-mcp.d.ts +1 -1
  269. package/dist/task-settings.d.ts +11 -8
  270. package/dist/task-settings.js +31 -11
  271. package/dist/tool-approval.d.ts +55 -35
  272. package/dist/tool-approval.js +112 -74
  273. package/dist/trace/core-keyset-guard.d.ts +12 -9
  274. package/dist/trace/engine-notice-wire.d.ts +1 -1
  275. package/dist/trace/engine-notice-wire.js +4 -2
  276. package/dist/trace/exit-seat.d.ts +7 -1
  277. package/dist/trace/exit-seat.js +1 -0
  278. package/dist/trace/ledger-sink.d.ts +2 -2
  279. package/dist/trace/ledger-sink.js +12 -4
  280. package/dist/trace/model-segment.d.ts +74 -25
  281. package/dist/trace/model-segment.js +141 -32
  282. package/dist/trace/project.d.ts +15 -6
  283. package/dist/trace/project.js +12 -4
  284. package/dist/trace/redact.d.ts +72 -9
  285. package/dist/trace/redact.js +1509 -471
  286. package/dist/trace/self-minted-wire.d.ts +598 -47
  287. package/dist/trace/self-minted-wire.js +190 -20
  288. package/dist/trace/wire-projection-faces.d.ts +1 -1
  289. package/dist/trace/wire-projection-faces.js +1 -1
  290. package/dist/verifier-pause-card.d.ts +33 -5
  291. package/dist/verifier-pause-card.js +15 -10
  292. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  293. package/dist/web-admin-client/apply-effective.js +90 -10
  294. package/dist/workspace-space.d.ts +19 -3
  295. package/dist/workspace-space.js +8 -4
  296. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  297. package/package.json +3 -2
  298. package/wire-changes/server@7.143.0.json +1167 -0
  299. package/wire-changes/server@7.144.0.json +291 -0
  300. package/dist/session-records-skipped-notice.d.ts +0 -21
  301. package/dist/session-records-skipped-notice.js +0 -27
@@ -4,9 +4,10 @@ import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
4
4
  import { join } from "node:path";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
6
6
  import { randomBytes } from "node:crypto";
7
- import { AppendLog, atomicWriteFile, ensureDir, isProcessLive, processFingerprint, sanitizePathComponent, writeThenLink } from "@sema-agent/core";
7
+ import { AppendLog, atomicWriteFile, ensureDir, isProcessLive, processFingerprint, sanitizePathComponent, sanitizeScope, writeThenLink } from "@sema-agent/core";
8
8
  import { recordFailOpen } from "../observability/fail-open.js";
9
9
  import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
10
+ import { joinFromStore, splitForStore } from "./wiring-section-codec.js";
10
11
  import { RUN_HOLDER_DEATH_CODES, RUN_ORPHANED_ERROR, RUN_STALLED_ERROR, StoreBootRefusalError, buildRunOrphanedError, readLegacyHolderDeathCode, isTerminalRunStatus, settledLegObservationOf } from "./store-contracts.js";
11
12
  import { notifyRunTerminal } from "../observability/run-terminal.js";
12
13
  import { readRunIdentityCells, runIdentityCells } from "../identity-source.js";
@@ -26,6 +27,13 @@ const EVENT_RECORD_SHAPE = {
26
27
  return typeof record.seq === "number" ? record : undefined;
27
28
  },
28
29
  };
30
+ const SECTION_BLOB_SHAPE = {
31
+ what: "wiring-section blob record without a string digest and an object/array body",
32
+ read(record) {
33
+ const r = record;
34
+ return typeof r.digest === "string" && typeof r.body === "object" && r.body !== null ? record : undefined;
35
+ },
36
+ };
29
37
  const CLAIM_RECORD_SHAPE = {
30
38
  what: "active-run claim record without a string sessionId / taskId",
31
39
  read(record) {
@@ -61,6 +69,10 @@ export class FileRunStore {
61
69
  byIdem = new Map();
62
70
  events = new Map();
63
71
  eventLogs = new Map();
72
+ blobsDir;
73
+ sectionBlobs = new Map();
74
+ blobLogs = new Map();
75
+ unresolvedReported = new Set();
64
76
  checkpointProbe;
65
77
  claimOwner = { nonce: randomBytes(12).toString("hex"), ...processFingerprint() };
66
78
  claimLocks = new Map();
@@ -72,6 +84,7 @@ export class FileRunStore {
72
84
  this.runsDir = join(root, "runs");
73
85
  this.activeDir = join(root, "runs", "active");
74
86
  this.tmpDir = join(root, "tmp");
87
+ this.blobsDir = join(root, "run-blobs");
75
88
  this.spaceCommitsDir = join(root, "space-commits");
76
89
  this.spaceCommits = createInProcessSpaceCommitTable({
77
90
  load: (spaceKey) => this.loadSpaceCommit(spaceKey),
@@ -109,6 +122,9 @@ export class FileRunStore {
109
122
  activePath(sessionId) {
110
123
  return join(this.activeDir, sanitizePathComponent(sessionId));
111
124
  }
125
+ blobLedgerPath(sessionId) {
126
+ return typeof sessionId === "string" ? join(this.blobsDir, `${sanitizeScope(sessionId)}.jsonl`) : undefined;
127
+ }
112
128
  spaceCommitPath(spaceKey) {
113
129
  return join(this.spaceCommitsDir, `${sanitizePathComponent(spaceKey)}.json`);
114
130
  }
@@ -144,6 +160,7 @@ export class FileRunStore {
144
160
  const { identitySource, identityScope, identityPrincipalInc, ...rest } = d;
145
161
  return {
146
162
  ...rest,
163
+ result: d.result ?? null,
147
164
  idemKey: typeof d.idemKey === "string" ? d.idemKey : null,
148
165
  idemBodyFingerprint: typeof d.idemBodyFingerprint === "string" ? d.idemBodyFingerprint : null,
149
166
  identity: readRunIdentityCells(identitySource, identityScope, identityPrincipalInc),
@@ -261,6 +278,19 @@ export class FileRunStore {
261
278
  this.events.set(disk.taskId, list);
262
279
  }
263
280
  }
281
+ for (const sessionId of new Set([...this.runs.values()].map((r) => r.sessionId))) {
282
+ const path = this.blobLedgerPath(sessionId);
283
+ if (path === undefined)
284
+ continue;
285
+ const recs = this.replay(path, SECTION_BLOB_SHAPE).records;
286
+ if (recs.length === 0)
287
+ continue;
288
+ const index = new Map();
289
+ for (const b of recs)
290
+ if (!index.has(b.digest))
291
+ index.set(b.digest, b.body);
292
+ this.sectionBlobs.set(sessionId, index);
293
+ }
264
294
  let claims;
265
295
  try {
266
296
  claims = readdirSync(this.activeDir);
@@ -435,10 +465,58 @@ export class FileRunStore {
435
465
  return;
436
466
  const clone = data == null ? null : structuredClone(data);
437
467
  const ts = new Date().toISOString();
438
- this.eventLogFor(taskId).append({ seq, type, data: clone, ts }, false);
439
- list.push({ seq, type, data: clone, ts });
468
+ const stored = this.storeSections(taskId, type, clone);
469
+ this.eventLogFor(taskId).append({ seq, type, data: stored, ts }, false);
470
+ list.push({ seq, type, data: stored, ts });
440
471
  this.events.set(taskId, list);
441
472
  }
473
+ storeSections(taskId, type, data) {
474
+ const { stored, blobs } = splitForStore(type, data);
475
+ if (blobs.length === 0)
476
+ return stored;
477
+ const sessionId = this.runs.get(taskId)?.sessionId;
478
+ const path = sessionId === undefined ? undefined : this.blobLedgerPath(sessionId);
479
+ if (sessionId === undefined || path === undefined)
480
+ return data;
481
+ let index = this.sectionBlobs.get(sessionId);
482
+ if (index === undefined) {
483
+ index = new Map();
484
+ this.sectionBlobs.set(sessionId, index);
485
+ }
486
+ const fresh = blobs.filter((b) => !index.has(b.digest));
487
+ if (fresh.length > 0) {
488
+ const log = this.blobLogFor(sessionId, path);
489
+ for (const [i, b] of fresh.entries())
490
+ log.append({ digest: b.digest, body: b.body }, i === fresh.length - 1);
491
+ for (const b of fresh)
492
+ index.set(b.digest, b.body);
493
+ }
494
+ return stored;
495
+ }
496
+ blobLogFor(sessionId, path) {
497
+ let log = this.blobLogs.get(sessionId);
498
+ if (!log) {
499
+ log = new AppendLog(path);
500
+ this.blobLogs.set(sessionId, log);
501
+ }
502
+ return log;
503
+ }
504
+ dropSectionBlobs(sessionId) {
505
+ const path = this.blobLedgerPath(sessionId);
506
+ if (path !== undefined)
507
+ rmSync(path, { force: true });
508
+ this.blobLogs.get(sessionId)?.close();
509
+ this.blobLogs.delete(sessionId);
510
+ this.sectionBlobs.delete(sessionId);
511
+ }
512
+ reportUnresolved(taskId, seq, missing) {
513
+ const key = `${taskId}\u0000${seq}`;
514
+ if (this.unresolvedReported.has(key))
515
+ return;
516
+ this.unresolvedReported.add(key);
517
+ const sections = missing.map((m) => `${m.section}:${m.digest}`).join(",");
518
+ recordFailOpen("server.run-store.corrupt-record-skipped", `kind=section-ref taskId=${taskId} seq=${seq} sections=${sections} reason=wiring_manifest row references section blobs its session's ledger does not hold (row withheld from reads)`);
519
+ }
442
520
  async maxSeq(taskId) {
443
521
  const list = this.events.get(taskId);
444
522
  return list && list.length ? Math.max(...list.map((e) => e.seq)) : 0;
@@ -449,10 +527,19 @@ export class FileRunStore {
449
527
  }
450
528
  async getEvents(taskId, afterSeq) {
451
529
  const list = this.events.get(taskId) ?? [];
452
- return list
453
- .filter((e) => e.seq > afterSeq)
454
- .sort((a, b) => a.seq - b.seq)
455
- .map((e) => ({ ...e, data: e.data == null ? null : structuredClone(e.data) }));
530
+ const sessionId = this.runs.get(taskId)?.sessionId;
531
+ const blobs = sessionId === undefined ? undefined : this.sectionBlobs.get(sessionId);
532
+ const lookup = (digest) => blobs?.get(digest);
533
+ const out = [];
534
+ for (const e of list.filter((x) => x.seq > afterSeq).sort((a, b) => a.seq - b.seq)) {
535
+ const joined = joinFromStore(e.type, e.data, lookup);
536
+ if (joined.kind === "unresolved") {
537
+ this.reportUnresolved(taskId, e.seq, joined.missing);
538
+ continue;
539
+ }
540
+ out.push({ ...e, data: joined.data == null ? null : structuredClone(joined.data) });
541
+ }
542
+ return out;
456
543
  }
457
544
  async setTerminal(taskId, status, result, error) {
458
545
  await fenceSpaceCommitAtTerminal(taskId, async (spaceCommit) => this.writeTerminal(taskId, status, result, error, spaceCommit));
@@ -661,6 +748,7 @@ export class FileRunStore {
661
748
  const claimed = this.active.get(sessionId);
662
749
  if (claimed !== undefined)
663
750
  return { active: claimed };
751
+ this.dropSectionBlobs(sessionId);
664
752
  let removed = 0;
665
753
  for (const [taskId, r] of [...this.runs]) {
666
754
  if (r.sessionId !== sessionId)
@@ -1024,7 +1112,7 @@ export class FileRunStore {
1024
1112
  return new Set([...this.runs.values()].map((r) => r.sessionId));
1025
1113
  }
1026
1114
  dispose() {
1027
- for (const log of this.eventLogs.values()) {
1115
+ for (const log of [...this.eventLogs.values(), ...this.blobLogs.values()]) {
1028
1116
  try {
1029
1117
  log.close();
1030
1118
  }
@@ -1032,6 +1120,7 @@ export class FileRunStore {
1032
1120
  }
1033
1121
  }
1034
1122
  this.eventLogs.clear();
1123
+ this.blobLogs.clear();
1035
1124
  }
1036
1125
  }
1037
1126
  //# sourceMappingURL=file-run-store.js.map
@@ -32,7 +32,7 @@
32
32
  * 路由表 LRU 上限 {@link ROUTE_MAX}:满额逐最老(refresh-on-use);被逐后下次 `acquire` 按上述规则重derive
33
33
  * (requireExisting 的 host-first 重试仍落对店),中途 touch/noteTaskRun 缺路由=落 transient(no-op 级)。
34
34
  */
35
- import { type SessionStore, type AcquiredSession, type SessionStoreSummary, type SessionPlacement, type PlacedSessionRow } from "@sema-agent/core";
35
+ import { type SessionStore, type AcquiredSession, type SessionHead, type SessionStoreSummary, type SessionPlacement, type PlacedSessionRow } from "@sema-agent/core";
36
36
  import type { ExecutionPlacementSeat } from "../execution-placement.js";
37
37
  import type { ForkToFn } from "./session-fork.js";
38
38
  /** acquire 选项形(core 5.48 SessionStore 契约):[ref] placement=受信 spawner 的分区建会话声明。 */
@@ -63,6 +63,13 @@ export declare class ForkRoutingSessionStore implements SessionStore {
63
63
  readonly executionPlacement?: ExecutionPlacementSeat;
64
64
  /** fork 续写的店契约透传(host 有才有):目标在 host 店原子新建,新 id 与源一并记 host 路由(与 {@link fork} 的 host 腿同)。 */
65
65
  readonly forkTo?: ForkToFn;
66
+ /**
67
+ * core `SessionStore.headOf`(按 id 读一行:属主 / 住客 / 叶子)—— **按 acquire 的路由转发**({@link pick}:placed 名册 → 路由表 → 未知落 transient,
68
+ * 与 acquire 对同一只 id 落的店同一只),所以答的就是 acquire 交出的那只会话所在的行(core 7.62.0 [ref] 盒义务 7:声明 placements 的店答 `headOf`,
69
+ * 住客与 acquire 交出的同源;引擎在子 Runner 上据它读「没人派生的 run」自己那一行定委派树属主)。两只店都答 `headOf` 才声明:有一边答不了 ⇒ 不声明
70
+ * (半只读口会把那一边的行答成「不在」)。
71
+ */
72
+ readonly headOf?: (sessionId: string) => Promise<SessionHead | undefined>;
66
73
  constructor(host: SessionStore, transient: SessionStore);
67
74
  private remember;
68
75
  private pick;
@@ -11,6 +11,7 @@ export class ForkRoutingSessionStore {
11
11
  listPlaced;
12
12
  executionPlacement;
13
13
  forkTo;
14
+ headOf;
14
15
  constructor(host, transient) {
15
16
  this.host = host;
16
17
  this.transient = transient;
@@ -23,6 +24,11 @@ export class ForkRoutingSessionStore {
23
24
  if (host.fork === undefined && transient.fork === undefined) {
24
25
  this.fork = undefined;
25
26
  }
27
+ const hostHeadOf = host.headOf;
28
+ const transientHeadOf = transient.headOf;
29
+ if (typeof hostHeadOf === "function" && typeof transientHeadOf === "function") {
30
+ this.headOf = (id) => (this.pick(id) === host ? hostHeadOf.call(host, id) : transientHeadOf.call(transient, id));
31
+ }
26
32
  const hostFaces = host;
27
33
  if (hostFaces.executionPlacement !== undefined)
28
34
  this.executionPlacement = hostFaces.executionPlacement;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * 🔴 一次性迁移 M36(窗口见 `plugins/one-time-migrations.ts` 登记表)—— **引擎 7.61.0 之前导入的、在每个项目根放行的全局 allow,按引擎写下的那一句判据退役**。
3
+ *
4
+ * ## 为什么
5
+ * 引擎 7.61.0 之前的设置导入门把用户层(用户配置目录下的那份 settings)里从 `/` 写起的路径规则存成**全局行**。全局行在每个任务的**项目根**读 `/x`,
6
+ * 用户层却在**它自己的配置目录**读 —— 同一串字落店之后守着 / 放着的是另一个地方:一条本意是「配置目录下的 notes」的放行 `Edit(/notes/**)`
7
+ * 在每个项目里放行 `notes/` 的编辑、不问。引擎 7.61.0 起导入门不再这样存(`preview.skipped`,理由前缀 `unsupported.layer_root:`);
8
+ * **存量行**引擎不迁、也不在读侧丢 —— 判据只写成一句话(引擎 INTEGRATION-CORE §5.14),由店的属主跑。本文件就是那一次跑。
9
+ *
10
+ * ## 判据(逐字照引擎那一句;不加条件、不减条件)
11
+ * 一个已存的 add 被退役,当且仅当四条都成立:行的态是 `allow`;add 的出处是 `imported-cc`;行的 scope 是 `global`;`ruleBasesNeeded(row)` 点名 `root`。
12
+ * **按 add 退役、不按行**:每只选中的行写**一只** observed-remove 墓碑,`removedDots` 恰是选中的那几只 add —— 同一行另有一只 `user` add 的,那一行照旧活着
13
+ * (人亲手同意过的那一份不跟着导入一起走)。deny / ask 的 add **不退役**:它们按店的读法(`<task>/x`)只收紧,退役会把部署有意带进来的收紧放掉。
14
+ *
15
+ * ## 读哪些桶(店自己答;答不全的那一种如实写下)
16
+ * 一律问**店**:它能叫出名字的每一只桶,判据在桶里判(不在桶外按「谁可能有」预筛)。
17
+ * · SQL:规则表里的每一只桶(`listRuleBucketOwners`,按 `owner_key` 分页)。不从审批记录推 —— 收编把规则桶整桶改键到新身份、审批史留在旧身份名下,
18
+ * 从记录推出的属主集在收编之后漏掉新桶。
19
+ * · File:引擎的 File 分区后端**没有**列桶口(桶文件按属主名的单向摘要命名),本步能叫出名字的只有本店导入记录点名过的属主
20
+ * (`FileRuleApprovalRecordStore.importRecordOwners`;`imported-cc` 只由导入记录派生,记录是只增日志)。**已知缺口(如实)**:引擎的本地数据根收编
21
+ * 把一只桶改名到一个没有任何导入记录点名的身份之后,那只桶本步叫不出、不读 —— 等引擎给 File 分区后端一个列桶口再收。
22
+ *
23
+ * ## 写在哪里(一处)
24
+ * 墓碑经**这只桶自己的写面**落(`writerOf(partition).apply({ kind: "tighten-delete" })`,引擎的写面契约)—— SQL 两孪生走 `SqlDurableRulePartition` 的那只
25
+ * (店内唯一写法 `writeBucket`),File 走引擎 File 分区的那只。同一个函数、同一次调用,不分叉。删除点(`deletedBy`)由这只桶的写面 `nextDot()` 铸
26
+ * —— 与引擎撤销口 `removePersistedRule` 同一约定(本副本的 actor,一次删除一枚)。OCC:读到的 rev 交给 `apply`,输了就重读重选(另一只副本可能刚退役过,
27
+ * 重选为空 ⇒ 零写),有界次数后点名跳过、下一次起服再来。
28
+ *
29
+ * ## 失败方向
30
+ * 列桶 / 解析桶 / 读桶 / 取点 / 写面**抛** ⇒ 原样抛:起服拒,收据账里已提交的墓碑随拒因交出(与本段其余各步同一条路)。例外两条,都由店的判官按抛出物的**类**判(不按文案):
31
+ * 取点时店说这只桶**在写它的那一步里没了**(`source.isVanishedBucket`:另一只副本删桶恰落在这一窗)⇒ 无可退役、点名跳过 `vanished`(桶都没了,它什么都不放行);
32
+ * 另一条是解析桶(属主 → 分区)或读桶时**店的唯一判官整桶拒**了
33
+ * 这只桶(解析与读同一条律、同一只判官;`source.isWholeBucketRefusal`:确定性判决,引擎读侧对它同样整桶拒、它什么都不放行;SQL = 读腿真往外交的那两类 —— 判官四道的拒与某只 JSON 列的体读不出)
34
+ * ⇒ 点名跳过 `bucket_unreadable`,接着读下一只桶(一只读不出的桶不挡别的桶,也不挡起服);一次读失败(连接 / 超时)
35
+ * 证明不了以后也读不出,所以它**不**归这一类 —— 跳过它就是让那几行在读恢复之后照旧放行。File 店没有这种判决证据(引擎的 File 分区对损坏与 I/O 失败抛同一种错,
36
+ * 解析时读收编标记也是:一次 EIO 与一份坏标记同一种错)⇒ 那一侧解析 / 读桶抛一律起服拒。另两种店**答了**却做不了的(没有写面或写面拒 / 并发争不过)⇒ 点名跳过,下一次起服再试,其间那几行照旧放行,每次起服都点名。
37
+ */
38
+ import { type DurableRulePartitionProvider, type PersistedRule, type RuleAdd, type RuleOwner } from "@sema-agent/core";
39
+ /** 一只被退役的导入 add 所在的行(一行一条读数)。**不带规则正文**(与 M11 同一条纪律:规则正文不出店)—— 桶键 + 工具名足够让运维去列举面对上它。 */
40
+ export interface ImportedLayerRootAllowRetired {
41
+ /** 桶键(`buildRuleOwnerKey`:属主的单向摘要;两种店同一把,日志里不出属主名)。 */
42
+ readonly ownerKey: string;
43
+ readonly tool: string;
44
+ /** 这一行被退役的导入 add 数(≥ 1)。 */
45
+ readonly addsRetired: number;
46
+ /** 退役之后这一行是否仍活着 —— 它另有别的出处的 add(人亲手同意过的那一份)。`false` = 这一行不再生效。 */
47
+ readonly stillLive: boolean;
48
+ }
49
+ /**
50
+ * 跳过一只桶的成因(闭集;日志句按它穷尽分)。
51
+ * · `bucket_unreadable` —— 解析或读这只桶时,店的唯一判官整桶拒了它(`isWholeBucketRefusal` 真)。引擎读侧对它同样整桶拒:它什么都不放行。
52
+ * · `vanished` —— 读到了要退役的行,写它的那一步里这只桶被并发删掉了(店的判官按类说)。桶没了 ⇒ 无可退役,什么都不放行;不拒启。
53
+ * · `not_writable` —— 选中了行,而这只桶没有写面(只读视图)或写面拒了这只墓碑。那几行照旧放行,每次起服都点名。
54
+ * · `contended` —— 每一次写都输给并发写者,有界次数用完。下一次起服再来;其间照旧放行。
55
+ */
56
+ export type ImportedLayerRootSkipReason = "bucket_unreadable" | "vanished" | "not_writable" | "contended";
57
+ export interface ImportedLayerRootBucketSkipped {
58
+ readonly ownerKey: string;
59
+ readonly reason: ImportedLayerRootSkipReason;
60
+ /** 一句不带行内容的话:读 / 解析桶抛出来的东西只报它的种类(原句可能引到桶里的行 —— 与 M11 `contentFreeRefusal` 同一条纪律;
61
+ * 原句由店自己的披露口说,File 店的 `permission_rule_store_disclosure`、SQL 店的整桶拒句);写面拒的是闭集词,原样带。 */
62
+ readonly why: string;
63
+ }
64
+ /** 本步记进收据账的两格(`OneTimeMigrationReport` 的两只键,随提交追加)。 */
65
+ export interface ImportedLayerRootReadings {
66
+ importedLayerRootAllowsRetired: ImportedLayerRootAllowRetired[];
67
+ importedLayerRootBucketsSkipped: ImportedLayerRootBucketSkipped[];
68
+ }
69
+ /** 一种店交给本步的三样东西:它能叫出名字的桶的属主(见头注「读哪些桶」)、它的 durable 分区后端(读桶、写墓碑)、它的整桶拒判别(见头注「失败方向」)。 */
70
+ export interface ImportedLayerRootRetirementSource {
71
+ candidateOwners(): Promise<readonly RuleOwner[]>;
72
+ readonly durable: DurableRulePartitionProvider;
73
+ /** 这只读桶抛出物是不是店的唯一判官的**确定性**整桶拒(真 ⇒ 点名跳过、读下一只桶;假 ⇒ 原样抛、起服拒)。判的是读面**真往外交的**抛出物的类,不按文案。 */
74
+ isWholeBucketRefusal(e: unknown): boolean;
75
+ /** 这只取点抛出物是不是店说的「桶在写它的那一步里没了」(真 ⇒ 点名跳过 `vanished`;假 ⇒ 原样抛、起服拒)。 */
76
+ isVanishedBucket(e: unknown): boolean;
77
+ }
78
+ /** 判据(引擎 §5.14 那一句,逐字):这一行里该退役的 add;不选 ⇒ 空。 */
79
+ export declare function importedLayerRootAddsOf(row: PersistedRule): readonly RuleAdd[];
80
+ /** 跑一遍:读记录点名的每只桶(按桶键去重),退役判据选中的 add。读数随每次提交记进 `into`。 */
81
+ export declare function retireImportedLayerRootAllows(source: ImportedLayerRootRetirementSource, into: ImportedLayerRootReadings): Promise<void>;
82
+ //# sourceMappingURL=imported-layer-root-retirement.d.ts.map
@@ -0,0 +1,96 @@
1
+ import { ruleBasesNeeded, writerOf } from "@sema-agent/core";
2
+ import { buildRuleOwnerKey } from "./permission-rule-store-sql.js";
3
+ const RETIREMENT_OCC_ATTEMPTS = 5;
4
+ export function importedLayerRootAddsOf(row) {
5
+ if (row.behavior !== "allow" || row.scope.kind !== "global" || !ruleBasesNeeded(row).includes("root"))
6
+ return [];
7
+ return row.adds.filter((a) => a.origin === "imported-cc");
8
+ }
9
+ export async function retireImportedLayerRootAllows(source, into) {
10
+ const seen = new Set();
11
+ for (const owner of await source.candidateOwners()) {
12
+ const ownerKey = buildRuleOwnerKey(owner);
13
+ if (seen.has(ownerKey))
14
+ continue;
15
+ seen.add(ownerKey);
16
+ await retireInBucket(source, owner, ownerKey, into);
17
+ }
18
+ }
19
+ async function retireInBucket(source, owner, ownerKey, into) {
20
+ const durable = source.durable;
21
+ const skip = (reason, why) => void into.importedLayerRootBucketsSkipped.push({ ownerKey, reason, why });
22
+ const unreadable = (what, e) => {
23
+ if (!source.isWholeBucketRefusal(e))
24
+ throw e;
25
+ skip("bucket_unreadable", withheld(what, e));
26
+ };
27
+ let partition;
28
+ try {
29
+ partition = partitionOf(durable, owner);
30
+ }
31
+ catch (e) {
32
+ return unreadable("the store refused this bucket as a whole while resolving it", e);
33
+ }
34
+ for (let attempt = 0; attempt < RETIREMENT_OCC_ATTEMPTS; attempt++) {
35
+ let stored;
36
+ try {
37
+ stored = await partition.list();
38
+ }
39
+ catch (e) {
40
+ return unreadable("the store refused this bucket as a whole", e);
41
+ }
42
+ const selected = stored.rules.flatMap((row) => {
43
+ const adds = importedLayerRootAddsOf(row);
44
+ return adds.length > 0 ? [{ row, adds }] : [];
45
+ });
46
+ if (selected.length === 0)
47
+ return;
48
+ const writer = writerOf(partition);
49
+ if (writer === undefined)
50
+ return skip("not_writable", "this bucket is served through a read-only view (it has no write face)");
51
+ let rev = stored.rev;
52
+ let lost = false;
53
+ for (const { row, adds } of selected) {
54
+ let deletedBy;
55
+ try {
56
+ deletedBy = await writer.nextDot();
57
+ }
58
+ catch (e) {
59
+ if (!source.isVanishedBucket(e))
60
+ throw e;
61
+ return skip("vanished", "the bucket was deleted while this step was writing to it (a concurrent delete); nothing is left to retire");
62
+ }
63
+ const tombstone = { behavior: row.behavior, rule: row.rule, scope: row.scope, removedDots: adds.map((a) => a.dot), deletedBy };
64
+ const out = await writer.apply({ kind: "tighten-delete", tombstone }, { expectedRev: rev });
65
+ if ("conflict" in out) {
66
+ lost = true;
67
+ break;
68
+ }
69
+ if ("refused" in out)
70
+ return skip("not_writable", `the store refused the tombstone (${out.refused})`);
71
+ rev = out.rev;
72
+ into.importedLayerRootAllowsRetired.push({ ownerKey, tool: row.tool, addsRetired: adds.length, stillLive: row.adds.length > adds.length });
73
+ }
74
+ if (!lost)
75
+ return;
76
+ }
77
+ skip("contended", `every write lost to a concurrent writer ${RETIREMENT_OCC_ATTEMPTS} times`);
78
+ }
79
+ function partitionOf(durable, owner) {
80
+ switch (owner.kind) {
81
+ case "principal":
82
+ return durable.forPrincipal(owner.principal);
83
+ case "local-owner":
84
+ if (durable.forLocalOwner === undefined)
85
+ throw new Error("this provider has no local-owner bucket");
86
+ return durable.forLocalOwner();
87
+ default: {
88
+ const unknown = owner;
89
+ throw new Error(`M36: an owner of a kind this pass does not know: ${JSON.stringify(unknown)}`);
90
+ }
91
+ }
92
+ }
93
+ function withheld(what, e) {
94
+ return `${what} threw ${e instanceof Error ? e.name : typeof e} (its text is withheld here: it may quote the bucket's rows)`;
95
+ }
96
+ //# sourceMappingURL=imported-layer-root-retirement.js.map
@@ -147,11 +147,9 @@ export declare class LocalCheckpointStore {
147
147
  * · **没有列,所以没有列/blob 一致性门**:SQL 孪生的两道矛盾门(`tool_call_id` 与 `bound_input_hash`
148
148
  * 的列 vs blob)在本形结构上不存在 —— 本形只有 blob 这一个真源,谈不上两份互相矛盾。判别力因此**不弱**:
149
149
  * 那两道门防的是「外部改库 / schema 偏斜让列与 blob 分家」,而本形没有可分家的第二份。
150
- * · **没有行级版本闸**:本类 `peekScopeByToken` 顶注已亲核过这条事实 —— 本形的 `get()` 没有行级版本闸,
151
- * 唯一的读不动形是账本重放级(整店同时读不动)。所以 SQL 孪生那道 `version > MAX_SUPPORTED` 的
152
- * `unparseable` 臂在这里没有对应物;本口的 `unparseable` 只由**窄读器**判(blob 形不合)。
153
- * · **窄读器是同一只** `pendingActionToolCallId`(与 SQL 孪生共用,零第二份手抄):身份三元组的第一维
154
- * `sourceTaskId`、`boundInputHash`、以及「读不出 vs 确定不匹配」的三态,全部由它一家判。
150
+ * · **身份判词是同一只** `candidateIdentityOf`(与 SQL 孪生共用,零第二份手抄):先问 core 判官(答 `lacking` ⇒ `unparseable`,
151
+ * 7.144.0 起两只孪生同一臂 —— 修前只有 SQL 孪生按版本列比,本形没有对应物),再由窄读器判身份三元组的第一维 `sourceSessionId`、
152
+ * `boundInputHash`、以及「读不出 vs 确定不匹配」的三态。
155
153
  */
156
154
  findCheckpointCandidatesForAsk(scope: string, sessionId: string, toolCallId: string, sinceMs: number): Promise<CheckpointAskCandidate[]>;
157
155
  /**
@@ -159,9 +157,9 @@ export declare class LocalCheckpointStore {
159
157
  * 语义与存在理由的唯一属主 = SQL 侧 `peekScopeByToken` 顶注。
160
158
  *
161
159
  * ⚠️ 形差如实记:SQL 孪生那口是真「轻读」(只 SELECT scope 一列),本形没有列可选 —— core 的 File 店
162
- * 只给 `get(token)`,所以这里读的是**整行**。后果对本形无害:本形的 `get()` 没有行级版本闸(唯一的
163
- * 读不动形是账本重放级 = 整店同时读不动,`findPendingTokenBySession` 先抛),所以「行体读得出而 scope
164
- * 读不出」这一支在本形结构上不存在。哪天本形补了行级闸,这里要跟着改成不碰行体的读。
160
+ * 只给 `get(token)`,所以这里读的是**整行**。后果对本形无害:本形的 `get()` 没有行级拒(两只孪生 7.144.0 起都不按版本拒 ——
161
+ * 本引擎续不续由 core 判官在续跑时答;本形连 SQL 孪生剩下的坏体一臂也没有,唯一的读不动形是账本重放级 = 整店同时读不动,
162
+ * `findPendingTokenBySession` 先抛),所以「行体读得出而 scope 读不出」这一支在本形结构上不存在。哪天本形补了行级拒,这里要跟着改成不碰行体的读。
165
163
  */
166
164
  peekScopeByToken(token: CheckpointToken): Promise<string | null | undefined>;
167
165
  /** `undefined` = no pending row; else the owner scope (local scopes are always strings — never null).
@@ -6,7 +6,7 @@ import { createHash } from "node:crypto";
6
6
  import { existsSync, readFileSync, readdirSync, unlinkSync, mkdirSync } from "node:fs";
7
7
  import { join } from "node:path";
8
8
  import { FileCheckpointStore, atomicWriteFile, executionVerdict, sanitizePathComponent, } from "@sema-agent/core";
9
- import { approvalDecisionOfWinner, approvalPayloadFingerprint, boundedRuleOffers, boundedToolInput, pendingActionToolCallId, pendingRowPrecedes, queueRowGateKind, TERMINAL_BACKSTOP_MS, TERMINAL_GRACE_MS } from "./checkpoint-store-sql.js";
9
+ import { approvalDecisionOfWinner, approvalPayloadFingerprint, boundedRuleOffers, boundedToolInput, candidateIdentityOf, pendingRowPrecedes, queueRowGateKind, TERMINAL_BACKSTOP_MS, TERMINAL_GRACE_MS } from "./checkpoint-store-sql.js";
10
10
  import { quarantineUnreadableSidecar } from "./local-sidecar-quarantine.js";
11
11
  import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, readStringArrayColumn } from "./sql-json-column.js";
12
12
  import { UNMANAGED_RETENTION } from "./retention-store-sql.js";
@@ -194,6 +194,7 @@ export class LocalCheckpointStore {
194
194
  ...((card) => (card !== undefined ? { approvalCard: card } : {}))(parkedApprovalCard(cp.gate)),
195
195
  ...parkRowFacts(cp.pendingAction),
196
196
  ...skillCardFacts(summary),
197
+ rowVerdict: summary.rowVerdict,
197
198
  });
198
199
  }
199
200
  return rows.sort((a, b) => (b.riskDescriptor?.severity ?? 0) - (a.riskDescriptor?.severity ?? 0) || a.createdAt - b.createdAt);
@@ -276,14 +277,14 @@ export class LocalCheckpointStore {
276
277
  if (cp.scope !== scope || cp.sessionId !== sessionId || cp.createdAt < sinceMs)
277
278
  continue;
278
279
  const base = { token: t, status: cp.status, createdAtMs: cp.createdAt };
279
- const derived = pendingActionToolCallId(cp);
280
+ const derived = candidateIdentityOf(cp);
280
281
  if (!derived.readable) {
281
- out.push({ ...base, sourceTaskId: null, boundCallId: null, boundInputHash: null, unparseable: true });
282
+ out.push({ ...base, sourceSessionId: null, boundCallId: null, boundInputHash: null, unparseable: true });
282
283
  continue;
283
284
  }
284
285
  if (derived.toolCallId !== toolCallId)
285
286
  continue;
286
- out.push({ ...base, sourceTaskId: derived.sourceTaskId, boundCallId: derived.toolCallId, boundInputHash: derived.boundInputHash });
287
+ out.push({ ...base, sourceSessionId: derived.sourceSessionId, boundCallId: derived.toolCallId, boundInputHash: derived.boundInputHash });
287
288
  }
288
289
  return out.sort((a, b) => a.createdAtMs - b.createdAtMs || (a.token < b.token ? -1 : a.token > b.token ? 1 : 0));
289
290
  }