@sema-agent/server 7.139.0 → 7.140.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/MIGRATION.md +181 -0
  2. package/USAGE.md +19 -13
  3. package/dist/adoption/runner.js +1 -1
  4. package/dist/adoption/sql.js +1 -1
  5. package/dist/approval-card.d.ts +6 -6
  6. package/dist/bench/s1/live-deps.js +3 -2
  7. package/dist/bench/s1/row.d.ts +5 -2
  8. package/dist/bench/s1/row.js +2 -22
  9. package/dist/boot/adoption.js +1 -1
  10. package/dist/boot/execution-env.js +12 -10
  11. package/dist/boot/execution-lane.d.ts +8 -0
  12. package/dist/boot/execution-lane.js +6 -1
  13. package/dist/boot/memory-boundary.d.ts +14 -51
  14. package/dist/boot/memory-boundary.js +10 -20
  15. package/dist/boot/memory-consolidation.d.ts +15 -11
  16. package/dist/boot/memory-consolidation.js +23 -12
  17. package/dist/boot/resolve-spec.d.ts +3 -5
  18. package/dist/boot/resolve-spec.js +2 -4
  19. package/dist/boot/runner-deps.d.ts +3 -3
  20. package/dist/boot/runner-deps.js +1 -0
  21. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  22. package/dist/boot/stage-03-store-backend.js +2 -3
  23. package/dist/boot/stage-04-stores.d.ts +2 -6
  24. package/dist/boot/stage-04-stores.js +5 -5
  25. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  26. package/dist/boot/stage-06-runners.d.ts +2 -6
  27. package/dist/boot/stage-06-runners.js +2 -2
  28. package/dist/boot/stage-07-capability-layer.d.ts +2 -6
  29. package/dist/boot/stage-08-reapers.d.ts +2 -6
  30. package/dist/boot/stage-09-leader.d.ts +2 -6
  31. package/dist/boot/stage-10-http-server.d.ts +2 -6
  32. package/dist/boot/stage-10-http-server.js +5 -4
  33. package/dist/boot/stores.d.ts +3 -6
  34. package/dist/boot/stores.js +27 -40
  35. package/dist/boot/task-list-lane.d.ts +1 -1
  36. package/dist/boot/task-list-lane.js +1 -1
  37. package/dist/boot/web-admin.js +35 -9
  38. package/dist/capabilities/execution-lane.d.ts +2 -2
  39. package/dist/config-catalog.js +2 -1
  40. package/dist/config-provider.d.ts +14 -13
  41. package/dist/config-provider.js +24 -18
  42. package/dist/config-types.d.ts +11 -2
  43. package/dist/config.js +2 -1
  44. package/dist/delegated-session-owner.d.ts +2 -1
  45. package/dist/delegated-session-owner.js +1 -1
  46. package/dist/deployment-shape.d.ts +9 -8
  47. package/dist/deployment-shape.js +4 -4
  48. package/dist/execution-lane-caps.d.ts +97 -106
  49. package/dist/execution-lane-caps.js +67 -83
  50. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  51. package/dist/http/memory-compliance-failure-reply.js +5 -0
  52. package/dist/http/memory-layer-reply.d.ts +30 -0
  53. package/dist/http/memory-layer-reply.js +24 -0
  54. package/dist/http/resume-legs.js +13 -16
  55. package/dist/http/retired-service-deps.d.ts +1 -1
  56. package/dist/http/retired-service-deps.js +1 -1
  57. package/dist/http/routes/adoption.js +1 -1
  58. package/dist/http/routes/memory-bundle.js +3 -0
  59. package/dist/http/routes/memory-compliance.js +8 -1
  60. package/dist/http/routes/memory-consolidation.js +12 -1
  61. package/dist/http/routes/memory-origin.js +14 -2
  62. package/dist/http/routes/memory-policy.js +5 -0
  63. package/dist/http/routes/sessions.js +28 -11
  64. package/dist/http/routes/tasks.js +4 -2
  65. package/dist/http/server.d.ts +5 -25
  66. package/dist/http/server.js +2 -2
  67. package/dist/identity-source.d.ts +1 -1
  68. package/dist/identity-source.js +1 -1
  69. package/dist/lane-home-probe.d.ts +68 -42
  70. package/dist/lane-home-probe.js +53 -30
  71. package/dist/leader/wire.js +5 -4
  72. package/dist/memory-bundle-engine.d.ts +16 -9
  73. package/dist/memory-bundle-engine.js +29 -6
  74. package/dist/memory-operator-faces.d.ts +85 -30
  75. package/dist/memory-operator-faces.js +136 -30
  76. package/dist/memory-project-layer.d.ts +3 -21
  77. package/dist/memory-project-layer.js +11 -8
  78. package/dist/memory-scope-stores.d.ts +73 -0
  79. package/dist/memory-scope-stores.js +86 -0
  80. package/dist/memory-scope.d.ts +29 -5
  81. package/dist/memory-scope.js +16 -4
  82. package/dist/memory-sync-client.d.ts +20 -7
  83. package/dist/memory-sync-client.js +31 -13
  84. package/dist/plugins/adoption-log-sql.js +4 -4
  85. package/dist/plugins/approval-ask-store-sql.js +14 -14
  86. package/dist/plugins/approval-nonce-store.js +4 -4
  87. package/dist/plugins/blob-backend.d.ts +4 -4
  88. package/dist/plugins/blob-backend.js +7 -7
  89. package/dist/plugins/breaker-state-sql.js +2 -2
  90. package/dist/plugins/checkpoint-index-columns.js +2 -2
  91. package/dist/plugins/checkpoint-store-sql.js +16 -16
  92. package/dist/plugins/device-store-sql.js +19 -19
  93. package/dist/plugins/ensure-index.d.ts +1 -2
  94. package/dist/plugins/execution-placement-sql.d.ts +8 -8
  95. package/dist/plugins/execution-placement-sql.js +8 -8
  96. package/dist/plugins/file-history-store-sql.d.ts +2 -2
  97. package/dist/plugins/file-history-store-sql.js +4 -4
  98. package/dist/plugins/image-bake-store-sql.js +9 -9
  99. package/dist/plugins/image-index-sql.js +11 -11
  100. package/dist/plugins/leader-run-store-sql.js +4 -4
  101. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  102. package/dist/plugins/mailbox-store-sql.js +4 -4
  103. package/dist/plugins/memory-engine-tidb.js +5 -5
  104. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  105. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  106. package/dist/plugins/one-time-migrations.d.ts +10 -9
  107. package/dist/plugins/one-time-migrations.js +36 -36
  108. package/dist/plugins/org-delivery-quota-store.js +2 -2
  109. package/dist/plugins/outcome-ledger-sql.js +2 -2
  110. package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
  111. package/dist/plugins/permission-rule-store-sql.js +16 -16
  112. package/dist/plugins/remote-env-adb.d.ts +7 -24
  113. package/dist/plugins/remote-env-adb.js +22 -5
  114. package/dist/plugins/remote-env-device.d.ts +2 -28
  115. package/dist/plugins/remote-env-device.js +2 -1
  116. package/dist/plugins/remote-env-e2b.d.ts +18 -26
  117. package/dist/plugins/remote-env-e2b.js +51 -4
  118. package/dist/plugins/remote-env-file-error.d.ts +1 -1
  119. package/dist/plugins/remote-env-file-error.js +8 -2
  120. package/dist/plugins/remote-env-host.d.ts +19 -35
  121. package/dist/plugins/remote-env-host.js +26 -3
  122. package/dist/plugins/remote-env-k8s.d.ts +3 -14
  123. package/dist/plugins/remote-env-k8s.js +3 -2
  124. package/dist/plugins/remote-env-local-docker.d.ts +4 -15
  125. package/dist/plugins/remote-env-local-docker.js +5 -4
  126. package/dist/plugins/remote-env-ssh.d.ts +4 -24
  127. package/dist/plugins/remote-env-ssh.js +4 -3
  128. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  129. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  130. package/dist/plugins/retention-lane-store-sql.js +2 -2
  131. package/dist/plugins/retention-store-sql.d.ts +1 -1
  132. package/dist/plugins/retention-store-sql.js +6 -6
  133. package/dist/plugins/run-store-sql.js +15 -15
  134. package/dist/plugins/schema-consistency.d.ts +6 -6
  135. package/dist/plugins/schema-consistency.js +1 -1
  136. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  137. package/dist/plugins/schema-ensure-legs.js +2 -2
  138. package/dist/plugins/schema-live-columns.d.ts +1 -1
  139. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  140. package/dist/plugins/session-rules-column.d.ts +1 -1
  141. package/dist/plugins/session-rules-column.js +1 -1
  142. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  143. package/dist/plugins/session-workspace-cell.js +1 -1
  144. package/dist/plugins/shared-memory-store-sql.js +2 -2
  145. package/dist/plugins/sql-driver.d.ts +10 -5
  146. package/dist/plugins/sql-driver.js +6 -6
  147. package/dist/plugins/sql-errors.js +1 -1
  148. package/dist/plugins/store-backend.d.ts +4 -6
  149. package/dist/plugins/store-backend.js +6 -6
  150. package/dist/plugins/task-list-store-sql.js +11 -11
  151. package/dist/plugins/tidb-pool.js +5 -5
  152. package/dist/plugins/tidb-session-storage.js +4 -4
  153. package/dist/plugins/tidb-session-store.js +13 -13
  154. package/dist/plugins/tool-result-store-sql.d.ts +2 -2
  155. package/dist/plugins/tool-result-store-sql.js +3 -3
  156. package/dist/plugins/user-input-ledger-sql.js +2 -2
  157. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  158. package/dist/plugins/workflow-run-store-sql.js +19 -19
  159. package/dist/plugins/write-behind-counter.d.ts +2 -3
  160. package/dist/plugins/write-behind-counter.js +5 -5
  161. package/dist/resource-suspend.d.ts +14 -12
  162. package/dist/resource-suspend.js +1 -1
  163. package/dist/resource-window.d.ts +4 -3
  164. package/dist/run-local.js +14 -19
  165. package/dist/runs.d.ts +8 -4
  166. package/dist/runs.js +49 -65
  167. package/dist/session-incarnation.d.ts +1 -1
  168. package/dist/session-incarnation.js +1 -1
  169. package/dist/session-policy-wire.d.ts +1 -1
  170. package/dist/sql-engine-posture.d.ts +1 -1
  171. package/dist/sql-engine-posture.js +1 -1
  172. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  173. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  174. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  175. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  176. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  177. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  178. package/dist/task-a2a.js +5 -6
  179. package/dist/task-mcp.d.ts +20 -7
  180. package/dist/task-mcp.js +17 -9
  181. package/dist/terminal.d.ts +27 -0
  182. package/dist/terminal.js +6 -0
  183. package/dist/trace/redact.d.ts +3 -1
  184. package/dist/trace/redact.js +80 -28
  185. package/dist/trace/self-minted-wire.d.ts +58 -0
  186. package/dist/trace/self-minted-wire.js +16 -0
  187. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  188. package/dist/web-admin-client/candidate-gate.js +1 -1
  189. package/dist/web-admin-client/http-client.d.ts +5 -4
  190. package/dist/web-admin-client/http-client.js +2 -2
  191. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  192. package/dist/web-admin-client/read-warnings.js +5 -9
  193. package/package.json +2 -2
  194. package/wire-changes/server@7.140.0.json +184 -0
package/MIGRATION.md CHANGED
@@ -7,6 +7,187 @@
7
7
  > ⚠️ 完整清单在仓库根 `CHANGELOG.md`——它**不随 npm tarball 出包**(本文件随包)。看完整迁移窗的
8
8
  > 权威姿势是源码 tag diff:`git diff v<旧>..v<新>`(每版都推 `v<版本>` tag);npm 包页也镜像 CHANGELOG。
9
9
 
10
+ ## 7.140.0 —— 依赖方向门(测试门;零 wire、零行为) · `CONFIG_PROVIDER=local`:`config.d` 里读不出的文档成被拒文档,候选整拒、拒句点名文件与形(行为变更;运维面) · 脱敏:PEM 私钥 armor 体里夹着由别的凭据装着的假收尾 ⇒ 整块照遮(安全) · SQL 方言字 `"tidb"` → `"mysql"`(嵌入方类型面 BREAKING;起服日志的后端字同换) · 🔴 记忆同步:同步层是个人平面键的 file 部署,这一层改同步会话读写的那只店,旧游标升级后被拒一次(删游标,不改绑) · 记忆同步层引擎读不出 ⇒ 起服拒(行为收紧) · `verify:true` 任务停在审批 / 计划审阅门上:run 行停驻、会话保持占用(行为变更) · 新旋钮 `READ_DENY_FLOOR_REQUIRED`(缺省 false;安全) · `REMOTE_EXEC=host` 不再被代声明「记忆能持久」(行为面) · `verify:true` 任务撞资源限停驻(行为变更) · 请求自带的 MCP / A2A 声明写着引擎永远不发的头 ⇒ 新提交 400(行为收紧) · 执行环境的家目录在每只环境开起来时被对证,对不上 ⇒ 那只环境拒起(六条车道;行为收紧;安全) · 记忆诸口答在请求点名的层住的那只店上:两店部署上条目 id / 店级账本的请求带层座 `scope`、落到个人店的抹除 `409 memory.erasure_store_unjudged`(行为变更;wire 加性;嵌入方 `ServiceDeps.sessionMemoryStatus` 改形,BREAKING 类型面) · 订正 7.138.0 节第 23 条 ⑩:扣留次序是先记后判(文字订正) · 契约包 settings-schema 15.2.0 · 引擎 7.60.0
11
+
12
+ 1. **依赖方向门(测试门;零 wire、零行为;部署与嵌入方零动作)**:`src/` 读引擎(`@sema-agent/core`)的方式进了一道本仓的测试门 —— 说明符闭集、禁深路径与沿文件系统走引擎安装目录、
13
+ 禁整模块绑定、读表里不得有引擎的 SQL 方言店类、方言店文件不得继承引擎的店基类、`src/stores-sql/**` 的目录级依赖。它只检查源码,不进运行时、不改任何 wire 与存储格式。
14
+ 唯一碰到运行路径的一处是 S1 bench 行的 `meta.coreVersion`:改读引擎根导出 `CONTRACT_KIT_ENGINE_VERSION`,值与此前相同(装机引擎的版本)。
15
+ **谁受伤**:无。**出路 / 回滚**:无需。
16
+ 2. **`CONFIG_PROVIDER=local`:`config.d` 里读不出的文档不再被读成那个域的缺省,而是一条被拒文档 —— 整份本地候选被拒,拒句点名文件与形(行为变更;运维面)**:
17
+ `config.d/<域>.json` 在场但空 / 纯空白(编辑器非原子保存留下的半写、截断)、坏 JSON,或解析出来不是 JSON 对象(`null` / 数组 / 数 / 串 / 布尔)。上一版两类各走一条路:
18
+ 目录域(`models` / `skills` / `mcp` / `plugins` / `scenarios` / `collab` / `prompts`)先按那个域的缺省读成一份空目录 / 空注册表、再由候选判官整拒,
19
+ 拒判的成因记成 `domain_invalid`、另出一行 `config_domain_invalid`;门控域(`rosters` / `governance` / `execution` / `limits`)整份读抛,
20
+ 起服记 `config_source_unreachable_using_env`、刷新拍记 `web_admin_refresh_failed`、手动刷新口答 502,没有拒判行,看不出是哪一份坏了。
21
+ 本版不分域同判(配置契约的文件层先于域解析):读腿把配置契约对这棵目录的拒单原样交成被拒文档,候选判官整拒,`config_candidate_rejected` 的 `errors[]` 每份一条
22
+ `{ domain, reason, error }` —— `domain` 是那份文档的名字,`reason` 是配置契约的闭集词:`empty`(空 / 纯空白)· `invalid_json`(坏 JSON)· `not_object`(`null` / 数组 / 标量)·
23
+ `io`(在场却读不出:权限等);`error` 是配置契约的拒句(点名文件的真实路径与形、给出路,不回显文件内容;`io` 是文件系统的原话,有的不带路径 —— 认是哪一份读 `domain`);
24
+ `GET /v1/models.candidateRejected.domains` 含那个域;起服不再出 `config_source_unreachable_using_env`,刷新拍跑完(手动刷新口 200);这一形不再出 `config_domain_invalid`
25
+ (那一行只留给读得出、判形失败的域)。几份同时读不出 ⇒ 每份一条,一次说全;带事实的 `runtime.json`(`reason: "retired_domain"`)与读不出的文档同在 ⇒ 同一行里都列出(`runtime` 在前)。
26
+ 退役域文件 `config.d/runtime.json` 自己读不出 ⇒ 同样是一条被拒文档(`domain: "runtime"`);配置根本身是个普通文件 ⇒ 每份文档一条 `io`(文件系统原话 `ENOTDIR`)。
27
+ 已知边:一份读不出的文档与一份嵌套深过 200 层的文档同在 ⇒ 仍整份读抛(与上一版同),先把那份过深的文档改浅。
28
+ 另一条已知边:读腿的失败路径是两读(严读拒了才问整目录拒单),那份文件恰在两读之间被修好 ⇒ 这一拍照原样抛严读那一读的错
29
+ (走读失败那条臂:起服 `config_source_unreachable_using_env`、刷新拍 `web_admin_refresh_failed`),诊断说的是已经不在的坏形;下一拍重读即自愈。
30
+ 被拒那一拍的版本号(拒判行的 `version`、世代账的 `configTargetVersion`)是配置契约按文档内容算的版本:同样的坏内容同一个号(同一份坏树不重响),内容一改就换号、拒判行再响一次(拒句没变也换),修好回到内容版本 —— 读不出的文档按去掉首尾空白的原文算(只差首尾空白不换号),带事实的 `runtime.json` 按读出来的值算(只改缩进 / 键序不换号)。
31
+ `config_local_no_models` 多一个键 `reason`(判官给 `models` 的成因词),hint 按它说「读不出(哪一形)」还是「判形失败」。
32
+ — **谁需要**:单机 / 本地配置的部署 —— 半写的 `config.d` 文件不会被读成一份空的模型目录或 MCP 注册表,门控域的半写也不再被报成「配置源不可达」,运维直接看到是哪一份文件、坏成什么形。
33
+ — **谁受伤**:按 `config_source_unreachable_using_env` / `web_admin_refresh_failed` 认「门控域文件坏了」,或按 `config_domain_invalid` / `reason: "domain_invalid"` 认「某个域文件读不出」的告警规则 ——
34
+ 改认 `config_candidate_rejected` 里 `reason` 为 `empty` / `invalid_json` / `not_object` / `io` 的那几条。配置结局不变:候选整拒、一个域都不应用,起服回落 env(本地没有 LKG),刷新拍保持在用的配置。
35
+ 配置根本身读不出(普通文件)上一版走「源不可达」,本版是一行逐份 `io` 的拒判(结局同:env / 保现用)。
36
+ — **补偿**:修好那份文件(写成合法的 JSON 对象),或删掉它(删掉 = 回到那个域的缺省);下一个刷新拍落地,不用重启(restart-to-apply 的面照旧要重启)。
37
+ 3. **脱敏:PEM 私钥 armor 体里夹着一枚由别的凭据装着的假收尾栅栏 ⇒ 整块照遮(行为面,安全;7.138.0 披露过、7.139.0 未修也漏带披露的那一形)**:
38
+ 上一版的脱敏在 armor 体里**最早**的一枚 `-----END … PRIVATE KEY-----` 处收口 —— 那一枚若装在 JSON 秘密字段的串值里(或体里一整只 SSH2 armor 里),
39
+ 其后的私钥体以明文留在 trace / 运维日志行里。本版跳过装在别的凭据里的收尾,盖到真收尾;有界日志行的扫描窗里真收尾在窗外 ⇒ 从起始栅栏遮到窗尾。
40
+ 体长上界(8192)改按单元量(一枚别的凭据算一格,与 SSH2 栅栏臂同一把尺)⇒ 体里装着别的凭据、按字符量超界而按单元量不超的块也整块一枚记号。
41
+ 其余文本输出逐字节不变;体里一枚没有任何凭据装着的收尾串仍算收尾(与「真收尾之后跟一段文字」不可区分);文本里没有真收尾时的整段读法与上一版同。
42
+ — **谁需要**:把含私钥 armor 的文本交给脱敏面的部署。— **谁受伤**:无。— **补偿 / 回滚**:无需;回滚到上一版即回到那一形的明文残留。
43
+
44
+ 4. **SQL 方言字 `"tidb"` → `"mysql"`(嵌入方类型面 BREAKING;零 wire、零表、零存储格式;部署配置零动作)**:语法族的字只剩 `"mysql" | "pg"`,与 `DB_BACKEND` / `StoreBackend.kind` 同字;`tidb` 只剩引擎名的意思(`SqlEngine`,驱动探到的引擎事实)。
45
+ **谁受伤**:① 读根导出 `createTaskListLane(...)` 返回值 `backend` 的嵌入方:`"tidb"` 改成 `"mysql"`(TypeScript 编译红即通知)。② 自建 `createHttpServer` 并自己给 `sqlEngine` 的嵌入方:`dialect` 只收 `"mysql" | "pg"`,
46
+ `"tidb"` ⇒ 起服拒(拒句点名形 `{ dialect: "mysql" | "pg", facts }`);用本服务自己的装配、或把驱动读口原样交进来的不受影响。③ 按起服日志 `*_store_enabled` 的 `backend: "tidb"`(或 `tidb+minio`)筛的运维查询:字改为 `mysql`(`mysql+minio`)。
47
+ 不受影响:HTTP 客户端;`DB_BACKEND` / `SESSION_BACKEND` / `MEMORY_ENGINE_BACKEND` 的取值;数据库的表、列与行。会话策略 / 治理窗 / 后台子代三只方言店的源文件同时换了目录,包的导出表里没有这几条路径,包外本来就 import 不到,无需动作。
48
+ **出路**:换字。没有别名,没有兼容臂。**回滚**:回到上一版即可(没有数据迁移)。
49
+ 5. **记忆同步的同步层是个人平面的键(`user:` / `userproj:` / `org:`;同步层 = `MEMORY_SYNC_SCOPE`,缺省 = `MEMORY_SCOPE`)的 file 记忆部署:这一层改为同步会话读写的那只店;它的旧游标升级后被拒一次,删掉它(行为变更;修复)**:
50
+ 上一版同步执行器同步部署的店(`<引擎根>/memory`),会话的全局个人层却在个人挂载上的另一只店(`<引擎根>/personal/memory`):写进这一层的新记忆不推,拉下来的会话读不到。
51
+ 本版这一层同步个人挂载那只店(由引擎的唯一读法答,与会话同一只);项目层(`userrepo:…`)、`proj:` 键与非类型化的同步层(含 `local`)不变 —— 同步层不是个人平面的键(例:`MEMORY_SCOPE=user:<P>` 而 `MEMORY_SYNC_SCOPE=local`)⇒ 本条与你无关。
52
+ — **升级后看**:第一轮这一层出一行 `memory_sync_layer_failed`(`scope` = 同步层,拒句 `cursor is for store "file:…/memory"; this round's store is "file:…/personal/memory"`),这一层零请求,别的层照跑,下一轮同样拒,直到处置。
53
+ 这一层此前没同步过(没有游标文件)⇒ 不出这一行,第一轮直接同步。
54
+ — **处置(只这一条)**:删掉那只游标文件(路径 = 该行的 `cursorPath`),下一轮从空基线重收敛 —— 推个人店里会话写的、拉中心这一层有的、不推删除;两边都改过的条目按冲突上报。
55
+ **不要**按拒句的出路 (1) 改绑:旧游标的基线是部署店里那一层的条目,个人店里没有它们,改绑后的那一轮会把它们当成「本地已删」推成删除(中心与别的设备上的这些记忆随之被删)。
56
+ — **谁受伤**:升级前在这类部署上跑过同步的部署(这一层停同步,直到删掉那只游标)。部署店里那一层原有的条目(上一版拉下来的)留在原处、不再有读者(会话本来就不读它们);中心有的那些在重收敛时拉进个人店。
57
+ — **回滚**:回到 7.139.x 病照在(同步回到部署的店);这一层的新游标绑的是个人店,7.139.x 在店轴拒它一次,处置同上(删掉它)。
58
+ 6. **记忆同步的同步层引擎读不出 ⇒ 起服拒(行为收紧)**:同步执行器在起服装配时就向引擎问同步层住哪只店,引擎读不出的键在那里被拒,码 `config.memory_scope_key`(引擎原句,`resolveMemoryScopeStore: …`),服务不起。
59
+ 配置边界放行、引擎拒的形今天只有一种:全空白的 `MEMORY_SYNC_SCOPE`(类型化而读不出的键 `loadConfig` 已先拒)。
60
+ — **谁受伤**:`MEMORY_SYNC_SCOPE` 设成全空白的部署 —— 上一版起得来,每一轮同步被引擎拒,同步从未发生;本版起不来。
61
+ — **补偿**:把 `MEMORY_SYNC_SCOPE` 改成要同步的那一层(或删掉它,缺省 = 类型化的 `MEMORY_SCOPE`);不开同步就把 `MEMORY_SYNC_URL` 连同 `MEMORY_SYNC_SCOPE` / `MEMORY_SYNC_TOKEN` 一并撤掉(只撤 URL、留着 scope 或 token,起服仍拒:半配置)。
62
+ — **回滚**:回到 7.139.x 又起得来,同步照旧每一轮被拒。
63
+ 7. **`verify:true` 的任务停在审批 / 计划审阅门上:run 行停驻、会话保持占用,不再立刻 `failed`(行为变更;wire 形不新)**:
64
+ 开了耐久审批(`DURABLE_APPROVAL`)且有 run 店的部署上,`verify:true` 任务的实现腿(或某一轮修复)撞上要人批的工具 / 计划审阅门时 ——
65
+ 上一版:`POST /v1/runs` 的行立刻 `failed` + `errorCode: "unexpected.suspended"`(计划审阅门 `unexpected.needs_review`)并释放会话;`POST /v1/tasks` 答 200 终局体
66
+ (`terminal.kind: "failed"` + `nestedPause`);卡却仍待决,批准之后工具照样执行,行停在 `failed`、决定体不带 `taskId`。
67
+ 本版:行停在 `suspended`(计划审阅门 `needs_review` + `errorCode: "review.pending"`),`result.terminal.kind: "paused"`(带 `gate`、不带 `token`),会话保持占用;
68
+ `GET /v1/runs/:id/events` 的尾帧是 `suspended` / `needs_review` 而不是 `done`;`POST /v1/tasks` 答停驻回执 `{status: "suspended" | "needs_review", taskId, sessionId}`
69
+ (与非 verify 任务的同步停驻同一形;同 `Idempotency-Key` 重放答同一份);决这张卡(审批门 `POST /v1/approvals/:sessionId/decide`;计划审阅门 `POST /v1/assistant/tasks/:taskId/plan_review`)续回同一条行,审批的决定体带 `taskId`,行翻成终局;
70
+ 取消停驻中的这条 run(`POST /v1/runs/:id/cancel`)⇒ 卡离开待决列表、行 `failed` + `errorCode: "cancelled"`、会话释放。
71
+ 另:取消一条 `verify:true` / `cascade:true` 的后台 run,引擎交回无码失败时行带 `errorCode: "cancelled"`(上一版无码)。
72
+ — **谁需要**:用 `verify:true` 提交、实现腿会碰到要人批的工具的任务,以及决这些卡的运维 —— 批准之后 run 行如实翻转。
73
+ — **谁受伤**:把「verify + 审批 ⇒ 立刻 failed」当信号的调用方 —— 修后同一提交停驻等人,停驻期间同会话再提交 / `DELETE /v1/sessions/:id` / 换绑设备 / 会话同步都答 409
74
+ (与普通停驻同形),先决卡或取消;同步 verify 调用方的 200 体换成停驻回执,改按停驻回执处理(轮询 `GET /v1/runs/<taskId>`)。dry-run 审阅停驻没有决断端点,停驻到取消或过期。
75
+ — **补偿**:`APPROVAL_TIMEOUT_SEC`(> 0 时到时收回停驻)、checkpoint 绝对过期兜底(常开)、`POST /v1/runs/:id/cancel`、部署级 `DURABLE_APPROVAL=false`(没有耐久停驻)。
76
+ 回滚:本版不写新列、不迁数据;回退之后,本版留下的 verify 停驻行仍由续跑腿的 verify 臂驱动(那条臂在上一版就处理认领在的 verify 停驻行;回退形上未实跑)。
77
+ — **已知限制**:`cascade:true` 任务的某一级停在审批上时照旧 —— 行 `failed` + `unexpected.suspended`、会话释放;那张卡在 `GET /v1/approvals` 里看得见但决不掉
78
+ (409 `conflict.resume_context_unavailable`),到期自动收回。引擎侧修好之前请别对 cascade 任务开耐久审批。
79
+ 8. **读拒表的字节地板可以要求了:新旋钮 `READ_DENY_FLOOR_REQUIRED`(缺省 false;安全;行为面只在设 true 时变)**:读拒表有行(出厂读拒档 credentials / agent-config 在岗即有行)
80
+ 而这条车道的执行环境不守字节地板(起服行 `remote_exec_enabled.keepsReadFloor=false`;七条车道今天都是)时 —— 设 true ⇒ 这类 run 在准备期拒,终局码 `config.read_deny_floor_unkept`,
81
+ 一个命令都不起、零 token,同步提交答 409;起服多一行 warn `read_deny_floor_required_unkept { provider, note }` 点名车道与键。不设 / false ⇒ 与上一版相同:run 照跑,
82
+ 每 run 恰一条运维通告同码(`engine_notice` 结构化日志,不上用户流)。坏词(`required` 之类)⇒ 起服拒,拒句点名键与词表。
83
+ 自拼 `ServiceConfig` 的嵌入方:新增必填席 `readDenyFloorRequired: boolean`(`READ_DENY_FLOOR_REQUIRED` 的值,缺省 false),由 `loadConfig` 一次铸出。
84
+ — **谁需要**:要把「读拒表里的文件字节不进对话」当硬门的部署(合规 / 托管)。
85
+ — **谁受伤**:设了 true 的部署上带手的 run 一律拒起(七条车道都不守地板)—— 这是旋钮本身的意思,不是副作用;不设的部署零变化。
86
+ — **补偿**:不设 = 照跑并每 run 一条通告;要「既跑又守」等守地板的车道。
87
+ 9. **执行环境能力只有一个作者 `capabilitiesFor(部署配置)`;`REMOTE_EXEC=host` 不再被代声明 `memoryPersistenceCapable: true`(行为面;部署零配置改动;嵌入方零动作)**:
88
+ ① **host 车道的记忆披露**:装配层不再替 host 车道写 `memoryPersistenceCapable: true`,`MEMORY_PERSISTENCE_CAPABLE` 原样直通、缺席即缺席;起服 info 行
89
+ `memory_persistence_capable_auto_declared` 删除。引擎按执行环境块(host 车道 `hostLocalPaths: true`)照教写指令、按名册推断能不能存:名册里有本机可写工具的 run 与上一版相同;
90
+ 名册写不了的 run(如 `AUTONOMY=read-only`)从此收到「本会话没有持久记忆」的只读披露(上一版被那只代声明压掉)。host 车道的起服记忆边界审计与上一版一样零行;
91
+ 沙箱 / 远端车道的 `memory_remote_lane_write_instruction_dropped` 照出,句子不再说「引擎把它判成 remote」。
92
+ ② **内部模块**(都不在包根出口,嵌入方零动作;改本仓源码的人看这里):`effectiveMemoryPersistenceCapable` 删除;车道能力表删七位
93
+ `isolation` / `suspendable` / `canonicalPathAuthority` / `hostFilePlane` / `coreRemoteExecutionEnv` / `sandboxPathAdjudication` / `memoryPersistenceCapable`
94
+ (改读 `capabilitiesFor(config)` 的块:`isolation` / `suspendable` / `canonicalPathAuthoritative` / `hostLocalPaths` / `io`;写门走不走代理 = `!hostLocalPaths`);
95
+ `MemoryWriteBoundaryFacts.coreRemoteExecutionEnv` 删除;部署形表 `lane` 轴的事实 `k8sSnapshotStore` 换成 `block`(执行环境块)。
96
+ wire 零变化(`executionLane` 的 `provider` / `toolsOnThisHost` / `isolated` 八词逐格同值)。
97
+ — **谁需要**:改车道能力的人(改一处,适配器、部署形、起服行、wire 同翻);host 部署上名册写不了的 run 不再被说成「能存」。
98
+ — **谁受伤**:靠那只代声明拿到「能存」口径的 host 部署(改为如实只读披露);按 `memory_persistence_capable_auto_declared` 认 host 记忆可写的运维告警。
99
+ — **补偿**:host 车道确实能存而名册推断不出的形,设 `MEMORY_PERSISTENCE_CAPABLE=on`。回滚到上一版即恢复代声明(零数据面)。
100
+ 10. **`verify:true` 任务的实现腿 / 修复轮撞资源限(预算 / turns / 墙钟)时停驻,不再 `failed`(行为变更;wire 形不新;只在 `RESOURCE_SUSPEND` 开着、有 durable checkpoint 的部署上)**:
101
+ 上一版:`RESOURCE_SUSPEND` 开着时,普通任务撞限落一张 `resource_limit` 停驻、可续;`verify:true` 任务被 opt-in 整只排除,撞同一个限 ⇒ `POST /v1/runs` 的行 `failed` +
102
+ `errorCode` 为 `limits.max_walltime_exceeded` / `limits.max_turns_exceeded` / `limits.max_cost_exceeded` / `limits.max_tokens_exceeded`,已做的工作作废;`POST /v1/tasks` 答 200 终局 `failed` 体。
103
+ 本版:行停在 `suspended`(无失败码;`result.terminal.kind: "paused"`、`gate.kind: "resource_limit"`、不带 `token`),会话保持占用,(`POST /v1/runs` 提交的 run)`GET /v1/runs/:id/events` 的尾帧是 `suspended`;
104
+ `POST /v1/tasks` 答停驻回执 `{status: "suspended", taskId, sessionId}`(与普通任务的同步停驻同形);`POST /v1/assistant/tasks/:taskId/resume` 续回同一条行,续完仍过验证门。
105
+ 不变的:`cascade:true` 任务不带 opt-in,撞限仍 `failed`;验证器自己那一腿(引擎另铸它的 spec,不带 opt-in)撞限仍失败;抢占(`POST /v1/assistant/tasks/:id/preempt`)对 verify 任务的首片仍答
106
+ 「not preempt-eligible」的 no-op(续跑片接抢占信号);没开 `RESOURCE_SUSPEND` 的部署零变化。
107
+ 另:跨片总额三旋钮(`RESOURCE_SUSPEND_TOTAL_TOKENS` / `_TOTAL_BUDGET_USD` / `_MAX_SLICES`)与 `RESOURCE_SUSPEND_TTL_SEC` 对 verify 任务和普通任务同一份供值;`GET /v1/runs/:id` 的 `crossSliceUsage`
108
+ 因此也出现在配了总额的 verify run 上 —— verify 是只回结果的组合腿、没有逐 turn 落账的流,running 期的 `spentTokens` / `spentMicroUsd` 是上一次停驻时落下的量(首片为 0),别当「还没花钱」读;同步 `POST /v1/tasks` 提交的 run 提交腿不写这本账(与同步提交的普通任务同形),停驻前那一片永不进账。
109
+ 嵌入方:`resourceSuspendOptIn` 的入参 `isVerify` 删除(`src/resource-suspend.ts`,不在包根出口;改本仓源码的人看这里)。
110
+ — **谁需要**:开了 `RESOURCE_SUSPEND` 和 durable checkpoint、用 `verify:true` 提交的任务可能撞预算 / turns / 墙钟的部署 —— 撞限不再丢掉整条已做的工作。
111
+ — **谁受伤**:把「verify 任务撞限 ⇒ `failed` + `limits.*`」当信号(重试 / 告警规则读上面四个码)的调用方 —— 修后同一提交停驻等续跑;同步 verify 调用方的 200 体换成停驻回执,改按回执轮询
112
+ `GET /v1/runs/<taskId>`;停驻期间同会话再提交 / `DELETE /v1/sessions/:id` / 换绑设备 / 会话同步都答 409(先续跑或取消);开着 resource-suspend 时这类任务的单片花费只在边界上判
113
+ (引擎的流中途 $ 投影取消一臂自动关,与普通任务同),单片最多多烧一个 turn。
114
+ — **补偿**:`RESOURCE_SUSPEND` 关掉即整个回到「撞限 `failed`」(部署级,含非 verify 任务);`RESOURCE_SUSPEND_TTL_SEC`(缺省 30 天)收回弃置的停驻;`RESOURCE_SUSPEND_TOTAL_TOKENS` /
115
+ `_TOTAL_BUDGET_USD` / `_MAX_SLICES` 给**一条腿**的续跑链封顶(引擎的跨片账只跟着一次运行的续跑走:验证门的每一轮修复是引擎另起的一次运行,账从零起,总额整份重新给它 —— 实现腿一条链、每一轮修复各一条链,verify 任务没有跨腿的总额);`POST /v1/runs/:id/cancel`。刻意不加逐任务的「verify 撞限就失败」旋钮(那是第二条规则)。
116
+ — **回滚**:本版不写新列、不迁数据;回退之后本版留下的停驻行仍是普通的 `resource_limit` 停驻行,可用 `POST /v1/assistant/tasks/:taskId/resume` 续或取消(回退形上未实跑)。
117
+ 11. **请求自带的 MCP / A2A 声明里写着引擎永远不发的头 ⇒ 新提交 400(行为收紧;wire 码不新)**:`mcpServers[i].transport.headers` 的件头名是 MCP 传输自己写的头
118
+ (`content-type` · `accept` · `mcp-session-id` · `mcp-protocol-version` · `last-event-id`,任何大小写)、同一头名两个拼写、件头名撞 `principalHeader`(`a2aPeers[i].headers` 后两形同)⇒
119
+ `400 request.field_invalid`,拒句点名 `mcpServers[i].transport.headers` / `a2aPeers[i].headers`、只说规范化小写的头名,不带值;`POST /v1/capabilities/mcp/probe` 同拒同句。
120
+ 上一版:提交照收、那一台挂上,此后每一次发送 `credential_unavailable`。身份头名本身撞属主的 400 不变(同一份声明里件头也撞时,点名的是件头那一处 —— 判官先判件头)。件里名叫 `connector-assertion` 的头照收。
121
+ — **谁需要**:自带 MCP / A2A 头的调用方 —— 提交即知是哪一格。
122
+ — **谁受伤**:带这三形之一的提交整单 400(壳的 `.mcp.json` 里 http 条目写了 `Content-Type` / `Accept` 头的尤其);升级前停驻、请求体 `a2aPeers` 的对端带后两形的任务,续跑时那一条对端不挂
123
+ (运维 warn `a2a_injection_dropped` 点名;上一版挂上、每次发送失败)。MCP 的存量停驻体续跑照旧挂上、由引擎在发送时拒那一台。
124
+ — **补偿**:删掉那只头(MCP 传输自己写 `content-type` / `accept` 与会话头)、同名只留一个拼写、身份头换个名。**回滚**:回到上一版即回到「提交照收、运行期才见」(零数据面)。
125
+
126
+ 12. **执行环境的家目录被证:声明(`REMOTE_EXEC_HOME_DIR`)与车道出厂答案在每只环境开起来时与环境里的 `$HOME` 对证,对不上 ⇒ 那只环境拒起(行为收紧;安全;wire 零新键、零新码)**:
127
+ 上一版 `k8s` / `local-docker` / `ssh` 已对证;本版起 `adb` / `e2b` / `host` 同一只判官、同一组拒句。拒句点名主张、实测值与改法。升级前逐车道核一次:
128
+ ① **`adb`** —— 声明了 `REMOTE_EXEC_HOME_DIR` 的部署:设备 shell 里 `echo $HOME` 的结果必须与它一致(去尾斜杠后逐字比);不一致 ⇒ 首连拒(`connect_failed`),设成实测值或删掉声明
129
+ (删掉后首连实测填座;`~/` 形规则的下单门只认声明,删声明的部署 `~/` 规则在提交时 422)。设备 shell 没有 `HOME` / 答空串 ⇒ 声明在场时拒,删掉声明即回到「座缺席 + 一行 warn」。
130
+ ② **`e2b`** —— 不声明时主张是 `/home/user`(基础模板的用户;2026-10-29 在真沙箱上实测一致:缺省模板的用户是 `user`、`$HOME` = `/home/user`);自定义模板换了用户的部署,沙箱里 `$HOME` 不是 `/home/user` ⇒ 建沙箱时拒(`connect_failed`,沙箱随即收掉):
131
+ 设 `REMOTE_EXEC_HOME_DIR=<沙箱里 echo $HOME 的结果>`。已挂起的会话恢复时同样对证,对不上 ⇒ 沙箱重新挂起(快照留着),改对配置后续跑。每只沙箱建起来 / 恢复时多一次 `commands.run`。
132
+ ③ **`host`(含 `run-local`)** —— 主张(声明,缺席时 = 服务进程的家目录)必须等于子进程拿到的 `HOME`(继承面 + 会话 `settings.env`)。按旧文档把声明指向账户家而 `HOME` 指别处的部署,
133
+ 或会话 `settings.env` 里写的 `HOME` 与主张不等的会话 ⇒ 那只环境拒起(命令面 `shell_unavailable`、文件面 `target_unavailable`、连接 `connect_failed`):删掉声明(或设成 `HOME` 的值),或去掉会话里的 `HOME`。
134
+ 子进程 env 里没有 `HOME`(如 `inheritEnv` 名单不含它)⇒ 读数是账户的家目录(子进程 shell 对 `~` 的展开),服务进程自己的 `HOME` 指别处时对不上即拒。
135
+ win32 宿主:盘符形是绝对路径,`\` 与 `/`、大小写不计。起服时铸的 worktree 基环境同样被证,对不上时孤儿 worktree 清扫不跑(清扫本就尽力而为,不挡起服)。
136
+ ④ **`device`** —— 读不了家目录,声明即座(与上一版同);声明在场时起服多一行 warn `execution_lane_home_unmeasured`(`provider` + `note`,点名声明值与「未实测」)。
137
+ ⑤ **远端车道文件面「连不上 / 拒开」的码 `unknown` → `target_unavailable`**(k8s / local-docker / adb / e2b / ssh;动作从未开始、什么都没落下):引擎不再把它读成「任务根被删了」,
138
+ Bash 工具结果里是连不上的原因(含家目录的拒句)。按文件错误码 `unknown` 认「连不上」的告警 / 脚本改认 `target_unavailable`。
139
+ ⑥ **内部模块**(都不在包根出口,嵌入方零动作;改本仓源码的人看这里):适配器的家目录配置多一位 `homeDirSource: "declared" | "lane"`(缺席 = `"declared"`),只影响拒句的改法措辞,
140
+ 部署给适配器的两位只由 `buildLaneHomeClaim(config)` 铸;e2b / host 适配器不给 `homeDir` 时在环境开起来时实测(上一版缺席即缺席);起服句 `buildUndeclaredHomeNote` 换成 `buildLaneHomeBootNote`。
141
+ — **谁需要**:多用户部署、镜像换代后家目录变了而声明没跟上的部署、`e2b` 自定义模板、`host` 上会话改 `HOME` 的部署 —— `~/` 规则不再静默守错目录。
142
+ — **谁受伤**:主张与真实 `$HOME` 对不上而上一版照跑的部署(上面 ①–③),升级后每只环境拒起。
143
+ — **补偿**:拒句给出改法;回滚到上一版即恢复照单全收(零数据面)。
144
+ 13. **记忆诸口答在请求点名的层住的那只店上;两店部署上条目 id / 店级账本的请求要带层座 `scope`;会话 id 两口不必带;个人层条目本版不经抹除口抹除(行为变更;修复;wire 加性)**:file 记忆部署上,类型化个人层(`user:` / `userproj:` / `org:`)
145
+ 住在个人挂载上的另一只店(`<引擎根>/personal/memory`),会话写它、读它的也是那一只;上一版运维面(出处、抹除、外源标记三口、会话记忆状态、会话自助抹除)、bundle 导出 / 导入、
146
+ 整理一律答在部署的店(`<引擎根>/memory`)上 —— 对个人层是错的答案(抹除收执说擦了、下一个会话照读得到;记忆状态答 0;导出的包是空的;导入的落在会话不读的店)。
147
+ 本版每个动词答在请求点名的层住的那只店上:点名层的请求按点名的层(导出的 `scopes`、导入包的 `scopes`、外源列表的 `scopes`、抹除的 `select.scope` / `expectedScopes`、整理的层);
148
+ 条目 id 与店级账本的动词(出处、清标账、清标、`select.ids` 而不带 `expectedScopes` 的抹除)多一个可选层座:GET 口查询串 `?scope=<层键>`,POST 口体 `"scope": "<层键>"`(抹除口不加键,用 `expectedScopes`)。
149
+ 会话 id 的两口(会话记忆状态、会话自助抹除,以及 `select.sessionId` 的 operator 抹除)不点名层时不拒 —— 一只会话可以跨两只店:记忆状态读本部署的每一只店(至多两只)再合成一份
150
+ (计数相加、最近一次取最大、任一店有采集记录即 `captureOptedOut: true`、任一店读不出 ⇒ 那一键缺席,不补 0 / false;只有一只店时就是那只店的答案);按会话抹除落部署的店。
151
+ 层座仍可给(会话自助抹除在体里、记忆状态在查询串),给了就只答那一层住的店。
152
+ **抹除只在部署的店上执行**:抹除 `requestId` 的幂等判(重放收敛、同一 id 换了选择子 ⇒ `409 memory.erasure_selector_mismatch`)记在每只店自己的证据链上,而部署还没有跨店的抹除请求身份 ——
153
+ 所以落到个人店的抹除(点名的层住在个人挂载上;或按会话抹除而这只会话在个人店里有贡献、或个人店的账读不出)答 `409 memory.erasure_store_unjudged`,什么都没删、什么都没记。
154
+ 这条护栏是计划删除的(不是过渡双读):引擎给出部署级的抹除请求身份那一版,本服务删掉它,个人店上的抹除随之开放。
155
+ — **谁受伤**:本部署点名的层(`MEMORY_SCOPE`〔单用户〕、`MEMORY_SYNC_SCOPE`、登记簿项目的种子层、`MEMORY_CONSOLIDATION_SCOPES`)里有个人平面键的 file 部署 ——
156
+ ① 不带层座的条目 id / 店级账本请求上一版 200(答在部署的店上),本版 `400 request.memory_layer`(句子点名哪几层住哪只店);一次导出 / 外源列表点名的层跨两只店 ⇒ 400,按店拆成两次;
157
+ ② 抹除个人层条目的请求:operator 抹除点名个人层 —— 上一版 200(落在部署的店上,对个人层是空擦),本版 `409 memory.erasure_store_unjudged`;
158
+ 会话自助抹除(不带层座)而这只会话在个人店有贡献(或个人店的账读不出)—— 上一版 200:真擦掉这只会话在部署的店里的那一半(项目平面的层),个人店那一半原样、收执不提它;
159
+ 本版 `409 memory.erasure_store_unjudged`、一条都不擦(两店都有贡献时,上一版擦掉的部署店那一半本版也不擦了);
160
+ ③ 会话记忆状态上一版只数部署的店(写进个人层的那一半读成 0),本版是两只店的合计 —— 数字会变大,这是改对了。
161
+ 引擎读不出的层键(⇒ `400 request.memory_layer`)在导出 / 同步 / 整理口上对**任何**部署(含单店)都从上一版的 200 / 500 变 400。
162
+ 除这一条外,单店形不受影响、答法逐字同上一版 —— 单店形 = SQL 记忆后端,或 file 记忆后端而配置不点名个人平面键**且请求不点名个人平面的层**(缺省 `local` 即此形)。
163
+ file 部署上请求自己点名个人平面的层(例:operator 抹除 `select.scope: "user:<P>"`)不在此列,配置不点名个人平面键也一样:那一层住在个人挂载上的店 ⇒
164
+ 抹除 `409 memory.erasure_store_unjudged`(上一版 200,答在部署的店上;拒之前个人挂载上的店已被打开,挂载目录不在时会建出),其余动词答在那只店上(上一版答在部署的店上)。
165
+ 自建 `ServiceDeps` 并自己给 `sessionMemoryStatus` 的嵌入方:面形改为先定店 `storesAt(at?) → readonly { controlPlane, status(sessionId) }[]`(不带层座 ⇒ 本部署的每一只店;TypeScript 编译红即通知)。
166
+ — **处置**:运维脚本 / 控制台在这类部署上给条目 id / 店级账本的请求带上层座(要答的那一层);跨店导出拆成每店一次;引擎读不出的层键改成读得出的键。
167
+ 会话所有者的客户端(记忆状态 / 自助抹除)不需要改请求形;两店部署上自助抹除答 409 的那一形(这只会话在个人店有贡献)要按 409 处理 —— 上一版这一形 200、擦掉部署店那一半,本版一条不擦;
168
+ 要先擦掉部署店那一半,带层座 `scope` 点名一个住在部署的店上的层(收执只覆盖那只店,见下面已知限制 ②)。
169
+ 个人层条目本版没有抹除口可用 —— 上一版也没有(它的收执不覆盖个人店),本版改成落到个人店的抹除在任何删除之前响亮拒。
170
+ 嵌入方按新面形实现 `storesAt`:单店的实现返回一只元素的数组,答法与上一版同。
171
+ — **升级后看**:修前在部署的店上做过的操作不会被补做 —— 修前「擦掉」的个人层条目仍被会话读得到,本版同样擦不了(`409`),等引擎给出部署级抹除请求身份的那一版;
172
+ 修前导入落进部署店的个人层条目留在原处、没有读者(推断),要它们进个人店就从原包按本版重新导入。
173
+ — **已知限制**(本版抹除护栏与店集的边;引擎的部署级抹除请求身份 / 部署级读口到货后收):
174
+ ① 按会话抹除(会话自助口,或 operator 的 `select.sessionId` 不带 `expectedScopes`)已在部署的店上执行过,这只会话之后又往个人店写过 ⇒ 原样重放同一个 `requestId` 答 `409 memory.erasure_store_unjudged` ——
175
+ 拒句的「什么都没删」说的是这一次调用,第一次的删除照旧有效;要拿到收敛的应答,在会话自助口带层座 `scope` 点名一个住在部署的店上的层(例:`local`)重放同一个 `requestId`:
176
+ 选择子不变,引擎按第一次钉下的 id 集重答一张新收执(`at` 是这一次的;托管链完整时第一次删掉的条目列在 `erasedPreviously`)。operator 口没有层座键,这一序列上的这条路只在会话自助口。
177
+ ② 会话自助抹除带层座、而那一层住在部署的店上 ⇒ 不过按会话的那道判:落部署的店执行、答 200,收执只覆盖部署的店(层座不进引擎、不进收执),这只会话在个人店里的那一半原样、收执不提。
178
+ ③ 会话记忆状态的合成与按会话抹除的 409 判只看本部署此刻点名的层住的店:换过 `MEMORY_SCOPE`(或同步层、登记簿种子层、整理层)、不再点名个人平面键之后,
179
+ 留在个人挂载那只店里的会话贡献不在其列 —— 状态里读不到那一半,按会话抹除照常 200 而那一半原样(与上一版同形)。
180
+ ①② 随引擎的部署级抹除请求身份一并收;③ 随引擎的部署级读口改为按持久化的平面枚举。
181
+ — **回滚**:回到 7.139.x 各口回到部署的店上(层座键被忽略的口照旧 200 —— 答案对个人层仍是错的,个人层的抹除又变回空擦)。
182
+ 14. **订正 7.138.0 节第 23 条 ⑩ 的「扣留次序」:引擎 7.60.0(本服务 7.139.0 起)是先记后判 —— 被读器拒的座答里认作凭据的值照样进扣留表(文字订正;零行为变更)**:
183
+ 7.138.0 节第 23 条 ⑩ 写的是「先过读器、放行了才记 —— 被读器拒的形的值不进扣留表:那一台失败,环境里同值的变量仍交给 host shell 子进程」。
184
+ 那一句在当时的引擎 7.59.0 上为真;7.139.0 起提货的引擎 7.60.0 恢复了先记后判,7.139.0 节没有写这一变化。现行次序:座答里认作凭据的值 ——
185
+ http 头按凭据词表选中的头,按所写的原值与传输会发出的值各读一份;stdio 件按 env 项的读法 —— 在读器判形**之前**就记进扣留表;空值不记;一个扣不住的值不挡别的值,整份答案随后被拒。
186
+ 所以读器随后拒的形(件值含 CR / LF / NUL、头名不是 HTTP token、两个头名只差大小写、变量名不是标识符形)只让那一台失败,其中认作凭据的值已在表里 ——
187
+ 服务进程环境里同值的变量**不再**交给 host shell 子进程。
188
+ **消费方动作**:无(只改文字,运行时没有变化)。⑩ 的补偿里「件值别与长期留在服务进程环境里的变量同值而又带读器拒的形」不再是防漏的必要条件(同值的变量已被扣下);
189
+ 名册 `headerRefs` 指向的变量值带尾换行时那一台仍失败,去掉那个换行照旧是让它能用的办法。
190
+
10
191
  ## 7.139.0 —— 执行放置成为根会话行上的一格:🔴 SQL 后端 `session_meta` 加八列、`device_session` 表退役、`approval_ask` 加一列 `execution_lane`(本服务起服时自己改表;升级前备份、先停光全部旧副本再起本版;回滚只有恢复备份)· 路由 `GET /v1/devices/sessions/:id` 删除(BREAKING,wire;换读 `GET /v1/sessions/:id/execution-placement`)· 新口 `POST /v1/sessions/:id/children/retire` · fork 可带键重试 `{forkId, forkNonce}`(wire additive)· 四只新 409(`conflict.session_mirror` / `conflict.session_writer` / `conflict.fork_*` / 活子代)与拒体新顶层键 `forkPath` / `boundLane` / `children` / `retirePath`(行为面)· 会话行条件写 `expectedRowTag` ⇒ `409 conflict.session_row_changed`(wire 加性)· 🔴 记忆同步:升级后每一层停同步直到运维对该层游标做一步 · 请求键 `rewindFiles` 退役(wire BREAKING;新提交 400)· `POST /v1/rules/cc-import/prepare` 的 200 体少键 `translated`(wire BREAKING,读侧)· 后台行多可选键 `sessionId`(wire 加性)· 旁问路由 400 只给 `config.unknown_role`(行为变更)· 声明判官的拒句不再回显调用方写的名(运维面)· 部署 mod 包内核契约号 6(`contract: 5` 起服拒)· 四只新运维通告码不上用户流 · 沙箱带外 env 名单点到本服务自有凭据名 ⇒ 起服拒(`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` / `K8S_SANDBOX_ENV`;安全,行为收紧)· k8s 车道 `K8S_NAMESPACE` 必设(部署面,行为收紧)· 模型目录 `apiKeyEnv` 点到名单型旋钮正在交出的名 ⇒ 该候选整拒(安全)· `CONFIG_PROVIDER=remote` 无中心地址 / `RETENTION_MODE=enforce` 缺天数或节律 ⇒ 起服拒(行为收紧,fail-closed)· 会话规则 / 持久规则桶文法戳 7(升级序:先升全部读者再放写)· 执行环境写入改「暂存 → 一次提交」(七条车道一条规则;行为面)· 本机宿主车道 workflow 子代 `isolation: "worktree"` 的已知变化(E10,引擎 7.61.0 收)· 嵌入方类型面 BREAKING 多处(`RunnerDeps.peerSeat` 三员对象 · `createHttpServer` 的 `authorize` 席必填 · `resolveSpec` 不再写 `sessionId` · 设备店绑定四法换两只放置写 · 停驻赎回腿的会话店必须带执行席、`root` → `rootOccupant` · `StoreBackend` 问店行与迁移报告多键)· 契约包 settings-schema 15.0.0 · 引擎 7.60.0
11
192
 
12
193
  1. **🔴 记忆同步(`MEMORY_SYNC_URL` 设了的 file 记忆部署):升级后每一层都停同步,直到运维对那一层的游标做一步**:
package/USAGE.md CHANGED
@@ -312,7 +312,7 @@ MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;词
312
312
 
313
313
  | 旋钮 | 谁触发、什么时刻判 | 拒/停的形 | 能打断在跑的 run 吗 |
314
314
  |------|------------------|-----------|--------------------|
315
- | `MAX_TASK_COST_USD` | 引擎(core)按**这一片任务**的累计花费判:首个模型调用前的 pre-call 估算 + turn 结束回查;**未开** `RESOURCE_SUSPEND` 时另有流中途投影取消(开了 resource-suspend 这一臂自动关,只在边界判) | 未开/不合格 ⇒ 终态 `failed` + `errorCode: limits.max_cost_exceeded`(HTTP 仍 200 / SSE `done` 帧带码);**开了 resource-suspend 且合格 ⇒ `suspended` + `resource_limit` 卡**(可续跑,不是失败)——消费方两种终态都要认 | ✅ 能,但只封**单片**:一次 park→resume 会重开满窗(见下条「per-slice 窗 vs 跨片总额」) |
315
+ | `MAX_TASK_COST_USD` | 引擎(core)按**这一片任务**的累计花费判:首个模型调用前的 pre-call 估算 + turn 结束回查;**未开** `RESOURCE_SUSPEND` 时另有流中途投影取消(开了 resource-suspend 这一臂自动关,只在边界判) | 未开/不合格 ⇒ 终态 `failed` + `errorCode: limits.max_cost_exceeded`(HTTP 仍 200 / SSE `done` 帧带码);**开了 resource-suspend 且合格 ⇒ `suspended` + `resource_limit` 卡**(可续跑,不是失败;`verify:true` 任务的实现腿与修复轮同样合格,`cascade:true` 任务不合格)——消费方两种终态都要认 | ✅ 能,但只封**单片**:一次 park→resume 会重开满窗(见下条「per-slice 窗 vs 跨片总额」) |
316
316
  | `MAX_PRINCIPAL_COST_USD`(+ `COST_QUOTA_WINDOW_SEC`) | **HTTP 提交面**在受理请求**之前**读该 principal 桶内累计。挂门的是**任务/run 族**:`/v1/tasks`、`POST /v1/runs`、steer/resume/wake、workflows、leader、a2a,以及 park 后赎回时开的续跑腿(⚠️ 例外见下:operator-only 的记忆整合口不在此列) | `429` + `errorCode: limit.cost_quota_exceeded` + `Retry-After` 头 + 体 `{usedMicroUsd, limitMicroUsd, retryAfterSec, windowResetsAt}` | ❌ **不能**。跑起来之后不再回查:越顶那张单会**跑完**,天花板从**下一次提交**起生效 |
317
317
  | `USAGE_WINDOWS[].maxCostUsd`(§9.2) | 引擎在**每个 turn 边界**把累计花费记进跨任务账本再回查窗;提交面另有同店同键的快速门 | 基建合格 ⇒ `suspended` + `checkpointGate.reason=usage_window` + `resumeAfterMs`(等窗放行原样续跑);不合格 ⇒ `failed` + `errorCode: usage.window_exhausted` + `retryAfterMs`;提交面 ⇒ `429 usage.window_exhausted` | ✅ 能,且是唯一按**跨任务累计**花费中途停的一根(第一根按的是这一片自己的额度,管不到租户总账) |
318
318
 
@@ -431,7 +431,7 @@ MODEL_ID=<your-model-name> MODEL_CHEAP_ID=<your-cheap-model-name>
431
431
  存量中心配置里的 `roles.team` / `roles.synthesize` 由 settings-schema 的一次性迁移搬走,side query 带 `modelRole` 表外词(含 `advisor`)⇒ **400**
432
432
  `request.field_invalid`(不再回落主模型;带了 `model` 也一样拒)。要给委派子代配模型就绑 `subagent`,主任务绑 `default`。
433
433
  - 调用方可在 `objective` 里 `@<模型名>` 选模型,**只认已配置的名单**(`MODEL_ID` / `MODEL_CHEAP_ID`,或目录条目)——注入不了 `baseUrl`/`apiKey`;无 `@` → 默认模型;`@` 点中一条已发布但本部署不可用的目录条目 ⇒ 400 `request.model_unavailable`。
434
- - **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision,…}],default,defaultModel,droppedEntries}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源;`reasoning` / `vision` 两列是**三态**:声明了给布尔,**未声明 = 键缺席**(7.131.0 起;env 部署不设 `MODEL_REASONING` / `MODEL_VISION` 就是未声明,没有 `true` 缺省 —— 需要思考的模型显式写 `MODEL_REASONING=true`,纯文本模型写 `MODEL_VISION=false`;缺席时引擎对图收、对思考档不发),契约 §A.1d;`droppedEntries`(7.123.0 起恒在场,零条 = `[]`)是本代目录里被读腿逐条丢掉的条目(下标 + 闭集原因词 + 可披露身份),契约 §A.1d。 7.126.0 起另有**可选**顶层键 `candidateRejected: { domains, at, source }`:最近一次配置候选被候选判官整拒时在场(`domains` = 判形失败的配置域名,`source` = `local` 本机 `config.d` / `remote` 中心,`at` = 判下它的时刻)—— 在场就说明这份目录是回落的那一份(整份候选没收,候选里的模型一个都不在),真因域在 `domains` 里;后来的候选被判 clean 即缺席;dry-run 姿势(web-admin 腿 compare-only)恒缺席(拒判只走日志)。**缺席不等于配置一定干净**(也可能是更早的 server)。只含域名 / 时刻 / 源形态,拒因句与文件路径只在引擎日志 `config_candidate_rejected` 里,契约 §A.1d。 7.133.0 起另有**恒在场**的顶层键 `modelPlane: { servedTable, catalog, refusalCode?, gap? }` —— 壳问 server,不猜:`servedTable`(`"env"` | `"catalog"`)= 此刻服务哪张模型表;`catalog`(`"absent"` | `"adopted"` | `"refused"`)= 最近一份目录候选在两道判官手里的结局(`refused` = 候选判官整拒,或模型面组拒;`adopted` 说的是「没有被判官整拒」,不是「最新候选已落地」,后者问 `/health` 的世代账;没有 LKG 时服务的是 env 表,有 LKG 时目录表仍在服,谁在服归 `servedTable`;逐条被拒的条目不算整拒);`refusalCode` / `gap` 是起服路由判官(`judgeServedModelRoute`)对当前 config 的判决,通过 ⇒ 两键缺席(进程起来了,正常缺席;自建装配 / 不拒启的入口可能在场),不带拒因句。只在起服后可答,没有起服前的预判口;新键追加在应答最末。契约 §A.1d。 7.135.0 起另有**恒在场**的顶层键 `aliases: [{ name, atMentionable? }]` —— `model` 被认、却不是 `models` 行名的每一个词:`default` 别名(服务表有缺省模型才在)、按部署档位绑定铸出的档位词 / CC 别名 / `best`、以及被认的上游 id 写法;成员资格由受理口的判官逐词定(服务端不写词表)。判受理一条:`model` 的值是某一行或某一别名的 `name`(大小写敏感),且那一项的 `atMentionable` 不是 `false` ⇒ 过模型门;其余 ⇒ 400(不要再拿行的 `id` 推)。`atMentionable` 与行同一只判定、同一条在场律(`atMention` 不是 `all` 才出键)。零条 = `[]`,缺席 = 更早的 server(档位词 / `default` 判「说不清」)。契约 §A.1d。
434
+ - **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision,…}],default,defaultModel,droppedEntries}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源;`reasoning` / `vision` 两列是**三态**:声明了给布尔,**未声明 = 键缺席**(7.131.0 起;env 部署不设 `MODEL_REASONING` / `MODEL_VISION` 就是未声明,没有 `true` 缺省 —— 需要思考的模型显式写 `MODEL_REASONING=true`,纯文本模型写 `MODEL_VISION=false`;缺席时引擎对图收、对思考档不发),契约 §A.1d;`droppedEntries`(7.123.0 起恒在场,零条 = `[]`)是本代目录里被读腿逐条丢掉的条目(下标 + 闭集原因词 + 可披露身份),契约 §A.1d。 7.126.0 起另有**可选**顶层键 `candidateRejected: { domains, at, source }`:最近一次配置候选被候选判官整拒时在场(`domains` = 被判官整拒点名的配置域名 —— 判形失败的域、本机 `config.d` 里读不出的文档所在的域、带事实的退役域,`source` = `local` 本机 `config.d` / `remote` 中心,`at` = 判下它的时刻)—— 在场就说明这份目录是回落的那一份(整份候选没收,候选里的模型一个都不在),真因域在 `domains` 里;后来的候选被判 clean,或配置源回到已应用的那一代(`config.d` 原样改回 / 中心退回那一版,日志 `config_source_back_to_applied`)即缺席;dry-run 姿势(web-admin 腿 compare-only)恒缺席(拒判只走日志)。**缺席不等于配置一定干净**(也可能是更早的 server)。只含域名 / 时刻 / 源形态,拒因句与文件路径只在引擎日志 `config_candidate_rejected` 里,契约 §A.1d。 7.133.0 起另有**恒在场**的顶层键 `modelPlane: { servedTable, catalog, refusalCode?, gap? }` —— 壳问 server,不猜:`servedTable`(`"env"` | `"catalog"`)= 此刻服务哪张模型表;`catalog`(`"absent"` | `"adopted"` | `"refused"`)= 最近一份目录候选在两道判官手里的结局(`refused` = 候选判官整拒,或模型面组拒;`adopted` 说的是「没有被判官整拒」,不是「最新候选已落地」,后者问 `/health` 的世代账;没有 LKG 时服务的是 env 表,有 LKG 时目录表仍在服,谁在服归 `servedTable`;逐条被拒的条目不算整拒);`refusalCode` / `gap` 是起服路由判官(`judgeServedModelRoute`)对当前 config 的判决,通过 ⇒ 两键缺席(进程起来了,正常缺席;自建装配 / 不拒启的入口可能在场),不带拒因句。只在起服后可答,没有起服前的预判口;新键追加在应答最末。契约 §A.1d。 7.135.0 起另有**恒在场**的顶层键 `aliases: [{ name, atMentionable? }]` —— `model` 被认、却不是 `models` 行名的每一个词:`default` 别名(服务表有缺省模型才在)、按部署档位绑定铸出的档位词 / CC 别名 / `best`、以及被认的上游 id 写法;成员资格由受理口的判官逐词定(服务端不写词表)。判受理一条:`model` 的值是某一行或某一别名的 `name`(大小写敏感),且那一项的 `atMentionable` 不是 `false` ⇒ 过模型门;其余 ⇒ 400(不要再拿行的 `id` 推)。`atMentionable` 与行同一只判定、同一条在场律(`atMention` 不是 `all` 才出键)。零条 = `[]`,缺席 = 更早的 server(档位词 / `default` 判「说不清」)。契约 §A.1d。
435
435
  - 不设 `MODEL_CHEAP_ID` → 所有角色 = 主模型(行为不变)。
436
436
  - `MODEL_CHEAP_ID` 写成与 `MODEL_ID` **同一个 id**(7.104.0 起)→ 那就是主模型本身:不铸 cheap 槽,所有角色 = 主模型,起服一行
437
437
  `config_env_entry_cheap_same_as_main`(同时设的其余 `MODEL_CHEAP_*` 键一并不生效)。要给同一只上游 id 第二种形(另一个价 / 思考 /
@@ -445,6 +445,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
445
445
  ```
446
446
  - 经 `RoleSpec.promptRole: "code"` 挂在**角色**上(7.137.0 起 / 引擎 7.56.0;此前是把同一段目录文本粘进 `RoleSpec.systemPrompt`),非开发角色保持中立。角色基底只有一条来源链:任务 → 请求的模型角色的预设 → 引擎委派子代的人设,**第一个说出基底的来源整个说了算** —— 任务自带 `systemPrompt`(或客户端注入)、或场景自己写了角色词(cowork 场景写 `cowork`)时任务优先;这些 run 的宿主角色是 `code`(按 `when.host.role` 条件的 overlay 自此对它们生效),基底字节与此前相同。
447
447
  - **验证门**(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`(要过程可见性用异步形)。
448
+ - **实现腿撞资源限(`RESOURCE_SUSPEND` 开着)**:`verify:true` 任务的实现腿(或某一轮修复)撞预算 / turns / 墙钟限时**停驻**而不是 `failed`:`POST /v1/runs` 的行停在 `suspended`(门 `resource_limit`,无失败码)、会话保持占用;`POST /v1/tasks` 答停驻回执;用 `POST /v1/assistant/tasks/:id/resume` 续,续完照常过验证门。验证器自己那一腿由引擎另铸 spec、不带这个 opt-in,撞限照旧失败。跨片总额(`RESOURCE_SUSPEND_TOTAL_*` / `_MAX_SLICES`)按**一条腿的**续跑链记:验证门的每一轮修复是引擎另起的一次运行,账从零起,所以 verify 任务的花费上界是实现腿那条链与各轮修复各自那条链的上界之和,没有跨腿的总额。没开 `RESOURCE_SUSPEND` 的部署行为不变(撞限 `failed` + `limits.*` 码)。停驻期间同会话再提交 / 删会话 / 换绑设备 / 会话同步都 409,先续跑或取消;被弃置的停驻由 `RESOURCE_SUSPEND_TTL_SEC` 到期收回(缺省 30 天)。
448
449
  - **记忆(文件记忆引擎,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 不提交)。
449
450
  **`MEMORY_PERSISTENCE_CAPABLE`(三态,7.14.0 起)**=**部署自述**「本机能不能把用户的『记住 X』落到持久处」,与请求键 `memoryWrite` 两轴正交(后者收紧本次运行,前者是 operator 声明;任一取否即只读方向)。缺省不设=引擎按 roster 自行推断;`true`=本部署有推断看不见的持久通道(自定义 writer / 记忆 MCP / 远程执行车道与记忆根共享挂载);`false`=强制只读披露并关掉文件工具往记忆根的写通道。不认得的词拒启。
450
451
  🔴 **`false` 自 core 5.27.0(7.14.0 提货)起还多一层——但只在 file 记忆引擎上**(`MEMORY_ENGINE_BACKEND` 未设 = 默认单机形):该会话是**受限会话**——materialize/搜索/harvest 一律按**已提交账**供给,记忆根下无事务背书的磁盘分歧既不收编也不供给,而是留盘 + 响亮点名(`restricted_divergence`,本服务把它计进 `memory_harvest_rejections_total{code}` 并 warn 一条),等下一次**非受限**会话走正常门收编。合法流程不受影响:用户手改、`git pull` 落下的删除照旧(延后,不销毁),并发的可写会话提交的变更算有事务背书。
@@ -1948,7 +1949,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
1948
1949
  | `GET /v1/capabilities/mcp[?scenario=<场景名>]` | **无需先跑 run 的逐台 MCP 状态**(现连、列工具、关掉;按调用方限速 + 30 秒复用)。答的是**某个场景**会挂哪些中心声明的 MCP 服务器:不带参数 = 这位主体 run 时的场景(**7.131.0+**:中心按主体指派的场景胜出,否则部署缺省场景;此前恒读部署缺省场景;指派悬空 ⇒ `503 state.scenario_assignment_unknown`,与提交任务时同一句;`GET /v1/sessions/:id/mcp` 与 `…/a2a` 两张会话面板同读这位主体 run 时的场景:a2a 面板悬空时同样整面 503,而 mcp 面板另有「这个会话上一次真挂上了什么」那一半(`lastLegMcp`),悬空时答 `200`、`lastLegMcp` 照答、`servers` 缺席、拒因在 `scenarioRefusal: { errorCode, error, detail }`(与状态面整面 503 的体是同一份成员,`detail` 是门拒的机读事实 `{ scenario, source }`;`servers` 缺席 = 场景这一半没答,`servers: []` = 该场景没配 MCP));`?scenario=<名>`(**7.130.0+**)= 点名场景,可见集与同场景任务 run 时是同一只解析、过同一只场景门 —— 不在册 `400 scenario_unknown`(附在册词表;空串 `?scenario=` 同此,与提交 `scenario: ""` 同答)、这位 principal 的场景白名单集外 `400 scenario_not_allowed`(附 allowlist),两者的体与提交任务时的拒逐字同形;重复给出参数 `400 request.field_invalid`(提交腿没有这一形)。场景门接缝 `scenarioGate` 是 `createHttpServer` 的必填件:自建 `ServiceDeps` 的嵌入方用包根导出的 `createScenarioGate` 铸它(`"peek"` 腿给读面),没递就是 tsc 红。老 server 忽略这个参数、回缺省场景那一份,按 `GET /v1/capabilities` 的 `version` 判。`REQUIRE_PRINCIPAL` 下无身份 `401`(先于场景门)。每一行(两条口同形)在 §G.7 的行形之外多两个可选键(**7.133.0+**):`toolNames`(这台会挂上的工具名,引擎命名空间形 `mcp__<server>__<tool>`,读数序)+ `toolNamesTruncated: true`(名单超过 200 只时只截表,`toolCount` 仍是真数;读数用 `toolCount`,别用 `toolNames.length`);该台读数里没有名单 ⇒ 两键缺席(不编 `[]`),没连上的台是在场的 `[]`;老 server 没有这两键,按缺席读。自带 `.mcp.json` 的探测口是 `POST /v1/capabilities/mcp/probe` |
1949
1950
  | `POST /v1/admin/drain` `{"actionId":"…","worker":"…","deadlineAt":…}` | **排空口**(7.121.0 起体 = settings-schema `DrainRequest`;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,或单用户部署声明了 `OPERATOR_SINGLE_USER=true`;两条出路都没有〔名单为空且没声明〕⇒ 501)。体 `{ actionId, worker, deadlineAt, scope?, expectedGeneration?, instanceId?, term? }`:`actionId` 幂等键(人手形自取,如 `manual:<uuid>`)、`worker` 本引擎的 worker 名(`SEMA_WEB_ADMIN_WORKER`)、`deadlineAt` 到期自停的 epoch ms、`scope` 本引擎的租户 scope(`FLEET_SCOPE`;不带 = 缺省 scope `global`,与没设 `FLEET_SCOPE` 的引擎相符 —— 多租引擎要带它自己的)、`expectedGeneration` fleet 成员的代际(`FLEET_GENERATION`;非成员不带)、`instanceId` 本进程身份(`GET /health` 读;不带则不比)。身份逐字段比(`worker` / `expectedGeneration` 缺席对缺席),不符 ⇒ `409 conflict.fleet_identity`(什么都不变);首次 ⇒ `200 {actionId, since, deadlineAt, state:"draining"}` 并**进入排空**(拒新提交、本副本可抢占的在飞腿当拍让出、活的审批卡改路耐久停驻、在飞归零或到期限即停);再来 ⇒ `200 … state:"already_draining"` 回显第一次的 `since` / `deadlineAt`,不重置。体坏 ⇒ `400 request.field_invalid`;`deadlineAt` 离本引擎此刻超过 `FLEET_LEASE_OUTAGE_MAX_MS`(缺省 24 h,一台实例活着而不服务的最长时长;7.122.0 起)⇒ 同码 400(什么都不变;拒句点名字段与上界的值;只在这一发会进入排空时判 —— 已在排空或硬停已在进行时任何重发都回 `already_draining`),已过的期限照收(进入即到期);嵌入宿主(无收尾链)⇒ `501 capability.drain_state_required`。没有 worker 身份的引擎(没配 `SEMA_WEB_ADMIN_WORKER`)恒 409 —— 用 SIGTERM。经本口进的排空之后,平台随后发的第一发 SIGTERM 被吸收、不缩短期限(第二发判据见「排空期的第二发信号」)。7.120.x 的 `{"reason":"…"}` 声明形与 `/health.drainReason` 已退役。 |
1950
1951
  | `GET /v1/config/catalog` | **配置目录自描述**(operator-only —— `explicitOperatorOk`:没有运维名册〔`OPERATOR_PRINCIPALS` 为空且没有单用户声明 `OPERATOR_SINGLE_USER=true`〕⇒ 501 `capability.operator_principals_required`,有名册而调用方不是运维 ⇒ 403)。逐 env 键一行:`{name, domain, type, semantics, writeLanes, effectiveLane, envHeld, envTiming, staticDefault?/derivedDefaultNote?, effectiveValue, valueClass, danger, center?{domain,path,precedence,timing,restartSlice?,managedNow,effectiveNow}}`(🔴 7.106.0 起 `center.domainExists` 删除:座位在加载期对契约 `DOMAIN_SCHEMAS` 核过域 + 路径,核不过即拒启 ⇒ 有 `center` 块 ⇔ 中心可写;readFace 四键 / `PERMISSIONS_DISABLE_AUTO_MODE` / `MODEL_DEGRADE_ON` / `_REACTIVE` 七行的座位随之删除);顶层带 `restartSlices`(重启片闭集)与 `centerDomains`(settings-schema 现行域表)。**两轴不混**:`writeLanes`=谁能写,`effectiveLane`=现在谁在生效(env-wins 族 env 占位 ⇒ center 腿 `effectiveNow:false`)。secret 类值**永不回传**(只回在场位;opaque 回在场位+长度;URL 剥 userinfo)。完备性由仓内 AST 双向对账门执法(分母=全 `src/` 生产 env 读取点)。旋钮 `CONFIG_CATALOG_ENABLED=false`(合规部署)⇒ 501 `feature.config_catalog_disabled`(路径恒挂载)+ 能力位 `configCatalog:false`。响应 `Cache-Control: no-store`。**7.57.0 起**:`enum` 行的 `effectiveValue` **恒落在该行自己的 `enumValues` 闭集内**(仓内机器门执法)——此前 `SESSION_BACKEND` 回的是**内部标签** `tidb`(自 5.0.0 起是**退役公名**,写回去 boot 拒),现归一成公名 `mysql`;`MODEL_DEFAULT_THINKING` 补上一直被解析器接受、却漏在目录闭集外的 `xhigh`,并改为回**实算值**(`off`/未设 ⇒ `null`)而不是 env 原文。 |
1951
- | `POST /v1/admin/config/refresh` | **配置手动刷新**(operator-only,与上一行同门:没有运维名册〔`OPERATOR_PRINCIPALS` 为空且没有单用户声明 `OPERATOR_SINGLE_USER=true`〕⇒ 501;名单非空而调用方不在名单上 ⇒ 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。候选被判官整拒(坏域 / 坏 prompts / 带事实的退役域 —— 后者 7.126.0 起)是这一拍的结论,不是失败:照样 200,`targetVersion ≠ appliedVersion`,拒因在 `config_candidate_rejected` 日志行;拍真的失败(配置源不可达 / 读不了 / 应用抛错)⇒ `502 internal.config_refresh_failed`。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
1952
+ | `POST /v1/admin/config/refresh` | **配置手动刷新**(operator-only,与上一行同门:没有运维名册〔`OPERATOR_PRINCIPALS` 为空且没有单用户声明 `OPERATOR_SINGLE_USER=true`〕⇒ 501;名单非空而调用方不在名单上 ⇒ 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。候选被判官整拒(坏域 / 坏 prompts / 带事实的退役域 —— 7.126.0 起 / 本机 `config.d` 里读不出的文档,门控域在内)是这一拍的结论,不是失败:照样 200,`targetVersion ≠ appliedVersion`,拒因在 `config_candidate_rejected` 日志行;拍真的失败(配置源不可达 / 读不了 / 应用抛错)⇒ `502 internal.config_refresh_failed`。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
1952
1953
  | `GET /health` | 健康(无需鉴权)。**7.67.0+** 恒带 `startedAt`(引擎进程起点 epoch ms,一次铸;与 `pid` 并列的换代锚——值变了就是换了一条命)。7.37.0+ 配置管道在场时带世代账键:`configTargetVersion`(本副本**最后见到**的配置版本,身份标)、`configAppliedVersion`(最后一次真落地的版本)、`configTargetOrdinal`/`configAppliedOrdinal`(7.38.0-rc.2 起,**收货序数**——`CONFIG_PROVIDER=local` 下 version 是内容哈希不承诺序,「改了没生效」看序数对不对齐)、`configApplyStaleMs`(target≠applied **持续**时长;收敛时键缺席)—— 编排器据此摘掉「配置持续落后」的副本 |
1953
1954
  | `GET /v1/sessions/:id/background` · `POST /v1/sessions/:id/background/stop` `{"includeRetained":true\|false}` | **会话后台任务的读口与停止口**(**7.102.0+**;能力位 `background.listFace` / `background.exitFaces`,老 server 404)。读口列**本会话**、**本副本**上的后台任务行(`{ rows: [{ id, description?, type, status, createdAt, sessionScoped, retained?, sessionId? }] }`,`retained:true` = 声明了保留的活服务,正常退出不会停它;`sessionId` = 后台 agent 行的子代会话 id,绑定之后才在);停止口「软 → 等一次 `HOST_BG_KILL_GRACE_MS` → 硬」收掉本会话的后台 shell(SIGTERM 处理器先有一次宽限跑完,之后组 SIGKILL,屏蔽 SIGTERM 的循环也活不过去;有后台行时应答慢一次宽限)并逐字返回受据 `{ receipts: [{ id, outcome }] }`:`killed` / `already_gone` / `retained_skipped`(`includeRetained:false` 留下的活服务)/ `no_pgid`(远端 / 沙箱车道没有本机进程组可发,已派普通 kill,「可能还在跑」;host 车道的 `already_gone` 只由观察得出 —— 引擎已收割组长或内核答组已空,7.103.0 起;darwin 上梯子那一枪先落地、引擎还没收割的那一拍如实答 `no_pgid`,判「收掉没有」读进程)。`includeRetained` 必填:`true` = 连活服务一起停(壳的「Exit and stop tasks」),`false` = 活服务照留(`sema kill`)。鉴权 = 会话属主或显式 operator(未知与他人同 404);停止口在无凭据写门内(没配 service 凭证且未开 `ALLOW_UNAUTHED_WRITES` ⇒ 503 `auth.service_token_required`)。`DELETE /v1/sessions/:id` 走同一只收敛(`includeRetained:false`);run 取消(Esc)**不**收后台 shell。契约 §16 |
1954
1955
  | `GET /readyz` | **就绪探针**(**7.102.0+**,无需鉴权;7.121.0 起是唯一的探针路径)。就绪 ⇒ `200 {"ready":true}`;未就绪 ⇒ `503 {"ready":false,"reasons":[…]}` + `Retry-After: 5`,`reasons` ⊆ {`draining`, `model_roster_pending`}(按优先序)。与 `/health` 的 `ready` / `readyReason` / `reasons` 同一只判;库连不上**不算**未就绪(`storeLive` 只在 `/health` 披露)。给只认状态码的**摘流**探针用(k8s `readinessProbe.httpGet`、LB 健康检查、镜像 `HEALTHCHECK`);存活探针用 TCP 探端口,不打 HTTP,见 §0「探针」 |
@@ -2207,10 +2208,13 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
2207
2208
  > (与命令同一条 shell、同一份 env;k8s 接在建工作区根的同一条命令后面,不多一次往返;adb 经设备 shell)填座,于是代码检索不再恒问人。实测缺席(没答上 / 答的不是绝对路径,含空串)⇒ 座缺席,
2208
2209
  > 引擎照旧失败关闭(上面那些递归读照旧问 / 拒),环境照开,并响一行 `execution_lane_home_undeclared`(`provider` + `note`,点名读到了什么与出路;同一部署同一句只响一次)。device 车道的设备协议
2209
2210
  > 没有家目录读数,座缺席,起服响一行同一只 warn。`~/` 形规则的下单门只认声明(提交那一刻执行环境还没开,读不到实测值):要写 `~/` 形规则就声明 `REMOTE_EXEC_HOME_DIR`。
2210
- > **声明会被对证**:k8s、local-docker 与 ssh 车道在每只执行环境开起来那一拍问一次 `$HOME`(与命令同一条 shell、同一份 env),与 `REMOTE_EXEC_HOME_DIR` 不一致(去掉尾斜杠后逐字比)
2211
- > 或问不出 ⇒ 那只执行环境不开,工具结果里的拒句点名两个值与改法(改声明,或让环境以声明的那个用户运行);环境答了的不一致记在那只环境上(此后每次回同一句,不再起容器 / pod / 不再问),
2212
- > 问不出的那一次不记、下一次重问。
2213
- > e2b / host / adb / device 车道今天不对证(声明照单全收)。
2211
+ > **声明与出厂答案都会被对证**(本版起六条车道同一只判官):k8s、local-docker、ssh、adb、e2b 在每只执行环境开起来那一拍问一次 `$HOME`(与命令同一条 shell、同一份 env;
2212
+ > adb 经设备 shell、e2b 是建 / 恢复沙箱时的一次 `commands.run`),host 读它自己组合给子进程的那份 env 里的 `HOME`(会话 `settings.env` 改了 `HOME` 也算);
2213
+ > 与主张(`REMOTE_EXEC_HOME_DIR`,或 host 的本进程家目录 / e2b 的 `/home/user`)不一致(去掉尾斜杠后逐字比)或问不出 ⇒ 那只执行环境不开,工具结果里的拒句点名两个值与改法
2214
+ > (把 `REMOTE_EXEC_HOME_DIR` 设成实测值、删掉错的声明,或让环境的 `HOME` 读主张那个值);环境答了的不一致记在那只环境上(此后每次回同一句,不再起容器 / pod / 沙箱、不再问),
2215
+ > 问不出的那一次不记、下一次重问。e2b 恢复出来的沙箱对不上时重新挂起(快照留着),不杀。
2216
+ > e2b 的出厂答案 `/home/user` 已于 2026-10-29 在真沙箱上实测一致(缺省模板:用户 `user`、`$HOME` = `/home/user`);自定义模板换了用户的,`$HOME` 若不是它,没声明 `REMOTE_EXEC_HOME_DIR` 的 e2b 部署的每只沙箱建起来就拒,把声明设成沙箱里 `echo $HOME` 的结果(声明同样被对证)。
2217
+ > device 车道读不了家目录:声明即座,起服响一行 `execution_lane_home_unmeasured`(点名声明值与「未实测」)。
2214
2218
  >
2215
2219
  > **同批顺带:场景旧名 `team` / 工具旧名 `run_team` 退役(BREAKING)。** 此前过渡窗的别名层
2216
2220
  > (`SCENARIO_ALIASES`)整体撤销:请求体里显式传 `scenario:"team"` 从「静默归一到 `discuss`」变成
@@ -3014,15 +3018,17 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
3014
3018
  **谁需要读这一节**:用 `.mcp.json` 带凭据头 / 子进程环境的单用户壳,带 `a2aPeers[].headers` 的调用方,名册里用 `envRefs` / `headerRefs` 的部署,自建 `createHttpServer` 的嵌入方(MIGRATION 7.138.0 节第 24 条)。
3015
3019
 
3016
3020
  - **件的形由引擎在作答处判,比此前严**。下列形读器拒 —— 那一台 `credential_unavailable`(提交照收、兄弟照挂、运行期才见):stdio 件名不是标识符形(含 `.` / `-`,如 `MY-VAR`)· 任一件值含 CR / LF / NUL(多行 PEM、Secret 文件的尾换行;http 头值首尾的换行此前被发送时的头规范化吞掉,现被拒)·
3017
- http / A2A 头名不是 HTTP token · 两个头名只差大小写 · MCP http 的件头名是传输自己写的头(`content-type` · `accept` · `mcp-session-id` · `mcp-protocol-version` · `last-event-id`;A2A 没有这张表)·
3018
- stdio 的秘密形件(变量名被引擎认作凭据名)的值恰等于一只每个子进程都会继承的变量(`PATH` / `HOME` 一类)的值。
3021
+ http / A2A 头名不是 HTTP token · 名册 `headerRefs` 里两个头名只差大小写、或 MCP http 的头名是传输自己写的头(`content-type` · `accept` · `mcp-session-id` · `mcp-protocol-version` · `last-event-id`;A2A 没有这张表;
3022
+ 请求体自带的这两形在受理口就拒,见下面「头属主」一条)· stdio 的秘密形件(变量名被引擎认作凭据名)的值恰等于一只每个子进程都会继承的变量(`PATH` / `HOME` 一类)的值。
3019
3023
  - **在哪看见**:MCP 的连接期 `wiring_manifest.mcp[]` 行(`status:"failed"`、`errorCode:"credential_unavailable"`、`delivered:"no"`)与调用期 `tool_end.errorCode`;`GET /v1/sessions/:id/mcp` 面板的那一台 `failed`。A2A 这一侧只有文本:会话 A2A 面板 `peers[].cardFetched:false` + `error`,run 内是工具结果的错误文本(没有机读码)。
3020
3024
  运维日志:本服务的座自己拒时(引用不在表里 / 绑定不符 / 引用种类座不答)一行 warn `peer_seat_refused { protocol, peer, reason }`(`reason` ∈ `handle_not_held` · `binding_mismatch` · `kind_env` · `kind_vault` · `kind_assertion` · `kind_unknown`),不带件值、不带引用 id;因件的形被引擎读器拒的那一台没有这一行,看上面的码 / 文本。
3021
- - **扣留次序**:引擎把座答里认作凭据的 http 头值与 stdio 秘密形件值记为自己持有的凭据值 —— 服务进程环境里同值的变量不再交给模型可驱动的 host shell(Bash)子进程(MCP stdio 子进程只继承 MCP SDK 的少数默认变量〔`HOME` · `LOGNAME` · `PATH` · `SHELL` · `TERM` · `USER`〕与座给的件,拿不到服务进程环境的其余变量)。座的答案先过读器、放行了才记:
3022
- 被读器拒的形(件值含 CR / LF / NUL、头名不是 HTTP token、两个头名只差大小写、变量名不是标识符形)的值**不进扣留表**,那一台失败而环境里同值的变量照旧交给 host shell 子进程(上一发布版先记后判);MCP 传输自己写的头名在读器之后的协议层才拒,值此时已在表里。名册 `headerRefs` 指向的变量值带尾换行时尤其要去掉那个换行。
3025
+ - **扣留次序**:引擎把座答里认作凭据的 http 头值与 stdio 秘密形件值记为自己持有的凭据值 —— 服务进程环境里同值的变量不再交给模型可驱动的 host shell(Bash)子进程(MCP stdio 子进程只继承 MCP SDK 的少数默认变量〔`HOME` · `LOGNAME` · `PATH` · `SHELL` · `TERM` · `USER`〕与座给的件,拿不到服务进程环境的其余变量)。座的答案**先记后判**(引擎 7.60.0 起):
3026
+ 认作凭据的值在读器判形**之前**就记进扣留表 —— http 头按凭据词表选中的头,按所写的原值与传输会发出的值各读一份;stdio 件按 env 项的读法;空值不记;一个扣不住的值不挡别的值,整份答案随后被拒。所以读器随后拒的形(件值含 CR / LF / NUL、头名不是 HTTP token、两个头名只差大小写、变量名不是标识符形)只让那一台失败,其中认作凭据的值已在表里 —— 环境里同值的变量照样不交给 host shell 子进程;MCP 传输自己写的头名在读器之后的协议层才拒,值同样已在表里。名册 `headerRefs` 指向的变量值带尾换行时那一台仍失败,要去掉那个换行(去掉之前那只变量已被扣留)。
3023
3027
  - **`/metrics` 两只读数**:`peer_registry_entries`(登记表现有条目数)· `peer_registry_holders`(各条目的持有数之和 —— 持有者是宿主租约与引擎:引擎拿到一份带引用的声明时持有、不再能用它拨号时放,一条腿从调用到流落定、一只留存子代从登记到离账;一只租约持有三个条目记三次)。没有过期、没有上限;在飞腿与后台子代全落定后两只回到名册基线(名册里带件条目的条数)。基线之上持续不回落 = 有作用域或引擎持有没放。
3024
- - **`principalHeader` 的名**:MCP 条目 `transport.principalHeader` 取传输自己写的头名(上面五个,任何大小写)或引擎的断言头 `connector-assertion`,A2A 条目 `principalHeader` 取 `connector-assertion` ⇒ **新提交 `400 request.field_invalid`**
3025
- (点名 `mcpServers[i].transport.principalHeader` / `a2aPeers[i].principalHeader`;拒句里的头名是引擎固定表里的规范化(小写)名,不回显调用方写的原串 / 大小写形(调用方写的恰是小写时,句里的名与所写相同))。耐久 resume 重放存量体不 4xx:MCP 那一台由引擎在拨号时拒,A2A 那一条对端整条不进(warn `a2a_injection_dropped`)。
3028
+ - **头属主(入口判)**:请求体自带的一条 MCP / A2A 声明,这次发送会带的头集合(件头 + 身份头名)受理时问引擎的属主判官一次 —— 件头名是 MCP 传输自己写的头(上面五个,任何大小写)· 同一头名两个拼写 · 件头名撞身份头名 · MCP 条目 `transport.principalHeader` 取传输自己写的头名或引擎的断言头 `connector-assertion` · A2A 条目 `principalHeader` 取 `connector-assertion` ⇒ **新提交 `400 request.field_invalid`**
3029
+ (点名 `mcpServers[i].transport.headers` / `mcpServers[i].transport.principalHeader` / `a2aPeers[i].headers` / `a2aPeers[i].principalHeader`;头名撞传输或引擎自有名时,拒句里的头名是引擎固定表里的规范化(小写)名,不回显调用方写的原串 / 大小写形(调用方写的恰是小写时,句里的名与所写相同);
3030
+ 同名两拼写与撞身份头名两形,句里是调用方所写名字的小写形(剥控制与双向字符);拒句从不带值;一份声明同时撞几处 ⇒ 点名判官报出的第一处,件头先于身份头名)。探测口同拒同句。件里名叫 `connector-assertion` 的头不撞(见下一条)。7.139.x 及以前件头的这三形新提交照收、那一台每次发送 `credential_unavailable`。
3031
+ 耐久 resume 重放存量体不 4xx:MCP 那一台由引擎在拨号 / 发送时拒,A2A 那一条对端整条不进(warn `a2a_injection_dropped`)。
3026
3032
  - **断言头不发送**:引擎的断言头是固定的名 `connector-assertion`、值由对端座作答;本部署没有断言来源,座对这一种恒拒(9.5d)。这说的是 `assertionHeader` 声明本身不产生断言头:调用方自己写在 `headers` 里、名字恰为 `connector-assertion` 的头仍按普通件处理(引擎只在它作 `principalHeader` 时保留这个名)。
3027
3033
  - **探测口与面板**:`POST /v1/capabilities/mcp/probe` 带 `headers` / `env` 的申报与任务提交走同一条路(件在这次走查的租约下登记,拨号落地即放;同样的件形判;缓存键含件);`GET /v1/capabilities/mcp` 与两张会话面板拨名册声明,递同一只座。
3028
3034
  - **补偿**:多行值改 base64 或改传文件路径,Secret 文件去掉尾换行;变量名改标识符形;件头名改非协议名;`principalHeader` 换成非协议、非引擎自有的名(例 `x-agent-principal`);秘密形变量别设成与 `PATH` / `HOME` 之类同值。
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { ADOPTION_PHASE, adoptionLockName, } from "../plugins/adoption-log-sql.js";
3
- import { policyKeyFor } from "../plugins/session-policy-store-sql.js";
3
+ import { policyKeyFor } from "../stores-sql/session-policy-store-sql.js";
4
4
  import { buildRuleOwnerKey } from "../plugins/permission-rule-store-sql.js";
5
5
  import { withAdoptionQuiesce } from "./quiesce.js";
6
6
  import { AFFECTED_CONFIG_TEMPLATES, MEMORY_PROJECT_SCOPE_PREFIXES, MEMORY_SCOPE_MAX_CHARS, NOT_MIGRATED_BY_DESIGN, REBIND_LEGS, buildVerbatimPair, rewriteMemoryScope, } from "./plan.js";
@@ -1,5 +1,5 @@
1
1
  export function ph(dialect, i) {
2
- return dialect === "tidb" ? "?" : `$${i}`;
2
+ return dialect === "mysql" ? "?" : `$${i}`;
3
3
  }
4
4
  export function buildConflictProbeSql(dialect, leg) {
5
5
  const on = (leg.residualKey ?? []).map((c) => ` AND a.${c} = b.${c}`).join("");
@@ -556,12 +556,12 @@ export declare const ApprovalCardSchema: z.ZodObject<{
556
556
  question: "question";
557
557
  plan: "plan";
558
558
  skill: "skill";
559
- shell: "shell";
560
559
  workflow: "workflow";
561
- fetch: "fetch";
562
- "file-write": "file-write";
563
560
  "file-edit": "file-edit";
561
+ "file-write": "file-write";
564
562
  "notebook-edit": "notebook-edit";
563
+ shell: "shell";
564
+ fetch: "fetch";
565
565
  generic: "generic";
566
566
  }>>;
567
567
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
@@ -710,12 +710,12 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
710
710
  question: "question";
711
711
  plan: "plan";
712
712
  skill: "skill";
713
- shell: "shell";
714
713
  workflow: "workflow";
715
- fetch: "fetch";
716
- "file-write": "file-write";
717
714
  "file-edit": "file-edit";
715
+ "file-write": "file-write";
718
716
  "notebook-edit": "notebook-edit";
717
+ shell: "shell";
718
+ fetch: "fetch";
719
719
  generic: "generic";
720
720
  }>>;
721
721
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
@@ -6,7 +6,7 @@ import { withUnattendedLeg } from "../../unattended-permission-mode.js";
6
6
  import { createBrain } from "../../brain.js";
7
7
  import { buildPricing } from "../../budget.js";
8
8
  import { RemoteContainerExecutionEnv } from "../../plugins/remote-env-e2b.js";
9
- import { E2B_SANDBOX_HOME } from "../../execution-lane-caps.js";
9
+ import { buildLaneHomeClaim } from "../../execution-lane-caps.js";
10
10
  import { createDurableAskPolicy } from "../../approval.js";
11
11
  import { runOracle as runStandaloneOracle } from "./oracle.js";
12
12
  import { makeRepairOracle } from "./repair-oracle-adapter.js";
@@ -68,9 +68,10 @@ const sh = (env) => async (cmd) => {
68
68
  return { code: r.value.exitCode, out: (r.value.stdout + r.value.stderr).trim() };
69
69
  };
70
70
  async function provisionSandbox(rt, role, cellId) {
71
+ const homeSeat = rt.e2bTemplate ? {} : buildLaneHomeClaim({ remoteExec: { provider: "e2b" } });
71
72
  const env = new RemoteContainerExecutionEnv({
72
73
  apiKey: rt.e2bApiKey,
73
- homeDir: E2B_SANDBOX_HOME,
74
+ ...homeSeat,
74
75
  ...(rt.e2bTemplate ? { template: rt.e2bTemplate } : {}),
75
76
  timeoutMs: rt.sandboxTimeoutMs ?? 600_000,
76
77
  metadata: { s1Cell: cellId, s1Role: role },
@@ -34,8 +34,11 @@ export type { RunRecord, OracleVerdicts, DeliveryDecision, CoreStatsSubset, Inte
34
34
  /** The schema version stamped into every row — the field-contract handshake with core's metric tool. */
35
35
  export declare const S1_SCHEMA_VERSION: "s1.v1";
36
36
  export type S1SchemaVersion = typeof S1_SCHEMA_VERSION;
37
- /** The INSTALLED core version, read from node_modules at load(SPEC §0 provenance-honesty——接入审计 L16:
38
- * 硬钉 "1.111.0" 在 core 升到 1.258.x 后让 harness 每行 meta.coreVersion 输出错误溯源;动态读=永不再漂)。 */
37
+ /** The INSTALLED core version (SPEC §0 provenance-honesty — a hard-pinned "1.111.0" once drifted past a core upgrade and stamped every row's
38
+ * `meta.coreVersion` with the wrong provenance). Read from core's own root export `CONTRACT_KIT_ENGINE_VERSION` — the engine's
39
+ * `package.json` version, resolved by the engine itself ("unknown" only under a bundler that severed the module from its package root) —
40
+ * not by walking the installed package's directory from here (the dependency-direction gate, `test/dependency-direction-gate.test.ts` R2,
41
+ * bans reading core's install tree by file-system path). */
39
42
  export declare const S1_CORE_VERSION: string;
40
43
  /** The arm tag as emitted on the wire (lowercase — the s1.v1 contract value; the internal `Arm` is uppercase). The
41
44
  * harness emits a SUBSET of core's `RunRecord["arm"]` (which also carries "sup-vf", an S1b ablation S1 does not run). */
@@ -1,27 +1,7 @@
1
1
  import { buildReport, trulyCorrect, } from "@sema-agent/core/bench";
2
- import { createRequire } from "node:module";
3
- import { readFileSync, existsSync } from "node:fs";
4
- import { dirname, join } from "node:path";
2
+ import { CONTRACT_KIT_ENGINE_VERSION } from "@sema-agent/core";
5
3
  export const S1_SCHEMA_VERSION = "s1.v1";
6
- export const S1_CORE_VERSION = (() => {
7
- try {
8
- const require = createRequire(import.meta.url);
9
- let dir = dirname(require.resolve("@sema-agent/core"));
10
- for (let i = 0; i < 6; i++) {
11
- const pj = join(dir, "package.json");
12
- if (existsSync(pj)) {
13
- const parsed = JSON.parse(readFileSync(pj, "utf8"));
14
- if (parsed.name === "@sema-agent/core" && parsed.version)
15
- return parsed.version;
16
- }
17
- dir = dirname(dir);
18
- }
19
- return "unknown";
20
- }
21
- catch {
22
- return "unknown";
23
- }
24
- })();
4
+ export const S1_CORE_VERSION = CONTRACT_KIT_ENGINE_VERSION;
25
5
  export function armTag(arm) {
26
6
  switch (arm) {
27
7
  case "SOLO":
@@ -5,7 +5,7 @@ export async function runAdoptionBootScan(ctx) {
5
5
  return { scanned: 0, resumed: [], stalled: [], rejected: [], failed: [] };
6
6
  const runner = createAdoptionRunner({
7
7
  store,
8
- dialect: ctx.backend?.kind === "pg" ? "pg" : "tidb",
8
+ dialect: ctx.backend?.kind === "pg" ? "pg" : "mysql",
9
9
  now: ctx.now ?? Date.now,
10
10
  logger: ctx.logger,
11
11
  });
@@ -34,8 +34,9 @@ import { createCacheMissMemory } from "../workspace-cache.js";
34
34
  import { workspaceSnapshotTimeoutOf } from "../workspace-space.js";
35
35
  import { sayEgressPolicyReading } from "../sandbox-egress-policy.js";
36
36
  import { sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-path-env.js";
37
- import { LANE_HOME_UNDECLARED_EVENT, createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
38
- import { REMOTE_EXEC_PROVIDER_WORDS, buildUndeclaredHomeNote, executionLaneHomeDir, executionLaneOf, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
37
+ import { createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
38
+ import { REMOTE_EXEC_PROVIDER_WORDS, buildLaneHomeBootNote, buildLaneHomeClaim, capabilitiesFor, executionLaneOf, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
39
+ import { warnReadDenyFloorUnkept } from "./execution-lane.js";
39
40
  function boundedSessionSetter(map, maxEntries) {
40
41
  return (sid, value) => {
41
42
  map.delete(sid);
@@ -226,8 +227,7 @@ function hostWorktreeUnwrappedRefusal() {
226
227
  }
227
228
  export function createExecutionEnv(ctx) {
228
229
  const { config, logger, metrics, taskAttachmentStore } = ctx;
229
- const laneHomeDir = executionLaneHomeDir(config);
230
- const homeDirSeat = laneHomeDir !== undefined ? { homeDir: laneHomeDir } : {};
230
+ const homeDirSeat = buildLaneHomeClaim(config);
231
231
  const homeAbsentNotice = { onHomeAbsent: createLaneHomeAbsenceReporter((event, fields) => logger.warn(event, fields)) };
232
232
  const perTaskImage = new PerTaskImageRegistry();
233
233
  const sessionEnvSelection = new SessionEnvironmentSelection();
@@ -245,7 +245,7 @@ export function createExecutionEnv(ctx) {
245
245
  if (config.remoteExec?.provider === "e2b") {
246
246
  executionEnvFactory = e2bExecutionEnvFactory({
247
247
  apiKey: config.remoteExec.apiKey,
248
- ...homeDirSeat,
248
+ ...homeDirSeat, ...homeAbsentNotice,
249
249
  ...(config.remoteExec.template ? { template: config.remoteExec.template } : {}),
250
250
  ...(config.remoteExec.timeoutMs != null ? { timeoutMs: config.remoteExec.timeoutMs } : {}),
251
251
  ...(config.remoteExec.livenessMs != null ? { livenessMs: config.remoteExec.livenessMs } : {}),
@@ -358,7 +358,7 @@ export function createExecutionEnv(ctx) {
358
358
  if (hostScheduler)
359
359
  logger.info(`R7: self-wake scheduler enabled (host lane), store=${schedulerStorePath}`);
360
360
  const hostCfg = {
361
- ...homeDirSeat,
361
+ ...homeDirSeat, ...homeAbsentNotice,
362
362
  ...(config.remoteExec.workspaceBase ? { workspaceBase: config.remoteExec.workspaceBase } : {}),
363
363
  ...(config.remoteExec.commandTimeoutMs != null ? { commandTimeoutMs: config.remoteExec.commandTimeoutMs } : {}),
364
364
  ...(hostScheduler ? { scheduler: hostScheduler } : {}),
@@ -465,16 +465,18 @@ export function createExecutionEnv(ctx) {
465
465
  if (executionEnvFactory) {
466
466
  const isolated = laneIsolated(executionLaneOf(config.remoteExec.provider));
467
467
  const suspendable = DEPLOYMENT_SHAPE_PREDICATES.suspendableHands.holds(config);
468
+ const keepsReadFloor = capabilitiesFor(config).keepsReadFloor;
468
469
  const sandboxEnvKeys = [...sandboxEnvNamesInForce(config)].sort();
469
- logger.info("remote_exec_enabled", { provider: config.remoteExec.provider, isolated, suspendable, ...(sandboxEnvKeys.length > 0 ? { sandboxEnvKeys } : {}) });
470
+ logger.info("remote_exec_enabled", { provider: config.remoteExec.provider, isolated, suspendable, keepsReadFloor, ...(sandboxEnvKeys.length > 0 ? { sandboxEnvKeys } : {}) });
470
471
  if (!isolated)
471
472
  logger.warn("remote_exec_real_system", { provider: config.remoteExec.provider, note: buildRealSystemNote(config.remoteExec) });
472
- const homeNote = buildUndeclaredHomeNote(config);
473
- if (homeNote !== undefined)
474
- logger.warn(LANE_HOME_UNDECLARED_EVENT, { provider: config.remoteExec.provider, note: homeNote });
473
+ const homeLine = buildLaneHomeBootNote(config);
474
+ if (homeLine !== undefined)
475
+ logger.warn(homeLine.event, { provider: config.remoteExec.provider, note: homeLine.note });
475
476
  if (executionLaneOf(config.remoteExec.provider) === "host")
476
477
  logger.info("task_inherit_env_honored", { honored: taskInheritEnvRefusal(config) === undefined });
477
478
  }
479
+ warnReadDenyFloorUnkept(config, logger);
478
480
  const lspProvider = config.remoteExec?.provider;
479
481
  const lspLane = executionLaneOf(lspProvider);
480
482
  const lspLaneBindsReads = lspLane !== undefined && laneBindsReads(lspLane);
@@ -1,5 +1,6 @@
1
1
  import { type CrossInvariantView } from "../config-invariants.js";
2
2
  import type { ServiceConfig } from "../config-types.js";
3
+ import { buildReadDenyFloorUnkeptNote } from "../execution-lane-caps.js";
3
4
  import type { Logger } from "../observability/logger.js";
4
5
  /** `config.d/remote-exec.json` 能写进来的车道(文件契约里不带密钥名、可 1:1 映射的两条;e2b/k8s/ssh/adb 要 NAME→值解析,尚未接线)。 */
5
6
  export declare const FILE_SOURCED_LANES: readonly ["host", "local-docker"];
@@ -28,6 +29,13 @@ export declare function composeExecutionLane(config: ServiceConfig, ctx: Executi
28
29
  * 非宿主车道零动作 —— 不解析、不装观察者。
29
30
  */
30
31
  export declare function settleHostLaneShell(config: Pick<ServiceConfig, "remoteExec">, logger: Pick<Logger, "info" | "warn">): Promise<void>;
32
+ /**
33
+ * **读地板的起服一行**:部署要求读拒表的字节地板(`READ_DENY_FLOOR_REQUIRED=true`)而最终车道的执行环境块不守 ⇒ 每条读拒表有行的 run 都在准备期拒 ——
34
+ * 起服先说清后果与出路(`warn read_deny_floor_required_unkept { provider, note }`;判据与句子的唯一属主 `buildReadDenyFloorUnkeptNote`)。
35
+ * 两个入口调同一只(与 {@link settleHostLaneShell} 同形):HTTP 服务在执行环境装配里(`boot/execution-env.ts`,有没有执行环境工厂都调),`run-local` 在宿主车道定下之后 ——
36
+ * 旋钮两个入口都递给引擎(`RunnerDeps.readDenyFloorRequired`),所以两个入口都要先说。不要求 / 车道守地板 ⇒ 零动作。
37
+ */
38
+ export declare function warnReadDenyFloorUnkept(config: Parameters<typeof buildReadDenyFloorUnkeptNote>[0], logger: Pick<Logger, "warn">): void;
31
39
  /**
32
40
  * 车道合成之后的跨域不变量 —— 表(`config-invariants.ts`)里读 `remoteExec.provider` 的那几条,boot 期 `live === next`。
33
41
  * 同步、纯判据:只读 config,不碰文件(测试可以对 `loadConfig()` 的产物直接调它)。