@sema-agent/server 7.144.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 (305) hide show
  1. package/MIGRATION.md +621 -0
  2. package/README.md +3 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +233 -54
  5. package/deploy/facts/CHANGES.json +25 -0
  6. package/deploy/facts/README.md +57 -0
  7. package/deploy/facts/lanes.json +54 -0
  8. package/deploy/facts/lanes.schema.json +57 -0
  9. package/deploy/facts/sandbox-rbac.json +113 -0
  10. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  11. package/deploy/facts/sealed-key.json +9 -0
  12. package/deploy/facts/sealed-key.schema.json +52 -0
  13. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  14. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  15. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  16. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  17. package/deploy/sema-up/chart/values.yaml +7 -0
  18. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  19. package/dist/adoption/import-limits.d.ts +6 -0
  20. package/dist/adoption/import-limits.js +7 -0
  21. package/dist/adoption/import.d.ts +62 -0
  22. package/dist/adoption/import.js +107 -0
  23. package/dist/adoption/wire.d.ts +52 -0
  24. package/dist/adoption/wire.js +9 -0
  25. package/dist/approval-ask-machine.d.ts +2 -2
  26. package/dist/approval-card.d.ts +3 -12
  27. package/dist/approval-card.js +0 -4
  28. package/dist/approval-gate-currency.d.ts +1 -1
  29. package/dist/approval-gate-currency.js +1 -1
  30. package/dist/approval-reconciler.d.ts +1 -1
  31. package/dist/audit.d.ts +2 -21
  32. package/dist/audit.js +0 -9
  33. package/dist/boot/deployment-mods.d.ts +11 -1
  34. package/dist/boot/deployment-mods.js +15 -2
  35. package/dist/boot/device-lane.js +2 -0
  36. package/dist/boot/engine-lease.d.ts +193 -21
  37. package/dist/boot/engine-lease.js +146 -20
  38. package/dist/boot/execution-env.d.ts +4 -0
  39. package/dist/boot/execution-env.js +12 -0
  40. package/dist/boot/exit-boundary.d.ts +50 -0
  41. package/dist/boot/exit-boundary.js +32 -0
  42. package/dist/boot/exit-last.d.ts +20 -4
  43. package/dist/boot/exit-last.js +21 -4
  44. package/dist/boot/governance-seams.js +1 -0
  45. package/dist/boot/memory-consolidation.d.ts +29 -17
  46. package/dist/boot/memory-consolidation.js +26 -15
  47. package/dist/boot/reapers.d.ts +12 -4
  48. package/dist/boot/reapers.js +39 -15
  49. package/dist/boot/resolve-spec.d.ts +2 -0
  50. package/dist/boot/resolve-spec.js +38 -15
  51. package/dist/boot/runner-deps.js +1 -1
  52. package/dist/boot/session-faces.d.ts +1 -1
  53. package/dist/boot/session-faces.js +6 -4
  54. package/dist/boot/shutdown.js +27 -9
  55. package/dist/boot/stage-01-config.js +1 -1
  56. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  57. package/dist/boot/stage-03-store-backend.js +2 -2
  58. package/dist/boot/stage-04-stores.d.ts +1 -0
  59. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  60. package/dist/boot/stage-05-execution-env.js +3 -3
  61. package/dist/boot/stage-06-runners.d.ts +3 -0
  62. package/dist/boot/stage-06-runners.js +11 -10
  63. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  64. package/dist/boot/stage-07-capability-layer.js +7 -2
  65. package/dist/boot/stage-08-reapers.d.ts +3 -0
  66. package/dist/boot/stage-08-reapers.js +3 -3
  67. package/dist/boot/stage-09-leader.d.ts +4 -1
  68. package/dist/boot/stage-10-http-server.d.ts +4 -1
  69. package/dist/boot/stage-10-http-server.js +4 -3
  70. package/dist/boot/stores.d.ts +1 -0
  71. package/dist/boot/stores.js +35 -19
  72. package/dist/boot/workflow-orchestration.d.ts +1 -1
  73. package/dist/boot/workflow-orchestration.js +2 -1
  74. package/dist/capabilities/composite-members.d.ts +3 -1
  75. package/dist/capabilities/composite-members.js +3 -1
  76. package/dist/capabilities/scenarios.d.ts +2 -2
  77. package/dist/capability-facts.d.ts +18 -1
  78. package/dist/capability-facts.js +25 -7
  79. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  80. package/dist/config-catalog.js +13 -4
  81. package/dist/config-d-migration.d.ts +3 -2
  82. package/dist/config-provider.d.ts +2 -2
  83. package/dist/config-types.d.ts +43 -4
  84. package/dist/config.d.ts +6 -1
  85. package/dist/config.js +67 -11
  86. package/dist/deleted-session-ids.d.ts +19 -0
  87. package/dist/deleted-session-ids.js +26 -0
  88. package/dist/deploy-facts.d.ts +155 -0
  89. package/dist/deploy-facts.js +94 -0
  90. package/dist/device-ws-hub.d.ts +48 -3
  91. package/dist/device-ws-hub.js +48 -2
  92. package/dist/error-code-family.d.ts +35 -0
  93. package/dist/error-code-family.js +26 -0
  94. package/dist/fleet/drain-entry.d.ts +39 -3
  95. package/dist/fleet/drain-entry.js +6 -0
  96. package/dist/fleet/fleet-bus.d.ts +15 -4
  97. package/dist/fleet/fleet-bus.js +17 -3
  98. package/dist/hooks/branch-transcript.d.ts +1 -1
  99. package/dist/hooks/branch-transcript.js +1 -0
  100. package/dist/hooks/classic-stations.d.ts +25 -8
  101. package/dist/hooks/classic-stations.js +29 -3
  102. package/dist/hooks/hook-runner.d.ts +33 -16
  103. package/dist/hooks/hook-runner.js +166 -73
  104. package/dist/hooks/hook-source.d.ts +14 -2
  105. package/dist/hooks/hook-source.js +8 -0
  106. package/dist/http/active-run-conflict.d.ts +1 -1
  107. package/dist/http/active-run-conflict.js +1 -1
  108. package/dist/http/admission.js +13 -2
  109. package/dist/http/checkpoint-ctx.d.ts +60 -71
  110. package/dist/http/checkpoint-ctx.js +35 -40
  111. package/dist/http/dispatch.js +18 -2
  112. package/dist/http/durable-run-leg.d.ts +5 -0
  113. package/dist/http/durable-run-leg.js +8 -6
  114. package/dist/http/execution-context.d.ts +4 -0
  115. package/dist/http/execution-context.js +9 -0
  116. package/dist/http/health-self-report.d.ts +6 -2
  117. package/dist/http/health-self-report.js +3 -2
  118. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  119. package/dist/http/memory-compliance-failure-reply.js +2 -15
  120. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  121. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  122. package/dist/http/principal-gate.d.ts +35 -12
  123. package/dist/http/principal-gate.js +16 -12
  124. package/dist/http/request-guards.d.ts +1 -1
  125. package/dist/http/request-guards.js +5 -5
  126. package/dist/http/resume-legs.d.ts +22 -0
  127. package/dist/http/resume-legs.js +31 -20
  128. package/dist/http/route-ctx.d.ts +26 -10
  129. package/dist/http/route-table.js +2 -0
  130. package/dist/http/routes/adoption.d.ts +11 -0
  131. package/dist/http/routes/adoption.js +80 -6
  132. package/dist/http/routes/agents-roster.js +1 -0
  133. package/dist/http/routes/approvals-assistant.d.ts +20 -1
  134. package/dist/http/routes/approvals-assistant.js +29 -7
  135. package/dist/http/routes/background.js +1 -0
  136. package/dist/http/routes/capabilities.js +4 -1
  137. package/dist/http/routes/diagnostics.d.ts +9 -14
  138. package/dist/http/routes/diagnostics.js +10 -20
  139. package/dist/http/routes/engine.d.ts +31 -0
  140. package/dist/http/routes/engine.js +81 -0
  141. package/dist/http/routes/memory-bundle.js +3 -0
  142. package/dist/http/routes/memory-consolidation.js +3 -5
  143. package/dist/http/routes/memory-origin.d.ts +1 -1
  144. package/dist/http/routes/memory-origin.js +2 -4
  145. package/dist/http/routes/memory-policy.js +5 -1
  146. package/dist/http/routes/observability.js +3 -6
  147. package/dist/http/routes/rules.d.ts +1 -1
  148. package/dist/http/routes/rules.js +5 -2
  149. package/dist/http/routes/runs.js +7 -3
  150. package/dist/http/routes/session-sync.js +24 -25
  151. package/dist/http/routes/sessions-list.d.ts +1 -1
  152. package/dist/http/routes/sessions.js +4 -0
  153. package/dist/http/routes/tasks.js +35 -14
  154. package/dist/http/routes/trace-usage.js +1 -1
  155. package/dist/http/run-concurrency-cap.d.ts +86 -0
  156. package/dist/http/run-concurrency-cap.js +54 -0
  157. package/dist/http/run-meta.d.ts +14 -7
  158. package/dist/http/run-meta.js +5 -2
  159. package/dist/http/server.d.ts +27 -16
  160. package/dist/http/server.js +21 -3
  161. package/dist/http/stored-body-replay.d.ts +9 -6
  162. package/dist/http/stored-body-replay.js +19 -5
  163. package/dist/http/submit-ctx.d.ts +12 -0
  164. package/dist/http/submit-ctx.js +23 -0
  165. package/dist/http/wire-types.d.ts +8 -3
  166. package/dist/json-body-limit.d.ts +8 -0
  167. package/dist/json-body-limit.js +2 -0
  168. package/dist/leader/diffout.d.ts +1 -1
  169. package/dist/local-data-root.d.ts +2 -2
  170. package/dist/memory-operator-faces.d.ts +9 -4
  171. package/dist/memory-scope-stores.d.ts +9 -7
  172. package/dist/memory-scope-stores.js +3 -14
  173. package/dist/memory-scope.d.ts +36 -0
  174. package/dist/memory-scope.js +32 -1
  175. package/dist/net-address.d.ts +53 -0
  176. package/dist/net-address.js +111 -0
  177. package/dist/observability/fail-open.d.ts +28 -12
  178. package/dist/observability/fail-open.js +28 -12
  179. package/dist/orchestration/workflow-notify-journal.js +2 -3
  180. package/dist/org-delivery-gate.js +1 -1
  181. package/dist/peer-directory.d.ts +6 -12
  182. package/dist/peer-directory.js +5 -1
  183. package/dist/plugins/approval-ask-store-file.d.ts +16 -2
  184. package/dist/plugins/approval-ask-store-file.js +21 -1
  185. package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
  186. package/dist/plugins/approval-ask-store-memory.js +11 -8
  187. package/dist/plugins/caching-session-store.d.ts +6 -1
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  190. package/dist/plugins/checkpoint-store-face.js +152 -0
  191. package/dist/plugins/file-run-store.d.ts +13 -7
  192. package/dist/plugins/file-run-store.js +12 -13
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  194. package/dist/plugins/fork-routing-session-store.js +2 -2
  195. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  196. package/dist/plugins/local-checkpoint-store.d.ts +16 -5
  197. package/dist/plugins/local-checkpoint-store.js +25 -6
  198. package/dist/plugins/local-session-store.d.ts +80 -21
  199. package/dist/plugins/local-session-store.js +79 -22
  200. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  201. package/dist/plugins/memory-engine-pg.js +96 -214
  202. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  203. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  204. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  205. package/dist/plugins/memory-engine-tidb.js +97 -227
  206. package/dist/plugins/memory-key-guards.d.ts +1 -1
  207. package/dist/plugins/memory-origin-law.d.ts +3 -3
  208. package/dist/plugins/memory-run-store.d.ts +2 -0
  209. package/dist/plugins/memory-run-store.js +6 -0
  210. package/dist/plugins/one-time-migrations.d.ts +32 -56
  211. package/dist/plugins/one-time-migrations.js +27 -119
  212. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  213. package/dist/plugins/permission-rule-store-file.js +8 -1
  214. package/dist/plugins/pg-pool.js +1 -1
  215. package/dist/plugins/pg-session-storage.d.ts +17 -4
  216. package/dist/plugins/pg-session-storage.js +8 -4
  217. package/dist/plugins/run-store-sql.d.ts +4 -0
  218. package/dist/plugins/run-store-sql.js +5 -2
  219. package/dist/plugins/schema-ensure-legs.js +2 -2
  220. package/dist/plugins/session-fork.d.ts +31 -9
  221. package/dist/plugins/session-fork.js +3 -2
  222. package/dist/plugins/session-placement.d.ts +4 -2
  223. package/dist/plugins/session-store.d.ts +1 -1
  224. package/dist/plugins/sql-json-column.d.ts +5 -1
  225. package/dist/plugins/store-backend.d.ts +11 -8
  226. package/dist/plugins/store-backend.js +8 -7
  227. package/dist/plugins/store-contracts.d.ts +1 -11
  228. package/dist/plugins/store-contracts.js +0 -9
  229. package/dist/plugins/store-sweep.d.ts +63 -0
  230. package/dist/plugins/store-sweep.js +48 -0
  231. package/dist/plugins/tidb-pool.js +1 -1
  232. package/dist/plugins/tidb-session-store.d.ts +16 -3
  233. package/dist/plugins/tidb-session-store.js +8 -4
  234. package/dist/prompt-screen.d.ts +18 -0
  235. package/dist/prompt-screen.js +5 -0
  236. package/dist/rules-consent.d.ts +56 -51
  237. package/dist/rules-consent.js +86 -14
  238. package/dist/run-acceptance.d.ts +40 -10
  239. package/dist/run-acceptance.js +38 -5
  240. package/dist/run-cancel-context.d.ts +4 -1
  241. package/dist/run-cancel-context.js +2 -1
  242. package/dist/runs.js +2 -2
  243. package/dist/sandbox-egress-policy.js +6 -11
  244. package/dist/sandbox-rbac-rules.d.ts +88 -0
  245. package/dist/sandbox-rbac-rules.js +80 -0
  246. package/dist/sealed-key-layout.d.ts +17 -0
  247. package/dist/sealed-key-layout.js +4 -0
  248. package/dist/sealed-key.js +5 -5
  249. package/dist/security.d.ts +48 -9
  250. package/dist/security.js +9 -2
  251. package/dist/session-agent.d.ts +39 -0
  252. package/dist/session-agent.js +16 -0
  253. package/dist/session-error-wire.d.ts +4 -4
  254. package/dist/session-notify-door.d.ts +5 -3
  255. package/dist/session-resident-background.d.ts +57 -0
  256. package/dist/session-resident-background.js +20 -0
  257. package/dist/session-sync-kernel.d.ts +53 -14
  258. package/dist/session-sync-kernel.js +70 -1
  259. package/dist/session-sync.d.ts +5 -3
  260. package/dist/session-workspace.d.ts +1 -0
  261. package/dist/session-workspace.js +1 -0
  262. package/dist/sighup-idle.d.ts +9 -7
  263. package/dist/sighup-idle.js +4 -5
  264. package/dist/spec-fields.d.ts +16 -0
  265. package/dist/spec-fields.js +7 -0
  266. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  267. package/dist/stored-request-env-credentials-m38.js +8 -0
  268. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  269. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +33 -429
  270. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +70 -209
  271. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  272. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  273. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  274. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  275. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  276. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  277. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  278. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  279. package/dist/task-settings.d.ts +59 -4
  280. package/dist/task-settings.js +50 -4
  281. package/dist/tool-approval.d.ts +2 -2
  282. package/dist/trace/core-keyset-guard.d.ts +8 -7
  283. package/dist/trace/engine-notice-wire.d.ts +1 -1
  284. package/dist/trace/engine-notice-wire.js +2 -0
  285. package/dist/trace/exit-seat.d.ts +6 -0
  286. package/dist/trace/exit-seat.js +1 -0
  287. package/dist/trace/model-segment.d.ts +3 -2
  288. package/dist/trace/model-segment.js +16 -8
  289. package/dist/trace/project.js +9 -0
  290. package/dist/trace/redact.d.ts +79 -4
  291. package/dist/trace/redact.js +523 -123
  292. package/dist/trace/self-minted-wire.d.ts +391 -1
  293. package/dist/trace/self-minted-wire.js +145 -0
  294. package/dist/trace/wire-projection-faces.d.ts +1 -1
  295. package/dist/trace/wire-projection-faces.js +1 -1
  296. package/dist/usage-analytics.d.ts +4 -0
  297. package/package.json +12 -4
  298. package/scripts/drain-check-local.mjs +8 -29
  299. package/scripts/drain-check.mysql.sql +3 -24
  300. package/scripts/drain-check.pg.sql +3 -24
  301. package/skills/update-config.md +1 -1
  302. package/wire-changes/server@7.145.0.json +146 -0
  303. package/wire-changes/server@7.146.0.json +3221 -0
  304. package/dist/approval-batch-census.d.ts +0 -27
  305. package/dist/approval-batch-census.js +0 -27
@@ -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
@@ -21,7 +21,7 @@ export type FailOpenEntry = {
21
21
  export declare const FAIL_OPEN_TAGS: {
22
22
  readonly "server.approval-ask-journal.compaction-failed": {
23
23
  readonly cls: "F";
24
- readonly note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。";
24
+ readonly note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,与起服重放到删行记录时的那一次压实 —— 同一只 `compactOrRecord`;local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实(删行记录引起的压实失败,位 `removalRecordsOnDisk` 留着:下一次任何写、或下一次起服再试;起服那一次失败同样只留痕、不拒启)。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。";
25
25
  };
26
26
  readonly "server.approval-ask-journal.corrupt-record-skipped": {
27
27
  readonly cls: "F";
@@ -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,11 @@ 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 另有一座:判官判决 `rowVerdict` 与技能卡两位共用的那一次**整行读**(`projectStoredRow`;按快照摘要记忆,未命中才读)—— 整行解不出 ⇒ 这一行不带判决与两位;体是对象但 core 摘要读不动 ⇒ 判决照给、只丢两位;两形逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。 (`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` 整行读取代,树上零命中。)";
201
+ };
202
+ readonly "server.approvals.queue-row-agent-unreadable": {
203
+ readonly cls: "F";
204
+ readonly note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `session-agent.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。";
205
205
  };
206
206
  readonly "server.approvals.durable-row-checkpoint-id-missing": {
207
207
  readonly cls: "F";
@@ -215,17 +215,21 @@ export declare const FAIL_OPEN_TAGS: {
215
215
  readonly cls: "F";
216
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。";
217
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
+ };
218
222
  readonly "server.approvals.queue-row-gate-kind-missing": {
219
223
  readonly cls: "F";
220
- 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 或删会话)。";
221
225
  };
222
226
  readonly "server.sql-json.checkpoint.pending-steer-queue-lossy": {
223
227
  readonly cls: "F";
224
- 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 指纹查那一行。";
225
229
  };
226
230
  readonly "server.sql-json.checkpoint.outcome-unreadable": {
227
231
  readonly cls: "F";
228
- 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`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。";
229
233
  };
230
234
  readonly "server.sql-json.checkpoint.execution-outcome-unreadable": {
231
235
  readonly cls: "F";
@@ -373,7 +377,7 @@ export declare const FAIL_OPEN_TAGS: {
373
377
  };
374
378
  readonly "server.run-terminal.redact-threw": {
375
379
  readonly cls: "F";
376
- readonly note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。";
380
+ readonly note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位;块界上扫描窗前移的认证扫描抛 ⇒ 窗不动,只是没省,交出的字节一个不变):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。";
377
381
  };
378
382
  readonly "server.run-terminal.provider-echo-shaped": {
379
383
  readonly cls: "F";
@@ -439,6 +443,14 @@ export declare const FAIL_OPEN_TAGS: {
439
443
  readonly cls: "F";
440
444
  readonly note: "S-1874 / S-2137(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):每行的 `objective` = 这道门所属 run 的目标预览 —— 按 run id 直读那一行的 `objectivePreview` 列(写入时已脱敏 + 截断;`GET /v1/assistant/tasks` 读同一列)。门 → run 是按键直读:门所在会话的认领持有者 / 最近一条腿,委派子代的门读派它的那条 run(停驻子代行上的 `parentTaskId`,行经判别器 `findParkedAgentForCheckpoint` 取)。某一行这几次直读失败(店抖动 / 那一行 run 的 `result` 格读不出 —— SQL `getRun` 对坏格刻意抛)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡这一次不显示它属于哪个任务(纯展示位;不参与任何决裁、续跑或门判)。不放行的代价是一行 run 读不出就打掉整个用户的待批列表(人看不到要批的卡)。故 F 类;必须留痕,否则「这一次没读成」与「这道门本来就没有 run」同形。detail = 那一行的会话 id 与错误句。前身(7.97.0–7.135.x):同一格读停驻上下文、坏体落 null 的那一只 tag(objective-ctx-corrupt),随 S-1874 退役(inbox 不再读续跑上下文)。";
441
445
  };
446
+ readonly "server.objective-delivery.face-fill-failed": {
447
+ readonly cls: "F";
448
+ readonly note: "`run-acceptance.ts` 的补写口(腿上装着 prompt 屏时,本服务存 / 转目标的面在提交时不写,引擎交付之后以交付的那一份补写):某一张面的补写抛错 —— `run-preview`(run 行预览列的写一次补写,店抖动 / 行已被收割删除)、`fleet-name`(进程内 fleet 行的名;不会抛,列在闭集里是为了词全)。放行的最坏后果 = 那张面保持提交时的**空**:预览缺席(列表 / 收件箱 / fleet 行不显示这条 run 是什么任务)—— 少写,不是写错:不会写出屏前原文,不参与任何门判、续跑决裁或模型输入。不放行的代价是一次展示面的写失败打断这条正在跑的 run。故 F 类;必须留痕,否则「补写失败」与「屏改写过、本来就没有可写的那一份」同形。detail = `face=<面> err=<错误句,经运维日志出口座>`。";
449
+ };
450
+ readonly "server.objective-delivery.verify-replay-copy": {
451
+ readonly cls: "P-DEBT";
452
+ readonly note: "`submit-ctx.ts` 的 `persistSubmissionCtx`:腿上装着 prompt 屏、且这次提交是 verify 形(只回结果的腿:宿主看不到受理帧,分不出屏改没改,也看不到有没有交付)⇒ 续跑输入照旧存请求原文的目标,不按「交付的那一份」写。理由:verify 形停驻后的续跑把续跑输入里的目标交给引擎的验证器(`resumeWithVerification` 的 `objective`),留空 = 验证器拿不到任务陈述;引擎自己的首跑验证器同样读请求原文。方向明知不对(屏丢弃 / 抛错 / 改写过的目标原文仍在 checkpoint ctx 里,直到这一行被收割),待引擎把交付的那一份交给宿主(含只回结果的腿)、验证器改读交付的目标之后修掉。每一次这样的提交记一次;计数非零 = 这台部署有「prompt 屏 + verify 形」的提交,它们的续跑输入里有屏前原文。detail = `session=<会话 id>`。";
453
+ };
442
454
  readonly "server.run-store.corrupt-record-skipped": {
443
455
  readonly cls: "F";
444
456
  readonly note: "S-582(`plugins/file-run-store.ts`,local 车道的 File 形 run 店;四个盘面同一只座):盘上一条记录读不出形 —— 一行 `42` / 缺本店必填键的对象 / 中间的半截 JSON(撕尾不走本 tag,那是崩溃的正常落盘形)⇒ 跳过它继续。前三个盘面各自的最坏后果:`run.json` 坏 ⇒ 那条 run 读成**缺席**(`GET /v1/runs/:id` 404,listRuns 少一行;它若占着 claim,EEXIST 路按「行不在」判残骸接管);`events.jsonl` 一行坏 ⇒ 回放少一个事件(其余照读、按 seq 去重不变);claim 记录坏 ⇒ 走既有的撕裂 claim 路(有非终局行就收编,否则隔离出 activeDir)。第四个盘面 `run-blobs/<会话>.jsonl`(`wiring_manifest` 行容器段的块账本,`plugins/wiring-section-codec.ts`)同一只座、两个检测点:① 重放时一条块记录形不合(`digest` 不是串 / `body` 不是容器)⇒ 跳过;② 读口(`getEvents`)装回时清单行引用的块不在本会话账本里(块缺:账本行被删 / 被跳过、断电丢尾、删会话时 run 目录删不掉留下的僵尸 run)⇒ 那一帧这一次不交出(永不交出缺段的清单),每个 `(taskId, seq)` 每进程计一次,`maxSeq` / `retainedFrom` 照旧按存位;明细 `kind=section-ref taskId= seq= sections=<段:摘要,…>`。块账本整份读不出(权限 / 挂载)不走本 tag,与 `events.jsonl` 读不出同一条路(strict 拒启,否则原样抛)。都是**可用性**损失,不开任何门 ⇒ F。修前三面全零披露(店自己的 `typeof … continue` 与 core 的静默跳过);计数让「这台机器的 run 账在腐」在遥测里显形。⚠️ `RUN_STORE_STRICT_HYDRATE=on` 的射程是「文件读不出」,不含「文件里有坏行」—— strict 档下坏行照走本 tag(未改 strict 语义,见普查表第 96 行)。";
@@ -613,6 +625,10 @@ export declare const FAIL_OPEN_TAGS: {
613
625
  readonly cls: "F";
614
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=<词>`。";
615
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
+ };
616
632
  };
617
633
  /** 词表键推导的闭集类型——未登记的 tag 传不进 {@link recordFailOpen}(编译期拒)。 */
618
634
  export type FailOpenTag = keyof typeof FAIL_OPEN_TAGS;
@@ -3,7 +3,7 @@ import { createLogger } from "./logger.js";
3
3
  export const FAIL_OPEN_TAGS = {
4
4
  "server.approval-ask-journal.compaction-failed": {
5
5
  cls: "F",
6
- note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。",
6
+ note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,与起服重放到删行记录时的那一次压实 —— 同一只 `compactOrRecord`;local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实(删行记录引起的压实失败,位 `removalRecordsOnDisk` 留着:下一次任何写、或下一次起服再试;起服那一次失败同样只留痕、不拒启)。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。",
7
7
  },
8
8
  "server.approval-ask-journal.corrupt-record-skipped": {
9
9
  cls: "F",
@@ -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,11 @@ 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 另有一座:判官判决 `rowVerdict` 与技能卡两位共用的那一次**整行读**(`projectStoredRow`;按快照摘要记忆,未命中才读)—— 整行解不出 ⇒ 这一行不带判决与两位;体是对象但 core 摘要读不动 ⇒ 判决照给、只丢两位;两形逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。 (`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` 整行读取代,树上零命中。)",
183
+ },
184
+ "server.approvals.queue-row-agent-unreadable": {
185
+ cls: "F",
186
+ note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `session-agent.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。",
187
187
  },
188
188
  "server.approvals.durable-row-checkpoint-id-missing": {
189
189
  cls: "F",
@@ -197,17 +197,21 @@ export const FAIL_OPEN_TAGS = {
197
197
  cls: "F",
198
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。",
199
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
+ },
200
204
  "server.approvals.queue-row-gate-kind-missing": {
201
205
  cls: "F",
202
- 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 或删会话)。",
203
207
  },
204
208
  "server.sql-json.checkpoint.pending-steer-queue-lossy": {
205
209
  cls: "F",
206
- 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 指纹查那一行。",
207
211
  },
208
212
  "server.sql-json.checkpoint.outcome-unreadable": {
209
213
  cls: "F",
210
- 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`(读腿漏了投影)与连接/超时一律原样上抛 —— 那是码坏或故障,不是数据坏。",
211
215
  },
212
216
  "server.sql-json.checkpoint.execution-outcome-unreadable": {
213
217
  cls: "F",
@@ -355,7 +359,7 @@ export const FAIL_OPEN_TAGS = {
355
359
  },
356
360
  "server.run-terminal.redact-threw": {
357
361
  cls: "F",
358
- note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。",
362
+ note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位;块界上扫描窗前移的认证扫描抛 ⇒ 窗不动,只是没省,交出的字节一个不变):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。",
359
363
  },
360
364
  "server.run-terminal.provider-echo-shaped": {
361
365
  cls: "F",
@@ -397,6 +401,14 @@ export const FAIL_OPEN_TAGS = {
397
401
  cls: "F",
398
402
  note: "S-1874 / S-2137(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):每行的 `objective` = 这道门所属 run 的目标预览 —— 按 run id 直读那一行的 `objectivePreview` 列(写入时已脱敏 + 截断;`GET /v1/assistant/tasks` 读同一列)。门 → run 是按键直读:门所在会话的认领持有者 / 最近一条腿,委派子代的门读派它的那条 run(停驻子代行上的 `parentTaskId`,行经判别器 `findParkedAgentForCheckpoint` 取)。某一行这几次直读失败(店抖动 / 那一行 run 的 `result` 格读不出 —— SQL `getRun` 对坏格刻意抛)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡这一次不显示它属于哪个任务(纯展示位;不参与任何决裁、续跑或门判)。不放行的代价是一行 run 读不出就打掉整个用户的待批列表(人看不到要批的卡)。故 F 类;必须留痕,否则「这一次没读成」与「这道门本来就没有 run」同形。detail = 那一行的会话 id 与错误句。前身(7.97.0–7.135.x):同一格读停驻上下文、坏体落 null 的那一只 tag(objective-ctx-corrupt),随 S-1874 退役(inbox 不再读续跑上下文)。",
399
403
  },
404
+ "server.objective-delivery.face-fill-failed": {
405
+ cls: "F",
406
+ note: "`run-acceptance.ts` 的补写口(腿上装着 prompt 屏时,本服务存 / 转目标的面在提交时不写,引擎交付之后以交付的那一份补写):某一张面的补写抛错 —— `run-preview`(run 行预览列的写一次补写,店抖动 / 行已被收割删除)、`fleet-name`(进程内 fleet 行的名;不会抛,列在闭集里是为了词全)。放行的最坏后果 = 那张面保持提交时的**空**:预览缺席(列表 / 收件箱 / fleet 行不显示这条 run 是什么任务)—— 少写,不是写错:不会写出屏前原文,不参与任何门判、续跑决裁或模型输入。不放行的代价是一次展示面的写失败打断这条正在跑的 run。故 F 类;必须留痕,否则「补写失败」与「屏改写过、本来就没有可写的那一份」同形。detail = `face=<面> err=<错误句,经运维日志出口座>`。",
407
+ },
408
+ "server.objective-delivery.verify-replay-copy": {
409
+ cls: "P-DEBT",
410
+ note: "`submit-ctx.ts` 的 `persistSubmissionCtx`:腿上装着 prompt 屏、且这次提交是 verify 形(只回结果的腿:宿主看不到受理帧,分不出屏改没改,也看不到有没有交付)⇒ 续跑输入照旧存请求原文的目标,不按「交付的那一份」写。理由:verify 形停驻后的续跑把续跑输入里的目标交给引擎的验证器(`resumeWithVerification` 的 `objective`),留空 = 验证器拿不到任务陈述;引擎自己的首跑验证器同样读请求原文。方向明知不对(屏丢弃 / 抛错 / 改写过的目标原文仍在 checkpoint ctx 里,直到这一行被收割),待引擎把交付的那一份交给宿主(含只回结果的腿)、验证器改读交付的目标之后修掉。每一次这样的提交记一次;计数非零 = 这台部署有「prompt 屏 + verify 形」的提交,它们的续跑输入里有屏前原文。detail = `session=<会话 id>`。",
411
+ },
400
412
  "server.run-store.corrupt-record-skipped": {
401
413
  cls: "F",
402
414
  note: "S-582(`plugins/file-run-store.ts`,local 车道的 File 形 run 店;四个盘面同一只座):盘上一条记录读不出形 —— 一行 `42` / 缺本店必填键的对象 / 中间的半截 JSON(撕尾不走本 tag,那是崩溃的正常落盘形)⇒ 跳过它继续。前三个盘面各自的最坏后果:`run.json` 坏 ⇒ 那条 run 读成**缺席**(`GET /v1/runs/:id` 404,listRuns 少一行;它若占着 claim,EEXIST 路按「行不在」判残骸接管);`events.jsonl` 一行坏 ⇒ 回放少一个事件(其余照读、按 seq 去重不变);claim 记录坏 ⇒ 走既有的撕裂 claim 路(有非终局行就收编,否则隔离出 activeDir)。第四个盘面 `run-blobs/<会话>.jsonl`(`wiring_manifest` 行容器段的块账本,`plugins/wiring-section-codec.ts`)同一只座、两个检测点:① 重放时一条块记录形不合(`digest` 不是串 / `body` 不是容器)⇒ 跳过;② 读口(`getEvents`)装回时清单行引用的块不在本会话账本里(块缺:账本行被删 / 被跳过、断电丢尾、删会话时 run 目录删不掉留下的僵尸 run)⇒ 那一帧这一次不交出(永不交出缺段的清单),每个 `(taskId, seq)` 每进程计一次,`maxSeq` / `retainedFrom` 照旧按存位;明细 `kind=section-ref taskId= seq= sections=<段:摘要,…>`。块账本整份读不出(权限 / 挂载)不走本 tag,与 `events.jsonl` 读不出同一条路(strict 拒启,否则原样抛)。都是**可用性**损失,不开任何门 ⇒ F。修前三面全零披露(店自己的 `typeof … continue` 与 core 的静默跳过);计数让「这台机器的 run 账在腐」在遥测里显形。⚠️ `RUN_STORE_STRICT_HYDRATE=on` 的射程是「文件读不出」,不含「文件里有坏行」—— strict 档下坏行照走本 tag(未改 strict 语义,见普查表第 96 行)。",
@@ -571,6 +583,10 @@ export const FAIL_OPEN_TAGS = {
571
583
  cls: "F",
572
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=<词>`。",
573
585
  },
586
+ "server.capabilities.adoption-import-unreadable": {
587
+ cls: "F",
588
+ note: "能力位 `adoptionImport`(`adoption/import.ts` 的 `readAdoptionImportCapability`,`GET /v1/capabilities` 每请求一读):按调用者读它作为源主体的那一条收编行时库读抛(断连 / 超时 / 池断)⇒ 这一位缺席、能力面照常 200。放行的是**藏**的方向:缺席 = 「你还没被收编」,触发臂不出导入入口,导入口本身不受影响(它自己读行、读失败照常 5xx)。最坏后果 = 这一拍用户看不到「一键收编」,下一次读能力面恢复。计数非零 = 收编日志所在的库在这台副本上读不动。",
589
+ },
574
590
  };
575
591
  export function failOpenTagForDroppedFrame(frameType) {
576
592
  switch (frameType) {
@@ -4,6 +4,7 @@ import { buildFleetWorkflowRow } from "../fleet/fleet-bus.js";
4
4
  import { isTerminalWorkflowRowStatus, seedTerminalWorkflowRow } from "../fleet/fleet-terminal-window.js";
5
5
  import { buildParkSessionRows } from "./workflow-agent-session-index.js";
6
6
  import { recordFailOpen } from "../observability/fail-open.js";
7
+ import { seatText } from "../trace/exit-seat.js";
7
8
  import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
8
9
  export const WORKFLOW_NOTIFY_KEY_DISPOSITION = {
9
10
  runId: "carry",
@@ -25,10 +26,8 @@ export function recoverySummary(status, error) {
25
26
  if (status === "completed")
26
27
  return "workflow completed";
27
28
  const base = error ? `workflow failed: ${error}` : "workflow failed";
28
- const redacted = base
29
+ const redacted = seatText("workflow-recovery-summary", base)
29
30
  .replace(/https?:\/\/[^\s"'`]+/gi, REDACTION_MARKS.url)
30
- .replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi, "[redacted-token]")
31
- .replace(/\b(?:api[_-]?key|secret|token|password|authorization)\b\s*[:=]\s*"?[^\s"',}]+/gi, "[redacted-secret]")
32
31
  .replace(/(?:\/[A-Za-z0-9_.-]+){2,}/g, REDACTION_MARKS.path)
33
32
  .replace(/(?:[A-Za-z]:)?(?:\\{1,2}[A-Za-z0-9_.$-]+){2,}/g, REDACTION_MARKS.path);
34
33
  return redacted.length > SUMMARY_MAX ? `${redacted.slice(0, SUMMARY_MAX)}…[+${redacted.length - SUMMARY_MAX} chars]` : redacted;
@@ -1,6 +1,6 @@
1
1
  import { CrossSessionCodecError, MAILBOX_TOMBSTONED_RECIPIENT_CODE, PRINCIPAL_INBOX_HANDLE, peerSessionBoxHandle, mintCrossPrincipalRecord, uuidv7, } from "@sema-agent/core";
2
2
  import { principalShapeProblem } from "./security.js";
3
- import { mailboxKeyProblem } from "./plugins/mailbox-store-sql.js";
3
+ import { mailboxKeyProblem } from "./stores-sql/mailbox-store-sql.js";
4
4
  export const ORG_DELIVERY_QUOTA = Object.freeze({ windowMs: 3_600_000, attemptsPerSender: 60, perPair: 10, perRecipient: 30 });
5
5
  export const PRINCIPAL_INBOX_BOUND = 50;
6
6
  export const ORG_DELIVERY_REFUSAL_MESSAGES = Object.freeze({
@@ -63,6 +63,9 @@
63
63
  * · `tempo` = `sessionTempoOfRunStatus(lastStatus)`(`plugins/store-contracts.ts` 的那**一张**表,
64
64
  * `GET /v1/sessions` 的 `tempo` 列读的是同一只函数 —— 一处定义两处读);
65
65
  * · `inboundPosture` = managed 层 `crossSessionInbound === "refuse"` ⇒ `"unavailable"`,否则 `"available"`;
66
+ * · `occupant` = 会话行的化身(`session_meta.incarnation`,与列表行**同一次读** —— lister 交 `{ row, occupant }`,化身从不进行本身)= 会话腿 acquire
67
+ * 读到的那一位(core 7.64.0 起跨会话信与回执按 (会话 id, 住客) 投:目录投的若是别的一格,寄往这只会话的每封信都会被判成「给另一位住客的」而丢弃);
68
+ * 行上没有化身(本仓的店每建一行铸一枚,只有坏行 / 人为改库才缺)⇒ `null`。令牌只进引擎(`ListAgents` 不渲染它),本仓不把它投上 wire / 日志正文;
66
69
  * · `pid` / `procStartMs` / `sockPath` / `cwd` = **恒缺席**(server 会话是耐久可寻址实体,不是进程;
67
70
  * 缺席即 core 的探活臂按 `isPeerSessionProcessAlive` 直接跳过);
68
71
  * · `peerProtocol` / `peerFeatures` = 不铸(v1 不声明 CC 能力位;core 侧全 optional)。
@@ -71,18 +74,9 @@ import { type PeerDirectory } from "@sema-agent/core";
71
74
  import type { CrossSessionInboundSettingLayers } from "@sema-agent/core";
72
75
  import type { Logger } from "./observability/logger.js";
73
76
  import type { MailboxRecipientLifecycle } from "./plugins/mailbox-recipient-lifecycle.js";
74
- import { type SessionListItem } from "./security.js";
75
- /** 会话枚举面(= `GET /v1/sessions` 用的那只 `OwnerAwareSessionStore.listSessions`)。 */
76
- export type PeerSessionLister = (opts: {
77
- owner?: string;
78
- includeUnowned?: boolean;
79
- cursor?: {
80
- lastActivityAt: string;
81
- sessionId: string;
82
- };
83
- limit: number;
84
- q?: string;
85
- }) => Promise<SessionListItem[]>;
77
+ import { type OwnerAwareSessionStore } from "./security.js";
78
+ /** 会话枚举面(= `GET /v1/sessions` 用的那只列表面的带住客形 `OwnerAwareSessionStore.listSessionRows`:每行配读到它时的住客)。 */
79
+ export type PeerSessionLister = NonNullable<OwnerAwareSessionStore["listSessionRows"]>;
86
80
  /**
87
81
  * 一次 `listPeerSessions` 最多铸多少行。
88
82
  *