@sema-agent/server 7.142.0 → 7.143.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 (258) hide show
  1. package/MIGRATION.md +442 -0
  2. package/USAGE.md +41 -24
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +7 -5
  5. package/dist/approval-ask-audit-store.js +12 -6
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +124 -25
  9. package/dist/approval-card.js +103 -23
  10. package/dist/approval-queue-kind.d.ts +27 -0
  11. package/dist/approval-queue-kind.js +6 -0
  12. package/dist/approval-reconciler.d.ts +8 -8
  13. package/dist/approval-reconciler.js +3 -3
  14. package/dist/audit.js +4 -2
  15. package/dist/boot/budget-tracing.d.ts +1 -1
  16. package/dist/boot/governance-seams.d.ts +26 -41
  17. package/dist/boot/governance-seams.js +61 -28
  18. package/dist/boot/late-binds.d.ts +7 -4
  19. package/dist/boot/late-binds.js +3 -1
  20. package/dist/boot/leader.js +2 -4
  21. package/dist/boot/memory-consolidation.d.ts +0 -8
  22. package/dist/boot/memory-consolidation.js +3 -3
  23. package/dist/boot/reapers.js +5 -4
  24. package/dist/boot/resolve-spec.d.ts +1 -1
  25. package/dist/boot/resolve-spec.js +8 -8
  26. package/dist/boot/runner-deps.d.ts +10 -7
  27. package/dist/boot/runner-deps.js +5 -17
  28. package/dist/boot/shutdown.d.ts +9 -0
  29. package/dist/boot/shutdown.js +16 -2
  30. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  31. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  32. package/dist/boot/stage-03-store-backend.js +1 -2
  33. package/dist/boot/stage-04-stores.d.ts +5 -2
  34. package/dist/boot/stage-04-stores.js +3 -5
  35. package/dist/boot/stage-05-execution-env.d.ts +5 -2
  36. package/dist/boot/stage-06-runners.d.ts +5 -2
  37. package/dist/boot/stage-06-runners.js +1 -3
  38. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  39. package/dist/boot/stage-07-capability-layer.js +5 -1
  40. package/dist/boot/stage-08-reapers.d.ts +5 -2
  41. package/dist/boot/stage-09-leader.d.ts +5 -2
  42. package/dist/boot/stage-10-http-server.d.ts +5 -2
  43. package/dist/boot/stage-10-http-server.js +9 -1
  44. package/dist/boot/stores.d.ts +5 -2
  45. package/dist/boot/stores.js +7 -7
  46. package/dist/boot/web-admin.d.ts +5 -1
  47. package/dist/boot/web-admin.js +31 -19
  48. package/dist/capabilities/hands-lane.d.ts +9 -39
  49. package/dist/capabilities/hands-lane.js +8 -13
  50. package/dist/capabilities/mcp-probe.d.ts +3 -2
  51. package/dist/capabilities/scenarios.d.ts +11 -1
  52. package/dist/capabilities/scenarios.js +1 -0
  53. package/dist/capabilities/skills.d.ts +1 -17
  54. package/dist/capabilities/skills.js +0 -8
  55. package/dist/capability-facts.d.ts +8 -8
  56. package/dist/capability-facts.js +4 -4
  57. package/dist/card-void.d.ts +6 -9
  58. package/dist/config-catalog.js +1 -1
  59. package/dist/config-dir-trust.js +58 -29
  60. package/dist/config-invariants.d.ts +7 -1
  61. package/dist/config-invariants.js +7 -0
  62. package/dist/config-provider.d.ts +10 -0
  63. package/dist/config-provider.js +15 -4
  64. package/dist/config-root-migration.d.ts +13 -0
  65. package/dist/config-root-migration.js +99 -0
  66. package/dist/config-types.d.ts +5 -5
  67. package/dist/config.d.ts +4 -3
  68. package/dist/config.js +1 -1
  69. package/dist/delegated-session-owner.d.ts +5 -3
  70. package/dist/delegated-session-owner.js +1 -1
  71. package/dist/device-ws-protocol.d.ts +1 -0
  72. package/dist/device-ws-protocol.js +2 -1
  73. package/dist/env-model-table-gate.d.ts +53 -0
  74. package/dist/env-model-table-gate.js +53 -0
  75. package/dist/fleet/fleet-bus.d.ts +28 -52
  76. package/dist/fleet/fleet-bus.js +35 -100
  77. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  78. package/dist/fleet/fleet-reconciler.js +1 -1
  79. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  80. package/dist/fleet/subagent-tail-bus.js +15 -28
  81. package/dist/hooks/hook-runner.js +28 -7
  82. package/dist/host-decision.d.ts +54 -20
  83. package/dist/host-decision.js +42 -14
  84. package/dist/http/admission.d.ts +1 -1
  85. package/dist/http/admission.js +7 -3
  86. package/dist/http/approval-sweeps.js +11 -8
  87. package/dist/http/caller-trust.d.ts +1 -1
  88. package/dist/http/durable-run-leg.js +2 -2
  89. package/dist/http/engine-refusal.d.ts +16 -0
  90. package/dist/http/engine-refusal.js +17 -0
  91. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  92. package/dist/http/memory-compliance-failure-reply.js +4 -6
  93. package/dist/http/owner-access.d.ts +11 -0
  94. package/dist/http/owner-access.js +13 -0
  95. package/dist/http/resume-legs.d.ts +21 -7
  96. package/dist/http/resume-legs.js +71 -49
  97. package/dist/http/resume-restatement.d.ts +39 -0
  98. package/dist/http/resume-restatement.js +25 -0
  99. package/dist/http/route-ctx.d.ts +35 -10
  100. package/dist/http/route-ctx.js +1 -1
  101. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  102. package/dist/http/routes/approvals-assistant.js +142 -31
  103. package/dist/http/routes/capabilities.js +11 -2
  104. package/dist/http/routes/memory-policy.d.ts +2 -2
  105. package/dist/http/routes/memory-policy.js +1 -1
  106. package/dist/http/routes/notify-wake.js +23 -25
  107. package/dist/http/routes/rules.js +48 -13
  108. package/dist/http/routes/runs.js +9 -8
  109. package/dist/http/routes/session-memory-sync.d.ts +34 -6
  110. package/dist/http/routes/session-memory-sync.js +27 -10
  111. package/dist/http/routes/session-sync.js +13 -20
  112. package/dist/http/routes/sessions.d.ts +2 -2
  113. package/dist/http/routes/sessions.js +22 -23
  114. package/dist/http/routes/tasks.js +27 -49
  115. package/dist/http/server.d.ts +13 -7
  116. package/dist/http/server.js +2 -2
  117. package/dist/http/stored-body-replay.js +15 -4
  118. package/dist/http/wire-types.d.ts +17 -7
  119. package/dist/leader/leader.js +5 -2
  120. package/dist/leader/wire.d.ts +7 -1
  121. package/dist/leader/wire.js +6 -5
  122. package/dist/leg-facts.d.ts +37 -0
  123. package/dist/leg-facts.js +15 -0
  124. package/dist/memory-bundle-engine.d.ts +1 -4
  125. package/dist/memory-bundle-engine.js +2 -2
  126. package/dist/memory-operator-faces.d.ts +30 -66
  127. package/dist/memory-operator-faces.js +17 -88
  128. package/dist/memory-scope-stores.d.ts +38 -40
  129. package/dist/memory-scope-stores.js +51 -36
  130. package/dist/memory-scope.d.ts +0 -9
  131. package/dist/memory-scope.js +0 -9
  132. package/dist/memory-sync-client.js +14 -3
  133. package/dist/memory-sync.d.ts +20 -4
  134. package/dist/memory-sync.js +23 -4
  135. package/dist/model-plane-face.d.ts +13 -7
  136. package/dist/model-plane-face.js +2 -1
  137. package/dist/observability/fail-open.d.ts +20 -4
  138. package/dist/observability/fail-open.js +17 -4
  139. package/dist/observability/run-terminal.js +4 -0
  140. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  141. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  142. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  143. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  144. package/dist/orchestration/workflow-park-decision.js +5 -3
  145. package/dist/org-delivery-gate.d.ts +11 -0
  146. package/dist/org-delivery-gate.js +19 -1
  147. package/dist/parked-decide.d.ts +13 -9
  148. package/dist/parked-decide.js +7 -7
  149. package/dist/parked-revive-surface.js +1 -1
  150. package/dist/peer-inbound-face.d.ts +127 -0
  151. package/dist/peer-inbound-face.js +158 -0
  152. package/dist/permission-rule-list.d.ts +13 -9
  153. package/dist/permission-rule-list.js +7 -3
  154. package/dist/plugins/approval-ask-store-file.js +18 -6
  155. package/dist/plugins/approval-ask-store-memory.js +8 -6
  156. package/dist/plugins/approval-ask-store-sql.d.ts +28 -13
  157. package/dist/plugins/approval-ask-store-sql.js +30 -11
  158. package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
  159. package/dist/plugins/checkpoint-store-sql.js +9 -7
  160. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  161. package/dist/plugins/file-history-store-sql.js +24 -19
  162. package/dist/plugins/file-run-store.d.ts +29 -0
  163. package/dist/plugins/file-run-store.js +97 -8
  164. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  165. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  166. package/dist/plugins/local-checkpoint-store.d.ts +1 -1
  167. package/dist/plugins/local-checkpoint-store.js +2 -2
  168. package/dist/plugins/local-session-store.d.ts +6 -2
  169. package/dist/plugins/local-session-store.js +8 -2
  170. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  171. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  172. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  173. package/dist/plugins/mailbox-store-sql.js +76 -7
  174. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  175. package/dist/plugins/memory-sync-store-pg.js +21 -0
  176. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  177. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  178. package/dist/plugins/one-time-migrations.d.ts +32 -2
  179. package/dist/plugins/one-time-migrations.js +106 -3
  180. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  181. package/dist/plugins/org-delivery-quota-store.js +2 -12
  182. package/dist/plugins/park-commit-watch.d.ts +1 -1
  183. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  184. package/dist/plugins/permission-rule-store-file.js +15 -2
  185. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  186. package/dist/plugins/permission-rule-store-sql.js +35 -2
  187. package/dist/plugins/remote-env-device.d.ts +8 -11
  188. package/dist/plugins/remote-env-device.js +6 -3
  189. package/dist/plugins/remote-env-k8s.d.ts +37 -24
  190. package/dist/plugins/remote-env-k8s.js +50 -17
  191. package/dist/plugins/retention-store-sql.d.ts +2 -2
  192. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  193. package/dist/plugins/sandbox-read-floor.js +2 -7
  194. package/dist/plugins/sql-errors.d.ts +10 -1
  195. package/dist/plugins/sql-errors.js +13 -0
  196. package/dist/plugins/store-backend.d.ts +23 -28
  197. package/dist/plugins/store-backend.js +9 -1
  198. package/dist/plugins/store-contracts.d.ts +29 -5
  199. package/dist/plugins/store-contracts.js +4 -1
  200. package/dist/plugins/task-attachment-store.d.ts +2 -2
  201. package/dist/plugins/task-attachment-store.js +37 -52
  202. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  203. package/dist/plugins/tool-result-store-sql.js +23 -2
  204. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  205. package/dist/plugins/wiring-section-codec.js +55 -0
  206. package/dist/plugins/workspace-fill.d.ts +1 -1
  207. package/dist/rule-entry-list.d.ts +3 -2
  208. package/dist/rule-entry-list.js +5 -1
  209. package/dist/rules-consent.d.ts +28 -5
  210. package/dist/rules-consent.js +40 -28
  211. package/dist/run-local.js +9 -5
  212. package/dist/runs.d.ts +12 -8
  213. package/dist/runs.js +6 -7
  214. package/dist/runtime-governance.d.ts +1 -1
  215. package/dist/server-secret-env.d.ts +4 -0
  216. package/dist/session-error-wire.d.ts +12 -0
  217. package/dist/session-error-wire.js +6 -0
  218. package/dist/session-incarnation.d.ts +1 -1
  219. package/dist/session-notify-door.d.ts +106 -0
  220. package/dist/session-notify-door.js +93 -0
  221. package/dist/session-sync.d.ts +9 -14
  222. package/dist/session-sync.js +5 -5
  223. package/dist/session-workspace.d.ts +3 -13
  224. package/dist/session-workspace.js +0 -9
  225. package/dist/standing-answer-grant.d.ts +5 -0
  226. package/dist/standing-answer-grant.js +10 -0
  227. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  228. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  229. package/dist/task-mcp.d.ts +1 -1
  230. package/dist/task-settings.d.ts +11 -8
  231. package/dist/task-settings.js +31 -11
  232. package/dist/tool-approval.d.ts +52 -34
  233. package/dist/tool-approval.js +66 -57
  234. package/dist/trace/core-keyset-guard.d.ts +11 -8
  235. package/dist/trace/engine-notice-wire.d.ts +1 -1
  236. package/dist/trace/engine-notice-wire.js +3 -1
  237. package/dist/trace/exit-seat.d.ts +7 -1
  238. package/dist/trace/exit-seat.js +1 -0
  239. package/dist/trace/ledger-sink.d.ts +2 -2
  240. package/dist/trace/model-segment.d.ts +55 -25
  241. package/dist/trace/model-segment.js +101 -33
  242. package/dist/trace/project.d.ts +7 -4
  243. package/dist/trace/project.js +6 -0
  244. package/dist/trace/redact.d.ts +61 -9
  245. package/dist/trace/redact.js +1490 -468
  246. package/dist/trace/self-minted-wire.d.ts +510 -38
  247. package/dist/trace/self-minted-wire.js +165 -17
  248. package/dist/trace/wire-projection-faces.d.ts +1 -1
  249. package/dist/trace/wire-projection-faces.js +1 -1
  250. package/dist/verifier-pause-card.d.ts +33 -5
  251. package/dist/verifier-pause-card.js +15 -10
  252. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  253. package/dist/web-admin-client/apply-effective.js +90 -10
  254. package/dist/workspace-space.d.ts +19 -3
  255. package/dist/workspace-space.js +8 -4
  256. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  257. package/package.json +3 -2
  258. package/wire-changes/server@7.143.0.json +1167 -0
@@ -18,6 +18,7 @@ import { createCenterConfigTier } from "../center-config-tier.js";
18
18
  import { buildCenterCredentialHealthView, createCenterCredentialRenewer } from "../center-credential-renewer.js";
19
19
  import { centerManagedConfigKeys } from "../web-admin-client/apply-effective.js";
20
20
  import { configSourceKind, createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../config-provider.js";
21
+ import { REMOTE_CATALOG_SOURCE } from "../env-model-table-gate.js";
21
22
  import { ConfigDirUntrustedError } from "../config-dir-trust.js";
22
23
  import { createKeyResolver } from "../key-resolver.js";
23
24
  import { buildSealedKeyPublicFace, ensureCheckpointCtxSealing, ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
@@ -55,11 +56,14 @@ export async function createWebAdminRuntime(ctx) {
55
56
  let latestEffective;
56
57
  let candidateRejection;
57
58
  let judgedOrdinal = 0;
58
- const noteCandidateVerdict = (ordinal, rejection) => {
59
+ let arrivalSeq = 0;
60
+ const admitArrival = (ordinal, rejection) => {
59
61
  if (ordinal < judgedOrdinal)
60
- return;
62
+ return { seq: undefined };
61
63
  judgedOrdinal = ordinal;
62
64
  candidateRejection = rejection;
65
+ arrivalSeq += 1;
66
+ return { seq: arrivalSeq };
63
67
  };
64
68
  const applyLedger = createConfigApplyLedger();
65
69
  let lastPull = "none";
@@ -88,6 +92,7 @@ export async function createWebAdminRuntime(ctx) {
88
92
  let bootSkillStale = false;
89
93
  let pendingRestart;
90
94
  let modelRefusals;
95
+ let modelRefusalsArrival;
91
96
  const cc = config.webAdmin;
92
97
  const bootCredential = cc?.credential.read();
93
98
  const bootVerdict = bootCredential === undefined ? undefined : judgeCenterCredentialAtBoot(bootCredential);
@@ -208,7 +213,7 @@ export async function createWebAdminRuntime(ctx) {
208
213
  const domains = verdict.domains.join(",");
209
214
  if (candidateRejection?.version === r.effective.version && candidateRejection.domains.join(",") === domains)
210
215
  return;
211
- noteCandidateVerdict(ordinal, candidateRejectionOf(r, verdict, candidateSource().kind, Date.now()));
216
+ admitArrival(ordinal, candidateRejectionOf(r, verdict, candidateSource().kind, Date.now()));
212
217
  logger.warn("config_candidate_rejected", buildCandidateRejectedFields(r, verdict, leg, { lkgVersion: latestEffective?.version ?? "(env)", ...localDirField }));
213
218
  };
214
219
  const noteSourceAtApplied = () => {
@@ -217,7 +222,7 @@ export async function createWebAdminRuntime(ctx) {
217
222
  if (rejected === undefined || rejected.version === appliedVersion)
218
223
  return;
219
224
  const gen = generationOf(appliedVersion);
220
- noteCandidateVerdict(gen, undefined);
225
+ admitArrival(gen, undefined);
221
226
  if (!cc?.dryRun)
222
227
  applyLedger.applied(gen, appliedVersion);
223
228
  logger.info("config_source_back_to_applied", {
@@ -258,8 +263,9 @@ export async function createWebAdminRuntime(ctx) {
258
263
  if (!same)
259
264
  notifySelfReport("model_refusals");
260
265
  };
261
- const recordApply = (rep) => {
266
+ const recordApply = (rep, ticket) => {
262
267
  applyLedger.recordApply(rep);
268
+ modelRefusalsArrival = ticket.seq;
263
269
  publishModelRefusals(buildModelRefusalsSignal(rep.modelRefusals));
264
270
  };
265
271
  let adoptedArtifact;
@@ -518,19 +524,21 @@ export async function createWebAdminRuntime(ctx) {
518
524
  const lkgEffective = read.lkg.effective;
519
525
  candidateIdentity.set(lkgEffective, identity);
520
526
  bindValidator(read.lkg.etag, identity);
521
- return { effective: lkgEffective, ...(read.lkg.etag !== undefined ? { etag: read.lkg.etag } : {}), prompts: read.prompts };
527
+ return { effective: lkgEffective, ...(read.lkg.etag !== undefined ? { etag: read.lkg.etag } : {}), prompts: read.prompts, catalogSource: REMOTE_CATALOG_SOURCE };
522
528
  };
523
529
  const bootApplyLkgInline = async (lkgR) => {
524
530
  const lkgGen = generationOf(lkgR.effective.version);
525
531
  applyLedger.seenTarget(lkgGen, lkgR.effective.version);
532
+ const lkgArrival = admitArrival(lkgGen, undefined);
526
533
  let lkgReport;
527
534
  applyEffective(config, lkgR.effective, logger, {
528
535
  leg: "boot",
536
+ catalogSource: lkgR.catalogSource,
529
537
  sealedKeys,
530
538
  generation: lkgGen,
531
539
  report: (rep) => {
532
540
  lkgReport = rep;
533
- recordApply(rep);
541
+ recordApply(rep, lkgArrival);
534
542
  },
535
543
  });
536
544
  const lkgIdentity = candidateIdentityOf(lkgR.effective);
@@ -613,7 +621,7 @@ export async function createWebAdminRuntime(ctx) {
613
621
  }
614
622
  else {
615
623
  warnReadNotices(r, "boot");
616
- logEffectiveDiff(config, r.effective, logger);
624
+ logEffectiveDiff(config, r.effective, r.catalogSource, logger);
617
625
  ccEtag = r.etag;
618
626
  }
619
627
  }
@@ -631,14 +639,16 @@ export async function createWebAdminRuntime(ctx) {
631
639
  warnReadNotices(r, "boot");
632
640
  const bootGen = generationOf(r.effective.version);
633
641
  applyLedger.seenTarget(bootGen, r.effective.version);
642
+ const bootArrival = admitArrival(bootGen, undefined);
634
643
  let bootReport;
635
644
  applyEffective(config, r.effective, logger, {
636
645
  leg: "boot",
646
+ catalogSource: r.catalogSource,
637
647
  sealedKeys,
638
648
  generation: bootGen,
639
649
  report: (rep) => {
640
650
  bootReport = rep;
641
- recordApply(rep);
651
+ recordApply(rep, bootArrival);
642
652
  },
643
653
  });
644
654
  markApplied(bootGen, r.effective);
@@ -651,7 +661,7 @@ export async function createWebAdminRuntime(ctx) {
651
661
  const lkgPlane = await bootFromLkg("boot candidate's model plane was refused", "model-plane");
652
662
  if (lkgPlane) {
653
663
  let planeReport;
654
- applyEffective(config, withModelPlaneOf(r.effective, lkgPlane.effective), logger, { leg: "boot", sealedKeys, generation: bootGen, report: (rep) => (planeReport = rep) });
664
+ applyEffective(config, withModelPlaneOf(r.effective, lkgPlane.effective), logger, { leg: "boot", catalogSource: lkgPlane.catalogSource, sealedKeys, generation: bootGen, report: (rep) => (planeReport = rep) });
655
665
  if (modelPlaneCommitted(planeReport)) {
656
666
  bootPlaneEff = lkgPlane.effective;
657
667
  logger.warn("config_model_plane_from_lkg", { version: r.effective.version, lkgVersion: lkgPlane.effective.version, note: "the live candidate's model plane was refused at boot — serving the LKG's model plane (the catalog and what rides with it) with the live candidate's other groups; the refresh cadence re-judges the candidate" });
@@ -746,6 +756,7 @@ export async function createWebAdminRuntime(ctx) {
746
756
  restartState: () => buildRestartSignal(pendingRestart, planeDeferredNoHandoff),
747
757
  configHandoffState: () => (configProvider === undefined || configProvider.kind === "local" || !lkgSurvivesRestart ? undefined : buildConfigHandoff(latchHandoff(), handoffMissingSince)),
748
758
  modelRefusalsState: () => modelRefusals,
759
+ latestPlaneRefusalState: () => (modelRefusals?.plane !== undefined && modelRefusalsArrival !== undefined && modelRefusalsArrival === arrivalSeq ? modelRefusals.plane : undefined),
749
760
  candidateRejectionState: () => (cc?.dryRun ? undefined : candidateRejection),
750
761
  configApplyState: () => (configProvider ? applyLedger.view() : undefined),
751
762
  centerPullState: () => {
@@ -905,11 +916,12 @@ export async function createWebAdminRuntime(ctx) {
905
916
  const committed = applyEffective(config, eff, logger, {
906
917
  leg: "hot",
907
918
  checkpointStorePresent,
919
+ catalogSource: c.catalogSource,
908
920
  sealedKeys,
909
921
  generation: gen,
910
922
  report: (rep) => {
911
923
  report = rep;
912
- recordApply(rep);
924
+ recordApply(rep, c.arrival);
913
925
  },
914
926
  ...(planeChanged ? { swapPlane: swapRunnerDeps } : {}),
915
927
  });
@@ -937,14 +949,14 @@ export async function createWebAdminRuntime(ctx) {
937
949
  const demoteToNoCenter = async (awaiting) => {
938
950
  const gen = reserveArrivalGeneration();
939
951
  applyLedger.seenTarget(gen, NO_CENTER_EFFECTIVE.version);
940
- const hot = await commitHot({ eff: NO_CENTER_EFFECTIVE, prompts: undefined, gen, phase: "no-center" });
952
+ const arrival = admitArrival(gen, undefined);
953
+ const hot = await commitHot({ eff: NO_CENTER_EFFECTIVE, catalogSource: REMOTE_CATALOG_SOURCE, prompts: undefined, gen, arrival, phase: "no-center" });
941
954
  if (!hot.committed) {
942
955
  throw new Error("the no-center tier was refused (the Runners did not accept the env model table) — the previous account's center configuration is still in force; retried next tick");
943
956
  }
944
957
  if (hot.report !== undefined && !hot.report.fullyApplied) {
945
958
  logger.warn("center_identity_demotion_partial", { groups: refusedGroups(hot.report).map((g) => g.group), note: "a group of the no-center tier was refused — that group keeps its previous values (loud; the env base for that group could not be applied)" });
946
959
  }
947
- noteCandidateVerdict(gen, undefined);
948
960
  latestEffective = undefined;
949
961
  ccEtag = undefined;
950
962
  announceTier(tier.demote(awaiting, hot.report !== undefined ? refusedGroups(hot.report).map((g) => g.group) : []));
@@ -1013,14 +1025,14 @@ export async function createWebAdminRuntime(ctx) {
1013
1025
  announceCandidateRejected(r, verdict, arrival !== undefined ? "late-boot" : "refresh", tickGen);
1014
1026
  return "ok";
1015
1027
  }
1016
- noteCandidateVerdict(tickGen, undefined);
1028
+ const tickArrival = admitArrival(tickGen, undefined);
1017
1029
  warnReadNotices(r, "refresh");
1018
1030
  if (ccRef?.dryRun) {
1019
- logEffectiveDiff(config, r.effective, logger);
1031
+ logEffectiveDiff(config, r.effective, r.catalogSource, logger);
1020
1032
  ccEtag = r.etag;
1021
1033
  }
1022
1034
  else {
1023
- const hot = await commitHot({ eff: r.effective, prompts: verdict.prompts, gen: tickGen, phase: "refresh" });
1035
+ const hot = await commitHot({ eff: r.effective, catalogSource: r.catalogSource, prompts: verdict.prompts, gen: tickGen, arrival: tickArrival, phase: "refresh" });
1024
1036
  if (!hot.committed)
1025
1037
  return "ok";
1026
1038
  const applyReport = hot.report;
@@ -1127,14 +1139,14 @@ export async function createWebAdminRuntime(ctx) {
1127
1139
  announceCandidateRejected(r, lateVerdict, "late-boot", lateGen);
1128
1140
  return;
1129
1141
  }
1130
- noteCandidateVerdict(lateGen, undefined);
1142
+ const lateArrival = admitArrival(lateGen, undefined);
1131
1143
  warnReadNotices(r, "boot-deferred");
1132
1144
  if (ccRef?.dryRun) {
1133
- logEffectiveDiff(config, r.effective, logger);
1145
+ logEffectiveDiff(config, r.effective, r.catalogSource, logger);
1134
1146
  ccEtag = r.etag;
1135
1147
  return;
1136
1148
  }
1137
- const hotLate = await commitHot({ eff: r.effective, prompts: lateVerdict.prompts, gen: lateGen, phase: "boot-deferred" });
1149
+ const hotLate = await commitHot({ eff: r.effective, catalogSource: r.catalogSource, prompts: lateVerdict.prompts, gen: lateGen, arrival: lateArrival, phase: "boot-deferred" });
1138
1150
  if (!hotLate.committed)
1139
1151
  return;
1140
1152
  const applyReportLate = hotLate.report;
@@ -12,8 +12,8 @@
12
12
  * 不是静默继承 full(词表闭集纪律)。
13
13
  * ② {@link HANDS_EXCLUSIVE_TOOL_NAMES} + {@link handsDenyPolicy} —— 纵深:hands=none 的任务即便被误接到
14
14
  * 有手 Runner 上,手独占名单逐一 deny。**不是**主保证(主保证是根本不挂 factory ⇒ 工具面不可见)。
15
- * ③ {@link stampHandsLane} / {@link handsLaneOf} —— 车道作为 TaskSpec 上的**显式字段**([ref]):
16
- * resolveSpec 出口铸一次,执行点读一次,**缺席即拒**(不是回落最宽车道)。
15
+ * ③ {@link createHandsRunnerSelector} —— 车道是这条腿的部署事实(`leg-facts.ts`:装配器出口铸一次,两只漏斗以装配输出调选路器时读一次),
16
+ * **缺席即拒**(不是回落最宽车道)。
17
17
  */
18
18
  import { type Runner, type TaskSpec, type ToolPolicy } from "@sema-agent/core";
19
19
  /** 场景对手带工具面的表态(闭集)。`full` = core 手带 band 照常 mount;`none` = 不挂 executionEnvFactory 的 Runner。 */
@@ -114,32 +114,7 @@ export declare function tightenWithHandsDeny(base: ToolPolicy | undefined): Tool
114
114
  /** 装配点的取用形:`full` 原样放行基线,`none` 叠 deny。**穷举 switch**,无缺省臂。 */
115
115
  export declare function toolPolicyForHands(hands: ScenarioHands, base: ToolPolicy | undefined): ToolPolicy | undefined;
116
116
  /**
117
- * 执行车道在 TaskSpec 上的**显式字段键**([ref];修前是一张以 spec **对象身份**为键的 WeakMap 旁表)。
118
- *
119
- * 为什么是 symbol 而不是字符串键:`TaskSpec` 是**上游 core 的类型面**,一个字符串键会进
120
- * `Object.keys` / `JSON.stringify` / core 自己的键审计,等于 server 在别人的契约上私自加一个键;
121
- * symbol 键随 spread(`{...spec}`)与 rest 解构(`const {objective, ...taskConfig} = spec`)结构性
122
- * 地跟着走,却对上游的键面**不可见**(结构化克隆与 JSON 同样跳过 symbol 键)。于是「车道是 spec 上
123
- * 的一个字段、复制 spec 不丢车道」与「不污染上游契约」两件事同时成立。
124
- *
125
- * 修前的旁表要求「从 resolveSpec 出来的那一只对象必须一路原样活到执行点」——一条**隐形**的对象身份
126
- * 契约:任何一次 `{...spec}` 都会静默把车道降级成最宽的 `full`(实测:登记 `none` 的 spec 复制后
127
- * `laneOf` 答 `full`)。字段化把那条隐形要求整条删掉。
128
- */
129
- export declare const HANDS_LANE_FIELD: unique symbol;
130
- /** 已铸车道的 TaskSpec。铸点唯一(`boot/resolve-spec.ts` 的 resolveSpec 出口),读点唯一({@link handsLaneOf})。 */
131
- export type LanedTaskSpec = TaskSpec & {
132
- readonly [HANDS_LANE_FIELD]: ScenarioHands;
133
- };
134
- /**
135
- * 铸车道(**单一属主**:只允许 resolveSpec 的出口调用)。
136
- *
137
- * 字段是 `enumerable`(所以复制得走)、`writable:false` + `configurable:false`(所以同一只 spec 被
138
- * 第二次铸车道会当场 TypeError —— 两个写者是漂移的成因,响亮好过后到者悄悄赢)。
139
- */
140
- export declare function stampHandsLane<T extends TaskSpec>(spec: T, hands: ScenarioHands): T & LanedTaskSpec;
141
- /**
142
- * 车道字段缺席的拒因 —— 具名类,便于调用点/测试按类型判,而不是嗅文案。
117
+ * 车道读不到的拒因 —— 具名类,便于调用点/测试按类型判,而不是嗅文案。
143
118
  *
144
119
  * 🔴 **刻意不是 `HttpError`、刻意不铸新的 wire 错误码**:它落到 `http/server.ts` 的兜底 catch,
145
120
  * wire 上是 500 `internal.error`(内部文本不回显,只进 `request_error` 日志行)。理由两条:
@@ -153,19 +128,14 @@ export declare class HandsLaneUnstampedError extends Error {
153
128
  constructor();
154
129
  }
155
130
  /**
156
- * 读车道 —— **缺席即拒**([ref] P 类:车道选择是保护型量,fail-closed;`observability/fail-open.ts`
157
- * 头注把「车道选择」逐字列在「正解是 fail-closed,不是留痕后继续放行」那一族里)。
131
+ * 装配点的选路席:`{full, handsless}` 两只 Runner + 这条腿的车道 ⇒ 本任务跑哪一只。公共缝 `runnerFor(spec)` 的生产实现;
132
+ * 两只漏斗(受理 / 续跑)以**装配器输出的那一只对象**调它(`leg-facts.ts`:读在 `stampSpecRoot` 复制之前)。
158
133
  *
159
- * 修前此处是 `?? "full"`:一只没经过本仓 resolver 的 spec 会**静默拿到最宽的车道**(全量可写手带)。
160
- * 「唯一可达形是测试桩」这个论证不是防线 —— 它是一句关于今天调用图的断言,而防线要防的正是明天多出
161
- * 来的第二个执行点。缺席现在整只拒(500 + 日志留原句),而不是把一个未经裁定的任务放进有手车道。
162
- */
163
- export declare function handsLaneOf(spec: TaskSpec): ScenarioHands;
164
- /**
165
- * 装配点的选路席:`{full, handsless}` 两只 Runner + 车道字段 ⇒ 本任务跑哪一只。
134
+ * 车道读不到 ⇒ **缺席即拒**([ref] P 类:车道选择是保护型量,fail-closed;`observability/fail-open.ts` 头注把「车道选择」逐字列在
135
+ * 「正解是 fail-closed,不是留痕后继续放行」那一族里)。读不到的两种来路:嵌入方自带的 `resolveSpec`(不铸本仓的腿事实),
136
+ * 或有人把复制品交了进来(读晚了)—— 都整只拒(500 + 日志留原句),绝不把一个未经裁定的任务放进最宽的有手车道。
166
137
  *
167
- * 具名工厂而不是在 main.ts 手搓闭包:选路规则(读字段 → 穷举 switch)于是只有**一份实现**,
168
- * 测试与生产装配拿的是同一只(手搓等价闭包 = 第二真源,正是本件要删的那一类)。
138
+ * 具名工厂而不是在 main.ts 手搓闭包:选路规则(读车道 → 穷举 switch)于是只有**一份实现**,测试与生产装配拿的是同一只。
169
139
  */
170
140
  export declare function createHandsRunnerSelector(pair: HandsRunnerPair): (spec: TaskSpec) => Runner;
171
141
  //# sourceMappingURL=hands-lane.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { handBandEffects, judgeRuleToolName, combinePolicies, createAllowDenyPolicy } from "@sema-agent/core";
2
+ import { legFactsOf } from "../leg-facts.js";
2
3
  import { TOOL_NAME_ROSTER } from "../namespaced-rule-name.js";
3
4
  export function withoutHands(deps) {
4
5
  const { executionEnvFactory: _handsDropped, ...rest } = deps;
@@ -29,7 +30,7 @@ export const HANDS_BAND_TOOL_NAMES = Object.freeze([
29
30
  "ExitWorktree",
30
31
  "ListAgents",
31
32
  ].filter((n, i, all) => judgeRuleToolName(n, TOOL_NAME_ROSTER).kind === "current" && all.indexOf(n) === i));
32
- export const HANDS_DUAL_USE_TOOL_NAMES = Object.freeze(["TaskOutput", "TaskStop", "SendMessage", "AgentTranscript", "ListAgents"]);
33
+ export const HANDS_DUAL_USE_TOOL_NAMES = Object.freeze(["TaskStop", "SendMessage", "AgentTranscript", "ListAgents"]);
33
34
  export const HANDS_EXCLUSIVE_TOOL_NAMES = Object.freeze(HANDS_BAND_TOOL_NAMES.filter((n) => !HANDS_DUAL_USE_TOOL_NAMES.includes(n)));
34
35
  export const OFFICE_KEPT_HAND_TOOL_NAMES = Object.freeze(["Read", "Glob", "Grep"]);
35
36
  export const OFFICE_EXCLUDED_TOOL_NAMES = Object.freeze(HANDS_EXCLUSIVE_TOOL_NAMES.filter((n) => !OFFICE_KEPT_HAND_TOOL_NAMES.includes(n)));
@@ -48,24 +49,18 @@ export function toolPolicyForHands(hands, base) {
48
49
  return tightenWithHandsDeny(base);
49
50
  }
50
51
  }
51
- export const HANDS_LANE_FIELD = Symbol("sema-server.handsLane");
52
- export function stampHandsLane(spec, hands) {
53
- Object.defineProperty(spec, HANDS_LANE_FIELD, { value: hands, enumerable: true, writable: false, configurable: false });
54
- return spec;
55
- }
56
52
  export class HandsLaneUnstampedError extends Error {
57
53
  constructor() {
58
54
  super("execution lane is not stamped on this task spec — refusing to run it rather than falling back to the widest (full-hands) lane");
59
55
  this.name = "HandsLaneUnstampedError";
60
56
  }
61
57
  }
62
- export function handsLaneOf(spec) {
63
- const lane = spec[HANDS_LANE_FIELD];
64
- if (lane === undefined)
65
- throw new HandsLaneUnstampedError();
66
- return lane;
67
- }
68
58
  export function createHandsRunnerSelector(pair) {
69
- return (spec) => pickHandsRunner(handsLaneOf(spec), pair);
59
+ return (spec) => {
60
+ const hands = legFactsOf(spec)?.hands;
61
+ if (hands === undefined)
62
+ throw new HandsLaneUnstampedError();
63
+ return pickHandsRunner(hands, pair);
64
+ };
70
65
  }
71
66
  //# sourceMappingURL=hands-lane.js.map
@@ -354,8 +354,9 @@ export declare function buildMcpProbeInflightRefusal(): McpProbeRefusal;
354
354
  * 在任何传输被触碰**之前**就被拒)。
355
355
  *
356
356
  * 异源复核 [medium]:修前这一形在两条口上都被抛给分派器尾 ⇒ `500 internal.error`。可自带申报那一口的申报
357
- * 是**调用方**写的,把它答成 500 是把调用方的错说成这台机器故障;中心申报那一口反过来 —— 那是部署方写的,
358
- * 5xx 才是对的方向。⇒ 一条规则:**谁写的申报,谁的错**。
357
+ * 是**调用方**写的,把它答成 500 是把调用方的错说成这台机器故障 ⇒ 自带申报那一口答 400 `request.field_invalid`(本句)。
358
+ * 中心申报那一口**不走本句**:那是部署方写的、部署上挂不起来,引擎的拒按同步提交腿读的同一张「码 → 状态」表读成应答
359
+ * (409 `config.mcp_server_name_collision` + 引擎原句,`http/engine-refusal.ts`),与同一份声明集在提交腿上的答复同码同状态同句。
359
360
  *
360
361
  * 🔴 **不回显因由**:那句话来自申报集本身,可能带调用方的内情(名字、地址形)。调用方手里有自己的体,
361
362
  * 点名「两台撞了命名空间」就够他自己找;原文留在那一层的日志里。
@@ -5,6 +5,7 @@ import { type RepoReadClient } from "./repo-tools.js";
5
5
  import { type LoadedSkill, type RunSkillEntry, type ScenarioSkillEntry, type SkillSource } from "./skills.js";
6
6
  import { type ScenarioHands } from "./hands-lane.js";
7
7
  import type { DelegationRootWitness } from "../delegated-session-owner.js";
8
+ import type { BackgroundCompletionSinkFor } from "../session-notify-door.js";
8
9
  /**
9
10
  * Scenario routing — a deployment serves many scenarios from one image. Each request's `scenario`
10
11
  * selects a pre-wired capability bundle: tools (incl. subagent roster) + its prompt seats + skills.
@@ -85,7 +86,8 @@ export interface ScenarioContext {
85
86
  /**
86
87
  * [ref] / [ref]:**委派树根的见证**(停驻挂点的属主来源)—— 根会话 id + 调用方判断那一刻读到的根行住客(`delegated-session-owner.ts` 的 `DelegationRootWitness`)。
87
88
  * 由**每一个**接了停驻挂点的取用方显式交出(一条读法,没有回落):请求腿 = 本请求经鉴权解析的会话与受理时那一读(`boot/resolve-spec.ts`);`/decide` 赎回面 = 行上的
88
- * `rootSessionId` 与赎回腿写口放行的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它**只**喂停驻挂点,不挂任何会话级设施(那是 {@link sessionId} 的事,
89
+ * `rootSessionId` 与赎回腿写口放行的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它喂停驻挂点与 Runner 之外的后台子代完成 relay(会话通知门的目标住客:属主与化身),
90
+ * 不挂任何会话级设施(那是 {@link sessionId} 的事,
89
91
  * 判据是「这只 bundle 是不是在那只会话上取用的」,与属主来源是两个独立判据)。缺席 = 没有根可交(boot 期探针、run-local、行上没有根)⇒ 律给哨兵。
90
92
  * 挂点在停驻那一刻再读一次根行:住客不是见证的那一位(删了、同 id 被重新登记)⇒ 停驻否决 —— 不按新住客认领。
91
93
  */
@@ -157,6 +159,14 @@ export interface ScenarioDeps {
157
159
  * 停驻都经它(子代沿用父的委派工具实例)。
158
160
  */
159
161
  ensureChildSessionDurable?: (sessionId: string, root: DelegationRootWitness | undefined) => Promise<void>;
162
+ /**
163
+ * **Runner 之外的后台子代完成**交给哪里 —— 按委派树根见证({@link ScenarioContext.delegationRoot})造委派工具挂载期的 `background.notify`。
164
+ * 停驻赎回腿的复活、操作员 `handle.resume` 都不是哪一次 run 内的调用,没有调用车道;引擎只在能解出一只完成 sink(调用 ?? 挂载)时才起后台续跑,
165
+ * 解不出 ⇒ 拒(`revive.no_background`)。sink = 委派树根会话的会话通知门(`session-notify-door.ts` 的 `createBackgroundCompletionRelay`;律与地址、
166
+ * 竞态、条目形都写在那里)。Runner 之内的调用照旧走调用车道,这只 sink 不被调。缺席(没有门的装配:run-local)⇒ 不接 ——
167
+ * 不接一只空 sink(接了 = 引擎起续跑、完成没人收)。
168
+ */
169
+ backgroundCompletionSinkFor?: BackgroundCompletionSinkFor;
160
170
  /**
161
171
  * [ref]([ref] F2 症状 → [ref] 定谳):**会话级**任务清单店解析器,属主 =
162
172
  * `boot/task-list-lane.ts` 的 {@link import("../boot/task-list-lane.js").createTaskListLane}
@@ -59,6 +59,7 @@ export function buildScenarios(deps) {
59
59
  ...(deps.backgroundAgentStore ? { agentStore: deps.backgroundAgentStore } : {}),
60
60
  ...(deps.checkpointStore ? { checkpointStore: deps.checkpointStore } : {}),
61
61
  ...(ensureChildSessionDurable !== undefined ? { ensureChildSessionDurable: (childSessionId) => ensureChildSessionDurable(childSessionId, delegationRoot) } : {}),
62
+ ...(deps.backgroundCompletionSinkFor !== undefined && delegationRoot !== undefined ? { notify: deps.backgroundCompletionSinkFor(delegationRoot) } : {}),
62
63
  },
63
64
  ...createSubagentExtraTools(deps.subagentExtraTools),
64
65
  ...(deps.logger
@@ -1,4 +1,4 @@
1
- import type { SkillSpec, TaskSpec } from "@sema-agent/core";
1
+ import type { SkillSpec } from "@sema-agent/core";
2
2
  import type { RemoteExecProvider } from "../execution-lane-caps.js";
3
3
  import { type Logger } from "../observability/logger.js";
4
4
  /**
@@ -105,22 +105,6 @@ export type ScenarioSkillEntry = SkillListEntry<SkillSource>;
105
105
  export type RunSkillSource = SkillSource | "request";
106
106
  /** run 级名册的一条(`wiring_manifest.skills[]`)。铸点唯一:`capabilities/scenarios.ts` 的 `buildRunSkills`。 */
107
107
  export type RunSkillEntry = SkillListEntry<RunSkillSource>;
108
- /**
109
- * run 级技能名册在 TaskSpec 上的**显式字段键** —— 与执行车道字段(`hands-lane.ts` 的 `HANDS_LANE_FIELD`,[ref])同一形:symbol 键随
110
- * spread / rest 解构走(续跑腿的 `taskConfig` 就是 rest 解构出来的),对上游 core 的键面不可见(JSON / 结构化克隆跳过 symbol 键)。
111
- * 铸点唯一 = `boot/resolve-spec.ts` 的 resolveSpec 出口({@link stampRunSkills});读点唯一 = {@link runSkillsOf}(每条投 `wiring_manifest` 的腿)。
112
- */
113
- export declare const RUN_SKILLS_FIELD: unique symbol;
114
- /**
115
- * 铸名册(**单一属主**:只许 resolveSpec 的出口调用)。字段 `enumerable`(复制得走)、`writable:false` + `configurable:false`(同一只 spec 被第二次铸 ⇒
116
- * 当场 TypeError,两个写者是漂移的成因)。名册冻结一份拷贝(spec 与腿不共享可变引用)。
117
- */
118
- export declare function stampRunSkills<T extends TaskSpec>(spec: T, roster: readonly RunSkillEntry[]): T;
119
- /**
120
- * 读名册。`undefined` = 这只 spec 不是本仓装配出口产的(嵌入方自写 `resolveSpec` / 测试桩)⇒ 腿上没有关于技能的陈述(段缺席)。
121
- * 不是保护型量(缺席只少一段披露,不放宽任何东西)⇒ 缺席照常跑,与车道字段的「缺席即拒」不同。入参收 `object`:续跑腿手里是 rest 解构出来的 taskConfig。
122
- */
123
- export declare function runSkillsOf(spec: object): readonly RunSkillEntry[] | undefined;
124
108
  /** 一个技能范围的卡上清单 —— 与 {@link skillsForScenario} 同一只过滤、同一个序,只是投影不同。 */
125
109
  export declare function scenarioSkillEntries(loaded: readonly LoadedSkill[], scope: string): ScenarioSkillEntry[];
126
110
  /** {@link parseFrontmatter} 的三种读数(闭集):`absent` = 第一行不是围栏,没有 frontmatter(正当的全局技能)· `block` = 围栏收好了的块 · `unclosed` = 第一行是围栏而块没收好(读不了 —— 调用方拒载)。 */
@@ -127,14 +127,6 @@ function skillsInScope(loaded, scope) {
127
127
  export function skillsForScenario(loaded, scope) {
128
128
  return skillsInScope(loaded, scope).map((k) => k.spec);
129
129
  }
130
- export const RUN_SKILLS_FIELD = Symbol("sema-server.runSkills");
131
- export function stampRunSkills(spec, roster) {
132
- Object.defineProperty(spec, RUN_SKILLS_FIELD, { value: Object.freeze(roster.map((e) => Object.freeze({ ...e }))), enumerable: true, writable: false, configurable: false });
133
- return spec;
134
- }
135
- export function runSkillsOf(spec) {
136
- return spec[RUN_SKILLS_FIELD];
137
- }
138
130
  export function scenarioSkillEntries(loaded, scope) {
139
131
  return skillsInScope(loaded, scope).map((k) => ({ name: k.spec.name, description: k.spec.description, source: k.source }));
140
132
  }
@@ -21,9 +21,8 @@
21
21
  import type { FlatServiceDeps } from "./http/server.js";
22
22
  import type { ServiceConfig } from "./config.js";
23
23
  import type { OwnerAwareSessionStore } from "./security.js";
24
- import type { ServiceFileHistoryStore } from "./plugins/store-backend.js";
24
+ import type { ServiceBlobExchange, ServiceFileHistoryStore } from "./plugins/store-backend.js";
25
25
  import { resolveStreamApprovalGate, type ApprovalFrameFamily } from "./tool-approval.js";
26
- import { type SyncBlobHistoryStore } from "./session-sync.js";
27
26
  import { type WorkspaceSyncCapability } from "./workspace-space.js";
28
27
  import type { WorkspaceCacheCapability } from "./workspace-cache.js";
29
28
  /** why 闭集:词 → 给运维看的一句义(诊断 / 测试读它;wire 上的拒句由各门自写)。 */
@@ -47,7 +46,7 @@ export declare const CAPABILITY_FACT_WHY: {
47
46
  readonly session_export_absent: "the session store has no entry export faces (exportEntries / exportEntriesStream)";
48
47
  readonly session_import_staging_absent: "the session store has no staged-import face (beginImportStaging)";
49
48
  readonly policy_purge_absent: "the session policy store has no deleteBySession purge verb";
50
- readonly sync_blob_faces_absent: "the file-history store has no blob transfer faces (SQL backends only)";
49
+ readonly blob_exchange_absent: "the file-history store carries no blob exchange (FileHistoryStore.blobExchange — SQL backends only)";
51
50
  readonly device_hub_absent: "the device lane hub is not wired";
52
51
  readonly device_store_absent: "the device store is not wired";
53
52
  readonly device_enrollment_absent: "device enrollment is not wired";
@@ -193,10 +192,11 @@ export declare function sessionSync(d: Pick<Deps, "backend" | "sessionStorage" |
193
192
  sessionStorage: SyncSessionStore;
194
193
  historyStore: ServiceFileHistoryStore;
195
194
  }>;
196
- /** 会话同步的**文件历史半族**:对话半族 ∧ 文件历史店有 blob 搬运面(只有 SQL 两只店有)。「店有没有 blob 两面」只在 `syncBlobFacesOf` 判一次(marker 门,不做名字探测),
197
- * blob 取值口 `blobGetterOf` 读的是同一只 —— 本事实为真 ⟺ 取值口通到 `historyStore.getBlob`。 */
198
- export declare function sessionSyncFileHistory(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy | "sync_blob_faces_absent", {
199
- historyStore: SyncBlobHistoryStore;
195
+ /** 会话同步的**文件历史半族**:对话半族 ∧ 文件历史店带 blob 交换组(只有 SQL 两只店有)。「店能不能交换 blob」只在 `blobExchangeOf` 判一次(core 判官),
196
+ * blob 取值口 `blobGetterOf` 读的是同一只 —— 本事实为真 ⟺ 取值口通到 `blobExchange.get`;判过的组随事实交出,路由的 GET / PUT / 在场预检只读它。 */
197
+ export declare function sessionSyncFileHistory(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy | "blob_exchange_absent", {
198
+ historyStore: ServiceFileHistoryStore;
199
+ blobExchange: ServiceBlobExchange;
200
200
  }>;
201
201
  /** 持久审批底座(checkpoint 店)在场 —— `/v1/approvals/*` 与 `/v1/assistant/*` 整条车道、会话 wake 都站在它上面。 */
202
202
  export declare function checkpointPark(d: Pick<Deps, "checkpointStore">): Fact<"checkpoint_store_absent", {
@@ -280,7 +280,7 @@ export declare function memoryExport(d: Pick<Deps, "memoryExport">): Fact<"memor
280
280
  read: Store<"memoryExport">;
281
281
  }>;
282
282
  /**
283
- * 中心侧同步口(`POST /v1/memory/sync/:scope`):DB 记忆平面的同步执行位在场 ∧ 本中心声明了同步身份(`MEMORY_SYNC_SERVE_IDENTITY`)。
283
+ * 中心侧同步口(`POST /v2/memory/sync/:scope`):DB 记忆平面的同步执行位在场 ∧ 本中心声明了同步身份(`MEMORY_SYNC_SERVE_IDENTITY`)。
284
284
  * 见证 = 执行位 + 那份声明 —— 能力位 `memorySyncServe` 的 `{ identity }` 逐字投影它,入站 `peer` 与它按串比:一处声明,两个读者读同一个值。
285
285
  */
286
286
  export declare function memorySyncServe(d: Pick<Deps, "memorySync" | "config">): Fact<"memory_db_plane_absent" | "memory_sync_identity_undeclared", {
@@ -4,7 +4,7 @@ import { DEPLOYMENT_SHAPE_PREDICATES } from "./deployment-shape.js";
4
4
  import { presentedApprovalFrameFamily, resolveStreamApprovalGate } from "./tool-approval.js";
5
5
  import { selfOrchestrationDenial } from "./task-workflow.js";
6
6
  import { centerEntitlementSourceWired } from "./runtime-caps-resolver.js";
7
- import { overwriteWipeIncapable, syncBlobFacesOf } from "./session-sync.js";
7
+ import { blobExchangeOf, overwriteWipeIncapable } from "./session-sync.js";
8
8
  import { WORKSPACE_PERSIST_DEFAULT, WORKSPACE_SNAPSHOT_KEEP_DEFAULT, workspaceSnapshotTimeoutOf } from "./workspace-space.js";
9
9
  import { headReadOf } from "./session-incarnation.js";
10
10
  export const CAPABILITY_FACT_WHY = {
@@ -27,7 +27,7 @@ export const CAPABILITY_FACT_WHY = {
27
27
  session_export_absent: "the session store has no entry export faces (exportEntries / exportEntriesStream)",
28
28
  session_import_staging_absent: "the session store has no staged-import face (beginImportStaging)",
29
29
  policy_purge_absent: "the session policy store has no deleteBySession purge verb",
30
- sync_blob_faces_absent: "the file-history store has no blob transfer faces (SQL backends only)",
30
+ blob_exchange_absent: "the file-history store carries no blob exchange (FileHistoryStore.blobExchange — SQL backends only)",
31
31
  device_hub_absent: "the device lane hub is not wired",
32
32
  device_store_absent: "the device store is not wired",
33
33
  device_enrollment_absent: "device enrollment is not wired",
@@ -190,8 +190,8 @@ export function sessionSyncFileHistory(d) {
190
190
  const sync = sessionSync(d);
191
191
  if (!sync.available)
192
192
  return sync;
193
- const faces = syncBlobFacesOf(sync.historyStore);
194
- return faces !== undefined ? yes({ historyStore: faces }) : no("sync_blob_faces_absent");
193
+ const blobExchange = blobExchangeOf(sync.historyStore);
194
+ return blobExchange !== undefined ? yes({ historyStore: sync.historyStore, blobExchange }) : no("blob_exchange_absent");
195
195
  }
196
196
  export function checkpointPark(d) {
197
197
  return d.checkpointStore !== undefined ? yes({ checkpointStore: d.checkpointStore }) : no("checkpoint_store_absent");
@@ -1,18 +1,15 @@
1
1
  /**
2
- * **结算时作废一张本服务兑现不了的卡** —— 全仓「结算作废」的唯一动词:读卡 → 卡仍 pending ∧ 卡在调用方说的那只会话上 ⇒
2
+ * **结算时作废一张本 run 自己会话上的、本服务兑现不了的卡** —— 读卡 → 卡仍 pending ∧ 卡在调用方说的那只会话上 ⇒
3
3
  * 按卡**自己的** scope 走 checkpoint 店的 `expire`(与引擎的本进程仲裁器、续跑的 resolve 同一只 CAS,恰一个赢家)。不新增任何持久态。
4
4
  *
5
- * 规则只有一条:**本服务兑现不了的卡不留在待决面上**。两个产地读这一只动词,各自只答「手里是哪一张卡、它该在哪只会话上」:
6
- * · 验证器自己的停驻(`verifier-pause-card.ts`):卡在验证器现铸的会话上,本服务的续跑链连不回它;
7
- * · 停驻没落定就以失败收场的腿(`runs.ts` 的 `voidHeldParkCard`:后台腿与续跑腿):卡在本 run 的会话上,但兑现它的那条 run 已经
8
- * `failed`、认领已放 —— 卡的命运先于认领释放(调用方先调本动词、再放认领)。
5
+ * 规则只有一条:**本服务兑现不了的卡不留在待决面上**。产地 = 停驻没落定就以失败收场的腿(`runs.ts` 的 `voidHeldParkCard`:后台腿与
6
+ * 续跑腿):卡在本 run 的会话上,但兑现它的那条 run 已经 `failed`、认领已放 —— 卡的命运先于认领释放(调用方先调本动词、再放认领)。
7
+ * 验证器自己的停驻卡不走这里:它由引擎的 `Runner.voidVerifierPause` 作废(引擎读卡上的组合腿判它是不是验证器的卡,
8
+ * `verifier-pause-card.ts`);那只动词只收验证器的卡,本 run 自己会话上的卡按引擎的读法仍走店级 `expire`。
9
9
  *
10
10
  * 不抛:作废没做成(店读 / 作废抛错、卡的会话对不上、没接店)⇒ 卡回到「留在待决面上、由审批兜底收割收走」的形,按产地登记的 tag
11
11
  * 响亮留痕(计数 + 探针行 + 一次 warn),结算照常往下走。卡已不 pending / 已不在 ⇒ 什么都不做(CAS 输给了别的结算者,结局相同)。
12
- *
13
- * ## 🚧 过渡(引擎动词到货即改调)
14
- * 店级 `expire` 只作废卡,**不释放**引擎为这张卡钉住的会话(引擎在停驻时 pin 会话,只在续跑终局 / 续跑失败臂 unpin):
15
- * 被作废的卡的会话在本副本内存里一直常驻到进程重启。引擎给出「作废停驻卡并释放其会话」的动词之后,本动词改调它(两个产地一字不改)。
12
+ * 店级 `expire` 只作废卡,不动引擎在停驻时给这只会话打的钉(钉在续跑终局 / 续跑失败臂放)。
16
13
  */
17
14
  import type { CheckpointToken } from "@sema-agent/core";
18
15
  import { type FailOpenTag } from "./observability/fail-open.js";
@@ -337,7 +337,7 @@ export const CONFIG_CATALOG = [
337
337
  return compat.reasoningEffortLevels ?? null;
338
338
  },
339
339
  }),
340
- r("MODEL_ROUTER_ID", "modelPlane", "string", "leader 路由分类模型覆写", { derivedDefaultNote: "缺席 ⇒ MODEL_CHEAP_ID,再退 default", danger: BILL }),
340
+ r("MODEL_ROUTER_ID", "modelPlane", "string", "leader 路由分类模型覆写", { derivedDefaultNote: "缺席 ⇒ 在服务表里解 classifier 角色(classifier → summarize → default;env cheap 槽绑 summarize,采纳的目录绑它自己的)", danger: BILL }),
341
341
  r("MODEL_THINKING_FORMAT", "modelPlane", "enum", "本网关收「开/关思考」的拼法(上 core OpenAICompletionsCompat.thinkingFormat;缺省开思考的 vLLM/Qwen 网关只有 qwen-chat-template 关得掉;anthropic 腿不铸此键;未知词拒启)", {
342
342
  enumValues: [...THINKING_FORMATS],
343
343
  derivedDefaultNote: "缺席 ⇒ 不铸此键,core 按 baseUrl/模型 id 自行推断(默认 openai 的 reasoning_effort)",