@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.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +103 -24
- package/dist/adoption/plan.d.ts +4 -4
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -2
- package/dist/approval-card.js +9 -0
- package/dist/approval-hmac.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +2 -2
- package/dist/approval-reconciler.js +1 -1
- package/dist/bench/l8/artifact.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/budget-tracing.js +2 -5
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +6 -6
- package/dist/boot/org-memory.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +17 -4
- package/dist/boot/resolve-spec.d.ts +12 -0
- package/dist/boot/resolve-spec.js +29 -7
- package/dist/boot/retention-lane.d.ts +2 -2
- package/dist/boot/runner-deps.d.ts +17 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/runtime-caps.d.ts +23 -0
- package/dist/boot/runtime-caps.js +24 -2
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +14 -3
- package/dist/boot/stores.js +31 -1
- package/dist/boot/task-list-lane.d.ts +2 -2
- package/dist/brain.js +51 -31
- package/dist/budget.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +3 -3
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/config-center/hot-keys-registry.js +5 -0
- package/dist/config-center/http-client.d.ts +2 -2
- package/dist/config-center/read-face.d.ts +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-types.d.ts +100 -25
- package/dist/config.d.ts +11 -3
- package/dist/config.js +91 -15
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +2 -2
- package/dist/device-store.d.ts +3 -3
- package/dist/device-ws-hub.d.ts +4 -2
- package/dist/device-ws-hub.js +9 -3
- package/dist/device-ws-protocol.d.ts +2 -2
- package/dist/env-facts.d.ts +1 -1
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/fleet-bus.d.ts +5 -2
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/hooks/hook-runner.d.ts +8 -1
- package/dist/http/active-run-conflict.d.ts +2 -2
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +27 -5
- package/dist/http/routes/admin-memory-optout.d.ts +48 -0
- package/dist/http/routes/admin-memory-optout.js +75 -0
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +21 -21
- package/dist/http/routes/capabilities.js +20 -9
- package/dist/http/routes/diagnostics.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +1 -1
- package/dist/http/routes/memory-bundle.js +2 -1
- package/dist/http/routes/memory-compliance.d.ts +4 -4
- package/dist/http/routes/memory-origin.d.ts +4 -4
- package/dist/http/routes/memory-origin.js +3 -1
- package/dist/http/routes/memory-policy.js +6 -2
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +5 -2
- package/dist/http/routes/rules.js +84 -5
- package/dist/http/routes/run-memory-capture.d.ts +34 -0
- package/dist/http/routes/run-memory-capture.js +97 -0
- package/dist/http/routes/runs.d.ts +1 -0
- package/dist/http/routes/runs.js +212 -6
- package/dist/http/routes/session-sync.d.ts +4 -6
- package/dist/http/routes/session-sync.js +60 -47
- package/dist/http/routes/sessions.js +61 -188
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/tasks.js +1 -1
- package/dist/http/routes/workflows.js +19 -0
- package/dist/http/server.d.ts +35 -13
- package/dist/http/server.js +110 -14
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +41 -8
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/leader.d.ts +1 -1
- package/dist/leader/repair-oracle.d.ts +2 -2
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/main.js +14 -6
- package/dist/memory-bundle-engine.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +5 -5
- package/dist/memory-origin-fence.d.ts +35 -0
- package/dist/memory-origin-fence.js +66 -0
- package/dist/memory-posture.d.ts +13 -1
- package/dist/memory-posture.js +1 -0
- package/dist/memory-scope.d.ts +6 -1
- package/dist/memory-scope.js +3 -2
- package/dist/model-select.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +17 -5
- package/dist/orchestration/hardened-vm-runner.d.ts +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +7 -2
- package/dist/plugins/blob-backend.js +22 -18
- package/dist/plugins/caching-session-store.d.ts +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.d.ts +170 -0
- package/dist/plugins/file-history-store-sql.js +827 -0
- package/dist/plugins/file-run-store.d.ts +44 -5
- package/dist/plugins/file-run-store.js +85 -13
- package/dist/plugins/fork-routing-session-store.d.ts +1 -1
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-session-store.d.ts +9 -1
- package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
- package/dist/plugins/memory-origin-law.d.ts +2 -2
- package/dist/plugins/memory-run-store.d.ts +4 -3
- package/dist/plugins/memory-run-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +16 -6
- package/dist/plugins/permission-rule-store-file.js +77 -13
- package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
- package/dist/plugins/permission-rule-store-sql.js +123 -21
- package/dist/plugins/pg-pool.js +59 -0
- package/dist/plugins/pg-safe-json.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
- package/dist/plugins/retention-store-sql.d.ts +7 -7
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.d.ts +9 -3
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +59 -29
- package/dist/plugins/store-backend.js +75 -15
- package/dist/plugins/store-contracts.d.ts +5 -3
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.js +59 -0
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/prompts-domain-validate.js +1 -1
- package/dist/resource-suspend.d.ts +1 -1
- package/dist/resource-window.d.ts +3 -3
- package/dist/rules-consent.d.ts +231 -9
- package/dist/rules-consent.js +411 -13
- package/dist/run-local.js +29 -4
- package/dist/runs.d.ts +15 -1
- package/dist/runs.js +19 -0
- package/dist/runtime-caps-resolver.d.ts +36 -1
- package/dist/runtime-caps-resolver.js +25 -0
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +5 -5
- package/dist/security.js +1 -1
- package/dist/session-sync.d.ts +52 -37
- package/dist/session-sync.js +19 -16
- package/dist/shared-memory-scope-authorizer.d.ts +1 -1
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +22 -1
- package/dist/spec-fields.js +11 -0
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- package/dist/task-workflow.d.ts +1 -1
- package/dist/text-bidi.d.ts +2 -2
- package/dist/tool-approval.d.ts +191 -9
- package/dist/tool-approval.js +248 -29
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/project.d.ts +8 -2
- package/dist/trace/project.js +10 -0
- package/dist/turn-activity.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +3 -3
- package/dist/http/tar.d.ts +0 -17
- package/dist/http/tar.js +0 -53
- package/dist/http/workspace-content.d.ts +0 -11
- package/dist/http/workspace-content.js +0 -20
- package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
- 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,
|
|
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
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
|
|
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
|
-
/**
|
|
59
|
-
*
|
|
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
|
+
* protected — never a synchronous external-store delete). Reaper-driven; SQL twins only. */
|
|
61
62
|
sweepOrphanBlobs?(): Promise<number>;
|
|
62
|
-
/**
|
|
63
|
-
|
|
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
|
-
/**
|
|
164
|
-
* store). REQUIRED on all backends (local = core's
|
|
165
|
-
|
|
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)
|
|
265
|
-
* SQL 后端(mysql|pg)把 blob
|
|
266
|
-
* (D-1 附件 →
|
|
267
|
-
*
|
|
268
|
-
*
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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-
|
|
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
|
-
|
|
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
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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. (
|
|
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
|
|
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
|
|
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
|
|
88
|
+
* 🔴 **读命中会刷新插入序**(codex 交叉复审 R1-[high] 的逐出半场,验真后修):终局的 run **不主动清**
|
|
89
89
|
* (与 `turn-activity.ts` 同理由:主动清会制造「done 已打点、行还没翻终态」窗口里的假缺席),于是纯
|
|
90
90
|
* 写序 FIFO 下,一条长跑的 run 会被它之后的 8192 条**早已终局**的记录挤掉 —— 恰好挤掉唯一还需要这份
|
|
91
91
|
* 数据的那一条。改成「按读刷新」= 真 LRU:被 poll 的(=活着且有人看的)那条永远是最年轻的。
|