@sema-agent/server 7.144.0 → 7.146.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 (305) hide show
  1. package/MIGRATION.md +621 -0
  2. package/README.md +3 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +233 -54
  5. package/deploy/facts/CHANGES.json +25 -0
  6. package/deploy/facts/README.md +57 -0
  7. package/deploy/facts/lanes.json +54 -0
  8. package/deploy/facts/lanes.schema.json +57 -0
  9. package/deploy/facts/sandbox-rbac.json +113 -0
  10. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  11. package/deploy/facts/sealed-key.json +9 -0
  12. package/deploy/facts/sealed-key.schema.json +52 -0
  13. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  14. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  15. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  16. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  17. package/deploy/sema-up/chart/values.yaml +7 -0
  18. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  19. package/dist/adoption/import-limits.d.ts +6 -0
  20. package/dist/adoption/import-limits.js +7 -0
  21. package/dist/adoption/import.d.ts +62 -0
  22. package/dist/adoption/import.js +107 -0
  23. package/dist/adoption/wire.d.ts +52 -0
  24. package/dist/adoption/wire.js +9 -0
  25. package/dist/approval-ask-machine.d.ts +2 -2
  26. package/dist/approval-card.d.ts +3 -12
  27. package/dist/approval-card.js +0 -4
  28. package/dist/approval-gate-currency.d.ts +1 -1
  29. package/dist/approval-gate-currency.js +1 -1
  30. package/dist/approval-reconciler.d.ts +1 -1
  31. package/dist/audit.d.ts +2 -21
  32. package/dist/audit.js +0 -9
  33. package/dist/boot/deployment-mods.d.ts +11 -1
  34. package/dist/boot/deployment-mods.js +15 -2
  35. package/dist/boot/device-lane.js +2 -0
  36. package/dist/boot/engine-lease.d.ts +193 -21
  37. package/dist/boot/engine-lease.js +146 -20
  38. package/dist/boot/execution-env.d.ts +4 -0
  39. package/dist/boot/execution-env.js +12 -0
  40. package/dist/boot/exit-boundary.d.ts +50 -0
  41. package/dist/boot/exit-boundary.js +32 -0
  42. package/dist/boot/exit-last.d.ts +20 -4
  43. package/dist/boot/exit-last.js +21 -4
  44. package/dist/boot/governance-seams.js +1 -0
  45. package/dist/boot/memory-consolidation.d.ts +29 -17
  46. package/dist/boot/memory-consolidation.js +26 -15
  47. package/dist/boot/reapers.d.ts +12 -4
  48. package/dist/boot/reapers.js +39 -15
  49. package/dist/boot/resolve-spec.d.ts +2 -0
  50. package/dist/boot/resolve-spec.js +38 -15
  51. package/dist/boot/runner-deps.js +1 -1
  52. package/dist/boot/session-faces.d.ts +1 -1
  53. package/dist/boot/session-faces.js +6 -4
  54. package/dist/boot/shutdown.js +27 -9
  55. package/dist/boot/stage-01-config.js +1 -1
  56. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  57. package/dist/boot/stage-03-store-backend.js +2 -2
  58. package/dist/boot/stage-04-stores.d.ts +1 -0
  59. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  60. package/dist/boot/stage-05-execution-env.js +3 -3
  61. package/dist/boot/stage-06-runners.d.ts +3 -0
  62. package/dist/boot/stage-06-runners.js +11 -10
  63. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  64. package/dist/boot/stage-07-capability-layer.js +7 -2
  65. package/dist/boot/stage-08-reapers.d.ts +3 -0
  66. package/dist/boot/stage-08-reapers.js +3 -3
  67. package/dist/boot/stage-09-leader.d.ts +4 -1
  68. package/dist/boot/stage-10-http-server.d.ts +4 -1
  69. package/dist/boot/stage-10-http-server.js +4 -3
  70. package/dist/boot/stores.d.ts +1 -0
  71. package/dist/boot/stores.js +35 -19
  72. package/dist/boot/workflow-orchestration.d.ts +1 -1
  73. package/dist/boot/workflow-orchestration.js +2 -1
  74. package/dist/capabilities/composite-members.d.ts +3 -1
  75. package/dist/capabilities/composite-members.js +3 -1
  76. package/dist/capabilities/scenarios.d.ts +2 -2
  77. package/dist/capability-facts.d.ts +18 -1
  78. package/dist/capability-facts.js +25 -7
  79. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  80. package/dist/config-catalog.js +13 -4
  81. package/dist/config-d-migration.d.ts +3 -2
  82. package/dist/config-provider.d.ts +2 -2
  83. package/dist/config-types.d.ts +43 -4
  84. package/dist/config.d.ts +6 -1
  85. package/dist/config.js +67 -11
  86. package/dist/deleted-session-ids.d.ts +19 -0
  87. package/dist/deleted-session-ids.js +26 -0
  88. package/dist/deploy-facts.d.ts +155 -0
  89. package/dist/deploy-facts.js +94 -0
  90. package/dist/device-ws-hub.d.ts +48 -3
  91. package/dist/device-ws-hub.js +48 -2
  92. package/dist/error-code-family.d.ts +35 -0
  93. package/dist/error-code-family.js +26 -0
  94. package/dist/fleet/drain-entry.d.ts +39 -3
  95. package/dist/fleet/drain-entry.js +6 -0
  96. package/dist/fleet/fleet-bus.d.ts +15 -4
  97. package/dist/fleet/fleet-bus.js +17 -3
  98. package/dist/hooks/branch-transcript.d.ts +1 -1
  99. package/dist/hooks/branch-transcript.js +1 -0
  100. package/dist/hooks/classic-stations.d.ts +25 -8
  101. package/dist/hooks/classic-stations.js +29 -3
  102. package/dist/hooks/hook-runner.d.ts +33 -16
  103. package/dist/hooks/hook-runner.js +166 -73
  104. package/dist/hooks/hook-source.d.ts +14 -2
  105. package/dist/hooks/hook-source.js +8 -0
  106. package/dist/http/active-run-conflict.d.ts +1 -1
  107. package/dist/http/active-run-conflict.js +1 -1
  108. package/dist/http/admission.js +13 -2
  109. package/dist/http/checkpoint-ctx.d.ts +60 -71
  110. package/dist/http/checkpoint-ctx.js +35 -40
  111. package/dist/http/dispatch.js +18 -2
  112. package/dist/http/durable-run-leg.d.ts +5 -0
  113. package/dist/http/durable-run-leg.js +8 -6
  114. package/dist/http/execution-context.d.ts +4 -0
  115. package/dist/http/execution-context.js +9 -0
  116. package/dist/http/health-self-report.d.ts +6 -2
  117. package/dist/http/health-self-report.js +3 -2
  118. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  119. package/dist/http/memory-compliance-failure-reply.js +2 -15
  120. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  121. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  122. package/dist/http/principal-gate.d.ts +35 -12
  123. package/dist/http/principal-gate.js +16 -12
  124. package/dist/http/request-guards.d.ts +1 -1
  125. package/dist/http/request-guards.js +5 -5
  126. package/dist/http/resume-legs.d.ts +22 -0
  127. package/dist/http/resume-legs.js +31 -20
  128. package/dist/http/route-ctx.d.ts +26 -10
  129. package/dist/http/route-table.js +2 -0
  130. package/dist/http/routes/adoption.d.ts +11 -0
  131. package/dist/http/routes/adoption.js +80 -6
  132. package/dist/http/routes/agents-roster.js +1 -0
  133. package/dist/http/routes/approvals-assistant.d.ts +20 -1
  134. package/dist/http/routes/approvals-assistant.js +29 -7
  135. package/dist/http/routes/background.js +1 -0
  136. package/dist/http/routes/capabilities.js +4 -1
  137. package/dist/http/routes/diagnostics.d.ts +9 -14
  138. package/dist/http/routes/diagnostics.js +10 -20
  139. package/dist/http/routes/engine.d.ts +31 -0
  140. package/dist/http/routes/engine.js +81 -0
  141. package/dist/http/routes/memory-bundle.js +3 -0
  142. package/dist/http/routes/memory-consolidation.js +3 -5
  143. package/dist/http/routes/memory-origin.d.ts +1 -1
  144. package/dist/http/routes/memory-origin.js +2 -4
  145. package/dist/http/routes/memory-policy.js +5 -1
  146. package/dist/http/routes/observability.js +3 -6
  147. package/dist/http/routes/rules.d.ts +1 -1
  148. package/dist/http/routes/rules.js +5 -2
  149. package/dist/http/routes/runs.js +7 -3
  150. package/dist/http/routes/session-sync.js +24 -25
  151. package/dist/http/routes/sessions-list.d.ts +1 -1
  152. package/dist/http/routes/sessions.js +4 -0
  153. package/dist/http/routes/tasks.js +35 -14
  154. package/dist/http/routes/trace-usage.js +1 -1
  155. package/dist/http/run-concurrency-cap.d.ts +86 -0
  156. package/dist/http/run-concurrency-cap.js +54 -0
  157. package/dist/http/run-meta.d.ts +14 -7
  158. package/dist/http/run-meta.js +5 -2
  159. package/dist/http/server.d.ts +27 -16
  160. package/dist/http/server.js +21 -3
  161. package/dist/http/stored-body-replay.d.ts +9 -6
  162. package/dist/http/stored-body-replay.js +19 -5
  163. package/dist/http/submit-ctx.d.ts +12 -0
  164. package/dist/http/submit-ctx.js +23 -0
  165. package/dist/http/wire-types.d.ts +8 -3
  166. package/dist/json-body-limit.d.ts +8 -0
  167. package/dist/json-body-limit.js +2 -0
  168. package/dist/leader/diffout.d.ts +1 -1
  169. package/dist/local-data-root.d.ts +2 -2
  170. package/dist/memory-operator-faces.d.ts +9 -4
  171. package/dist/memory-scope-stores.d.ts +9 -7
  172. package/dist/memory-scope-stores.js +3 -14
  173. package/dist/memory-scope.d.ts +36 -0
  174. package/dist/memory-scope.js +32 -1
  175. package/dist/net-address.d.ts +53 -0
  176. package/dist/net-address.js +111 -0
  177. package/dist/observability/fail-open.d.ts +28 -12
  178. package/dist/observability/fail-open.js +28 -12
  179. package/dist/orchestration/workflow-notify-journal.js +2 -3
  180. package/dist/org-delivery-gate.js +1 -1
  181. package/dist/peer-directory.d.ts +6 -12
  182. package/dist/peer-directory.js +5 -1
  183. package/dist/plugins/approval-ask-store-file.d.ts +16 -2
  184. package/dist/plugins/approval-ask-store-file.js +21 -1
  185. package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
  186. package/dist/plugins/approval-ask-store-memory.js +11 -8
  187. package/dist/plugins/caching-session-store.d.ts +6 -1
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  190. package/dist/plugins/checkpoint-store-face.js +152 -0
  191. package/dist/plugins/file-run-store.d.ts +13 -7
  192. package/dist/plugins/file-run-store.js +12 -13
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  194. package/dist/plugins/fork-routing-session-store.js +2 -2
  195. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  196. package/dist/plugins/local-checkpoint-store.d.ts +16 -5
  197. package/dist/plugins/local-checkpoint-store.js +25 -6
  198. package/dist/plugins/local-session-store.d.ts +80 -21
  199. package/dist/plugins/local-session-store.js +79 -22
  200. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  201. package/dist/plugins/memory-engine-pg.js +96 -214
  202. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  203. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  204. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  205. package/dist/plugins/memory-engine-tidb.js +97 -227
  206. package/dist/plugins/memory-key-guards.d.ts +1 -1
  207. package/dist/plugins/memory-origin-law.d.ts +3 -3
  208. package/dist/plugins/memory-run-store.d.ts +2 -0
  209. package/dist/plugins/memory-run-store.js +6 -0
  210. package/dist/plugins/one-time-migrations.d.ts +32 -56
  211. package/dist/plugins/one-time-migrations.js +27 -119
  212. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  213. package/dist/plugins/permission-rule-store-file.js +8 -1
  214. package/dist/plugins/pg-pool.js +1 -1
  215. package/dist/plugins/pg-session-storage.d.ts +17 -4
  216. package/dist/plugins/pg-session-storage.js +8 -4
  217. package/dist/plugins/run-store-sql.d.ts +4 -0
  218. package/dist/plugins/run-store-sql.js +5 -2
  219. package/dist/plugins/schema-ensure-legs.js +2 -2
  220. package/dist/plugins/session-fork.d.ts +31 -9
  221. package/dist/plugins/session-fork.js +3 -2
  222. package/dist/plugins/session-placement.d.ts +4 -2
  223. package/dist/plugins/session-store.d.ts +1 -1
  224. package/dist/plugins/sql-json-column.d.ts +5 -1
  225. package/dist/plugins/store-backend.d.ts +11 -8
  226. package/dist/plugins/store-backend.js +8 -7
  227. package/dist/plugins/store-contracts.d.ts +1 -11
  228. package/dist/plugins/store-contracts.js +0 -9
  229. package/dist/plugins/store-sweep.d.ts +63 -0
  230. package/dist/plugins/store-sweep.js +48 -0
  231. package/dist/plugins/tidb-pool.js +1 -1
  232. package/dist/plugins/tidb-session-store.d.ts +16 -3
  233. package/dist/plugins/tidb-session-store.js +8 -4
  234. package/dist/prompt-screen.d.ts +18 -0
  235. package/dist/prompt-screen.js +5 -0
  236. package/dist/rules-consent.d.ts +56 -51
  237. package/dist/rules-consent.js +86 -14
  238. package/dist/run-acceptance.d.ts +40 -10
  239. package/dist/run-acceptance.js +38 -5
  240. package/dist/run-cancel-context.d.ts +4 -1
  241. package/dist/run-cancel-context.js +2 -1
  242. package/dist/runs.js +2 -2
  243. package/dist/sandbox-egress-policy.js +6 -11
  244. package/dist/sandbox-rbac-rules.d.ts +88 -0
  245. package/dist/sandbox-rbac-rules.js +80 -0
  246. package/dist/sealed-key-layout.d.ts +17 -0
  247. package/dist/sealed-key-layout.js +4 -0
  248. package/dist/sealed-key.js +5 -5
  249. package/dist/security.d.ts +48 -9
  250. package/dist/security.js +9 -2
  251. package/dist/session-agent.d.ts +39 -0
  252. package/dist/session-agent.js +16 -0
  253. package/dist/session-error-wire.d.ts +4 -4
  254. package/dist/session-notify-door.d.ts +5 -3
  255. package/dist/session-resident-background.d.ts +57 -0
  256. package/dist/session-resident-background.js +20 -0
  257. package/dist/session-sync-kernel.d.ts +53 -14
  258. package/dist/session-sync-kernel.js +70 -1
  259. package/dist/session-sync.d.ts +5 -3
  260. package/dist/session-workspace.d.ts +1 -0
  261. package/dist/session-workspace.js +1 -0
  262. package/dist/sighup-idle.d.ts +9 -7
  263. package/dist/sighup-idle.js +4 -5
  264. package/dist/spec-fields.d.ts +16 -0
  265. package/dist/spec-fields.js +7 -0
  266. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  267. package/dist/stored-request-env-credentials-m38.js +8 -0
  268. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  269. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +33 -429
  270. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +70 -209
  271. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  272. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  273. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  274. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  275. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  276. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  277. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  278. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  279. package/dist/task-settings.d.ts +59 -4
  280. package/dist/task-settings.js +50 -4
  281. package/dist/tool-approval.d.ts +2 -2
  282. package/dist/trace/core-keyset-guard.d.ts +8 -7
  283. package/dist/trace/engine-notice-wire.d.ts +1 -1
  284. package/dist/trace/engine-notice-wire.js +2 -0
  285. package/dist/trace/exit-seat.d.ts +6 -0
  286. package/dist/trace/exit-seat.js +1 -0
  287. package/dist/trace/model-segment.d.ts +3 -2
  288. package/dist/trace/model-segment.js +16 -8
  289. package/dist/trace/project.js +9 -0
  290. package/dist/trace/redact.d.ts +79 -4
  291. package/dist/trace/redact.js +523 -123
  292. package/dist/trace/self-minted-wire.d.ts +391 -1
  293. package/dist/trace/self-minted-wire.js +145 -0
  294. package/dist/trace/wire-projection-faces.d.ts +1 -1
  295. package/dist/trace/wire-projection-faces.js +1 -1
  296. package/dist/usage-analytics.d.ts +4 -0
  297. package/package.json +12 -4
  298. package/scripts/drain-check-local.mjs +8 -29
  299. package/scripts/drain-check.mysql.sql +3 -24
  300. package/scripts/drain-check.pg.sql +3 -24
  301. package/skills/update-config.md +1 -1
  302. package/wire-changes/server@7.145.0.json +146 -0
  303. package/wire-changes/server@7.146.0.json +3221 -0
  304. package/dist/approval-batch-census.d.ts +0 -27
  305. package/dist/approval-batch-census.js +0 -27
@@ -4,6 +4,21 @@ import { liveHostForegroundChildCount, reapHostForegroundChildren } from "../plu
4
4
  import { liveEphemeralHostWorkspaceCount, reapEphemeralHostWorkspaces } from "../plugins/host-workspace-registry.js";
5
5
  import { seatText } from "../trace/exit-seat.js";
6
6
  const PROCESS_EXIT_INCLUDES_RETAINED = false;
7
+ export function countShellsExitWouldKill(opts) {
8
+ const registry = opts.registry ?? defaultTaskRegistry;
9
+ try {
10
+ return registry.countRunningBackgroundShells({ includeRetained: PROCESS_EXIT_INCLUDES_RETAINED });
11
+ }
12
+ catch (err) {
13
+ try {
14
+ opts.onUnreadable(err);
15
+ }
16
+ catch (reportErr) {
17
+ console.error("engine_handover_shell_count_report_threw", reportErr);
18
+ }
19
+ return 1;
20
+ }
21
+ }
7
22
  export function installProcessExitBoundary({ logger }) {
8
23
  const reapOwnChildProcesses = () => {
9
24
  let backgroundSoftStopped = 0;
@@ -81,8 +96,25 @@ export function installProcessExitBoundary({ logger }) {
81
96
  };
82
97
  process.once("exit", onProcessExit);
83
98
  let disposed = false;
99
+ let shellCountUnreadableReported = false;
100
+ const shellsExitWouldKill = () => countShellsExitWouldKill({
101
+ onUnreadable: (err) => {
102
+ if (shellCountUnreadableReported)
103
+ return;
104
+ shellCountUnreadableReported = true;
105
+ let text;
106
+ try {
107
+ text = String(err);
108
+ }
109
+ catch {
110
+ text = Object.prototype.toString.call(err);
111
+ }
112
+ logger.warn("engine_handover_shell_count_unreadable", { counted: 1, err: seatText("operator-log-text", text) });
113
+ },
114
+ });
84
115
  return {
85
116
  reapChildProcessesEarly: reapOwnChildProcesses,
117
+ shellsExitWouldKill,
86
118
  dispose: () => {
87
119
  if (disposed)
88
120
  return;
@@ -1,10 +1,18 @@
1
1
  import { z } from "zod";
2
+ /** 本构建写的格式号([ref] 抬到 2;[ref] 抬到 3:必填 `lane`,退 `orphan` / `firstAttachWindowExpired`)。格式 1 = 无 `format` 键的旧形。 */
3
+ export declare const EXIT_LAST_FORMAT = 3;
2
4
  /** 读回 schema(宪法 [ref] §2:边界读一律 safeParse,不裸铸)。写侧同形。 */
3
5
  declare const ExitLastSchema: z.ZodObject<{
6
+ format: z.ZodLiteral<3>;
4
7
  at: z.ZodString;
5
8
  version: z.ZodString;
6
9
  pid: z.ZodNumber;
7
- orphan: z.ZodBoolean;
10
+ lane: z.ZodEnum<{
11
+ orphan: "orphan";
12
+ handover: "handover";
13
+ awaitingFirstAttach: "awaitingFirstAttach";
14
+ owned: "owned";
15
+ }>;
8
16
  reason: z.ZodString;
9
17
  idleForMs: z.ZodNumber;
10
18
  attached: z.ZodNumber;
@@ -15,9 +23,17 @@ declare const ExitLastSchema: z.ZodObject<{
15
23
  export type ExitLastInfo = z.infer<typeof ExitLastSchema>;
16
24
  export declare function exitLastPath(dataRoot: string): string;
17
25
  /** 自退那一刻写留痕(同步;自身绝不抛 —— 留痕写失败不得阻塞停机)。 */
18
- export declare function writeExitLast(dataRoot: string, info: Omit<ExitLastInfo, "at" | "pid">): void;
19
- /** boot 读回:在场读回、缺席/坏字节/坏形回 `undefined`(绝不抛 —— 留痕坏了不能挡启动)。 */
20
- export declare function readExitLast(dataRoot: string): ExitLastInfo | undefined;
26
+ export declare function writeExitLast(dataRoot: string, info: Omit<ExitLastInfo, "format" | "at" | "pid">): void;
27
+ /** {@link readExitLast} 的读数:本构建格式读成了 ⇒ `found`;文件格式号不是 {@link EXIT_LAST_FORMAT} ⇒ `formatMismatch`(契约 6)。 */
28
+ export type ExitLastReading = {
29
+ readonly kind: "found";
30
+ readonly info: ExitLastInfo;
31
+ } | {
32
+ readonly kind: "formatMismatch";
33
+ readonly fileFormat: number;
34
+ };
35
+ /** boot 读回:本构建格式读回 `found`、别的格式号回 `formatMismatch`;缺席/坏字节/本格式坏形回 `undefined`(绝不抛 —— 留痕坏了不能挡启动)。 */
36
+ export declare function readExitLast(dataRoot: string): ExitLastReading | undefined;
21
37
  /** 读回并报过之后即清(幂等,缺席零抛):在场 ⇔ **上一次**退出是自退。 */
22
38
  export declare function clearExitLast(dataRoot: string): void;
23
39
  export {};
@@ -1,11 +1,14 @@
1
1
  import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { z } from "zod";
4
+ import { ENGINE_LANES } from "./engine-lease.js";
5
+ export const EXIT_LAST_FORMAT = 3;
4
6
  const ExitLastSchema = z.object({
7
+ format: z.literal(EXIT_LAST_FORMAT),
5
8
  at: z.string(),
6
9
  version: z.string(),
7
10
  pid: z.number(),
8
- orphan: z.boolean(),
11
+ lane: z.enum(ENGINE_LANES),
9
12
  reason: z.string(),
10
13
  idleForMs: z.number(),
11
14
  attached: z.number(),
@@ -18,19 +21,33 @@ export function exitLastPath(dataRoot) {
18
21
  }
19
22
  export function writeExitLast(dataRoot, info) {
20
23
  try {
21
- const body = { at: new Date().toISOString(), pid: process.pid, ...info };
24
+ const body = { format: EXIT_LAST_FORMAT, at: new Date().toISOString(), pid: process.pid, ...info };
22
25
  writeFileSync(exitLastPath(dataRoot), JSON.stringify(body) + "\n");
23
26
  }
24
27
  catch {
25
28
  }
26
29
  }
30
+ function fileFormatOf(raw) {
31
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw))
32
+ return undefined;
33
+ if (!Object.hasOwn(raw, "format"))
34
+ return 1;
35
+ const f = raw.format;
36
+ return typeof f === "number" && Number.isSafeInteger(f) ? f : undefined;
37
+ }
27
38
  export function readExitLast(dataRoot) {
28
39
  try {
29
40
  const p = exitLastPath(dataRoot);
30
41
  if (!existsSync(p))
31
42
  return undefined;
32
- const parsed = ExitLastSchema.safeParse(JSON.parse(readFileSync(p, "utf8")));
33
- return parsed.success ? parsed.data : undefined;
43
+ const raw = JSON.parse(readFileSync(p, "utf8"));
44
+ const fileFormat = fileFormatOf(raw);
45
+ if (fileFormat === undefined)
46
+ return undefined;
47
+ if (fileFormat !== EXIT_LAST_FORMAT)
48
+ return { kind: "formatMismatch", fileFormat };
49
+ const parsed = ExitLastSchema.safeParse(raw);
50
+ return parsed.success ? { kind: "found", info: parsed.data } : undefined;
34
51
  }
35
52
  catch {
36
53
  return undefined;
@@ -54,6 +54,7 @@ const DENY_CONFLICTS = {
54
54
  },
55
55
  workflows: null,
56
56
  org_memory_mount: null,
57
+ memory_consolidation: null,
57
58
  };
58
59
  function resolveGovernanceDeclarations(config) {
59
60
  return {
@@ -2,7 +2,9 @@ import { type LaneHomeDeployment } from "../execution-lane-caps.js";
2
2
  import { type MemoryScopeStores } from "../memory-scope-stores.js";
3
3
  import type { RestartSliceCtx } from "../web-admin-client/restart-signal.js";
4
4
  import type { MemoryConsolidationDriverConfig, ServiceConfig } from "../config-types.js";
5
- import { resolveMemoryConsolidationDriver, type ConsolidationWriteJudge, type ConsolidationWriteJudgeInput, type EngineNotice, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryConsolidationDriverDeps, type PermissionRuleStoreProvider } from "@sema-agent/core";
5
+ import { resolveMemoryConsolidationDriver, type ConsolidationWriteJudge, type ConsolidationWriteJudgeInput, type EngineNotice, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type MemoryGovernanceDurability, type PermissionRuleStoreProvider, type CompliancePosture, type RunMemoryConsolidationOptions } from "@sema-agent/core";
6
+ /** 合规档位座的型 = 驱动动词 `compliance.postureOf` 收的那一只(core 的座型不在包根导出面上;取动词选项的成员型,形的属主仍是 core)。 */
7
+ type CompliancePostureSeat = NonNullable<NonNullable<RunMemoryConsolidationOptions["compliance"]>["postureOf"]>;
6
8
  /**
7
9
  * 座解析的 options 形 = core 解析器交回的那只(core 7.50.0 起它**不含** `writeJudge`:判官不是模型席的一部分,由调用方在动词上带)。
8
10
  * 取解析器的返回型而不是自己写 `Omit<…>`:形的属主是 core 的解析器,本仓不持第二份。
@@ -141,11 +143,12 @@ export declare function createPerScopeSingleFlight<T>(): (scope: string, run: ()
141
143
  *
142
144
  * ① **记忆引擎没接线**(`MEMORY_ENGINE=off`,或多租户形——本仓的记忆引擎只在单用户部署上装配):
143
145
  * 没有引擎就没有库可折叠,阀门是一句空话;
144
- * ② **后端不自带控制面归属**(`controlPlaneRoot`):driver 的 run 账(`distiller-runs.json`)、mint 归档
145
- * 与引擎的 consolidation gate 全住在控制面上。缺它时 core 会把控制面**回落到本进程的本地盘**
146
- * (`deriveControlPlaneDir`),而本仓是 stateless replicas ⇒ 一轮分钟级 run 的续跑账会落在某个随机
147
- * pod 的盘上,pod 重建即失,而 run 是**可续跑**设计的(重跑=整库重新 mint,真金白银)。判据与
148
- * `createMemoryComplianceFaces` 逐字同源(读的是后端的**面**,不看后端方言名);
146
+ * ② **整理状态不随后端走**(引擎对这只后端的答案 `memoryGovernanceDurability` = `"replica-local"`):driver 的 run 账
147
+ * (`distiller-runs.json`)、mint 归档与引擎的 consolidation gate 住在引擎的控制面上;后端不发布控制面时 core 会把它
148
+ * **回落到本进程的本地盘**(`deriveControlPlaneDir`),而本仓是 stateless replicas ⇒ 一轮分钟级 run 的续跑账会落在某个随机
149
+ * pod 的盘上,pod 重建即失,而 run 是**可续跑**设计的(重跑=整库重新 mint,真金白银)。判据**只问引擎的这一个答案**
150
+ * (「整理能不能开」就是它回答的那一问;不自读后端的面、不看后端方言名);部署面(合规 / 外源 / 状态 / 部署对象)问的是
151
+ * 另一件事 —— 后端发不发布控制面 —— 读 `backendOwnsControlPlane`,不读这里;
149
152
  * ③ **`MEMORY_PROVENANCE=off`**:core 的 `screenConsolidationOptions` 明写 consolidation 不能在
150
153
  * `provenance:"off"` 下开(fold law 必须铸得出 origin 标记,否则一个被标记过的输入折出来的产物会
151
154
  * **不带标记**地提交)。这一条本来就会在引擎构造期抛,提前判只为一件事:把**两根**旋钮的名字同时
@@ -164,15 +167,20 @@ export declare function assertConsolidationDriverWirable(input: ConsolidationWir
164
167
  export interface ConsolidationWiringFacts {
165
168
  /** 本部署接了记忆引擎吗(`boot/stores.ts` 的 `memoryEngine !== undefined`)。 */
166
169
  readonly memoryEngineWired: boolean;
167
- /** 记忆后端自带控制面归属吗(`typeof backend.controlPlaneRoot === "string"` 且非空)。 */
168
- readonly controlPlaneOwned: boolean;
170
+ /** 整理读写的状态随不随后端走:引擎对这只后端的答案(`memoryGovernanceDurability`,`"backend"` / `"replica-local"`)。
171
+ * 引擎契约逐字「a host that arms or reports consolidation asks here, never of a backend member it probes itself」——
172
+ * 阀门就是「整理能不能开」这一问,所以只问引擎、不自己读后端的面;部署面(合规 / 外源 / 状态 / 部署对象)问的是另一件事
173
+ * (后端发不发布控制面,`backendOwnsControlPlane`),不问这里。记忆引擎没接 ⇒ `"replica-local"`(判官先答 `no-memory-engine`)。 */
174
+ readonly governanceDurability: MemoryGovernanceDurability;
169
175
  /** 只进文案 —— 让「该去拧哪根旋钮」这句话指向该腿上**真的**有效的那一根。 */
170
176
  readonly memoryEngineBackend: ServiceConfig["memoryEngineBackend"];
171
177
  /** 部署声明的 provenance 姿态(`config.memoryProvenance`;缺席 ≡ core 缺省 `carry`)。 */
172
178
  readonly provenance?: "off" | "carry";
179
+ /** 部署的合规档位(`config.compliancePosture`;缺席 = 无档位)。否决集只经引擎的 `resolveComplianceDenies` 求(与装配三座席同一只)。 */
180
+ readonly compliancePosture?: CompliancePosture;
173
181
  }
174
- /** 「阀门若开,这台部署结构上跑不起来」的三种成因(闭集;加一种 = 下面两只穷举 switch 编译红)。 */
175
- export type ConsolidationUnwirable = "no-memory-engine" | "no-control-plane" | "provenance-off";
182
+ /** 「阀门若开,这台部署结构上跑不起来」的四种成因(闭集;加一种 = 下面两只穷举 switch 编译红)。`"replica-local"` 是引擎 `MemoryGovernanceDurability` 的那个词,逐字。 */
183
+ export type ConsolidationUnwirable = "no-memory-engine" | "replica-local" | "provenance-off" | "compliance-denied";
176
184
  /**
177
185
  * 「阀门若开,这台部署结构上跑不跑得起来」的**判官**(三臂逐条理由见 {@link assertConsolidationDriverWirable} 头注)。
178
186
  * 返回成因词;`undefined` = 跑得起来。两处读它:显式 on 的拒启(句子 = {@link unwirableRefusal}),以及出厂缺省派生
@@ -209,8 +217,8 @@ export declare function consolidationSeatBillingOf(plane: ConsolidationSeatPlane
209
217
  * (结构上跑不起来由下游 D1 三条拒启臂照拒,本判决不吞);开而座落主模型 ⇒ 开 + 一行
210
218
  * `memory_consolidation_on_main_model`(部署方显式承担,但必须知道账按主模型记)。
211
219
  * · **未设 = 出厂缺省派生**([ref] 取代 [ref] ① 的「出厂 off」实况):
212
- * 结构上跑不起来(判官 {@link consolidationDriverUnwirable} 有成因:多租户 / `MEMORY_ENGINE=off` / pg·mysql
213
- * 记忆后端 / `MEMORY_PROVENANCE=off`)⇒ **恒关、零提示、零探针** —— 派生开撞上 D1 拒启臂 = 每台配了便宜模型的
220
+ * 结构上跑不起来(判官 {@link consolidationDriverUnwirable} 有成因 —— 成因表只有 {@link ConsolidationUnwirable} 这一份;
221
+ * 配置目录说明与 USAGE 各列的同一串各有一条钉对着它)⇒ **恒关、零提示、零探针** —— 派生开撞上 D1 拒启臂 = 每台配了便宜模型的
214
222
  * 多租户 worker 升级即起不来;而配不配便宜模型它都开不了,一句指向 `MODEL_CHEAP_ID` 的提示是误导;
215
223
  * 座不落主模型({@link consolidationSeatBillingOf} = `own-model`)⇒ **开**;
216
224
  * 否则(落主模型 / 解不出)⇒ **关** + 一行 `memory_consolidation_default_off_no_cheap_model`(点名 `MODEL_CHEAP_ID`,
@@ -271,10 +279,10 @@ export declare function createConsolidationValve(input: ConsolidationValveInput
271
279
  };
272
280
  /** 阀门判决的两件输入(装配点与纯判共用一只形 —— 两个入口递的是同一组事实)。 */
273
281
  export interface ConsolidationValveInput {
274
- readonly config: Pick<ServiceConfig, "memoryConsolidationDriver" | "memoryEngineBackend" | "memoryProvenance" | "models" | "tiers" | "roles">;
275
- /** 只读两件:在不在(记忆引擎接没接线)、后端有没有控制面归属(`backendOwnsControlPlane` 只问那一个面)。 */
282
+ readonly config: Pick<ServiceConfig, "memoryConsolidationDriver" | "memoryEngineBackend" | "memoryProvenance" | "compliancePosture" | "models" | "tiers" | "roles">;
283
+ /** 只读两件:在不在(记忆引擎接没接线)、整理状态随不随后端走(引擎的 `memoryGovernanceDurability` 答)。 */
276
284
  readonly memoryEngine: {
277
- readonly backend: unknown;
285
+ readonly backend: MemoryBackend;
278
286
  } | undefined;
279
287
  }
280
288
  /**
@@ -459,8 +467,8 @@ export interface MemoryConsolidationFaces {
459
467
  /** 跑(或**续跑**)一轮。core 的 run 行是持久的:同一 scope 上有 pending run 时本调用 CONTINUE 它
460
468
  * (同一 plan 缓存、同一 force requestId、零新 mint)—— 所以这一口对**重试安全**。 */
461
469
  run(scope: string): Promise<ConsolidationRunReceipt>;
462
- /** 该 scope 最近一次 driver run 的账(`undefined` = 从没跑过 —— 诚实缺席,不编一个空壳)。 */
463
- lastRun(scope: string): ConsolidationDriverRunRow | undefined;
470
+ /** 该 scope 最近一次 driver run 的账(`undefined` = 从没跑过 —— 诚实缺席,不编一个空壳)。core 7.63.0([ref])起经引擎的治理店座读、异步。 */
471
+ lastRun(scope: string): Promise<ConsolidationDriverRunRow | undefined>;
464
472
  }
465
473
  /**
466
474
  * 在**记忆作用域店**上建 consolidation 操作面。命名照 CLAUDE.md 工厂律:返回带行为的活对象 ⇒ `create*`。
@@ -506,6 +514,10 @@ export declare function createMemoryConsolidationFaces(stores: MemoryScopeStores
506
514
  * 应用时拒 = 引擎在驱动里铸的 `memory.consolidation_incomplete`;早问拒 = 驱动抛出的拒绝经引擎导出的投递口(`deliverWriteRefusal`)转成的
507
515
  * `memory.consolidation_refused`(本仓不读通告名、不自铸通告形)。 */
508
516
  onNotice?: (notice: EngineNotice) => void;
517
+ /** core 7.63.0([ref]):部署的合规档位座(装配层给 `RunnerDeps.compliancePostureResolver` 那**同一只**;`undefined` = 部署没有档位)。
518
+ * 必填键 —— 缺席不能被读成「没有档位」:驱动动词每一轮先拿它问**层属主**的档位(契约 = {@link memoryScopeContractOf}`([scope])`,
519
+ * 与会话铸 spec 同一只),否决 ⇒ 在写判官、任何读、任何模型调用之前拒 `config.compliance_denied`;自动整理腿读同一只座。 */
520
+ postureOf: CompliancePostureSeat | undefined;
509
521
  }): MemoryConsolidationFaces;
510
522
  export {};
511
523
  //# sourceMappingURL=memory-consolidation.d.ts.map
@@ -1,12 +1,12 @@
1
1
  import { redactSecrets } from "../trace/redact.js";
2
2
  import { recordFailOpen } from "../observability/fail-open.js";
3
3
  import { buildOperatorRosterWayOut } from "../http/principal-gate.js";
4
- import { memoryMountRootOf } from "../memory-scope.js";
4
+ import { memoryMountRootOf, memoryScopeContractOf } from "../memory-scope.js";
5
5
  import { executionLaneHomeDir } from "../execution-lane-caps.js";
6
6
  import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
7
7
  import { captureRecordStoreOf } from "../memory-operator-faces.js";
8
- import { backendOwnsControlPlane, memoryStoreForRequest } from "../memory-scope-stores.js";
9
- import { createConsolidationWriteJudge, deliverWriteRefusal, expandTiers, MemoryEngine, modelOriginOf, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
8
+ import { memoryStoreForRequest } from "../memory-scope-stores.js";
9
+ import { createConsolidationWriteJudge, deliverWriteRefusal, expandTiers, MemoryEngine, memoryGovernanceDurability, modelOriginOf, resolveComplianceDenies, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
10
10
  import { seatText } from "../trace/exit-seat.js";
11
11
  export function resolveConsolidationDriverSeat(deps) {
12
12
  let options;
@@ -97,10 +97,12 @@ export function assertConsolidationDriverWirable(input) {
97
97
  export function consolidationDriverUnwirable(input) {
98
98
  if (!input.memoryEngineWired)
99
99
  return "no-memory-engine";
100
- if (!input.controlPlaneOwned)
101
- return "no-control-plane";
100
+ if (input.governanceDurability !== "backend")
101
+ return input.governanceDurability;
102
102
  if (input.provenance === "off")
103
103
  return "provenance-off";
104
+ if (input.compliancePosture !== undefined && resolveComplianceDenies(input.compliancePosture).has("memory_consolidation"))
105
+ return "compliance-denied";
104
106
  return undefined;
105
107
  }
106
108
  function unwirableRefusal(code, facts) {
@@ -110,18 +112,23 @@ function unwirableRefusal(code, facts) {
110
112
  `— there is no library to fold, and the two admin endpoints would answer over an engine that does not exist. ` +
111
113
  `(The engine is wired only on single-user deployments with MEMORY_ENGINE on; a multi-tenant worker keeps memory ` +
112
114
  `dark by design.) Wire the memory engine, or set MEMORY_CONSOLIDATION_DRIVER=off.`);
113
- case "no-control-plane":
114
- return (`MEMORY_CONSOLIDATION_DRIVER=on arms the memory-consolidation valve, but the wired memory backend ` +
115
- `(MEMORY_ENGINE_BACKEND=${facts.memoryEngineBackend}) does NOT own an engine control plane (controlPlaneRoot) — ` +
116
- `core would derive one on THIS replica's local disk, and a consolidation run's resumable account would die with ` +
117
- `the pod (a lost run re-mints the whole library at full model cost on the next attempt). The file memory backend ` +
118
- `owns a control plane; the pg/mysql memory backends do not. Set MEMORY_ENGINE_BACKEND=file, or set ` +
115
+ case "replica-local":
116
+ return (`MEMORY_CONSOLIDATION_DRIVER=on arms the memory-consolidation valve, but the memory engine answers "replica-local" for the ` +
117
+ `wired memory backend (MEMORY_ENGINE_BACKEND=${facts.memoryEngineBackend}) — a consolidation run's state would live on THIS ` +
118
+ `replica's local disk instead of riding the backend, and its resumable account would die with the pod (a lost run ` +
119
+ `re-mints the whole library at full model cost on the next attempt). The file memory backend keeps that state with the ` +
120
+ `backend (the engine answers "backend"); the pg/mysql memory backends do not. Set MEMORY_ENGINE_BACKEND=file, or set ` +
119
121
  `MEMORY_CONSOLIDATION_DRIVER=off.`);
120
122
  case "provenance-off":
121
123
  return (`MEMORY_CONSOLIDATION_DRIVER=on is incompatible with MEMORY_PROVENANCE=off — core refuses to enable consolidation ` +
122
124
  `under provenance "off" because the fold law must be able to MINT origin markers (a marked input's product would ` +
123
125
  `otherwise commit unmarked, i.e. the fold would launder provenance). Set MEMORY_PROVENANCE=carry (or unset it, ` +
124
126
  `which is the same posture), or set MEMORY_CONSOLIDATION_DRIVER=off.`);
127
+ case "compliance-denied":
128
+ return (`MEMORY_CONSOLIDATION_DRIVER=on arms the memory-consolidation valve, but this deployment's compliance posture ` +
129
+ `(COMPLIANCE_PROFILE=${facts.compliancePosture?.profile ?? "?"}, with COMPLIANCE_ADDITIONAL_DENIES) denies memory_consolidation — the engine ` +
130
+ `refuses every consolidation run before it reads, claims or calls a model (config.compliance_denied), on the admin endpoint and after ` +
131
+ `a settle alike. Set MEMORY_CONSOLIDATION_DRIVER=off, or run a posture that does not deny memory_consolidation.`);
125
132
  default: {
126
133
  const unreachable = code;
127
134
  throw new Error(`unhandled consolidation unwirable code: ${String(unreachable)}`);
@@ -132,10 +139,12 @@ function unwirableClause(code, facts) {
132
139
  switch (code) {
133
140
  case "no-memory-engine":
134
141
  return "no memory engine is wired here (multi-tenant posture, or MEMORY_ENGINE=off), so there is no library to fold";
135
- case "no-control-plane":
136
- return `the memory backend (MEMORY_ENGINE_BACKEND=${facts.memoryEngineBackend}) owns no engine control plane, so a consolidation run could not keep its account`;
142
+ case "replica-local":
143
+ return `the memory engine answers "replica-local" for the memory backend (MEMORY_ENGINE_BACKEND=${facts.memoryEngineBackend}), so a consolidation run's state would not outlive its replica and could not keep its account`;
137
144
  case "provenance-off":
138
145
  return "MEMORY_PROVENANCE=off, and consolidation needs provenance to mint origin markers";
146
+ case "compliance-denied":
147
+ return "the deployment's compliance posture (COMPLIANCE_PROFILE / COMPLIANCE_ADDITIONAL_DENIES) denies memory_consolidation, so the engine refuses every run";
139
148
  default: {
140
149
  const unreachable = code;
141
150
  throw new Error(`unhandled consolidation unwirable code: ${String(unreachable)}`);
@@ -194,9 +203,10 @@ export function judgeConsolidationValve(input) {
194
203
  const { config, memoryEngine } = input;
195
204
  const wiring = {
196
205
  memoryEngineWired: memoryEngine !== undefined,
197
- controlPlaneOwned: backendOwnsControlPlane(memoryEngine?.backend),
206
+ governanceDurability: memoryEngine !== undefined ? memoryGovernanceDurability(memoryEngine.backend) : "replica-local",
198
207
  memoryEngineBackend: config.memoryEngineBackend,
199
208
  ...(config.memoryProvenance !== undefined ? { provenance: config.memoryProvenance } : {}),
209
+ ...(config.compliancePosture !== undefined ? { compliancePosture: config.compliancePosture } : {}),
200
210
  };
201
211
  const code = consolidationDriverUnwirable(wiring);
202
212
  const unwirable = code !== undefined ? { code, facts: wiring } : undefined;
@@ -363,6 +373,7 @@ export function createMemoryConsolidationFaces(stores, input) {
363
373
  const receipt = await runMemoryConsolidationDriver(engineOf(scope), scope, {
364
374
  ...input.seat.options,
365
375
  writeJudge: input.writeJudge,
376
+ compliance: { ...(input.postureOf !== undefined ? { postureOf: input.postureOf } : {}), scopeContract: memoryScopeContractOf([scope]) },
366
377
  ...(input.onNotice !== undefined ? { onNotice: input.onNotice } : {}),
367
378
  }).catch((err) => {
368
379
  deliverWriteRefusal(err, scope, input.onNotice);
@@ -373,7 +384,7 @@ export function createMemoryConsolidationFaces(stores, input) {
373
384
  }
374
385
  return receipt;
375
386
  }),
376
- lastRun: (scope) => readConsolidationDriverRun(engineOf(scope).controlPlaneRoot, scope),
387
+ lastRun: (scope) => engineOf(scope).readConsolidationDriverRun(scope),
377
388
  };
378
389
  }
379
390
  //# sourceMappingURL=memory-consolidation.js.map
@@ -22,7 +22,8 @@ import type { Metrics } from "../observability/metrics.js";
22
22
  import type { WorkflowNotifyGate, WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
23
23
  import type { TaskAttachmentStore } from "../plugins/task-attachment-store.js";
24
24
  import type { FileHistoryErasureFace } from "../file-history-capture.js";
25
- import type { ApprovalNonceStore, CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, ServiceWorkflowJournalStore, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
25
+ import type { ApprovalNonceStore, CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, StoreBackend } from "../plugins/store-backend.js";
26
+ import { type StoreSweep, type StoreSweepLeg } from "../plugins/store-sweep.js";
26
27
  import type { ToolApprovalCoordinator } from "../tool-approval.js";
27
28
  import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
28
29
  import { type SandboxPodReaper } from "../plugins/k8s-pod-reaper.js";
@@ -56,6 +57,14 @@ export interface ThrottledReaperCatch {
56
57
  * survives across ticks — a fresh instance per tick would never accumulate past 1.
57
58
  */
58
59
  export declare function createThrottledReaperCatch(name: string, logger: Logger, threshold?: number): ThrottledReaperCatch;
60
+ /**
61
+ * 维护 tick 里调后端按龄清扫动词的那一拍。逐腿上报:失败腿的原因只进那条腿的节流告警;成功腿先计数、再清连败(计数抛也记那条腿的失败)。
62
+ * 动词整只拒(不是 {@link StoreSweepError} 的逐腿形)⇒ 每条腿各记一次失败。永不拒(本拍的失败全由节流告警接住)。
63
+ */
64
+ export declare function runStoreSweepLeg(sweep: StoreSweep, nowMs: number, report: {
65
+ readonly guards: Readonly<Record<StoreSweepLeg, ThrottledReaperCatch>>;
66
+ readonly counted: (leg: StoreSweepLeg, removed: number) => void;
67
+ }): Promise<void>;
59
68
  /** [ref] —— 维护 tick 真正消费的那**一手**(窄口;理由见 `ReapersCtx.permissionRuleStores`)。
60
69
  * 可选成员:File 车道没有这一面(追加日志的压实是另一件事,如实登记在 `rules-consent.ts` 的
61
70
  * `PermissionRuleStoreBundle.reapExpired` 注里),缺席 ⇒ 本腿零调用。 */
@@ -75,7 +84,8 @@ export interface ReapersCtx {
75
84
  parkCommits: ParkCommitWatch | undefined;
76
85
  rateLimiter: RateLimiter | RateLimiterStore | undefined;
77
86
  costQuota: CostQuota | CostQuotaStore | undefined;
78
- toolResultStore: ToolResultStoreFull | undefined;
87
+ /** 本后端的按龄清扫动词(`plugins/store-sweep.ts`;腿 = 工具结果 / 名册,组合点 `boot/stores.ts`,界每次清扫现读)。tick 只调它,不逐店探按龄删的方法。 */
88
+ storeSweep: StoreSweep;
79
89
  /** [ref]:文件历史的**擦除脸**(后端在即在,与 `FILE_HISTORY_CAPTURE` 无关)—— 本段只用它的孤儿 blob GC。 */
80
90
  fileHistoryErasure: FileHistoryErasureFace | undefined;
81
91
  taskAttachmentStore: TaskAttachmentStore | undefined;
@@ -84,10 +94,8 @@ export interface ReapersCtx {
84
94
  workflowNotifyGate: WorkflowNotifyGate | undefined;
85
95
  /** [ref]/[ref] recover 的两半 opts(boot 与周期扫描共用,单点合成在 workflow-orchestration)。 */
86
96
  workflowRecoverOpts: Parameters<WorkflowNotifyGate["recover"]>[0];
87
- workflowJournalStore: ServiceWorkflowJournalStore | undefined;
88
97
  sqlWorkflowRunStore: WorkflowRunStore | undefined;
89
98
  workflowNotifyJournal: WorkflowNotifyJournalStore | undefined;
90
- rosterStore: RunnerDeps["rosterStore"];
91
99
  backgroundAgentStore: RunnerDeps["backgroundAgentStore"];
92
100
  mailboxStore: RunnerDeps["mailboxStore"];
93
101
  /** [ref] 车6:流内审批撤卡帧的投递口(收敛器/孤儿代打腿产出的帧经它反查 broker 的活连接;[ref] 起
@@ -1,6 +1,7 @@
1
1
  import { Runner, defaultTaskRegistry } from "@sema-agent/core";
2
2
  import { sweepStaleScratchpads } from "../env-facts.js";
3
3
  import { CostQuota } from "../observability/cost-quota.js";
4
+ import { STORE_SWEEP_LEGS, StoreSweepError } from "../plugins/store-sweep.js";
4
5
  import { isAdoptionQuiescing, trackMaintenanceLeg } from "../adoption/quiesce.js";
5
6
  import { createApprovalReconciler } from "../approval-reconciler.js";
6
7
  import { createE2bOrphanSandboxProvider, reclaimOrphanE2bSandboxes, E2B_ORPHAN_GRACE_MS } from "../plugins/e2b-orphan-reclaim.js";
@@ -33,6 +34,32 @@ export function createThrottledReaperCatch(name, logger, threshold = REAPER_FAIL
33
34
  },
34
35
  };
35
36
  }
37
+ export function runStoreSweepLeg(sweep, nowMs, report) {
38
+ const settle = (receipt, failed) => {
39
+ for (const leg of STORE_SWEEP_LEGS) {
40
+ if (failed.has(leg)) {
41
+ report.guards[leg].onError(failed.get(leg));
42
+ continue;
43
+ }
44
+ try {
45
+ report.counted(leg, receipt[leg]);
46
+ report.guards[leg].onSuccess();
47
+ }
48
+ catch (err) {
49
+ report.guards[leg].onError(err);
50
+ }
51
+ }
52
+ };
53
+ return Promise.resolve()
54
+ .then(() => sweep.sweep({ nowMs }))
55
+ .then((receipt) => settle(receipt, new Map()), (err) => {
56
+ if (err instanceof StoreSweepError)
57
+ settle(err.receipt, err.failed);
58
+ else
59
+ for (const leg of STORE_SWEEP_LEGS)
60
+ report.guards[leg].onError(err);
61
+ });
62
+ }
36
63
  export function createPlacementAwareReapSessions(deps) {
37
64
  const { host, routed } = deps;
38
65
  const listPlaced = typeof host?.listPlaced === "function" ? host.listPlaced.bind(host) : undefined;
@@ -59,7 +86,7 @@ export function createPlacementAwareReapSessions(deps) {
59
86
  };
60
87
  }
61
88
  export function startReapers(ctx) {
62
- const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, toolResultStore, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, approvalAskAudit, sandboxPodReaper, } = ctx;
89
+ const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, storeSweep, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, sqlWorkflowRunStore, workflowNotifyJournal, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, approvalAskAudit, sandboxPodReaper, } = ctx;
63
90
  const leg = (p) => {
64
91
  if (p !== undefined)
65
92
  trackMaintenanceLeg(p);
@@ -91,7 +118,16 @@ export function startReapers(ctx) {
91
118
  const runDenySweepGuard = createThrottledReaperCatch("run_deny_sweep", logger);
92
119
  const runsReapSuspendedGuard = createThrottledReaperCatch("runs_reap_suspended", logger);
93
120
  const checkpointReapCtxGuard = createThrottledReaperCatch("checkpoint_reap_ctx", logger);
94
- const toolResultReapGuard = createThrottledReaperCatch("tool_result_reap", logger);
121
+ const storeSweepGuards = {
122
+ "roster-aged": createThrottledReaperCatch("roster_reap_older_than", logger),
123
+ "tool-results-aged": createThrottledReaperCatch("tool_result_reap", logger),
124
+ "workflow-journal-expired": createThrottledReaperCatch("workflow_journal_reap_expired", logger),
125
+ };
126
+ const storeSweepCount = {
127
+ "roster-aged": reapCount("roster_rows_reaped_total", {}),
128
+ "tool-results-aged": undefined,
129
+ "workflow-journal-expired": undefined,
130
+ };
95
131
  const fileHistorySweepOrphanBlobsGuard = createThrottledReaperCatch("file_history_sweep_orphan_blobs", logger);
96
132
  const legacySnapshotBlobSweepGuard = createThrottledReaperCatch("legacy_snapshot_blob_sweep", logger);
97
133
  const attachmentReapUnboundGuard = createThrottledReaperCatch("attachment_reap_unbound", logger);
@@ -99,11 +135,9 @@ export function startReapers(ctx) {
99
135
  const imageBakesReapStaleGuard = createThrottledReaperCatch("image_bakes_reap_stale", logger);
100
136
  const worktreeReapGuard = createThrottledReaperCatch("worktree_reap", logger);
101
137
  const workflowNotifyRecoverGuard = createThrottledReaperCatch("workflow_notify_recover", logger);
102
- const workflowJournalReapExpiredGuard = createThrottledReaperCatch("workflow_journal_reap_expired", logger);
103
138
  const workflowRunReapAllScopesGuard = createThrottledReaperCatch("workflow_run_reap_all_scopes", logger);
104
139
  const workflowNotifyJournalReapAckedGuard = createThrottledReaperCatch("workflow_notify_journal_reap_acked", logger);
105
140
  const bgAgentsReapGuard = createThrottledReaperCatch("bg_agents_reap", logger);
106
- const rosterReapOlderThanGuard = createThrottledReaperCatch("roster_reap_older_than", logger);
107
141
  const leaderRunStaleGuard = createThrottledReaperCatch("leader_run_reap_stale", logger);
108
142
  const leaderRunStore = config.leaderEnabled ? backend?.leaderRun?.() : undefined;
109
143
  const scratchpadSweepStaleGuard = createThrottledReaperCatch("scratchpad_sweep_stale", logger);
@@ -244,10 +278,7 @@ export function startReapers(ctx) {
244
278
  rateLimiter?.sweep();
245
279
  if (costQuota instanceof CostQuota)
246
280
  costQuota.reap();
247
- const reapToolResults = toolResultStore?.reap?.bind(toolResultStore);
248
- leg(reapToolResults && Promise.resolve()
249
- .then(() => reapToolResults(Date.now(), { maxAgeMs: config.toolResultTtlSec * 1000 }))
250
- .then(() => toolResultReapGuard.onSuccess(), toolResultReapGuard.onError));
281
+ leg(runStoreSweepLeg(storeSweep, Date.now(), { guards: storeSweepGuards, counted: (l, n) => storeSweepCount[l]?.(n) }));
251
282
  leg(fileHistoryErasure
252
283
  ?.sweepOrphanBlobs?.()
253
284
  .then(() => fileHistorySweepOrphanBlobsGuard.onSuccess(), fileHistorySweepOrphanBlobsGuard.onError));
@@ -290,9 +321,6 @@ export function startReapers(ctx) {
290
321
  leg(workflowNotifyGate
291
322
  ?.recover(workflowRecoverOpts)
292
323
  .then(() => workflowNotifyRecoverGuard.onSuccess(), workflowNotifyRecoverGuard.onError));
293
- leg(workflowJournalStore
294
- ?.reapExpired?.(Date.now(), config.workflowJournalRetentionMs)
295
- .then(() => workflowJournalReapExpiredGuard.onSuccess(), workflowJournalReapExpiredGuard.onError));
296
324
  if (!wfRunReapInFlight) {
297
325
  const sweep = sqlWorkflowRunStore?.reapAllScopes?.(Date.now(), { maxAgeMs: config.workflowRunRetentionMs });
298
326
  if (sweep) {
@@ -311,10 +339,6 @@ export function startReapers(ctx) {
311
339
  .then(() => bgAgentsReapGuard.onSuccess(), bgAgentsReapGuard.onError)
312
340
  .finally(() => (bgAgentReapInFlight = false)));
313
341
  }
314
- leg(rosterStore
315
- ?.reapOlderThan?.(Date.now() - config.rosterRetentionMs)
316
- .then(reapCount("roster_rows_reaped_total", {}))
317
- .then(() => rosterReapOlderThanGuard.onSuccess(), rosterReapOlderThanGuard.onError));
318
342
  leg(leaderRunStore
319
343
  ?.reapStaleRunning(config.leaderRunStaleMs, Date.now())
320
344
  .then(reapCount("leader_runs_stale_reaped_total", {}))
@@ -41,6 +41,8 @@ export interface ResolveSpecCtx {
41
41
  fenceSessionOwner: (sid: string, owner: string | null) => void;
42
42
  hookLlm: ReturnType<typeof createHookLlm>["hookLlm"];
43
43
  hookAgent: HookLlmCall;
44
+ /** 部署座在任务座之下挂了链成员的站点式样(第 5 段装配口从引擎准入记录读出,`boot/deployment-mods.ts` 的 `belowTaskChainPatternsOf`)—— 原样交 hooks 注册上下文(托管车道在这些站上只许收紧)。 */
45
+ belowTaskChainPatterns: readonly string[];
44
46
  fleetBus: FleetEventBus;
45
47
  hookWakeBus: {
46
48
  deliver?: (sessionId: string, text: string) => Promise<boolean>;