@sema-agent/server 7.141.0 → 7.143.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 (341) hide show
  1. package/MIGRATION.md +657 -0
  2. package/USAGE.md +102 -30
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +61 -43
  5. package/dist/approval-ask-audit-store.js +69 -44
  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 +126 -27
  9. package/dist/approval-card.js +103 -23
  10. package/dist/approval-crash-convergence.d.ts +17 -7
  11. package/dist/approval-crash-convergence.js +94 -22
  12. package/dist/approval-deny-reasons.d.ts +34 -30
  13. package/dist/approval-deny-reasons.js +21 -6
  14. package/dist/approval-policy-settlement.d.ts +1 -1
  15. package/dist/approval-queue-kind.d.ts +27 -0
  16. package/dist/approval-queue-kind.js +6 -0
  17. package/dist/approval-reconciler.d.ts +41 -9
  18. package/dist/approval-reconciler.js +45 -42
  19. package/dist/audit.js +4 -2
  20. package/dist/auth-bridge.d.ts +9 -6
  21. package/dist/auth-bridge.js +9 -3
  22. package/dist/boot/adoption.js +2 -1
  23. package/dist/boot/budget-tracing.d.ts +17 -1
  24. package/dist/boot/budget-tracing.js +10 -6
  25. package/dist/boot/device-lane.d.ts +1 -1
  26. package/dist/boot/execution-env.d.ts +24 -4
  27. package/dist/boot/execution-env.js +26 -23
  28. package/dist/boot/execution-lane.js +2 -1
  29. package/dist/boot/exit-boundary.js +5 -4
  30. package/dist/boot/governance-seams.d.ts +26 -41
  31. package/dist/boot/governance-seams.js +61 -28
  32. package/dist/boot/late-binds.d.ts +7 -4
  33. package/dist/boot/late-binds.js +3 -1
  34. package/dist/boot/leader.js +2 -4
  35. package/dist/boot/memory-consolidation.d.ts +0 -8
  36. package/dist/boot/memory-consolidation.js +5 -4
  37. package/dist/boot/parked-revive-gate.js +2 -1
  38. package/dist/boot/permission-rules-audit.d.ts +0 -28
  39. package/dist/boot/permission-rules-audit.js +2 -1
  40. package/dist/boot/read-deny-anchor-audit.js +2 -1
  41. package/dist/boot/reapers.js +9 -7
  42. package/dist/boot/resolve-spec.d.ts +1 -1
  43. package/dist/boot/resolve-spec.js +19 -10
  44. package/dist/boot/retention-lane.js +5 -3
  45. package/dist/boot/runner-deps.d.ts +10 -7
  46. package/dist/boot/runner-deps.js +20 -29
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.js +4 -3
  49. package/dist/boot/shutdown.d.ts +9 -0
  50. package/dist/boot/shutdown.js +19 -4
  51. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  52. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  53. package/dist/boot/stage-03-store-backend.js +1 -2
  54. package/dist/boot/stage-04-stores.d.ts +5 -2
  55. package/dist/boot/stage-04-stores.js +6 -7
  56. package/dist/boot/stage-05-execution-env.d.ts +6 -3
  57. package/dist/boot/stage-05-execution-env.js +8 -6
  58. package/dist/boot/stage-06-runners.d.ts +6 -3
  59. package/dist/boot/stage-06-runners.js +3 -4
  60. package/dist/boot/stage-07-capability-layer.d.ts +6 -3
  61. package/dist/boot/stage-07-capability-layer.js +7 -2
  62. package/dist/boot/stage-08-reapers.d.ts +6 -3
  63. package/dist/boot/stage-08-reapers.js +3 -2
  64. package/dist/boot/stage-09-leader.d.ts +6 -3
  65. package/dist/boot/stage-10-http-server.d.ts +6 -3
  66. package/dist/boot/stage-10-http-server.js +14 -5
  67. package/dist/boot/stores.d.ts +5 -2
  68. package/dist/boot/stores.js +10 -9
  69. package/dist/boot/web-admin.d.ts +5 -1
  70. package/dist/boot/web-admin.js +48 -36
  71. package/dist/boot/webfetch-summarize-lane.js +2 -1
  72. package/dist/boot/workflow-orchestration.js +3 -2
  73. package/dist/capabilities/builtin-tools.d.ts +2 -1
  74. package/dist/capabilities/builtin-tools.js +2 -4
  75. package/dist/capabilities/composite-members.d.ts +2 -1
  76. package/dist/capabilities/composite-members.js +2 -1
  77. package/dist/capabilities/hands-lane.d.ts +9 -39
  78. package/dist/capabilities/hands-lane.js +8 -13
  79. package/dist/capabilities/mcp-probe.d.ts +3 -2
  80. package/dist/capabilities/scenarios.d.ts +11 -1
  81. package/dist/capabilities/scenarios.js +1 -0
  82. package/dist/capabilities/skills.d.ts +1 -17
  83. package/dist/capabilities/skills.js +0 -8
  84. package/dist/capability-facts.d.ts +31 -7
  85. package/dist/capability-facts.js +27 -4
  86. package/dist/card-void.d.ts +6 -9
  87. package/dist/config-catalog.js +2 -1
  88. package/dist/config-dir-trust.js +58 -29
  89. package/dist/config-invariants.d.ts +7 -1
  90. package/dist/config-invariants.js +7 -0
  91. package/dist/config-provider.d.ts +10 -0
  92. package/dist/config-provider.js +15 -4
  93. package/dist/config-root-migration.d.ts +13 -0
  94. package/dist/config-root-migration.js +99 -0
  95. package/dist/config-types.d.ts +19 -8
  96. package/dist/config.d.ts +10 -3
  97. package/dist/config.js +18 -4
  98. package/dist/delegated-session-owner.d.ts +5 -3
  99. package/dist/delegated-session-owner.js +1 -1
  100. package/dist/device-ws-protocol.d.ts +1 -0
  101. package/dist/device-ws-protocol.js +2 -1
  102. package/dist/env-model-table-gate.d.ts +53 -0
  103. package/dist/env-model-table-gate.js +53 -0
  104. package/dist/execution-lane-caps.d.ts +2 -1
  105. package/dist/fleet/fleet-bus.d.ts +34 -55
  106. package/dist/fleet/fleet-bus.js +35 -100
  107. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  108. package/dist/fleet/fleet-reconciler.js +1 -1
  109. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  110. package/dist/fleet/subagent-tail-bus.js +15 -28
  111. package/dist/hooks/hook-runner.d.ts +6 -0
  112. package/dist/hooks/hook-runner.js +58 -8
  113. package/dist/host-decision.d.ts +54 -20
  114. package/dist/host-decision.js +42 -14
  115. package/dist/http/admission.d.ts +1 -1
  116. package/dist/http/admission.js +7 -3
  117. package/dist/http/approval-sweeps.js +11 -8
  118. package/dist/http/caller-trust.d.ts +1 -1
  119. package/dist/http/dispatch.js +4 -2
  120. package/dist/http/durable-run-leg.js +2 -2
  121. package/dist/http/engine-refusal.d.ts +16 -0
  122. package/dist/http/engine-refusal.js +17 -0
  123. package/dist/http/execution-context.d.ts +2 -2
  124. package/dist/http/idempotency.d.ts +1 -1
  125. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  126. package/dist/http/memory-compliance-failure-reply.js +4 -6
  127. package/dist/http/owner-access.d.ts +11 -0
  128. package/dist/http/owner-access.js +13 -0
  129. package/dist/http/principal-gate.d.ts +3 -1
  130. package/dist/http/principal-gate.js +17 -8
  131. package/dist/http/resume-legs.d.ts +21 -7
  132. package/dist/http/resume-legs.js +76 -58
  133. package/dist/http/resume-restatement.d.ts +39 -0
  134. package/dist/http/resume-restatement.js +25 -0
  135. package/dist/http/route-ctx.d.ts +35 -10
  136. package/dist/http/route-ctx.js +1 -1
  137. package/dist/http/route-table.js +2 -0
  138. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  139. package/dist/http/routes/approvals-assistant.js +142 -31
  140. package/dist/http/routes/attachments.js +18 -0
  141. package/dist/http/routes/capabilities.js +16 -4
  142. package/dist/http/routes/memory-policy.d.ts +2 -2
  143. package/dist/http/routes/memory-policy.js +27 -7
  144. package/dist/http/routes/notify-wake.js +23 -25
  145. package/dist/http/routes/rules.js +48 -13
  146. package/dist/http/routes/runs.js +12 -11
  147. package/dist/http/routes/session-memory-sync.d.ts +91 -0
  148. package/dist/http/routes/session-memory-sync.js +174 -0
  149. package/dist/http/routes/session-sync.js +13 -20
  150. package/dist/http/routes/sessions-list.d.ts +2 -1
  151. package/dist/http/routes/sessions.d.ts +2 -2
  152. package/dist/http/routes/sessions.js +22 -23
  153. package/dist/http/routes/tasks.js +34 -54
  154. package/dist/http/run-read-face.d.ts +7 -0
  155. package/dist/http/run-read-face.js +9 -3
  156. package/dist/http/send.d.ts +5 -0
  157. package/dist/http/send.js +9 -2
  158. package/dist/http/server.d.ts +27 -15
  159. package/dist/http/server.js +4 -6
  160. package/dist/http/stored-body-replay.js +15 -4
  161. package/dist/http/submit-replay.d.ts +4 -3
  162. package/dist/http/submit-replay.js +2 -2
  163. package/dist/http/sync-submit-body.d.ts +21 -4
  164. package/dist/http/sync-submit-body.js +13 -0
  165. package/dist/http/wire-types.d.ts +17 -7
  166. package/dist/identity-source.d.ts +21 -2
  167. package/dist/identity-source.js +6 -0
  168. package/dist/leader/leader.js +5 -2
  169. package/dist/leader/wire.d.ts +7 -1
  170. package/dist/leader/wire.js +6 -5
  171. package/dist/leg-facts.d.ts +37 -0
  172. package/dist/leg-facts.js +15 -0
  173. package/dist/memory-bundle-engine.d.ts +1 -4
  174. package/dist/memory-bundle-engine.js +2 -2
  175. package/dist/memory-incident-sink.d.ts +19 -6
  176. package/dist/memory-incident-sink.js +8 -4
  177. package/dist/memory-operator-faces.d.ts +30 -66
  178. package/dist/memory-operator-faces.js +17 -88
  179. package/dist/memory-scope-stores.d.ts +38 -40
  180. package/dist/memory-scope-stores.js +51 -36
  181. package/dist/memory-scope.d.ts +0 -9
  182. package/dist/memory-scope.js +0 -9
  183. package/dist/memory-sync-client.d.ts +21 -21
  184. package/dist/memory-sync-client.js +62 -43
  185. package/dist/memory-sync-identity.d.ts +24 -0
  186. package/dist/memory-sync-identity.js +57 -0
  187. package/dist/memory-sync.d.ts +27 -5
  188. package/dist/memory-sync.js +29 -7
  189. package/dist/model-plane-face.d.ts +13 -7
  190. package/dist/model-plane-face.js +2 -1
  191. package/dist/observability/fail-open.d.ts +47 -14
  192. package/dist/observability/fail-open.js +37 -11
  193. package/dist/observability/run-terminal.d.ts +92 -34
  194. package/dist/observability/run-terminal.js +171 -162
  195. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  196. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  197. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  198. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  199. package/dist/orchestration/workflow-park-decision.js +5 -3
  200. package/dist/org-delivery-gate.d.ts +11 -0
  201. package/dist/org-delivery-gate.js +19 -1
  202. package/dist/parked-decide.d.ts +13 -9
  203. package/dist/parked-decide.js +7 -7
  204. package/dist/parked-revive-surface.js +1 -1
  205. package/dist/peer-inbound-face.d.ts +127 -0
  206. package/dist/peer-inbound-face.js +158 -0
  207. package/dist/permission-rule-list.d.ts +13 -9
  208. package/dist/permission-rule-list.js +7 -3
  209. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  210. package/dist/plugins/approval-ask-store-file.js +64 -11
  211. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  212. package/dist/plugins/approval-ask-store-memory.js +17 -14
  213. package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
  214. package/dist/plugins/approval-ask-store-sql.js +79 -30
  215. package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
  216. package/dist/plugins/checkpoint-store-sql.js +9 -7
  217. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  218. package/dist/plugins/file-history-store-sql.js +24 -19
  219. package/dist/plugins/file-run-store.d.ts +35 -1
  220. package/dist/plugins/file-run-store.js +108 -9
  221. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  222. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  223. package/dist/plugins/local-checkpoint-store.d.ts +1 -1
  224. package/dist/plugins/local-checkpoint-store.js +2 -2
  225. package/dist/plugins/local-session-store.d.ts +42 -9
  226. package/dist/plugins/local-session-store.js +83 -33
  227. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  228. package/dist/plugins/local-task-attachment-store.js +67 -43
  229. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  230. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  231. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  232. package/dist/plugins/mailbox-store-sql.js +76 -7
  233. package/dist/plugins/memory-key-guards.d.ts +3 -3
  234. package/dist/plugins/memory-run-store.d.ts +6 -1
  235. package/dist/plugins/memory-run-store.js +11 -1
  236. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  237. package/dist/plugins/memory-sync-store-pg.js +21 -0
  238. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  239. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  240. package/dist/plugins/one-time-migrations.d.ts +58 -2
  241. package/dist/plugins/one-time-migrations.js +161 -4
  242. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  243. package/dist/plugins/org-delivery-quota-store.js +2 -12
  244. package/dist/plugins/park-commit-watch.d.ts +1 -1
  245. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  246. package/dist/plugins/permission-rule-store-file.js +15 -2
  247. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  248. package/dist/plugins/permission-rule-store-sql.js +35 -2
  249. package/dist/plugins/remote-env-device.d.ts +8 -11
  250. package/dist/plugins/remote-env-device.js +6 -3
  251. package/dist/plugins/remote-env-e2b.d.ts +23 -4
  252. package/dist/plugins/remote-env-e2b.js +111 -28
  253. package/dist/plugins/remote-env-k8s.d.ts +61 -22
  254. package/dist/plugins/remote-env-k8s.js +133 -33
  255. package/dist/plugins/remote-env-local-docker.d.ts +15 -3
  256. package/dist/plugins/remote-env-local-docker.js +40 -12
  257. package/dist/plugins/retention-store-sql.d.ts +2 -2
  258. package/dist/plugins/run-store-sql.d.ts +9 -1
  259. package/dist/plugins/run-store-sql.js +9 -1
  260. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  261. package/dist/plugins/sandbox-read-floor.js +2 -7
  262. package/dist/plugins/sql-errors.d.ts +10 -1
  263. package/dist/plugins/sql-errors.js +13 -0
  264. package/dist/plugins/store-backend.d.ts +33 -35
  265. package/dist/plugins/store-backend.js +10 -1
  266. package/dist/plugins/store-contracts.d.ts +50 -1
  267. package/dist/plugins/store-contracts.js +6 -0
  268. package/dist/plugins/task-attachment-store.d.ts +112 -14
  269. package/dist/plugins/task-attachment-store.js +207 -29
  270. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  271. package/dist/plugins/tool-result-store-sql.js +23 -2
  272. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  273. package/dist/plugins/wiring-section-codec.js +55 -0
  274. package/dist/plugins/workspace-fill.d.ts +60 -0
  275. package/dist/plugins/workspace-fill.js +106 -0
  276. package/dist/project-bundle.d.ts +38 -0
  277. package/dist/project-bundle.js +609 -0
  278. package/dist/rule-entry-list.d.ts +3 -2
  279. package/dist/rule-entry-list.js +5 -1
  280. package/dist/rules-consent.d.ts +28 -5
  281. package/dist/rules-consent.js +40 -28
  282. package/dist/run-local.js +11 -13
  283. package/dist/runs.d.ts +12 -8
  284. package/dist/runs.js +6 -8
  285. package/dist/runtime-governance.d.ts +1 -1
  286. package/dist/sandbox-egress-policy.d.ts +4 -1
  287. package/dist/sandbox-egress-policy.js +3 -1
  288. package/dist/sandbox-git-plane.d.ts +31 -12
  289. package/dist/sandbox-git-plane.js +24 -4
  290. package/dist/security.d.ts +9 -0
  291. package/dist/security.js +8 -0
  292. package/dist/server-secret-env.d.ts +4 -0
  293. package/dist/session-error-wire.d.ts +36 -0
  294. package/dist/session-error-wire.js +13 -0
  295. package/dist/session-incarnation.d.ts +1 -1
  296. package/dist/session-notify-door.d.ts +106 -0
  297. package/dist/session-notify-door.js +93 -0
  298. package/dist/session-sync.d.ts +9 -14
  299. package/dist/session-sync.js +5 -5
  300. package/dist/session-workspace.d.ts +3 -13
  301. package/dist/session-workspace.js +0 -9
  302. package/dist/standing-answer-grant.d.ts +5 -0
  303. package/dist/standing-answer-grant.js +10 -0
  304. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  305. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  306. package/dist/task-mcp.d.ts +1 -1
  307. package/dist/task-settings.d.ts +21 -10
  308. package/dist/task-settings.js +46 -13
  309. package/dist/terminal.d.ts +39 -19
  310. package/dist/terminal.js +65 -22
  311. package/dist/tool-approval.d.ts +56 -37
  312. package/dist/tool-approval.js +78 -71
  313. package/dist/trace/core-keyset-guard.d.ts +134 -14
  314. package/dist/trace/engine-notice-wire.d.ts +9 -3
  315. package/dist/trace/engine-notice-wire.js +7 -3
  316. package/dist/trace/exit-seat.d.ts +9 -2
  317. package/dist/trace/exit-seat.js +1 -0
  318. package/dist/trace/ledger-sink.d.ts +10 -6
  319. package/dist/trace/ledger-sink.js +2 -2
  320. package/dist/trace/model-segment.d.ts +55 -25
  321. package/dist/trace/model-segment.js +101 -33
  322. package/dist/trace/project.d.ts +25 -5
  323. package/dist/trace/project.js +22 -0
  324. package/dist/trace/redact.d.ts +61 -9
  325. package/dist/trace/redact.js +1490 -468
  326. package/dist/trace/self-minted-wire.d.ts +745 -24
  327. package/dist/trace/self-minted-wire.js +239 -9
  328. package/dist/trace/wire-projection-faces.d.ts +2 -2
  329. package/dist/trace/wire-projection-faces.js +2 -2
  330. package/dist/verifier-pause-card.d.ts +33 -5
  331. package/dist/verifier-pause-card.js +15 -10
  332. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  333. package/dist/web-admin-client/apply-effective.js +109 -9
  334. package/dist/web-admin-client/effective-keys.js +2 -0
  335. package/dist/web-admin-client/types.d.ts +4 -0
  336. package/dist/workspace-space.d.ts +19 -3
  337. package/dist/workspace-space.js +8 -4
  338. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  339. package/package.json +3 -2
  340. package/wire-changes/server@7.142.0.json +639 -0
  341. package/wire-changes/server@7.143.0.json +1167 -0
@@ -1,6 +1,6 @@
1
1
  import { type UsageRow } from "../usage-analytics.js";
2
2
  import type { TaskStatus } from "@sema-agent/core";
3
- import { StoreBootRefusalError, type FenceLanded, type FencedRun, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
3
+ import { StoreBootRefusalError, type FenceLanded, type FencedRun, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef, type SettledLegMemoryObservation } from "./store-contracts.js";
4
4
  import type { RunStoreCheckpointProbe } from "./memory-run-store.js";
5
5
  import type { LedgerEventType } from "../trace/ledger-events.js";
6
6
  import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
@@ -41,6 +41,14 @@ export declare class FileRunStore implements InProcessClaimFence {
41
41
  private readonly events;
42
42
  /** taskId → the open append log (one O_APPEND fd per run, lazily opened, held for lifetime). */
43
43
  private readonly eventLogs;
44
+ /** `<root>/run-blobs/` — one section-blob ledger per session (plane 4 of the header). */
45
+ private readonly blobsDir;
46
+ /** sessionId → (digest → section body): the index of plane 4 (hydrated per session that has run rows). */
47
+ private readonly sectionBlobs;
48
+ /** sessionId → the open section-blob ledger (lazily opened, held until the session is deleted / dispose). */
49
+ private readonly blobLogs;
50
+ /** `(taskId, seq)` of manifest rows already reported as unresolvable (one report per row per store instance = per process). */
51
+ private readonly unresolvedReported;
44
52
  /** [ref] the checkpoint-table stand-in (see memory-run-store.ts {@link RunStoreCheckpointProbe} — the full
45
53
  * rationale lives on the interface); absent ⇒ the suspended-run reapers stay honest NO-OPs. */
46
54
  private checkpointProbe?;
@@ -61,6 +69,11 @@ export declare class FileRunStore implements InProcessClaimFence {
61
69
  private runJsonPath;
62
70
  private eventsPath;
63
71
  private activePath;
72
+ /** A session's section-blob ledger. The file name is core's `sanitizeScope` form (readable prefix + sha256 of the id), not the
73
+ * bare id: two ids that differ only in letter case are one file on a case-insensitive file system (macOS by default), and a
74
+ * deleted session must never take another session's blocks with it. `undefined` only for a run row read back from a damaged
75
+ * run.json whose session id is not a string — such a row has no ledger (its manifest rows are stored whole). */
76
+ private blobLedgerPath;
64
77
  private spaceCommitPath;
65
78
  /** One space's commit record, or `undefined` (no file). A record that is not this store's shape is a loud read failure
66
79
  * (the reader — the next run's connect — refuses; it never guesses that no commit is in flight). */
@@ -129,6 +142,22 @@ export declare class FileRunStore implements InProcessClaimFence {
129
142
  isPreemptRequested(taskId: string, owner: string | null): Promise<boolean>;
130
143
  heartbeat(taskId: string, owner: string | null): Promise<void>;
131
144
  appendEvent(taskId: string, seq: number, type: LedgerEventType, data: unknown): Promise<void>;
145
+ /**
146
+ * 写口里第四个盘面的那一段(与事件行的追加在**同一同步调用**里,块在前):帧经编解码拆成引用形 + 段体,本会话块账本里还没有的段体先追加
147
+ * (一批一次 fsync:事件行本身 fsync:false,而一只块被同会话之后每一条清单行引用 —— 丢一行丢一帧,丢一块丢一串帧),再把引用形交回给
148
+ * 事件行的追加。块追加抛 ⇒ 原样上抛:事件行不写,不退回整帧(与事件行自己写失败同一条路,汇点的串行写口留 seq 洞)。
149
+ * 这条 run 没有行(会话不详)⇒ 没有块账本可挂 ⇒ 帧原样存:和类型里「没有一段用引用」的合法实例,读口原样交出。
150
+ */
151
+ private storeSections;
152
+ private blobLogFor;
153
+ /** Drop a session's section-blob ledger: the file first, then the open fd and the index. The file removal is NOT best-effort
154
+ * (unlike {@link dropRun}'s directory): it is the delete's first destructive step, so a removal that fails throws before
155
+ * anything else changed — the session delete answers an error and a retry starts from the same state, instead of leaving
156
+ * an index that no longer matches the disk. (`AppendLog.close` never throws: it swallows its own `closeSync`.) */
157
+ private dropSectionBlobs;
158
+ /** 读口的悬空引用臂:清单行有一段装不回 ⇒ 这一帧这一次不交出(永不交出缺段的清单),每 `(taskId, seq)` 每只店实例(= 每进程)留一次 F 类痕;
159
+ * 帧仍在索引里,`maxSeq` / `retainedFrom` 照旧按存位算(下一个写者的 seq 不会撞上它)。 */
160
+ private reportUnresolved;
132
161
  maxSeq(taskId: string): Promise<number>;
133
162
  retainedFrom(taskId: string): Promise<number>;
134
163
  getEvents(taskId: string, afterSeq: number): Promise<RunEvent[]>;
@@ -169,6 +198,11 @@ export declare class FileRunStore implements InProcessClaimFence {
169
198
  * `createdAt DESC, taskId DESC`,与本店 {@link FileRunStore.listSessions} 挑 `rn=1` 那一行的比较器逐字同一份)。
170
199
  */
171
200
  latestRunForSession(sessionId: string): Promise<LatestRunRef | undefined>;
201
+ /**
202
+ * [ref] —— 这个会话**最近一条已结腿**与它的记忆观测(规则属主 = `store-contracts.ts` 的 {@link SettledLegMemoryObservation};
203
+ * {@link SqlRunStore.latestMemoryObservationForSession} 的孪生:同一只已结谓词(`isTerminalRunStatus`)、同一个排序口径 —— 与本店 {@link FileRunStore.latestRunForSession} 的比较器逐字同一份)。
204
+ */
205
+ latestMemoryObservationForSession(sessionId: string): Promise<SettledLegMemoryObservation | undefined>;
172
206
  /** DISTINCT sessions newest-first by last activity (the CC /resume picker): latest run's preview/status + first/last/count. */
173
207
  listSessions(opts: {
174
208
  owner?: string;
@@ -4,10 +4,11 @@ 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 { RUN_HOLDER_DEATH_CODES, RUN_ORPHANED_ERROR, RUN_STALLED_ERROR, StoreBootRefusalError, buildRunOrphanedError, readLegacyHolderDeathCode } from "./store-contracts.js";
10
+ import { joinFromStore, splitForStore } from "./wiring-section-codec.js";
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";
13
14
  import { createInProcessSpaceCommitTable, fenceSpaceCommitAtTerminal, SPACE_COMMIT_RECORD_SCHEMA } from "../workspace-space-commit.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));
@@ -595,6 +682,16 @@ export class FileRunStore {
595
682
  }
596
683
  return latest === undefined ? undefined : { taskId: latest.taskId, owner: latest.owner, createdAt: latest.createdAt.toISOString() };
597
684
  }
685
+ async latestMemoryObservationForSession(sessionId) {
686
+ let latest;
687
+ for (const r of this.runs.values()) {
688
+ if (r.sessionId !== sessionId || !isTerminalRunStatus(r.status))
689
+ continue;
690
+ if (latest === undefined || r.createdAt.getTime() > latest.createdAt.getTime() || (r.createdAt.getTime() === latest.createdAt.getTime() && r.taskId > latest.taskId))
691
+ latest = r;
692
+ }
693
+ return latest === undefined ? undefined : settledLegObservationOf(latest.taskId, latest.result);
694
+ }
598
695
  async listSessions(opts) {
599
696
  const bySession = new Map();
600
697
  for (const r of this.runs.values()) {
@@ -651,6 +748,7 @@ export class FileRunStore {
651
748
  const claimed = this.active.get(sessionId);
652
749
  if (claimed !== undefined)
653
750
  return { active: claimed };
751
+ this.dropSectionBlobs(sessionId);
654
752
  let removed = 0;
655
753
  for (const [taskId, r] of [...this.runs]) {
656
754
  if (r.sessionId !== sessionId)
@@ -1014,7 +1112,7 @@ export class FileRunStore {
1014
1112
  return new Set([...this.runs.values()].map((r) => r.sessionId));
1015
1113
  }
1016
1114
  dispose() {
1017
- for (const log of this.eventLogs.values()) {
1115
+ for (const log of [...this.eventLogs.values(), ...this.blobLogs.values()]) {
1018
1116
  try {
1019
1117
  log.close();
1020
1118
  }
@@ -1022,6 +1120,7 @@ export class FileRunStore {
1022
1120
  }
1023
1121
  }
1024
1122
  this.eventLogs.clear();
1123
+ this.blobLogs.clear();
1025
1124
  }
1026
1125
  }
1027
1126
  //# sourceMappingURL=file-run-store.js.map
@@ -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
@@ -151,7 +151,7 @@ export declare class LocalCheckpointStore {
151
151
  * 唯一的读不动形是账本重放级(整店同时读不动)。所以 SQL 孪生那道 `version > MAX_SUPPORTED` 的
152
152
  * `unparseable` 臂在这里没有对应物;本口的 `unparseable` 只由**窄读器**判(blob 形不合)。
153
153
  * · **窄读器是同一只** `pendingActionToolCallId`(与 SQL 孪生共用,零第二份手抄):身份三元组的第一维
154
- * `sourceTaskId`、`boundInputHash`、以及「读不出 vs 确定不匹配」的三态,全部由它一家判。
154
+ * `sourceSessionId`、`boundInputHash`、以及「读不出 vs 确定不匹配」的三态,全部由它一家判。
155
155
  */
156
156
  findCheckpointCandidatesForAsk(scope: string, sessionId: string, toolCallId: string, sinceMs: number): Promise<CheckpointAskCandidate[]>;
157
157
  /**
@@ -278,12 +278,12 @@ export class LocalCheckpointStore {
278
278
  const base = { token: t, status: cp.status, createdAtMs: cp.createdAt };
279
279
  const derived = pendingActionToolCallId(cp);
280
280
  if (!derived.readable) {
281
- out.push({ ...base, sourceTaskId: null, boundCallId: null, boundInputHash: null, unparseable: true });
281
+ out.push({ ...base, sourceSessionId: null, boundCallId: null, boundInputHash: null, unparseable: true });
282
282
  continue;
283
283
  }
284
284
  if (derived.toolCallId !== toolCallId)
285
285
  continue;
286
- out.push({ ...base, sourceTaskId: derived.sourceTaskId, boundCallId: derived.toolCallId, boundInputHash: derived.boundInputHash });
286
+ out.push({ ...base, sourceSessionId: derived.sourceSessionId, boundCallId: derived.toolCallId, boundInputHash: derived.boundInputHash });
287
287
  }
288
288
  return out.sort((a, b) => a.createdAtMs - b.createdAtMs || (a.token < b.token ? -1 : a.token > b.token ? 1 : 0));
289
289
  }
@@ -272,6 +272,8 @@ export declare class LocalSessionStore implements SessionStore {
272
272
  /**
273
273
  * 改写面与执行席的读法({@link placementProbe} 的一形):placed ⇒ 那份元组;普通 ⇒ `undefined`;行头读不出(`corrupt_session` / `invalid_session`)⇒ `undefined` —— 没有可读的
274
274
  * placement 记录,这一行按普通行答,内容读不读得出归真正读内容的那一读(坏档照样换得掉,与 forking 探针同一条规矩);说不出(`storage`)⇒ 抛那只故障。
275
+ * core 7.61.0 起 repo 的探针按行头的元组自己读、不整头解码:placed 行的属主格坏了探针照答元组(本臂不再接得住 placed 行)—— 探针拒只剩「行头记录整个读不出」,
276
+ * 那时没有任何元组可守(`test/local-session-placement.test.ts` 的 [ref] 三格)。
275
277
  */
276
278
  private placedRecordOf;
277
279
  /** {@link placedRecordOf} 的是非形。 */
@@ -288,7 +290,8 @@ export declare class LocalSessionStore implements SessionStore {
288
290
  private metaOf;
289
291
  /**
290
292
  * {@link metaOf} 的本体(三态,不抛「用不了」):边档里有那一格 ⇒ 读它;没有 ⇒ 问**唯一探针** {@link probeArchive} 一次 —— 不在 ⇒ 无此会话;在而读得出 ⇒ 补铸({@link cellOfPresent});
291
- * 读不出 ⇒ {@link UnusableArchive}(**不补铸**:不替一份读不出的存档铸化身)。要动存档的读者({@link metaOf})把它上抛;不动存档、只要「有没有」的读者
293
+ * 读不出 ⇒ {@link UnusableArchive}(**不补铸**:不替一份读不出的存档铸化身;`corrupt_session` / `invalid_session` 两词的故障换成具名拒 {@link SessionOwnerUnreadableError} ——
294
+ * 格缺 ∧ 存档用不了 = 这只会话没有可读的属主,见 {@link ownerUnreadableArchive})。要动存档的读者({@link metaOf})把它上抛;不动存档、只要「有没有」的读者
292
295
  * ({@link executionPlacementBackfill})原样收下。
293
296
  */
294
297
  private metaRead;
@@ -304,7 +307,8 @@ export declare class LocalSessionStore implements SessionStore {
304
307
  * 叶子出自会话存档(本店的**内容**;core `SessionRepo.headOf`:File repo 读日志首记录与尾、不重放 —— 存档首行的属主 / 令牌本店不读)。
305
308
  * 存档读不出(会话头坏了、I/O 故障)⇒ 头照答行上的属主与住客,叶子那一格带着那只故障(`UnreadableLeaf`,读叶子的人收到它):只判归属的读者
306
309
  * 不因坏存档改判,坏存档只让读内容的那一位看见(SQL 孪生的头不碰 `session_event`,同一条律;规则在 `session-incarnation.ts` 头注)。
307
- * 行本身读不出(边档里还没有这一格、要从存档推出这只会话在不在,而存档读不出 —— {@link metaOf} 的探针)⇒ 整只拒。
310
+ * 行本身读不出(边档里还没有这一格、要从存档推出这只会话在不在,而存档读不出 —— {@link metaOf} 的探针)⇒ 整只拒:会话头坏 / 日志结构走不通 ⇒ 具名拒
311
+ * {@link SessionOwnerUnreadableError}(没有可读的属主;码与句子是原故障的),说不出在不在的 I/O 级故障 ⇒ 原故障。
308
312
  * 两样住在两只文件里 ⇒ 先读那一格、读叶子、再同步复读那一格:格没了(读间被删)或换了主 / 换了住客 ⇒ `undefined`(调用方按删处理),
309
313
  * 所以一只头从不把这一代的属主配上另一代的叶子([ref] 六轮复审同一条)。`undefined` = 无此会话。
310
314
  * 化身那一格经 `headFromRow` 的 `absent` 读法(边档对象形恒有令牌;读不出的边档整只严格拒在 `metaOf` 之前)。
@@ -349,9 +353,9 @@ export declare class LocalSessionStore implements SessionStore {
349
353
  writeSessionRowCells(sessionId: string, cells: SessionRowPatch, how: ReplaySessionRowWrite): Promise<ReplaySessionRowWriteOutcome<SessionSummary>>;
350
354
  /**
351
355
  * 写原语锁住的那一行(调用方持这只会话的写锁并已 {@link loadRowSidecars}):会话元数据那一格(属主 `owner ?? null` —— 与头读、列表行同读;化身经
352
- * `incarnationFromCell` 的 `absent` 读法;执行位 `mirror`)+ 列表面上有它(会话仓里有;`forking` 中间态的存档不在 ⇒ 不在列表上)+ 两只边档的格。
353
- * 没有那一格或不在列表面上 ⇒ `undefined`(没有行)。委派分区行(placed)不上列表面(repo 的 `list()` 按存档行头排除,义务 2)⇒ 走到这里的行恒非 placed,
354
- * `placed: false` 是列表面那一判的投影,不是另一读。
356
+ * `incarnationFromCell` 的 `absent` 读法;执行位 `mirror`)+ 行集里有它({@link rowHeaderOf};`forking` 中间态的存档不在 ⇒ 不在列表上)+ 两只边档的格。
357
+ * 没有那一格或不在列表面上 ⇒ `undefined`(没有行)。委派分区行(placed)不上列表面(repo 的 `list()` 按存档行头排除,义务 2;行头读不出的行没有可读的 placement 记录、
358
+ * 按普通行读 —— 文件头注那一条)⇒ `placed: false` 是列表面那一判的投影,不是另一读。存档读不出的行照样是一行(行格住在边档,写得了;HTTP 改名口的坏档判据排在本原语之前)。
355
359
  */
356
360
  private lockedRowOf;
357
361
  /** 两只边档上这只会话的可写格(已发布的值;缺键 = 缺省)。调用方先 {@link loadRowSidecars}。 */
@@ -361,10 +365,35 @@ export declare class LocalSessionStore implements SessionStore {
361
365
  /** 应答行(锁内另读):列表行同一只合成 + 读到它时那一格上的住客。不在列表面上 / 没有那一格 ⇒ `undefined`。 */
362
366
  private listRowOf;
363
367
  /** ONE session's list row — {@link listSessions}' projection ({@link summaryOf}, the same synthesis) for one id;
364
- * `undefined` = not a row of the list face (not in the session repo). */
368
+ * `undefined` = not a row of the list face ({@link rowHeaders}). */
365
369
  sessionSummaryOf(sessionId: string): Promise<SessionSummary | undefined>;
366
- /** 会话仓里这只会话的列表元数据(列表面上的行 = `repo.list()` 里的一项)。 */
367
- private listedMeta;
370
+ /**
371
+ * 本店的**行集** —— 唯一的会话枚举(列表 {@link listSessions}、一次性迁移 M33 的步 1 读它;按 id 读的 {@link rowHeaderOf} 是同一只判据的一只 id 形):
372
+ * · 引擎仓的列表(core `repo.list()`:存档**行头**读得出、非 placed)—— 行头读得出的行;
373
+ * · ∪ 会话元数据边档里有格、不在引擎仓列表里的 id,经 {@link headerUnreadableRowOf}:存档头读了抛、且不是 placed 行 ⇒ 行头读不出的行(带那只故障);
374
+ * 不抛(存档不在:fork 中间态 / 删除中;或读间新建)/ placed 行(行头读得出,repo 的 `listPlaced` 认得它,尾部再坏也不上列表面)⇒ 不是行集里的行。
375
+ * 边档里没有格、存档头又读不出的会话(7.104.0 之前写下、此后从没被读过)没有一格可读的行事实 —— 属主读不出 ⇒ 不进行集(fail-closed,与归属门同读:
376
+ * {@link metaOf} 判不了它在不在 ⇒ 整只拒);运维面由 core 列表的披露座与起服 warn 点名它。
377
+ * 「行头读不读得出」(行集,M33 回填行事实问的就是它)与「叶子读不读得出」(列表行的 `unreadable`,{@link listedRowOf})是两件事、各一只读法。
378
+ */
379
+ private rowHeaders;
380
+ /**
381
+ * 行集里的这一行({@link rowHeaders} 的按 id 一形:同一只判据,只判这一只 id 的行 —— 别的会话读不出不改它的答)。`undefined` = 不是行集里的行。
382
+ * ⚠️ 如实:取它的行头仍经引擎仓列表(`repo.list()` 读一遍各会话的头),所以别的会话的头坏了,这一次读照旧为它报一次读坏披露;按 id 直读不在本形里。
383
+ */
384
+ private rowHeaderOf;
385
+ /** 不在引擎仓列表里、边档有格的一只 id:存档头读了抛、且不是 placed 行 ⇒ 行头读不出的那一行;否则 `undefined`(见 {@link rowHeaders})。 */
386
+ private headerUnreadableRowOf;
387
+ /**
388
+ * 委派分区行的 id 集的读者(repo 记 placement ⇒ 它的 `listPlaced`,行头那一读;不记 ⇒ 空集 —— 那种 repo 里没有 placed 行)。惰性、一次读:只在有一只 id 的存档头读抛、
389
+ * 要分「行头读不出」与「行头读得出的 placed 行尾部坏了」时才读。
390
+ */
391
+ private createPlacedIdsReader;
392
+ /**
393
+ * 列表面上的一行的内容那一半 = 头读的**叶子**那一读({@link archiveHeadOf},与 {@link headOf} 的叶子同一读):行头读不出 ⇒ 读不出(那只故障);行头读得出 ⇒ 再读叶子,
394
+ * 抛 ⇒ 读不出(尾部 I/O 故障之类:行头好、头读照样抛);否则读得出。所以行上的 `unreadable` 与头读、读口对同一只会话的答复同读。
395
+ */
396
+ private listedRowOf;
368
397
  /** [ref] —— 换源通告的基线读(local 孪生;三态读法与 SQL 两孪生的 `session_meta.instruction_source` 同一只编解码)。 */
369
398
  readInstructionSource(sessionId: string): Promise<InstructionSourceBaseline>;
370
399
  /**
@@ -481,6 +510,10 @@ export declare class LocalSessionStore implements SessionStore {
481
510
  * `lastTaskRunId` = that run's `result.runId`). One call per list (not per row); a session with no
482
511
  * run row ⇒ `0 / "" / null` (TiDB's null→"" mapping); a run-store read failure throws (never `0 / ""`).
483
512
  *
513
+ * - `unreadable` — present-iff the row's head leaf cannot be read ({@link listedRowOf}: the archive header, or the tail the head read
514
+ * scans): the row's facts above still come from its session-meta cell; `objectivePreview` is null; the marker's
515
+ * `errorCode` is what the session's own reads answer.
516
+ *
484
517
  * Keyset matches the contract: STRICTLY older than the cursor, ties broken by id DESC; `limit` is honored after
485
518
  * the in-memory sort. Cheap (a local single-user store holds few sessions). Errors reading one session's entries
486
519
  * degrade that row's preview to null rather than failing the whole list.
@@ -693,7 +726,7 @@ export declare class LocalSessionStore implements SessionStore {
693
726
  /**
694
727
  * 一次性迁移 M33 的 local 腿(`LocalBackend.runOneTimeMigrations` 调;起服、先于任何请求;窗内每次起服都跑,第二次起零命中):
695
728
  * 0. 恢复先行({@link settleArchiveSnapshots},幂等);
696
- * 1. **枚举**:id 全集 = 引擎仓的列表(读得出头的存档)∪ 边档全部键;只在边档里的、头读抛的 ⇒ 计 unreadable(步 3 整档读抛的同计)。两边都不在的读不出存档(列表跳过它、边档里没它的格)
729
+ * 1. **枚举**(行集 `rowHeaders`):id 全集 = 引擎仓的列表(读得出头的存档)∪ 边档全部键;只在边档里的、头读抛且不是 placed 行(行头读得出)的 ⇒ 计 unreadable(步 3 整档读抛的同计)。两边都不在的读不出存档(列表跳过它、边档里没它的格)
697
730
  * 对本店与引擎同样不可见,不计;
698
731
  * 2. **行回填**:列表里每一只存档 —— 格缺 ⇒ 建一格(化身新铸、属主「从没被记下」,与补铸同义);格缺建档时刻 ⇒ 写存档头的;格缺谱系而存档头有 ⇒ 写它。只写行(边档的一次提交),
699
732
  * 然后一道**落盘屏障**(边档文件与目录各 fsync)—— 在这之前不碰任何存档;