@sema-agent/server 7.140.0 → 7.142.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 (296) hide show
  1. package/MIGRATION.md +505 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +142 -25
  5. package/dist/approval-ask-audit-store.d.ts +54 -38
  6. package/dist/approval-ask-audit-store.js +58 -39
  7. package/dist/approval-batch-census.d.ts +27 -0
  8. package/dist/approval-batch-census.js +27 -0
  9. package/dist/approval-card.d.ts +39 -24
  10. package/dist/approval-card.js +6 -3
  11. package/dist/approval-crash-convergence.d.ts +17 -7
  12. package/dist/approval-crash-convergence.js +94 -22
  13. package/dist/approval-deny-reasons.d.ts +34 -30
  14. package/dist/approval-deny-reasons.js +21 -6
  15. package/dist/approval-policy-settlement.d.ts +1 -1
  16. package/dist/approval-reconciler.d.ts +33 -1
  17. package/dist/approval-reconciler.js +43 -40
  18. package/dist/approval.d.ts +15 -0
  19. package/dist/approval.js +10 -0
  20. package/dist/audit.d.ts +4 -2
  21. package/dist/audit.js +2 -2
  22. package/dist/auth-bridge.d.ts +9 -6
  23. package/dist/auth-bridge.js +9 -3
  24. package/dist/boot/adoption.js +2 -1
  25. package/dist/boot/budget-tracing.d.ts +16 -0
  26. package/dist/boot/budget-tracing.js +10 -6
  27. package/dist/boot/device-lane.d.ts +11 -0
  28. package/dist/boot/device-lane.js +16 -0
  29. package/dist/boot/engine-lease.d.ts +24 -3
  30. package/dist/boot/engine-lease.js +9 -2
  31. package/dist/boot/execution-env.d.ts +24 -4
  32. package/dist/boot/execution-env.js +34 -27
  33. package/dist/boot/execution-lane.js +2 -1
  34. package/dist/boot/exit-boundary.js +5 -4
  35. package/dist/boot/memory-boundary.d.ts +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +1 -1
  37. package/dist/boot/memory-consolidation.js +3 -2
  38. package/dist/boot/parked-revive-gate.js +2 -1
  39. package/dist/boot/permission-rules-audit.d.ts +0 -28
  40. package/dist/boot/permission-rules-audit.js +2 -1
  41. package/dist/boot/read-deny-anchor-audit.js +2 -1
  42. package/dist/boot/reapers.d.ts +2 -2
  43. package/dist/boot/reapers.js +4 -3
  44. package/dist/boot/resolve-spec.js +18 -6
  45. package/dist/boot/retention-lane.js +5 -3
  46. package/dist/boot/runner-deps.js +16 -13
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.d.ts +1 -1
  49. package/dist/boot/session-faces.js +8 -6
  50. package/dist/boot/shutdown.js +8 -2
  51. package/dist/boot/stage-04-stores.js +3 -2
  52. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  53. package/dist/boot/stage-05-execution-env.js +11 -7
  54. package/dist/boot/stage-06-runners.d.ts +1 -3
  55. package/dist/boot/stage-06-runners.js +3 -2
  56. package/dist/boot/stage-07-capability-layer.d.ts +1 -2
  57. package/dist/boot/stage-07-capability-layer.js +10 -11
  58. package/dist/boot/stage-08-reapers.d.ts +1 -2
  59. package/dist/boot/stage-08-reapers.js +3 -2
  60. package/dist/boot/stage-09-leader.d.ts +1 -2
  61. package/dist/boot/stage-10-http-server.d.ts +1 -2
  62. package/dist/boot/stage-10-http-server.js +6 -4
  63. package/dist/boot/stores.js +13 -6
  64. package/dist/boot/web-admin.js +18 -17
  65. package/dist/boot/webfetch-summarize-lane.js +2 -1
  66. package/dist/boot/workflow-orchestration.js +3 -2
  67. package/dist/capabilities/builtin-tools.d.ts +2 -1
  68. package/dist/capabilities/builtin-tools.js +2 -4
  69. package/dist/capabilities/composite-members.d.ts +2 -1
  70. package/dist/capabilities/composite-members.js +2 -1
  71. package/dist/capabilities/scenarios.d.ts +1 -1
  72. package/dist/capability-facts.d.ts +33 -0
  73. package/dist/capability-facts.js +32 -0
  74. package/dist/card-void.d.ts +38 -0
  75. package/dist/card-void.js +23 -0
  76. package/dist/config-catalog.js +12 -8
  77. package/dist/config-provider.d.ts +13 -13
  78. package/dist/config-provider.js +19 -33
  79. package/dist/config-types.d.ts +39 -10
  80. package/dist/config.d.ts +6 -0
  81. package/dist/config.js +72 -49
  82. package/dist/delegated-session-owner.d.ts +21 -19
  83. package/dist/delegated-session-owner.js +1 -1
  84. package/dist/device-store.d.ts +7 -0
  85. package/dist/device-store.js +3 -0
  86. package/dist/execution-config-root.d.ts +22 -0
  87. package/dist/execution-config-root.js +35 -0
  88. package/dist/execution-lane-caps.d.ts +50 -2
  89. package/dist/execution-lane-caps.js +90 -13
  90. package/dist/execution-placement.d.ts +3 -0
  91. package/dist/execution-placement.js +7 -0
  92. package/dist/fleet/drain-entry.d.ts +3 -0
  93. package/dist/fleet/fleet-bus.d.ts +6 -3
  94. package/dist/hooks/hook-runner.d.ts +6 -0
  95. package/dist/hooks/hook-runner.js +30 -1
  96. package/dist/hosted-posture.d.ts +8 -0
  97. package/dist/hosted-posture.js +4 -0
  98. package/dist/http/admission.js +3 -3
  99. package/dist/http/caller-trust.d.ts +3 -2
  100. package/dist/http/caller-trust.js +2 -1
  101. package/dist/http/dispatch.js +8 -2
  102. package/dist/http/execution-context.d.ts +2 -2
  103. package/dist/http/idempotency.d.ts +1 -1
  104. package/dist/http/live-frame.d.ts +24 -0
  105. package/dist/http/live-frame.js +16 -0
  106. package/dist/http/principal-gate.d.ts +3 -1
  107. package/dist/http/principal-gate.js +17 -8
  108. package/dist/http/resume-legs.js +42 -29
  109. package/dist/http/route-table.js +4 -0
  110. package/dist/http/routes/approvals-assistant.js +1 -0
  111. package/dist/http/routes/attachments.js +18 -0
  112. package/dist/http/routes/capabilities.js +10 -6
  113. package/dist/http/routes/diagnostics.d.ts +0 -19
  114. package/dist/http/routes/diagnostics.js +16 -2
  115. package/dist/http/routes/memory-bundle.d.ts +2 -2
  116. package/dist/http/routes/memory-bundle.js +1 -1
  117. package/dist/http/routes/memory-compliance.js +1 -1
  118. package/dist/http/routes/memory-policy.js +27 -7
  119. package/dist/http/routes/run-permission-mode.d.ts +75 -0
  120. package/dist/http/routes/run-permission-mode.js +170 -0
  121. package/dist/http/routes/runs.js +3 -3
  122. package/dist/http/routes/session-memory-sync.d.ts +63 -0
  123. package/dist/http/routes/session-memory-sync.js +157 -0
  124. package/dist/http/routes/session-sync.d.ts +3 -6
  125. package/dist/http/routes/session-sync.js +7 -2
  126. package/dist/http/routes/sessions-list.d.ts +2 -1
  127. package/dist/http/routes/sessions.js +5 -4
  128. package/dist/http/routes/tasks.js +70 -71
  129. package/dist/http/run-read-face.d.ts +7 -0
  130. package/dist/http/run-read-face.js +10 -4
  131. package/dist/http/send.d.ts +6 -1
  132. package/dist/http/send.js +10 -3
  133. package/dist/http/server.d.ts +20 -7
  134. package/dist/http/server.js +2 -4
  135. package/dist/http/sse-log.d.ts +3 -8
  136. package/dist/http/stored-body-replay.d.ts +3 -3
  137. package/dist/http/stored-body-replay.js +3 -1
  138. package/dist/http/submit-replay.d.ts +4 -3
  139. package/dist/http/submit-replay.js +2 -2
  140. package/dist/http/sync-submit-body.d.ts +21 -4
  141. package/dist/http/sync-submit-body.js +13 -0
  142. package/dist/identity-source.d.ts +21 -2
  143. package/dist/identity-source.js +6 -0
  144. package/dist/instruction-source-notice.d.ts +7 -0
  145. package/dist/instruction-source-notice.js +6 -6
  146. package/dist/mcp-assertion-header.d.ts +4 -0
  147. package/dist/mcp-assertion-header.js +5 -0
  148. package/dist/memory-incident-sink.d.ts +19 -6
  149. package/dist/memory-incident-sink.js +8 -4
  150. package/dist/memory-posture.d.ts +1 -1
  151. package/dist/memory-scope.d.ts +4 -4
  152. package/dist/memory-scope.js +1 -1
  153. package/dist/memory-sync-client.d.ts +35 -23
  154. package/dist/memory-sync-client.js +122 -52
  155. package/dist/memory-sync-identity.d.ts +24 -0
  156. package/dist/memory-sync-identity.js +57 -0
  157. package/dist/memory-sync.d.ts +7 -1
  158. package/dist/memory-sync.js +6 -3
  159. package/dist/observability/fail-open.d.ts +57 -12
  160. package/dist/observability/fail-open.js +50 -9
  161. package/dist/observability/metrics.js +0 -1
  162. package/dist/observability/run-terminal.d.ts +93 -31
  163. package/dist/observability/run-terminal.js +175 -171
  164. package/dist/observability/secret-env-scrub.d.ts +20 -1
  165. package/dist/observability/secret-env-scrub.js +14 -0
  166. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
  167. package/dist/orchestration/workflow-completion-inbox.js +13 -5
  168. package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
  169. package/dist/orchestration/workflow-notify-journal.js +2 -1
  170. package/dist/permission-mode-admission.d.ts +68 -0
  171. package/dist/permission-mode-admission.js +23 -0
  172. package/dist/permission-rule-list.d.ts +55 -6
  173. package/dist/permission-rule-list.js +52 -5
  174. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  175. package/dist/plugins/approval-ask-store-file.js +48 -7
  176. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  177. package/dist/plugins/approval-ask-store-memory.js +9 -8
  178. package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
  179. package/dist/plugins/approval-ask-store-sql.js +49 -19
  180. package/dist/plugins/caching-session-store.d.ts +6 -0
  181. package/dist/plugins/caching-session-store.js +3 -0
  182. package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
  183. package/dist/plugins/checkpoint-store-sql.js +74 -3
  184. package/dist/plugins/device-store-sql.d.ts +5 -2
  185. package/dist/plugins/device-store-sql.js +4 -1
  186. package/dist/plugins/execution-placement-sql.d.ts +11 -1
  187. package/dist/plugins/execution-placement-sql.js +12 -1
  188. package/dist/plugins/file-run-store.d.ts +7 -2
  189. package/dist/plugins/file-run-store.js +12 -2
  190. package/dist/plugins/fork-routing-session-store.d.ts +10 -32
  191. package/dist/plugins/fork-routing-session-store.js +2 -61
  192. package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
  193. package/dist/plugins/k8s-exec-protocol.js +6 -1
  194. package/dist/plugins/local-checkpoint-store.d.ts +10 -1
  195. package/dist/plugins/local-checkpoint-store.js +22 -0
  196. package/dist/plugins/local-session-store.d.ts +260 -39
  197. package/dist/plugins/local-session-store.js +582 -57
  198. package/dist/plugins/local-session-window.d.ts +17 -3
  199. package/dist/plugins/local-session-window.js +7 -13
  200. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  201. package/dist/plugins/local-task-attachment-store.js +67 -43
  202. package/dist/plugins/memory-key-guards.d.ts +3 -3
  203. package/dist/plugins/memory-run-store.d.ts +7 -2
  204. package/dist/plugins/memory-run-store.js +12 -2
  205. package/dist/plugins/one-time-migrations.d.ts +68 -2
  206. package/dist/plugins/one-time-migrations.js +120 -4
  207. package/dist/plugins/pg-pool.js +3 -2
  208. package/dist/plugins/pg-session-storage.d.ts +2 -0
  209. package/dist/plugins/pg-session-storage.js +3 -2
  210. package/dist/plugins/remote-env-e2b.d.ts +47 -7
  211. package/dist/plugins/remote-env-e2b.js +242 -46
  212. package/dist/plugins/remote-env-k8s.d.ts +51 -6
  213. package/dist/plugins/remote-env-k8s.js +234 -44
  214. package/dist/plugins/remote-env-local-docker.d.ts +40 -14
  215. package/dist/plugins/remote-env-local-docker.js +127 -33
  216. package/dist/plugins/run-store-sql.d.ts +11 -3
  217. package/dist/plugins/run-store-sql.js +13 -4
  218. package/dist/plugins/sandbox-read-floor.d.ts +273 -0
  219. package/dist/plugins/sandbox-read-floor.js +608 -0
  220. package/dist/plugins/session-ownership.d.ts +2 -1
  221. package/dist/plugins/session-placement.d.ts +17 -4
  222. package/dist/plugins/session-placement.js +2 -1
  223. package/dist/plugins/session-store.d.ts +18 -20
  224. package/dist/plugins/session-store.js +4 -12
  225. package/dist/plugins/store-backend.d.ts +41 -7
  226. package/dist/plugins/store-backend.js +22 -4
  227. package/dist/plugins/store-contracts.d.ts +35 -3
  228. package/dist/plugins/store-contracts.js +3 -0
  229. package/dist/plugins/task-attachment-store.d.ts +112 -14
  230. package/dist/plugins/task-attachment-store.js +221 -28
  231. package/dist/plugins/tidb-pool.js +2 -1
  232. package/dist/plugins/tidb-session-store.d.ts +4 -1
  233. package/dist/plugins/tidb-session-store.js +3 -2
  234. package/dist/plugins/workspace-fill.d.ts +60 -0
  235. package/dist/plugins/workspace-fill.js +106 -0
  236. package/dist/project-bundle.d.ts +38 -0
  237. package/dist/project-bundle.js +609 -0
  238. package/dist/run-cancel-context.d.ts +34 -0
  239. package/dist/run-cancel-context.js +7 -0
  240. package/dist/run-local.js +2 -8
  241. package/dist/runs.d.ts +39 -12
  242. package/dist/runs.js +69 -55
  243. package/dist/sandbox-egress-policy.d.ts +4 -1
  244. package/dist/sandbox-egress-policy.js +3 -1
  245. package/dist/sandbox-git-plane.d.ts +31 -12
  246. package/dist/sandbox-git-plane.js +24 -4
  247. package/dist/security.d.ts +11 -2
  248. package/dist/security.js +8 -0
  249. package/dist/server-secret-env.d.ts +2 -1
  250. package/dist/server-secret-env.js +2 -4
  251. package/dist/session-error-wire.d.ts +46 -4
  252. package/dist/session-error-wire.js +23 -0
  253. package/dist/session-incarnation.d.ts +9 -3
  254. package/dist/session-sync-kernel.d.ts +42 -1
  255. package/dist/session-sync-kernel.js +17 -0
  256. package/dist/session-sync.js +16 -4
  257. package/dist/sql-engine-coordinates.d.ts +49 -0
  258. package/dist/sql-engine-coordinates.js +27 -0
  259. package/dist/standing-answer-grant.d.ts +31 -2
  260. package/dist/standing-answer-grant.js +14 -2
  261. package/dist/store-posture.d.ts +1 -1
  262. package/dist/task-a2a.d.ts +1 -1
  263. package/dist/task-mcp.d.ts +1 -1
  264. package/dist/task-settings.d.ts +62 -27
  265. package/dist/task-settings.js +105 -29
  266. package/dist/terminal.d.ts +97 -20
  267. package/dist/terminal.js +107 -18
  268. package/dist/tool-approval.d.ts +4 -3
  269. package/dist/tool-approval.js +12 -14
  270. package/dist/trace/core-keyset-guard.d.ts +196 -2
  271. package/dist/trace/engine-notice-wire.d.ts +8 -2
  272. package/dist/trace/engine-notice-wire.js +4 -2
  273. package/dist/trace/exit-seat.d.ts +9 -1
  274. package/dist/trace/exit-seat.js +1 -0
  275. package/dist/trace/ledger-sink.d.ts +8 -4
  276. package/dist/trace/ledger-sink.js +2 -2
  277. package/dist/trace/model-segment.d.ts +2 -2
  278. package/dist/trace/project.d.ts +18 -1
  279. package/dist/trace/project.js +16 -0
  280. package/dist/trace/redact.js +323 -90
  281. package/dist/trace/self-minted-wire.d.ts +419 -4
  282. package/dist/trace/self-minted-wire.js +145 -0
  283. package/dist/trace/wire-projection-faces.d.ts +1 -1
  284. package/dist/trace/wire-projection-faces.js +1 -1
  285. package/dist/verifier-pause-card.d.ts +8 -0
  286. package/dist/verifier-pause-card.js +19 -0
  287. package/dist/web-admin-client/apply-effective.d.ts +5 -7
  288. package/dist/web-admin-client/apply-effective.js +22 -2
  289. package/dist/web-admin-client/candidate-gate.d.ts +1 -1
  290. package/dist/web-admin-client/effective-keys.js +2 -0
  291. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  292. package/dist/web-admin-client/types.d.ts +4 -0
  293. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
  294. package/package.json +2 -2
  295. package/wire-changes/server@7.141.0.json +367 -0
  296. package/wire-changes/server@7.142.0.json +639 -0
package/dist/terminal.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { terminalProjection } from "@sema-agent/core";
2
+ import { errorCodeOf } from "./observability/err-text.js";
2
3
  import { recordFailOpen } from "./observability/fail-open.js";
4
+ import { redactSecrets } from "./trace/redact.js";
3
5
  export function failureCodeOf(terminal) {
4
6
  return terminal.kind === "failed" ? terminal.code : undefined;
5
7
  }
@@ -8,25 +10,116 @@ export const STORE_ERROR_CODE = "internal.store_error";
8
10
  export function outwardFailureCode(code) {
9
11
  return OUTWARD_CODE_SHAPE.test(code) ? code : STORE_ERROR_CODE;
10
12
  }
13
+ export function isCodeToken(code) {
14
+ return typeof code === "string" && CODE_TOKEN_SHAPE.test(code) && redactSecrets(code, { observe: false }) === code;
15
+ }
16
+ const CODE_TOKEN_SHAPE = /^[A-Za-z0-9_.:-]{1,64}$/;
17
+ export function codeFieldOf(err) {
18
+ const code = errorCodeOf(err);
19
+ return isCodeToken(code) ? { code } : {};
20
+ }
21
+ export const PAUSE_SEATS = [
22
+ { path: ["terminal"], token: "token", gate: "gate" },
23
+ { path: ["terminal", "nestedPause"], token: "token", gate: "gate" },
24
+ { path: ["verification", "verifierPause"], token: "checkpointToken", gate: "checkpointGate" },
25
+ ];
26
+ export function mapPauseSeats(result, f) {
27
+ let out = result;
28
+ for (const seat of PAUSE_SEATS)
29
+ out = mapSeatAt(out, seat.path, 0, (o) => f(o, seat));
30
+ return out;
31
+ }
32
+ function mapSeatAt(node, path, depth, f) {
33
+ if (node === null || typeof node !== "object" || Array.isArray(node))
34
+ return node;
35
+ if (depth === path.length)
36
+ return f(node);
37
+ const key = path[depth];
38
+ if (!Object.hasOwn(node, key))
39
+ return node;
40
+ const child = node[key];
41
+ const next = mapSeatAt(child, path, depth + 1, f);
42
+ return Object.is(next, child) ? node : { ...node, [key]: next };
43
+ }
44
+ function dropCapability(seat, keys) {
45
+ if (!Object.hasOwn(seat, keys.token))
46
+ return seat;
47
+ const { [keys.token]: _drop, ...rest } = seat;
48
+ return rest;
49
+ }
11
50
  export function sealResultForExit(result) {
12
- const t = result?.terminal;
13
- if (t === null || typeof t !== "object")
51
+ return seal(result, "exit");
52
+ }
53
+ export function sealStoredResult(result, seat) {
54
+ return seal(result, seat);
55
+ }
56
+ function seal(result, at) {
57
+ if (result === null || typeof result !== "object")
14
58
  return result;
15
- if (t.kind === "paused")
16
- return { ...result, terminal: stripPausedToken(t) };
17
- if (t.kind !== "failed")
59
+ return foldOutwardFailureCodes(mapPauseSeats(result, dropCapability), at);
60
+ }
61
+ function foldOutwardFailureCodes(result, at) {
62
+ const terminal = foldCauseCode(result.terminal, at);
63
+ const priorAttempts = result.attempts;
64
+ const attempts = foldAttemptCodes(priorAttempts, at);
65
+ const terminalKept = Object.is(terminal, result.terminal);
66
+ const attemptsKept = Object.is(attempts, priorAttempts);
67
+ if (terminalKept && attemptsKept)
18
68
  return result;
19
- let terminal = t;
20
- if (t.nestedPause !== undefined)
21
- terminal = { ...terminal, nestedPause: stripPausedToken(t.nestedPause) };
22
- if (t.code !== undefined) {
23
- const outward = outwardFailureCode(t.code);
24
- if (outward !== t.code) {
25
- console.warn(`[terminal] outward_failure_code_folded original=${t.code} outward=${outward}`, { message: t.message });
26
- terminal = { ...terminal, code: outward, message: `${t.message ?? "the durable store failed"} [original code: ${t.code}]` };
69
+ return { ...result, ...(terminalKept ? {} : { terminal }), ...(attemptsKept ? {} : { attempts }) };
70
+ }
71
+ function foldCauseCode(terminal, at) {
72
+ const t = failedCauseWithCode(terminal);
73
+ if (t === undefined)
74
+ return terminal;
75
+ const outward = outwardFailureCode(t.code);
76
+ if (outward === t.code)
77
+ return terminal;
78
+ reportFold(t.code, outward, t.message, at);
79
+ const message = typeof t.message === "string" ? t.message : "the durable store failed";
80
+ return { ...t, code: outward, message: `${message} [original code: ${t.code}]` };
81
+ }
82
+ function foldAttemptCodes(attempts, at) {
83
+ if (!Array.isArray(attempts))
84
+ return attempts;
85
+ let folded;
86
+ attempts.forEach((attempt, i) => {
87
+ if (attempt === null || typeof attempt !== "object")
88
+ return;
89
+ const code = attempt.errorCode;
90
+ if (typeof code !== "string")
91
+ return;
92
+ const outward = outwardFailureCode(code);
93
+ if (outward === code)
94
+ return;
95
+ reportFold(code, outward, undefined, at);
96
+ (folded ??= [...attempts])[i] = { ...attempt, errorCode: outward };
97
+ });
98
+ return folded ?? attempts;
99
+ }
100
+ const STORED_RESULT_FOLD_TAG = "server.terminal.stored-result-code-folded";
101
+ function reportFold(code, outward, message, at) {
102
+ const messageBytes = typeof message === "string" ? Buffer.byteLength(message, "utf8") : 0;
103
+ const fields = `original=${isCodeToken(code) ? code : "<not-a-code>"} outward=${outward} messageBytes=${messageBytes} at=${at}`;
104
+ switch (at) {
105
+ case "exit":
106
+ console.warn(`[terminal] outward_failure_code_folded ${fields}`);
107
+ return;
108
+ case "run.result":
109
+ case "ev.done.result":
110
+ recordFailOpen(STORED_RESULT_FOLD_TAG, fields);
111
+ return;
112
+ default: {
113
+ const unhandled = at;
114
+ throw new Error(`unhandled fold sighting: ${String(unhandled)}`);
27
115
  }
28
116
  }
29
- return terminal === t ? result : { ...result, terminal };
117
+ }
118
+ function failedCauseWithCode(t) {
119
+ if (t === null || typeof t !== "object")
120
+ return undefined;
121
+ const { kind, code } = t;
122
+ return kind === "failed" && typeof code === "string" ? { ...t, kind, code } : undefined;
30
123
  }
31
124
  export function outwardPlane(terminal) {
32
125
  const plane = terminalProjection(terminal);
@@ -35,10 +128,6 @@ export function outwardPlane(terminal) {
35
128
  const outward = outwardFailureCode(plane.errorCode);
36
129
  return outward === plane.errorCode ? plane : { ...plane, errorCode: outward };
37
130
  }
38
- function stripPausedToken(paused) {
39
- const { token: _drop, ...rest } = paused;
40
- return rest;
41
- }
42
131
  export function nestedPauseOf(terminal) {
43
132
  return terminal.kind === "failed" ? terminal.nestedPause : undefined;
44
133
  }
@@ -34,7 +34,7 @@ export declare function approvalDecidePath(sessionId: string): string;
34
34
  /**
35
35
  * [ref] 随批小件:`tool_approval.not_pending` 404 的**判别位**([ref] 排障代价实证 —— 三因合并成一句人话,现场分不出「答案没地方兑」与「打错副本了」)。
36
36
  * DECIDED/PARKED 已从 404 分流(DECIDED ⇒ 200 回放首决,回执带 `decidedBy`,**不是**成因;PARKED ⇒ 赎回席),残余两类:
37
- * · 行 `VOID` / `DENIED`(没有人决过它)—— `cause` = **行上记的那个成因词**(问账 `denied_reason` 列;与决断口 410 `gone.ask` 体的 `cause`、审计 settle 行
37
+ * · 行 `VOID` / `DENIED`(没有人决过它)—— `cause` = **行上记的那个成因词**(问账 `ending_cause` 列;与决断口 410 `gone.ask` 体的 `cause`、审计 settle 行
38
38
  * 的 `cause` 同一个词,闭集 {@link SettleCause});行上没写归因(存量行)⇒ 缺席,不替没写的行编一个词;
39
39
  * · {@link NOT_PENDING_UNKNOWN_CAUSE} —— 无行 / 行不是调用方的 / 行仍在别处活着:换副本或换端点重试才有意义(这个词只属于 404 面,不是结局成因)。
40
40
  * 对齐 [ref] 反枚举语义:cause 只在**已过属主门**的面上出,不扩枚举面(属主门不过 = 与未知 id 同形)。
@@ -1666,7 +1666,8 @@ export declare class ToolApprovalCoordinator {
1666
1666
  * ② 在 `deadlineMs` 之前等:未决卡结清、在飞腿闭合(闭了的腿照常落 `leg_closed`)、**本次路由到 park 的卡全部结清**
1667
1667
  * (F1:观察到 core 已处置这次调用 —— 停车行提交或承载它的腿退场 ⇒ 那张卡的审计 settle 行此刻才写,见 {@link settleParksAwaitingCommit})、
1668
1668
  * 店里在飞的 `put` 静默;
1669
- * ③ 到期:仍未闭的腿 ⇒ 审计落 `interrupted_by_shutdown` 记号(下一次 boot 收敛照样列出它,decided 臂的 `resumeSafe:false` 提醒不丢);
1669
+ * ③ 等待结束(全结清或到期)⇒ 审计落**一行**进程级 `interrupted_by_shutdown` 记录([ref]:有序收尾走完是进程的事实,不是腿的 —— 此刻还没结清的卡
1670
+ * 不论在不在协调器的追踪视野里,下一次 boot 都写 `shutdown_before_park`;下一次 boot 收敛照样列出它们,decided 臂的 `resumeSafe:false` 提醒不丢);
1670
1671
  * 仍未提交的 park ⇒ settle 行**不写**(账本上仍是 pending 孤儿 ⇒ 下一次 boot 与崩溃同路收敛,证据不丢),交回调用方
1671
1672
  * (`uncommittedParks`,运维 warn `approval_park_uncommitted_at_shutdown` 由关停序落 —— 它握 logger)。之后才观察到的照样写 settle 行
1672
1673
  * (观察到就是结清,迟到也是)。
@@ -1674,7 +1675,7 @@ export declare class ToolApprovalCoordinator {
1674
1675
  * 的 await 里 —— 零活流的后台 / 委派子代也在内)在登记那一刻按同一条路收场(`askBroadcast` 的铸造审计点之后读这一位)。等待条件
1675
1676
  * 因此数「在飞的 ask」({@link asksInFlight},`askBroadcast` 进出计数)而不只是 `pending` —— 尚未登记的卡不在 `pending` 里。
1676
1677
  * `deadlineMs` 是绝对时刻(`Date.now()` 域):关停序对审批面与店 quiesce 读**同一个**到期点(一个宽限窗,不是两个)。
1677
- * 从不抛错(关停序不许被审计面卡住);再调一次 = 再等一次(记号有去重集,零重写)。
1678
+ * 从不抛错(关停序不许被审计面卡住);再调一次 = 再等一次(关停记录一世一行,零重写)。
1678
1679
  */
1679
1680
  drainForShutdown(deadlineMs: number): Promise<{
1680
1681
  uncommittedParks: Array<{
@@ -15,7 +15,7 @@ import { ownerOfCheckpointScope } from "./security.js";
15
15
  import { deriveAskId, deriveAskScopedBatchId, deriveBatchId, MAX_DECISION_NOTE_CHARS, noteLandedOnRow, noteRecordedReceipt } from "./approval-ask-machine.js";
16
16
  import { currentParkArm, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildReplayFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readProbeReason, readReadRootCandidate, readStoredCardEnvelope, readRuleEvidence, readAllowRuleShadowed, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readParkRowTrueSeat, readAskClassPair, readClosedWordSeat, buildApprovalCompleteFrame, readRuleOfferList, } from "./approval-card.js";
17
17
  import { askOwnerAdmits, askRowCarriesOwner, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
18
- import { APPROVAL_ENDING_CAUSES, SETTLE_OUTCOME, causeOfAskRow } from "./approval-deny-reasons.js";
18
+ import { APPROVAL_ENDING_CAUSES, SETTLE_OUTCOME, askRowEndingCause, askRowParkTrigger } from "./approval-deny-reasons.js";
19
19
  import { settleByPolicy } from "./approval-policy-settlement.js";
20
20
  import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
21
21
  import { governanceOriginOf } from "./runtime-governance.js";
@@ -898,7 +898,7 @@ export class ToolApprovalCoordinator {
898
898
  await new Promise((r) => setTimeout(r, SHUTDOWN_DRAIN_POLL_MS));
899
899
  }
900
900
  await this.parkCommits?.quiesce(deadlineMs);
901
- this.askAudit?.noteLegsInterruptedByShutdown();
901
+ this.askAudit?.noteInterruptedByShutdown();
902
902
  return { uncommittedParks: [...this.parksAwaitingCommit].map((p) => ({ approvalId: p.approvalId, taskId: p.taskId })) };
903
903
  }
904
904
  noteParkCommitted(calls) {
@@ -1057,12 +1057,11 @@ export class ToolApprovalCoordinator {
1057
1057
  classifyClaimLoss(askId, current, _where) {
1058
1058
  if (current.state === "absent")
1059
1059
  return { kind: "absent" };
1060
- const rowCause = current.cause;
1061
- if (rowCause?.kind === "ending")
1062
- return { kind: "ended", cause: rowCause.cause };
1060
+ if (current.endingCause !== undefined)
1061
+ return { kind: "ended", cause: current.endingCause };
1063
1062
  const replayedOutcome = replayTerminalAskRow(current);
1064
1063
  if (replayedOutcome === "unavailable") {
1065
- return rowCause?.kind === "park_trigger" ? { kind: "parked", cause: rowCause.cause } : { kind: "parked" };
1064
+ return current.parkTrigger !== undefined ? { kind: "parked", cause: current.parkTrigger } : { kind: "parked" };
1066
1065
  }
1067
1066
  const replayed = settleArgsOfDecided(replayedOutcome);
1068
1067
  if (!replayed.allowed)
@@ -2300,8 +2299,8 @@ export class ToolApprovalCoordinator {
2300
2299
  }
2301
2300
  case "DENIED":
2302
2301
  case "VOID": {
2303
- const rowCause = causeOfAskRow(row);
2304
- body = { state: "void", ...projection, ...(rowCause?.kind === "ending" ? { cause: rowCause.cause } : {}) };
2302
+ const endingCause = askRowEndingCause(row);
2303
+ body = { state: "void", ...projection, ...(endingCause !== undefined ? { cause: endingCause } : {}) };
2305
2304
  break;
2306
2305
  }
2307
2306
  case "STREAM_PENDING":
@@ -2413,8 +2412,7 @@ export class ToolApprovalCoordinator {
2413
2412
  }
2414
2413
  case "DENIED":
2415
2414
  case "VOID": {
2416
- const rowCause = causeOfAskRow(row);
2417
- return this.notPending(rowCause?.kind === "ending" ? rowCause.cause : undefined);
2415
+ return this.notPending(askRowEndingCause(row));
2418
2416
  }
2419
2417
  case "STREAM_PENDING":
2420
2418
  return this.notPending(NOT_PENDING_UNKNOWN_CAUSE);
@@ -3028,17 +3026,17 @@ export class ToolApprovalCoordinator {
3028
3026
  }
3029
3027
  if (this.editedDecisionInFlight(askId))
3030
3028
  continue;
3031
- const rowCause = causeOfAskRow(row);
3032
- if (rowCause?.kind === "ending") {
3029
+ const endingCause = askRowEndingCause(row);
3030
+ if (endingCause !== undefined) {
3033
3031
  const before = this.waitingRegistrationCount(askId);
3034
- this.settleVoidedSiblings([askId], rowCause.cause);
3032
+ this.settleVoidedSiblings([askId], endingCause);
3035
3033
  settled += before;
3036
3034
  continue;
3037
3035
  }
3038
3036
  const outcome = replayTerminalAskRow(row);
3039
3037
  if (outcome === "unavailable") {
3040
3038
  const before = this.waitingRegistrationCount(askId);
3041
- const parkCause = (rowCause?.kind === "park_trigger" ? rowCause.cause : undefined) ?? (Date.now() >= row.expiresAtMs ? APPROVAL_ENDING_CAUSES.TTL_EXPIRED : APPROVAL_ENDING_CAUSES.SHUTDOWN_BEFORE_PARK);
3039
+ const parkCause = askRowParkTrigger(row) ?? (Date.now() >= row.expiresAtMs ? APPROVAL_ENDING_CAUSES.TTL_EXPIRED : APPROVAL_ENDING_CAUSES.SHUTDOWN_BEFORE_PARK);
3042
3040
  this.settleSameAskIdParkRoute(askId, parkCause);
3043
3041
  settled += before;
3044
3042
  continue;
@@ -17,9 +17,10 @@
17
17
  * ⑨⑩([ref],2026-08-31)把两个最大的 wire 面也纳入:TaskSpec 按「server 有无写点」记 Wired/Unwired,
18
18
  * TaskResult 按「转发/摘除」记 Forwarded/Stripped —— 谁改 resolve-spec.ts / runs.ts 的发射点谁同步本文件。
19
19
  */
20
- import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, PendingAction, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, SideQueryResult, WiringManifest, PermissionModeReceipt, GateOutcome, GateDisposition, Settlement, PausedCause, TerminalCause, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus, NodeLspManagerOptions, RunnerDeps, SessionMemoryStatus, PromptManifestIdentity, PromptIdentityLayers, PromptManifestSelectors, PromptManifestSection, PromptChainLink, SupersededOverlay, ToolDisclosureManifest } from "@sema-agent/core";
20
+ import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, PendingAction, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, SideQueryResult, WiringManifest, PermissionModeReceipt, GateOutcome, GateDisposition, Settlement, PausedCause, TerminalCause, CheckpointGate, CheckpointToken, VerificationResult, CascadeRunResult, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus, NodeLspManagerOptions, RunnerDeps, SessionMemoryStatus, PromptManifestIdentity, PromptIdentityLayers, PromptManifestSelectors, PromptManifestSection, PromptChainLink, SupersededOverlay, ToolDisclosureManifest } from "@sema-agent/core";
21
21
  import type { ToolApprovalFrame } from "../tool-approval.js";
22
22
  import type { TableCoreKeys } from "./projection-table.js";
23
+ import type { PauseSeat } from "../terminal.js";
23
24
  /** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。
24
25
  * 🔴 **导出**([ref] U1/U2):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
25
26
  * `observability/run-terminal.ts` 的三张叶表 + 结果顶层键表用同一只断言,而不是各自再抄一份
@@ -248,6 +249,190 @@ type TerminalArmForwarded = "kind" | "code" | "message" | "nestedPause" | "detai
248
249
  type TerminalArmStripped = never;
249
250
  type _GuardTerminalArm = AssertAllKeysHandled<Exclude<NonPausedTerminalKeys, TerminalArmForwarded | TerminalArmStripped>>;
250
251
  type _GuardTerminalArmReverse = AssertAllKeysHandled<Exclude<TerminalArmForwarded | TerminalArmStripped, NonPausedTerminalKeys>>;
252
+ type SeatDepth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
253
+ type JoinPath<K extends string, P extends string> = [P] extends [never] ? never : P extends "" ? K : `${K}.${P}`;
254
+ /** 两个型**全同**(不是「互相可赋」:全可选成员的子对象与它的父对象互相可赋,却不是同一个型)。 */
255
+ type SameType<A, B> = (<G>() => G extends A ? 1 : 2) extends <G>() => G extends B ? 1 : 2 ? true : false;
256
+ /** `T` 与祖先链上某一层**全同** ⇒ 这是递归类型的回环(如 JSON 值类型),再走只是同一棵子树换个前缀,停。只比祖先、不比兄弟。
257
+ * 有限型的子代不可能与祖先全同(祖先含着它),所以全同只在递归上成立;「互相可赋」会把同形的有限子代(`{text?, cause?: {text?}}` 的 `cause`)误判成回环、整枝丢掉。 */
258
+ type SeenOnPath<T, Seen extends readonly unknown[]> = Seen extends readonly [infer H, ...infer R extends readonly unknown[]] ? SameType<T, H> extends true ? true : SeenOnPath<T, R> : false;
259
+ /**
260
+ * `T` 里类型为 `Leaf` 的全部路径(点分;数组元素记 `[]`;`any` 不展开)。回环按祖先链判停;深度封顶 12 且**封顶响亮**:
261
+ * 走到底还没走完的分支产出以 `<depth-exhausted>` 收尾的路径 —— 它不在座表里 ⇒ 下面的正向对账 TS2344(封顶静默返回 `never`
262
+ * 会让更深的座看不见;门内 `riskDescriptor` 的子树今天就到第 7 层)。
263
+ */
264
+ type PathsTo<T, Leaf, Seen extends readonly unknown[] = [], D extends number = 12> = [D] extends [never] ? "<depth-exhausted>" : 0 extends 1 & T ? never : T extends Leaf ? "" : T extends string | number | boolean | bigint | symbol | null | undefined ? never : T extends (...args: never[]) => unknown ? never : SeenOnPath<T, Seen> extends true ? never : T extends readonly (infer E)[] ? JoinPath<"[]", PathsTo<E, Leaf, [...Seen, T], SeatDepth[D]>> : T extends object ? {
265
+ [K in keyof T & string]-?: JoinPath<K, PathsTo<NonNullable<T[K]>, Leaf, [...Seen, T], SeatDepth[D]>>;
266
+ }[keyof T & string] : never;
267
+ type _SeatWalkDeep = {
268
+ verification: {
269
+ deep: {
270
+ a: {
271
+ b: {
272
+ c: {
273
+ d: {
274
+ e: {
275
+ f: {
276
+ t: CheckpointToken;
277
+ };
278
+ };
279
+ };
280
+ };
281
+ };
282
+ };
283
+ };
284
+ };
285
+ };
286
+ type _SeatWalkCheckDepth8 = AssertAllKeysHandled<Exclude<"verification.deep.a.b.c.d.e.f.t", PathsTo<_SeatWalkDeep, CheckpointToken>>>;
287
+ type _SeatWalkTooDeep = {
288
+ a: {
289
+ b: {
290
+ c: {
291
+ d: {
292
+ e: {
293
+ f: {
294
+ g: {
295
+ h: {
296
+ i: {
297
+ j: {
298
+ k: {
299
+ l: {
300
+ m: {
301
+ t: CheckpointToken;
302
+ };
303
+ };
304
+ };
305
+ };
306
+ };
307
+ };
308
+ };
309
+ };
310
+ };
311
+ };
312
+ };
313
+ };
314
+ };
315
+ };
316
+ type _SeatWalkCheckExhaustionLoud = AssertAllKeysHandled<Exclude<"a.b.c.d.e.f.g.h.i.j.k.l.m.<depth-exhausted>", PathsTo<_SeatWalkTooDeep, CheckpointToken>>>;
317
+ /** 本仓结算点交给封口的**全部出口结果类型**(普通腿 / verify 腿 / cascade 腿)—— ⑩f(停驻座)与 ⑩g(结果文本叶,`observability/run-terminal.ts`)同读这一组。 */
318
+ export type ExitResult = TaskResult | VerificationResult | CascadeRunResult;
319
+ type SeatPathText<P extends readonly string[]> = P extends readonly [infer H extends string, ...infer R extends readonly string[]] ? (R extends readonly [] ? H : `${H}.${SeatPathText<R>}`) : never;
320
+ /** 座表上某一键(凭据 / 门)的全部路径,按行分配。⑩g 的结果文本叶从派生键集里减掉这几条(它们归封口 + 门脱敏,不归文本表)。 */
321
+ export type SeatKeyPaths<S, K extends "token" | "gate"> = S extends PauseSeat ? `${SeatPathText<S["path"]>}.${S[K]}` : never;
322
+ type _GuardTokenSeats = AssertAllKeysHandled<Exclude<PathsTo<ExitResult, CheckpointToken>, SeatKeyPaths<PauseSeat, "token">>>;
323
+ type _GuardTokenSeatsReverse = AssertAllKeysHandled<Exclude<SeatKeyPaths<PauseSeat, "token">, PathsTo<ExitResult, CheckpointToken>>>;
324
+ type _GuardGateSeats = AssertAllKeysHandled<Exclude<PathsTo<ExitResult, CheckpointGate>, SeatKeyPaths<PauseSeat, "gate">>>;
325
+ type _GuardGateSeatsReverse = AssertAllKeysHandled<Exclude<SeatKeyPaths<PauseSeat, "gate">, PathsTo<ExitResult, CheckpointGate>>>;
326
+ /** 一个串型装得下任意文字 ⇔ 以它为键的记录不要求任何具名键(`string` / 模板串 / 品牌串给出索引签名或空形;闭集字面量给出必需键)。 */
327
+ type FreeTextString<S extends string> = {} extends Record<S, 0> ? "" : never;
328
+ type TextLeafSegment<K extends string | number> = K extends number ? (number extends K ? "*" : `${K}`) : string extends K ? "*" : K;
329
+ export type TextLeafPaths<T, Seen extends readonly unknown[] = [], D extends number = 12> = [D] extends [never] ? "<depth-exhausted>" : 0 extends 1 & T ? "" : unknown extends T ? "" : T extends string ? FreeTextString<T> : T extends number | boolean | bigint | symbol | null | undefined ? never : T extends (...args: never[]) => unknown ? never : SeenOnPath<T, Seen> extends true ? never : T extends readonly (infer E)[] ? JoinPath<"[]", TextLeafPaths<E, [...Seen, T], SeatDepth[D]>> : T extends object ? {
330
+ [K in keyof T & (string | number)]-?: JoinPath<TextLeafSegment<K>, TextLeafPaths<T[K], [...Seen, T], SeatDepth[D]>>;
331
+ }[keyof T & (string | number)] : never;
332
+ /** 落在某个前缀**之下或就是它**的路径折成那个前缀(子树归前缀的属主);不在任何前缀下的原样。前缀之间不许互相嵌套(嵌套 ⇒ 一条路径折成两个,表上两行同判一片叶)。 */
333
+ export type CollapseUnder<P extends string, Prefix extends string> = P extends unknown ? ([OwnerPrefixOf<P, Prefix>] extends [never] ? P : OwnerPrefixOf<P, Prefix>) : never;
334
+ type OwnerPrefixOf<P extends string, Prefix extends string> = Prefix extends unknown ? (P extends Prefix | `${Prefix}.${string}` ? Prefix : never) : never;
335
+ /** 判别联合各臂键的**并集**(`keyof` 一个联合给的是交集)。 */
336
+ type AllKeysOfUnion<T> = T extends unknown ? keyof T : never;
337
+ /** 联合里各臂在键 `K` 上的成员型之并(没有这一键的臂不贡献)。 */
338
+ type MemberOfUnion<T, K extends PropertyKey> = T extends unknown ? (K extends keyof T ? T[K] : never) : never;
339
+ /**
340
+ * 处置词 `W` 盖得住型 `V` ⇔ `V` 之下的每一片自由文本叶(相对 `V` 的路径)都在 `Covers[W]` 里。词表即盖法表:叶词盖 `""`(成员自己那片叶)、
341
+ * `text[]` 类词盖 `"[]"`、按自家派生表下降的词与整树词盖 `string`(下降目标的表同样是 {@link OwnerTable},逐层同一条)。
342
+ */
343
+ export type CoveringWords<V, Covers extends Record<string, string>> = {
344
+ [W in keyof Covers & string]: [Exclude<TextLeafPaths<V>, Covers[W]>] extends [never] ? W : never;
345
+ }[keyof Covers & string];
346
+ /**
347
+ * 属主表的型:`T`(可为判别联合,取各臂键之并)的每个成员一行、少一行 / 多一行都红,且每行只许 {@link CoveringWords} —— 一个 `"verbatim"`
348
+ * 落在藏着自由文本叶的对象成员上(core 往 `stats.nested` 这种数字袋里加一个字符串成员)⇒ 该行不再可赋 ⇒ tsc 红,不是静默逐字。
349
+ */
350
+ export type OwnerTable<T, Covers extends Record<string, string>> = {
351
+ readonly [K in AllKeysOfUnion<T>]: CoveringWords<MemberOfUnion<T, K>, Covers>;
352
+ };
353
+ type _TextWalkProbe = {
354
+ s: string;
355
+ w: "a" | "b";
356
+ tpl: `${string}.x`;
357
+ br: string & {
358
+ readonly brand: 1;
359
+ };
360
+ n: number;
361
+ f: boolean;
362
+ o: unknown;
363
+ a: any;
364
+ arr: {
365
+ t: string;
366
+ }[];
367
+ idx: Record<string, string>;
368
+ byNum: Record<number, string>;
369
+ tuple0: {
370
+ 0: string;
371
+ };
372
+ own: {
373
+ x: string;
374
+ y: {
375
+ z: string;
376
+ };
377
+ };
378
+ nil?: null;
379
+ ev: {
380
+ text?: string;
381
+ cause?: {
382
+ text?: string;
383
+ };
384
+ };
385
+ };
386
+ type _TextWalkExpected = "s" | "tpl" | "br" | "o" | "a" | "arr.[].t" | "idx.*" | "byNum.*" | "tuple0.0" | "own" | "ev.text" | "ev.cause.text";
387
+ type _TextWalkGot = CollapseUnder<TextLeafPaths<_TextWalkProbe>, "own">;
388
+ type _TextLeafWalkCheckShapes = AssertAllKeysHandled<Exclude<_TextWalkExpected, _TextWalkGot> | Exclude<_TextWalkGot, _TextWalkExpected>>;
389
+ type _TextWalkTooDeep = {
390
+ a: {
391
+ b: {
392
+ c: {
393
+ d: {
394
+ e: {
395
+ f: {
396
+ g: {
397
+ h: {
398
+ i: {
399
+ j: {
400
+ k: {
401
+ l: {
402
+ m: {
403
+ t: string;
404
+ };
405
+ };
406
+ };
407
+ };
408
+ };
409
+ };
410
+ };
411
+ };
412
+ };
413
+ };
414
+ };
415
+ };
416
+ };
417
+ };
418
+ type _TextLeafWalkCheckExhaustionLoud = AssertAllKeysHandled<Exclude<"a.b.c.d.e.f.g.h.i.j.k.l.m.<depth-exhausted>", TextLeafPaths<_TextWalkTooDeep>>>;
419
+ type _CoverProbeWords = {
420
+ verbatim: "";
421
+ "text[]": "[]";
422
+ tree: string;
423
+ };
424
+ type _CoverWordsCheck = AssertAllKeysHandled<Exclude<CoveringWords<{
425
+ tokens: number;
426
+ label: string;
427
+ }, _CoverProbeWords>, "tree"> | Exclude<"tree", CoveringWords<{
428
+ tokens: number;
429
+ label: string;
430
+ }, _CoverProbeWords>> | Exclude<"verbatim" | "tree", CoveringWords<{
431
+ tokens: number;
432
+ carrier?: "header" | "query";
433
+ }, _CoverProbeWords>> | Exclude<"text[]" | "tree", CoveringWords<readonly string[] | undefined, _CoverProbeWords>> | Extract<"verbatim" | "text[]", CoveringWords<{
434
+ note: string;
435
+ }[], _CoverProbeWords>>>;
251
436
  type SessionMemoryStatusProjected = "captureOptedOut" | "committedCount" | "foldedCount" | "optOutSource" | "lastCaptureAt";
252
437
  type SessionMemoryStatusExcluded = "writeHome";
253
438
  type _GuardSessionMemoryStatus = AssertAllKeysHandled<Exclude<keyof SessionMemoryStatus, SessionMemoryStatusProjected | SessionMemoryStatusExcluded>>;
@@ -478,7 +663,16 @@ export type CoreKeysetGuards = [
478
663
  _GuardLspOptionsReverse,
479
664
  _GuardLedgerRunnerDepsReverse,
480
665
  _GuardSessionWorkspace,
481
- _GuardSessionWorkspaceReverse
666
+ _GuardSessionWorkspaceReverse,
667
+ _GuardTokenSeats,
668
+ _GuardTokenSeatsReverse,
669
+ _GuardGateSeats,
670
+ _GuardGateSeatsReverse,
671
+ _SeatWalkCheckDepth8,
672
+ _SeatWalkCheckExhaustionLoud,
673
+ _TextLeafWalkCheckShapes,
674
+ _TextLeafWalkCheckExhaustionLoud,
675
+ _CoverWordsCheck
482
676
  ];
483
677
  export {};
484
678
  //# sourceMappingURL=core-keyset-guard.d.ts.map
@@ -31,7 +31,7 @@ export declare function engineNoticeSessionId(notice: {
31
31
  sessionId?: unknown;
32
32
  detail?: Record<string, unknown>;
33
33
  }): string | undefined;
34
- /** wire 上的 `engine_notice` 载荷(**五键固定**,设计稿 ②)。`type` 由发帧处补(SSE)/ 由账本行的 type 列承载。 */
34
+ /** wire 上的 `engine_notice` 载荷(**六键固定**,设计稿 ②;`eventId` 随投递身份一并到货)。`type` 由发帧处补(SSE)/ 由账本行的 type 列承载。 */
35
35
  export interface EngineNoticeWireRow {
36
36
  /** 稳定机器码 —— 消费契约:cli 按 `code`+`detail` 渲染(见 {@link ENGINE_NOTICE_WIRE_CODES} 各码的 detail 形)。 */
37
37
  code: string;
@@ -46,6 +46,12 @@ export interface EngineNoticeWireRow {
46
46
  sessionId: string;
47
47
  /** **服务端观察时刻**(ms epoch)——`EngineNotice` 自身不带时间戳,这是本仓收到它的那一拍,不是 core 铸它的那一拍。 */
48
48
  ts: number;
49
+ /**
50
+ * 这一次投递的身份(uuidv7,非空):分流器**扇出时铸一枚**({@link EngineNoticeRouter} 的 `fanOut`,与 `ts` 同处),同腿的 live 帧与 durable 账本行是**同一只行对象**,
51
+ * 所以两个载体同值。live 帧因此带 `id:` 行(契约 §0.6:载荷有 `eventId` 才发行),重连后从 durable 尾(`GET /v1/runs/:id/events`,从头重放)读到的同一条通告靠这一枚认出是同一件事。
52
+ * 同一内容的两次投递是两件事、两枚身份。不是 core 的字段(`EngineNotice` 没有),也不可从内容推:同码同毫秒的两条内容哈希会撞。
53
+ */
54
+ eventId: string;
49
55
  }
50
56
  /**
51
57
  * 上 wire 的**注册方写的自由文本**的唯一出口纪律:`redactSecrets` + 截到 {@link NOTICE_TEXT_MAX}。
@@ -106,7 +112,7 @@ export declare function engineNoticeEventData(notice: {
106
112
  code: string;
107
113
  message: string;
108
114
  detail?: Record<string, unknown>;
109
- }, sessionId: string, nowMs: number): EngineNoticeWireRow;
115
+ }, sessionId: string, nowMs: number, eventId: string): EngineNoticeWireRow;
110
116
  /**
111
117
  * 一条 run 腿注册进来的投递口。抛错由 {@link EngineNoticeRouter.route} 隔离(见那里的 fail-open 登记)。
112
118
  * 返回值只对 {@link EngineNoticeRouter.routeConfirmed} 有意义([ref] codex r1-F2 / r2-F1):durable 口交回它那一次账本写的 thenable,
@@ -1,3 +1,4 @@
1
+ import { uuidv7 } from "@sema-agent/core";
1
2
  import { redactSecrets } from "./redact.js";
2
3
  import { redactListEntry } from "../list-entry-display.js";
3
4
  import { recordFailOpen } from "../observability/fail-open.js";
@@ -128,13 +129,14 @@ export function redactNoticeRuleText(code, detail) {
128
129
  });
129
130
  return { ...detail, [at.array]: redacted };
130
131
  }
131
- export function engineNoticeEventData(notice, sessionId, nowMs) {
132
+ export function engineNoticeEventData(notice, sessionId, nowMs, eventId) {
132
133
  return {
133
134
  code: notice.code,
134
135
  message: redactNoticeMessage(notice.message).slice(0, NOTICE_TEXT_MAX),
135
136
  detail: sanitizeNoticeDetail(redactNoticeRuleText(notice.code, notice.detail)),
136
137
  sessionId,
137
138
  ts: nowMs,
139
+ eventId,
138
140
  };
139
141
  }
140
142
  const isThenableResult = (v) => typeof v === "object" && v !== null && typeof v.then === "function";
@@ -189,7 +191,7 @@ export class EngineNoticeRouter {
189
191
  const leg = list && list.length > 0 ? list[list.length - 1] : undefined;
190
192
  if (!leg || leg.sinks.length === 0)
191
193
  return [];
192
- const row = engineNoticeEventData(notice, sessionId, nowMs);
194
+ const row = engineNoticeEventData(notice, sessionId, nowMs, uuidv7());
193
195
  const outcomes = [];
194
196
  for (const { slot, sink } of leg.sinks) {
195
197
  try {
@@ -9,7 +9,8 @@ export type SafeText = string & {
9
9
  * · `trace-frame-text`:trace 帧的自由文本位(子代名 / 动作行 / 通告正文与结果 / 诊断 / 注入摘录 / 压缩说明 / 人类输入的署名与附件标签 …),不设界;
10
10
  * · `trace-frame-line`:trace 帧里一行宽的展示位(`workspace_changed.cwd` / `brain_status.detail`),界 300 码元;
11
11
  * · `operator-log-text`:运维日志字段里的一句话 —— 读口坏行的缺陷句(core 的筛按位置点名并回显落盘标量)、`tool_trace` 行里工具的输出 / 失败句 / 拒因、
12
- * hook 吐出的预览(非 JSON 的输出 / 应答体)与判词、Stop 评估者回话的头、观察面回调与唤醒投递抛出的句子、matcher 超预算的那两串、标题器的两只失败句;界 200 码元(含截断记号);
12
+ * hook 吐出的预览(非 JSON 的输出 / 应答体)与判词、Stop 评估者回话的头、观察面回调与唤醒投递抛出的句子、matcher 超预算的那两串、标题器的两只失败句、
13
+ * 起服面(`src/boot/**`)各条运维行里抛出物的句子与起服自检读数里的客户端异常原文(门 `test/boot-log-thrown-text-seat.test.ts`);界 200 码元(含截断记号);
13
14
  * · `operator-log-arg`:运维日志字段里模型写的工具入参(`tool_trace` 的 `arg.*`:路径 / 命令 / 模式 / 非对象入参的串形);界 120 码元(含截断记号);
14
15
  * · `operator-log-error`:运维日志字段里 hook 一侧的报错 —— hook 命令的 stderr、prompt 条目的载体失败句、起子进程 / 读会话分支抛出的句子;界 300 码元(含截断记号);
15
16
  * · `operator-log-message`:运维日志字段里写给人看的一段话 —— hook 输出的 `systemMessage`、Stop 评估者判「做不到」的理由;界 500 码元(含截断记号);
@@ -19,6 +20,9 @@ export type SafeText = string & {
19
20
  * 引擎放过的形照抹);界 200 码元,原样出门(JSON 串值,消费方自己渲染)。
20
21
  * · `peer-declaration-sentence`:引擎判官对一份 MCP / A2A 对端声明说的句子(`toolAxes` / `toolFaces` / `sessionMetaKey` / 启动界的原因句,逐字带着声明方写的工具名、键名),
21
22
  * 进请求面 400 拒句、续跑重放的丢弃行与重读行、名册的跳过行 —— 读者是调用方与运维,句子已是一行;不设界(拒句要说全判官的话),原样出门。
23
+ * · `inbox-diagnostics-text`:`workflow_complete` 补投帧上的诊断教学文本(`diagnostics`)—— 引擎在 workflow 完成通知上铸的「读哪里 / 怎么续跑」文本,入会话收件时洗一次,
24
+ * 店里(`payload` 列)只放出门安全的字节,drain 逐字带出。洗法与 live `task_notification.diagnostics` 同一个 scope(`free-text`);
25
+ * 这一行比 `trace-frame-text` 多一条界(4000 码元,与同族条目的文本位同额),原样出门:`payload` 列是 TEXT,无界的文本一旦超过列宽,入箱写整条失败、补投连摘要一起丢(完成已被记作送达),所以先有界。
22
26
  * · `boot-refusal-line`:起服拒启的一行拒句 —— 部署座装配的拒句(`mods-declaration.ts`:声明的席名、包名、读包者 / 引擎准入交回的话);它经进程级 fatal 出口原样多行进 stderr,
23
27
  * 所以必须在这里先压成一行(一句拒因里的换行会在运维的终端里伪造出第二条日志行);界 512 码元(含截断记号)。
24
28
  */
@@ -62,6 +66,10 @@ declare const EXIT_SEATS: {
62
66
  readonly "peer-declaration-sentence": {
63
67
  readonly scope: "free-text";
64
68
  };
69
+ readonly "inbox-diagnostics-text": {
70
+ readonly scope: "free-text";
71
+ readonly maxChars: 4000;
72
+ };
65
73
  readonly "boot-refusal-line": {
66
74
  readonly scope: "free-text";
67
75
  readonly maxChars: 512;
@@ -14,6 +14,7 @@ const EXIT_SEATS = {
14
14
  "session-title": { scope: "free-text", maxChars: 80, emit: "title-line" },
15
15
  "mcp-remote-text": { scope: "free-text", maxChars: 200 },
16
16
  "peer-declaration-sentence": { scope: "free-text" },
17
+ "inbox-diagnostics-text": { scope: "free-text", maxChars: 4000 },
17
18
  "boot-refusal-line": { scope: "free-text", maxChars: 512, emit: "log-line" },
18
19
  };
19
20
  export function seatMaxChars(seat) {
@@ -1,5 +1,5 @@
1
1
  import { type TerminalCause } from "@sema-agent/core";
2
- import { brainStatusEventData, type LegWiringSections } from "./project.js";
2
+ import { brainStatusEventData, type ModelUsageSeat, type LegWiringSections } from "./project.js";
3
3
  import { NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
4
4
  import { type LedgerEventType, type ParkLedgerEventType } from "./ledger-events.js";
5
5
  /**
@@ -59,7 +59,8 @@ export interface LedgerSink {
59
59
  onForwardEvent(e: {
60
60
  type?: string;
61
61
  }): void;
62
- /** Park event (durable F4 suspend / [ref] D-B review pause): ONLY the `checkpointGate` is persisted —
62
+ /** Park event (durable F4 suspend / [ref] D-B review pause), written AFTER any pending `model_usage` delta of the leg (the status frame
63
+ * is the last frame a leg writes — `appendParkRow` owns that order): ONLY the `checkpointGate` is persisted —
63
64
  * never the capability `checkpointToken` (search [18] Q1b).
64
65
  * 🔴 **The gate is redacted, not "non-secret"** ([ref], 2026-09-10 — the arm [ref] R3 left open): it carries no
65
66
  * capability token, but its `reason` and the `riskDescriptor` leaf family are model-/human-controlled display
@@ -73,8 +74,8 @@ export interface LedgerSink {
73
74
  /** Terminal `done` event. `result` must already be checkpoint-token-stripped (and, on the bg leg,
74
75
  * model-usage-attached) by the caller. */
75
76
  appendDone(result: unknown): Promise<void>;
76
- /** Convenience for the sync detach lane (no model-usage interleave there): flush, then project the result
77
- * to its park/terminal event exactly like the bg leg's done case. `result` must already be stripped. */
77
+ /** Convenience for the sync detach lane: flush, then project the result to its park/terminal event exactly like the
78
+ * bg leg's done case (a park goes through {@link appendParked}, which settles pending model usage first). `result` must already be stripped. */
78
79
  onDone(result: {
79
80
  terminal: TerminalCause;
80
81
  }): Promise<void>;
@@ -154,5 +155,8 @@ export declare function createLedgerSink(opts: {
154
155
  /** 这条腿的 `wiring_manifest` **本仓自铸段**(`LegWiringSections`:[ref] `instructions` 读腿的 `InstructionSelectionLeg.segment`、run 级 `skills` 读 spec 字段
155
156
  * `runSkillsOf`)。**必填**:账本行与 live 帧是同一条腿的两个载体,段必须来自同一只腿;在投帧那一刻读(core 推帧之前已 await 过 loader)。 */
156
157
  legSections: () => LegWiringSections;
158
+ /** 这条腿的计量席(E8 累加器 + 归因键)。在场 ⇒ {@link LedgerSink.appendParked} 在停驻行之前先把未结清的用量差落成 `model_usage` 行(状态帧最后,见 `appendParkRow`);
159
+ * 缺席 ⇒ 这条腿没接累加器,停驻行之前无账可结(夹具、不经 `appendParked` 停驻的腿)。 */
160
+ usage?: ModelUsageSeat;
157
161
  }): LedgerSink;
158
162
  //# sourceMappingURL=ledger-sink.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import {} from "@sema-agent/core";
2
2
  import { outwardPlane } from "../terminal.js";
3
3
  import { recordFailOpen } from "../observability/fail-open.js";
4
- import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData, parkEventData } from "./project.js";
4
+ import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData, appendParkRow } from "./project.js";
5
5
  import { NotifiedKeys, taskNotificationStreamKeyOf } from "../orchestration/workflow-completion-inbox.js";
6
6
  import { isParkLedgerEventType } from "./ledger-events.js";
7
7
  import { isModelSegmentBoundary, reasoningDeltaBytes, reasoningSegmentEventId } from "./model-segment.js";
@@ -179,7 +179,7 @@ export function createLedgerSink(opts) {
179
179
  return append("status", statusData);
180
180
  };
181
181
  const appendParked = (kind, result) => {
182
- return append(kind, parkEventData(result));
182
+ return appendParkRow(append, opts.usage, kind, result);
183
183
  };
184
184
  const appendDone = (result) => append("done", { result });
185
185
  const onDone = async (result) => {