@sema-agent/server 7.125.1 → 7.126.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.
- package/MIGRATION.md +195 -2
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +263 -140
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/networkpolicy-sandbox.yaml +47 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +5 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +2 -2
- package/deploy/sema-up/chart/templates/server.yaml +1 -1
- package/deploy/sema-up/chart/values.yaml +12 -0
- package/deploy/sema-up/cluster-up.sh +10 -10
- package/deploy/sema-up/kube-up.sh +11 -10
- package/deploy/sema-up/lib/dataroot.sh +1 -1
- package/deploy/sema-up/lib/envf.sh +5 -5
- package/deploy/sema-up/lib/flagshape.sh +5 -5
- package/deploy/sema-up/lib/lanes.py +1 -1
- package/deploy/sema-up/lib/parse-machines.py +2 -2
- package/deploy/sema-up/lib/shell-access.sh +1 -1
- package/deploy/sema-up/preflight.sh +4 -4
- package/deploy/sema-up/sema-up.sh +33 -33
- package/deploy/sema-up/smoke.sh +3 -3
- package/deploy/sema-up/stack/compose.yaml +1 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +6 -2
- package/dist/approval-card.d.ts +20 -4
- package/dist/approval-content-kind.d.ts +38 -22
- package/dist/approval-content-kind.js +20 -4
- package/dist/audit.js +2 -0
- package/dist/bench/s1/arms.d.ts +9 -37
- package/dist/bench/s1/arms.js +4 -61
- package/dist/bench/s1/live-deps.d.ts +4 -10
- package/dist/bench/s1/live-deps.js +1 -222
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/reviewer.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +5 -7
- package/dist/bench/s1/row.js +0 -2
- package/dist/bench/s1/run-firm.d.ts +2 -2
- package/dist/bench/s1/run-firm.js +1 -4
- package/dist/bench/s1/runner-ctx.d.ts +17 -29
- package/dist/bench/s1/runner-ctx.js +3 -7
- package/dist/bench/s1/tasks.d.ts +9 -46
- package/dist/bench/s1/tasks.js +4 -63
- package/dist/boot/execution-env.d.ts +38 -26
- package/dist/boot/execution-env.js +71 -38
- package/dist/boot/memory-boundary.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +0 -3
- package/dist/boot/parked-revive-gate.js +2 -2
- package/dist/boot/resolve-spec.d.ts +0 -2
- package/dist/boot/resolve-spec.js +12 -17
- package/dist/boot/retention-lane.d.ts +12 -1
- package/dist/boot/retention-lane.js +2 -0
- package/dist/boot/runner-deps.d.ts +5 -5
- package/dist/boot/runner-deps.js +5 -16
- package/dist/boot/session-faces.d.ts +5 -1
- package/dist/boot/session-faces.js +37 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +2 -3
- package/dist/boot/stage-06-runners.js +8 -7
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +3 -4
- package/dist/boot/stage-08-reapers.d.ts +2 -3
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/boot/stores.d.ts +1 -0
- package/dist/boot/stores.js +4 -3
- package/dist/boot/web-admin.d.ts +5 -0
- package/dist/boot/web-admin.js +28 -14
- package/dist/brain.d.ts +2 -2
- package/dist/brain.js +1 -1
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/hands-lane.d.ts +9 -6
- package/dist/capabilities/hands-lane.js +2 -2
- package/dist/capabilities/memory-notice.d.ts +27 -22
- package/dist/capabilities/memory-notice.js +15 -17
- package/dist/capabilities/scenarios.d.ts +9 -14
- package/dist/capabilities/scenarios.js +5 -50
- package/dist/capability-facts.d.ts +22 -11
- package/dist/capability-facts.js +13 -6
- package/dist/config-catalog.js +11 -4
- package/dist/config-provider.d.ts +5 -1
- package/dist/config-provider.js +23 -4
- package/dist/config-types.d.ts +14 -1
- package/dist/config.js +39 -6
- package/dist/deployment-governance.d.ts +19 -21
- package/dist/deployment-governance.js +7 -8
- package/dist/env-name-allowlist-knobs.d.ts +5 -5
- package/dist/env-name-allowlist-knobs.js +1 -0
- package/dist/execution-lane-caps.js +2 -2
- package/dist/hooks/hook-runner.d.ts +84 -30
- package/dist/hooks/hook-runner.js +74 -41
- package/dist/http/admission.js +12 -9
- package/dist/http/durable-run-leg.d.ts +5 -4
- package/dist/http/durable-run-leg.js +1 -1
- package/dist/http/idempotency.d.ts +28 -6
- package/dist/http/idempotency.js +10 -2
- package/dist/http/principal-gate.d.ts +14 -0
- package/dist/http/principal-gate.js +7 -0
- package/dist/http/request-guards.d.ts +2 -1
- package/dist/http/request-guards.js +14 -14
- package/dist/http/resume-legs.d.ts +2 -2
- package/dist/http/resume-legs.js +5 -4
- package/dist/http/route-ctx.d.ts +8 -6
- package/dist/http/routes/a2a-serve.js +11 -7
- package/dist/http/routes/approvals-assistant.js +18 -3
- package/dist/http/routes/background.d.ts +1 -1
- package/dist/http/routes/background.js +1 -1
- package/dist/http/routes/capabilities.js +10 -2
- package/dist/http/routes/mcp-reconnect.js +1 -1
- package/dist/http/routes/runs.d.ts +4 -3
- package/dist/http/routes/runs.js +12 -13
- package/dist/http/routes/session-sync.js +14 -11
- package/dist/http/routes/sessions.js +9 -9
- package/dist/http/routes/side-query.js +6 -19
- package/dist/http/routes/tasks.js +12 -11
- package/dist/http/server.d.ts +4 -0
- package/dist/http/server.js +2 -2
- package/dist/http/submit-replay.d.ts +15 -8
- package/dist/http/submit-replay.js +6 -0
- package/dist/http/wire-types.d.ts +7 -9
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/internal-run-env.d.ts +30 -0
- package/dist/internal-run-env.js +11 -0
- package/dist/leader/wire.js +3 -2
- package/dist/memory-scope.d.ts +19 -7
- package/dist/memory-scope.js +25 -8
- package/dist/observability/fail-open.d.ts +15 -3
- package/dist/observability/fail-open.js +15 -3
- package/dist/observability/metrics.d.ts +0 -1
- package/dist/observability/metrics.js +0 -3
- package/dist/observability/run-terminal.js +69 -4
- package/dist/permission-rule-vocab.d.ts +3 -2
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plan-cache-probe.d.ts +3 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +42 -28
- package/dist/plugins/checkpoint-store-sql.js +57 -11
- package/dist/plugins/file-run-store.d.ts +25 -21
- package/dist/plugins/file-run-store.js +70 -34
- package/dist/plugins/local-checkpoint-store.d.ts +8 -5
- package/dist/plugins/local-checkpoint-store.js +5 -15
- package/dist/plugins/local-session-store.d.ts +66 -7
- package/dist/plugins/local-session-store.js +168 -101
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +1 -1
- package/dist/plugins/memory-run-store.d.ts +19 -3
- package/dist/plugins/memory-run-store.js +38 -3
- package/dist/plugins/one-time-migrations.d.ts +141 -39
- package/dist/plugins/one-time-migrations.js +32 -143
- package/dist/plugins/pg-pool.js +11 -1
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +9 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -0
- package/dist/plugins/remote-env-adb.js +1 -0
- package/dist/plugins/remote-env-device.d.ts +3 -0
- package/dist/plugins/remote-env-device.js +1 -0
- package/dist/plugins/remote-env-e2b.d.ts +4 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-host.d.ts +12 -0
- package/dist/plugins/remote-env-host.js +11 -1
- package/dist/plugins/remote-env-k8s.d.ts +227 -39
- package/dist/plugins/remote-env-k8s.js +450 -75
- package/dist/plugins/remote-env-local-docker.d.ts +4 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -0
- package/dist/plugins/remote-env-ssh.js +1 -0
- package/dist/plugins/retention-store-sql.d.ts +4 -1
- package/dist/plugins/retention-store-sql.js +11 -9
- package/dist/plugins/run-store-sql.d.ts +44 -6
- package/dist/plugins/run-store-sql.js +92 -27
- package/dist/plugins/session-capture-record-store-sql.d.ts +2 -3
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +17 -3
- package/dist/plugins/tidb-pool.js +15 -3
- package/dist/plugins/tidb-session-storage.js +3 -2
- package/dist/plugins/tidb-session-store.d.ts +2 -0
- package/dist/plugins/tidb-session-store.js +6 -2
- package/dist/request-key-closure.d.ts +12 -0
- package/dist/request-key-closure.js +3 -3
- package/dist/router/route-orchestration.d.ts +3 -11
- package/dist/router/route-orchestration.js +0 -4
- package/dist/rule-entry-list.js +0 -4
- package/dist/rules-consent.js +3 -0
- package/dist/run-local.d.ts +5 -4
- package/dist/run-local.js +23 -17
- package/dist/runs.js +1 -0
- package/dist/security.d.ts +7 -0
- package/dist/security.js +5 -0
- package/dist/server-secret-env.d.ts +10 -4
- package/dist/server-secret-env.js +4 -1
- package/dist/session-incarnation.d.ts +46 -2
- package/dist/session-incarnation.js +14 -3
- package/dist/session-sync-kernel.d.ts +10 -3
- package/dist/spec-fields.d.ts +24 -8
- package/dist/spec-fields.js +21 -2
- package/dist/task-workflow.d.ts +6 -4
- package/dist/task-workflow.js +3 -2
- package/dist/tool-approval.d.ts +78 -6
- package/dist/tool-approval.js +7 -3
- package/dist/trace/core-keyset-guard.d.ts +4 -4
- package/dist/trace/engine-notice-wire.d.ts +26 -1
- package/dist/trace/engine-notice-wire.js +7 -2
- package/dist/trace/project.d.ts +8 -3
- package/dist/trace/project.js +15 -1
- package/dist/trace/self-minted-wire.d.ts +104 -2
- package/dist/trace/self-minted-wire.js +35 -0
- package/dist/web-admin-client/apply-effective.d.ts +13 -7
- package/dist/web-admin-client/apply-effective.js +11 -26
- package/dist/web-admin-client/apply-ledger.d.ts +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +39 -4
- package/dist/web-admin-client/candidate-gate.js +9 -2
- package/dist/web-admin-client/facade.d.ts +2 -2
- package/dist/web-admin-client/http-client.d.ts +3 -1
- package/dist/web-admin-client/http-client.js +4 -3
- package/dist/web-admin-client/read-warnings.d.ts +33 -5
- package/dist/web-admin-client/read-warnings.js +41 -6
- package/dist/web-admin-client/types.d.ts +11 -5
- package/dist/workspace-cache.d.ts +45 -0
- package/dist/workspace-cache.js +30 -0
- package/dist/workspace-space-commit.d.ts +116 -0
- package/dist/workspace-space-commit.js +117 -0
- package/dist/workspace-space.d.ts +75 -9
- package/dist/workspace-space.js +52 -1
- package/package.json +4 -4
- package/dist/boot/session-incarnation-seat.d.ts +0 -41
- package/dist/boot/session-incarnation-seat.js +0 -69
- package/dist/capabilities/code-review-council.d.ts +0 -49
- package/dist/capabilities/code-review-council.js +0 -111
- package/dist/capabilities/collab-wire.d.ts +0 -36
- package/dist/capabilities/collab-wire.js +0 -2
- package/dist/capabilities/collab-workflows.d.ts +0 -47
- package/dist/capabilities/collab-workflows.js +0 -90
- package/dist/capabilities/prompts/code-review.d.ts +0 -25
- package/dist/capabilities/prompts/code-review.js +0 -39
- package/dist/capabilities/prompts/team.d.ts +0 -10
- package/dist/capabilities/prompts/team.js +0 -6
- package/dist/capabilities/team.d.ts +0 -113
- package/dist/capabilities/team.js +0 -70
|
@@ -118,7 +118,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
118
118
|
},
|
|
119
119
|
"server.approvals.park-row-blob-unreadable": {
|
|
120
120
|
cls: "F",
|
|
121
|
-
note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowFactsCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。",
|
|
121
|
+
note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowFactsCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 **第二座 `member=gate`**(`readParkGateCell`:同一列的 **`gate` 子树**在场却不是一只对象 —— 队列行的卡词与到期两条腿的分法都读它):读不出 = 门上无卡,队列行不带卡词,**到期改道** —— core `facetOf` 读「无卡 = 不是一问」为 `A`,所以一张本该到期**作废**的问答行改走 SLA **拒扫腿**(模型拿到一次「拒」而不是整条 run 作废);改道后的续跑 `get()` 对同一份坏 blob 响亮拒(拒扫腿每拍一条失败),行留停驻、由 `terminal_at_ms` 兜底收割 —— 所以最坏后果**不是**「只少展示」,是一张问答行的到期去向变了、最长挂到绝对上限。放行仍对:不放行的代价与 pendingAction 座同(一行坏 blob 打掉整个租户的队列与到期读腿)。计数 detail = `member=gate` 时,去按 session 查那一行的 `checkpoint.gate`。",
|
|
122
122
|
},
|
|
123
123
|
"server.sql-json.checkpoint.pending-steer-queue-lossy": {
|
|
124
124
|
cls: "F",
|
|
@@ -206,7 +206,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
206
206
|
},
|
|
207
207
|
"server.hooks.matcher-unjudged": {
|
|
208
208
|
cls: "F",
|
|
209
|
-
note: "S-995(`hooks/hook-runner.ts` 的 `
|
|
209
|
+
note: "S-995(`hooks/hook-runner.ts` 的 `toolMatcherIssue`,fresh 受理面「工具事件 matcher 选中别名而选不中正名 ⇒ 400」判据的**未判**臂;detail = `event=… reason=… matcherChars=…`,不带 matcher 原字节):一只 matcher 没能被判 ⇒ 照旧受理。判据一条顺序、两档共用(7.114.0 修复轮):长度上限 → 形只问契约包的 `hookMatcherForm`(literal 形〔名字表 / 空 / `*`〕两档都直接问 `hookMatcherSelects`、不占预算;regex 形 regex 档把同一只契约函数交进 vm 带每次求值各一份的固定预算〔超时 = 灾难回溯 ⇒ 确定的 400 拒,不是未判、不登记〕、literal 档不适用;invalid 形 regex 档 = 确定的 400 拒〔S-1455 收尾:不是未判、不登记;运行期另记 `hook_matcher_invalid`〕、literal 档不适用)。现在只有一种 reason —— `oversize`(两档:超 8 192 字符不读;多租户车道上 hooks 不装配,这一笔只为让超长输入显形)。`invalid_regex` 臂自 S-1455 收尾(7.126.0)起退役:它是确定性的坏配置、不是「判不了」,与超预算同类 ⇒ 受理当场 400。**不记**的:literal 档(多租户车道)遇正则形 = 不适用 —— 该车道 hooks 整只不装配,没有被守的对象,不是未判。放行的最坏后果 = **那一只 matcher 没被这条判据守住**:它若真写了别名,照旧永不命中(7.112.0 对正则形一律不判,同一后果);**不是安全闸**(受理面的有效性判 = S-924 的「响亮」,决定不了任何放行 / 拒绝 / 权限;hook 的 deny 语义在运行期 hook-runner)。拒放集合相对 7.113.0 的一处放宽:超过上限的字面别名 matcher 7.113.0 拒、7.114.0 两档未判受理(已披露)。计数让「受理面一直判不了」(超长 matcher)显形。",
|
|
210
210
|
},
|
|
211
211
|
"server.hooks.notice-sink-threw": {
|
|
212
212
|
cls: "F",
|
|
@@ -273,7 +273,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
273
273
|
"server.redact.ppk-eat-to-end": { cls: "F", note: "S-107 第三十二轮重扫:PuTTY .ppk 容器扫描器(redact.ts redactPpkContainers)在「无合格终止 / 收口后同容器范围再见私钥字段 / 收口后到下一版本头之间夹非空白」三形下从头**吃到输入末尾**(fail-closed 取证丢弃)——终态 errorMessage 座上=整条错误文案变成 «redacted:private-key»,与 redactions_applied_total{private-key} 的诚实替换同形不可分,故要有自己的计数/探针;影子扫不计;计数=多少次整段吃尾。" },
|
|
274
274
|
"server.approval-card.closed-word-out-of-set": {
|
|
275
275
|
cls: "F",
|
|
276
|
-
note: "S-249(`approval-card.ts`
|
|
276
|
+
note: "S-249(`approval-card.ts` 的边界窄读族;今天四个成员:`readRuleOffersAbsence`、S-934 ② 起的 `readAskClassPair`(core 7.37.0 #1214 的类对 `askClass` / `classes`,活卡帧 / 呈卡帧的卡 / 运维队列行同一只,判法 = core 屏 `screenAskClassMembers`(S-955 ⑥ / core 7.38.0 #1249,本仓零自写对判),两键同在同缺,半对 / 集外 / 首员不符 / 重复员 = 屏拒 = 读不出;detail 前缀 `askClass=` / `classes=`),与 S-721 起的 `readClosedWordSeat` —— 一座一只 core 成员筛,座是参数:`mandate`(core 7.32.0 #1092,活卡帧 / 活挂起行 / 运维队列行同一只,闭集筛 = core `isPersistedRuleMandate`)与 S-755 起的 `origin`(运维队列行读 park 行孪生座,闭集筛 = core `isAskOrigin`,与 inbox 行 core 投影处同一只筛)、S-1170 起的 `classifierNoRuling`(core 7.43.0 #1353 的成因词,活卡帧读 `AskRequest.classifierNoRuling`,闭集筛 = core `isAutoModeFallbackCause`)与 `differs`(core 7.44.0 #1374,载体是 `runs.ts` 的 409 `steering.duplicate_input_id` 体读的引擎拒错 `detail.differs`,闭集筛 = core `STEER_REPLAY_FACETS` 的非空子集;集外成员 / 空 / 非数组 ⇒ 不铸 `detail`,码仍是契约);detail 前缀 `ruleOffersAbsence=` / `mandate=` / `origin=` / `classifierNoRuling=` / `differs=` 判别是哪一座;第四个成员是 `approval-content-kind.ts` 的 `readApprovalCard` —— 卡词 `approvalCard` 自己的闭集窄读,活 ask / LOCAL 店停驻门 / SQL 店读出的门子树三个载体共用一只,闭集 = core `TOOL_APPROVAL_CARDS`,detail 前缀 `approvalCard=`):活卡帧 / `card_json` / (S-700 起)运维队列行(`parkRowFacts` 读寄存行上的 park 孪生座;队列是热读面 ⇒ 同一行每读一次计一次)的一个**闭集词**座上,键在场而词不在本仓认得的那张表里(世代差,或第三方 producer)⇒ 该座**按缺席**处置。放行的最坏后果=卡上少一行「为什么这次没有规则候选」的解释(壳退回不显示该行),它**不改变任何裁决**——门在引擎里早已判完,本座是展示/观测面;反方向(把一个消费端词表外的值原样上卡)更坏:下游按闭集写的分支会落进 default 臂或渲染出生词。本臂存在的全部理由是**判别**:修前「上游发了个生词」与「上游根本没发这个键」在遥测上同形,而前者意味着本仓的词表该跟着 core 加词了(型面另有两向编译围栏,但那只在**重新编译**时说话,跑在线上的那一版不会自己红)。detail 带座名与那个词(经 redactSecrets 截 40);数 / 布尔等原始值原样,对象 / 数组 / 函数 / null 只报形名(`<object>` / `<array>` / `<function>` / `<null>`,S-700 codex r1:格式化从不调用值自己的转换方法 —— 持久层里一格 `{\"toString\":null}` 曾让诊断本身抛出、打掉整只队列)。",
|
|
277
277
|
},
|
|
278
278
|
"server.pg-pool.idle-client-error": {
|
|
279
279
|
cls: "F",
|
|
@@ -379,6 +379,18 @@ export const FAIL_OPEN_TAGS = {
|
|
|
379
379
|
bound: "FLEET_LEASE_OUTAGE_MAX_MS",
|
|
380
380
|
note: "`fleet/serving-lease.ts` 的 `noteCenterCapabilities`(fleet 成员每一次中心能力读数;detail = `worker=<w> generation=<g> was=<enabled|none>`):中心答复体读得出、却**没有宣告** `servingLease`(老中心 `{ ok: true }` / 降级中心 / 位撤掉)⇒ 规则 1:租约不生效,`leaseState: none`,零续租、零 503 —— 这只 fleet 成员此刻**不受围栏**。答复体读不出不进这一臂(那是「没有读数」,上一次的位与钟原样,`fleet-client.ts` `capabilityReadingOf`);已被拒的实例不进(拒是黏的,位消失不复活)。归 R:能力门控是契约规则(中心不宣告 = 中心不执行围栏),裁定写定替换只来自中心权威终止或运维覆盖;位只开关围栏、不碰钟 —— 位缺席期间 `T_max` 的钟照走(最后一次授予的到期 / 本进程第一次见到位的时刻),位一回来即按它判,所以位的抖动绕不过 `FLEET_LEASE_OUTAGE_MAX_MS`。放行的最坏后果 = 中心不执行围栏期间,一只被取代的实例照常服务(这一段由中心的选择定界,不由引擎)。计数长期保留:非零 = 这台中心没宣告租约能力。",
|
|
381
381
|
},
|
|
382
|
+
"server.workspace-cache.unavailable": {
|
|
383
|
+
cls: "F",
|
|
384
|
+
note: "k8s 车道按工作区空间的构建缓存卷(`WORKSPACE_CACHE=volume`,`plugins/remote-env-k8s.ts` 连沙箱那一步):这条 run 拿不到它空间的缓存卷 —— 卷建不成(RBAC 少动词 / API 拒 / 网络错,`reason=claim_failed`)、卷在快照时限内没绑定(集群没有缺省 StorageClass / 供给器不在,`reason=claim_unbound`)、卷绑上了而挂着它的 pod 起不来(挂载失败 / 卷所在节点没了,`reason=claim_unmountable`)—— 后两种把等它的那只 pod 删掉,换一只不挂卷的 —— 、或本副本读不出会话住客没有空间键(`reason=incarnation_unknown`)⇒ run **照常起**:不挂卷、不注入工具缓存 env,工具按镜像自己的缓存目录工作(每轮重下依赖)。放行的最坏后果 = 这一轮构建慢(缓存定义上可再生),不是门、不是凭据、不碰工作区与快照;反方向(卷拿不到就拒这一轮)会让一个缓存把整条 run 打掉。同拍一行运维日志 `workspace_cache_unavailable`(`space` 前缀 / `reason` / `error`)。计数非零 = 这台部署开了缓存卷却拿不到,运维去看 StorageClass / Role / 配额。",
|
|
385
|
+
},
|
|
386
|
+
"server.workspace-cache.reclaim-failed": {
|
|
387
|
+
cls: "F",
|
|
388
|
+
note: "k8s 车道按工作区空间的构建缓存卷的**回收**(`plugins/remote-env-k8s.ts` `createSpaceReclaimer`;两条腿同一只回收座:会话删除协调器 `boot/session-faces.ts` `purgeSession` 与托管留存 sweep `boot/retention-lane.ts` 删掉会话树之后):按标签 `sema.space=<空间摘要>` 删卷的请求失败(Role 少 `deletecollection` / API 拒 / 网络,`reason=delete_failed`)、回收座这次调用的绝对截止(= 快照时限)先到(请求没发或在途被切,`reason=budget`),或在线腿删除前读不出被删会话的住客(`reason=occupant_unreadable`;化身缺席的存量行 = 没有空间,不计)⇒ 卷留着(住客读不出时该空间的快照对象也没回收,归桶的生命周期规则),会话照删(不挡删除)。放行的最坏后果 = 节点盘上多留一只没人再用的卷(存储泄漏,不碰任何别的空间、不是门不是凭据);反方向(删卷失败就拒删会话)会让一个缓存挡住删除权。同拍一行 `workspace_cache_reclaim_failed`(回收座的两形:`space` 前缀 / `label` / `reason` / `error`;住客读不出那一形:`sessionId` / `reason` / `error`)。计数非零 = 有卷没回收掉,运维按行里的标签手清,并核 Role。",
|
|
389
|
+
},
|
|
390
|
+
"server.workspace-space.reclaim-failed": {
|
|
391
|
+
cls: "F",
|
|
392
|
+
note: "k8s 车道工作区空间结束时对**快照对象**的回收(`plugins/remote-env-k8s.ts` `createSpaceReclaimer` 的对象部分;与上一条同一只回收座、两条腿:会话删除协调器与托管留存 sweep):按空间的 `<前缀>/<化身>/space/` 分区(快照 + `latest`)和该会话停驻车道里名字带被结束住客归属记号的 `<前缀>/<会话 id>/*.tar.gz` 分别 LIST、逐个预签 DELETE;LIST 失败、DELETE 失败(HTTP 非 2xx / 非 404、网络)LIST 超过 1000 个对象被截断,或回收座一次调用的绝对截止(= 快照时限;卷回收也在内)到点〔切断在途请求、停掉余下的;这次调用里还没轮到的空间零请求、各记一次;没删的归生命周期规则〕,各记一次(detail `lane=space|park stage=list|delete|budget`;会话删除口把回收座脱离应答路径,座若抛了——契约禁止——记 `stage=seat_threw`)⇒ 这些对象留在桶里,会话照删(不挡删除)。放行的最坏后果 = 一份已无人能读的工作区快照留在桶里(会话已删,经 API 不可达;内容是用户工作区,所以不是「只占盘」—— 留到桶的生命周期规则把它过期掉为止);不碰任何别的空间、不是门不是凭据;反方向(清不掉对象就拒删会话)会让一个对象存储抖动挡住用户的删除权。故 F 类,但必须留痕:静默吞掉之后「这个会话删了、它的工作区内容还在不在桶里」在遥测里没有任何痕迹。同拍一行 `workspace_space_reclaim_failed`(`space` 前缀 / `sessionId` / `lane` / `stage` / `error`)。计数非零 = 有对象没回收掉,运维按行里的空间前缀 / 会话 id 去桶里手清,并核对象存储的可达性与 DELETE 权限。回收与同一空间的尚在途的 run 末提交不是互斥的:会话删除时没有活 run(409 挡),但上一条 run 的提交若恰在删除之后才落对象,这批对象不在本次回收射程内(同样归桶的生命周期规则)。停驻分区按会话 id 分区,所以只删名字带被结束住客归属记号的对象(不读任何钟)—— 会话 id 删后被别人重新登记,新住客停驻出的快照带它自己的记号、不碰;不带记号的旧形与 `none` 留给桶的生命周期规则。",
|
|
393
|
+
},
|
|
382
394
|
"server.fleet.announce-reply-unreadable": {
|
|
383
395
|
cls: "P-DEBT",
|
|
384
396
|
note: "7.121.0 修复验证轮(`fleet-client.ts` 的公告环,fleet 成员每一拍心跳 2xx 答复;detail = `why=<body|not-an-object|invalid-capabilities> leaseState=<此刻的租约态>`):答复不是能力读数(体读不出 / 不是对象 / `capabilities` 键在场而形坏 —— settings-schema 9.0.0 `readCapabilityReading` 的 `unreadable`,外加本仓的 `body`)⇒ 当作没有这一拍答复,租约的状态与钟原样。**一律**计数(不论租约生效与否):租约还没生效(`leaseState=none`)时这只成员**一直不受围栏**,而修前这一形零计数(中心每拍答 `<html>` ⇒ 成员恒 none、零痕迹);租约已生效时计数说明中心的答复在坏、围栏靠的是上一次读数。归 P 类:围栏轴;归 DEBT:本进程判不出中心为什么答坏体,收口条件 = 中心契约 / 监控(中心侧对心跳答复形的执法)落地。每段连拍另有一行 warn `fleet_announce_reply_unreadable`(带 `why`)。",
|
|
@@ -62,7 +62,6 @@ export interface MetricsSummary {
|
|
|
62
62
|
};
|
|
63
63
|
cascade: Record<string, number>;
|
|
64
64
|
verifications: Record<string, number>;
|
|
65
|
-
councilRuns: Record<string, number>;
|
|
66
65
|
toolErrors: Record<string, number>;
|
|
67
66
|
/** S-451(additive,7.87.0):窗内 HTTP **失败**请求数,按状态码**类**聚合 —— 键只有 `"4xx"` / `"5xx"`
|
|
68
67
|
* 两种,2xx/3xx 一格不进。⚠️ `"4xx"` 里**含 `499`**(本仓给「客户端在响应结束前断连」铸的标签,
|
|
@@ -186,7 +186,6 @@ export class Metrics {
|
|
|
186
186
|
})(cby("plan_cache_recurrence_total", "hit")),
|
|
187
187
|
cascade: cby("cascade_total", "outcome"),
|
|
188
188
|
verifications: cby("verifications_total", "verdict"),
|
|
189
|
-
councilRuns: cby("council_runs_total", "mode"),
|
|
190
189
|
toolErrors: Object.fromEntries([...(this.counters.get("tool_calls_total")?.series.values() ?? [])]
|
|
191
190
|
.filter((s) => s.labels.ok === "false")
|
|
192
191
|
.map((s) => [s.labels.name ?? "?", s.value])),
|
|
@@ -221,8 +220,6 @@ export function createMetrics() {
|
|
|
221
220
|
m.counter("task_tokens_total", "Total model tokens consumed by tasks");
|
|
222
221
|
m.histogram("task_duration_seconds", "Async run wall-clock duration");
|
|
223
222
|
m.gauge("runs_active", "Async runs currently executing");
|
|
224
|
-
m.counter("council_runs_total", "Code-review council runs (L1+L3)");
|
|
225
|
-
m.histogram("council_tokens", "Total model tokens per council review (lenses + arbiter)");
|
|
226
223
|
m.histogram("task_cache_hit_rate", "Prefix-cache hit rate per task (core-computed stats.cacheHitRate, 0..1)", [
|
|
227
224
|
0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 1,
|
|
228
225
|
]);
|
|
@@ -172,10 +172,74 @@ const STRANDED_ANSWER_TREATMENT = {
|
|
|
172
172
|
toolCallId: "provider-join-key",
|
|
173
173
|
};
|
|
174
174
|
const TERMINAL_FAILURE_DETAIL_TREATMENT = {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
175
|
+
provider_rejected: {
|
|
176
|
+
kind: "verbatim",
|
|
177
|
+
status: "verbatim",
|
|
178
|
+
code: "provider-echo",
|
|
179
|
+
providerCondition: "verbatim",
|
|
180
|
+
providerConditionSource: "verbatim",
|
|
181
|
+
providerResetAtMs: "verbatim",
|
|
182
|
+
route: "verbatim",
|
|
183
|
+
},
|
|
184
|
+
coded: { kind: "verbatim", detail: "free-text-tree" },
|
|
185
|
+
model_output_invalid: { kind: "verbatim", cause: "verbatim", outputLimit: "verbatim" },
|
|
178
186
|
};
|
|
187
|
+
const TERMINAL_DETAIL_WALK_DEPTH = 32;
|
|
188
|
+
const TERMINAL_DETAIL_TOO_DEEP = "[omitted: nested deeper than 32 levels]";
|
|
189
|
+
function redactStringLeaves(node, depth = 0) {
|
|
190
|
+
if (typeof node === "string")
|
|
191
|
+
return redactErrorMessage(node) ?? node;
|
|
192
|
+
if (node === null || typeof node !== "object")
|
|
193
|
+
return node;
|
|
194
|
+
if (depth > TERMINAL_DETAIL_WALK_DEPTH)
|
|
195
|
+
return TERMINAL_DETAIL_TOO_DEEP;
|
|
196
|
+
if (Array.isArray(node)) {
|
|
197
|
+
const next = node.map((x) => redactStringLeaves(x, depth + 1));
|
|
198
|
+
return next.every((x, i) => x === node[i]) ? node : next;
|
|
199
|
+
}
|
|
200
|
+
let out;
|
|
201
|
+
for (const [k, v] of Object.entries(node)) {
|
|
202
|
+
const nv = redactStringLeaves(v, depth + 1);
|
|
203
|
+
if (nv !== v)
|
|
204
|
+
(out ??= { ...node })[k] = nv;
|
|
205
|
+
}
|
|
206
|
+
return out ?? node;
|
|
207
|
+
}
|
|
208
|
+
function shapeTerminalFailureDetail(detail) {
|
|
209
|
+
if (detail === null || typeof detail !== "object" || Array.isArray(detail))
|
|
210
|
+
return detail;
|
|
211
|
+
const d = detail;
|
|
212
|
+
const kind = d.kind;
|
|
213
|
+
const table = typeof kind === "string" && Object.hasOwn(TERMINAL_FAILURE_DETAIL_TREATMENT, kind) ? TERMINAL_FAILURE_DETAIL_TREATMENT[kind] : undefined;
|
|
214
|
+
if (table === undefined)
|
|
215
|
+
return redactStringLeaves(d);
|
|
216
|
+
let out;
|
|
217
|
+
for (const [key, treatment] of Object.entries(table)) {
|
|
218
|
+
const v = d[key];
|
|
219
|
+
if (v === undefined)
|
|
220
|
+
continue;
|
|
221
|
+
switch (treatment) {
|
|
222
|
+
case "verbatim":
|
|
223
|
+
case "provider-join-key":
|
|
224
|
+
break;
|
|
225
|
+
case "provider-echo":
|
|
226
|
+
if (!admitProviderEcho(v, `terminal.detail.${key}`))
|
|
227
|
+
delete (out ??= { ...d })[key];
|
|
228
|
+
break;
|
|
229
|
+
case "free-text-tree": {
|
|
230
|
+
const nv = redactStringLeaves(v);
|
|
231
|
+
if (nv !== v)
|
|
232
|
+
(out ??= { ...d })[key] = nv;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
default: {
|
|
236
|
+
const unhandled = treatment;
|
|
237
|
+
throw new Error(`unhandled failure-detail treatment: ${String(unhandled)}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return out ?? detail;
|
|
242
|
+
}
|
|
179
243
|
const TERMINAL_BLOCKED_DETAIL_TREATMENT = {
|
|
180
244
|
kind: "verbatim",
|
|
181
245
|
cause: "verbatim",
|
|
@@ -279,7 +343,7 @@ export function redactTerminalResult(result) {
|
|
|
279
343
|
nt = { ...base, nestedPause: { ...np, gate: g.gate } };
|
|
280
344
|
const cur = nt ?? base;
|
|
281
345
|
const detail = cur.detail;
|
|
282
|
-
const shaped =
|
|
346
|
+
const shaped = shapeTerminalFailureDetail(detail);
|
|
283
347
|
if (shaped !== detail)
|
|
284
348
|
nt = { ...cur, detail: shaped };
|
|
285
349
|
}
|
|
@@ -609,6 +673,7 @@ const CHECKPOINT_GATE_TREATMENT = {
|
|
|
609
673
|
safetyAxis: "verbatim",
|
|
610
674
|
realApproval: "verbatim",
|
|
611
675
|
resumeAfterMs: "verbatim",
|
|
676
|
+
approvalCard: "verbatim",
|
|
612
677
|
};
|
|
613
678
|
export function redactCheckpointGate(gate) {
|
|
614
679
|
if (gate === null || typeof gate !== "object" || Array.isArray(gate))
|
|
@@ -14,9 +14,10 @@ export declare function isPersistedRuleTool(name: string): boolean;
|
|
|
14
14
|
* 唯一拼写)/ `wildcard`([ref] 尾 space-star,单命令体上与 prefix **同一谓词**,建议面自此铸它)/
|
|
15
15
|
* `subpath`(Read 目录形,永不容纳任何命令)/ `path`(core 7.9.0 [ref]:路径族 deny/ask/allow 的模式文法
|
|
16
16
|
* —— `//abs`、`~/`、`/root-relative`、cwd 相对,段内 `*`、跨段 `**`)/ `name` / `name_prefix`(core 7.43.0 #1318:`Skill` 的名字文法 ——
|
|
17
|
-
* `Skill(<名>)` 精确、`Skill(<前缀>:*)` 名字前缀、无词界;技能卡的建议行 `match: "name"`)
|
|
17
|
+
* `Skill(<名>)` 精确、`Skill(<前缀>:*)` 名字前缀、无词界;技能卡的建议行 `match: "name"`)/ `host` / `subdomain`(core 7.49.0 #1365:
|
|
18
|
+
* `WebFetch(domain:<host>)` 精确主机、`WebFetch(domain:*.<域>)` 域下每个主机 —— 只有 allow 形)。
|
|
18
19
|
*/
|
|
19
|
-
export declare const PERSISTED_RULE_MATCHES: readonly ["exact", "prefix", "wildcard", "subpath", "path", "name", "name_prefix"];
|
|
20
|
+
export declare const PERSISTED_RULE_MATCHES: readonly ["exact", "prefix", "wildcard", "subpath", "path", "name", "name_prefix", "host", "subdomain"];
|
|
20
21
|
/**
|
|
21
22
|
* S-511 —— `RuleBehavior` 每一员在**无同意仪式的直接写口**(`POST /v1/rules`)上的逐员表态。
|
|
22
23
|
*
|
|
@@ -2,7 +2,7 @@ import { ruleToolGrammarOf } from "@sema-agent/core";
|
|
|
2
2
|
export function isPersistedRuleTool(name) {
|
|
3
3
|
return ruleToolGrammarOf(name) !== undefined;
|
|
4
4
|
}
|
|
5
|
-
export const PERSISTED_RULE_MATCHES = ["exact", "prefix", "wildcard", "subpath", "path", "name", "name_prefix"];
|
|
5
|
+
export const PERSISTED_RULE_MATCHES = ["exact", "prefix", "wildcard", "subpath", "path", "name", "name_prefix", "host", "subdomain"];
|
|
6
6
|
const MATCHES_PIN = true;
|
|
7
7
|
void MATCHES_PIN;
|
|
8
8
|
export const DIRECT_RULE_WRITE_ADMITS = {
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* does an agent's traffic actually re-pose near-duplicate objectives per tenant? (arXiv 2602.18922:
|
|
9
9
|
* heterogeneous queries can hit 0–12%.) We hold the real multi-tenant traffic, so this is ours to count.
|
|
10
10
|
*
|
|
11
|
-
* **The token criterion is
|
|
12
|
-
*
|
|
11
|
+
* **The token criterion is core `strategy-store`'s (`compileStrategyQuery`) as last shipped in core 7.48.0** — core 7.49.0
|
|
12
|
+
* retired the strategy store with no replacement, so there is no core counterpart left to stay in lockstep with: from
|
|
13
|
+
* that release on this criterion is the probe's own definition, frozen at that form. Note the
|
|
13
14
|
* **asymmetry**: a stored problem is matched on its full `tokens()` set, the query on its
|
|
14
15
|
* `significant()` set. A hit = `significant(new) ⊆ tokens(historical)` OR (5.49 legacy acceptance
|
|
15
16
|
* arm) the non-CJK subset `qAlnum` is non-empty and fully contained (`qAlnum ⊆ tokens(historical)`).
|
|
@@ -538,7 +538,7 @@ export declare const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
|
538
538
|
* 64 字符(`approval-ask-machine.ts` deterministicId),按构造不可能更长。
|
|
539
539
|
* · `task_id` → 64:入口 `UUIDV7_RE`(`security.ts:134`)只放行 36 字符的规范 uuidv7;与兄弟列
|
|
540
540
|
* `task_run.task_id VARCHAR(64)` 同宽(此前 255 是本家族独有的偏离,无依据)。
|
|
541
|
-
* · `session_id` → 64
|
|
541
|
+
* · `session_id` → 64:提交入口只收 canonical uuid(36 字符;7.125.x 及更早硬拒 >64),列宽仍容存量,
|
|
542
542
|
* 与 `session_meta`/`task_run` 同宽。
|
|
543
543
|
* · `owner` → 190:`assertPrincipalShape` 的 `PRINCIPAL_MAX_LENGTH = 190`(`security.ts` 的同名导出常量,
|
|
544
544
|
* 刻意不钉行号 —— 旧注写的 `security.ts:350` 已随该文件编辑漂走)硬拒更长者;
|
|
@@ -42,6 +42,9 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
42
42
|
* 🔴 必须转发(与 retention / placements / instruction-source 同一条教训):生产默认把真店包进本类,不转发 = parked 决定腿
|
|
43
43
|
* 与记忆座在默认部署上读不到化身。 */
|
|
44
44
|
readonly sessionFaceOf?: SessionFaceReader;
|
|
45
|
+
/** core `SessionStore.incarnationOf`(按 id 读住客)—— 同一条纯转发、同一条理由:答的是行上那一格,绝不从暖缓存里那只会话的元数据答
|
|
46
|
+
* (缓存的会话活得比「另一只店删掉又重建了这一行」长)。🔴 必须转发:k8s 工作区空间的每 run 读与起服门读的就是本类。 */
|
|
47
|
+
readonly incarnationOf?: SessionStore["incarnationOf"];
|
|
45
48
|
readonly register?: (sessionId: string, owner: string | null) => Promise<void>;
|
|
46
49
|
/** Delegated SessionRepo seam (§0.5) — list/fork/delete operate on the DURABLE tables directly (they bypass the
|
|
47
50
|
* warm cache by design; a fork/delete must read/write durable state, not a possibly-stale cached view). */
|
|
@@ -7,6 +7,7 @@ export class CachingSessionStore {
|
|
|
7
7
|
timer;
|
|
8
8
|
ownerOf;
|
|
9
9
|
sessionFaceOf;
|
|
10
|
+
incarnationOf;
|
|
10
11
|
register;
|
|
11
12
|
listSessions;
|
|
12
13
|
fork;
|
|
@@ -49,6 +50,8 @@ export class CachingSessionStore {
|
|
|
49
50
|
this.ownerOf = ownerAware.ownerOf.bind(inner);
|
|
50
51
|
if (ownerAware.sessionFaceOf)
|
|
51
52
|
this.sessionFaceOf = ownerAware.sessionFaceOf.bind(inner);
|
|
53
|
+
if (typeof inner.incarnationOf === "function")
|
|
54
|
+
this.incarnationOf = inner.incarnationOf.bind(inner);
|
|
52
55
|
if (ownerAware.register)
|
|
53
56
|
this.register = ownerAware.register.bind(inner);
|
|
54
57
|
if (ownerAware.listSessions)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
2
2
|
import type { Pool as PgPool } from "pg";
|
|
3
|
-
import { type ExecutionOutcomeRecordWord, type GateOutcome, type Checkpoint, type CheckpointGate, type CheckpointState, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type PendingSteerInput, type ResumeOutcome, type ResolvedOutcome, type ResolveExpectation, type ReopenReason, type RiskDescriptor, type StoreDurability, type StoreFidelity } from "@sema-agent/core";
|
|
3
|
+
import { type ExecutionOutcomeRecordWord, type GateOutcome, type Checkpoint, type CheckpointGate, type CheckpointState, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type PendingSteerInput, type ResumeOutcome, type ResolvedOutcome, type ResolveExpectation, type ReopenReason, type RiskDescriptor, type StoreDurability, type StoreFidelity, type ToolApprovalCard } from "@sema-agent/core";
|
|
4
4
|
import { type ParkRowFacts, type RuleOfferProjection } from "../approval-card.js";
|
|
5
5
|
import { type SqlDialect, type SqlDriver } from "./sql-driver.js";
|
|
6
6
|
export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
@@ -127,17 +127,14 @@ export interface PendingCheckpoint extends ParkRowFacts {
|
|
|
127
127
|
*/
|
|
128
128
|
hasBidiControls?: true;
|
|
129
129
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* `
|
|
135
|
-
*
|
|
136
|
-
* (普通工具门 / 非工具 park / toolName 缺席的存量行)。展示/分诊用,永不参与 resume / gate / CAS。
|
|
137
|
-
* 两条 durable 读面(`GET /v1/approvals` 行 + `/stream` `pending` 帧)经同一投影同时携带;live 腿的
|
|
138
|
-
* 同名键在 `LivePendingRow.contentKind`(同一词属主)。
|
|
130
|
+
* core 7.49.0 #1414:**这一行渲在哪张卡上** —— 门上引擎铸的 `gate.approvalCard`(闭集 core `TOOL_APPROVAL_CARDS`;`question` = 问用户的
|
|
131
|
+
* 问题,不是副作用工具),即 core `summarizeCheckpoint` 投给 `CheckpointSummary.approvalCard` 的同一个词。读法单点 = `approval-content-kind.ts`
|
|
132
|
+
* 的 `parkedApprovalCard`(只在审批门型上读、闭集窄读;两只店同调它:SQL 孪生读 `checkpoint` 列的 `gate` 子树,LOCAL 孪生读 blob 上的门)。
|
|
133
|
+
* 🔴 缺席即缺席([ref]② OMIT 纪律):非审批门、7.49.0 之前停驻的存量行(门上无卡 —— core 的读法「无卡 = 不是一问」,本仓**不**从
|
|
134
|
+
* 工具名回推)。两条 durable 读面(`GET /v1/approvals` 行 + `/stream` `pending` 帧)经同一投影同时携带;live 腿的同名键在
|
|
135
|
+
* `LivePendingRow.approvalCard`。展示/分诊用,永不参与 resume / gate / CAS。(此前此处是按 `tool_name` 列派生的 `contentKind`,随 #1414 删。)
|
|
139
136
|
*/
|
|
140
|
-
|
|
137
|
+
approvalCard?: ToolApprovalCard;
|
|
141
138
|
}
|
|
142
139
|
/**
|
|
143
140
|
* [ref]([ref] / DEBTS [ref]):session 键读口(`findPendingTokenBySession` / `peekPendingScope`)的**行绑定**。
|
|
@@ -416,8 +413,8 @@ interface SteerColumnRead {
|
|
|
416
413
|
* **一列一形**:`pending_steer_queue` 存 `PendingSteerEntry[]`。
|
|
417
414
|
*
|
|
418
415
|
* 🔴 7.74.0 起只剩这**一**列。队列化之前的裸单座列 `pending_steer` 随它的席位一起退役了(core 7.17.0
|
|
419
|
-
* [ref] d:引擎对带席的行 PRE-CAS 拒 `seat_retired`)
|
|
420
|
-
* (`plugins/one-time-migrations.ts
|
|
416
|
+
* [ref] d:引擎对带席的行 PRE-CAS 拒 `seat_retired`),存量列 7.74.0 起由启动期的一次性迁移删掉;迁移窗关后删码,
|
|
417
|
+
* 仍带着这一列的跳版升级库起服**响亮拒**(`plugins/one-time-migrations.ts` 的退役 schema 拒启臂)。
|
|
421
418
|
* ⇒ 这里刻意**没有**第二条读腿:双读臂的寿命就是那一次迁移,不是永远。
|
|
422
419
|
*
|
|
423
420
|
* 列有内容却读不出 ⇒ `lossy`(两个调用点对它的处置见 {@link SteerColumnRead})。
|
|
@@ -623,29 +620,46 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
623
620
|
*
|
|
624
621
|
* [ref] D-D: the deadline-branch EXPIRES (≈ abort) every kind EXCEPT a tool-approval human/irreversible_ask
|
|
625
622
|
* gate — those are resolve-DENIED gracefully by the SLA deny-sweep (listExpiredApprovalGates →
|
|
626
|
-
* resumeCheckpoint(deny)), so expiring them here too would race + lose the graceful denial.
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
623
|
+
* resumeCheckpoint(deny)), so expiring them here too would race + lose the graceful denial. Legacy rows (gate_kind
|
|
624
|
+
* NULL) stay on the expire path. The terminal_at_ms-branch is the crash-safe backstop for ANY kind (incl. a human
|
|
625
|
+
* gate whose deny-resume keeps failing) — it always abort-expires past the absolute cap (which is now STRICTLY
|
|
626
|
+
* after the deadline, so it never races the deny-sweep at the deadline instant).
|
|
627
|
+
*
|
|
628
|
+
* core 7.49.0 #1414 / #1468 A-S4: among the approval kinds, which rows the deny-sweep owns has ONE judge — core
|
|
629
|
+
* `facetOf(gate)`. A gate carrying the `question` card is facet `B` (a question's deadline voids it; denying a question
|
|
630
|
+
* is incoherent), so step ② expires it here row by row (token CAS, `status='pending'` guarded — a concurrent decide or
|
|
631
|
+
* another replica wins cleanly). The card lives only in the `checkpoint` blob's `gate` subtree, so the split cannot be
|
|
632
|
+
* one SQL predicate without writing core's judgment a second time in SQL; the old `tool_name` literal arm is gone. A
|
|
633
|
+
* gate with no card (parked before 7.49.0) is no question — core's reading — and stays with the deny-sweep.
|
|
633
634
|
*/
|
|
634
635
|
reapExpired(cutoff: number): Promise<number>;
|
|
636
|
+
/** reapExpired ②'s position in the overdue approval rows, per store instance (see there). Absent = start from the earliest deadline. */
|
|
637
|
+
private reapCursor;
|
|
635
638
|
/**
|
|
636
|
-
* [ref] D-D (SLA-timer): the sessions of pending
|
|
637
|
-
*
|
|
638
|
-
* with the denial) — graceful, vs the abort that expire() gives
|
|
639
|
-
* rows (gate_kind NULL — they predate the split and fall through to
|
|
640
|
-
* the per-tick deny-resume work (each is a model run).
|
|
641
|
-
* 🔴
|
|
642
|
-
*
|
|
643
|
-
*
|
|
639
|
+
* [ref] D-D (SLA-timer): the sessions of pending approval-kind checkpoints past their `deadline` (the per-approval
|
|
640
|
+
* SLA) that the deny-sweep owns ({@link denySweepOwns} — core `facetOf` reads them as facet `A`) — the reaper resolve-DENIES
|
|
641
|
+
* each (re-resume with decision=deny → the model continues with the denial) — graceful, vs the abort that expire() gives
|
|
642
|
+
* resource_limit/needs_review. Excludes legacy rows (gate_kind NULL — they predate the split and fall through to
|
|
643
|
+
* reapExpired's expire path). `limit` bounds the per-tick deny-resume work (each is a model run).
|
|
644
|
+
* 🔴 core 7.49.0 #1414 / #1468 A-S4: a gate carrying the `question` card (facet `B`) is NOT deny-swept — core refuses
|
|
645
|
+
* `sla_timeout` on it pre-CAS — reapExpired voids it instead. The card lives only in the blob's `gate` subtree and the
|
|
646
|
+
* judge is core's (the split is not one SQL predicate — see {@link reapExpired}), so the filter runs on the rows read;
|
|
647
|
+
* the read is therefore PAGED, filter first and `limit` after: pages of {@link REAP_CLASSIFY_BATCH} rows in the stable
|
|
648
|
+
* (deadline, token) order, the cursor advancing, until `limit` rows are collected or the overdue rows run out — the same
|
|
649
|
+
* "filter, then take `limit`" the LOCAL twin does. A backlog of question rows ahead of the deny-sweep's rows costs extra
|
|
650
|
+
* bounded pages, never a hidden deny-sweep row (they used to hold slots of a `LIMIT limit` window until voided).
|
|
644
651
|
*/
|
|
645
652
|
listExpiredApprovalGates(cutoff: number, limit?: number): Promise<Array<{
|
|
646
653
|
sessionId: string;
|
|
647
654
|
scope: string;
|
|
648
655
|
}>>;
|
|
656
|
+
/**
|
|
657
|
+
* core 7.49.0 #1414 / #1468 A-S4 —— 审批门型里过了 deadline 的 pending 行(deadline 升序),每行带 core 对它的到期读法
|
|
658
|
+
* (`denySweepOwns` = 审批门型 ∧ core `facetOf` 读作 `A`,门型取列、卡取 `gate` 子树)。到期两条腿(reapExpired 的 ②、拒扫腿的选行)读同一只:
|
|
659
|
+
* 对审批门型「谁拒扫、谁作废」本仓不写第二份判据。读恒有界(每次一页 `limit` 行),序 = (deadline, token) 稳定序;`after` = 从这一位置之后读
|
|
660
|
+
* (reapExpired 的跨拍游标;拒扫腿选行一次之内的翻页游标)。
|
|
661
|
+
*/
|
|
662
|
+
private overdueApprovalRows;
|
|
649
663
|
/** Pending checkpoints for the operator queue — NON-secret fields only (never the token). `taskId` is
|
|
650
664
|
* joined from task_active (the JOIN KEY to the run/trace — a suspended run KEEPS its
|
|
651
665
|
* session claim, so the join is live for every pending row; null only in pathological windows). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parkedApprovalCard, parkedFacetOf } from "../approval-content-kind.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { APPROVAL_GATE_KINDS_SQL_IN } from "../tool-approval.js";
|
|
3
|
+
import { APPROVAL_GATE_KINDS_SQL_IN, denySweepOwns } from "../tool-approval.js";
|
|
4
4
|
import { CheckpointError, MAX_RULE_TEXT_CHARS, validatePendingSteer, appendPendingSteer, checkpointVersionOf, winnerFromOutcome, summarizeCheckpoint, MAX_SUPPORTED_CHECKPOINT_VERSION, ExecutionOutcomeConflictError, executionRecordDisposition, executionVerdict, } from "@sema-agent/core";
|
|
5
5
|
import { redactDeep, redactSecrets } from "../trace/redact.js";
|
|
6
6
|
import { MAX_RULE_OFFERS, MAX_RULE_OFFER_BATCH_MEMBERS, RuleOfferRawSchema, backfillLegacyBatchMemberKind, parkRowFacts, screenUncoveredDetailSeat } from "../approval-card.js";
|
|
@@ -10,6 +10,7 @@ import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "./sql-driver.
|
|
|
10
10
|
import { isDupKeyError, isMissingColumnError } from "./sql-errors.js";
|
|
11
11
|
import { MANAGED_RETENTION } from "./retention-store-sql.js";
|
|
12
12
|
import { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
13
|
+
const REAP_CLASSIFY_BATCH = 200;
|
|
13
14
|
export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
14
15
|
const MAX_TOOL_INPUT_CHARS = 8192;
|
|
15
16
|
export const TERMINAL_BACKSTOP_MS = Math.max(60_000, (Number.isFinite(Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS)) ? Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS) : 0) || 30 * 86_400_000);
|
|
@@ -182,6 +183,22 @@ function readParkRowFactsCell(cell) {
|
|
|
182
183
|
return parkRowFacts(pendingAction);
|
|
183
184
|
}
|
|
184
185
|
const PARK_ROW_PENDING_ACTION = { key: "pendingAction", as: "pending_action" };
|
|
186
|
+
const PARK_ROW_GATE = { key: "gate", as: "park_gate" };
|
|
187
|
+
function readParkGateCell(cell) {
|
|
188
|
+
try {
|
|
189
|
+
return decodeNullableJsonColumn(cell, readParkGateMemberBody, "checkpoint.checkpoint $.gate (approval card / expiry facet)");
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
if (!isJsonColumnBodyProblem(e))
|
|
193
|
+
throw e;
|
|
194
|
+
recordFailOpen("server.approvals.park-row-blob-unreadable", "member=gate");
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const readParkGateMemberBody = createObjectColumnReader();
|
|
199
|
+
function parkedGateOfRow(r) {
|
|
200
|
+
return { kind: r.gate_kind ?? undefined, approvalCard: readParkGateCell(r[PARK_ROW_GATE.as])?.approvalCard };
|
|
201
|
+
}
|
|
185
202
|
const readPendingActionMemberBody = createObjectColumnReader();
|
|
186
203
|
export function boundedToolInput(args) {
|
|
187
204
|
if (args === undefined)
|
|
@@ -518,21 +535,49 @@ export class SqlCheckpointStore {
|
|
|
518
535
|
}
|
|
519
536
|
async reapExpired(cutoff) {
|
|
520
537
|
const res = await this.db.query(this.q("UPDATE checkpoint SET status = 'expired', decided_at_ms = ? " +
|
|
521
|
-
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= ? AND (gate_kind IS NULL OR gate_kind NOT IN ${APPROVAL_GATE_KINDS_SQL_IN}
|
|
522
|
-
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= $2 AND (gate_kind IS NULL OR gate_kind NOT IN ${APPROVAL_GATE_KINDS_SQL_IN}
|
|
523
|
-
|
|
538
|
+
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= ? AND (gate_kind IS NULL OR gate_kind NOT IN ${APPROVAL_GATE_KINDS_SQL_IN})) OR (terminal_at_ms IS NOT NULL AND terminal_at_ms <= ?))`, "UPDATE checkpoint SET status = 'expired', decided_at_ms = $1 " +
|
|
539
|
+
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= $2 AND (gate_kind IS NULL OR gate_kind NOT IN ${APPROVAL_GATE_KINDS_SQL_IN})) OR (terminal_at_ms IS NOT NULL AND terminal_at_ms <= $3))`), [Date.now(), cutoff, cutoff]);
|
|
540
|
+
let n = res.affected;
|
|
541
|
+
const batch = await this.overdueApprovalRows(cutoff, REAP_CLASSIFY_BATCH, this.reapCursor);
|
|
542
|
+
for (const row of batch) {
|
|
543
|
+
if (!row.denySweeps && (await this.expire(row.token, row.scope)))
|
|
544
|
+
n++;
|
|
545
|
+
}
|
|
546
|
+
const last = batch.at(-1);
|
|
547
|
+
this.reapCursor = batch.length < REAP_CLASSIFY_BATCH || last === undefined ? undefined : { deadline: last.deadline, token: last.token };
|
|
548
|
+
return n;
|
|
524
549
|
}
|
|
550
|
+
reapCursor;
|
|
525
551
|
async listExpiredApprovalGates(cutoff, limit = 100) {
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
552
|
+
const hits = [];
|
|
553
|
+
let after;
|
|
554
|
+
while (hits.length < limit) {
|
|
555
|
+
const page = await this.overdueApprovalRows(cutoff, REAP_CLASSIFY_BATCH, after);
|
|
556
|
+
for (const r of page) {
|
|
557
|
+
if (hits.length < limit && r.denySweeps)
|
|
558
|
+
hits.push({ sessionId: r.sessionId, scope: r.scope });
|
|
559
|
+
}
|
|
560
|
+
const last = page.at(-1);
|
|
561
|
+
if (page.length < REAP_CLASSIFY_BATCH || last === undefined)
|
|
562
|
+
break;
|
|
563
|
+
after = { deadline: last.deadline, token: last.token };
|
|
564
|
+
}
|
|
565
|
+
return hits;
|
|
566
|
+
}
|
|
567
|
+
async overdueApprovalRows(cutoff, limit, after) {
|
|
568
|
+
const head = `SELECT c.token, c.session_id, c.scope, c.gate_kind, c.deadline, ${jsonColumnText(this.db.dialect, "checkpoint", PARK_ROW_GATE)} FROM checkpoint c ` +
|
|
569
|
+
`WHERE c.status = 'pending' AND c.gate_kind IN ${APPROVAL_GATE_KINDS_SQL_IN} AND c.deadline IS NOT NULL AND `;
|
|
570
|
+
const { rows } = await this.db.query(after === undefined
|
|
571
|
+
? head + this.q("c.deadline <= ? ORDER BY c.deadline ASC, c.token ASC LIMIT ?", "c.deadline <= $1 ORDER BY c.deadline ASC, c.token ASC LIMIT $2")
|
|
572
|
+
: head +
|
|
573
|
+
this.q("c.deadline <= ? AND (c.deadline > ? OR (c.deadline = ? AND c.token > ?)) ORDER BY c.deadline ASC, c.token ASC LIMIT ?", "c.deadline <= $1 AND (c.deadline > $2 OR (c.deadline = $3 AND c.token > $4)) ORDER BY c.deadline ASC, c.token ASC LIMIT $5"), after === undefined ? [cutoff, limit] : [cutoff, after.deadline, after.deadline, after.token, limit]);
|
|
574
|
+
return rows.map((r) => ({ token: String(r.token), sessionId: String(r.session_id), scope: String(r.scope), deadline: Number(r.deadline), denySweeps: denySweepOwns(parkedGateOfRow(r)) }));
|
|
530
575
|
}
|
|
531
576
|
async listPending(scope) {
|
|
532
577
|
const d = this.db.dialect;
|
|
533
578
|
const base = `SELECT c.session_id, c.scope, c.tool_name, c.tool_call_id, ${jsonColumnText(d, "tool_input")}, c.bound_input_hash, ` +
|
|
534
579
|
`${jsonColumnText(d, "risk_descriptor")}, ${jsonColumnText(d, "rule_suggestions")}, c.has_bidi_controls, c.created_at_ms, c.deadline, c.gate_kind, ta.task_id, ` +
|
|
535
|
-
`${jsonColumnText(d, "checkpoint", PARK_ROW_PENDING_ACTION)} ` +
|
|
580
|
+
`${jsonColumnText(d, "checkpoint", PARK_ROW_PENDING_ACTION)}, ${jsonColumnText(d, "checkpoint", PARK_ROW_GATE)} ` +
|
|
536
581
|
"FROM checkpoint c LEFT JOIN task_active ta ON ta.session_id = c.session_id WHERE c.status='pending'";
|
|
537
582
|
const { rows } = scope
|
|
538
583
|
? await this.db.query(`${base}${this.q(" AND c.scope=?", " AND c.scope=$1")} ORDER BY c.created_at_ms ASC`, [scope])
|
|
@@ -543,6 +588,7 @@ export class SqlCheckpointStore {
|
|
|
543
588
|
const boundInputHash = r.bound_input_hash ?? null;
|
|
544
589
|
const gateKind = r.gate_kind ?? null;
|
|
545
590
|
const ruleOffers = readRuleOffersCell(r.rule_suggestions);
|
|
591
|
+
const approvalCard = parkedApprovalCard(parkedGateOfRow(r));
|
|
546
592
|
return {
|
|
547
593
|
sessionId: String(r.session_id),
|
|
548
594
|
scope: String(r.scope),
|
|
@@ -558,7 +604,7 @@ export class SqlCheckpointStore {
|
|
|
558
604
|
riskDescriptor: readRiskDescriptorCell(r.risk_descriptor),
|
|
559
605
|
...(ruleOffers !== undefined ? { ruleOffers } : {}),
|
|
560
606
|
...(Number(r.has_bidi_controls) === 1 ? { hasBidiControls: true } : {}),
|
|
561
|
-
...(
|
|
607
|
+
...(approvalCard !== undefined ? { approvalCard } : {}),
|
|
562
608
|
...readParkRowFactsCell(r[PARK_ROW_PENDING_ACTION.as]),
|
|
563
609
|
};
|
|
564
610
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type UsageRow } from "../usage-analytics.js";
|
|
2
2
|
import type { TaskStatus } from "@sema-agent/core";
|
|
3
|
-
import { StoreBootRefusalError, type CreateRunOutcome, type NewRunMeta, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
3
|
+
import { StoreBootRefusalError, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
4
4
|
import type { RunStoreCheckpointProbe } from "./memory-run-store.js";
|
|
5
5
|
import type { LedgerEventType } from "../trace/ledger-events.js";
|
|
6
|
+
import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
|
|
6
7
|
/**
|
|
7
8
|
* `RUN_STORE_STRICT_HYDRATE=on` 下 hydrate 列不出 `runs/` 时的**拒启**类型([ref] 件B;codex 对抗复审
|
|
8
9
|
* R1-[high] 验真后从裸 `Error` 升成具名类型)。
|
|
@@ -25,6 +26,11 @@ export declare class FileRunStore {
|
|
|
25
26
|
private readonly runsDir;
|
|
26
27
|
private readonly activeDir;
|
|
27
28
|
private readonly tmpDir;
|
|
29
|
+
/** `<root>/space-commits/` — the twin of `workspace_space_commit`: one record per space key (file name = the key,
|
|
30
|
+
* checked by `sanitizePathComponent`; written by `atomicWriteFile`). */
|
|
31
|
+
private readonly spaceCommitsDir;
|
|
32
|
+
/** The k8s workspace space's commit fence (the rule: `workspace-space-commit.ts`) over the record files. */
|
|
33
|
+
private readonly spaceCommits;
|
|
28
34
|
/** taskId → RunRow (the run registry index). */
|
|
29
35
|
private readonly runs;
|
|
30
36
|
/** sessionId → taskId — the single-active-run claim (the task_active table; index of active/*). */
|
|
@@ -55,6 +61,15 @@ export declare class FileRunStore {
|
|
|
55
61
|
private runJsonPath;
|
|
56
62
|
private eventsPath;
|
|
57
63
|
private activePath;
|
|
64
|
+
private spaceCommitPath;
|
|
65
|
+
/** One space's commit record, or `undefined` (no file). A record that is not this store's shape is a loud read failure
|
|
66
|
+
* (the reader — the next run's connect — refuses; it never guesses that no commit is in flight). */
|
|
67
|
+
private loadSpaceCommit;
|
|
68
|
+
/** The k8s workspace space's commit fence rows (SQL twin: `workspace_space_commit`; the rule: `workspace-space-commit.ts`). */
|
|
69
|
+
readSpaceCommit(spaceKey: string): Promise<SpaceCommitReading | undefined>;
|
|
70
|
+
claimSpaceCommit(spaceKey: string, taskId: string, state: SpaceCommitState, claim: SpaceCommitClaim): Promise<boolean>;
|
|
71
|
+
endSpaceCommit(spaceKey: string, taskId: string): Promise<void>;
|
|
72
|
+
abandonSpaceCommit(spaceKey: string, taskId: string): Promise<boolean>;
|
|
58
73
|
private toRow;
|
|
59
74
|
private toDisk;
|
|
60
75
|
private toRecord;
|
|
@@ -120,6 +135,9 @@ export declare class FileRunStore {
|
|
|
120
135
|
/** [ref] FIRST terminal writer wins(SQL 孪生同款正向 CAS on running/suspended/needs_review,
|
|
121
136
|
* [1.207 codex M1] 负向形漏 blocked/timeout);claim 释放保持无条件(幂等)。 */
|
|
122
137
|
setTerminal(taskId: string, status: TaskStatus, result: PersistedTaskResult | null, error: string | null): Promise<void>;
|
|
138
|
+
/** The terminal write's one synchronous section (SQL twin: one transaction): the k8s space's pending commit record (when
|
|
139
|
+
* offered) → the terminal row → the active-run claim release. Returns whether the pending record is now this run's. */
|
|
140
|
+
private writeTerminal;
|
|
123
141
|
/** Durable F4: park NON-terminal `suspended`, KEEP the task_active claim. CAS on running/suspended (reaper-revert guard).
|
|
124
142
|
* S-173:同时落 `result` —— 封口脱敏后的投影(`sealRunRowResult`,凭据不落;`null` = 没观察到 park 结果),SQL 孪生同注。 */
|
|
125
143
|
setSuspended(taskId: string, result: PersistedTaskResult | null): Promise<void>;
|
|
@@ -131,11 +149,15 @@ export declare class FileRunStore {
|
|
|
131
149
|
markResuming(taskId: string, instanceId: string): Promise<boolean>;
|
|
132
150
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
133
151
|
getRun(taskId: string): Promise<RunRecord | undefined>;
|
|
134
|
-
/** Undo THIS submission's
|
|
152
|
+
/** Undo THIS submission's binding (key + body fingerprint → null) — called only where the submit surface refuses the submission
|
|
135
153
|
* before any work and terminalizes the row it just claimed (the sync leg's zero-work refusal, a device-placement reject):
|
|
136
154
|
* the error answer invites a retry, and a retry with the same key must run, not replay the refusal. The row stays (it
|
|
137
|
-
* is the refusal's record); only the
|
|
155
|
+
* is the refusal's record); only the binding is freed. */
|
|
138
156
|
releaseIdemKey(taskId: string): Promise<void>;
|
|
157
|
+
/** The body fingerprint this row's binding of `idem.key` holds — binding `idem.bodyFingerprint` first when it holds none (first
|
|
158
|
+
* arrival binds and is persisted, everyone after reads; the file twin of the SQL conditional UPDATE — one writer per data root,
|
|
159
|
+
* single-threaded between the check and the write). `null` = no such row, or the row is not bound to this key (never written). */
|
|
160
|
+
bindIdemBodyFingerprint(taskId: string, idem: RunIdemBinding): Promise<string | null>;
|
|
139
161
|
/** The run a submission's scoped `Idempotency-Key` names (the file twin of `uq_task_run_idem`), if any. */
|
|
140
162
|
getRunByIdem(idemKey: string): Promise<RunRecord | undefined>;
|
|
141
163
|
/** Runs newest-first, keyset on (createdAt, taskId) DESC; optional exact-match filters (owner is exact, like the SQL). */
|
|
@@ -312,24 +334,6 @@ export declare class FileRunStore {
|
|
|
312
334
|
private releaseClaim;
|
|
313
335
|
/** Drop a run entirely (registry + event log + open fd + on-disk dir) — used by deleteBySession. */
|
|
314
336
|
private dropRun;
|
|
315
|
-
/**
|
|
316
|
-
* 🔴 **一次性迁移 M3 的 local 腿(窗口见 `one-time-migrations.ts` 登记表,随 M3 一起删)** —— 退役词旧拼法的账本改写,
|
|
317
|
-
* SQL 两孪生那条整表 UPDATE 的 local 形。逐条走**同一只**纯改写函数,所以三条车道改出来的字节一致。
|
|
318
|
-
*
|
|
319
|
-
* 为什么是 store 上的一只动词、而不是外面一个文件走查:本店的账本有**两份**在场 —— 盘上的 jsonl
|
|
320
|
-
* 与 hydrate 进来的内存索引。外部走查只改得到前者,读腿读的却是后者(`getEvents` 从 Map 取),
|
|
321
|
-
* 于是迁移在本次进程里完全不生效、下次重启才"忽然"生效。两份一起改的唯一正确位置就是这里。
|
|
322
|
-
*
|
|
323
|
-
* 写盘用整文件原子替换(不是追加):改的是**已有行**,而 `AppendLog` 只会往后写。替换之前把**全部**
|
|
324
|
-
* append fd 撤掉(rename 之后旧 fd 指向的是被 unlink 的 inode,继续往那儿追加 = 之后的事件全部写进一个
|
|
325
|
-
* 没人看得见的文件),下一次 `appendEvent` 会按惰性规则重新开。撤 fd 复用**既有的那一只** {@link dispose}
|
|
326
|
-
* —— 刻意不在这里另写一段 close+catch:那会是本文件第二处同形的兜底臂,而规则要变少不要变多。
|
|
327
|
-
* 常态下这一撤是空操作:本动词跑在 boot 期,那时一个 append fd 都还没惰性开出来。
|
|
328
|
-
*
|
|
329
|
-
* 幂等:零命中 ⇒ 一个字节都不写、一只 fd 都不撤(第二跑零 I/O)。
|
|
330
|
-
* @returns 被改写的账本**行**数(不是 run 数)。
|
|
331
|
-
*/
|
|
332
|
-
migrateRetiredAskOriginRows(): Promise<number>;
|
|
333
337
|
/**
|
|
334
338
|
* 一次性迁移 **M6 的 local 腿**(窗、删法与删后谁接住:窗口见 `plugins/one-time-migrations.ts` 登记表):把 ≤7.115.x 写下的死亡判决行
|
|
335
339
|
* (`failed` ∧ 码列空 ∧ 句子是那两句,判据 = `readLegacyHolderDeathCode`)补上机读码,盘上(`run.json` 整份原子替换,同 `persist`)与内存同改。
|