@sema-agent/server 7.51.0 → 7.52.1

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 (203) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/USAGE.md +103 -24
  4. package/dist/adoption/plan.d.ts +4 -4
  5. package/dist/adoption/plan.js +11 -0
  6. package/dist/approval-card.d.ts +26 -2
  7. package/dist/approval-card.js +9 -0
  8. package/dist/approval-hmac.d.ts +1 -1
  9. package/dist/approval-reconciler.d.ts +2 -2
  10. package/dist/approval-reconciler.js +1 -1
  11. package/dist/bench/l8/artifact.d.ts +1 -1
  12. package/dist/bench/s1/arms.d.ts +1 -1
  13. package/dist/bench/s1/live-deps.d.ts +1 -1
  14. package/dist/bench/s1/oracle.d.ts +1 -1
  15. package/dist/bench/s1/row.d.ts +1 -1
  16. package/dist/boot/budget-tracing.d.ts +1 -1
  17. package/dist/boot/budget-tracing.js +2 -5
  18. package/dist/boot/coordinators.js +3 -1
  19. package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
  20. package/dist/boot/device-lane.js +2 -0
  21. package/dist/boot/engine-lease.d.ts +1 -1
  22. package/dist/boot/execution-env.d.ts +1 -1
  23. package/dist/boot/governance-seams.d.ts +2 -2
  24. package/dist/boot/leader.d.ts +1 -1
  25. package/dist/boot/memory-boundary.d.ts +2 -2
  26. package/dist/boot/memory-consolidation.d.ts +6 -6
  27. package/dist/boot/org-memory.d.ts +1 -1
  28. package/dist/boot/parked-revive-gate.d.ts +3 -3
  29. package/dist/boot/reapers.d.ts +2 -2
  30. package/dist/boot/reapers.js +17 -4
  31. package/dist/boot/resolve-spec.d.ts +12 -0
  32. package/dist/boot/resolve-spec.js +29 -7
  33. package/dist/boot/retention-lane.d.ts +2 -2
  34. package/dist/boot/runner-deps.d.ts +17 -7
  35. package/dist/boot/runner-deps.js +4 -2
  36. package/dist/boot/runtime-caps.d.ts +23 -0
  37. package/dist/boot/runtime-caps.js +24 -2
  38. package/dist/boot/session-faces.d.ts +1 -1
  39. package/dist/boot/session-faces.js +14 -3
  40. package/dist/boot/stores.js +31 -1
  41. package/dist/boot/task-list-lane.d.ts +2 -2
  42. package/dist/brain.js +51 -31
  43. package/dist/budget.d.ts +2 -2
  44. package/dist/capabilities/center-plugins.d.ts +1 -1
  45. package/dist/capabilities/collab-workflows.d.ts +1 -1
  46. package/dist/capabilities/hands-lane.d.ts +3 -3
  47. package/dist/capabilities/scenarios.d.ts +3 -3
  48. package/dist/capabilities/skills.d.ts +1 -1
  49. package/dist/config-center/hot-keys-registry.js +5 -0
  50. package/dist/config-center/http-client.d.ts +2 -2
  51. package/dist/config-center/read-face.d.ts +1 -1
  52. package/dist/config-center/restart-signal.d.ts +1 -1
  53. package/dist/config-types.d.ts +100 -25
  54. package/dist/config.d.ts +11 -3
  55. package/dist/config.js +91 -15
  56. package/dist/deployment-governance.d.ts +1 -1
  57. package/dist/device-enrollment.d.ts +2 -2
  58. package/dist/device-store.d.ts +3 -3
  59. package/dist/device-ws-hub.d.ts +4 -2
  60. package/dist/device-ws-hub.js +9 -3
  61. package/dist/device-ws-protocol.d.ts +2 -2
  62. package/dist/env-facts.d.ts +1 -1
  63. package/dist/execution-lane-caps.d.ts +1 -1
  64. package/dist/fleet/fleet-bus.d.ts +5 -2
  65. package/dist/fleet/fleet-reconciler.d.ts +1 -1
  66. package/dist/fleet/fleet-terminal-window.d.ts +1 -1
  67. package/dist/hooks/hook-runner.d.ts +8 -1
  68. package/dist/http/active-run-conflict.d.ts +2 -2
  69. package/dist/http/principal-gate.d.ts +1 -1
  70. package/dist/http/route-ctx.d.ts +27 -5
  71. package/dist/http/routes/admin-memory-optout.d.ts +48 -0
  72. package/dist/http/routes/admin-memory-optout.js +75 -0
  73. package/dist/http/routes/agents-roster.d.ts +1 -1
  74. package/dist/http/routes/approvals-assistant.js +21 -21
  75. package/dist/http/routes/capabilities.js +20 -9
  76. package/dist/http/routes/diagnostics.d.ts +1 -1
  77. package/dist/http/routes/leader.d.ts +1 -1
  78. package/dist/http/routes/memory-bundle.d.ts +1 -1
  79. package/dist/http/routes/memory-bundle.js +2 -1
  80. package/dist/http/routes/memory-compliance.d.ts +4 -4
  81. package/dist/http/routes/memory-origin.d.ts +4 -4
  82. package/dist/http/routes/memory-origin.js +3 -1
  83. package/dist/http/routes/memory-policy.js +6 -2
  84. package/dist/http/routes/retention-ops.d.ts +1 -1
  85. package/dist/http/routes/rules.d.ts +5 -2
  86. package/dist/http/routes/rules.js +84 -5
  87. package/dist/http/routes/run-memory-capture.d.ts +34 -0
  88. package/dist/http/routes/run-memory-capture.js +97 -0
  89. package/dist/http/routes/runs.d.ts +1 -0
  90. package/dist/http/routes/runs.js +212 -6
  91. package/dist/http/routes/session-sync.d.ts +4 -6
  92. package/dist/http/routes/session-sync.js +60 -47
  93. package/dist/http/routes/sessions.js +61 -188
  94. package/dist/http/routes/shared-memory.d.ts +1 -1
  95. package/dist/http/routes/tasks.js +1 -1
  96. package/dist/http/routes/workflows.js +19 -0
  97. package/dist/http/server.d.ts +35 -13
  98. package/dist/http/server.js +110 -14
  99. package/dist/http/verify-rounds.d.ts +1 -1
  100. package/dist/http/wire-types.d.ts +41 -8
  101. package/dist/leader/endpoint.d.ts +1 -1
  102. package/dist/leader/leader.d.ts +1 -1
  103. package/dist/leader/repair-oracle.d.ts +2 -2
  104. package/dist/leader/repair-oracle.js +1 -1
  105. package/dist/main.js +14 -6
  106. package/dist/memory-bundle-engine.d.ts +1 -1
  107. package/dist/memory-operator-faces.d.ts +5 -5
  108. package/dist/memory-origin-fence.d.ts +35 -0
  109. package/dist/memory-origin-fence.js +66 -0
  110. package/dist/memory-posture.d.ts +13 -1
  111. package/dist/memory-posture.js +1 -0
  112. package/dist/memory-scope.d.ts +6 -1
  113. package/dist/memory-scope.js +3 -2
  114. package/dist/model-select.d.ts +2 -2
  115. package/dist/observability/fail-open.d.ts +17 -5
  116. package/dist/observability/fail-open.js +17 -5
  117. package/dist/orchestration/hardened-vm-runner.d.ts +2 -2
  118. package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
  119. package/dist/plugins/background-shell-support.d.ts +2 -2
  120. package/dist/plugins/blob-backend.d.ts +7 -2
  121. package/dist/plugins/blob-backend.js +22 -18
  122. package/dist/plugins/caching-session-store.d.ts +7 -3
  123. package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
  124. package/dist/plugins/file-history-store-sql.d.ts +170 -0
  125. package/dist/plugins/file-history-store-sql.js +827 -0
  126. package/dist/plugins/file-run-store.d.ts +44 -5
  127. package/dist/plugins/file-run-store.js +85 -13
  128. package/dist/plugins/fork-routing-session-store.d.ts +1 -1
  129. package/dist/plugins/fork-routing-session-store.js +2 -2
  130. package/dist/plugins/leader-run-store-sql.d.ts +1 -1
  131. package/dist/plugins/local-session-store.d.ts +9 -1
  132. package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
  133. package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
  134. package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
  135. package/dist/plugins/memory-origin-law.d.ts +2 -2
  136. package/dist/plugins/memory-run-store.d.ts +4 -3
  137. package/dist/plugins/memory-run-store.js +2 -1
  138. package/dist/plugins/permission-rule-store-file.d.ts +16 -6
  139. package/dist/plugins/permission-rule-store-file.js +77 -13
  140. package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
  141. package/dist/plugins/permission-rule-store-sql.js +123 -21
  142. package/dist/plugins/pg-pool.js +59 -0
  143. package/dist/plugins/pg-safe-json.d.ts +1 -1
  144. package/dist/plugins/remote-env-device.d.ts +1 -1
  145. package/dist/plugins/remote-env-k8s.d.ts +1 -1
  146. package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
  147. package/dist/plugins/retention-store-sql.d.ts +7 -7
  148. package/dist/plugins/retention-store-sql.js +6 -0
  149. package/dist/plugins/run-store-sql.d.ts +9 -3
  150. package/dist/plugins/run-store-sql.js +2 -2
  151. package/dist/plugins/send-user-file.d.ts +1 -1
  152. package/dist/plugins/session-placement.d.ts +1 -1
  153. package/dist/plugins/sql-errors.d.ts +1 -1
  154. package/dist/plugins/store-backend.d.ts +59 -29
  155. package/dist/plugins/store-backend.js +75 -15
  156. package/dist/plugins/store-contracts.d.ts +5 -3
  157. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  158. package/dist/plugins/tidb-pool.js +59 -0
  159. package/dist/plugins/web-search.d.ts +1 -1
  160. package/dist/prompts-domain-validate.js +1 -1
  161. package/dist/resource-suspend.d.ts +1 -1
  162. package/dist/resource-window.d.ts +3 -3
  163. package/dist/rules-consent.d.ts +231 -9
  164. package/dist/rules-consent.js +411 -13
  165. package/dist/run-local.js +29 -4
  166. package/dist/runs.d.ts +15 -1
  167. package/dist/runs.js +19 -0
  168. package/dist/runtime-caps-resolver.d.ts +36 -1
  169. package/dist/runtime-caps-resolver.js +25 -0
  170. package/dist/runtime-governance.d.ts +1 -1
  171. package/dist/security.d.ts +5 -5
  172. package/dist/security.js +1 -1
  173. package/dist/session-sync.d.ts +52 -37
  174. package/dist/session-sync.js +19 -16
  175. package/dist/shared-memory-scope-authorizer.d.ts +1 -1
  176. package/dist/sighup-idle.d.ts +1 -1
  177. package/dist/spec-fields.d.ts +22 -1
  178. package/dist/spec-fields.js +11 -0
  179. package/dist/store-live-probe.d.ts +2 -2
  180. package/dist/task-a2a.d.ts +1 -1
  181. package/dist/task-cwd.d.ts +1 -1
  182. package/dist/task-mcp.d.ts +3 -3
  183. package/dist/task-settings.d.ts +3 -3
  184. package/dist/task-workflow.d.ts +1 -1
  185. package/dist/text-bidi.d.ts +2 -2
  186. package/dist/tool-approval.d.ts +191 -9
  187. package/dist/tool-approval.js +248 -29
  188. package/dist/trace/core-keyset-guard.d.ts +3 -3
  189. package/dist/trace/engine-notice-wire.d.ts +6 -4
  190. package/dist/trace/engine-notice-wire.js +2 -0
  191. package/dist/trace/ledger-events.d.ts +1 -1
  192. package/dist/trace/ledger-sink.d.ts +2 -2
  193. package/dist/trace/project.d.ts +8 -2
  194. package/dist/trace/project.js +10 -0
  195. package/dist/turn-activity.d.ts +1 -1
  196. package/dist/wall-clock-jump-guard.d.ts +3 -3
  197. package/package.json +3 -3
  198. package/dist/http/tar.d.ts +0 -17
  199. package/dist/http/tar.js +0 -53
  200. package/dist/http/workspace-content.d.ts +0 -11
  201. package/dist/http/workspace-content.js +0 -20
  202. package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
  203. package/dist/plugins/file-snapshot-store-sql.js +0 -213
@@ -1,7 +1,6 @@
1
1
  import type { Pool as MysqlPool } from "mysql2/promise";
2
2
  import type { Pool as PgPool } from "pg";
3
- import type { SessionStore, SessionPolicyStore, FileSnapshotStore, WorkflowJournalStore, ToolResultStore } from "@sema-agent/core";
4
- import { type FileSnapshotBounds } from "@sema-agent/core";
3
+ import type { SessionStore, SessionPolicyStore, FileHistoryStore, WorkflowJournalStore, ToolResultStore } from "@sema-agent/core";
5
4
  import { type OutcomeSink } from "./file-outcome-sink.js";
6
5
  import { type InboxWarn } from "./workflow-run-store-sql.js";
7
6
  import { FileRunStore } from "./file-run-store.js";
@@ -9,6 +8,7 @@ import { LocalCheckpointStore } from "./local-checkpoint-store.js";
9
8
  import { FileResumeAnchorStore } from "./file-resume-anchor-store.js";
10
9
  import { type ApprovalExemptionStore } from "./approval-exemption-store.js";
11
10
  import { type ApprovalAskStore as ApprovalAskStoreType } from "./approval-ask-store-sql.js";
11
+ import { type MemoryOptOutGrantStore } from "./memory-optout-grant-store-sql.js";
12
12
  import { type SendFileLedger } from "./send-file-ledger.js";
13
13
  import { TiDBResumeAnchorStore, PgResumeAnchorStore } from "./resume-anchor-store-sql.js";
14
14
  import type { ServiceConfig } from "../config-types.js";
@@ -45,22 +45,27 @@ export type { ApprovalAskStore, AskRow, NewAskRow, AskTransitionPatch, DecideAsk
45
45
  * it, core's InMemory omits it → optional). tidb/pg = durable twins; local = core's InMemorySessionPolicyStore (works
46
46
  * local — rules need no cloud-only infra). The shared env-gated equivalence suite keeps the twins byte-matched to InMemory. */
47
47
  export type ServiceSessionPolicyStore = SessionPolicyStore;
48
- /** E19 rewind-files FileSnapshotStore — core's interface PLUS the service `deleteBySession` (E21 purge; the durable
49
- * twins carry it, core's InMemory omits it → optional). tidb/pg = durable twins (manifest+blobs, reuse core
50
- * captureManifest/applyManifest); local = core's FileFileSnapshotStore(file-backed content-addressed,跨重启
51
- * 存活——接入审计 L6 订正:旧注释写 InMemory 会误导 local 快照持久性判断). Also the 2c work-artifact transfer store. */
52
- export type ServiceFileSnapshotStore = FileSnapshotStore & {
53
- /** [805]③a observability tail (SQL twins only — core's local stores drop the count internally, a core-side
54
- * gap): captureManifest's tolerated-vanished counter metric sink, assigned by main.ts when present.
55
- * codex F8: async sinks admitted; the twins swallow a rejected promise (never-throw seam holds). */
56
- onSkippedVanished?: (count: number) => void | Promise<void>;
48
+ /** S-15 per-edited-file rewind FileHistoryStore — core's interface PLUS the service extras only the SQL twins
49
+ * carry (optional so the local lane's core `FileFileHistoryStore` still fits). Replaces the retired E19
50
+ * whole-tree `ServiceFileSnapshotStore` (design/381: the boundary covers the TRACKED set only — files this
51
+ * session edited; there is no whole-tree manifest anymore). Also the 2c history-transfer store
52
+ * (exportHistory/importHistory + the blob negotiation faces below). */
53
+ export type ServiceFileHistoryStore = FileHistoryStore & {
54
+ /** 2c sync blob-face marker see SqlFileHistoryStore.syncBlobFaces (codex R2-high: name-probing
55
+ * `putBlob` on an arbitrary store collides with the local core store's PRIVATE void helper). */
56
+ syncBlobFaces?: true;
57
+ /** E21 purge / overwrite-dst sync wipe: drop the WHOLE scope incl. v1 baselines + DV-14 markers
58
+ * (`reap(scope, [])` deliberately retains those while the scope lives — not a purge). SQL twins only. */
57
59
  deleteBySession?(scope: string): Promise<number>;
58
- /** 2c session-sync DoS bound GLOBALLY GC grace-window orphan blobs (standalone PUTs never imported, plus the
59
- * blobs reap()/deleteBySession() left orphaned byte deletion is ASYNC, never on the sync purge path). The durable
60
- * twins carry it (scheduled by the main.ts reaper, error-tolerant → eventual consistency); core's InMemory omits it. */
60
+ /** Async byte-GC for the file_history_blob domain (orphans left by reap/purge/lost mint races; grace-window
61
+ * protectednever a synchronous external-store delete). Reaper-driven; SQL twins only. */
61
62
  sweepOrphanBlobs?(): Promise<number>;
62
- /** The subset of `hashes` already present a cheap SQL INDEX probe (BOTH backends). Used by the §10 import
63
- * blob-presence pre-check (a HEAD/index check, NOT N full getBlob GETs). The durable twins carry it; optional. */
63
+ /** 2c blob negotiation: upload one content-addressed blob ahead of importHistory. SQL twins only. */
64
+ putBlob?(hash: string, bytes: Uint8Array): Promise<import("@sema-agent/core").FileHistoryResult>;
65
+ /** 2c blob read face (scope-checked by the route against the session's history graph). SQL twins only. */
66
+ getBlob?(hash: string): Promise<Uint8Array | undefined>;
67
+ /** The subset of `hashes` already present — a cheap SQL INDEX probe (the import presence pre-check,
68
+ * never N full getBlob GETs). SQL twins only. */
64
69
  hasBlobs?(hashes: string[]): Promise<Set<string>>;
65
70
  };
66
71
  /** SVC-2 (core CORE-7) WorkflowJournalStore — core's interface PLUS the service `deleteByRun` (GC extra). tidb/pg =
@@ -160,9 +165,38 @@ export interface StoreBackend {
160
165
  /** E6 durable SessionPolicyStore (operator-tightened per-session tool rules). REQUIRED on all backends — works local
161
166
  * (local = core's InMemorySessionPolicyStore), like resumeAnchor. Backs core's RunnerDeps.sessionPolicyStore. */
162
167
  sessionPolicy(): ServiceSessionPolicyStore;
163
- /** E19 rewind-files FileSnapshotStore (working-tree snapshot/restore keyed by entryId; also the 2c artifact-transfer
164
- * store). REQUIRED on all backends (local = core's InMemoryFileSnapshotStore). Backs core's RunnerDeps.fileSnapshotStore. */
165
- fileSnapshot(): ServiceFileSnapshotStore;
168
+ /** S-15 per-edited-file rewind FileHistoryStore (trackEdit/annulTrack/snapshot/restore over the tracked set;
169
+ * also the 2c history-transfer store). REQUIRED on all backends (local = core's file-backed
170
+ * `FileFileHistoryStore` under the data root). Backs core's RunnerDeps.fileHistoryStore. */
171
+ fileHistory(): ServiceFileHistoryStore;
172
+ /** design/383 §3.1 / S-50 §一(S-49 S-2):per-principal **memory-capture opt-out 授权表**
173
+ * (`memory_optout_grant`)—— `RuntimeCaps.allowMemoryOptOut` 的本地 verdict 源(三层折叠:per-principal
174
+ * 行 → 部署缺省哨兵行 → 代码缺省 allow)+ `/v1/admin/memory-optout` 四端点的持久层。
175
+ *
176
+ * 🔴 **可选**(与 permissionRule 同族):SQL 后端 = 双方言 twin;`local` 车道 **undefined**,且缺席是一个
177
+ * 真答案 —— 没有 verdict 源时 `allowMemoryOptOut` 键不合成(core 读「无 per-principal 限制」,`open` 姿态
178
+ * 下 opt-out 照常生效),而 `MEMORY_CAPTURE_POLICY=governed` 在启动期对无源部署拒启
179
+ * (`boot/runtime-caps.ts` `assertMemoryCapturePolicyWirable`)。刻意**不给 local 一个 in-memory twin**:
180
+ * 一条授权行是「operator 写下的合规事实」,进程内 Map 会在重启时静默丢掉它,下一次解析读到的是
181
+ * 「没有行 ⇒ 代码缺省 allow」—— 那是**放宽面**上的静默降级(permissionRule 那条禁令的同一理由)。
182
+ * File 形候真实的 local+governed 部署需求出现再落(候需求档)。 */
183
+ memoryOptOutGrant(): MemoryOptOutGrantStore | undefined;
184
+ /** S-1 legacy-epoch discriminant (core `RunnerDeps.legacyRewindBoundaryProbe`): does the RETIRED whole-tree
185
+ * snapshot epoch hold a boundary for (sessionId, entryId)? Reads the legacy `snapshot_manifest` table.
186
+ * SQL backends only (local never had a whole-tree epoch table). Diagnostic input on the refusal path —
187
+ * a probe that cannot tell answers undefined (reads exactly like an absent probe), never throws. */
188
+ legacyRewindBoundaryProbe?(query: {
189
+ sessionId: string;
190
+ entryId: string;
191
+ }): Promise<boolean | undefined>;
192
+ /** Retired-epoch byte hygiene: GC grace-passed orphan `snapshot_blob` rows/objects (rows the retention
193
+ * lane's `snapshot_manifest` sweeps keep orphaning — without this leg their BYTES would outlive every
194
+ * manifest reference forever, incl. MinIO objects). SQL backends only; reaper-driven. */
195
+ legacySnapshotBlobSweep?(): Promise<number>;
196
+ /** Retired-epoch right-to-delete: drop the session's LEGACY `snapshot_manifest` rows on the online E21
197
+ * purge (the retention lane already sweeps them on expiry — the two delete legs must converge on the
198
+ * same row set; a user's DELETE must reach old-epoch data too). Bytes go via the async legacy sweep. */
199
+ legacySnapshotPurge?(sessionId: string): Promise<number>;
166
200
  /** SVC-2 (core CORE-7) durable WorkflowJournalStore — the cross-replica resume journal for an LLM-authored workflow
167
201
  * (RunWorkflowOptions.journalStore). REQUIRED on all backends (tidb/pg = durable twins; local = core's
168
202
  * InMemoryWorkflowJournalStore, single-replica/in-process).
@@ -261,17 +295,13 @@ export interface StoreBackend {
261
295
  * splits a fleet window into disjoint buckets = soft-limit leak). OPTIONAL: local backend omits (no fleet). */
262
296
  dbNowMs?(): Promise<number>;
263
297
  }
264
- /** (c)(clay 拍 a+c,2026-07-27)云形快照 blob 姿势门——boot 时调用(main.ts),纯函数可单测。
265
- * SQL 后端(mysql|pg)把 blob 字节落 `snapshot_blob` 单行的形已被两役实证撞 mysql-协议包墙
266
- * (D-1 附件 → 对象存储裁定;snapshot_blob >31MiB 同墙):大字节归对象存储。云形缺 MinIO
267
- * fail-loud(启动了才是假安全);`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true` = 显式接受 SQL +
268
- * per-blob 帽(单机/测试台形)。local 后端不经此门(file/in-memory 快照店,无 SQL 包墙) */
298
+ /** (c)(clay 拍 a+c,2026-07-27;S-15 换店后域=file_history_blob,门与旋钮名不变)云形 blob 姿势门——
299
+ * boot 时调用(boot/stores.ts),纯函数可单测。SQL 后端(mysql|pg)把 blob 字节落单行的形已被两役
300
+ * 实证撞 mysql-协议包墙(D-1 附件 → 对象存储裁定):大字节归对象存储。per-file 历史的 blob=单文件
301
+ * 字节,同一堵墙(>6MiB 的被 track 文件在 TiDB 上落不进 SQL ⇒ trackEdit 拒 ⇒ 默认 DV-14 下该次
302
+ * 编辑被拒)。云形缺 MinIO fail-loud(启动了才是假安全);`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true` =
303
+ * 显式接受 SQL 店 + per-blob 帽(单机/测试台形)。local 后端不经此门(file 店,无 SQL 包墙)。 */
269
304
  export declare function assertCloudSnapshotBlobPosture(kind: "mysql" | "pg" | "local", config: Pick<ServiceConfig, "snapshotBlobStore" | "snapshotBlobAllowSql">): void;
270
- /** REWIND_SNAPSHOT_MAX_MB overrides ONLY the byte cap of core's DEFAULT_SNAPSHOT_BOUNDS (raise for
271
- * big monorepos, lower for tight DBs). File-count / ignoreDirs stay core defaults — the knob answers the one
272
- * field the 20G-workspace case needed; more knobs when a case shows up. Exported for tests
273
- * (fractional-MB rounding + partial-merge semantics need a regression lock). */
274
- export declare function snapshotBoundsFromConfig(config: ServiceConfig): FileSnapshotBounds;
275
305
  /**
276
306
  * 启动日志里「跨副本 or 进程内」那一格的标签。
277
307
  *
@@ -1,22 +1,23 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
- import { AdoptionError, FileStorageBackend, FileSessionRepo, DEFAULT_SNAPSHOT_BOUNDS } from "@sema-agent/core";
3
+ import { AdoptionError, FileStorageBackend, FileSessionRepo } from "@sema-agent/core";
4
4
  import { FileWorkflowJournalStore } from "@sema-agent/core";
5
5
  import { TiDBOutcomeLedger, PgOutcomeLedger } from "./outcome-ledger-sql.js";
6
6
  import { FileOutcomeSink } from "./file-outcome-sink.js";
7
7
  import { TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore } from "./workflow-run-store-sql.js";
8
- import { FileRunStore } from "./file-run-store.js";
8
+ import { FileRunStore, RunStoreStrictHydrateError } from "./file-run-store.js";
9
9
  import { LocalSessionStore } from "./local-session-store.js";
10
10
  import { LocalCheckpointStore } from "./local-checkpoint-store.js";
11
11
  import { FileResumeAnchorStore } from "./file-resume-anchor-store.js";
12
12
  import { TiDBApprovalExemptionStore, PgApprovalExemptionStore, FileApprovalExemptionStore } from "./approval-exemption-store.js";
13
13
  import { TiDBApprovalAskStore, PgApprovalAskStore } from "./approval-ask-store-sql.js";
14
14
  import { InMemoryApprovalAskStore } from "./approval-ask-store-memory.js";
15
+ import { TiDBMemoryOptOutGrantStore, PgMemoryOptOutGrantStore } from "./memory-optout-grant-store-sql.js";
15
16
  import { TiDBSendFileLedger, PgSendFileLedger, FileSendFileLedger } from "./send-file-ledger.js";
16
17
  import { TiDBResumeAnchorStore, PgResumeAnchorStore } from "./resume-anchor-store-sql.js";
17
18
  import { TiDBSessionPolicyStore, PgSessionPolicyStore } from "./session-policy-store-sql.js";
18
19
  import { TiDBWorkflowJournalStore, PgWorkflowJournalStore } from "./workflow-journal-store-sql.js";
19
- import { TiDBFileSnapshotStore, PgFileSnapshotStore } from "./file-snapshot-store-sql.js";
20
+ import { TiDBFileHistoryStore, PgFileHistoryStore, FILE_HISTORY_BLOB_TABLE, FILE_HISTORY_BLOB_KEY_PREFIX } from "./file-history-store-sql.js";
20
21
  import { MinioBlobBackend, SqlBlobBackend } from "./blob-backend.js";
21
22
  import { createTidbPool, ensureSchema as ensureTidbSchema } from "./tidb-pool.js";
22
23
  import { createPgPool, ensurePgSchema, pgPoolOptions } from "./pg-pool.js";
@@ -41,7 +42,21 @@ import { TiDBRetentionLaneStore, PgRetentionLaneStore } from "./retention-lane-s
41
42
  import { createSqlPermissionRuleStores } from "./permission-rule-store-sql.js";
42
43
  import { createFilePermissionRuleStores } from "./permission-rule-store-file.js";
43
44
  import { mysqlDriver, pgDriver } from "./sql-driver.js";
44
- function snapshotBlobBackend(config, dialect, pool) {
45
+ function historyBlobBackend(config, dialect, pool) {
46
+ const s = config.snapshotBlobStore;
47
+ if (!s)
48
+ return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes, FILE_HISTORY_BLOB_TABLE);
49
+ return new MinioBlobBackend({
50
+ endpoint: s.endpoint,
51
+ bucket: s.bucket,
52
+ accessKey: s.accessKey,
53
+ secretKey: s.secretKey,
54
+ ...(s.region ? { region: s.region } : {}),
55
+ keyPrefix: `${s.keyPrefix ?? ""}${FILE_HISTORY_BLOB_KEY_PREFIX}`,
56
+ ...(s.presignTtlSec ? { presignTtlSec: s.presignTtlSec } : {}),
57
+ }, { dialect, pool, table: FILE_HISTORY_BLOB_TABLE });
58
+ }
59
+ function legacyBlobBackend(config, dialect, pool) {
45
60
  const s = config.snapshotBlobStore;
46
61
  if (!s)
47
62
  return new SqlBlobBackend(dialect, pool, config.snapshotBlobSqlMaxBytes);
@@ -55,18 +70,51 @@ function snapshotBlobBackend(config, dialect, pool) {
55
70
  ...(s.presignTtlSec ? { presignTtlSec: s.presignTtlSec } : {}),
56
71
  }, { dialect, pool });
57
72
  }
73
+ async function legacyProbeImpl(dialect, pool, query) {
74
+ try {
75
+ if (dialect === "tidb") {
76
+ const [rows] = await pool.query("SELECT 1 FROM snapshot_manifest WHERE scope = ? AND snap_key = ? LIMIT 1", [query.sessionId, query.entryId]);
77
+ return rows.length > 0;
78
+ }
79
+ const r = await pool.query("SELECT 1 FROM snapshot_manifest WHERE scope = $1 AND snap_key = $2 LIMIT 1", [query.sessionId, query.entryId]);
80
+ return r.rows.length > 0;
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ async function legacyPurgeImpl(dialect, pool, sessionId) {
87
+ if (dialect === "tidb") {
88
+ const [r] = await pool.query("DELETE FROM snapshot_manifest WHERE scope = ?", [sessionId]);
89
+ return Number(r.affectedRows ?? 0);
90
+ }
91
+ const r = await pool.query("DELETE FROM snapshot_manifest WHERE scope = $1", [sessionId]);
92
+ return r.rowCount ?? 0;
93
+ }
94
+ async function legacySweepImpl(config, dialect, pool) {
95
+ const sql = "SELECT blob_hash FROM snapshot_blob WHERE blob_hash NOT IN (SELECT blob_hash FROM snapshot_manifest)";
96
+ let orphans;
97
+ if (dialect === "tidb") {
98
+ const [rows] = await pool.query(sql);
99
+ orphans = rows.map((r) => String(r.blob_hash));
100
+ }
101
+ else {
102
+ const r = await pool.query(sql);
103
+ orphans = r.rows.map((row) => row.blob_hash);
104
+ }
105
+ if (orphans.length === 0)
106
+ return 0;
107
+ return legacyBlobBackend(config, dialect, pool).deleteBlobs(orphans);
108
+ }
58
109
  export function assertCloudSnapshotBlobPosture(kind, config) {
59
110
  if (kind === "local" || config.snapshotBlobStore || config.snapshotBlobAllowSql)
60
111
  return;
61
- throw new Error("cloud deployments (DB_BACKEND=mysql|pg) must configure object storage for snapshot blobs " +
112
+ throw new Error("cloud deployments (DB_BACKEND=mysql|pg) must configure object storage for rewind file-history blobs " +
62
113
  "(MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY): single-row SQL blob writes hit TiDB's " +
63
114
  "txn-entry-size-limit (default 6MiB) / the mysql-protocol packet limit (bytes belong in object storage — " +
64
115
  "same ruling as the D-1 attachment store). Single-box/test rigs may explicitly opt out with " +
65
- "SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true (a per-blob cap then applies; oversized blobs are rejected 413).");
66
- }
67
- export function snapshotBoundsFromConfig(config) {
68
- const mb = config.rewindSnapshotMaxMb;
69
- return mb !== undefined ? { ...DEFAULT_SNAPSHOT_BOUNDS, maxBytes: Math.round(mb * 1024 * 1024) } : DEFAULT_SNAPSHOT_BOUNDS;
116
+ "SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true (a per-blob cap then applies; an over-cap tracked file's first-touch " +
117
+ "backup is refused typed, which under the default DV-14 policy refuses that edit).");
70
118
  }
71
119
  class TiDBBackend {
72
120
  pool;
@@ -85,7 +133,11 @@ class TiDBBackend {
85
133
  permissionRule() { return createSqlPermissionRuleStores(mysqlDriver(this.pool)); }
86
134
  sendFileLedger() { return new TiDBSendFileLedger(this.pool); }
87
135
  sessionPolicy() { return new TiDBSessionPolicyStore(this.pool); }
88
- fileSnapshot() { return new TiDBFileSnapshotStore(this.pool, snapshotBlobBackend(this.config, "tidb", this.pool), snapshotBoundsFromConfig(this.config)); }
136
+ fileHistory() { return new TiDBFileHistoryStore(this.pool, historyBlobBackend(this.config, "tidb", this.pool), this.config.fileHistory); }
137
+ memoryOptOutGrant() { return new TiDBMemoryOptOutGrantStore(this.pool); }
138
+ legacyRewindBoundaryProbe(query) { return legacyProbeImpl("tidb", this.pool, query); }
139
+ legacySnapshotBlobSweep() { return legacySweepImpl(this.config, "tidb", this.pool); }
140
+ legacySnapshotPurge(sessionId) { return legacyPurgeImpl("tidb", this.pool, sessionId); }
89
141
  workflowJournal() { return new TiDBWorkflowJournalStore(this.pool); }
90
142
  outcomeSink() { return new TiDBOutcomeLedger(this.pool); }
91
143
  workflowRun(onWarn) { return new TiDBWorkflowRunStore(this.pool, onWarn); }
@@ -126,7 +178,11 @@ class PgBackend {
126
178
  permissionRule() { return createSqlPermissionRuleStores(pgDriver(this.pool)); }
127
179
  sendFileLedger() { return new PgSendFileLedger(this.pool); }
128
180
  sessionPolicy() { return new PgSessionPolicyStore(this.pool); }
129
- fileSnapshot() { return new PgFileSnapshotStore(this.pool, snapshotBlobBackend(this.config, "pg", this.pool), snapshotBoundsFromConfig(this.config)); }
181
+ fileHistory() { return new PgFileHistoryStore(this.pool, historyBlobBackend(this.config, "pg", this.pool), this.config.fileHistory); }
182
+ memoryOptOutGrant() { return new PgMemoryOptOutGrantStore(this.pool); }
183
+ legacyRewindBoundaryProbe(query) { return legacyProbeImpl("pg", this.pool, query); }
184
+ legacySnapshotBlobSweep() { return legacySweepImpl(this.config, "pg", this.pool); }
185
+ legacySnapshotPurge(sessionId) { return legacyPurgeImpl("pg", this.pool, sessionId); }
130
186
  workflowJournal() { return new PgWorkflowJournalStore(this.pool); }
131
187
  outcomeSink() { return new PgOutcomeLedger(this.pool); }
132
188
  workflowRun(onWarn) { return new PgWorkflowRunStore(this.pool, onWarn); }
@@ -169,7 +225,7 @@ class LocalBackend {
169
225
  try {
170
226
  this.fileBackend = new FileStorageBackend({
171
227
  root,
172
- ...(config.rewindSnapshotMaxMb !== undefined ? { snapshotBounds: { maxBytes: Math.round(config.rewindSnapshotMaxMb * 1024 * 1024) } } : {}),
228
+ ...(config.fileHistory !== undefined ? { fileHistory: config.fileHistory } : {}),
173
229
  onCorruptRead: (info) => this.onWarn?.("file_store_corrupt_read", {
174
230
  path: info.path,
175
231
  reason: info.reason,
@@ -178,7 +234,7 @@ class LocalBackend {
178
234
  note: "a durable read was treated as ABSENT because the bytes were unreadable (never a plain ENOENT). " +
179
235
  "Consequence depends on which store read it: session-policy = that run lost its SUBTRACTIVE session-rule " +
180
236
  "layer (deployment policy / hooks / shell gate still applied); session repo = a listing silently omitted " +
181
- "rows; file-snapshot = a snapshot or scope read as missing. Inspect the named path before deciding.",
237
+ "rows; file-history = a rewind boundary or scope read as missing. Inspect the named path before deciding.",
182
238
  }),
183
239
  });
184
240
  }
@@ -191,6 +247,7 @@ class LocalBackend {
191
247
  this.sessionStore = new LocalSessionStore(new FileSessionRepo(this.fileBackend.root), this.fileBackend.root);
192
248
  this.runStore = new FileRunStore(this.fileBackend.root, {
193
249
  error: (msg, fields) => void (this.onError ?? this.onWarn)?.(msg, fields),
250
+ strictHydrate: config.runStoreStrictHydrate,
194
251
  });
195
252
  this.resumeAnchorStore = new FileResumeAnchorStore(this.fileBackend.root);
196
253
  this.approvalExemptionStore = new FileApprovalExemptionStore(this.fileBackend.root);
@@ -240,7 +297,8 @@ class LocalBackend {
240
297
  }
241
298
  checkpointStoreInst;
242
299
  sessionPolicy() { return this.fileBackend.sessionPolicyStore; }
243
- fileSnapshot() { return this.fileBackend.fileSnapshotStore; }
300
+ fileHistory() { return this.fileBackend.fileHistoryStore; }
301
+ memoryOptOutGrant() { return undefined; }
244
302
  workflowJournal() { return this.workflowJournalStore; }
245
303
  outcomeSink() { return this.outcomeSinkInst; }
246
304
  session() { return this.sessionStore; }
@@ -275,6 +333,8 @@ export async function openStoreBackendWithFallback(config, logger) {
275
333
  catch (err) {
276
334
  if (err instanceof AdoptionError)
277
335
  throw err;
336
+ if (err instanceof RunStoreStrictHydrateError)
337
+ throw err;
278
338
  if (!mayFallback)
279
339
  throw err;
280
340
  logger.warn("store_db_unreachable_fallback_memory", {
@@ -30,9 +30,11 @@ export interface RunRecord {
30
30
  /** Which SYSTEM's credential submitted the run (oa/cc-mcp/portal…), derived at the auth gate — never
31
31
  * self-declared. null = legacy single-token deployment (authenticated, no system identity). */
32
32
  source: string | null;
33
- /** The replica that OWNS this run (the instanceId that created it). Lets a preempt/cancel handler tell
34
- * "this run is on MY replica" (consult the in-process inflight/preemptable map authoritatively) from "owned
35
- * elsewhere" (fall back to the durable cross-replica flag). null for pre-column rows. */
33
+ /** The replica currently HOLDING this run written at createRun and TAKEN OVER by markResuming (S-51: a
34
+ * cross-replica resume moves the seat, so a reader comparing it with its own instanceId is asking "is the
35
+ * live leg here NOW", not "who minted the row"). Lets a preempt/cancel/steer handler tell "this run is on
36
+ * MY replica" (consult the in-process inflight/steerable map authoritatively) from "held elsewhere" (fall
37
+ * back to the durable cross-replica flag). null for pre-column rows. */
36
38
  instanceId: string | null;
37
39
  /** First ~120 chars of the objective (secret-redacted at write) — the list's "what is this task" glance.
38
40
  * null for rows predating the column. */
@@ -33,7 +33,7 @@ export declare function ensurePgTaskListSchema(q: (text: string, params?: unknow
33
33
  * 语义 = 「这个 listKey 的清单**不存在过**」:item 行 + meta 行(高水位 `next_id` / 插入序
34
34
  * `next_sort`)一并抹掉。⚠️ **meta 行必须一起删**:留着它,同一个 listKey 被重新登记后
35
35
  * (会话 id 由调用方自选、删除后可被别人 `register`)新主的第一条任务会从旧主的高水位续号 ——
36
- * 那是一条跨化身的信息泄漏(「上一位在这里建过 47 条」)。
36
+ * 那是一条跨化身的信息外泄(「上一位在这里建过 47 条」)。
37
37
  *
38
38
  * 事务内先对 meta 行 `FOR UPDATE`(与 `mutate` 同一把分区锁)⇒ 与并发的清单写串行,不会删到
39
39
  * 一半被插回新行。meta 行不在(从未写过任何任务)= 无锁可拿,DELETE 命中 0 行,幂等。
@@ -1,5 +1,6 @@
1
1
  import mysql from "mysql2/promise";
2
2
  import { TIDB_APPROVAL_ASK_STATEMENTS } from "./approval-ask-store-sql.js";
3
+ import { TIDB_MEMORY_OPTOUT_GRANT_STATEMENTS } from "./memory-optout-grant-store-sql.js";
3
4
  import { TIDB_LEADER_RUN_STATEMENTS } from "./leader-run-store-sql.js";
4
5
  import { TIDB_ADOPTION_LOG_STATEMENTS } from "./adoption-log-sql.js";
5
6
  import { TIDB_PERMISSION_RULE_STATEMENTS } from "./permission-rule-store-sql.js";
@@ -335,6 +336,63 @@ export const SCHEMA_STATEMENTS = [
335
336
  created_at DATETIME(3) NOT NULL,
336
337
  PRIMARY KEY (blob_hash),
337
338
  KEY idx_snapshot_blob_created (created_at)
339
+ ) COLLATE utf8mb4_bin`,
340
+ `CREATE TABLE IF NOT EXISTS file_history_scope (
341
+ scope VARCHAR(64) NOT NULL,
342
+ created_at_ms BIGINT NOT NULL,
343
+ PRIMARY KEY (scope)
344
+ ) COLLATE utf8mb4_bin`,
345
+ `CREATE TABLE IF NOT EXISTS file_history_tracked (
346
+ scope VARCHAR(64) NOT NULL,
347
+ key_hash CHAR(64) NOT NULL,
348
+ track_key TEXT NOT NULL,
349
+ key_kind VARCHAR(16) NOT NULL,
350
+ key_family VARCHAR(8) NOT NULL,
351
+ base_available TINYINT(1) NOT NULL,
352
+ observed_later TINYINT(1) NOT NULL DEFAULT 0,
353
+ created_at_ms BIGINT NOT NULL,
354
+ PRIMARY KEY (scope, key_hash)
355
+ ) COLLATE utf8mb4_bin`,
356
+ `CREATE TABLE IF NOT EXISTS file_history_version (
357
+ scope VARCHAR(64) NOT NULL,
358
+ key_hash CHAR(64) NOT NULL,
359
+ version INT NOT NULL,
360
+ blob_hash CHAR(64) NULL,
361
+ mode INT NULL,
362
+ parent_ident TEXT NULL,
363
+ backup_time VARCHAR(40) NOT NULL,
364
+ PRIMARY KEY (scope, key_hash, version),
365
+ KEY idx_file_history_version_blob (blob_hash)
366
+ ) COLLATE utf8mb4_bin`,
367
+ `CREATE TABLE IF NOT EXISTS file_history_boundary (
368
+ scope VARCHAR(64) NOT NULL,
369
+ entry_id VARCHAR(64) NOT NULL,
370
+ published_at_ms BIGINT NOT NULL,
371
+ publish_seq BIGINT NOT NULL,
372
+ PRIMARY KEY (scope, entry_id),
373
+ UNIQUE KEY uq_file_history_boundary_seq (scope, publish_seq)
374
+ ) COLLATE utf8mb4_bin`,
375
+ `CREATE TABLE IF NOT EXISTS file_history_boundary_file (
376
+ scope VARCHAR(64) NOT NULL,
377
+ entry_id VARCHAR(64) NOT NULL,
378
+ key_hash CHAR(64) NOT NULL,
379
+ version INT NOT NULL,
380
+ PRIMARY KEY (scope, entry_id, key_hash),
381
+ KEY idx_file_history_bf_key (scope, key_hash)
382
+ ) COLLATE utf8mb4_bin`,
383
+ `CREATE TABLE IF NOT EXISTS file_history_reaped_entry (
384
+ scope VARCHAR(64) NOT NULL,
385
+ entry_id VARCHAR(64) NOT NULL,
386
+ reaped_at_ms BIGINT NOT NULL,
387
+ PRIMARY KEY (scope, entry_id)
388
+ ) COLLATE utf8mb4_bin`,
389
+ `CREATE TABLE IF NOT EXISTS file_history_blob (
390
+ blob_hash CHAR(64) NOT NULL,
391
+ byte_len BIGINT NOT NULL,
392
+ bytes LONGBLOB NULL,
393
+ created_at DATETIME(3) NOT NULL,
394
+ PRIMARY KEY (blob_hash),
395
+ KEY idx_file_history_blob_created (created_at)
338
396
  ) COLLATE utf8mb4_bin`,
339
397
  `CREATE TABLE IF NOT EXISTS workflow_journal (
340
398
  run_id VARCHAR(191) NOT NULL,
@@ -530,6 +588,7 @@ export const SCHEMA_STATEMENTS = [
530
588
  PRIMARY KEY (pool)
531
589
  ) COLLATE utf8mb4_bin`,
532
590
  ...TIDB_APPROVAL_ASK_STATEMENTS,
591
+ ...TIDB_MEMORY_OPTOUT_GRANT_STATEMENTS,
533
592
  ...TIDB_LEADER_RUN_STATEMENTS,
534
593
  `CREATE TABLE IF NOT EXISTS shared_memory_scope (
535
594
  -- 一个 org scope 一行。行缺席 = 该 org 从未开通 ⇒ 语义等价于 connected 且零 store(不是故障)。
@@ -98,7 +98,7 @@ export declare function createWebSearchBackend(cfg: WebSearchBackendConfig): Web
98
98
  *
99
99
  * 🔴 [2240] cli 逐串直证:3.18.0 我加了 `searxngParams` 字段和消费点,**却没开任何配置入口** ——
100
100
  * 两条门都没有位置填它,于是我在 [2239] 说的「这条是给你们的」是句空话。单测直接构造
101
- * `WebSearchBackendConfig` 传进去,**天然绕过了配置入口这一层**,于是「能力在」与「配得进」之间
101
+ * `WebSearchBackendConfig` 传进去,**天然跳过了配置入口这一层**,于是「能力在」与「配得进」之间
102
102
  * 断开,而两边的绿都是真的。判据:**按消费端实际能填的那个入口验,不是按自己构造的对象验。**
103
103
  *
104
104
  * 形状:`k=v` 用 `;` 分隔(`engines=bing,duckduckgo;language=zh-CN`)——值里本来就常含逗号,
@@ -22,7 +22,7 @@ function declarationIssue(d, where) {
22
22
  return `${where}: contentHash is required (sha256:<64hex> — the epoch declaration axis needs it for byte-level change detection)`;
23
23
  const expected = `sha256:${createHash("sha256").update(o.text).digest("hex")}`;
24
24
  if (o.contentHash !== expected)
25
- return `${where}: contentHash does not match sha256(text) — stale or tampered declaration`;
25
+ return `${where}: contentHash does not match sha256(text) — stale or altered declaration`;
26
26
  return undefined;
27
27
  }
28
28
  export function validateCenterPrompts(raw) {
@@ -13,7 +13,7 @@
13
13
  * remote VM — ORPHANING both (the run row is terminal, so nothing resumes them). So a resource-limit hit on a
14
14
  * verify/cascade task must FAIL CLEANLY (no suspend), exactly as before the flag. This exclusion is the SAME
15
15
  * boundary the `preemptSignal` wiring enforces in runs.ts (stream-path only), so eligibility and the signal stay
16
- * aligned. (Adversarial review wtyc7ist3 HIGH finding: without this, enabling RESOURCE_SUSPEND leaks a suspended
16
+ * aligned. (Cross review wtyc7ist3 HIGH finding: without this, enabling RESOURCE_SUSPEND leaks a suspended
17
17
  * VM + checkpoint on every verify/cascade task that hits a resource limit.)
18
18
  */
19
19
  export declare function resourceSuspendOptIn(opts: {
@@ -31,7 +31,7 @@
31
31
  * · **新世代必须清**:session purge 后客户端合法复用自带 taskId 重提交 —— {@link recordResourceWindow}
32
32
  * 每次先删后写,于是「新腿没窗」不会读到旧腿的窗(`turn-activity` codex S1-F2 同款陷阱)。
33
33
  *
34
- * 【已声明的代价:每次 poll 一次全量账本读(codex 对抗复审 R2-[medium],如实登记、本批不修)】
34
+ * 【已声明的代价:每次 poll 一次全量账本读(codex 交叉复审 R2-[medium],如实登记、本批不修)】
35
35
  * {@link buildCrossSliceUsage} 要对**全部** `model_usage` 行求和 ⇒ 调用点(`routes/runs.ts` 的 poll)在
36
36
  * 窗已登记时每拍读一次 `getEvents(taskId, 0)`,工作量随「轮询次数 × 已积累事件数」增长。三条限幅是**结构性**
37
37
  * 的,不是「应该很少见」:① **只有登记过窗的 run 才读**(没开三旋钮的部署、以及 verify/cascade 腿,一次都不读);
@@ -70,7 +70,7 @@ export interface CrossSliceUsage {
70
70
  */
71
71
  export declare function recordResourceWindow(taskId: string, rs: TaskSpec["resourceSuspend"] | undefined): void;
72
72
  /**
73
- * **续跑腿**的登记(与 {@link recordResourceWindow} 分家,codex 对抗复审 R2-[high] 验真后修)。
73
+ * **续跑腿**的登记(与 {@link recordResourceWindow} 分家,codex 交叉复审 R2-[high] 验真后修)。
74
74
  *
75
75
  * 🔴 三根旋钮在续跑腿上的下场**不同**,所以登记法也必须不同(S-3 已成文的上游契约,此处是它的读面孪生):
76
76
  * · `totalTokens` / `totalBudgetUsd` —— core **冻在账本上**(`debitLedger` 逐字 `prior ?? total`)。
@@ -85,7 +85,7 @@ export declare function recordResumeResourceWindow(taskId: string, rs: TaskSpec[
85
85
  /**
86
86
  * 本副本记得的跨片窗;无记录 ⇒ `undefined`(缺席语义见顶注:「无法证明」,不是「没有窗」)。
87
87
  *
88
- * 🔴 **读命中会刷新插入序**(codex 对抗复审 R1-[high] 的逐出半场,验真后修):终局的 run **不主动清**
88
+ * 🔴 **读命中会刷新插入序**(codex 交叉复审 R1-[high] 的逐出半场,验真后修):终局的 run **不主动清**
89
89
  * (与 `turn-activity.ts` 同理由:主动清会制造「done 已打点、行还没翻终态」窗口里的假缺席),于是纯
90
90
  * 写序 FIFO 下,一条长跑的 run 会被它之后的 8192 条**早已终局**的记录挤掉 —— 恰好挤掉唯一还需要这份
91
91
  * 数据的那一条。改成「按读刷新」= 真 LRU:被 poll 的(=活着且有人看的)那条永远是最年轻的。