@sema-agent/server 7.141.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 (171) hide show
  1. package/MIGRATION.md +215 -0
  2. package/USAGE.md +67 -12
  3. package/dist/approval-ask-audit-store.d.ts +54 -38
  4. package/dist/approval-ask-audit-store.js +58 -39
  5. package/dist/approval-card.d.ts +8 -8
  6. package/dist/approval-crash-convergence.d.ts +17 -7
  7. package/dist/approval-crash-convergence.js +94 -22
  8. package/dist/approval-deny-reasons.d.ts +34 -30
  9. package/dist/approval-deny-reasons.js +21 -6
  10. package/dist/approval-policy-settlement.d.ts +1 -1
  11. package/dist/approval-reconciler.d.ts +33 -1
  12. package/dist/approval-reconciler.js +43 -40
  13. package/dist/auth-bridge.d.ts +9 -6
  14. package/dist/auth-bridge.js +9 -3
  15. package/dist/boot/adoption.js +2 -1
  16. package/dist/boot/budget-tracing.d.ts +16 -0
  17. package/dist/boot/budget-tracing.js +10 -6
  18. package/dist/boot/device-lane.d.ts +1 -1
  19. package/dist/boot/execution-env.d.ts +24 -4
  20. package/dist/boot/execution-env.js +26 -23
  21. package/dist/boot/execution-lane.js +2 -1
  22. package/dist/boot/exit-boundary.js +5 -4
  23. package/dist/boot/memory-consolidation.js +2 -1
  24. package/dist/boot/parked-revive-gate.js +2 -1
  25. package/dist/boot/permission-rules-audit.d.ts +0 -28
  26. package/dist/boot/permission-rules-audit.js +2 -1
  27. package/dist/boot/read-deny-anchor-audit.js +2 -1
  28. package/dist/boot/reapers.js +4 -3
  29. package/dist/boot/resolve-spec.js +11 -2
  30. package/dist/boot/retention-lane.js +5 -3
  31. package/dist/boot/runner-deps.js +16 -13
  32. package/dist/boot/runtime-caps.js +3 -2
  33. package/dist/boot/session-faces.js +4 -3
  34. package/dist/boot/shutdown.js +3 -2
  35. package/dist/boot/stage-04-stores.js +3 -2
  36. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  37. package/dist/boot/stage-05-execution-env.js +8 -6
  38. package/dist/boot/stage-06-runners.d.ts +1 -1
  39. package/dist/boot/stage-06-runners.js +2 -1
  40. package/dist/boot/stage-07-capability-layer.d.ts +1 -1
  41. package/dist/boot/stage-07-capability-layer.js +2 -1
  42. package/dist/boot/stage-08-reapers.d.ts +1 -1
  43. package/dist/boot/stage-08-reapers.js +3 -2
  44. package/dist/boot/stage-09-leader.d.ts +1 -1
  45. package/dist/boot/stage-10-http-server.d.ts +1 -1
  46. package/dist/boot/stage-10-http-server.js +5 -4
  47. package/dist/boot/stores.js +3 -2
  48. package/dist/boot/web-admin.js +17 -17
  49. package/dist/boot/webfetch-summarize-lane.js +2 -1
  50. package/dist/boot/workflow-orchestration.js +3 -2
  51. package/dist/capabilities/builtin-tools.d.ts +2 -1
  52. package/dist/capabilities/builtin-tools.js +2 -4
  53. package/dist/capabilities/composite-members.d.ts +2 -1
  54. package/dist/capabilities/composite-members.js +2 -1
  55. package/dist/capability-facts.d.ts +24 -0
  56. package/dist/capability-facts.js +23 -0
  57. package/dist/config-catalog.js +1 -0
  58. package/dist/config-types.d.ts +15 -4
  59. package/dist/config.d.ts +6 -0
  60. package/dist/config.js +17 -3
  61. package/dist/execution-lane-caps.d.ts +2 -1
  62. package/dist/fleet/fleet-bus.d.ts +6 -3
  63. package/dist/hooks/hook-runner.d.ts +6 -0
  64. package/dist/hooks/hook-runner.js +30 -1
  65. package/dist/http/dispatch.js +4 -2
  66. package/dist/http/execution-context.d.ts +2 -2
  67. package/dist/http/idempotency.d.ts +1 -1
  68. package/dist/http/principal-gate.d.ts +3 -1
  69. package/dist/http/principal-gate.js +17 -8
  70. package/dist/http/resume-legs.js +5 -9
  71. package/dist/http/route-table.js +2 -0
  72. package/dist/http/routes/attachments.js +18 -0
  73. package/dist/http/routes/capabilities.js +5 -2
  74. package/dist/http/routes/memory-policy.js +26 -6
  75. package/dist/http/routes/runs.js +3 -3
  76. package/dist/http/routes/session-memory-sync.d.ts +63 -0
  77. package/dist/http/routes/session-memory-sync.js +157 -0
  78. package/dist/http/routes/sessions-list.d.ts +2 -1
  79. package/dist/http/routes/tasks.js +7 -5
  80. package/dist/http/run-read-face.d.ts +7 -0
  81. package/dist/http/run-read-face.js +9 -3
  82. package/dist/http/send.d.ts +5 -0
  83. package/dist/http/send.js +9 -2
  84. package/dist/http/server.d.ts +14 -8
  85. package/dist/http/server.js +2 -4
  86. package/dist/http/submit-replay.d.ts +4 -3
  87. package/dist/http/submit-replay.js +2 -2
  88. package/dist/http/sync-submit-body.d.ts +21 -4
  89. package/dist/http/sync-submit-body.js +13 -0
  90. package/dist/identity-source.d.ts +21 -2
  91. package/dist/identity-source.js +6 -0
  92. package/dist/memory-incident-sink.d.ts +19 -6
  93. package/dist/memory-incident-sink.js +8 -4
  94. package/dist/memory-sync-client.d.ts +21 -21
  95. package/dist/memory-sync-client.js +50 -42
  96. package/dist/memory-sync-identity.d.ts +24 -0
  97. package/dist/memory-sync-identity.js +57 -0
  98. package/dist/memory-sync.d.ts +7 -1
  99. package/dist/memory-sync.js +6 -3
  100. package/dist/observability/fail-open.d.ts +27 -10
  101. package/dist/observability/fail-open.js +20 -7
  102. package/dist/observability/run-terminal.d.ts +92 -34
  103. package/dist/observability/run-terminal.js +167 -162
  104. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  105. package/dist/plugins/approval-ask-store-file.js +48 -7
  106. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  107. package/dist/plugins/approval-ask-store-memory.js +9 -8
  108. package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
  109. package/dist/plugins/approval-ask-store-sql.js +49 -19
  110. package/dist/plugins/file-run-store.d.ts +6 -1
  111. package/dist/plugins/file-run-store.js +11 -1
  112. package/dist/plugins/local-session-store.d.ts +36 -7
  113. package/dist/plugins/local-session-store.js +76 -32
  114. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  115. package/dist/plugins/local-task-attachment-store.js +67 -43
  116. package/dist/plugins/memory-key-guards.d.ts +3 -3
  117. package/dist/plugins/memory-run-store.d.ts +6 -1
  118. package/dist/plugins/memory-run-store.js +11 -1
  119. package/dist/plugins/one-time-migrations.d.ts +27 -1
  120. package/dist/plugins/one-time-migrations.js +57 -3
  121. package/dist/plugins/remote-env-e2b.d.ts +23 -4
  122. package/dist/plugins/remote-env-e2b.js +111 -28
  123. package/dist/plugins/remote-env-k8s.d.ts +31 -5
  124. package/dist/plugins/remote-env-k8s.js +86 -19
  125. package/dist/plugins/remote-env-local-docker.d.ts +15 -3
  126. package/dist/plugins/remote-env-local-docker.js +40 -12
  127. package/dist/plugins/run-store-sql.d.ts +9 -1
  128. package/dist/plugins/run-store-sql.js +9 -1
  129. package/dist/plugins/store-backend.d.ts +10 -7
  130. package/dist/plugins/store-backend.js +1 -0
  131. package/dist/plugins/store-contracts.d.ts +26 -1
  132. package/dist/plugins/store-contracts.js +3 -0
  133. package/dist/plugins/task-attachment-store.d.ts +112 -14
  134. package/dist/plugins/task-attachment-store.js +221 -28
  135. package/dist/plugins/workspace-fill.d.ts +60 -0
  136. package/dist/plugins/workspace-fill.js +106 -0
  137. package/dist/project-bundle.d.ts +38 -0
  138. package/dist/project-bundle.js +609 -0
  139. package/dist/run-local.js +2 -8
  140. package/dist/runs.js +1 -2
  141. package/dist/sandbox-egress-policy.d.ts +4 -1
  142. package/dist/sandbox-egress-policy.js +3 -1
  143. package/dist/sandbox-git-plane.d.ts +31 -12
  144. package/dist/sandbox-git-plane.js +24 -4
  145. package/dist/security.d.ts +9 -0
  146. package/dist/security.js +8 -0
  147. package/dist/session-error-wire.d.ts +24 -0
  148. package/dist/session-error-wire.js +7 -0
  149. package/dist/task-settings.d.ts +10 -2
  150. package/dist/task-settings.js +15 -2
  151. package/dist/terminal.d.ts +39 -19
  152. package/dist/terminal.js +65 -22
  153. package/dist/tool-approval.d.ts +4 -3
  154. package/dist/tool-approval.js +12 -14
  155. package/dist/trace/core-keyset-guard.d.ts +123 -6
  156. package/dist/trace/engine-notice-wire.d.ts +8 -2
  157. package/dist/trace/engine-notice-wire.js +4 -2
  158. package/dist/trace/exit-seat.d.ts +2 -1
  159. package/dist/trace/ledger-sink.d.ts +8 -4
  160. package/dist/trace/ledger-sink.js +2 -2
  161. package/dist/trace/project.d.ts +18 -1
  162. package/dist/trace/project.js +16 -0
  163. package/dist/trace/self-minted-wire.d.ts +251 -2
  164. package/dist/trace/self-minted-wire.js +82 -0
  165. package/dist/trace/wire-projection-faces.d.ts +1 -1
  166. package/dist/trace/wire-projection-faces.js +1 -1
  167. package/dist/web-admin-client/apply-effective.js +21 -1
  168. package/dist/web-admin-client/effective-keys.js +2 -0
  169. package/dist/web-admin-client/types.d.ts +4 -0
  170. package/package.json +1 -1
  171. package/wire-changes/server@7.142.0.json +639 -0
@@ -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;
@@ -251,8 +251,11 @@ type _GuardTerminalArm = AssertAllKeysHandled<Exclude<NonPausedTerminalKeys, Ter
251
251
  type _GuardTerminalArmReverse = AssertAllKeysHandled<Exclude<TerminalArmForwarded | TerminalArmStripped, NonPausedTerminalKeys>>;
252
252
  type SeatDepth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
253
253
  type JoinPath<K extends string, P extends string> = [P] extends [never] ? never : P extends "" ? K : `${K}.${P}`;
254
- /** `T` 与祖先链上某一层**互相可赋**(同一个形)⇒ 这是递归类型的回环(如 JSON 值类型),再走只是同一棵子树换个前缀,停。只比祖先、不比兄弟。 */
255
- type SeenOnPath<T, Seen extends readonly unknown[]> = Seen extends readonly [infer H, ...infer R extends readonly unknown[]] ? [T] extends [H] ? [H] extends [T] ? true : SeenOnPath<T, R> : SeenOnPath<T, R> : false;
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;
256
259
  /**
257
260
  * `T` 里类型为 `Leaf` 的全部路径(点分;数组元素记 `[]`;`any` 不展开)。回环按祖先链判停;深度封顶 12 且**封顶响亮**:
258
261
  * 走到底还没走完的分支产出以 `<depth-exhausted>` 收尾的路径 —— 它不在座表里 ⇒ 下面的正向对账 TS2344(封顶静默返回 `never`
@@ -311,14 +314,125 @@ type _SeatWalkTooDeep = {
311
314
  };
312
315
  };
313
316
  type _SeatWalkCheckExhaustionLoud = AssertAllKeysHandled<Exclude<"a.b.c.d.e.f.g.h.i.j.k.l.m.<depth-exhausted>", PathsTo<_SeatWalkTooDeep, CheckpointToken>>>;
314
- type ExitResult = TaskResult | VerificationResult | CascadeRunResult;
317
+ /** 本仓结算点交给封口的**全部出口结果类型**(普通腿 / verify 腿 / cascade 腿)—— ⑩f(停驻座)与 ⑩g(结果文本叶,`observability/run-terminal.ts`)同读这一组。 */
318
+ export type ExitResult = TaskResult | VerificationResult | CascadeRunResult;
315
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;
316
- /** 座表上某一键(凭据 / 门)的全部路径,按行分配。 */
317
- type SeatKeyPaths<S, K extends "token" | "gate"> = S extends PauseSeat ? `${SeatPathText<S["path"]>}.${S[K]}` : never;
320
+ /** 座表上某一键(凭据 / 门)的全部路径,按行分配。⑩g 的结果文本叶从派生键集里减掉这几条(它们归封口 + 门脱敏,不归文本表)。 */
321
+ export type SeatKeyPaths<S, K extends "token" | "gate"> = S extends PauseSeat ? `${SeatPathText<S["path"]>}.${S[K]}` : never;
318
322
  type _GuardTokenSeats = AssertAllKeysHandled<Exclude<PathsTo<ExitResult, CheckpointToken>, SeatKeyPaths<PauseSeat, "token">>>;
319
323
  type _GuardTokenSeatsReverse = AssertAllKeysHandled<Exclude<SeatKeyPaths<PauseSeat, "token">, PathsTo<ExitResult, CheckpointToken>>>;
320
324
  type _GuardGateSeats = AssertAllKeysHandled<Exclude<PathsTo<ExitResult, CheckpointGate>, SeatKeyPaths<PauseSeat, "gate">>>;
321
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>>>;
322
436
  type SessionMemoryStatusProjected = "captureOptedOut" | "committedCount" | "foldedCount" | "optOutSource" | "lastCaptureAt";
323
437
  type SessionMemoryStatusExcluded = "writeHome";
324
438
  type _GuardSessionMemoryStatus = AssertAllKeysHandled<Exclude<keyof SessionMemoryStatus, SessionMemoryStatusProjected | SessionMemoryStatusExcluded>>;
@@ -555,7 +669,10 @@ export type CoreKeysetGuards = [
555
669
  _GuardGateSeats,
556
670
  _GuardGateSeatsReverse,
557
671
  _SeatWalkCheckDepth8,
558
- _SeatWalkCheckExhaustionLoud
672
+ _SeatWalkCheckExhaustionLoud,
673
+ _TextLeafWalkCheckShapes,
674
+ _TextLeafWalkCheckExhaustionLoud,
675
+ _CoverWordsCheck
559
676
  ];
560
677
  export {};
561
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 码元(含截断记号);
@@ -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) => {
@@ -30,7 +30,7 @@ import type { RunCompanionRecord } from "../observability/prompt-manifest.js";
30
30
  import { type SafeText } from "./exit-seat.js";
31
31
  import { type SemaProvenanceInput } from "./sema-provenance.js";
32
32
  import { type ExtensionRequesterFace, type ToolInputRewriteFace } from "./extension-call-face.js";
33
- import type { LedgerEventType } from "./ledger-events.js";
33
+ import type { LedgerEventType, ParkLedgerEventType } from "./ledger-events.js";
34
34
  import type { InstructionsSegment } from "../instruction-selection.js";
35
35
  import type { RunSkillEntry } from "../capabilities/skills.js";
36
36
  /** 账本写口的统一签名 —— `type` 是**闭集**(`ledger-events.ts`):新型必须先登记,否则调用点编译红
@@ -419,6 +419,23 @@ export interface ParkEventData {
419
419
  * 门身份读法与三处 durable 读面同一只(`durableRowIdentity`,face `run-events-park`):没有暂停因由的行不问身份(没有门可认);有因由而读不出 ⇒ 键缺席 + 计一次。
420
420
  */
421
421
  export declare function parkEventData(result: unknown, reopened?: string | null): ParkEventData;
422
+ /** 一腿的计量席:E8 累加器 + 这条腿在累加器里的归因键。`modelUsage` 缺席 ⇒ 这条腿没接累加器,没有用量可结。 */
423
+ export interface ModelUsageSeat {
424
+ readonly modelUsage: ModelUsageTracker | undefined;
425
+ readonly taskId: string;
426
+ }
427
+ /**
428
+ * park 账本行的**唯一写口** —— {@link parkEventData} 是行的唯一构造器,本函数是它的唯一落账处:后台腿与同步 detach 腿(`LedgerSink.appendParked`)、
429
+ * 续跑腿的再停两臂、重开臂与续跑 verify 臂(`resume-legs.ts`)都经这一只。
430
+ *
431
+ * **状态帧最后**:一腿账本的状态帧(终局 `done` / `failed`、停驻 `suspended` / `needs_review`)是这一腿主线写下的最后一帧(晚到的子代转发帧、完成后的 suggestions 是旁路写,不在此列),计量帧先于它写出 ——
432
+ * 终局由 {@link attachModelUsage} 先结清最后一拍再落 `done`,停驻由本函数先 drain 再落停驻行。顺序属于写口、不属于调用点:
433
+ * 只回结果的 verify 腿没有逐 turn 落账的流(无 `turn_end` 帧),挂起前的用量只有停驻这一拍才落账;若各调用点各自记得「先结清」,
434
+ * 这条腿的账本尾帧就会是 `model_usage`,与不带 `verify` 的停驻(用量在 `turn_end` 就结清了)两形不同序(`GET /v1/runs/:id/events` 的尾帧)。
435
+ * 用量行落不下 ⇒ 停驻行**照落**,然后把用量行的失败抛给调用方(失败语义与此前逐字同:账本里有停驻帧、调用方按「停驻没落定」收场 —— bg 腿以 `failed` 收、手里的卡作废;
436
+ * 尽力而为的调用点(detach 腿的兜底停驻、续跑腿的重开臂)照旧吞掉它,停驻帧不因为一笔用量行的失败而缺席)。顺序变了,谁来写、写不下谁抛没有变。
437
+ */
438
+ export declare function appendParkRow(append: AppendFn, usage: ModelUsageSeat | undefined, word: ParkLedgerEventType, result: unknown, reopened?: string | null): Promise<void>;
422
439
  /**
423
440
  * The `task_started` payload(core 7.50.0):一只委派子代**起跑**的那一帧 —— 每周期一只(首派 / 复活;耐久续跑腿不铸),
424
441
  * 序在子代的 `wiring_manifest` 之后、它的首个 `task_progress` 与首次模型请求之前。
@@ -317,6 +317,22 @@ export function parkEventData(result, reopened) {
317
317
  ...(reopened !== undefined ? { reopened } : {}),
318
318
  };
319
319
  }
320
+ export async function appendParkRow(append, usage, word, result, reopened) {
321
+ let drainFailed = false;
322
+ let drainFailure;
323
+ if (usage !== undefined) {
324
+ try {
325
+ await appendModelUsageDelta(append, usage.modelUsage, usage.taskId);
326
+ }
327
+ catch (e) {
328
+ drainFailed = true;
329
+ drainFailure = e;
330
+ }
331
+ }
332
+ await append(word, parkEventData(result, reopened));
333
+ if (drainFailed)
334
+ throw drainFailure;
335
+ }
320
336
  export function taskStartedEventData(ev) {
321
337
  return {
322
338
  taskId: ev.taskId,