@sema-agent/server 7.145.0 → 7.146.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 (275) hide show
  1. package/MIGRATION.md +492 -0
  2. package/USAGE.md +218 -47
  3. package/deploy/facts/CHANGES.json +25 -0
  4. package/deploy/facts/README.md +57 -0
  5. package/deploy/facts/lanes.json +54 -0
  6. package/deploy/facts/lanes.schema.json +57 -0
  7. package/deploy/facts/sandbox-rbac.json +113 -0
  8. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  9. package/deploy/facts/sealed-key.json +9 -0
  10. package/deploy/facts/sealed-key.schema.json +52 -0
  11. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  12. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  13. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  14. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  15. package/deploy/sema-up/chart/values.yaml +7 -0
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  17. package/dist/adoption/import-limits.d.ts +6 -0
  18. package/dist/adoption/import-limits.js +7 -0
  19. package/dist/adoption/import.d.ts +62 -0
  20. package/dist/adoption/import.js +107 -0
  21. package/dist/adoption/wire.d.ts +52 -0
  22. package/dist/adoption/wire.js +9 -0
  23. package/dist/approval-ask-machine.d.ts +2 -2
  24. package/dist/approval-card.d.ts +3 -12
  25. package/dist/approval-card.js +0 -4
  26. package/dist/approval-gate-currency.d.ts +1 -1
  27. package/dist/approval-gate-currency.js +1 -1
  28. package/dist/approval-reconciler.d.ts +1 -1
  29. package/dist/boot/deployment-mods.d.ts +11 -1
  30. package/dist/boot/deployment-mods.js +15 -2
  31. package/dist/boot/device-lane.js +2 -0
  32. package/dist/boot/engine-lease.d.ts +193 -21
  33. package/dist/boot/engine-lease.js +146 -20
  34. package/dist/boot/execution-env.d.ts +4 -0
  35. package/dist/boot/execution-env.js +12 -0
  36. package/dist/boot/exit-boundary.d.ts +50 -0
  37. package/dist/boot/exit-boundary.js +32 -0
  38. package/dist/boot/exit-last.d.ts +20 -4
  39. package/dist/boot/exit-last.js +21 -4
  40. package/dist/boot/governance-seams.js +1 -0
  41. package/dist/boot/memory-consolidation.d.ts +29 -17
  42. package/dist/boot/memory-consolidation.js +26 -15
  43. package/dist/boot/reapers.d.ts +12 -4
  44. package/dist/boot/reapers.js +39 -15
  45. package/dist/boot/resolve-spec.d.ts +2 -0
  46. package/dist/boot/resolve-spec.js +38 -15
  47. package/dist/boot/runner-deps.js +1 -1
  48. package/dist/boot/session-faces.js +3 -1
  49. package/dist/boot/shutdown.js +27 -9
  50. package/dist/boot/stage-01-config.js +1 -1
  51. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  52. package/dist/boot/stage-03-store-backend.js +2 -2
  53. package/dist/boot/stage-04-stores.d.ts +1 -0
  54. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  55. package/dist/boot/stage-05-execution-env.js +3 -3
  56. package/dist/boot/stage-06-runners.d.ts +3 -0
  57. package/dist/boot/stage-06-runners.js +11 -10
  58. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  59. package/dist/boot/stage-07-capability-layer.js +7 -2
  60. package/dist/boot/stage-08-reapers.d.ts +3 -0
  61. package/dist/boot/stage-08-reapers.js +3 -3
  62. package/dist/boot/stage-09-leader.d.ts +3 -0
  63. package/dist/boot/stage-10-http-server.d.ts +3 -0
  64. package/dist/boot/stage-10-http-server.js +3 -2
  65. package/dist/boot/stores.d.ts +1 -0
  66. package/dist/boot/stores.js +35 -19
  67. package/dist/boot/workflow-orchestration.d.ts +1 -1
  68. package/dist/boot/workflow-orchestration.js +2 -1
  69. package/dist/capabilities/composite-members.d.ts +3 -1
  70. package/dist/capabilities/composite-members.js +3 -1
  71. package/dist/capabilities/scenarios.d.ts +2 -2
  72. package/dist/capability-facts.d.ts +18 -1
  73. package/dist/capability-facts.js +25 -7
  74. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  75. package/dist/config-catalog.js +13 -4
  76. package/dist/config-provider.d.ts +2 -2
  77. package/dist/config-types.d.ts +43 -4
  78. package/dist/config.d.ts +6 -1
  79. package/dist/config.js +67 -11
  80. package/dist/deleted-session-ids.d.ts +19 -0
  81. package/dist/deleted-session-ids.js +26 -0
  82. package/dist/deploy-facts.d.ts +155 -0
  83. package/dist/deploy-facts.js +94 -0
  84. package/dist/device-ws-hub.d.ts +48 -3
  85. package/dist/device-ws-hub.js +48 -2
  86. package/dist/error-code-family.d.ts +35 -0
  87. package/dist/error-code-family.js +26 -0
  88. package/dist/fleet/drain-entry.d.ts +39 -3
  89. package/dist/fleet/drain-entry.js +6 -0
  90. package/dist/fleet/fleet-bus.d.ts +2 -1
  91. package/dist/hooks/branch-transcript.d.ts +1 -1
  92. package/dist/hooks/branch-transcript.js +1 -0
  93. package/dist/hooks/classic-stations.d.ts +25 -8
  94. package/dist/hooks/classic-stations.js +29 -3
  95. package/dist/hooks/hook-runner.d.ts +33 -16
  96. package/dist/hooks/hook-runner.js +166 -73
  97. package/dist/hooks/hook-source.d.ts +14 -2
  98. package/dist/hooks/hook-source.js +8 -0
  99. package/dist/http/active-run-conflict.d.ts +1 -1
  100. package/dist/http/active-run-conflict.js +1 -1
  101. package/dist/http/admission.js +11 -1
  102. package/dist/http/checkpoint-ctx.d.ts +59 -71
  103. package/dist/http/checkpoint-ctx.js +34 -40
  104. package/dist/http/dispatch.js +18 -2
  105. package/dist/http/durable-run-leg.d.ts +5 -0
  106. package/dist/http/durable-run-leg.js +1 -0
  107. package/dist/http/execution-context.d.ts +4 -0
  108. package/dist/http/execution-context.js +9 -0
  109. package/dist/http/health-self-report.d.ts +6 -2
  110. package/dist/http/health-self-report.js +3 -2
  111. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  112. package/dist/http/memory-compliance-failure-reply.js +2 -15
  113. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  114. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  115. package/dist/http/principal-gate.d.ts +35 -12
  116. package/dist/http/principal-gate.js +16 -12
  117. package/dist/http/request-guards.d.ts +1 -1
  118. package/dist/http/request-guards.js +5 -5
  119. package/dist/http/resume-legs.d.ts +22 -0
  120. package/dist/http/resume-legs.js +26 -17
  121. package/dist/http/route-ctx.d.ts +11 -10
  122. package/dist/http/route-table.js +2 -0
  123. package/dist/http/routes/adoption.d.ts +11 -0
  124. package/dist/http/routes/adoption.js +80 -6
  125. package/dist/http/routes/agents-roster.js +1 -0
  126. package/dist/http/routes/approvals-assistant.js +2 -1
  127. package/dist/http/routes/background.js +1 -0
  128. package/dist/http/routes/capabilities.js +4 -1
  129. package/dist/http/routes/diagnostics.d.ts +9 -14
  130. package/dist/http/routes/diagnostics.js +10 -20
  131. package/dist/http/routes/engine.d.ts +31 -0
  132. package/dist/http/routes/engine.js +81 -0
  133. package/dist/http/routes/memory-bundle.js +3 -0
  134. package/dist/http/routes/memory-consolidation.js +3 -5
  135. package/dist/http/routes/memory-origin.d.ts +1 -1
  136. package/dist/http/routes/memory-origin.js +2 -4
  137. package/dist/http/routes/memory-policy.js +5 -1
  138. package/dist/http/routes/observability.js +3 -6
  139. package/dist/http/routes/runs.js +7 -3
  140. package/dist/http/routes/session-sync.js +12 -25
  141. package/dist/http/routes/sessions-list.d.ts +1 -1
  142. package/dist/http/routes/sessions.js +4 -0
  143. package/dist/http/routes/tasks.js +23 -5
  144. package/dist/http/routes/trace-usage.js +1 -1
  145. package/dist/http/run-concurrency-cap.d.ts +86 -0
  146. package/dist/http/run-concurrency-cap.js +54 -0
  147. package/dist/http/server.d.ts +15 -12
  148. package/dist/http/server.js +18 -3
  149. package/dist/http/stored-body-replay.d.ts +9 -6
  150. package/dist/http/stored-body-replay.js +19 -5
  151. package/dist/http/wire-types.d.ts +8 -3
  152. package/dist/json-body-limit.d.ts +8 -0
  153. package/dist/json-body-limit.js +2 -0
  154. package/dist/leader/diffout.d.ts +1 -1
  155. package/dist/local-data-root.d.ts +2 -2
  156. package/dist/memory-operator-faces.d.ts +9 -4
  157. package/dist/memory-scope-stores.d.ts +9 -7
  158. package/dist/memory-scope-stores.js +3 -14
  159. package/dist/memory-scope.d.ts +36 -0
  160. package/dist/memory-scope.js +32 -1
  161. package/dist/net-address.d.ts +53 -0
  162. package/dist/net-address.js +111 -0
  163. package/dist/observability/fail-open.d.ts +14 -10
  164. package/dist/observability/fail-open.js +14 -10
  165. package/dist/orchestration/workflow-notify-journal.js +2 -3
  166. package/dist/org-delivery-gate.js +1 -1
  167. package/dist/peer-directory.d.ts +6 -12
  168. package/dist/peer-directory.js +5 -1
  169. package/dist/plugins/caching-session-store.d.ts +3 -1
  170. package/dist/plugins/caching-session-store.js +3 -0
  171. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  172. package/dist/plugins/checkpoint-store-face.js +152 -0
  173. package/dist/plugins/file-run-store.d.ts +0 -6
  174. package/dist/plugins/file-run-store.js +1 -12
  175. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  176. package/dist/plugins/fork-routing-session-store.js +2 -2
  177. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  178. package/dist/plugins/local-checkpoint-store.d.ts +2 -2
  179. package/dist/plugins/local-checkpoint-store.js +2 -1
  180. package/dist/plugins/local-session-store.d.ts +28 -5
  181. package/dist/plugins/local-session-store.js +32 -8
  182. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  183. package/dist/plugins/memory-engine-pg.js +96 -214
  184. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  185. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  186. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  187. package/dist/plugins/memory-engine-tidb.js +97 -227
  188. package/dist/plugins/memory-key-guards.d.ts +1 -1
  189. package/dist/plugins/memory-origin-law.d.ts +3 -3
  190. package/dist/plugins/one-time-migrations.d.ts +32 -56
  191. package/dist/plugins/one-time-migrations.js +25 -117
  192. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  193. package/dist/plugins/permission-rule-store-file.js +8 -1
  194. package/dist/plugins/pg-pool.js +1 -1
  195. package/dist/plugins/pg-session-storage.d.ts +17 -4
  196. package/dist/plugins/pg-session-storage.js +8 -4
  197. package/dist/plugins/run-store-sql.js +2 -2
  198. package/dist/plugins/schema-ensure-legs.js +2 -2
  199. package/dist/plugins/session-fork.d.ts +31 -9
  200. package/dist/plugins/session-fork.js +3 -2
  201. package/dist/plugins/session-placement.d.ts +4 -2
  202. package/dist/plugins/sql-json-column.d.ts +5 -1
  203. package/dist/plugins/store-backend.d.ts +11 -8
  204. package/dist/plugins/store-backend.js +8 -7
  205. package/dist/plugins/store-contracts.d.ts +1 -11
  206. package/dist/plugins/store-contracts.js +0 -9
  207. package/dist/plugins/store-sweep.d.ts +63 -0
  208. package/dist/plugins/store-sweep.js +48 -0
  209. package/dist/plugins/tidb-pool.js +1 -1
  210. package/dist/plugins/tidb-session-store.d.ts +16 -3
  211. package/dist/plugins/tidb-session-store.js +8 -4
  212. package/dist/prompt-screen.d.ts +6 -9
  213. package/dist/prompt-screen.js +2 -5
  214. package/dist/rules-consent.d.ts +20 -27
  215. package/dist/rules-consent.js +82 -6
  216. package/dist/run-cancel-context.d.ts +4 -1
  217. package/dist/run-cancel-context.js +2 -1
  218. package/dist/runs.js +1 -1
  219. package/dist/sandbox-egress-policy.js +6 -11
  220. package/dist/sandbox-rbac-rules.d.ts +88 -0
  221. package/dist/sandbox-rbac-rules.js +80 -0
  222. package/dist/sealed-key-layout.d.ts +17 -0
  223. package/dist/sealed-key-layout.js +4 -0
  224. package/dist/sealed-key.js +5 -5
  225. package/dist/security.d.ts +38 -6
  226. package/dist/security.js +9 -2
  227. package/dist/session-notify-door.d.ts +5 -3
  228. package/dist/session-resident-background.d.ts +57 -0
  229. package/dist/session-resident-background.js +20 -0
  230. package/dist/session-sync-kernel.d.ts +53 -14
  231. package/dist/session-sync-kernel.js +70 -1
  232. package/dist/session-sync.d.ts +5 -3
  233. package/dist/session-workspace.d.ts +1 -0
  234. package/dist/session-workspace.js +1 -0
  235. package/dist/sighup-idle.d.ts +9 -7
  236. package/dist/sighup-idle.js +4 -5
  237. package/dist/spec-fields.d.ts +16 -0
  238. package/dist/spec-fields.js +7 -0
  239. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  240. package/dist/stored-request-env-credentials-m38.js +8 -0
  241. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  242. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
  243. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
  244. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  245. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  246. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  247. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  248. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  249. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  250. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  251. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  252. package/dist/task-settings.d.ts +59 -4
  253. package/dist/task-settings.js +50 -4
  254. package/dist/tool-approval.d.ts +2 -2
  255. package/dist/trace/core-keyset-guard.d.ts +8 -7
  256. package/dist/trace/engine-notice-wire.d.ts +1 -1
  257. package/dist/trace/engine-notice-wire.js +2 -0
  258. package/dist/trace/exit-seat.d.ts +6 -0
  259. package/dist/trace/exit-seat.js +1 -0
  260. package/dist/trace/project.js +9 -0
  261. package/dist/trace/redact.d.ts +13 -2
  262. package/dist/trace/redact.js +305 -24
  263. package/dist/trace/self-minted-wire.d.ts +326 -8
  264. package/dist/trace/self-minted-wire.js +125 -7
  265. package/dist/trace/wire-projection-faces.d.ts +1 -1
  266. package/dist/trace/wire-projection-faces.js +1 -1
  267. package/dist/usage-analytics.d.ts +4 -0
  268. package/package.json +12 -4
  269. package/scripts/drain-check-local.mjs +8 -29
  270. package/scripts/drain-check.mysql.sql +3 -24
  271. package/scripts/drain-check.pg.sql +3 -24
  272. package/skills/update-config.md +1 -1
  273. package/wire-changes/server@7.146.0.json +3221 -0
  274. package/dist/approval-batch-census.d.ts +0 -27
  275. package/dist/approval-batch-census.js +0 -27
@@ -0,0 +1,2 @@
1
+ export const MAX_JSON_BODY_BYTES = 8 * 1024 * 1024;
2
+ //# sourceMappingURL=json-body-limit.js.map
@@ -45,7 +45,7 @@ export type PullDiffResult = {
45
45
  * 而它**本就已经** `import { safeRev } from "./diffout.js"` —— 依赖边在,共享零成本。两份手抄的后果不是
46
46
  * 「多写一行」,是**单边改值后上行/pull 两腿对同一个 diff 的过/拒判定分家**:同一份补丁在一条腿上过、
47
47
  * 另一条腿上被截断,而两处都「按自己的常量」正确工作,没有任何一处会报错。
48
- * (同族先例:`checkpoint-store-sql.ts` 的 `export const TERMINAL_GRACE_MS`。)
48
+ * (同族先例:`checkpoint-store-face.ts` 的 `export const TERMINAL_GRACE_MS`。)
49
49
  */
50
50
  export declare const DEFAULT_MAX_DIFF_BYTES: number;
51
51
  export declare function safeRev(rev: string): boolean;
@@ -7,8 +7,8 @@
7
7
  * `scripts/drain-check-local.mjs`(经 `dist/local-data-root.js` 取同一只函数,缺省数据根不再自抄一份链:抄本只对了一半,
8
8
  * 设了 `AGENT_DATA_DIR` 的部署不带参数跑脚本会读到另一个目录并报「干净」)。纯叶、零反向依赖 ⇒ 脚本引它不会把整个服务装载起来。
9
9
  *
10
- * ⚠️ 与**配置根**(`configLocalRoot`:`CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`,不吃 `LOCAL_DATA_ROOT`)不是同一条链 —— 两根分家的那一形由
11
- * boot 期的 `local_roots_split` 告警说出来,本函数不改那条解析。
10
+ * ⚠️ 与**配置根**(`configLocalRoot`:`CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`,不吃 `LOCAL_DATA_ROOT`)不是同一条链 —— 两根一声不响分家的那一形
11
+ * (没给 `CONFIG_LOCAL_DIR`)由 boot 期的 `local_roots_split` 告警说出来,本函数不改那条解析。
12
12
  */
13
13
  export declare function resolveLocalDataRoot(env: Readonly<Record<string, string | undefined>>, home: string): string;
14
14
  //# sourceMappingURL=local-data-root.d.ts.map
@@ -58,7 +58,7 @@
58
58
  * core 自己响亮拒(`memory.erasure_evidence_unavailable`),那是**运行期**的诚实拒,与「换部署形态才行」
59
59
  * 不是一回事(附录 A 两条分列)。
60
60
  */
61
- import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin, type MemoryErasureAttestation, type OriginClearanceRow, type DeploymentSessionMemoryStatus, type SessionCaptureRecordStore } from "@sema-agent/core";
61
+ import { type EntryProvenanceAccount, type MemoryBackend, type MemoryEntryOrigin, type MemoryErasureAttestation, type OriginClearanceRow, type DeploymentSessionMemoryStatus, type SessionCaptureRecordStore, type SessionMemoryStatus } from "@sema-agent/core";
62
62
  import { type MemoryScopeStores } from "./memory-scope-stores.js";
63
63
  import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
64
64
  /**
@@ -249,11 +249,16 @@ export interface SessionMemoryStatusFace {
249
249
  /** 一份会话记忆状态的读法(见 {@link SessionMemoryStatusFace.readingAt})。 */
250
250
  export interface SessionMemoryStatusReading {
251
251
  readonly key: string;
252
- /** 引擎的答案,原样(引擎不抛:读不出的源 = 缺席的键)。路由只投 wire 的五键。 */
252
+ /** 引擎的答案,原样(引擎不抛:读不出的源 = 缺席的键)。路由只投 wire 的键。 */
253
253
  status: (sessionId: string) => Promise<SessionMemoryView>;
254
254
  }
255
- /** 状态面上 wire 的五键所在的那一份:部署对象答案去掉逐店明细 `planes`(逐店明细不上 wire,见 `core-keyset-guard.ts`)。 */
256
- export type SessionMemoryView = Omit<DeploymentSessionMemoryStatus, "planes">;
255
+ /**
256
+ * 状态面上 wire 的键所在的那一份,**引擎的答案原样**:带层座 ⇒ 那只店的引擎答案(`SessionMemoryStatus`:五键 + `writeHome`,`writeHome` 是店绑定的键);
257
+ * 不带层座 ⇒ 部署对象的答案(`DeploymentSessionMemoryStatus`:引擎折好的五键 + 引擎择好的会话级 `writeHome` + 逐店明细 `planes`,每行是一只店原样的 `SessionMemoryStatus`)。
258
+ * 会话级 `writeHome` 由引擎在店之间择一(点名家的店里较新的那只的家,原样;任一店读不出 / 同刻 / 无店点名 ⇒ 缺席);本服务不折、不择一、不去重,
259
+ * 路由把顶层 `writeHome` 与每行的 `plane` / `writeHome` 原样投出(见 `core-keyset-guard.ts` ⑩e)。
260
+ */
261
+ export type SessionMemoryView = SessionMemoryStatus & Partial<Pick<DeploymentSessionMemoryStatus, "planes">>;
257
262
  /**
258
263
  * [ref] seam①([ref] §S-7,core 7.0.2 [ref] 件1)—— `GET /v1/sessions/:id/memory-status` 的引擎面。
259
264
  * 命名照 CLAUDE.md 工厂律:返回带行为的活对象 ⇒ `create*`。
@@ -2,10 +2,11 @@
2
2
  * 记忆作用域店 —— 本部署的记忆在本宿主的**唯一持有者**:「一层住在哪只店」与「本部署有哪些店」都只在这里答。
3
3
  *
4
4
  * ## 规则(一条)
5
- * 一层(scope)的平面只有引擎的纯分类函数答(`scopePlanesOf`,契约 = 本服务铸 spec 时盖在会话上的同一只判据 {@link memoryScopeContractOf});
5
+ * 一层(scope)的平面只有引擎答(`memoryScopePlaneOf`,契约 = 本服务铸 spec 时盖在会话上的同一只判据 {@link memoryScopeContractOf});
6
6
  * 一层的店 = 它那只平面的店(项目平面 = 部署的店;目录钉住的部署上个人平面是个人挂载上的另一只店,引擎的 `resolveMemoryScopeStore` 开它)。
7
- * **本部署有哪些店**只有引擎的部署对象答(`createMemoryDeployment(…).stores()`):项目店,再加上个人挂载**在盘上**的那只个人店 ——
8
- * 盘的集合,不是配置点名的层推出来的集合(配置只决定会话往哪写;换了 `MEMORY_SCOPE` 之后个人挂载上留下的那只店照样在集合里)。
7
+ * **本部署有哪些店**只有引擎的部署对象答(`createMemoryDeployment(…).stores()`,契约 `memory.deployment.store_set`):项目店,再加上个人挂载上
8
+ * **存有记录**的那只个人店 —— 盘的集合,不是配置点名的层推出来的集合(配置只决定会话往哪写;换了 `MEMORY_SCOPE` 之后个人挂载上写过的那只店照样在集合里),
9
+ * 也不是「开过」的集合(打开 / 读 / 被拒的请求只留下引擎具名的工件,不让店进集;每次从盘上读,每只部署对象答同一个集合)。
9
10
  * 本服务在会话之外读写某一层的每一条腿(同步执行器、项目层折叠、中心侧导出 / 同步、bundle 导出导入、合规抹除 / 出处、外源标记、会话记忆状态、整理)
10
11
  * 一律问**本对象**。本对象就是起服装配出来的那只记忆引擎对象(`boot/stores.ts` 的 `memoryEngine`、`run-local.ts` 的同名量):它的 `backend` / `root`
11
12
  * 正是交给 Runner 的两件事实(`RunnerDeps.memoryBackend` / `RunnerDeps.memoryEngineDir`)—— 宿主腿与会话对同一层答同一只店。每进程一只,所有腿共用。
@@ -18,7 +19,7 @@
18
19
  *
19
20
  * ## 请求的店({@link memoryStoreForRequest})
20
21
  * 点名层的动词按点名的层取店;点名的几层不在同一只店 ⇒ 响亮拒(一次请求只落一只店)。不点名层的条目 id / 店级账本动词答在**本部署唯一的那只店**上;
21
- * 部署有两只店(盘上有个人店)⇒ 不猜,响亮拒并指路「在请求里点名层」。没有部署对象的部署(SQL 记忆孪生,不钉目录 ⇒ 两个平面同一只店)恒是一只店。
22
+ * 部署有两只店(个人挂载上的店存有记录)⇒ 不猜,响亮拒并指路「在请求里点名层」。没有部署对象的部署(SQL 记忆孪生,不钉目录 ⇒ 两个平面同一只店)恒是一只店。
22
23
  */
23
24
  import { type MemoryBackend, type MemoryDeployment } from "@sema-agent/core";
24
25
  import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
@@ -29,7 +30,7 @@ export interface MemoryScopeStores {
29
30
  readonly root: string;
30
31
  /** capture opt-out 记录源(起服取一次的那一只;缺席 ⇒ 引擎各自的文件缺省)。本部署每一只记忆引擎 —— 部署对象、各操作面按店构造的引擎 —— 都只读这一格。 */
31
32
  readonly captureRecords: SessionCaptureRecordSource | undefined;
32
- /** 层 `layer` 的平面(引擎的规范化 + 纯分类函数,与引擎的店解析同一读法;零建店、零读盘)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
33
+ /** 层 `layer` 的平面(引擎的 `memoryScopePlaneOf`,与引擎的店解析同一只;零建店、零读盘)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
33
34
  planeOf(layer: string): "project" | "personal";
34
35
  /** 层 `layer` 住的那只店(先判平面、每个平面一只实例)。读不出的层键 ⇒ 同 {@link MemoryScopeStores.planeOf}。 */
35
36
  storeOf(layer: string): MemoryBackend;
@@ -37,7 +38,8 @@ export interface MemoryScopeStores {
37
38
  deployment(): MemoryDeployment | undefined;
38
39
  }
39
40
  /**
40
- * 控制面归属判据 —— 记忆操作面(合规 / 外源标记 / 会话记忆状态 / consolidation 阀门的 D1 拒启门)与部署对象共用的**同一只**谓词:
41
+ * 控制面归属判据 —— 记忆操作面(合规 / 外源标记 / 会话记忆状态)与部署对象共用的**同一只**谓词(这些部署面问「后端发不发布控制面」;
42
+ * 整理阀门问的是另一件事 —— 整理状态随不随后端走 —— 只问引擎的 `memoryGovernanceDurability`,见 `boot/memory-consolidation.ts`):
41
43
  * backend 的面上带**非空** `controlPlaneRoot` 才算归属在案。空串与缺席同判「不归属」:core 对空串会 truthy-回退到本副本盘上派生控制面
42
44
  * (engine 构造里的 `backendControl ? … : derive(…)`),对无状态多副本部署这正是 D1 要拒的那台机器(折叠账随 pod 一起死)。
43
45
  */
@@ -63,7 +65,7 @@ export declare class MemoryLayerRefusal extends Error {
63
65
  /**
64
66
  * 一次请求的记忆店。`layers` = 请求点名的层(空 = 没点名):
65
67
  * · 点名 ⇒ 它们共住的那一只店;分住两只 ⇒ 拒(一次请求只落一只店,按店拆成几次请求)。
66
- * · 没点名 ⇒ 本部署唯一的那只店(= 部署的店);部署有两只店(盘上有个人店,{@link MemoryScopeStores.deployment})⇒ 拒,指路在请求里点名层。
68
+ * · 没点名 ⇒ 本部署唯一的那只店(= 部署的店);部署有两只店(个人挂载上的店存有记录,{@link MemoryScopeStores.deployment})⇒ 拒,指路在请求里点名层。
67
69
  * `seat` = 这个动词点名层的那一处(拒句里指路用,如 `` `scope` ``;缺省 = 层座 `scope`)。
68
70
  * 拒一律 {@link MemoryLayerRefusal}(读不出的层键同码,引擎原句随句)。
69
71
  */
@@ -1,4 +1,4 @@
1
- import { createMemoryDeployment, normalizeMemorySpec, resolveMemoryScopeStore, scopePlanesOf } from "@sema-agent/core";
1
+ import { createMemoryDeployment, memoryScopePlaneOf, resolveMemoryScopeStore } from "@sema-agent/core";
2
2
  import { memoryScopeContractOf } from "./memory-scope.js";
3
3
  export function backendOwnsControlPlane(backend) {
4
4
  return controlPlaneRootOf(backend) !== undefined;
@@ -7,6 +7,7 @@ export function controlPlaneRootOf(backend) {
7
7
  const root = backend?.controlPlaneRoot;
8
8
  return typeof root === "string" && root !== "" ? root : undefined;
9
9
  }
10
+ const PLANE_FACE = "memoryScopeStores.planeOf";
10
11
  export function createMemoryScopeStores(input) {
11
12
  let personal;
12
13
  const resolve = (layer) => resolveMemoryScopeStore({
@@ -16,19 +17,7 @@ export function createMemoryScopeStores(input) {
16
17
  memoryEngineDir: input.root,
17
18
  ...(input.onIncident !== undefined ? { onIncident: input.onIncident } : {}),
18
19
  });
19
- const planeOf = (layer) => {
20
- const contract = memoryScopeContractOf([layer]);
21
- let spec;
22
- try {
23
- spec = normalizeMemorySpec({ scopes: [layer], writeScope: layer, ...(contract !== undefined ? { scopeContract: contract } : {}) });
24
- }
25
- catch {
26
- spec = undefined;
27
- }
28
- if (spec === undefined || spec.writeScope === null)
29
- return resolve(layer).plane;
30
- return scopePlanesOf(spec.scopes, spec.writeScope, spec.scopeContract)?.writePlane ?? "project";
31
- };
20
+ const planeOf = (layer) => memoryScopePlaneOf(PLANE_FACE, layer, memoryScopeContractOf([layer]));
32
21
  let deployment;
33
22
  return {
34
23
  backend: input.backend,
@@ -173,6 +173,42 @@ export declare function memoryEngineRootFor(config: Pick<ServiceConfig, "memoryE
173
173
  * 所以它的根必须走这条链而不是 `memoryEngineRootFor` 的分派(codex 修复验证轮 [medium]:分派会把 run-local 的
174
174
  * 记忆搬到 `<localDataRoot>/memory-work`,存量记忆与控制面升级后隐形)。 */
175
175
  export declare function fileMemoryEngineRoot(config: Pick<ServiceConfig, "memoryEngineDir">, fallbackRoot?: string): string;
176
+ /**
177
+ * 一条路径的**规范形**(给 {@link judgeMemoryRootOutsideDataRoot} 的 `canonical` 座用的生产实现):
178
+ * · 既存的绝对路径 ⇒ **原样**交给 `realpath`(`.native`:大小写不敏感的文件系统上返回盘上的拼写;符号链接、macOS 的 `/var` → `/private/var` 在这一步展平)。
179
+ * 不先在字串上折 `..`:操作系统在展开符号链接**之后**才折 `..`,`/link/..` 的真身是链接目标的父目录,字串折叠会把它读成 `/`;
180
+ * · 其余(尚不存在 / 相对)⇒ 绝对化并折叠 → 取**最深既存祖先**的 `realpath` → 接回尚不存在的尾巴(尾巴只做字串规范化)。
181
+ *
182
+ * 为什么按「最深既存祖先」而不是直接 `realpath(p)`:boot 期记忆根常常还没建出来(新数据根),`realpath` 对不存在的路径抛 ENOENT,
183
+ * 而数据根那一侧已经存在、会被展平 —— 两侧拼写空间不一样,同一个目录会被读成「不在其下」。祖先用 `existsSync` 找(它对 ENOENT / ENOTDIR / EACCES / ELOOP
184
+ * 一律答 `false`,不抛),所以走到的那一级一定 stat 得动;`realpath` 仍可能在「探完到取值之间目录被挪走 / 搜索权限被收」的竞态里抛 ——
185
+ * 不在本函数里吞(吞了就是一条无声的降级臂),由 boot 调用点接住并响亮报一行(`memory_engine_dir_check_unavailable`),起服照常。
186
+ *
187
+ * 取舍:尾巴(不存在的那几段)只比规范化字串,**不折大小写**,`..` 也按字串折:两个只差大小写、且都还不存在的拼写在大小写不敏感的盘上会被读成两处 ——
188
+ * 方向是多报一条 warn(这条判据的失败方向),不会漏报。
189
+ */
190
+ export declare function canonicalPathOf(p: string): string;
191
+ /** {@link judgeMemoryRootOutsideDataRoot} 的读数:记忆引擎的根落在本机数据根**之外**。三键即 boot 日志行的字段(`hint` 是一句带两条真路径的人话)。 */
192
+ export type MemoryRootOutsideDataRoot = {
193
+ readonly root: string;
194
+ readonly dataRoot: string;
195
+ readonly hint: string;
196
+ };
197
+ /**
198
+ * 【判官】file 形记忆引擎的**已解析根**是不是落在本机数据根(`config.localDataRoot`)**之外** —— 是 ⇒ 回两条真路径(boot 打一条 warn),不是 ⇒ `undefined`。
199
+ *
200
+ * 判据只有这一条**路径包含**:`path.relative(数据根, 记忆根)` 不以 `..` 段开头、也不是绝对路径(跨盘符)⇒ 在其下(相等也算在其下)。**与 env 是否显式无关**:
201
+ * `MEMORY_ENGINE_DIR` 缺席不是判据(此前判据是「`LOCAL_DATA_ROOT` 在 ∧ `MEMORY_ENGINE_DIR` 缺席」,于是 `AGENT_DATA_DIR` 已把两者放在同一处时,
202
+ * 「正在共享全机默认库」一句不真,而显式 `MEMORY_ENGINE_DIR` 指到数据根之外的真分家反而不报)。数据根缺席 ⇒ 无从比较,不报。
203
+ *
204
+ * 纯函数:不读 env、不读盘 —— 规范化走 `canonical` 座(缺省 `path.resolve`,字串规范形;boot 递 {@link canonicalPathOf} 取符号链接 / 大小写展平后的形)。
205
+ * 读数里的两条路径是**调用方给的原样拼写**(运维认得出来的那两条),不是规范形。
206
+ */
207
+ export declare function judgeMemoryRootOutsideDataRoot(a: {
208
+ readonly memoryRoot: string;
209
+ readonly dataRoot: string | undefined;
210
+ readonly canonical?: (p: string) => string;
211
+ }): MemoryRootOutsideDataRoot | undefined;
176
212
  /** 本部署 file 记忆引擎的**平面三坐标**(根 / 记忆目录 / 控制面目录)—— {@link fileMemoryPlaneFor} 一次算齐。 */
177
213
  export interface FileMemoryPlane {
178
214
  readonly root: string;
@@ -1,4 +1,5 @@
1
- import { join } from "node:path";
1
+ import { existsSync, realpathSync } from "node:fs";
2
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
2
3
  import { FileMemoryEngineBackend, resolveMemoryEngineRoot, deriveControlPlaneDir, formatUserScope, formatProjScope, normalizeMemorySpec } from "@sema-agent/core";
3
4
  import { capabilitiesFor, executionLaneOf } from "./execution-lane-caps.js";
4
5
  import { assertMemoryScopeWidth } from "./plugins/memory-key-guards.js";
@@ -9,6 +10,7 @@ const V2_SCOPE_PREFIX_BY_KIND = {
9
10
  org: "org:",
10
11
  proj: "proj:",
11
12
  userproj: "userproj:",
13
+ userlocal: "userlocal:",
12
14
  };
13
15
  export const V2_SCOPE_PREFIXES = Object.freeze(Object.values(V2_SCOPE_PREFIX_BY_KIND));
14
16
  export function isV2ScopeKey(key) {
@@ -108,6 +110,35 @@ export function memoryEngineRootFor(config, localRoot) {
108
110
  export function fileMemoryEngineRoot(config, fallbackRoot) {
109
111
  return resolveMemoryEngineRoot(config.memoryEngineDir ?? fallbackRoot);
110
112
  }
113
+ export function canonicalPathOf(p) {
114
+ if (isAbsolute(p) && existsSync(p))
115
+ return realpathSync.native(p);
116
+ const abs = resolve(p);
117
+ let existing = abs;
118
+ const tail = [];
119
+ while (!existsSync(existing)) {
120
+ const parent = dirname(existing);
121
+ if (parent === existing)
122
+ return abs;
123
+ tail.unshift(basename(existing));
124
+ existing = parent;
125
+ }
126
+ return join(realpathSync.native(existing), ...tail);
127
+ }
128
+ export function judgeMemoryRootOutsideDataRoot(a) {
129
+ if (!a.dataRoot)
130
+ return undefined;
131
+ const canonical = a.canonical ?? resolve;
132
+ const rel = relative(canonical(a.dataRoot), canonical(a.memoryRoot));
133
+ const inside = rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
134
+ if (inside)
135
+ return undefined;
136
+ return {
137
+ root: a.memoryRoot,
138
+ dataRoot: a.dataRoot,
139
+ hint: `memory engine root ${a.memoryRoot} is outside the local data root ${a.dataRoot}; set MEMORY_ENGINE_DIR under ${a.dataRoot} to isolate it`,
140
+ };
141
+ }
111
142
  export function fileMemoryPlaneFor(config, fallbackRoot) {
112
143
  if (config.requirePrincipal === true || !config.memoryEngineEnabled)
113
144
  return undefined;
@@ -0,0 +1,53 @@
1
+ export type CidrFamily = "ipv4" | "ipv6";
2
+ /** 一条 CIDR 的平数据读数。`net` 是写下的网络地址原文(不规范化,`BlockList` 按它建块)。 */
3
+ export interface ParsedCidr {
4
+ readonly net: string;
5
+ readonly prefix: number;
6
+ readonly family: CidrFamily;
7
+ /** 前缀之后还有为 1 的位(`10.0.0.5/8`)。宽文法照收;名单侧拒。 */
8
+ readonly hostBitsSet: boolean;
9
+ }
10
+ export type CidrParse = {
11
+ readonly ok: true;
12
+ readonly cidr: ParsedCidr;
13
+ } | {
14
+ readonly ok: false;
15
+ };
16
+ /**
17
+ * 宽文法:`<IPv4|IPv6>[/<十进制前缀>]`,裸地址 = 主机前缀(/32 或 /128)。前缀只认 `^\d+$` 且不超过族上界。
18
+ * 地址合法性归 `isIP`(它已拒前导零的 IPv4 段)。
19
+ */
20
+ export declare function parseCidr(text: string): CidrParse;
21
+ /** 名单项的规范文本(`net/prefix`,网络地址取规范形),或拒因。 */
22
+ export type TrustedProxyCidrParse = {
23
+ readonly ok: true;
24
+ readonly cidr: ParsedCidr;
25
+ readonly text: string;
26
+ } | {
27
+ readonly ok: false;
28
+ readonly flaw: string;
29
+ };
30
+ /**
31
+ * 可信代理名单的一项(设备 WS 预鉴权帽键;运维写下、安全轴)。在宽文法之上收紧 —— 歧义 = 拒,不收下当「差不多」:
32
+ * · 空项(`a,,b` / 尾逗号 / 只含空白):多半是拼接事故,收下会让人以为某条还在;
33
+ * · zone id(`fe80::1%eth0`):链路本地的接口名对别的主机没有意义;
34
+ * · 主机位非零(`10.0.0.5/8`):是想信整块还是信一台?两个出路都写进拒句;
35
+ * · 前缀 0(`0.0.0.0/0` / `::/0`):信全网任意来源的转发头 = 每个客户端自报帽键,等于一只绕帽旋钮 —— 本旋钮不提供它。
36
+ */
37
+ export declare function parseTrustedProxyCidr(text: string): TrustedProxyCidrParse;
38
+ /** 地址集合的活对象(按 CIDR 建块,判官 = node `BlockList`)。IPv4-mapped IPv6 的两种拼法与 IPv4 规则互相命中是 `BlockList` 自己的
39
+ * 跨族匹配(net-address.test 钉住:换 node 后它变了那里先红)。`has` 不改写地址 —— 出网策略判照旧按原文查。 */
40
+ export interface CidrSet {
41
+ has(address: string): boolean;
42
+ readonly size: number;
43
+ }
44
+ export declare function createCidrSet(cidrs: readonly ParsedCidr[]): CidrSet;
45
+ /** 可信代理名单(已由配置层逐项校验过的文本)⇒ 集合。坏项 = 装配缝(配置层已先拒),当场抛,不跳过。 */
46
+ export declare function createTrustedProxySet(items: readonly string[]): CidrSet;
47
+ /**
48
+ * 地址的规范形(帽键的唯一拼法):IPv4 原样(`isIP` 已保证点分十进制、无前导零);IPv6 取 WHATWG 的压缩小写形;
49
+ * IPv4-mapped IPv6(`::ffff:1.2.3.4` / `::ffff:102:304`)⇒ 点分 IPv4 —— 同一台主机经 IPv4 栈与双栈来时是同一个键。
50
+ * 非地址、带 zone id、带端口、带方括号 ⇒ `undefined`(端口 / 方括号由调用方按自己的文法先剥)。
51
+ */
52
+ export declare function canonicalAddress(text: string): string | undefined;
53
+ //# sourceMappingURL=net-address.d.ts.map
@@ -0,0 +1,111 @@
1
+ import { BlockList, isIP } from "node:net";
2
+ export function parseCidr(text) {
3
+ const slash = text.indexOf("/");
4
+ const net = slash < 0 ? text : text.slice(0, slash);
5
+ const fam = isIP(net);
6
+ const max = fam === 6 ? 128 : 32;
7
+ const prefixText = slash < 0 ? String(max) : text.slice(slash + 1);
8
+ const prefix = Number(prefixText);
9
+ if (fam === 0 || !/^\d+$/.test(prefixText) || prefix > max)
10
+ return { ok: false };
11
+ const family = fam === 6 ? "ipv6" : "ipv4";
12
+ return { ok: true, cidr: { net, prefix, family, hostBitsSet: hostBitsSet(net, prefix, family) } };
13
+ }
14
+ export function parseTrustedProxyCidr(text) {
15
+ if (text === "")
16
+ return { ok: false, flaw: "is empty (a stray comma, or a whitespace-only value)" };
17
+ if (text.includes("%"))
18
+ return { ok: false, flaw: "carries an interface zone id (%…), which means nothing to another host" };
19
+ const parsed = parseCidr(text);
20
+ if (!parsed.ok)
21
+ return { ok: false, flaw: "is not an IPv4 / IPv6 address or CIDR (address[/prefix], prefix in decimal within 32 / 128; hostnames are not accepted)" };
22
+ const { cidr } = parsed;
23
+ const net = canonicalNetwork(cidr);
24
+ if (cidr.prefix === 0) {
25
+ return { ok: false, flaw: "is a /0 prefix — it would trust the forwarded-for header from every source, so any client could pick its own cap key; list only your own reverse proxies" };
26
+ }
27
+ if (cidr.hostBitsSet) {
28
+ return { ok: false, flaw: `has host bits set past /${cidr.prefix} — write ${maskedNetwork(cidr)}/${cidr.prefix} to trust the whole block, or ${net}/${cidr.family === "ipv6" ? 128 : 32} to trust that one proxy` };
29
+ }
30
+ return { ok: true, cidr, text: `${net}/${cidr.prefix}` };
31
+ }
32
+ export function createCidrSet(cidrs) {
33
+ const list = new BlockList();
34
+ for (const c of cidrs)
35
+ list.addSubnet(c.net, c.prefix, c.family);
36
+ return {
37
+ size: cidrs.length,
38
+ has(address) {
39
+ const fam = isIP(address);
40
+ if (fam === 0)
41
+ return false;
42
+ return list.check(address, fam === 6 ? "ipv6" : "ipv4");
43
+ },
44
+ };
45
+ }
46
+ export function createTrustedProxySet(items) {
47
+ const cidrs = items.map((item, i) => {
48
+ const r = parseTrustedProxyCidr(item);
49
+ if (!r.ok)
50
+ throw new Error(`device lane: trusted proxy list item ${i + 1} of ${items.length} (${JSON.stringify(item)}) ${r.flaw} (assembly bug: DEVICE_TRUSTED_PROXY_CIDRS is validated at config load)`);
51
+ return r.cidr;
52
+ });
53
+ return createCidrSet(cidrs);
54
+ }
55
+ export function canonicalAddress(text) {
56
+ const fam = isIP(text);
57
+ if (fam === 4)
58
+ return text;
59
+ if (fam !== 6)
60
+ return undefined;
61
+ const inner = compressedIpv6(text);
62
+ if (inner === undefined)
63
+ return undefined;
64
+ const mapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(inner);
65
+ if (mapped !== null) {
66
+ const hi = parseInt(mapped[1], 16);
67
+ const lo = parseInt(mapped[2], 16);
68
+ return `${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`;
69
+ }
70
+ return inner;
71
+ }
72
+ function compressedIpv6(text) {
73
+ const href = `http://[${text}]/`;
74
+ return URL.canParse(href) ? new URL(href).hostname.slice(1, -1) : undefined;
75
+ }
76
+ function addressBytes(net, family) {
77
+ if (family === "ipv4")
78
+ return net.split(".").map(Number);
79
+ const zone = net.indexOf("%");
80
+ const host = compressedIpv6(zone < 0 ? net : net.slice(0, zone));
81
+ if (host === undefined)
82
+ return undefined;
83
+ const [left = "", right] = host.split("::");
84
+ const l = left === "" ? [] : left.split(":");
85
+ const r = right === undefined || right === "" ? [] : right.split(":");
86
+ const groups = [...l, ...Array(8 - l.length - r.length).fill("0"), ...r].map((g) => parseInt(g, 16));
87
+ return groups.flatMap((g) => [g >> 8, g & 255]);
88
+ }
89
+ function hostBitsSet(net, prefix, family) {
90
+ const bytes = addressBytes(net, family);
91
+ if (bytes === undefined)
92
+ return false;
93
+ return bytes.some((b, i) => (b & ~maskByte(prefix, i) & 255) !== 0);
94
+ }
95
+ function maskByte(prefix, index) {
96
+ const bits = Math.max(0, Math.min(8, prefix - index * 8));
97
+ return (0xff << (8 - bits)) & 255;
98
+ }
99
+ function maskedNetwork(c) {
100
+ const bytes = (addressBytes(c.net, c.family) ?? []).map((b, i) => b & maskByte(c.prefix, i));
101
+ if (c.family === "ipv4")
102
+ return bytes.join(".");
103
+ const groups = [];
104
+ for (let i = 0; i < 16; i += 2)
105
+ groups.push(((bytes[i] << 8) | bytes[i + 1]).toString(16));
106
+ return compressedIpv6(groups.join(":")) ?? groups.join(":");
107
+ }
108
+ function canonicalNetwork(c) {
109
+ return c.family === "ipv4" ? c.net : (compressedIpv6(c.net) ?? c.net);
110
+ }
111
+ //# sourceMappingURL=net-address.js.map
@@ -175,17 +175,13 @@ export declare const FAIL_OPEN_TAGS: {
175
175
  readonly cls: "F";
176
176
  readonly note: "design/382 §3.5(S-44;core 7.55.0 #1468 P1 阶段二起读者是 core `readRuleOffers`,经 `approval-card.ts` 的 `readRuleOfferList`,两条腿同调):batch offer 的 `uncoveredDetail` 明细座不是「每个计数段一行良构行」(集外 reason / 非数组 / 行数与 count 座不等 —— core 读者判丢、读数带 `uncoveredDetailDropped`)或行数超本仓展示帽 MAX_UNCOVERED_DETAIL_ROWS ⇒ 只丢这一座、batch 本体照投。放行的最坏后果 = 卡上少几行「这段为什么还会问」的解释(count 座仍在,core 契约明写明细缺席不是断言);把整只 batch 判假才是错的方向(一只真可兑的合取批从卡上消失)。纯展示轴 ⇒ F 类;必须留痕,否则上游明细座漂形在遥测里零痕迹。detail = `index=<core 列表里的下标>` + 丢的缘由(不带段文本)。";
177
177
  };
178
- readonly "server.approval-batch.kindless-row": {
179
- readonly cls: "F";
180
- readonly note: "起服普查(`approval-batch-census.ts`;SQL 两方言同一只读口 `SqlCheckpointStore.scanKindlessBatchRows`):一行审批停驻行(`checkpoint` 表,所有状态)的规则提议里,有 batch offer 带着**无 `kind` 的存量成员** —— 引擎读者(`readRuleOffers`)为这个旧形留着一条存量读臂(无 `kind`、四个命令文本键齐的成员读成 `command`,并给那只 offer 打 `kindlessForm` 记号),本仓用 `countKindlessBatchOffers` 数这个记号。载体两个:`rule_suggestions` 列、blob 里的 `pendingAction.ruleOffers`(detail 的 `carriers=` 点名是哪个)。每个带旧形成员的行记一次(逐次计数 + 探针行 + 每进程一次 warn),起服另出一行 info `approval_batch_kindless_rows { count }`。放行的最坏后果 = 无新增放行:这是读侧存量兼容臂被数的位,读法本来就是『旧形读成 command』,普查不改任何一行的读法、不翻行、不删臂;留痕的唯一目的是让『还有几行靠这条臂』可证 —— 计数为零(整个部署的每个副本起服都是零)才能由后续一版删那条存量臂;非零 = 还有行靠它,不可删,detail 的 `row=` 是行指纹(不是 token)。F 类(读侧兼容、纯展示轴:这条臂读出的是「不再询问」候选的卡面,不是门)。逐页读、不是原子快照(页间别的副本的写入可以让一行被漏数或多数一行);滚动升级窗里停在旧版本的副本之后写的旧形行,下次起服才数得到。后台跑、不挡起服就绪。";
181
- };
182
178
  readonly "server.checkpoint.inbox-risk-axes-damaged": {
183
179
  readonly cls: "F";
184
- readonly note: "core 7.55.0 `summarizeCheckpoint` 的第二参(`plugins/checkpoint-store-sql.ts` 的 `listByScope`:supervisor inbox / 调度视图的按 scope 待决投影):一行审批门的风险描述符读穿了一格坏轴 —— `axes` 不是普通对象,或某个标记(`egress` / `irreversible` / `shell`)在场却不是布尔(手改 / 第三方写者;引擎铸的行没有这一形)⇒ 行照投,`severity` 取有效标记给出的下界,证不出就缺席;core 交一句话给店的座,本座逐行计一次。放行的最坏后果 = 这一行在按 severity 倒排的 inbox 里排位偏低或无档(分诊材料,不是门;resume 的判据不读它)。不放行的代价是一行坏描述符打掉整个 scope 的 inbox(修前:非对象描述符抛 TypeError 出投影)。修前不传座 ⇒ 降档是静默的。detail = core 的句子(按 checkpoint id 与会话 JSON 点名、按形说成员,不带令牌、不带值);每次列 inbox 都会再说一次,直到那一行被修或被决。LOCAL 车道的同一句经 backend 的 `file_store_corrupt_read` 座(core File 店自带),不走本 tag。";
180
+ readonly note: "core 7.55.0 `summarizeCheckpoint` 的第二参(`stores-sql/checkpoint-store-sql.ts` 的 `listByScope`:supervisor inbox / 调度视图的按 scope 待决投影):一行审批门的风险描述符读穿了一格坏轴 —— `axes` 不是普通对象,或某个标记(`egress` / `irreversible` / `shell`)在场却不是布尔(手改 / 第三方写者;引擎铸的行没有这一形)⇒ 行照投,`severity` 取有效标记给出的下界,证不出就缺席;core 交一句话给店的座,本座逐行计一次。放行的最坏后果 = 这一行在按 severity 倒排的 inbox 里排位偏低或无档(分诊材料,不是门;resume 的判据不读它)。不放行的代价是一行坏描述符打掉整个 scope 的 inbox(修前:非对象描述符抛 TypeError 出投影)。修前不传座 ⇒ 降档是静默的。detail = core 的句子(按 checkpoint id 与会话 JSON 点名、按形说成员,不带令牌、不带值);每次列 inbox 都会再说一次,直到那一行被修或被决。LOCAL 车道的同一句经 backend 的 `file_store_corrupt_read` 座(core File 店自带),不走本 tag。";
185
181
  };
186
182
  readonly "server.rule-offers.offer-dropped": {
187
183
  readonly cls: "F";
188
- readonly note: "core 7.55.0 #1468 P1 阶段二(`approval-card.ts` 的 `readRuleOfferList`,规则提议列表的唯一读者,判官 = core `readRuleOffers`;两条腿同调 —— 耐久腿 `checkpoint-store-sql.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行;同步腿 `tool-approval.ts` `boundRuleOfferTexts`:活 ask 的 `AskRequest.ruleOffers`):一个元素读不出(`unknown_word`:offer / 成员的 `kind`、`match` 是本引擎不认的词 —— 更新的铸者或别的写者;`malformed`:不是对象、成员缺位或错型、空 batch、计数不是非负安全整数)⇒ 这一只整只丢(batch 不拆成员)、兄弟照投;整只值在场却不是列表(`not_an_array`)⇒ 这一行无供给。逐元素计。放行的最坏后果 = 卡上少一个「不再询问」选项(人仍可逐次批;少的是选项不是门 —— 渲出一个读不懂的选项、或少一个成员的合取批,才是错的方向)。修前耐久腿丢元素是静默的,同步腿走一行 logger warn(`rule_offer_dropped_unreadable_shape`,随之退役)。计数非零 = 有 offer 列表的形本引擎读不懂:上游版本领先(core 加了词)或库里的行被手改过。detail = `index=<下标> problem=<RULE_OFFER_SHAPE_PROBLEMS 的词>`(不带 offer 文本 —— 那是命令原文族)。";
184
+ readonly note: "core 7.55.0 #1468 P1 阶段二(`approval-card.ts` 的 `readRuleOfferList`,规则提议列表的唯一读者,判官 = core `readRuleOffers`;两条腿同调 —— 耐久腿 `checkpoint-store-face.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行;同步腿 `tool-approval.ts` `boundRuleOfferTexts`:活 ask 的 `AskRequest.ruleOffers`):一个元素读不出(`unknown_word`:offer / 成员的 `kind`、`match` 是本引擎不认的词 —— 更新的铸者或别的写者;`malformed`:不是对象、成员缺位或错型、空 batch、计数不是非负安全整数)⇒ 这一只整只丢(batch 不拆成员)、兄弟照投;整只值在场却不是列表(`not_an_array`)⇒ 这一行无供给。逐元素计。放行的最坏后果 = 卡上少一个「不再询问」选项(人仍可逐次批;少的是选项不是门 —— 渲出一个读不懂的选项、或少一个成员的合取批,才是错的方向)。修前耐久腿丢元素是静默的,同步腿走一行 logger warn(`rule_offer_dropped_unreadable_shape`,随之退役)。计数非零 = 有 offer 列表的形本引擎读不懂:上游版本领先(core 加了词)或库里的行被手改过。detail = `index=<下标> problem=<RULE_OFFER_SHAPE_PROBLEMS 的词>`(不带 offer 文本 —— 那是命令原文族)。";
189
185
  };
190
186
  readonly "server.rules.ticket-claim-release-failed": {
191
187
  readonly cls: "F";
@@ -201,7 +197,7 @@ export declare const FAIL_OPEN_TAGS: {
201
197
  };
202
198
  readonly "server.approvals.park-row-blob-unreadable": {
203
199
  readonly cls: "F";
204
- readonly note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)";
200
+ readonly note: "S-700(`stores-sql/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)";
205
201
  };
206
202
  readonly "server.approvals.queue-row-agent-unreadable": {
207
203
  readonly cls: "F";
@@ -219,17 +215,21 @@ export declare const FAIL_OPEN_TAGS: {
219
215
  readonly cls: "F";
220
216
  readonly note: "`session-notify-door.ts` 的 `deliver`(会话通知门的判活读;两只调用方 `POST /v1/sessions/:id/notify` 与后台子代完成 relay 同经):判活读 —— run 店的单活认领读 `getActiveTaskId` —— 抛(店瞬断 / 超时 / 连接被回收)⇒ 门当这只会话**没有在飞的 run**,落空闲臂:入收件箱,下次开流排空成 `task_notification` 帧,不把读失败抛给调用方。放行的最坏后果 = 这一条通知晚到 —— 本该在活流的下一个边界投递(`priority: next`),改成下一次开流才排空(至少一次,晚一次开流),不丢、不错投;两臂的投递动作之前紧邻的住客复核照做,所以这不是门、不是权限、不是凭证。不放行(抛)= 一次 run 店瞬断把通知路由答成 500(经全局兜底)、把后台子代的完成通知记成 `relay_failed` 交不出去,比晚一次开流更糟。读失败与「会话真的空闲」在外部同形,所以必须留痕:计数 + 探针(detail 带会话 id 与错句,经记录器统一脱敏)+ 每进程一次 warn。";
221
217
  };
218
+ readonly "server.session-id-tombstone.evicted": {
219
+ readonly cls: "P-DEBT";
220
+ readonly note: "`deleted-session-ids.ts` 的 `retireSessionId`(本进程删过的会话 id → 删前属主那张表的唯一铸点;执行上下文解析器 `resolveExecutionContext` 读它,拒本进程上这只 id 的执行服务删前属主之外的住客 —— 409 `conflict.session_id_retired`):表满(`DELETED_SESSION_ID_CAP` 条)⇒ 驱逐最旧的一条,那个 id 回到「本进程没删过」。保护面、方向明知是放行 ⇒ 记债:表独自守着一个窄 P 面 —— 本服务按裸会话 id 键的通告分流器(`EngineNoticeRouter`)收委派腿的用户面通告,引擎 7.64.0 的地址是树根会话 id、不带住客 ⇒ 被驱逐的那个 id 上,另一位属主在本进程重登之后,前任住客子代的被拒通告可按 id 落进新住客的流(暂存那一形不在其内:引擎 7.64.0 起按住客存取,弃掉、运维席一条 delegation.delivery_discarded)。不放行的形是表无界增长。收口条件 = core #3479(委派腿通告地址带根住客)到货 ∧ 服务侧按裸会话 id 键的座普查为零 —— 届时表、本 tag 与 409 `conflict.session_id_retired` 一并退。";
221
+ };
222
222
  readonly "server.approvals.queue-row-gate-kind-missing": {
223
223
  readonly cls: "F";
224
- readonly note: "S-1681(`plugins/checkpoint-store-sql.ts` 的 `queueRowGateKind`,7.132.0;SQL 与 local 两只孪生的 `listPending` 同调这一只判官):运维待批队列(`GET /v1/approvals` / `/stream`)读到一行 pending 的门型(SQL 孪生:`checkpoint.gate_kind` 列;local 孪生:快照上的门)是 NULL 或不是 core 登记的门型 ⇒ 这一行**不列**。按构造不可达:每次停驻都把门型反范式进这一列,一次性迁移 M21 把没有它的存量行从门子树补齐(读不出登记门型的置 expired)。放行(不列、队列其余照常)的最坏后果 = 一行谁也决不了的行不出现在队列上 —— 它本来就不可决:每一条决断口按门型绑定取行(`gate_kind IN (…)`),证不出门型就不当它是这道门;不放行(整只拒)的代价是一行坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧)。也不按缺键投出去:消费方按 `gateKind` 路由、缺键即 fail-closed,队列行的契约是 `gateKind` 恒在场。故 F 类;计数非零 = 写腿或手改出了错,`SELECT session_id FROM checkpoint WHERE status = 'pending' AND gate_kind IS NULL` 查那一行(置 expired 或删会话)。";
224
+ readonly note: "S-1681(`plugins/checkpoint-store-face.ts` 的 `queueRowGateKind`,7.132.0;SQL 与 local 两只孪生的 `listPending` 同调这一只判官):运维待批队列(`GET /v1/approvals` / `/stream`)读到一行 pending 的门型(SQL 孪生:`checkpoint.gate_kind` 列;local 孪生:快照上的门)是 NULL 或不是 core 登记的门型 ⇒ 这一行**不列**。按构造不可达:每次停驻都把门型反范式进这一列,一次性迁移 M21 把没有它的存量行从门子树补齐(读不出登记门型的置 expired)。放行(不列、队列其余照常)的最坏后果 = 一行谁也决不了的行不出现在队列上 —— 它本来就不可决:每一条决断口按门型绑定取行(`gate_kind IN (…)`),证不出门型就不当它是这道门;不放行(整只拒)的代价是一行坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧)。也不按缺键投出去:消费方按 `gateKind` 路由、缺键即 fail-closed,队列行的契约是 `gateKind` 恒在场。故 F 类;计数非零 = 写腿或手改出了错,`SELECT session_id FROM checkpoint WHERE status = 'pending' AND gate_kind IS NULL` 查那一行(置 expired 或删会话)。";
225
225
  };
226
226
  readonly "server.sql-json.checkpoint.pending-steer-queue-lossy": {
227
227
  readonly cls: "F";
228
- readonly note: "S-550(`plugins/checkpoint-store-sql.ts` 的 `get()`,core 5.14.0 #147 的耐久转向队列):一条挂起 run 的 `checkpoint.pending_steer_queue` 这一格**没能完整读出来**(不是合法 JSON 文本 / 不是数组 / 某一条目的四个必备键不合形)⇒ 读不出的那部分**丢掉**,run 照常 resume。放行的最坏后果 = 一条已经 park 的操作员转向指令**没有**在这次 resume 上注入(人以为说过的话没送到);不放行的代价是这条挂起的 run **永远不可 resume** —— resume 是它唯一的出路,为一格读不出的转向把整条 run 变成砖是错误的失败方向(写侧刻意相反:`setPendingSteer` 往一份读不全的队列上追加会把读不出的条目永久抹掉,那里 fail-loud)。故 F 类。留痕从一条 `logger.info` 升成登记 tag 的理由:日志行在**遥测轴**上是零信号,「这台机器的转向队列一直读不出来」与「这台机器本来就没人 steer」在指标上完全同形。计数非零 = 去按日志里的 token 指纹查那一行。";
228
+ readonly note: "S-550(`stores-sql/checkpoint-store-sql.ts` 的 `get()`,core 5.14.0 #147 的耐久转向队列):一条挂起 run 的 `checkpoint.pending_steer_queue` 这一格**没能完整读出来**(不是合法 JSON 文本 / 不是数组 / 某一条目的四个必备键不合形)⇒ 读不出的那部分**丢掉**,run 照常 resume。放行的最坏后果 = 一条已经 park 的操作员转向指令**没有**在这次 resume 上注入(人以为说过的话没送到);不放行的代价是这条挂起的 run **永远不可 resume** —— resume 是它唯一的出路,为一格读不出的转向把整条 run 变成砖是错误的失败方向(写侧刻意相反:`setPendingSteer` 往一份读不全的队列上追加会把读不出的条目永久抹掉,那里 fail-loud)。故 F 类。留痕从一条 `logger.info` 升成登记 tag 的理由:日志行在**遥测轴**上是零信号,「这台机器的转向队列一直读不出来」与「这台机器本来就没人 steer」在指标上完全同形。计数非零 = 去按日志里的 token 指纹查那一行。";
229
229
  };
230
230
  readonly "server.sql-json.checkpoint.outcome-unreadable": {
231
231
  readonly cls: "F";
232
- readonly note: "S-550(`plugins/checkpoint-store-sql.ts` 的 `findDecidedApprovalsForBinding`,`/decide` 的**幂等回放**腿):一条已决 checkpoint 行的 `outcome` 这一格读不出形(手改 / 撕裂写 / 迁移脚本改过)⇒ 这一行交出 `decision: null`(= 判别不出),调用方按「整次拒绝」处置。放行的最坏后果 = 一次 decide **重试**拿不到上次的判词,退回按新请求处理(而不是回放)—— 回放是锦上添花的腿,让一条读不出的 JSON 把一次重试变成 500 比这更坏;方向上没有任何批准被放宽(判不出就是判不出,调用方拒绝)。故 F 类。**只容忍体的问题**:`not-text`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。";
232
+ readonly note: "S-550(`stores-sql/checkpoint-store-sql.ts` 的 `findDecidedApprovalsForBinding`,`/decide` 的**幂等回放**腿):一条已决 checkpoint 行的 `outcome` 这一格读不出形(手改 / 撕裂写 / 迁移脚本改过)⇒ 这一行交出 `decision: null`(= 判别不出),调用方按「整次拒绝」处置。放行的最坏后果 = 一次 decide **重试**拿不到上次的判词,退回按新请求处理(而不是回放)—— 回放是锦上添花的腿,让一条读不出的 JSON 把一次重试变成 500 比这更坏;方向上没有任何批准被放宽(判不出就是判不出,调用方拒绝)。故 F 类。**只容忍体的问题**:`not-text`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。";
233
233
  };
234
234
  readonly "server.sql-json.checkpoint.execution-outcome-unreadable": {
235
235
  readonly cls: "F";
@@ -625,6 +625,10 @@ export declare const FAIL_OPEN_TAGS: {
625
625
  readonly cls: "F";
626
626
  readonly note: "在飞 run 的切档口(`http/routes/run-permission-mode.ts`,`POST /v1/runs/:id/permission-mode`):引擎已经收下新档(本腿下一次工具调用按它仲裁),把准入的词写回这条 run 存储体(run 模式词的唯一来源,续跑腿按它重建 spec)没有落定 —— 这一刻这条 run 已不持有会话认领或已不在跑(`claim_released`:切档与停驻 / 终局同时到;认领栅栏拒写,不会拿旧 run 的体盖掉同会话新 run 的)、会话没有存储体行(`context_absent`)、店写抛(`store_failed`:库抖 / 一行装不下 / 封签失败)。每次记一次 + 一行 warn,回执 `persisted:false` + `persistMiss` 照实告诉壳。放行的最坏后果 = 下一条腿(停驻后续跑 / 重启后续跑)回到切档前的词:切松了 ⇒ 续跑回到更严的档(多问);切严了 ⇒ 续跑回到切档前更松的档 —— 那一档是这条 run 提交时受理过的,受理判官当时判过,不越过任何部署拒;不是门、不是凭据。计数非零 = 切档常与停驻相撞或 checkpoint 店在出错;壳据 `persisted` 在续跑后重切。detail = `miss=<词> mode=<词>`。";
627
627
  };
628
+ readonly "server.capabilities.adoption-import-unreadable": {
629
+ readonly cls: "F";
630
+ readonly note: "能力位 `adoptionImport`(`adoption/import.ts` 的 `readAdoptionImportCapability`,`GET /v1/capabilities` 每请求一读):按调用者读它作为源主体的那一条收编行时库读抛(断连 / 超时 / 池断)⇒ 这一位缺席、能力面照常 200。放行的是**藏**的方向:缺席 = 「你还没被收编」,触发臂不出导入入口,导入口本身不受影响(它自己读行、读失败照常 5xx)。最坏后果 = 这一拍用户看不到「一键收编」,下一次读能力面恢复。计数非零 = 收编日志所在的库在这台副本上读不动。";
631
+ };
628
632
  };
629
633
  /** 词表键推导的闭集类型——未登记的 tag 传不进 {@link recordFailOpen}(编译期拒)。 */
630
634
  export type FailOpenTag = keyof typeof FAIL_OPEN_TAGS;
@@ -157,17 +157,13 @@ export const FAIL_OPEN_TAGS = {
157
157
  cls: "F",
158
158
  note: "design/382 §3.5(S-44;core 7.55.0 #1468 P1 阶段二起读者是 core `readRuleOffers`,经 `approval-card.ts` 的 `readRuleOfferList`,两条腿同调):batch offer 的 `uncoveredDetail` 明细座不是「每个计数段一行良构行」(集外 reason / 非数组 / 行数与 count 座不等 —— core 读者判丢、读数带 `uncoveredDetailDropped`)或行数超本仓展示帽 MAX_UNCOVERED_DETAIL_ROWS ⇒ 只丢这一座、batch 本体照投。放行的最坏后果 = 卡上少几行「这段为什么还会问」的解释(count 座仍在,core 契约明写明细缺席不是断言);把整只 batch 判假才是错的方向(一只真可兑的合取批从卡上消失)。纯展示轴 ⇒ F 类;必须留痕,否则上游明细座漂形在遥测里零痕迹。detail = `index=<core 列表里的下标>` + 丢的缘由(不带段文本)。",
159
159
  },
160
- "server.approval-batch.kindless-row": {
161
- cls: "F",
162
- note: "起服普查(`approval-batch-census.ts`;SQL 两方言同一只读口 `SqlCheckpointStore.scanKindlessBatchRows`):一行审批停驻行(`checkpoint` 表,所有状态)的规则提议里,有 batch offer 带着**无 `kind` 的存量成员** —— 引擎读者(`readRuleOffers`)为这个旧形留着一条存量读臂(无 `kind`、四个命令文本键齐的成员读成 `command`,并给那只 offer 打 `kindlessForm` 记号),本仓用 `countKindlessBatchOffers` 数这个记号。载体两个:`rule_suggestions` 列、blob 里的 `pendingAction.ruleOffers`(detail 的 `carriers=` 点名是哪个)。每个带旧形成员的行记一次(逐次计数 + 探针行 + 每进程一次 warn),起服另出一行 info `approval_batch_kindless_rows { count }`。放行的最坏后果 = 无新增放行:这是读侧存量兼容臂被数的位,读法本来就是『旧形读成 command』,普查不改任何一行的读法、不翻行、不删臂;留痕的唯一目的是让『还有几行靠这条臂』可证 —— 计数为零(整个部署的每个副本起服都是零)才能由后续一版删那条存量臂;非零 = 还有行靠它,不可删,detail 的 `row=` 是行指纹(不是 token)。F 类(读侧兼容、纯展示轴:这条臂读出的是「不再询问」候选的卡面,不是门)。逐页读、不是原子快照(页间别的副本的写入可以让一行被漏数或多数一行);滚动升级窗里停在旧版本的副本之后写的旧形行,下次起服才数得到。后台跑、不挡起服就绪。",
163
- },
164
160
  "server.checkpoint.inbox-risk-axes-damaged": {
165
161
  cls: "F",
166
- note: "core 7.55.0 `summarizeCheckpoint` 的第二参(`plugins/checkpoint-store-sql.ts` 的 `listByScope`:supervisor inbox / 调度视图的按 scope 待决投影):一行审批门的风险描述符读穿了一格坏轴 —— `axes` 不是普通对象,或某个标记(`egress` / `irreversible` / `shell`)在场却不是布尔(手改 / 第三方写者;引擎铸的行没有这一形)⇒ 行照投,`severity` 取有效标记给出的下界,证不出就缺席;core 交一句话给店的座,本座逐行计一次。放行的最坏后果 = 这一行在按 severity 倒排的 inbox 里排位偏低或无档(分诊材料,不是门;resume 的判据不读它)。不放行的代价是一行坏描述符打掉整个 scope 的 inbox(修前:非对象描述符抛 TypeError 出投影)。修前不传座 ⇒ 降档是静默的。detail = core 的句子(按 checkpoint id 与会话 JSON 点名、按形说成员,不带令牌、不带值);每次列 inbox 都会再说一次,直到那一行被修或被决。LOCAL 车道的同一句经 backend 的 `file_store_corrupt_read` 座(core File 店自带),不走本 tag。",
162
+ note: "core 7.55.0 `summarizeCheckpoint` 的第二参(`stores-sql/checkpoint-store-sql.ts` 的 `listByScope`:supervisor inbox / 调度视图的按 scope 待决投影):一行审批门的风险描述符读穿了一格坏轴 —— `axes` 不是普通对象,或某个标记(`egress` / `irreversible` / `shell`)在场却不是布尔(手改 / 第三方写者;引擎铸的行没有这一形)⇒ 行照投,`severity` 取有效标记给出的下界,证不出就缺席;core 交一句话给店的座,本座逐行计一次。放行的最坏后果 = 这一行在按 severity 倒排的 inbox 里排位偏低或无档(分诊材料,不是门;resume 的判据不读它)。不放行的代价是一行坏描述符打掉整个 scope 的 inbox(修前:非对象描述符抛 TypeError 出投影)。修前不传座 ⇒ 降档是静默的。detail = core 的句子(按 checkpoint id 与会话 JSON 点名、按形说成员,不带令牌、不带值);每次列 inbox 都会再说一次,直到那一行被修或被决。LOCAL 车道的同一句经 backend 的 `file_store_corrupt_read` 座(core File 店自带),不走本 tag。",
167
163
  },
168
164
  "server.rule-offers.offer-dropped": {
169
165
  cls: "F",
170
- note: "core 7.55.0 #1468 P1 阶段二(`approval-card.ts` 的 `readRuleOfferList`,规则提议列表的唯一读者,判官 = core `readRuleOffers`;两条腿同调 —— 耐久腿 `checkpoint-store-sql.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行;同步腿 `tool-approval.ts` `boundRuleOfferTexts`:活 ask 的 `AskRequest.ruleOffers`):一个元素读不出(`unknown_word`:offer / 成员的 `kind`、`match` 是本引擎不认的词 —— 更新的铸者或别的写者;`malformed`:不是对象、成员缺位或错型、空 batch、计数不是非负安全整数)⇒ 这一只整只丢(batch 不拆成员)、兄弟照投;整只值在场却不是列表(`not_an_array`)⇒ 这一行无供给。逐元素计。放行的最坏后果 = 卡上少一个「不再询问」选项(人仍可逐次批;少的是选项不是门 —— 渲出一个读不懂的选项、或少一个成员的合取批,才是错的方向)。修前耐久腿丢元素是静默的,同步腿走一行 logger warn(`rule_offer_dropped_unreadable_shape`,随之退役)。计数非零 = 有 offer 列表的形本引擎读不懂:上游版本领先(core 加了词)或库里的行被手改过。detail = `index=<下标> problem=<RULE_OFFER_SHAPE_PROBLEMS 的词>`(不带 offer 文本 —— 那是命令原文族)。",
166
+ note: "core 7.55.0 #1468 P1 阶段二(`approval-card.ts` 的 `readRuleOfferList`,规则提议列表的唯一读者,判官 = core `readRuleOffers`;两条腿同调 —— 耐久腿 `checkpoint-store-face.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行;同步腿 `tool-approval.ts` `boundRuleOfferTexts`:活 ask 的 `AskRequest.ruleOffers`):一个元素读不出(`unknown_word`:offer / 成员的 `kind`、`match` 是本引擎不认的词 —— 更新的铸者或别的写者;`malformed`:不是对象、成员缺位或错型、空 batch、计数不是非负安全整数)⇒ 这一只整只丢(batch 不拆成员)、兄弟照投;整只值在场却不是列表(`not_an_array`)⇒ 这一行无供给。逐元素计。放行的最坏后果 = 卡上少一个「不再询问」选项(人仍可逐次批;少的是选项不是门 —— 渲出一个读不懂的选项、或少一个成员的合取批,才是错的方向)。修前耐久腿丢元素是静默的,同步腿走一行 logger warn(`rule_offer_dropped_unreadable_shape`,随之退役)。计数非零 = 有 offer 列表的形本引擎读不懂:上游版本领先(core 加了词)或库里的行被手改过。detail = `index=<下标> problem=<RULE_OFFER_SHAPE_PROBLEMS 的词>`(不带 offer 文本 —— 那是命令原文族)。",
171
167
  },
172
168
  "server.rules.ticket-claim-release-failed": {
173
169
  cls: "F",
@@ -183,7 +179,7 @@ export const FAIL_OPEN_TAGS = {
183
179
  },
184
180
  "server.approvals.park-row-blob-unreadable": {
185
181
  cls: "F",
186
- note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)",
182
+ note: "S-700(`stores-sql/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)",
187
183
  },
188
184
  "server.approvals.queue-row-agent-unreadable": {
189
185
  cls: "F",
@@ -201,17 +197,21 @@ export const FAIL_OPEN_TAGS = {
201
197
  cls: "F",
202
198
  note: "`session-notify-door.ts` 的 `deliver`(会话通知门的判活读;两只调用方 `POST /v1/sessions/:id/notify` 与后台子代完成 relay 同经):判活读 —— run 店的单活认领读 `getActiveTaskId` —— 抛(店瞬断 / 超时 / 连接被回收)⇒ 门当这只会话**没有在飞的 run**,落空闲臂:入收件箱,下次开流排空成 `task_notification` 帧,不把读失败抛给调用方。放行的最坏后果 = 这一条通知晚到 —— 本该在活流的下一个边界投递(`priority: next`),改成下一次开流才排空(至少一次,晚一次开流),不丢、不错投;两臂的投递动作之前紧邻的住客复核照做,所以这不是门、不是权限、不是凭证。不放行(抛)= 一次 run 店瞬断把通知路由答成 500(经全局兜底)、把后台子代的完成通知记成 `relay_failed` 交不出去,比晚一次开流更糟。读失败与「会话真的空闲」在外部同形,所以必须留痕:计数 + 探针(detail 带会话 id 与错句,经记录器统一脱敏)+ 每进程一次 warn。",
203
199
  },
200
+ "server.session-id-tombstone.evicted": {
201
+ cls: "P-DEBT",
202
+ note: "`deleted-session-ids.ts` 的 `retireSessionId`(本进程删过的会话 id → 删前属主那张表的唯一铸点;执行上下文解析器 `resolveExecutionContext` 读它,拒本进程上这只 id 的执行服务删前属主之外的住客 —— 409 `conflict.session_id_retired`):表满(`DELETED_SESSION_ID_CAP` 条)⇒ 驱逐最旧的一条,那个 id 回到「本进程没删过」。保护面、方向明知是放行 ⇒ 记债:表独自守着一个窄 P 面 —— 本服务按裸会话 id 键的通告分流器(`EngineNoticeRouter`)收委派腿的用户面通告,引擎 7.64.0 的地址是树根会话 id、不带住客 ⇒ 被驱逐的那个 id 上,另一位属主在本进程重登之后,前任住客子代的被拒通告可按 id 落进新住客的流(暂存那一形不在其内:引擎 7.64.0 起按住客存取,弃掉、运维席一条 delegation.delivery_discarded)。不放行的形是表无界增长。收口条件 = core #3479(委派腿通告地址带根住客)到货 ∧ 服务侧按裸会话 id 键的座普查为零 —— 届时表、本 tag 与 409 `conflict.session_id_retired` 一并退。",
203
+ },
204
204
  "server.approvals.queue-row-gate-kind-missing": {
205
205
  cls: "F",
206
- note: "S-1681(`plugins/checkpoint-store-sql.ts` 的 `queueRowGateKind`,7.132.0;SQL 与 local 两只孪生的 `listPending` 同调这一只判官):运维待批队列(`GET /v1/approvals` / `/stream`)读到一行 pending 的门型(SQL 孪生:`checkpoint.gate_kind` 列;local 孪生:快照上的门)是 NULL 或不是 core 登记的门型 ⇒ 这一行**不列**。按构造不可达:每次停驻都把门型反范式进这一列,一次性迁移 M21 把没有它的存量行从门子树补齐(读不出登记门型的置 expired)。放行(不列、队列其余照常)的最坏后果 = 一行谁也决不了的行不出现在队列上 —— 它本来就不可决:每一条决断口按门型绑定取行(`gate_kind IN (…)`),证不出门型就不当它是这道门;不放行(整只拒)的代价是一行坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧)。也不按缺键投出去:消费方按 `gateKind` 路由、缺键即 fail-closed,队列行的契约是 `gateKind` 恒在场。故 F 类;计数非零 = 写腿或手改出了错,`SELECT session_id FROM checkpoint WHERE status = 'pending' AND gate_kind IS NULL` 查那一行(置 expired 或删会话)。",
206
+ note: "S-1681(`plugins/checkpoint-store-face.ts` 的 `queueRowGateKind`,7.132.0;SQL 与 local 两只孪生的 `listPending` 同调这一只判官):运维待批队列(`GET /v1/approvals` / `/stream`)读到一行 pending 的门型(SQL 孪生:`checkpoint.gate_kind` 列;local 孪生:快照上的门)是 NULL 或不是 core 登记的门型 ⇒ 这一行**不列**。按构造不可达:每次停驻都把门型反范式进这一列,一次性迁移 M21 把没有它的存量行从门子树补齐(读不出登记门型的置 expired)。放行(不列、队列其余照常)的最坏后果 = 一行谁也决不了的行不出现在队列上 —— 它本来就不可决:每一条决断口按门型绑定取行(`gate_kind IN (…)`),证不出门型就不当它是这道门;不放行(整只拒)的代价是一行坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧)。也不按缺键投出去:消费方按 `gateKind` 路由、缺键即 fail-closed,队列行的契约是 `gateKind` 恒在场。故 F 类;计数非零 = 写腿或手改出了错,`SELECT session_id FROM checkpoint WHERE status = 'pending' AND gate_kind IS NULL` 查那一行(置 expired 或删会话)。",
207
207
  },
208
208
  "server.sql-json.checkpoint.pending-steer-queue-lossy": {
209
209
  cls: "F",
210
- note: "S-550(`plugins/checkpoint-store-sql.ts` 的 `get()`,core 5.14.0 #147 的耐久转向队列):一条挂起 run 的 `checkpoint.pending_steer_queue` 这一格**没能完整读出来**(不是合法 JSON 文本 / 不是数组 / 某一条目的四个必备键不合形)⇒ 读不出的那部分**丢掉**,run 照常 resume。放行的最坏后果 = 一条已经 park 的操作员转向指令**没有**在这次 resume 上注入(人以为说过的话没送到);不放行的代价是这条挂起的 run **永远不可 resume** —— resume 是它唯一的出路,为一格读不出的转向把整条 run 变成砖是错误的失败方向(写侧刻意相反:`setPendingSteer` 往一份读不全的队列上追加会把读不出的条目永久抹掉,那里 fail-loud)。故 F 类。留痕从一条 `logger.info` 升成登记 tag 的理由:日志行在**遥测轴**上是零信号,「这台机器的转向队列一直读不出来」与「这台机器本来就没人 steer」在指标上完全同形。计数非零 = 去按日志里的 token 指纹查那一行。",
210
+ note: "S-550(`stores-sql/checkpoint-store-sql.ts` 的 `get()`,core 5.14.0 #147 的耐久转向队列):一条挂起 run 的 `checkpoint.pending_steer_queue` 这一格**没能完整读出来**(不是合法 JSON 文本 / 不是数组 / 某一条目的四个必备键不合形)⇒ 读不出的那部分**丢掉**,run 照常 resume。放行的最坏后果 = 一条已经 park 的操作员转向指令**没有**在这次 resume 上注入(人以为说过的话没送到);不放行的代价是这条挂起的 run **永远不可 resume** —— resume 是它唯一的出路,为一格读不出的转向把整条 run 变成砖是错误的失败方向(写侧刻意相反:`setPendingSteer` 往一份读不全的队列上追加会把读不出的条目永久抹掉,那里 fail-loud)。故 F 类。留痕从一条 `logger.info` 升成登记 tag 的理由:日志行在**遥测轴**上是零信号,「这台机器的转向队列一直读不出来」与「这台机器本来就没人 steer」在指标上完全同形。计数非零 = 去按日志里的 token 指纹查那一行。",
211
211
  },
212
212
  "server.sql-json.checkpoint.outcome-unreadable": {
213
213
  cls: "F",
214
- note: "S-550(`plugins/checkpoint-store-sql.ts` 的 `findDecidedApprovalsForBinding`,`/decide` 的**幂等回放**腿):一条已决 checkpoint 行的 `outcome` 这一格读不出形(手改 / 撕裂写 / 迁移脚本改过)⇒ 这一行交出 `decision: null`(= 判别不出),调用方按「整次拒绝」处置。放行的最坏后果 = 一次 decide **重试**拿不到上次的判词,退回按新请求处理(而不是回放)—— 回放是锦上添花的腿,让一条读不出的 JSON 把一次重试变成 500 比这更坏;方向上没有任何批准被放宽(判不出就是判不出,调用方拒绝)。故 F 类。**只容忍体的问题**:`not-text`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。",
214
+ note: "S-550(`stores-sql/checkpoint-store-sql.ts` 的 `findDecidedApprovalsForBinding`,`/decide` 的**幂等回放**腿):一条已决 checkpoint 行的 `outcome` 这一格读不出形(手改 / 撕裂写 / 迁移脚本改过)⇒ 这一行交出 `decision: null`(= 判别不出),调用方按「整次拒绝」处置。放行的最坏后果 = 一次 decide **重试**拿不到上次的判词,退回按新请求处理(而不是回放)—— 回放是锦上添花的腿,让一条读不出的 JSON 把一次重试变成 500 比这更坏;方向上没有任何批准被放宽(判不出就是判不出,调用方拒绝)。故 F 类。**只容忍体的问题**:`not-text`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。",
215
215
  },
216
216
  "server.sql-json.checkpoint.execution-outcome-unreadable": {
217
217
  cls: "F",
@@ -583,6 +583,10 @@ export const FAIL_OPEN_TAGS = {
583
583
  cls: "F",
584
584
  note: "在飞 run 的切档口(`http/routes/run-permission-mode.ts`,`POST /v1/runs/:id/permission-mode`):引擎已经收下新档(本腿下一次工具调用按它仲裁),把准入的词写回这条 run 存储体(run 模式词的唯一来源,续跑腿按它重建 spec)没有落定 —— 这一刻这条 run 已不持有会话认领或已不在跑(`claim_released`:切档与停驻 / 终局同时到;认领栅栏拒写,不会拿旧 run 的体盖掉同会话新 run 的)、会话没有存储体行(`context_absent`)、店写抛(`store_failed`:库抖 / 一行装不下 / 封签失败)。每次记一次 + 一行 warn,回执 `persisted:false` + `persistMiss` 照实告诉壳。放行的最坏后果 = 下一条腿(停驻后续跑 / 重启后续跑)回到切档前的词:切松了 ⇒ 续跑回到更严的档(多问);切严了 ⇒ 续跑回到切档前更松的档 —— 那一档是这条 run 提交时受理过的,受理判官当时判过,不越过任何部署拒;不是门、不是凭据。计数非零 = 切档常与停驻相撞或 checkpoint 店在出错;壳据 `persisted` 在续跑后重切。detail = `miss=<词> mode=<词>`。",
585
585
  },
586
+ "server.capabilities.adoption-import-unreadable": {
587
+ cls: "F",
588
+ note: "能力位 `adoptionImport`(`adoption/import.ts` 的 `readAdoptionImportCapability`,`GET /v1/capabilities` 每请求一读):按调用者读它作为源主体的那一条收编行时库读抛(断连 / 超时 / 池断)⇒ 这一位缺席、能力面照常 200。放行的是**藏**的方向:缺席 = 「你还没被收编」,触发臂不出导入入口,导入口本身不受影响(它自己读行、读失败照常 5xx)。最坏后果 = 这一拍用户看不到「一键收编」,下一次读能力面恢复。计数非零 = 收编日志所在的库在这台副本上读不动。",
589
+ },
586
590
  };
587
591
  export function failOpenTagForDroppedFrame(frameType) {
588
592
  switch (frameType) {