@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
@@ -14,7 +14,9 @@ export function createPeerDirectory(ctx) {
14
14
  listPeerSessions: async (access) => {
15
15
  const scope = access.scope;
16
16
  const includeUnowned = legacyUnownedAmnestyOpen({ requirePrincipal }, scope);
17
- const rows = await lister({ owner: scope, ...(includeUnowned ? { includeUnowned: true } : {}), limit: PEER_DIRECTORY_CAP + 1 });
17
+ const answers = await lister({ owner: scope, ...(includeUnowned ? { includeUnowned: true } : {}), limit: PEER_DIRECTORY_CAP + 1 });
18
+ const rows = answers.map((a) => a.row);
19
+ const occupantOf = new Map(answers.map((a) => [a.row.sessionId, a.occupant.incarnation ?? null]));
18
20
  const truncated = rows.length > PEER_DIRECTORY_CAP;
19
21
  if (truncated) {
20
22
  logger.warn("peer_directory_truncated", {
@@ -88,6 +90,7 @@ export function createPeerDirectory(ctx) {
88
90
  where: "hosted",
89
91
  ...(tempo !== undefined ? { tempo } : {}),
90
92
  inboundPosture: posture,
93
+ occupant: occupantOf.get(r.sessionId) ?? null,
91
94
  });
92
95
  }
93
96
  if (ungrammatical > 0) {
@@ -129,6 +132,7 @@ export function createPeerDirectory(ctx) {
129
132
  where: "hosted",
130
133
  diedAt: t.retiredAt,
131
134
  inboundPosture: posture,
135
+ occupant: null,
132
136
  });
133
137
  }
134
138
  return out;
@@ -130,6 +130,11 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
130
130
  private journalV1Records;
131
131
  /** 盘上还有 v1 信封记录(随 M34):重放到 v1 记录时置位,任何一次压实(整本重写成 v2)清位 —— 已被压实过的账本不再为升级重写第二次。 */
132
132
  private journalV1OnDisk;
133
+ /**
134
+ * 盘上还有删行记录({@link ROW_REMOVAL_OPS}):写下一条 / 重放到一条时置位,任何一次压实(整本重写成快照)清位 —— 与 {@link journalV1OnDisk} 同形。
135
+ * 置位期间压实到期(顶注「压实」段的起因 ②):同一拍压实;压实失败 ⇒ 位留着,下一次写(或下一次起服)再试。
136
+ */
137
+ private removalRecordsOnDisk;
133
138
  /** 本次启动隔离出去的原件路径(无坏字节 ⇒ `undefined`)。 */
134
139
  readonly corruptQuarantinePath: string | undefined;
135
140
  /**
@@ -159,11 +164,16 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
159
164
  * 代价如实:不可编码的值(BigInt / 循环引用)在本形上**抛**,而 InMemory 形收得下 —— 那与 SQL 孪生
160
165
  * 同向(它也存不下),是**介质事实**,写进顶注的边界段。
161
166
  *
162
- * 🔴 **压实失败不许落到调用方头上**(替补对抗复审 F3 [medium],实测后修):走到 `maybeCompact()` 时这
167
+ * 🔴 **压实失败不许落到调用方头上**(替补对抗复审 F3 [medium],实测后修):走到 {@link compactOrRecord} 时这
163
168
  * 一次写**已经 fsync 落盘、也已经翻进内存**,把一次纯管家动作的 I/O 错误抛给调用方 = 把一次已生效的
164
169
  * 人类批准报成失败(客户端重试会拿到 `ask_not_pending`)。压实是 F 类兜底:失败留痕、下一次写再试。
170
+ * 两个起因同一条:删行记录引起的压实失败,位({@link removalRecordsOnDisk})留着,下一次**任何**写(与下一次起服)再试 ——
171
+ * 不是等下一次真删了行的调用。三只删行动词的内核体全是同步前缀,所以走到这里时被删的行已经不在内存里,快照里没有它们。
165
172
  */
166
173
  private write;
174
+ /** 压实到期就压实;失败 ⇒ 登记过的 F 类兜底(计数 + 留痕),不上抛 —— `write()` 尾段与起服各调一次,同一句话。 */
175
+ private compactOrRecord;
176
+ /** 压实是否到期(顶注「压实」段两个起因)。到期 ⇒ 压实;失败原样抛给 {@link compactOrRecord}。 */
167
177
  private maybeCompact;
168
178
  /** 整本重写成行快照 + 原子替换。失败 ⇒ 原账本原样留着、`records` 不动(下一次写再试),日志由
169
179
  * core 的 [ref] 惰性重开接住 —— 一次瞬时 I/O 错误绝不把这条日志变成砖。 */
@@ -193,8 +203,12 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
193
203
  abortBatch(batchId: string): Promise<string[]>;
194
204
  deferReconcile(askId: string, expectedState: AskState, expectedRev: number, nowMs: number): Promise<boolean>;
195
205
  resolveProvisional(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
206
+ /** 删一个 run 名下的全部问行与批行。与两只留存动词同律:内核的纯读选择为空 ⇒ 不落账本、不压实;否则「先落账、再翻内存」并同拍压实(顶注「压实」段起因 ②)。 */
196
207
  deleteByTask(taskId: string): Promise<void>;
197
- /** 留存律的问行半场(谓词在内核,见接口注)。空的一次(内核的纯读选择为空)不落账本、不碰内存;否则照常「先落账、再翻内存」。 */
208
+ /**
209
+ * 留存律的问行半场(谓词在内核,见接口注)。空的一次(内核的纯读选择为空)不落账本、不碰内存、不压实;否则照常「先落账、再翻内存」,
210
+ * 并在 `write()` 尾段同一拍压实(顶注「压实」段起因 ②)—— 选择非空 ⇒ 内核同步前缀里必删 ≥ 1 行,被删行的字节不留在盘上。
211
+ */
198
212
  reapSettledAsks(cutoffMs: number, limit: number, keepAnchors: ReadonlySet<string>): Promise<number>;
199
213
  /** 留存律的批行半场(同上)。 */
200
214
  reapEmptyBatches(cutoffMs: number, limit: number): Promise<number>;
@@ -28,6 +28,7 @@ const JOURNAL_OPS = [
28
28
  ];
29
29
  const JOURNAL_OP_WORDS = new Set(JOURNAL_OPS);
30
30
  export const JOURNAL_OP_TABLE_GATE = true;
31
+ const ROW_REMOVAL_OPS = new Set(["reapSettledAsks", "reapEmptyBatches", "deleteByTask"]);
31
32
  const JOURNAL_V1_CLAIM_INTENTS = ["expire", "cancel"];
32
33
  const JOURNAL_V1_CLAIM_INTENT_WORDS = new Set(JOURNAL_V1_CLAIM_INTENTS);
33
34
  const JOURNAL_ENVELOPE = 2;
@@ -94,6 +95,7 @@ export class FileApprovalAskStore {
94
95
  corruptLineCount = 0;
95
96
  journalV1Records = 0;
96
97
  journalV1OnDisk = false;
98
+ removalRecordsOnDisk = false;
97
99
  corruptQuarantinePath;
98
100
  constructor(root) {
99
101
  const dir = join(root, APPROVAL_ASK_DIR);
@@ -117,6 +119,9 @@ export class FileApprovalAskStore {
117
119
  `and rewrote the live journal from the replayed state. A dropped record is a LOST approval-ask transition: inspect the quarantined file.`);
118
120
  this.compact();
119
121
  }
122
+ else if (this.removalRecordsOnDisk) {
123
+ this.compactOrRecord();
124
+ }
120
125
  }
121
126
  clockRead() {
122
127
  const pinned = this.pinnedNow;
@@ -136,6 +141,8 @@ export class FileApprovalAskStore {
136
141
  const onDisk = { v: JOURNAL_ENVELOPE, k: "op", t, ...callToDisk(encoded) };
137
142
  this.logFor().append(onDisk, true);
138
143
  this.records += 1;
144
+ if (ROW_REMOVAL_OPS.has(call.op))
145
+ this.removalRecordsOnDisk = true;
139
146
  this.pinnedNow = t;
140
147
  let out;
141
148
  try {
@@ -144,15 +151,22 @@ export class FileApprovalAskStore {
144
151
  finally {
145
152
  this.pinnedNow = null;
146
153
  }
154
+ this.compactOrRecord();
155
+ return out;
156
+ }
157
+ compactOrRecord() {
147
158
  try {
148
159
  this.maybeCompact();
149
160
  }
150
161
  catch (e) {
151
162
  recordFailOpen("server.approval-ask-journal.compaction-failed", `path=${this.path} err=${e instanceof Error ? e.message : String(e)}`);
152
163
  }
153
- return out;
154
164
  }
155
165
  maybeCompact() {
166
+ if (this.removalRecordsOnDisk) {
167
+ this.compact();
168
+ return;
169
+ }
156
170
  if (this.records < ASK_JOURNAL_COMPACT_MIN_RECORDS)
157
171
  return;
158
172
  const snapshot = this.core.exportRows();
@@ -168,6 +182,7 @@ export class FileApprovalAskStore {
168
182
  this.log?.closeForSwap();
169
183
  atomicWriteFile(this.tmpDir, this.path, lines.join(""));
170
184
  this.journalV1OnDisk = false;
185
+ this.removalRecordsOnDisk = false;
171
186
  this.records = lines.length;
172
187
  }
173
188
  replayRecord(disk) {
@@ -203,6 +218,8 @@ export class FileApprovalAskStore {
203
218
  refuse("unknown record kind");
204
219
  if (typeof probe.op !== "string" || !JOURNAL_OP_WORDS.has(probe.op))
205
220
  refuse("verb outside this build's closed set (a DOWNGRADE: a newer server wrote it)");
221
+ if (typeof probe.op === "string" && ROW_REMOVAL_OPS.has(probe.op))
222
+ this.removalRecordsOnDisk = true;
206
223
  if (typeof probe.t !== "number" || !Number.isFinite(probe.t))
207
224
  refuse("call record without a clock reading");
208
225
  if (probe.op === "claimTerminal" && !JOURNAL_V1_CLAIM_INTENT_WORDS.has(String(raw.intent)))
@@ -301,6 +318,9 @@ export class FileApprovalAskStore {
301
318
  return this.write({ op: "resolveProvisional", askId, from, to, patch }, (c) => this.core.resolveProvisional(c.askId, c.from, c.to, c.patch));
302
319
  }
303
320
  async deleteByTask(taskId) {
321
+ const plan = this.core.planDeleteByTask(taskId);
322
+ if (plan.askIds.length === 0 && plan.batchIds.length === 0)
323
+ return;
304
324
  return this.write({ op: "deleteByTask", taskId }, (c) => this.core.deleteByTask(c.taskId));
305
325
  }
306
326
  async reapSettledAsks(cutoffMs, limit, keepAnchors) {
@@ -16,8 +16,9 @@
16
16
  * · {@link InMemoryApprovalAskStore.exportRows} / {@link InMemoryApprovalAskStore.importRows} —— 压实用的
17
17
  * 整本快照口(纯搬行,不经任何谓词)。压实要把「一串调用」折成「一串终局行」,没有这一对就只能在
18
18
  * File 形里另写一套「哪些行还算数」的判据 —— 那才是第二份手抄。
19
- * · {@link InMemoryApprovalAskStore.planReapSettledAsks} / {@link InMemoryApprovalAskStore.planReapEmptyBatches} —— 两只留存动词的
20
- * **纯读选择**(删哪些行)。File 形据它判「这一次有没有东西可删」,空的一次不落账本;删除本身仍是接口动词,与选择共用这一只。
19
+ * · {@link InMemoryApprovalAskStore.planReapSettledAsks} / {@link InMemoryApprovalAskStore.planReapEmptyBatches} /
20
+ * {@link InMemoryApprovalAskStore.planDeleteByTask} —— 三只删行动词的**纯读选择**(删哪些行)。File 形据它判「这一次有没有东西可删」,空的一次不落账本;
21
+ * 删除本身仍是接口动词,与选择共用这一只。
21
22
  * · {@link InMemoryApprovalAskStore.peekAsk} —— 一行的**同步**点读(纯读,零判定)。File 形在写口的同步前缀里据它判「这次决议在不在
22
23
  * 属主域内」(出域的一次不落账本)、重放时据它喂行自己的属主([ref],理由在 File 形的 `decideAsk`)。
23
24
  *
@@ -118,6 +119,11 @@ export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
118
119
  getByIdempotencyKey(taskId: string, key: string): Promise<AskRow | null>;
119
120
  resolveProvisional(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
120
121
  deleteByTask(taskId: string): Promise<void>;
122
+ /** {@link deleteByTask} 会删哪些行(纯读,零写;选择与删除共用这一只,没有第二份谓词)。 */
123
+ planDeleteByTask(taskId: string): {
124
+ readonly askIds: readonly string[];
125
+ readonly batchIds: readonly string[];
126
+ };
121
127
  getBatch(batchId: string): Promise<BatchRow | null>;
122
128
  /**
123
129
  * 留存律的问行半场(谓词见接口注,与 SQL twin 的 `DELETE … LIMIT` 同答)。方法体全同步(零 `await`)⇒ File 形把它当一次落账的调用
@@ -365,14 +365,17 @@ export class InMemoryApprovalAskStore {
365
365
  return true;
366
366
  }
367
367
  async deleteByTask(taskId) {
368
- for (const [id, r] of this.asks) {
369
- if (r.taskId === taskId)
370
- this.asks.delete(id);
371
- }
372
- for (const [id, b] of this.batches) {
373
- if (b.taskId === taskId)
374
- this.batches.delete(id);
375
- }
368
+ const plan = this.planDeleteByTask(taskId);
369
+ for (const id of plan.askIds)
370
+ this.asks.delete(id);
371
+ for (const id of plan.batchIds)
372
+ this.batches.delete(id);
373
+ }
374
+ planDeleteByTask(taskId) {
375
+ return {
376
+ askIds: [...this.asks.values()].filter((r) => r.taskId === taskId).map((r) => r.askId),
377
+ batchIds: [...this.batches.values()].filter((b) => b.taskId === taskId).map((b) => b.batchId),
378
+ };
376
379
  }
377
380
  async getBatch(batchId) {
378
381
  const b = this.batches.get(batchId);
@@ -68,7 +68,9 @@ export declare class CachingSessionStore implements SessionStore {
68
68
  limit: number;
69
69
  q?: string;
70
70
  }) => Promise<SessionListItem[]>;
71
- readonly fork?: (sourceId: string, owner: string | null) => Promise<string | null>;
71
+ /** 带住客的同一只列表面(原样转发;理由同 listSessions)。 */
72
+ readonly listSessionRows?: OwnerAwareSessionStore["listSessionRows"];
73
+ readonly fork?: OwnerAwareSessionStore["fork"];
72
74
  /** fork 续写的店契约(原样转发;与 fork 同理绕过暖缓存 —— 读写的是持久行,新 id 本来就不在缓存里)。 */
73
75
  readonly forkTo?: OwnerAwareSessionStore["forkTo"];
74
76
  /** 执行席(原样转发:放置是会话**行**上的一格,缓存只缓存会话日志的暖句柄,不缓存行格 —— 读与写都直达内层店)。 */
@@ -116,6 +118,9 @@ export declare class CachingSessionStore implements SessionStore {
116
118
  * 裸店、不经本包装,但 security.ts 的 OwnerAwareSessionStore 契约列了它 —— 经 sessionStorage 消费的
117
119
  * 未来调用方不该静默 no-op,与 beginImportStaging 同批补齐(同一类白名单缺口)。 */
118
120
  readonly sweepStagingSessions?: () => Promise<number>;
121
+ /** 带戳存档的早拒口(local 店独有;`OwnerAwareSessionStore.assertArchiveAnonymous`),读持久存档头、不经暖缓存。
122
+ * 🔴 必须转发(与 staging 族同一条教训):默认部署把真店包进本类,会话同步第一阶段的路由读到的是包装层 —— 不转发 = 这一口在默认部署上静默不发(第一阶段仍答通用冲突),没有任何一处报错。 */
123
+ readonly assertArchiveAnonymous?: (sessionId: string) => Promise<void>;
119
124
  /** 2c session-sync (§7/§8) — delegated IDEMPOTENT replace; like importEntries it writes durable state under
120
125
  * `sessionId`, so a stale warm handle for that id is evicted on success (next acquire re-wakes from the new log). */
121
126
  readonly replaceEntries?: (sessionId: string, owner: string | null, entries: SessionTreeEntry[]) => Promise<void>;
@@ -10,6 +10,7 @@ export class CachingSessionStore {
10
10
  headOf;
11
11
  register;
12
12
  listSessions;
13
+ listSessionRows;
13
14
  fork;
14
15
  forkTo;
15
16
  executionPlacement;
@@ -29,6 +30,7 @@ export class CachingSessionStore {
29
30
  importEntries;
30
31
  beginImportStaging;
31
32
  sweepStagingSessions;
33
+ assertArchiveAnonymous;
32
34
  replaceEntries;
33
35
  retention;
34
36
  placements;
@@ -57,6 +59,8 @@ export class CachingSessionStore {
57
59
  this.register = ownerAware.register.bind(inner);
58
60
  if (ownerAware.listSessions)
59
61
  this.listSessions = ownerAware.listSessions.bind(inner);
62
+ if (ownerAware.listSessionRows)
63
+ this.listSessionRows = ownerAware.listSessionRows.bind(inner);
60
64
  if (ownerAware.sessionSummaryOf)
61
65
  this.sessionSummaryOf = ownerAware.sessionSummaryOf.bind(inner);
62
66
  if (ownerAware.writeSessionRowCells)
@@ -85,6 +89,8 @@ export class CachingSessionStore {
85
89
  this.listEntryIds = ownerAware.listEntryIds.bind(inner);
86
90
  if (ownerAware.exportEntriesStream)
87
91
  this.exportEntriesStream = ownerAware.exportEntriesStream.bind(inner);
92
+ if (ownerAware.assertArchiveAnonymous)
93
+ this.assertArchiveAnonymous = ownerAware.assertArchiveAnonymous.bind(inner);
88
94
  this.forget = (sessionId) => {
89
95
  this.evict(sessionId);
90
96
  return inner.forget?.(sessionId);