@sema-agent/server 7.51.0 → 7.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/USAGE.md +103 -24
  4. package/dist/adoption/plan.d.ts +4 -4
  5. package/dist/adoption/plan.js +11 -0
  6. package/dist/approval-card.d.ts +26 -2
  7. package/dist/approval-card.js +9 -0
  8. package/dist/approval-hmac.d.ts +1 -1
  9. package/dist/approval-reconciler.d.ts +2 -2
  10. package/dist/approval-reconciler.js +1 -1
  11. package/dist/bench/l8/artifact.d.ts +1 -1
  12. package/dist/bench/s1/arms.d.ts +1 -1
  13. package/dist/bench/s1/live-deps.d.ts +1 -1
  14. package/dist/bench/s1/oracle.d.ts +1 -1
  15. package/dist/bench/s1/row.d.ts +1 -1
  16. package/dist/boot/budget-tracing.d.ts +1 -1
  17. package/dist/boot/budget-tracing.js +2 -5
  18. package/dist/boot/coordinators.js +3 -1
  19. package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
  20. package/dist/boot/device-lane.js +2 -0
  21. package/dist/boot/engine-lease.d.ts +1 -1
  22. package/dist/boot/execution-env.d.ts +1 -1
  23. package/dist/boot/governance-seams.d.ts +2 -2
  24. package/dist/boot/leader.d.ts +1 -1
  25. package/dist/boot/memory-boundary.d.ts +2 -2
  26. package/dist/boot/memory-consolidation.d.ts +6 -6
  27. package/dist/boot/org-memory.d.ts +1 -1
  28. package/dist/boot/parked-revive-gate.d.ts +3 -3
  29. package/dist/boot/reapers.d.ts +2 -2
  30. package/dist/boot/reapers.js +17 -4
  31. package/dist/boot/resolve-spec.d.ts +12 -0
  32. package/dist/boot/resolve-spec.js +29 -7
  33. package/dist/boot/retention-lane.d.ts +2 -2
  34. package/dist/boot/runner-deps.d.ts +17 -7
  35. package/dist/boot/runner-deps.js +4 -2
  36. package/dist/boot/runtime-caps.d.ts +23 -0
  37. package/dist/boot/runtime-caps.js +24 -2
  38. package/dist/boot/session-faces.d.ts +1 -1
  39. package/dist/boot/session-faces.js +14 -3
  40. package/dist/boot/stores.js +31 -1
  41. package/dist/boot/task-list-lane.d.ts +2 -2
  42. package/dist/brain.js +51 -31
  43. package/dist/budget.d.ts +2 -2
  44. package/dist/capabilities/center-plugins.d.ts +1 -1
  45. package/dist/capabilities/collab-workflows.d.ts +1 -1
  46. package/dist/capabilities/hands-lane.d.ts +3 -3
  47. package/dist/capabilities/scenarios.d.ts +3 -3
  48. package/dist/capabilities/skills.d.ts +1 -1
  49. package/dist/config-center/hot-keys-registry.js +5 -0
  50. package/dist/config-center/http-client.d.ts +2 -2
  51. package/dist/config-center/read-face.d.ts +1 -1
  52. package/dist/config-center/restart-signal.d.ts +1 -1
  53. package/dist/config-types.d.ts +100 -25
  54. package/dist/config.d.ts +11 -3
  55. package/dist/config.js +91 -15
  56. package/dist/deployment-governance.d.ts +1 -1
  57. package/dist/device-enrollment.d.ts +2 -2
  58. package/dist/device-store.d.ts +3 -3
  59. package/dist/device-ws-hub.d.ts +4 -2
  60. package/dist/device-ws-hub.js +9 -3
  61. package/dist/device-ws-protocol.d.ts +2 -2
  62. package/dist/env-facts.d.ts +1 -1
  63. package/dist/execution-lane-caps.d.ts +1 -1
  64. package/dist/fleet/fleet-bus.d.ts +5 -2
  65. package/dist/fleet/fleet-reconciler.d.ts +1 -1
  66. package/dist/fleet/fleet-terminal-window.d.ts +1 -1
  67. package/dist/hooks/hook-runner.d.ts +8 -1
  68. package/dist/http/active-run-conflict.d.ts +2 -2
  69. package/dist/http/principal-gate.d.ts +1 -1
  70. package/dist/http/route-ctx.d.ts +27 -5
  71. package/dist/http/routes/admin-memory-optout.d.ts +48 -0
  72. package/dist/http/routes/admin-memory-optout.js +75 -0
  73. package/dist/http/routes/agents-roster.d.ts +1 -1
  74. package/dist/http/routes/approvals-assistant.js +21 -21
  75. package/dist/http/routes/capabilities.js +20 -9
  76. package/dist/http/routes/diagnostics.d.ts +1 -1
  77. package/dist/http/routes/leader.d.ts +1 -1
  78. package/dist/http/routes/memory-bundle.d.ts +1 -1
  79. package/dist/http/routes/memory-bundle.js +2 -1
  80. package/dist/http/routes/memory-compliance.d.ts +4 -4
  81. package/dist/http/routes/memory-origin.d.ts +4 -4
  82. package/dist/http/routes/memory-origin.js +3 -1
  83. package/dist/http/routes/memory-policy.js +6 -2
  84. package/dist/http/routes/retention-ops.d.ts +1 -1
  85. package/dist/http/routes/rules.d.ts +5 -2
  86. package/dist/http/routes/rules.js +84 -5
  87. package/dist/http/routes/run-memory-capture.d.ts +34 -0
  88. package/dist/http/routes/run-memory-capture.js +97 -0
  89. package/dist/http/routes/runs.d.ts +1 -0
  90. package/dist/http/routes/runs.js +212 -6
  91. package/dist/http/routes/session-sync.d.ts +4 -6
  92. package/dist/http/routes/session-sync.js +60 -47
  93. package/dist/http/routes/sessions.js +61 -188
  94. package/dist/http/routes/shared-memory.d.ts +1 -1
  95. package/dist/http/routes/tasks.js +1 -1
  96. package/dist/http/routes/workflows.js +19 -0
  97. package/dist/http/server.d.ts +35 -13
  98. package/dist/http/server.js +110 -14
  99. package/dist/http/verify-rounds.d.ts +1 -1
  100. package/dist/http/wire-types.d.ts +41 -8
  101. package/dist/leader/endpoint.d.ts +1 -1
  102. package/dist/leader/leader.d.ts +1 -1
  103. package/dist/leader/repair-oracle.d.ts +2 -2
  104. package/dist/leader/repair-oracle.js +1 -1
  105. package/dist/main.js +14 -6
  106. package/dist/memory-bundle-engine.d.ts +1 -1
  107. package/dist/memory-operator-faces.d.ts +5 -5
  108. package/dist/memory-origin-fence.d.ts +35 -0
  109. package/dist/memory-origin-fence.js +66 -0
  110. package/dist/memory-posture.d.ts +13 -1
  111. package/dist/memory-posture.js +1 -0
  112. package/dist/memory-scope.d.ts +6 -1
  113. package/dist/memory-scope.js +3 -2
  114. package/dist/model-select.d.ts +2 -2
  115. package/dist/observability/fail-open.d.ts +17 -5
  116. package/dist/observability/fail-open.js +17 -5
  117. package/dist/orchestration/hardened-vm-runner.d.ts +2 -2
  118. package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
  119. package/dist/plugins/background-shell-support.d.ts +2 -2
  120. package/dist/plugins/blob-backend.d.ts +7 -2
  121. package/dist/plugins/blob-backend.js +22 -18
  122. package/dist/plugins/caching-session-store.d.ts +7 -3
  123. package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
  124. package/dist/plugins/file-history-store-sql.d.ts +170 -0
  125. package/dist/plugins/file-history-store-sql.js +827 -0
  126. package/dist/plugins/file-run-store.d.ts +44 -5
  127. package/dist/plugins/file-run-store.js +85 -13
  128. package/dist/plugins/fork-routing-session-store.d.ts +1 -1
  129. package/dist/plugins/fork-routing-session-store.js +2 -2
  130. package/dist/plugins/leader-run-store-sql.d.ts +1 -1
  131. package/dist/plugins/local-session-store.d.ts +9 -1
  132. package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
  133. package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
  134. package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
  135. package/dist/plugins/memory-origin-law.d.ts +2 -2
  136. package/dist/plugins/memory-run-store.d.ts +4 -3
  137. package/dist/plugins/memory-run-store.js +2 -1
  138. package/dist/plugins/permission-rule-store-file.d.ts +16 -6
  139. package/dist/plugins/permission-rule-store-file.js +77 -13
  140. package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
  141. package/dist/plugins/permission-rule-store-sql.js +123 -21
  142. package/dist/plugins/pg-pool.js +59 -0
  143. package/dist/plugins/pg-safe-json.d.ts +1 -1
  144. package/dist/plugins/remote-env-device.d.ts +1 -1
  145. package/dist/plugins/remote-env-k8s.d.ts +1 -1
  146. package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
  147. package/dist/plugins/retention-store-sql.d.ts +7 -7
  148. package/dist/plugins/retention-store-sql.js +6 -0
  149. package/dist/plugins/run-store-sql.d.ts +9 -3
  150. package/dist/plugins/run-store-sql.js +2 -2
  151. package/dist/plugins/send-user-file.d.ts +1 -1
  152. package/dist/plugins/session-placement.d.ts +1 -1
  153. package/dist/plugins/sql-errors.d.ts +1 -1
  154. package/dist/plugins/store-backend.d.ts +59 -29
  155. package/dist/plugins/store-backend.js +75 -15
  156. package/dist/plugins/store-contracts.d.ts +5 -3
  157. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  158. package/dist/plugins/tidb-pool.js +59 -0
  159. package/dist/plugins/web-search.d.ts +1 -1
  160. package/dist/prompts-domain-validate.js +1 -1
  161. package/dist/resource-suspend.d.ts +1 -1
  162. package/dist/resource-window.d.ts +3 -3
  163. package/dist/rules-consent.d.ts +231 -9
  164. package/dist/rules-consent.js +411 -13
  165. package/dist/run-local.js +29 -4
  166. package/dist/runs.d.ts +15 -1
  167. package/dist/runs.js +19 -0
  168. package/dist/runtime-caps-resolver.d.ts +36 -1
  169. package/dist/runtime-caps-resolver.js +25 -0
  170. package/dist/runtime-governance.d.ts +1 -1
  171. package/dist/security.d.ts +5 -5
  172. package/dist/security.js +1 -1
  173. package/dist/session-sync.d.ts +52 -37
  174. package/dist/session-sync.js +19 -16
  175. package/dist/shared-memory-scope-authorizer.d.ts +1 -1
  176. package/dist/sighup-idle.d.ts +1 -1
  177. package/dist/spec-fields.d.ts +22 -1
  178. package/dist/spec-fields.js +11 -0
  179. package/dist/store-live-probe.d.ts +2 -2
  180. package/dist/task-a2a.d.ts +1 -1
  181. package/dist/task-cwd.d.ts +1 -1
  182. package/dist/task-mcp.d.ts +3 -3
  183. package/dist/task-settings.d.ts +3 -3
  184. package/dist/task-workflow.d.ts +1 -1
  185. package/dist/text-bidi.d.ts +2 -2
  186. package/dist/tool-approval.d.ts +191 -9
  187. package/dist/tool-approval.js +248 -29
  188. package/dist/trace/core-keyset-guard.d.ts +3 -3
  189. package/dist/trace/engine-notice-wire.d.ts +6 -4
  190. package/dist/trace/engine-notice-wire.js +2 -0
  191. package/dist/trace/ledger-events.d.ts +1 -1
  192. package/dist/trace/ledger-sink.d.ts +2 -2
  193. package/dist/trace/project.d.ts +8 -2
  194. package/dist/trace/project.js +10 -0
  195. package/dist/turn-activity.d.ts +1 -1
  196. package/dist/wall-clock-jump-guard.d.ts +3 -3
  197. package/package.json +3 -3
  198. package/dist/http/tar.d.ts +0 -17
  199. package/dist/http/tar.js +0 -53
  200. package/dist/http/workspace-content.d.ts +0 -11
  201. package/dist/http/workspace-content.js +0 -20
  202. package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
  203. package/dist/plugins/file-snapshot-store-sql.js +0 -213
package/README.md CHANGED
@@ -191,7 +191,7 @@ One row per endpoint family (not exhaustive):
191
191
  | `POST /v1/tasks` · `/v1/tasks/stream` | Synchronous task execution; SSE variant streams typed `TaskEvent`s token by token |
192
192
  | `POST /v1/runs` · `GET /v1/runs/:id` | Asynchronous runs: immediate `202`, background execution, poll for status/result |
193
193
  | `GET /v1/runs/:id/events` | Replayable SSE (`Last-Event-ID` resume); any replica can serve any run |
194
- | `POST /v1/runs/:id/cancel` / `steer` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | Run control verbs: cooperative cancel, mid-run steering, context compaction, sub-agent steering/resume |
194
+ | `POST /v1/runs/:id/cancel` / `steer` / `interrupt` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | Run control verbs: cooperative cancel, mid-run steering, turn-level interrupt (with `text`: cut the in-flight turn + steer, run continues; bare body: halt — cut + stop, the run ends completed with `haltedByUser:true`, session resumable), context compaction, sub-agent steering/resume |
195
195
  | `/v1/approvals` (list · decide · stream) | Human-in-the-loop approval center backed by durable checkpoints; decisions from any replica |
196
196
  | `/v1/sessions` (list · get · fork · init · settings · wake) | Session listing/search, audit inspection, fork, startup bundle |
197
197
  | `/v1/workflows` (list · get · stream · agents/:label/steer) | Deterministic workflow orchestration runs with live streams and per-agent steering |
package/README.zh-CN.md CHANGED
@@ -176,7 +176,7 @@ curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>"
176
176
  | `POST /v1/tasks` · `/v1/tasks/stream` | 同步任务执行;SSE 变体逐 token 流式输出类型化 `TaskEvent` |
177
177
  | `POST /v1/runs` · `GET /v1/runs/:id` | 异步 run:立即 `202`,后台续跑,轮询状态/结果 |
178
178
  | `GET /v1/runs/:id/events` | 可重放 SSE(`Last-Event-ID` 续订);任意副本可服务任意 run |
179
- | `POST /v1/runs/:id/cancel` / `steer` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | run 控制动词:协作式取消、运行中转向、上下文压缩、子智能体转向/恢复 |
179
+ | `POST /v1/runs/:id/cancel` / `steer` / `interrupt` / `compact` · `/v1/runs/:id/subagents/:target/steer` / `resume` | run 控制动词:协作式取消、运行中转向、turn 级中断(切当前在飞 turn,run 继续)、上下文压缩、子智能体转向/恢复 |
180
180
  | `/v1/approvals`(list · decide · stream) | 人工审批中心,底座是持久化检查点;任意副本都能批复 |
181
181
  | `/v1/sessions`(list · get · fork · init · settings · wake) | 会话列表/检索、审计回溯、fork、启动包 |
182
182
  | `/v1/workflows`(list · get · stream · agents/:label/steer) | 确定性 workflow 编排 run,带实时流与逐 agent 转向 |
package/USAGE.md CHANGED
@@ -59,7 +59,7 @@ MODEL_FIRST_TOKEN_TIMEOUT_MS=30000 # SSE 已开但迟迟不吐第一个 delta(
59
59
  MODEL_IDLE_TIMEOUT_MS=20000 # (1.40.1)出过 token 后中途卡死:每个 delta 重置,静默超时→中止(补 first-token 只管首字)
60
60
  # ④ 断路器:主网关连败 N 次即"开路"→ 快速失败,让 failover 立刻切备(不再逐个等超时)
61
61
  MODEL_CIRCUIT_BREAKER=true MODEL_CB_FAILURE_THRESHOLD=5 MODEL_CB_COOLDOWN_MS=30000
62
- # ⑤ 每次调用的重试上限(0–20)。**不设 = 用引擎默认**(server 不再钉死它)
62
+ # ⑤ 每次调用的重试上限(0–20)。**不设 = 用引擎默认**(server 不再写死它)
63
63
  GATEWAY_MAX_RETRIES=10 # openai 兼容腿(第三方限流 provider 走的就是这条)
64
64
  ANTHROPIC_MAX_RETRIES=10 # 云 Anthropic 腿
65
65
  ```
@@ -109,11 +109,11 @@ MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;词
109
109
  # (主模型 5xx、以及兜底的一般 http 错误类也切便宜模型)。
110
110
  # 不想要这两类触发就显式设回 rate_limit,breaker_open。拼错词 boot 拒启(不静默忽略)。
111
111
  ```
112
- - 反应式降级 brain 包在**最外层**(core council #8);fallback brain 用自己的凭据(decorator 清掉主模型的 per-call key 防泄漏给别的 provider)。**坑**:`MODEL_DEGRADE_TO` 最好别和被限流的是同一网关/账号,否则反应式切过去照样撞同一个 rate_limit。
112
+ - 反应式降级 brain 包在**最外层**(core council #8);fallback brain 用自己的凭据(decorator 清掉主模型的 per-call key 防外泄给别的 provider)。**坑**:`MODEL_DEGRADE_TO` 最好别和被限流的是同一网关/账号,否则反应式切过去照样撞同一个 rate_limit。
113
113
  - **定价怎么设**:`model.cost` 来自 `MODEL_COST_INPUT/OUTPUT/CACHE_READ/CACHE_WRITE`(**USD per 1M tokens**,默认 0 = `costUsd` 读 0)。云模型(如 review-gw 的 deepseek-v4-flash)必须设,否则 spend 恒为 $0;本地自托管(qwen)留 0 即对(无 per-token 外部花费)。字段名是 `costUsd`,**非美元计价的网关要先折算**(如 DeepSeek 官方 CNY ÷ 汇率)。配置控制面管的模型走 `CenterModel.cost`(中心存价、不存 secret)。
114
114
  - 成本计量**自动开**:从 config 的 `model.cost`(per-1M 绝对 USD)注入 `pricing`,core 算出权威的整数 `costMicroUsd`(避免浮点累计误差)。`/metrics` 新增:`model_cost_micro_usd_total{model}`(覆盖所有 brain 调用=主任务+异步+council 子任务的总花费)、`brain_first_token_ms`(网关 hang 早警)、`brain_call_latency_ms`、`tool_calls_total{name,ok}`、`budget_exceeded_total{code}`、`cost_quota_rejected_total`、`degraded_total{reason}`(1.40 降级)。
115
115
  - **近预算降级 vs 硬闸**:降级(`MODEL_DEGRADE_TO`,到 `atCostFraction` 切便宜模型)是**撑长**预算、任务仍完成(出口质量下降、发 `task.degraded` 事件可告警);硬闸(`maxCostUsd` 全额)仍在,切了便宜模型还超全额 → `limits.max_cost_exceeded` 停。
116
- - **`METRICS_TOKEN`**(可选,只读):设了它,`GET /metrics`+`/metrics/summary` 接受**它或** `SERVICE_AUTH_TOKEN`。**全 fleet 设同一个值** → 管理端(sema-web,规划名 sema-admin)用**一个** token 拉所有 worker 的指标,**无需持有各 worker 的全权 `SERVICE_AUTH_TOKEN`**(不破坏 secret 边界)。即使泄露也只暴露指标(只读)。
116
+ - **`METRICS_TOKEN`**(可选,只读):设了它,`GET /metrics`+`/metrics/summary` 接受**它或** `SERVICE_AUTH_TOKEN`。**全 fleet 设同一个值** → 管理端(sema-web,规划名 sema-admin)用**一个** token 拉所有 worker 的指标,**无需持有各 worker 的全权 `SERVICE_AUTH_TOKEN`**(不破坏 secret 边界)。即使外泄也只暴露指标(只读)。
117
117
  - **`GET /metrics/summary`**(token-gated,同 `/metrics`):`/metrics` 的**精炼 JSON**——`{model, runsActive, tasks{status}, tokensTotal, costUsd, costUsdByModel, taskDurationAvgSec, brainFirstTokenAvgMs, brainCallAvgMs, cacheHitRateAvg, rateLimited, costQuotaRejected, budgetExceeded, degraded, cascade, verifications, councilRuns, toolErrors}`。给**轻量 fleet 看板**用(管理端 sema-web 的 fleet 页按 worker 拉、渲染卡片、按轮询算速率;**不用 Prometheus/Grafana**)。counter 是累计值、histogram 报均值。
118
118
  - 预算闸是 core 强制的:`maxCostUsd` pre-call 估算(没花钱就拒)+ 流中途取消 + turn 边界(`limits.max_cost_exceeded`);`maxTokens` 超 → `limits.max_tokens_exceeded`(core 5.8.0 起 `budget.*` 前缀退役)。**review 网关**建议设 `MAX_TASK_COST_USD` 防单任务烧掉共享云 key。
119
119
  - 🔴 **per-slice 窗 vs 跨片总额(别把前者当后者用)**:`MAX_TASK_TOKENS` / `MAX_TASK_COST_USD` / 任务墙钟都是 core 的
@@ -180,7 +180,7 @@ MODEL_ID=<your-model-name> MODEL_CHEAP_ID=<your-cheap-model-name>
180
180
  MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「任务没自带 systemPrompt」时跑编码提示
181
181
  ```
182
182
  - 经 `RoleSpec.systemPrompt` 挂在**角色**上,非开发角色保持中立、全局默认 `DEFAULT_SYSTEM_PROMPT` 不变;任务自带 `systemPrompt`(或客户端注入)时仍优先。
183
- - **验证门**(core 1.44,opt-in):请求体带 `verify:true`(可选 `verifyRounds`,夹到 [1,5]、默认 2)→ 任务跑完后由**独立只读对抗 verifier**(`verifier` 角色,默认=主模型)证据强制地"试图 break 它",FAIL 则把 findings 注回同 session 续跑修复→重验,循环到 PASS 或轮数上限。结果带 `verification:{verdict,rounds,findings,evidence}`(`verdict` 看质量,`result`/`status` 仍是实现的)。**仅 `/v1/tasks`(同步)与 `/v1/runs`(异步)**——`/v1/tasks/stream` 不支持(多轮非单流,请求 verify 会 400)。verifier 工具默认 = 实现任务工具滤掉 `effect:"write"`(只读边界)。`/metrics` 加 `verifications_total{verdict}`。⚠️ 同步 `/v1/tasks` 形**没有事件通道**(过程帧无处回放,只回终局 JSON)——带 `verify`/`cascade` 的 200 体自 7.23.0 起附可选 `notice` 键指路 `POST /v1/runs`(要过程可见性用异步形;[3979])。
183
+ - **验证门**(core 1.44,opt-in):请求体带 `verify:true`(可选 `verifyRounds`,夹到 [1,5]、默认 2)→ 任务跑完后由**独立只读 verifier**(`verifier` 角色,默认=主模型)证据强制地"试图 break 它",FAIL 则把 findings 注回同 session 续跑修复→重验,循环到 PASS 或轮数上限。结果带 `verification:{verdict,rounds,findings,evidence}`(`verdict` 看质量,`result`/`status` 仍是实现的)。**仅 `/v1/tasks`(同步)与 `/v1/runs`(异步)**——`/v1/tasks/stream` 不支持(多轮非单流,请求 verify 会 400)。verifier 工具默认 = 实现任务工具滤掉 `effect:"write"`(只读边界)。`/metrics` 加 `verifications_total{verdict}`。⚠️ 同步 `/v1/tasks` 形**没有事件通道**(过程帧无处回放,只回终局 JSON)——带 `verify`/`cascade` 的 200 体自 7.23.0 起附可选 `notice` 键指路 `POST /v1/runs`(要过程可见性用异步形;[3979])。
184
184
  - **记忆(design/138 文件记忆引擎,2026-07-08 起唯一记忆面)**:core 注入式文件引擎——任务开始时 materialize 记忆目录(`MEMORY_ENGINE_DIR`,默认 `~/.ai-agent`),模型用**普通文件技能**读写记忆(CC `# Memory` 指令 + 派生索引;无 remember/recall 工具),任务边界 harvest 门(secret/cap 扫描)提交。单用户默认开,`MEMORY_ENGINE=off` 显式关;多租户恒关(文件基座无租户隔离,fail-closed)。旧 SQL 记忆面(`MEMORY_BACKEND`/`EMBEDDING_*`/`MEMORY_READ_LIMIT`/去重/向量检索、`GET/DELETE /v1/memory` 与 session memory 写 verb)已退役,数据不迁移——升级后对库跑一次 `scripts/drop-memory-tables.sql`。`body.memoryWrite:false` 仍是每请求只读开关(harvest 不提交)。
185
185
  **`MEMORY_PERSISTENCE_CAPABLE`(三态,7.14.0 起)**=**部署自述**「本机能不能把用户的『记住 X』落到持久处」,与请求键 `memoryWrite` 两轴正交(后者收紧本次运行,前者是 operator 声明;任一取否即只读方向)。缺省不设=引擎按 roster 自行推断;`true`=本部署有推断看不见的持久通道(自定义 writer / 记忆 MCP / 远程执行车道与记忆根共享挂载);`false`=强制只读披露并关掉文件工具往记忆根的写通道。不认得的词拒启。
186
186
  🔴 **`false` 自 core 5.27.0(7.14.0 提货)起还多一层——但只在 file 记忆引擎上**(`MEMORY_ENGINE_BACKEND` 未设 = 默认单机形):该会话是**受限会话**——materialize/搜索/harvest 一律按**已提交账**供给,记忆根下无事务背书的磁盘分歧既不收编也不供给,而是留盘 + 响亮点名(`restricted_divergence`,本服务把它计进 `memory_harvest_rejections_total{code}` 并 warn 一条),等下一次**非受限**会话走正常门收编。合法流程不受影响:用户手改、`git pull` 落下的删除照旧(延后,不销毁),并发的可写会话提交的变更算有事务背书。
@@ -216,7 +216,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
216
216
  - **org 记忆准入(design/170 件A,7.0.0 起 BREAKING)**:`org:*` 记忆 scope 分**两个来源**——部署自证
217
217
  (env `MEMORY_SCOPE` 的 org 形 + **单用户部署**的 `projects[].defaultScopes` org 键)直通;**多租户**
218
218
  部署里由调用方 `projectId` 选中的登记簿 org 键算 **request 来源**,必须拿到授权目录的逐 principal
219
- 授予才准入,拿不到一律 fail-closed 拒(纯读泄露面:projectId 只过形状门不过授权)。目录源**三态单选,
219
+ 授予才准入,拿不到一律 fail-closed 拒(纯读外泄面:projectId 只过形状门不过授权)。目录源**三态单选,
220
220
  授权面不双源合并**:config-center 远程腿(per-principal `orgMemory` 段)> `MEMORY_ORG_DIRECTORY_JSON`
221
221
  静态表 > 缺席(request 来源的 org scope 恒拒)。同一个目录也是 `GET /v1/memory/export` /
222
222
  `POST /v1/memory/sync/:scope` 的 `org:` 属主门真源(写面另需条目 `write:true`);拒绝形 = 终局
@@ -230,6 +230,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
230
230
  | `MEMORY_ORG_UNAVAILABLE_BACKOFF_MS` | `10000`(`[500, 600000]`) | 目录取不到之后的退避窗(只用于取数失败臂,不用于负结果) |
231
231
  | `MEMORY_DELEGATION_EVIDENCE` | 缺省(=引擎自缺省 `static-face`) | **委派臂的证据标准**(core 5.45.0 design/324)。`static-face`=今日行为:委派的 attestation 缺失/未知**且**静态工具面够得着外部内容 ⇒ 标记本会话记忆为已污染(可能性即暴露)。`attested-only`=**只**豁免那一条静态面标记,且**真的豁免了一次**才响亮通告(`engine_notice` 的 `memory.delegation_static_mark_waived`,每个 prepared leg **至多**一次);送达 `external` attestation 照标、非委派的污染类工具照标、委派工具自身被分类为污染的照标。⚠️ 通告**不是 leg 计数器**:不含委派的 leg、污染面没挂载的 leg、送达了 attestation 的委派都不发 —— 看不到通告的常态含义是「没有可豁免的事」,不是「配置坏了」。坏值**启动期拒**。**部署席 only**(TaskSpec 无同名键,任务/受治脚本无法据此放松部署)。⚠️ **已接受的代价**:`attested-only` 下**后台**子代的真实外部接触不标记本会话(其内容经 TaskOutput / 任务通知注入 / AgentTranscript 摘要回流,三条都不带 attestation);异常收尾的前台子代同理。已标记的会话永不回滚清洗。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.delegationEvidence`(`null`=本部署未设,引擎自缺省) |
232
232
  | `MEMORY_PROVENANCE` | 缺省(=引擎自缺省 `carry`) | **记忆 provenance 总开关**(core 5.46.0 design/336 §13-3)。一个会话被判为**已暴露**之后,它的记忆写怎么处置。`carry`=引擎缺省:**普通**记忆写照常提交,但带上引擎铸的 `origin` 标记(随条目走后端/同步/导出包);指令形文件(feedback / pinned / triggers / applies-when)仍被扣下隔离;派生索引的会话散文照回滚;内容扫描门原样跑(**标记不是豁免**)。`off`=design/336 之前的行为:不铸 origin 标记,已暴露会话的 harvest **一条都不收**(整体隔离候人审)。⚠️ 已提交的标记在编辑时照样带下去 —— `off` 停的是**铸**,从不抹掉已记的事实。与 `MEMORY_DELEGATION_EVIDENCE` **正交**(四种组合全合法):那一键决定**什么时候**判会话为已暴露,本键决定判了之后**对写做什么**。坏值**启动期拒**(`OFF`/`false`/`none` 这类「看起来像关掉」的写法一律不折成缺省 —— 静默回默认 = 一台自认为「暴露会话零收录」的部署其实在照常收录)。**部署席 only**(TaskSpec 无同名键,任务/受治脚本无法据此改姿态);**不冻进 checkpoint**(resume 腿跟当前部署配置走)。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.provenance`(`null`=本部署未设,引擎自缺省) |
233
+ | `MEMORY_CAPTURE_POLICY` | 缺省(=引擎自缺省 `open`) | **记忆采集 opt-out 的部署姿态**(core 7.0.0 design/383 §3.1;server S-49/S-50)。任务可带 `memory.capture:"off"` 声明「本会话不进长期记忆」(一次性,resume 恒不采集,无反向拼写),本键决定怎么裁那条声明:`open`=按面值生效,**只有**该 principal 的显式 `false` verdict 拒(403 `memory.capture_optout_denied`),resolver 故障**放行**+披露(隐私轴 fail-safe:错拒=记了用户明说不要记的会话,不可逆);`governed`=verdict **必答**(混合车队:部分用户强制留存),故障/缺席**拒跑**(fail-closed);`capture-required`=全体声明拒(一行配置)。verdict 源 = SQL 店后端上的授权表 `memory_optout_grant`(三层折叠:per-principal 行 → 部署缺省行 → 代码缺省 allow;管理面 `GET|PUT /v1/admin/memory-optout`(PUT=部署缺省行)· `PUT|DELETE …/:principal`,operator-only,能力位 `memoryOptOutGrant`,零缓存写后即生效)。🔴 **`governed` 而无 SQL 后端 ⇒ 启动期拒启**(无源 = 每个声明都被拒且没人知道为什么;要么 `DB_BACKEND=mysql|pg` 要么改姿态)。坏值**启动期拒**(`Governed`/`required`/`off` 一律不折成缺省:两种姿态的故障极性**相反**)。**部署席 only**;**不冻进 checkpoint**。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.capturePolicy`(`null`=本部署未设)。⚠️ 远端车道(e2b/k8s)上 `capture:"off"` 本版恒 409 `config.memory_capture_unsupported`(core 的记录载体契约是同步签名,SQL 载体接不上;单机本地车道走 core 文件三件套照常生效)。用户面三口:提交键 `memoryCapture:"off"`(声明形)· `POST /v1/runs/:id/memory/capture-optout`(live 中途翻转,owner 门)· `POST /v1/sessions/:id/memory/erase`(所有者自助抹除,select 硬限本会话)。契约全文 `docs/ASSISTANT-WIRE-CONTRACT.md` §12 |
233
234
 
234
235
  ⚠️ **拒启动**:多租户 + 记忆面点亮 + `projects[].defaultScopes` 里有 org 键 + 目录源缺席 ⇒ 启动报错
235
236
  并点名 projectId(该部署的每个此类请求都会在 prepare 期整拒,响亮拒启动比静默全拒服务诚实)。
@@ -269,7 +270,7 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
269
270
  时落 `task_list_meta`/`task_list_item` 两表 ⇒ **跨副本、跨重启都续得上**;**没有 SQL 后端的形态
270
271
  (`local`/纯内存)清单只活在进程内 —— 重启即丢待办**(同时活跃会话超过 4096 时最老的会话清单被
271
272
  LRU 回收)。要跨重启保住待办就配 SQL 后端;这与该形态下其余会话态设施(per-session cwd 等)是同一
272
- 条边界,不为它伪造持久性。**删除权**:`DELETE /v1/sessions/:id` 与托管留存 sweep 两条腿都把清单
273
+ 条边界,不为它自造持久性。**删除权**:`DELETE /v1/sessions/:id` 与托管留存 sweep 两条腿都把清单
273
274
  行与编号高水位一并抹掉(同 anchors/附件/快照的级联)——会话 id 可被重新认领,残留就等于把上一位
274
275
  主人的任务标题与编号进度交给下一个化身。
275
276
  - 多实例边界:同一数据根同时只允许一个实例(BootLock 独占,第二个进程拒启;死主自愈含 SIGKILL)。
@@ -281,6 +282,21 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
281
282
  两进程共用 file 数据目录是禁止形,静默容忍比拒启更坏)。
282
283
  `DB_BACKEND=memory` 并非全无盘:workflow 相关账本仍挂数据根下——多个 memory 形引擎**不要共用**
283
284
  数据根/HOME(1.309 起并发 boot 不再拒启,但账本内容级共享仍不受支持)。
285
+ - **`RUN_STORE_STRICT_HYDRATE=on|off`(缺省 `off`)—— file 后端 run 账本的 fail-closed 启动门**:
286
+ `DB_BACKEND=local` 的 run 账本在 boot 时把 `<数据根>/runs/` 列一遍重建内存索引。那次 `readdir` 失败
287
+ (权限、挂载丢失、路径被换走)时**缺省行为是照常起动**,只留一行 `file_run_store_hydrate_unreadable`
288
+ 的 **error** 日志(带 runs 目录绝对路径 + 异常文案)与 `fail_open_total{tag="server.run-store.
289
+ file-hydrate-unreadable"}` 计数 —— 但那之后**每一次 `GET /v1/runs/:id` 都会 miss**,而「miss」在 wire
290
+ 上与「本来就没有这条 run」完全同形。把 run 账本当真账本用(对账、审计、外部系统按 taskId 回查)的
291
+ 部署可以设 `on`:此时那次失败**拒启**,遗言仍带绝对路径与异常文案,拒因给三条出路(修权限/挂载、
292
+ 把 `LOCAL_DATA_ROOT` 指到可读目录、或撤掉本旋钮按旧形起动)。
293
+ 值取 on/off 双族词表(`on|true|1|yes|enabled` / `off|false|0|no|disabled`,空串=未设);**两族都不
294
+ 认得的词一律拒启**——静默回默认会把一次明确的 fail-closed 表态无声吃掉。只有 file 后端读它。
295
+ ⚠️ 这条拒启**穿过**「裸 boot 的 local 存不了盘就退回内存」那条既有降级臂:开了这根旋钮就是要
296
+ fail-closed,被降级成内存等于把它翻译成 fail-open(而且丢的正是持久 run 账本)。
297
+ 射程 = boot 期的**全部盘面**:`runs/`+`runs/active/` 的建目录、两次目录列举,加上逐个
298
+ `run.json` / `events.jsonl` / claim 文件的读取。目录里本来就没有的东西(`.DS_Store` 一类杂物、
299
+ 尚未落盘的目录)照旧跳过 —— 拒的是「读不出来」,不是「没有」。
284
300
 
285
301
  **监听绑址(1.306+,[1934])—— 桌面/单机形请注意**
286
302
  - `BIND_HOST` = 监听地址;显式设置**恒生效**(要在无鉴权下对外暴露,显式写 `BIND_HOST=0.0.0.0` 即可)。
@@ -291,14 +307,15 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
291
307
  `REMOTE_EXEC=host`(用户真机、非沙箱),绑全接口=同网段任何人可无鉴权提交任务并执行。
292
308
  - 配了凭证的部署(云形/k8s/compose)缺省**不变**(全接口),既有部署零影响。
293
309
 
294
- **workspace 浏览面(1.299+,#3)—— 任务产出的浏览/预览/打包下载**
295
- - 四只读端点(owner 门=session 面同款;`:key=latest`=最新快照):
296
- `GET /v1/sessions/:id/workspace`(列快照)/ `…/workspace/:key/tree`(文件树,`{path,hash,size?}`)/
297
- `…/workspace/:key/file?path=`(单文件预览,≤`WORKSPACE_FILE_MAX_BYTES` 默认 8MiB,超限 413
298
- `workspace_file_too_large` 信封带 `{sizeBytes,limit}`)/ `…/workspace/:key/archive`(流式 tar 下载)。
299
- - 建在 E19 快照店上(引擎每轮自动快照工作树)——零新存储;无快照店(rewindFiles 未接线)=501,
300
- 探测 `capabilities.workspace`(对象=`{browse,archive,maxFileBytes}`/`false`)。看的是**每轮结束的
301
- 定格**,不是运行中的活工作区(实时浏览=v2 另立)
310
+ **workspace 浏览面 —— 已随整树快照纪元退役(S-15/design/381)**
311
+ - 旧四端点(list/tree/file/archive)恒 `501 capability.workspace_retired`,`capabilities.workspace`
312
+ `false`。理由:rewind 换代为 per-file 历史(只备份代理**编辑过**的文件,无树遍历、无体积门),
313
+ 结构上不再存在「整个工作区」的 manifest 可投影;把 tracked-set 呈成 workspace 是语义谎。
314
+ - `WORKSPACE_FILE_MAX_BYTES` 随面转 INERT(值仍收下并校验,center 推送兼容;不再有任何效果)。
315
+ - rewind 的新姿势:提交带 `resumeAt` + `restoreFiles: true`( code-only 的 `rewindFilesTo`)
316
+ 引擎把**本会话跟踪集**收敛到该消息时刻的边界;`acceptPartialRestore: true` 容忍部分恢复
317
+ (缺省=响亮失败带逐文件账本)。旧键 `rewindFiles` 的 capture 义=容忍 no-op(首触跟踪恒开),
318
+ restore 义(与 resumeAt 同发)=typed 拒并指路 `restoreFiles`(迁移显式化是 core 裁定)。
302
319
 
303
320
  **可选 — SendUserFile 文件直链(把沙箱/主机里的文件发给用户,S3/MinIO 双轨)**
304
321
  ```bash
@@ -315,6 +332,7 @@ SEND_USER_FILE_SANDBOX_PUT_ENDPOINT=… # 可选:沙箱直传 PUT 的端
315
332
  ```
316
333
  - **词表优先级**:内网端点 `MINIO_ENDPOINT` 优先,`S3_ENDPOINT` 是外接 S3 兼容位(内网/公网同址场景可只给它,同时充当公网面);公网端点 `S3_PUBLIC_ENDPOINT` 优先,缺席回落 `S3_ENDPOINT`。空串一律按未设处理。
317
334
  - **🔴 云形(`DB_BACKEND=mysql|pg`)快照 blob 强制对象存储(1.295+,clay 拍)**:缺 MinIO 三键 ⇒ **boot 拒启**——单行 SQL blob 写会撞 TiDB `txn-entry-size-limit`(默认 6MiB,真库实测矮墙)/ mysql 协议 `max_allowed_packet`,大字节归对象存储(与 D-1 附件面同裁定)。单机/测试台显式逃生:`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true`(SQL 店此时带 per-blob 帽,tidb 默认 6MiB,超限 PUT 413 `blob_too_large_for_sql`;帽可用 `SNAPSHOT_BLOB_SQL_MAX_BYTES` 按部署真实限值覆写,两方言生效;pg 默认无帽)。
335
+ - **per-file rewind 历史的边界上限(S-15 twin 保留条款,core design/381 §片2)**:`FILE_HISTORY_RETENTION_KEEP` —— 每个 scope(会话)存活的**最新** boundary 数,**每次 boundary 提交后自剪**(最旧者先亡,刚提交者恒存活;失引用的版本行级联删,blob 字节走异步 grace 窗 GC;v1 基线永存)。未设=core 缺省 **100**(由 core 的 `resolveFileHistoryRetention` 兑现,server 不复制那个数);`unbounded` 是**唯一**的「不剪」拼法(整店自剪关闭,GC 归部署自排 `reap`);`0`/负数/小数/非数 ⇒ **boot 拒启**(码 `config.retention_policy_invalid`,与 core 内置后端同码同判——**省略这个键不等于不剪**,它选的是缺省 100)。三条车道(TiDB / PG / local 文件店)同旋钮同判。⚠️ 升级即生效:存量超 100 boundary 的 scope 在下一次提交时被剪到 100;要保全量先写 `unbounded`。被剪 entry 的键**已花掉**(再次 snapshot 同 entry 典型拒,不复铸)。排序=DB 分配的 per-scope 发布序号 `file_history_boundary.publish_seq`(不是墙钟):**自 7.50.x 有存量 `file_history_boundary` 的部署升级本版会在 boot 期被 `assertFileHistorySchema` 拒启并指明 `DROP TABLE file_history_boundary`**(本仓无 ALTER;丢的是 per-file rewind 便利态,会话与其他持久面不动)。
318
336
  - **🔴 公桶策略必须 GetObject-only**:`mc anonymous set download` 会**连带打开 ListBucket**——匿名 `GET /<bucket>/?list-type=2` 能枚举全部不可猜 key,能力链接设计即告失效。正确姿势=`mc anonymous set-json`,policy 只含 `Action:["s3:GetObject"]` on `arn:aws:s3:::<bucket>/*`(验证:对象 GET 200、桶 LIST 403)。
319
337
  - **两条轨**:ttl=0(默认)→ 匿名 GET 公桶下 `uuidv7/<name>` 不可猜 key,链接永久、可回收(删对象);0<ttl≤7 天 → 私桶 + SigV4 限时签名链接(7 天是 SigV4 物理上限,更久用 ttl=0)。
320
338
  - **执行 lane 与租户门**:e2b/k8s 沙箱 lane 任意租户可用(沙箱文件系统=租户边界,沙箱内 `curl -T` 直传、字节不中转、凭据不进沙箱);host/ssh lane 仅单用户部署(`REQUIRE_PRINCIPAL` 未开)时挂载。
@@ -344,7 +362,7 @@ FLEET_ADVERTISE_ADDRESS=http://<本机可达IP>:8090 # 可选:设了才启 flee
344
362
 
345
363
  生效与否的观测口=`/health` 世代账键(`configTargetVersion`/`configAppliedVersion`+两 ordinal+`configApplyStaleMs`,见 API 表 `/health` 行)——target≠applied 持续=「改了没生效」的机读信号。
346
364
  - **仅 `/v1/tasks`(同步)+ `/v1/runs`(异步)**——`/v1/tasks/stream` 不支持(多次尝试非单流,400)。与 `verify` **互斥**(同时给 → 400)。
347
- - 成本上界 = 任务的 `maxCostUsd`(防冷重跑税)。**三条 core 警示**:① 每档**冷重跑**重付输入成本(便宜档常过才划算);② 门收到**未脱敏**输出(自定义门转发外部 verifier 要脱敏);③ **写工具会跑 N 次**——**只用于只读/幂等任务**(每次升级整任务重跑)。开放式任务(找全 bug/文笔)没有可判定 oracle、级联会空转,那种用 `discuss`(广度对抗)而非级联(深度阶梯)。
365
+ - 成本上界 = 任务的 `maxCostUsd`(防冷重跑税)。**三条 core 警示**:① 每档**冷重跑**重付输入成本(便宜档常过才划算);② 门收到**未脱敏**输出(自定义门转发外部 verifier 要脱敏);③ **写工具会跑 N 次**——**只用于只读/幂等任务**(每次升级整任务重跑)。开放式任务(找全 bug/文笔)没有可判定 oracle、级联会空转,那种用 `discuss`(广度交叉)而非级联(深度阶梯)。
348
366
 
349
367
  **可选 — AskUserQuestion 的裁量窗(问活人的三个帽子)**
350
368
  ```bash
@@ -358,6 +376,21 @@ QUESTION_TTL_MS=300000
358
376
  - 三个值都有出厂缺省(即上面写的值),**不设=行为不变**;越界值**启动期响亮拒**(不静默夹取)。
359
377
  - 窗用尽 / 到期 **不是替人作答**:服务只报「此刻无人可答」,落点由引擎选——**durable 部署**(`DURABLE_APPROVAL=true` 且这条腿没有活的流)把问题 **park** 成待办,运维随后经审批面带答案补答;**无 durable 的部署**则让模型被告知"没人在"后按自己的判断继续(run 永不挂死)。
360
378
  - 想让人有更长时间答就调大 `QUESTION_TTL_MS`;想让 agent 少打扰人就调小 `QUESTION_MAX_TOTAL_PER_RUN`。
379
+ - 🔴 **`/v1/tasks/stream` 的开帧投递失败是响亮的(逐腿,不是部署级)**:这条腿(**且仅这条腿**)向引擎
380
+ 声明 `interactionPosture: "interactive"` —— 人就在这条 SSE 上,一次开帧投递失败(壳断连/流被撕裂)
381
+ 不再合成「没有人可问,你自己判」的续跑卡,而是让那次工具调用返回 coded 失败
382
+ `question.human_unavailable`。**其余每一条腿行为字节不变**:`/v1/tasks`(非流)、`/v1/runs`、A2A、
383
+ resume、cron / wake、`verify` / `cascade` 一律**不声明** ⇒ 续跑 + 披露卡 + 既有计数照旧
384
+ (那些腿本来就没人可问,拒掉它们只会把无人值守任务打死)。
385
+ 声明本身有前提:活体问答面与活体审批席**两个席位都在**、且调用方没有把 `interactiveTools` 声明成
386
+ `false` —— 缺任何一项就不声明(引擎的 posture 门是**拒整条腿**的,声明一个够不着人的姿态会让每个
387
+ 任务在准备阶段当场失败)。**发了 `x-detach-on-disconnect: true` 的请求同样不声明** —— 那个头逐字是
388
+ 「我可能随时走开,别杀 run」,正是 interactive 的反面。
389
+ ⚠️ **射程如实**:引擎的姿态解析是三腿的,**从这条腿委派出去的子代会继承根腿的姿态**(引擎的设计,
390
+ 宿主覆盖不了;语义自洽——子代的提问浮到的正是同一条流上的同一个人)。所以「无人腿不受影响」说的是
391
+ 以无人腿**提交**的 run,不是「任何后台工作」。
392
+ 要在活流腿上保留旧的自答续跑行为,目前的办法是把该请求改走 `/v1/tasks`(非流)或 `/v1/runs`,
393
+ 或带上 `x-detach-on-disconnect: true`。
361
394
 
362
395
  **流内审批协议(`approval_request` 帧族,design/172)—— 总开关 + 九个调优钮**
363
396
 
@@ -394,14 +427,32 @@ STREAM_APPROVAL_ADHOC_GRACE_MS=60000
394
427
  # 单机交互形推荐调低到 172800000(48h):一张卡挂两天没人批在单机上基本等于死卡,7d 默认是按
395
428
  # 多副本云形定的;调低让 resume 对账少扫陈年行([3899]④/[3900] 线,clay 裁=文档推荐不改全局默认)
396
429
  STREAM_APPROVAL_ORPHAN_TTL_MS=604800000
430
+ # 案A(7.52.0):**零活流铸造**的 ask 的悬挂窗(毫秒,默认 3600000=1h,有界 [60000, 86400000=24h])。
431
+ # 只作用于「到达时该 (owner, session) 下一条活 SSE 都没有」的那一类 —— 典型是 workflow 子代 ask
432
+ # (workflow 恒后台跑,人不在场);S-52 起 bg 提交腿(POST /v1/runs)与 resume 腿的委派子代 ask 同席
433
+ # (此前那两条腿结构性无席位,恒即拒,连本窗都够不着)。此前那一刻即答「无人可答」⇒ 整条命令死拒;现在它照常落一条
434
+ # STREAM_PENDING 行等人,人经 GET /v1/approvals / 壳队列 / 重连开流补投三条通道回来答,答完子代原地续跑;
435
+ # 窗满才走既有 park/deny 出路。**有活流的 ask 一毫秒不受影响**(仍是 STREAM_ASK_WINDOW_MS)。
436
+ # 调小 = 更接近旧行为(积压更少、但人来晚了就赶不上);UNATTENDED_APPROVAL_POLICY=deny 的部署完全不受
437
+ # 本键影响(那台机器上零活流的 ask 仍是当场拒,不挂窗、不占配额)。
438
+ UNREACHED_ASK_TTL_MS=3600000
397
439
  ```
398
440
  - **坏形一律启动期炸,不静默折默认**:五个 `numEnv` 键(`STREAM_ASK_WINDOW_MS` / `STREAM_ASK_WINDOW_MARGIN_MS` /
399
- `STREAM_APPROVAL_REPLAY_MAX` / 两个 `ADMIT_MAX_*`)非数字即拒启;四个收敛器键额外**有界**,越界拒启
400
- (不夹取);`STREAM_APPROVAL_RECONCILE_BATCH` 再加一道整数门(`200.5` 会一路走到 SQL `LIMIT` 上)。
441
+ `STREAM_APPROVAL_REPLAY_MAX` / 两个 `ADMIT_MAX_*`)非数字即拒启;四个收敛器键 + `UNREACHED_ASK_TTL_MS`
442
+ 额外**有界**,越界拒启(不夹取);`STREAM_APPROVAL_RECONCILE_BATCH` 再加一道整数门(`200.5` 会一路走到
443
+ SQL `LIMIT` 上)。
401
444
  - **🔴 跨旋钮不变量**:`STREAM_ASK_WINDOW_MS + STREAM_APPROVAL_ADHOC_GRACE_MS` 必须**严格小于**
402
445
  `STREAM_APPROVAL_ORPHAN_TTL_MS`,否则**拒启**并点名。理由是归因诚实:adhoc 判据在
403
446
  `(创建 + 窗 + 宽限)` 触发、遗孤兜底在 `(创建 + TTL)` 触发,兜底若先到,每条 adhoc 腿都会被记成
404
447
  `orphan_ttl_exceeded`(「遗孤」)而不是 `adhoc_leg_no_durable_domain`(「结构上无对账域」),审计面从此读不出真成因。
448
+ **同一条不变量对悬挂窗再判一次**(7.52.0 案A):`UNREACHED_ASK_TTL_MS + STREAM_APPROVAL_ADHOC_GRACE_MS`
449
+ 同样必须严格小于 `STREAM_APPROVAL_ORPHAN_TTL_MS`(悬挂行的 `expiresAtMs ≈ 创建 + 悬挂窗)。两条分开判
450
+ 是为了让拒启文案点得出**是哪一个键**破了不等式;默认值(1h + 60s vs 7d)自然满足。
451
+ ⚠️ 悬挂窗这一条**不是无条件**:门挂在「这台部署会不会铸出悬挂行」上,三形豁免(配置期可知)——
452
+ `STREAM_APPROVAL_ENABLED=false`(协议不上场,零 ask 行)、`TOOL_APPROVAL_ENABLED=false`(协调器不构造,
453
+ core 走 headless 缺省,零 ask 行)、`UNATTENDED_APPROVAL_POLICY=deny`(零活流的 ask 铸造时刻即拒,
454
+ 悬挂路径结构上不可达)。三形下该键即使与短 orphan TTL 组合也照常起服 —— 一批从未选择本能力的既有
455
+ 部署不因升级引入的 1h 缺省当场拒启。上一条(`STREAM_ASK_WINDOW_MS` 版)保持**无条件**,与既有行为逐字一致。
405
456
  - **断连时活卡怎么办(#245/[3777] 成文)**:客户端**优雅断开**(server 收到 socket close)时,流内未决 ask
406
457
  立即强转 durable park(7.16.0 #241),恢复后 attach 重放会重呈卡。客户端**网络中断**(TCP half-open,
407
458
  server 侧 close 事件不触发)是已知盲窗:SSE heartbeat 帧只会堆进 TCP 重传队列,server 要等 OS 级重传
@@ -665,7 +716,7 @@ ENGINE_LINGER_MS=60000 # 可选,默认 60s,下界 1000
665
716
  | `sessionId` | — | 续聊:带上次返回的 `sessionId`,服务端自动 wake 历史 |
666
717
  | `images` | — | 图文输入 `[{data,mimeType}|{url}]`(模型需支持 vision) |
667
718
  | `attachmentIds` | — | D-1 通用文件上传(1.289+):先 `POST /v1/attachments?name=…`(raw body,content-type=mime)拿句柄,提交时引用 ≤16 个;文件物化到执行环境工作目录 `attachments/` 下,objective 尾部自动追加文件清单(内容不进会话流)。单文件缺省 ≤32 MiB(`ATTACHMENT_MAX_BYTES`);可配 mime 白名单(`ATTACHMENT_MIME_ALLOWLIST` CSV,缺省不限);上传后未引用的按 `ATTACHMENT_UNBOUND_TTL_MS`(缺省 24h)回收。**云形态(tidb/pg)字节本体存对象存储——MinIO 必配**(`MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY`,与快照 lane 同一组变量),未配则附件面 501;local 形走本地文件店。 |
668
- | `scenario` | — | `default`(默认)/ `code-review`(见 §5)/ `scan`(同 §5 的 repo 只读工具但**中性无框架提示词**——objective+中心下发 skill 全权主导输出,OA 扫描类用;与 `code-review`/`discuss` 同属 clone-free 无执行环境场景,见 §5 末)/ **配置控制面可声明任意新场景**(`{name, toolset: none\|repo-readonly, prompt?}`,组合即配置、能力钉死在部署;restart-to-apply;center 可覆盖内建名,boot 日志 `config_center_scenarios.shadowsBuiltin` 可审计) |
719
+ | `scenario` | — | `default`(默认)/ `code-review`(见 §5)/ `scan`(同 §5 的 repo 只读工具但**中性无框架提示词**——objective+中心下发 skill 全权主导输出,OA 扫描类用;与 `code-review`/`discuss` 同属 clone-free 无执行环境场景,见 §5 末)/ **配置控制面可声明任意新场景**(`{name, toolset: none\|repo-readonly, prompt?}`,组合即配置、能力写死在部署;restart-to-apply;center 可覆盖内建名,boot 日志 `config_center_scenarios.shadowsBuiltin` 可审计) |
669
720
  | `repo` / `council` / `debate` | — | `repo` 为 `code-review`/`scan` 必填;`council`/`debate` 仅 `code-review`,见 §5 |
670
721
  | ~~model / tools / prompt~~ | 🚫 | **不接受**——服务端注入 |
671
722
 
@@ -778,7 +829,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
778
829
  | `GET /v1/sessions/<id>` | 审计回溯:当前上下文 + 摘要(owner 校验) |
779
830
  | `GET /v1/approvals?owner=user:42` | 高危写审批(durable,需 `DURABLE_APPROVAL=true`):**operator** 看待办队列(可按 owner 过滤);非 operator 只看自己的 |
780
831
  | `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
781
- | `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** service-token/单用户形;带 principal 的调用方钉死自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
832
+ | `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** service-token/单用户形;带 principal 的调用方锁定自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
782
833
  | `GET /v1/capabilities/scenarios/<name>` | 单个场景的只读详情:工具面、提示词概览、**本部署现在跑不跑得动**(见下) |
783
834
  | `POST /v1/admin/drain` `{"reason":"…"}` | **停机因由显式声明**(7.35.0+;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 = 谁都不是 operator ⇒ 恒 403)。编排壳在发 SIGTERM **之前**调它;server 记进程内 `drainState.reason`,draining 期由 `/health` 的 `drainReason` 与 503 `draining` 体的 `reason` 透出(未声明 = 两面键缺席)。声明是**覆盖式**、无 TTL、随进程重启清零 ⇒ 每次停机流程内都要重新声明。`reason` 非空、trim 后 ≤256 字符,坏值 400。🔴 **写口是特权的,读口不是**:`/health` 免鉴权(见下一行)且缺省全网卡监听 —— 任何能连到这个端口的人都读得到你写的那句话。**别在 reason 里写工单号、内部主机名或任何内部标识**。 |
784
835
  | `POST /v1/admin/config/refresh` | **配置手动刷新**(#322 批1;operator-only,与上一行同门:空 `OPERATOR_PRINCIPALS` ⇒ 恒 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
@@ -793,7 +844,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
793
844
  > 两面共用同一份判据,所以列表上画得出的场景点下去不会再突然 501。请按 `unavailableReason` 的**键**分支,
794
845
  > 不要去匹配英文文案——文案会改,键不会(新增取值只会追加,现役键不改语义)。
795
846
 
796
- > **operator 鉴权(审批队列)**:`OPERATOR_PRINCIPALS=ops:alice,ops:bob`(CSV)= 谁能当 operator——列任意 owner 待办 + 决议(批/否)。**单租户部署不设=旧行为**(握 service token 即 operator,向后兼容);设了之后,非名单 principal 列待办只看自己的、且**不能决议**(403,防"请求方批自己的高危操作"绕过 F4 闸)。⚠️ **多租户形拒启**(#157-①):`DURABLE_APPROVAL=true` + `REQUIRE_PRINCIPAL=true` 而 `OPERATOR_PRINCIPALS` 空 ⇒ 进程启动失败并点名修法——否则空名单会让任一已验证租户读到其他租户的待批队列(读面 true-for-all)。设名单,或确属单租户则不设 `REQUIRE_PRINCIPAL`。
847
+ > **operator 鉴权(审批队列)**:`OPERATOR_PRINCIPALS=ops:alice,ops:bob`(CSV)= 谁能当 operator——列任意 owner 待办 + 决议(批/否)。**单租户部署不设=旧行为**(握 service token 即 operator,向后兼容);设了之后,非名单 principal 列待办只看自己的、且**不能决议**(403,防"请求方批自己的高危操作"跳过 F4 闸)。⚠️ **多租户形拒启**(#157-①):`DURABLE_APPROVAL=true` + `REQUIRE_PRINCIPAL=true` 而 `OPERATOR_PRINCIPALS` 空 ⇒ 进程启动失败并点名修法——否则空名单会让任一已验证租户读到其他租户的待批队列(读面 true-for-all)。设名单,或确属单租户则不设 `REQUIRE_PRINCIPAL`。
797
848
  >
798
849
  > **部署治理三声明(7.21.0 起,design/170 件B/C/D)**——三根都是**配置期**旋钮,「谁能改它们」≡「谁能改
799
850
  > 部署配置」,不引入新鉴权面;三根**都不设 = 现行为逐字不变**,坏值一律**拒启**(安全轴上的旋钮不静默失效)。
@@ -833,6 +884,13 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
833
884
  > 且**状态变更与审计行同一个事务**(不存在"解冻了但账上没有")。
834
885
  > - `GET /v1/ops/retention/audit?domain=&limit=&before=` —— 审计读面(keyset 分页,游标形同名册面)。
835
886
  > - 能力位 `capabilities.retention` = `{mode, maxAgeDays}`(lane 开着)或 `null`(关着)。
887
+ > - **子代转录(placed 分区)的留存天数没有独立旋钮座**(S-03/#292②,设计判定 2026-08-30):placed 转录的
888
+ > 删除权**独家**归联合 reap(`reapDurableAgents`:行赢删才 release 转录;上面这条 lane 的候选谓词显式排除
889
+ > placed,见 `plugins/retention-store-sql.ts` 第五腿)——生效视界 = `BG_AGENT_RETENTION_MS`(缺省 7 天,
890
+ > 毫秒形,同时是 agent 行的留存旋钮;分区孤儿腿的 `olderThanMs` 同源)。core 的
891
+ > `SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT`(30 天)是共享词表常量,**本服务未按它跑**;天数形专用
892
+ > 旋钮要等 core 在 reap policy 开出转录独立年龄座后再铸(届时名 `SUBAGENT_TRANSCRIPT_RETENTION_DAYS`)。
893
+ > 生效值上 boot 日志:`wiring_static.subagentTranscriptRetentionMs`。
836
894
  > - `MEMORY_CONSOLIDATION_DRIVER=on|off`(默认 `off`):记忆**折叠(consolidation)阀门**。一个从未折叠过的
837
895
  > 记忆库只涨不折,检索质量随库龄衰减;开这根旋钮就给 worker 装上两个 operator 口,让人在自己选的节奏上
838
896
  > 跑折叠。⚠️ **闭集两词,别的一律拒启**——本旋钮是新的,不继承 `MEMORY_ENGINE` 的 `true/1/yes` 放宽:
@@ -1061,12 +1119,28 @@ tag 词表与每条的最坏后果见 `docs/FAIL-OPEN-CENSUS.md`。
1061
1119
  `source:"limit_approach"`)。批处理场景嫌噪声:`limits:{approachNotice:false}` 关闭;调阈:
1062
1120
  `limits:{approachNotice:{at:[0.5,0.9]}}`(两分数 (0,1] 且 r1<=r2,相等合法;坏形 400 点名)。
1063
1121
 
1064
- ### 9.2 部署级 token 治理窗(USAGE_WINDOWS,6.1.0 )
1122
+ ### 9.1b total_tokens 余量提醒帧(RB-318,缺省翻面 —— core 5.65 系起)
1065
1123
 
1066
- 跨任务的滑动 token 预算(core `usageWindows`),缺省不设=关。单键 JSON 数组:
1124
+ 声明了 token 上限(`limits.maxTokens` 或资源切片余量)的任务,**每个带工具调用的边界**现在会多一行
1125
+ CC 逐字节形的提醒帧:`<total_tokens>N tokens left</total_tokens>`(**缺省 ON**;此前需显式 opt-in)。
1126
+ - **谁受影响**:声明了 token 上限的部署——模型看得见余量倒数;未声明上限的任务**恒静默**(core 只发布
1127
+ 它已在强制执行的那道上限,不猜上下文窗)。
1128
+ - **退出旋钮**:提交体 `attachments: { totalTokensReminder: false }`;档位经
1129
+ `attachments.totalTokensReminderMode`(`off`/`infinite`/`fixed`/`countdown`/`padded-countdown`,
1130
+ 缺省 padded-countdown;词表外值 400 拒不折默认)。
1131
+ - **分辨依据**(消费端/日志过滤):该帧内文**恒以 ` tokens left` 结尾**;`Infinite` 常量臂(`infinite`
1132
+ 档)是唯一例外,单独放行——它不带数字、不依赖上限,且只在显式 `true` 下可达。
1133
+
1134
+ ### 9.2 部署级治理窗(USAGE_WINDOWS,6.1.0 起;$ ceiling=S-18/core 7.0.0 起)
1135
+
1136
+ 跨任务的滑动预算(core `usageWindows`),缺省不设=关。单键 JSON 数组;每窗两只**独立** ceiling
1137
+ (`maxTokens` token 数 / `maxCostUsd` 绝对美元)——each optional、**至少其一**(双缺拒启),
1138
+ whichever fills first 即耗尽,缺席的 ceiling 不参与(非 0、非 ∞):
1067
1139
 
1068
1140
  ```bash
1069
1141
  USAGE_WINDOWS='[{"windowMs":18000000,"maxTokens":5000000,"anchor":"first-use"}]' # 5h 窗 500 万 token
1142
+ USAGE_WINDOWS='[{"windowMs":604800000,"maxCostUsd":25,"anchor":"rolling"}]' # 7d 滑动窗 $25(纯 $ 窗合法)
1143
+ USAGE_WINDOWS='[{"windowMs":18000000,"maxTokens":5000000,"maxCostUsd":10,"anchor":"first-use"}]' # 双 ceiling:先满者停
1070
1144
  # anchor:"first-use"=首次消费开桶、到期重开;"rolling"=滑动窗(最近 windowMs 内的消费之和)
1071
1145
  ```
1072
1146
 
@@ -1077,8 +1151,13 @@ USAGE_WINDOWS='[{"windowMs":18000000,"maxTokens":5000000,"anchor":"first-use"}]'
1077
1151
  任务撞窗时,基建合格(checkpoint+durable approval)⇒ suspend(reason `usage_window`)等窗放行,
1078
1152
  不合格 ⇒ 响亮失败同码落终态记录。
1079
1153
  - 计量覆盖:主任务、具名/委托 subagent、hook 内部任务全计(部署真花销都进窗)。
1080
- - 坏形 `USAGE_WINDOWS` 拒启(fail-loud 点名第几项);**改窗形≈重开账**(first-use 桶按 windowMs
1081
- 配对,改了窗长老桶下次记账即弃)。
1154
+ - **$ (S-18,core 7.0.0 起)**:`maxCostUsd` 要求 run **可计价**——模型既无 pricing 条目也无
1155
+ `Model.cost` 声明时,cost 不是 0 而是**不存在**,$ 窗对它不可求值 ⇒ 任务门口拒
1156
+ (`config.usage_window_unpriced`),绝不记 0 让天花板静默失效。MIXED 声明(部署里同时有 $ 窗与纯
1157
+ token 窗)下共享账本行统一携带 cost;全部署零 $ 窗时账本行与此前逐字节同形。
1158
+ - 坏形 `USAGE_WINDOWS` 拒启(fail-loud 点名第几项);窗对象是**闭集**四键 {windowMs, maxTokens?,
1159
+ maxCostUsd?, anchor}——未知键(含拼错的 `maxCostUSD`)拒启点名,绝不静默降级成 token-only 治理;
1160
+ **改窗形≈重开账**(first-use 桶按 windowMs 配对,改了窗长老桶下次记账即弃)。
1082
1161
  - 存储:SQL 后端=跨副本一致(`usage_window` 表,行锁守恒);local=文件;纯内存 dev=进程内。
1083
1162
 
1084
1163
  ### 9.3 沙箱寿命声明(6.1.0 起)
@@ -19,7 +19,7 @@ export type IdentityEncoding = "verbatim" | "memory-scope" | "rule-owner-key";
19
19
  * 同族)。与那条腿的差别:桶键**不含**任何逐行变量(只有 principal),所以不必逐行扫出来重算 ——
20
20
  * 一对 (fromKey, toKey) 算一次,一条等值 UPDATE 走完全表。
21
21
  *
22
- * 🔴 `blob-rewrite` 为什么必须存在(codex 对抗复审 R1-F2,亲核属实):本仓有三张表的 JSON 载荷是**真源**,
22
+ * 🔴 `blob-rewrite` 为什么必须存在(codex 交叉复审 R1-F2,亲核属实):本仓有三张表的 JSON 载荷是**真源**,
23
23
  * 身份列只是它的投影,而读面读的是载荷:
24
24
  * · `workflow_run.run` —— `get()` 是 `JSON.parse(run)` 且**只**覆盖 `rev`(store 行内注写死),
25
25
  * 所以只改 `scope` 列的话 `get().scope` 仍是旧身份;调用方把它回传给 scope-guarded 的 `update()`
@@ -44,7 +44,7 @@ export interface BlobRewriteSpec {
44
44
  * 该表自己的乐观并发守卫列(三张载荷表都有 `rev`)。
45
45
  *
46
46
  * 🔴 为什么必须绑它(codex R2-F1,亲核属实):载荷改写是「读-改-写」,中间那道窗里若有一次正常业务写
47
- * 提交,盲写会把它**整条盖掉** —— 而这三张表的正常写路径本来都是 rev-CAS 守着的,收编凭什么可以绕过?
47
+ * 提交,盲写会把它**整条盖掉** —— 而这三张表的正常写路径本来都是 rev-CAS 守着的,收编凭什么可以跳过?
48
48
  * 绑上之后:`affected === 0` ⇒ 有人在窗里动过这一行 ⇒ **响亮抛**,整个事务回滚(两侧字节零变更),
49
49
  * 而不是静默丢一次别人的写。
50
50
  */
@@ -90,7 +90,7 @@ export declare const REBIND_LEGS: readonly RebindLegSpec[];
90
90
  * rate_limit),窗口语义与身份绑在一起搬过去要跨窗口对齐,复杂度与价值不成比例;清零重计的代价是
91
91
  * 新身份在当前窗口拿到一份新额度 —— 一次性部署级动作里这是可接受的,而且**方向偏松不偏紧**,
92
92
  * 不会把人锁在门外。
93
- * 🔴 D2 三员为什么不改:它们是**谁在什么时候做了什么**的史实字段。改写史实 = 伪造审计。
93
+ * 🔴 D2 三员为什么不改:它们是**谁在什么时候做了什么**的史实字段。改写史实 = 自造审计。
94
94
  */
95
95
  /**
96
96
  * 🔴 本数组的成员集合必须与 {@link NOT_MIGRATED_FACES}(冻结词表)**全等** —— 词表说有而这里没有
@@ -112,7 +112,7 @@ export interface ConfigTemplate {
112
112
  }
113
113
  export declare const AFFECTED_CONFIG_TEMPLATES: readonly ConfigTemplate[];
114
114
  /**
115
- * 目的地身份值的**列宽约束**(codex 对抗复审 R1-F3,亲核属实)。
115
+ * 目的地身份值的**列宽约束**(codex 交叉复审 R1-F3,亲核属实)。
116
116
  *
117
117
  * 🔴 病:请求面收 ≤190 字符的 principal,而迁移腿要把它写进**最窄**只有 `VARCHAR(64)` 的列
118
118
  * (`sandbox_image_index.tenant_id`),两根键列还是 `VARBINARY(190)`(**字节**,不是字符),memory scope
@@ -311,6 +311,17 @@ export const REBIND_LEGS = [
311
311
  residualKey: [],
312
312
  why: "记忆盘游标(每 scope 一行)",
313
313
  },
314
+ {
315
+ leg: "memory_optout_grant#principal",
316
+ table: "memory_optout_grant",
317
+ kind: "bulk-rebind",
318
+ action: "row-rewrite",
319
+ columns: ["principal"],
320
+ matchColumn: "principal",
321
+ encoding: "verbatim",
322
+ residualKey: [],
323
+ why: "记忆采集 opt-out 授权行(每 principal 一行;design/383 S-2)—— 不迁 = 收编后新身份丢自己的 verdict 覆盖",
324
+ },
314
325
  {
315
326
  leg: "agent_memory_engine_sync_cursor#scope",
316
327
  table: "agent_memory_engine_sync_cursor",
@@ -74,7 +74,7 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
74
74
  * {@link RuleOfferSchema} 的**不限长**孪生 —— 只判**结构**(闭词表 `kind`/`match` + 若干字符串),长度由
75
75
  * 调用方在**脱敏之后**自己截。
76
76
  *
77
- * 🔴 为什么必须有它(codex 对抗复审 [medium],验真后修):`redactSecrets` **会变长**(一条
77
+ * 🔴 为什么必须有它(codex 交叉复审 [medium],验真后修):`redactSecrets` **会变长**(一条
78
78
  * `password=…` 换成更长的遮蔽标记)。拿带 `.max()` 的形去校验**脱敏前**的原文,再脱敏,产出的就可能是
79
79
  * 一条超限的文本;而任何**回读**路径若再跑一遍同一个函数,那一条会在第二次校验时被整条丢掉 —— 于是
80
80
  * 「落库时在、读回时不在」,并且**只发生在有回读的那条腿上**(SQL 有列回读、LOCAL 直接从 blob 投),
@@ -196,6 +196,20 @@ export type RuleEvidenceProjection = z.infer<typeof RuleEvidenceSchema>;
196
196
  * · `orgRevision` / 缺席词 verbatim(数值 / 闭集词,非内容)。
197
197
  */
198
198
  export declare function readRuleEvidence(req: unknown): RuleEvidenceProjection | undefined;
199
+ /** S-15 第五单(core #490 修②)—— `ruleOffers` 缺席因由的**闭三词集**(core d.ts 逐字;词表是闭集,
200
+ * 未知词=形不合=按缺席处置,绝不透传一个消费端词表外的值)。 */
201
+ export declare const RuleOffersAbsenceSchema: z.ZodEnum<{
202
+ mandated: "mandated";
203
+ lane_cannot_speak: "lane_cannot_speak";
204
+ shadowed: "shadowed";
205
+ }>;
206
+ export type RuleOffersAbsence = z.infer<typeof RuleOffersAbsenceSchema>;
207
+ /**
208
+ * `AskRequest.ruleOffersAbsence`(core #490 修②)的**边界窄读** —— 活卡帧与 `card_json` 的唯一铸造点
209
+ * (与 {@link readProbeCause} 同款分工),两面结构性同值。闭集词 verbatim(非内容族,零 redact);
210
+ * 形不合/缺席 ⇒ 不铸键(缺席不是断言 —— 它同时覆盖「有 offers」与结构性无车道的门,core 契约逐字)。
211
+ */
212
+ export declare function readRuleOffersAbsence(req: unknown): RuleOffersAbsence | undefined;
199
213
  /**
200
214
  * design/172 §3.1 的**中性投影**——呈卡面看到的全部内容,与 wire 面的既有 `ToolApprovalFrame` 解耦。
201
215
  *
@@ -243,6 +257,11 @@ export declare const ApprovalCardSchema: z.ZodObject<{
243
257
  }, z.core.$strict>>;
244
258
  uncoveredSegments: z.ZodNumber;
245
259
  }, z.core.$strict>]>>>;
260
+ ruleOffersAbsence: z.ZodOptional<z.ZodEnum<{
261
+ mandated: "mandated";
262
+ lane_cannot_speak: "lane_cannot_speak";
263
+ shadowed: "shadowed";
264
+ }>>;
246
265
  probeCause: z.ZodOptional<z.ZodObject<{
247
266
  code: z.ZodString;
248
267
  roots: z.ZodObject<{
@@ -319,6 +338,11 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
319
338
  }, z.core.$strict>>;
320
339
  uncoveredSegments: z.ZodNumber;
321
340
  }, z.core.$strict>]>>>;
341
+ ruleOffersAbsence: z.ZodOptional<z.ZodEnum<{
342
+ mandated: "mandated";
343
+ lane_cannot_speak: "lane_cannot_speak";
344
+ shadowed: "shadowed";
345
+ }>>;
322
346
  probeCause: z.ZodOptional<z.ZodObject<{
323
347
  code: z.ZodString;
324
348
  roots: z.ZodObject<{
@@ -465,7 +489,7 @@ export interface ApprovalRequestFrame {
465
489
  * 「本批全体」的推断。
466
490
  *
467
491
  * 🔴 **发射面 = live emit only,不进 durable tail**(设计稿 §8 C-3/C-5):撤卡帧由 reaper 腿/收敛器
468
- * 这类**没有账本上下文**的调用点产出,那里没有 seq 可分配,硬塞进账本会铸出一条序号伪造的行。丢帧的
492
+ * 这类**没有账本上下文**的调用点产出,那里没有 seq 可分配,硬塞进账本会铸出一条序号自造的行。丢帧的
469
493
  * 结构补偿 = 172 §3.1 的「preamble 是壳侧卡集**全量对账基准**,不在基准内的一律清」——壳重连时的
470
494
  * preamble 本身就会让一张没收到撤卡帧的僵尸卡消失。
471
495
  *
@@ -151,6 +151,12 @@ export function readRuleEvidence(req) {
151
151
  ...(raw.personalRuleDotsAbsent !== undefined ? { personalRuleDotsAbsent: raw.personalRuleDotsAbsent } : {}),
152
152
  };
153
153
  }
154
+ export const RuleOffersAbsenceSchema = z.enum(["mandated", "lane_cannot_speak", "shadowed"]);
155
+ const RuleOffersAbsenceEnvelopeSchema = z.object({ ruleOffersAbsence: RuleOffersAbsenceSchema.optional() });
156
+ export function readRuleOffersAbsence(req) {
157
+ const parsed = RuleOffersAbsenceEnvelopeSchema.safeParse(req);
158
+ return parsed.success ? parsed.data.ruleOffersAbsence : undefined;
159
+ }
154
160
  export const ApprovalCardSchema = z
155
161
  .object({
156
162
  toolName: z.string().max(MAX_IDENT),
@@ -169,6 +175,7 @@ export const ApprovalCardSchema = z
169
175
  inputHasBidi: z.literal(true).optional(),
170
176
  persistedRuleShadowed: z.string().max(MAX_RULE_TEXT_CHARS).optional(),
171
177
  ruleOffers: z.array(RuleOfferSchema).max(MAX_RULE_OFFERS).optional(),
178
+ ruleOffersAbsence: RuleOffersAbsenceSchema.optional(),
172
179
  probeCause: ProbeCauseSchema.optional(),
173
180
  ruleEvidence: RuleEvidenceSchema.optional(),
174
181
  fromSubagent: z.literal(true).optional(),
@@ -209,6 +216,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
209
216
  const riskAxes = axes.success ? axes.data.riskAxes : undefined;
210
217
  const probeCause = readProbeCause(req);
211
218
  const ruleEvidence = readRuleEvidence(req);
219
+ const ruleOffersAbsence = readRuleOffersAbsence(req);
212
220
  const toolCallId = clip(source.toolCallId, MAX_IDENT);
213
221
  const sourceTaskId = clip(source.sourceTaskId, MAX_IDENT);
214
222
  const sourceAgentName = clip(source.sourceAgentName, MAX_AGENT_NAME);
@@ -229,6 +237,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
229
237
  ...(probeCause !== undefined ? { probeCause } : {}),
230
238
  ...(ruleEvidence !== undefined ? { ruleEvidence } : {}),
231
239
  ...(source.ruleOffers !== undefined && source.ruleOffers.length > 0 ? { ruleOffers: source.ruleOffers.map(copyRuleOffer) } : {}),
240
+ ...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
232
241
  ...(source.fromSubagent === true ? { fromSubagent: true } : {}),
233
242
  ...(sourceTaskId !== undefined ? { sourceTaskId } : {}),
234
243
  ...(sourceAgentName !== undefined ? { sourceAgentName } : {}),
@@ -9,7 +9,7 @@ import type { ApprovalHmacKey } from "./auth-keys.js";
9
9
  *
10
10
  * ── `reason` 入签(三方裁 (a):cli [1797] / core [1801]§四 / server;clay「干净切」令 [1802])─────────────
11
11
  * `reason` 是随决定落账的自由文本(审计面的一部分)。它此前**在信封之外** ⇒ 能改线上字节的一方(反代 /
12
- * 被劫持的客户端 —— 正是 HMAC 要防的威胁模型)可以在操作员批准同一个动作的那次决定里,把落账理由换成
12
+ * 被接管的客户端 —— 正是 HMAC 要防的风险模型)可以在操作员批准同一个动作的那次决定里,把落账理由换成
13
13
  * 别的:动作没变,**审计记录变了**。三方裁定纳入签名载荷,不留 `reasonUnsigned` 宽限代际(未上生产)。
14
14
  *
15
15
  * ── 🔴 字节构造规则(权威定义;跨仓签名器照此实现,docs/ASSISTANT-WIRE-CONTRACT.md §6.2 同源)──────────
@@ -123,7 +123,7 @@ export type GateMatchOutcome =
123
123
  side: "ask_only" | "checkpoint_only" | "neither";
124
124
  }
125
125
  /**
126
- * 三元组身份对得上、两侧摘要都在场却**不等** —— 唯一的真 mismatch。成因是**部署自伤**而非攻击
126
+ * 三元组身份对得上、两侧摘要都在场却**不等** —— 唯一的真 mismatch。成因是**部署自伤**而非不当调用
127
127
  * ([2897]②:hook/policy 把自己仍持引用的活对象在两铸点之间改了,或每读返回新值的有状态 getter)。
128
128
  * 处置 = 留痕不拒:计数 + 一条 warn,行照 ②③④⑤ 走(判据 1 不命中的既有 fail-safe 路径不变)。
129
129
  */
@@ -200,7 +200,7 @@ export interface ReconcileStats {
200
200
  /**
201
201
  * 🔴 判据 1 的**真** mismatch 行数(#168 件1③,黑板 [2897]②):三元组身份对得上、两侧摘要都在场却不等。
202
202
  *
203
- * 成因裁定 = **部署自伤,不是攻击**:core 已证在真正产生两次铸造的弧上摘要恒等,两条分歧路径都要求
203
+ * 成因裁定 = **部署自伤,不是不当调用**:core 已证在真正产生两次铸造的弧上摘要恒等,两条分歧路径都要求
204
204
  * 部署自己交出活对象(hook/policy 返回己持引用后在两铸点之间突变;或每读返回新值的有状态 getter)。
205
205
  * 所以处置是**留痕不拒**:计一笔 + 一条 warn,行照 ②③④⑤ 的既有 fail-safe 走 —— 判据 1 不命中本来
206
206
  * 就不会产生终态 denial(约束②),这里不新增任何拒绝语义。
@@ -111,7 +111,7 @@ export function createApprovalReconciler(deps) {
111
111
  candidates: gateMatch.candidates,
112
112
  reason: "ask and checkpoint minted the same bound input under the same (sourceTaskId, toolCallId) identity but the digests differ — " +
113
113
  "the known causes are deployment-side (a hook/policy mutating an object it still holds a reference to between the two mints, " +
114
- "or a stateful getter returning a fresh value per read), not tampering; this ask keeps its fail-safe route (no park, no denial)",
114
+ "or a stateful getter returning a fresh value per read), not out-of-band interference; this ask keeps its fail-safe route (no park, no denial)",
115
115
  });
116
116
  }
117
117
  catch {
@@ -114,7 +114,7 @@ export declare function loadPublicKeyB64(b64: string): KeyObject;
114
114
  */
115
115
  export declare function signArtifact(artifact: L8DeployContractArtifact, privateKey: KeyObject, keyId: string): L8DeployContractArtifact;
116
116
  /**
117
- * Verify an artifact: recompute the contentHash over the body and check it matches the stored one (tamper of any
117
+ * Verify an artifact: recompute the contentHash over the body and check it matches the stored one (rewrite of any
118
118
  * body field flips the hash), then ed25519-verify the detached signature over the canonical body. Returns false
119
119
  * (never throws) on a missing/garbage signature, a content-hash mismatch, or a bad signature.
120
120
  *
@@ -125,7 +125,7 @@ type EmittedStats = CoreStatsSubset & {
125
125
  humanReview: NonNullable<CoreStatsSubset["humanReview"]>;
126
126
  };
127
127
  /**
128
- * 🔴 THE 命门 — classify a SOLO/SUP cell's honest scoring eligibility from the engine result. An INFRA death
128
+ * 🔴 THE 关键点 — classify a SOLO/SUP cell's honest scoring eligibility from the engine result. An INFRA death
129
129
  * (OOM / passthrough / sandbox/env crash) surfaces as a terminal `status` of `"failed"` or `"timeout"` on the
130
130
  * VerificationResult (core TaskStatus) — it MUST be `"infra-failed"` (EXCLUDED from scoring), NOT scored as a
131
131
  * legitimate agent loss. An honest agent abandon (`"blocked"` = ran out of turns / gave up) is a SCORED loss, not
@@ -8,7 +8,7 @@
8
8
  * 🔴 ANTI-REWARD-HACK (oracle.ts §, runner-ctx.ts §5.1): the oracle ALWAYS grades in a env that is a DISTINCT
9
9
  * object from the worker env. We provision a SEPARATE E2B sandbox for the grader and transfer the worker's
10
10
  * COMMITTED tree into it via `git bundle` (export from the worker sandbox → import into the grader sandbox) —
11
- * so the grader's checkout is the worker's HEAD, but the grader sandbox can never be tampered by the worker
11
+ * so the grader's checkout is the worker's HEAD, but the grader sandbox can never be rewritten by the worker
12
12
  * (its hidden tests + its exec all run in a sandbox the worker never touched). `assertDistinctEnvs` is the
13
13
  * build-time guard; the structural separation is the real boundary.
14
14
  *
@@ -8,7 +8,7 @@
8
8
  * - DECORRELATED + ANTI-REWARD-HACK: it grades in a DISTINCT grader env (`ctx.newGraderEnv()`), never the
9
9
  * worker's own env — the SAME isolation the repair-loop §5.1 identity check enforces.
10
10
  * - HIDDEN + RESTORED-BEFORE-SCORING: the worker never sees `task.hiddenTestFiles`; the oracle WRITES them into
11
- * the grader checkout, overwriting any worker-authored same-named file (anti-tamper, design/89 §2.2).
11
+ * the grader checkout, overwriting any worker-authored same-named file (anti-rewrite, design/89 §2.2).
12
12
  *
13
13
  * The repair leg needs core's `RepairOracle = (graderEnv, evidence) => OracleResult` shape — a DIFFERENT
14
14
  * signature. `repair-oracle-adapter.ts` wraps this standalone oracle into that closure (do NOT pass `runOracle`
@@ -20,7 +20,7 @@
20
20
  * - The NUMERATOR is ONLY DELIVERED-CORRECT, and the OBJECTIVE oracle (oracle.ts) is the measure — an LLM-judge
21
21
  * is NEVER in the numerator (it may only be a GATE inside an arm).
22
22
  *
23
- * 🔴 HONEST runStatus (the 命门 against benchmark noise): an INFRA death — OOM / passthrough / nested-root crash —
23
+ * 🔴 HONEST runStatus (the 关键点 against benchmark noise): an INFRA death — OOM / passthrough / nested-root crash —
24
24
  * is `"infra-failed"` and MUST be EXCLUDED from scoring, NOT scored as a loss. Default is `"scored"`.
25
25
  *
26
26
  * 🔴 HONEST withhold-credit: SOLO `delivery.withheld` is ALWAYS false (only a SUP/TEAM gate can intercept). A
@@ -42,6 +42,6 @@ export declare function createBudgetAndTracing(ctx: BudgetTracingCtx): {
42
42
  }) => void;
43
43
  toolResultStore: import("../plugins/store-backend.js").ToolResultStoreFull | undefined;
44
44
  sessionPolicyStore: import("@sema-agent/core").SessionPolicyStore | undefined;
45
- fileSnapshotStore: import("../plugins/store-backend.js").ServiceFileSnapshotStore | undefined;
45
+ fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
46
46
  };
47
47
  //# sourceMappingURL=budget-tracing.d.ts.map