@sema-agent/server 7.137.0 → 7.139.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 (328) hide show
  1. package/MIGRATION.md +600 -142
  2. package/README.md +7 -3
  3. package/README.zh-CN.md +6 -3
  4. package/USAGE.md +132 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/wire.d.ts +3 -3
  8. package/dist/approval-card.d.ts +23 -16
  9. package/dist/approval-card.js +1 -0
  10. package/dist/audit.js +1 -0
  11. package/dist/background-agent-name.d.ts +5 -0
  12. package/dist/background-agent-name.js +5 -0
  13. package/dist/bench/s1/arms.d.ts +1 -1
  14. package/dist/bench/s1/arms.js +1 -3
  15. package/dist/bench/s1/run-firm.js +2 -2
  16. package/dist/boot/budget-tracing.d.ts +1 -12
  17. package/dist/boot/deployment-mods.d.ts +46 -16
  18. package/dist/boot/deployment-mods.js +82 -6
  19. package/dist/boot/device-lane.d.ts +8 -3
  20. package/dist/boot/device-lane.js +7 -2
  21. package/dist/boot/execution-env.d.ts +4 -2
  22. package/dist/boot/execution-env.js +16 -24
  23. package/dist/boot/execution-lane.d.ts +1 -1
  24. package/dist/boot/governance-seams.d.ts +12 -18
  25. package/dist/boot/governance-seams.js +10 -24
  26. package/dist/boot/leader.d.ts +3 -0
  27. package/dist/boot/leader.js +1 -0
  28. package/dist/boot/memory-consolidation.js +2 -2
  29. package/dist/boot/org-delivery.js +15 -2
  30. package/dist/boot/resolve-spec.d.ts +4 -1
  31. package/dist/boot/resolve-spec.js +29 -19
  32. package/dist/boot/retention-lane.d.ts +14 -8
  33. package/dist/boot/retention-lane.js +2 -8
  34. package/dist/boot/runner-deps.d.ts +10 -4
  35. package/dist/boot/runner-deps.js +2 -0
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-04-stores.d.ts +1 -12
  40. package/dist/boot/stage-05-execution-env.d.ts +3 -12
  41. package/dist/boot/stage-05-execution-env.js +8 -5
  42. package/dist/boot/stage-06-runners.d.ts +3 -12
  43. package/dist/boot/stage-06-runners.js +5 -3
  44. package/dist/boot/stage-07-capability-layer.d.ts +3 -12
  45. package/dist/boot/stage-07-capability-layer.js +2 -2
  46. package/dist/boot/stage-08-reapers.d.ts +3 -12
  47. package/dist/boot/stage-09-leader.d.ts +3 -12
  48. package/dist/boot/stage-09-leader.js +2 -3
  49. package/dist/boot/stage-10-http-server.d.ts +3 -12
  50. package/dist/boot/stage-10-http-server.js +5 -3
  51. package/dist/boot/stores.js +4 -4
  52. package/dist/boot/web-admin.d.ts +5 -2
  53. package/dist/boot/web-admin.js +5 -5
  54. package/dist/brain.js +5 -5
  55. package/dist/budget.d.ts +17 -15
  56. package/dist/budget.js +2 -2
  57. package/dist/capabilities/mcp-probe.d.ts +36 -11
  58. package/dist/capabilities/mcp-probe.js +44 -5
  59. package/dist/capabilities/scenarios.d.ts +1 -1
  60. package/dist/capability-facts.d.ts +21 -7
  61. package/dist/capability-facts.js +13 -3
  62. package/dist/checkpoint-identity.d.ts +13 -6
  63. package/dist/config-catalog.js +14 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +19 -24
  67. package/dist/config-provider.js +27 -12
  68. package/dist/config-types.d.ts +25 -12
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +52 -20
  71. package/dist/delegated-session-owner.d.ts +2 -2
  72. package/dist/deployment-shape.d.ts +7 -7
  73. package/dist/device-enrollment.d.ts +41 -2
  74. package/dist/device-enrollment.js +27 -12
  75. package/dist/device-store.d.ts +58 -85
  76. package/dist/device-store.js +19 -49
  77. package/dist/device-ws-hub.js +2 -1
  78. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  79. package/dist/exec-cut.d.ts +60 -0
  80. package/dist/exec-cut.js +36 -0
  81. package/dist/execution-lane-caps.d.ts +19 -0
  82. package/dist/execution-lane-caps.js +10 -0
  83. package/dist/execution-placement.d.ts +259 -0
  84. package/dist/execution-placement.js +199 -0
  85. package/dist/field-conflict.d.ts +3 -2
  86. package/dist/field-conflict.js +1 -0
  87. package/dist/gate-settlement.d.ts +71 -0
  88. package/dist/gate-settlement.js +40 -0
  89. package/dist/hooks/classic-stations.d.ts +1 -0
  90. package/dist/hooks/classic-stations.js +1 -0
  91. package/dist/hooks/command-spawn.d.ts +2 -2
  92. package/dist/hooks/hook-runner.js +14 -14
  93. package/dist/hosted-posture.d.ts +2 -2
  94. package/dist/http/admission.js +10 -19
  95. package/dist/http/checkpoint-ctx.d.ts +21 -12
  96. package/dist/http/checkpoint-ctx.js +4 -2
  97. package/dist/http/claimed-run.d.ts +1 -1
  98. package/dist/http/dispatch.d.ts +4 -0
  99. package/dist/http/dispatch.js +3 -0
  100. package/dist/http/durable-run-leg.js +12 -6
  101. package/dist/http/execution-context.d.ts +218 -0
  102. package/dist/http/execution-context.js +330 -0
  103. package/dist/http/memory-compliance-failure-reply.js +3 -0
  104. package/dist/http/resume-legs.d.ts +5 -11
  105. package/dist/http/resume-legs.js +179 -104
  106. package/dist/http/route-ctx.d.ts +44 -59
  107. package/dist/http/route-ctx.js +2 -5
  108. package/dist/http/routes/a2a-serve.js +10 -4
  109. package/dist/http/routes/agents-roster.d.ts +1 -1
  110. package/dist/http/routes/agents-roster.js +5 -1
  111. package/dist/http/routes/approvals-assistant.js +6 -6
  112. package/dist/http/routes/background.d.ts +29 -1
  113. package/dist/http/routes/background.js +29 -2
  114. package/dist/http/routes/capabilities.js +12 -10
  115. package/dist/http/routes/devices.d.ts +13 -19
  116. package/dist/http/routes/devices.js +21 -26
  117. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  118. package/dist/http/routes/mcp-reconnect.js +7 -5
  119. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  120. package/dist/http/routes/memory-origin.d.ts +1 -1
  121. package/dist/http/routes/rules.js +3 -3
  122. package/dist/http/routes/runs.js +11 -7
  123. package/dist/http/routes/session-sync.js +110 -15
  124. package/dist/http/routes/sessions.d.ts +6 -0
  125. package/dist/http/routes/sessions.js +119 -13
  126. package/dist/http/routes/side-query.d.ts +12 -4
  127. package/dist/http/routes/side-query.js +6 -8
  128. package/dist/http/routes/tasks.js +800 -782
  129. package/dist/http/server.d.ts +61 -39
  130. package/dist/http/server.js +11 -0
  131. package/dist/http/session-inherit-env.d.ts +3 -4
  132. package/dist/http/session-inherit-env.js +1 -1
  133. package/dist/http/wire-types.d.ts +22 -18
  134. package/dist/identity-source.d.ts +1 -1
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.js +1 -0
  137. package/dist/leader/wire.d.ts +7 -0
  138. package/dist/leader/wire.js +5 -4
  139. package/dist/mcp-assertion-header.d.ts +51 -40
  140. package/dist/mcp-assertion-header.js +10 -11
  141. package/dist/mcp-authorization-face.d.ts +27 -0
  142. package/dist/mcp-authorization-face.js +15 -0
  143. package/dist/memory-operator-faces.d.ts +13 -4
  144. package/dist/memory-operator-faces.js +1 -17
  145. package/dist/memory-sync-client.d.ts +53 -14
  146. package/dist/memory-sync-client.js +187 -92
  147. package/dist/memory-sync.d.ts +1 -1
  148. package/dist/memory-sync.js +3 -2
  149. package/dist/model-route-gap.d.ts +6 -22
  150. package/dist/model-route-gap.js +7 -5
  151. package/dist/mods-declaration.d.ts +110 -0
  152. package/dist/mods-declaration.js +109 -0
  153. package/dist/observability/cost-taxonomy.d.ts +2 -2
  154. package/dist/observability/err-text.d.ts +5 -0
  155. package/dist/observability/err-text.js +9 -0
  156. package/dist/observability/fail-open.d.ts +17 -1
  157. package/dist/observability/fail-open.js +17 -1
  158. package/dist/observability/run-terminal.js +0 -1
  159. package/dist/observability/secret-env-scrub.d.ts +1 -1
  160. package/dist/observability/secret-env-scrub.js +1 -1
  161. package/dist/orchestration/workflow-notify-journal.js +4 -4
  162. package/dist/org-memory-admission.d.ts +4 -3
  163. package/dist/org-memory-admission.js +6 -6
  164. package/dist/parked-decide.d.ts +49 -11
  165. package/dist/parked-decide.js +25 -26
  166. package/dist/parked-revive-surface.d.ts +12 -15
  167. package/dist/parked-revive-surface.js +3 -6
  168. package/dist/peer-seat.d.ts +156 -0
  169. package/dist/peer-seat.js +273 -0
  170. package/dist/permission-rule-vocab.d.ts +7 -7
  171. package/dist/permission-rule-vocab.js +3 -3
  172. package/dist/plain-string-record.d.ts +38 -0
  173. package/dist/plain-string-record.js +38 -0
  174. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  175. package/dist/plugins/approval-ask-store-file.js +11 -0
  176. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  177. package/dist/plugins/approval-ask-store-memory.js +12 -0
  178. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  179. package/dist/plugins/approval-ask-store-sql.js +30 -12
  180. package/dist/plugins/background-agent-store-sql.js +6 -3
  181. package/dist/plugins/caching-session-store.d.ts +11 -2
  182. package/dist/plugins/caching-session-store.js +15 -3
  183. package/dist/plugins/checkpoint-store-sql.d.ts +21 -25
  184. package/dist/plugins/checkpoint-store-sql.js +13 -15
  185. package/dist/plugins/device-store-sql.d.ts +25 -51
  186. package/dist/plugins/device-store-sql.js +49 -103
  187. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  188. package/dist/plugins/execution-placement-sql.js +223 -0
  189. package/dist/plugins/file-history-store-sql.d.ts +7 -6
  190. package/dist/plugins/file-history-store-sql.js +8 -7
  191. package/dist/plugins/file-run-store.d.ts +6 -1
  192. package/dist/plugins/file-run-store.js +4 -0
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  194. package/dist/plugins/fork-routing-session-store.js +16 -0
  195. package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
  196. package/dist/plugins/k8s-pod-reaper.js +3 -3
  197. package/dist/plugins/local-checkpoint-store.d.ts +1 -11
  198. package/dist/plugins/local-checkpoint-store.js +0 -1
  199. package/dist/plugins/local-session-store.d.ts +183 -45
  200. package/dist/plugins/local-session-store.js +412 -105
  201. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  202. package/dist/plugins/mailbox-store-sql.js +103 -15
  203. package/dist/plugins/memory-key-guards.d.ts +4 -0
  204. package/dist/plugins/memory-key-guards.js +1 -0
  205. package/dist/plugins/memory-run-store.d.ts +1 -1
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +117 -6
  209. package/dist/plugins/one-time-migrations.js +383 -14
  210. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
  212. package/dist/plugins/permission-rule-store-sql.js +34 -29
  213. package/dist/plugins/pg-pool.d.ts +7 -3
  214. package/dist/plugins/pg-session-storage.d.ts +41 -22
  215. package/dist/plugins/pg-session-storage.js +136 -55
  216. package/dist/plugins/remote-env-adb.d.ts +22 -4
  217. package/dist/plugins/remote-env-adb.js +70 -62
  218. package/dist/plugins/remote-env-device.d.ts +32 -12
  219. package/dist/plugins/remote-env-device.js +18 -17
  220. package/dist/plugins/remote-env-e2b.d.ts +19 -3
  221. package/dist/plugins/remote-env-e2b.js +41 -42
  222. package/dist/plugins/remote-env-file-error.d.ts +2 -0
  223. package/dist/plugins/remote-env-file-error.js +1 -1
  224. package/dist/plugins/remote-env-host.d.ts +23 -8
  225. package/dist/plugins/remote-env-host.js +66 -70
  226. package/dist/plugins/remote-env-k8s.d.ts +13 -16
  227. package/dist/plugins/remote-env-k8s.js +61 -54
  228. package/dist/plugins/remote-env-local-docker.d.ts +30 -5
  229. package/dist/plugins/remote-env-local-docker.js +46 -59
  230. package/dist/plugins/remote-env-ssh.d.ts +18 -4
  231. package/dist/plugins/remote-env-ssh.js +72 -56
  232. package/dist/plugins/remote-shell.d.ts +100 -3
  233. package/dist/plugins/remote-shell.js +166 -2
  234. package/dist/plugins/retention-store-sql.d.ts +23 -8
  235. package/dist/plugins/retention-store-sql.js +13 -1
  236. package/dist/plugins/run-store-sql.d.ts +13 -3
  237. package/dist/plugins/run-store-sql.js +5 -0
  238. package/dist/plugins/schema-consistency.d.ts +15 -5
  239. package/dist/plugins/schema-consistency.js +14 -8
  240. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  241. package/dist/plugins/schema-drift-sentence.js +38 -0
  242. package/dist/plugins/session-fork.d.ts +63 -12
  243. package/dist/plugins/session-fork.js +38 -21
  244. package/dist/plugins/session-ownership.d.ts +7 -0
  245. package/dist/plugins/session-ownership.js +5 -0
  246. package/dist/plugins/session-row-sql.d.ts +22 -0
  247. package/dist/plugins/session-row-sql.js +81 -0
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  250. package/dist/plugins/session-workspace-cell.js +38 -0
  251. package/dist/plugins/store-backend.d.ts +1 -1
  252. package/dist/plugins/store-backend.js +26 -14
  253. package/dist/plugins/store-contracts.d.ts +25 -5
  254. package/dist/plugins/tidb-pool.d.ts +12 -7
  255. package/dist/plugins/tidb-pool.js +15 -3
  256. package/dist/plugins/tidb-session-store.d.ts +74 -28
  257. package/dist/plugins/tidb-session-store.js +132 -53
  258. package/dist/plugins/tool-result-store-sql.d.ts +16 -8
  259. package/dist/plugins/tool-result-store-sql.js +26 -17
  260. package/dist/plugins/worktree-isolation.d.ts +3 -2
  261. package/dist/plugins/worktree-isolation.js +1 -7
  262. package/dist/project-identity.d.ts +1 -14
  263. package/dist/project-identity.js +0 -4
  264. package/dist/project-memory.d.ts +9 -15
  265. package/dist/project-memory.js +5 -4
  266. package/dist/request-key-closure.js +1 -1
  267. package/dist/request-value-closure.d.ts +6 -7
  268. package/dist/request-value-closure.js +1 -3
  269. package/dist/rules-consent.js +6 -4
  270. package/dist/run-local.d.ts +6 -0
  271. package/dist/run-local.js +36 -26
  272. package/dist/runs.d.ts +9 -2
  273. package/dist/runs.js +9 -2
  274. package/dist/sandbox-git-plane.d.ts +2 -2
  275. package/dist/security.d.ts +38 -12
  276. package/dist/security.js +8 -2
  277. package/dist/server-secret-env.d.ts +15 -8
  278. package/dist/server-secret-env.js +4 -2
  279. package/dist/session-children-retire.d.ts +27 -9
  280. package/dist/session-children-retire.js +9 -5
  281. package/dist/session-incarnation.d.ts +19 -10
  282. package/dist/session-incarnation.js +5 -3
  283. package/dist/session-row.d.ts +114 -5
  284. package/dist/session-row.js +55 -5
  285. package/dist/session-titler.d.ts +2 -2
  286. package/dist/session-workspace.d.ts +130 -0
  287. package/dist/session-workspace.js +83 -0
  288. package/dist/spec-fields.d.ts +1 -1
  289. package/dist/standing-answer-grant.d.ts +2 -13
  290. package/dist/standing-answer-grant.js +0 -7
  291. package/dist/task-a2a.d.ts +44 -14
  292. package/dist/task-a2a.js +46 -20
  293. package/dist/task-cwd.d.ts +6 -1
  294. package/dist/task-mcp.d.ts +33 -20
  295. package/dist/task-mcp.js +46 -22
  296. package/dist/tool-approval.d.ts +38 -8
  297. package/dist/tool-approval.js +57 -13
  298. package/dist/trace/core-keyset-guard.d.ts +33 -18
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +2 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +3 -0
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/project.d.ts +26 -7
  306. package/dist/trace/project.js +30 -3
  307. package/dist/trace/redact.js +42 -13
  308. package/dist/trace/self-minted-wire.d.ts +240 -12
  309. package/dist/trace/self-minted-wire.js +100 -4
  310. package/dist/trace/wire-projection-faces.d.ts +6 -6
  311. package/dist/trace/wire-projection-faces.js +6 -5
  312. package/dist/url-refusal.d.ts +1 -1
  313. package/dist/user-authored-text.d.ts +2 -2
  314. package/dist/user-authored-text.js +16 -1
  315. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  316. package/dist/web-admin-client/apply-effective.js +20 -10
  317. package/dist/web-admin-client/center-request.d.ts +3 -2
  318. package/dist/web-admin-client/center-request.js +2 -3
  319. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  320. package/dist/web-admin-client/skills-mcp.js +32 -18
  321. package/dist/web-admin-client/types.d.ts +11 -0
  322. package/package.json +3 -3
  323. package/wire-changes/server@7.138.0.json +446 -0
  324. package/wire-changes/server@7.139.0.json +348 -0
  325. package/dist/http/device-placement.d.ts +0 -175
  326. package/dist/http/device-placement.js +0 -145
  327. package/dist/http/mcp-remote-text.d.ts +0 -5
  328. package/dist/http/mcp-remote-text.js +0 -7
package/dist/brain.js CHANGED
@@ -6,7 +6,7 @@ import { createHash } from "node:crypto";
6
6
  import { isModelKeyPoison, modelKeyPoisonIdentity } from "./key-resolver.js";
7
7
  import { anthropicRouteRoot, brainLaneFor, mountRoutes, routeTableOf } from "./model-provider.js";
8
8
  import { openaiRouteBaseUrl } from "./model-route-endpoint.js";
9
- import { anthropicLaneCredentialOf } from "./model-route-gap.js";
9
+ import { anthropicLaneCredentialOf, declaredCredential } from "./model-route-gap.js";
10
10
  import { catalogEntryFingerprint } from "./web-admin-client/restart-signal.js";
11
11
  import { buildDisplaySafeRefusal, buildDisplaySafeUrl } from "./trace/redact.js";
12
12
  import { createModelReachBrain } from "./model-unreachable-notice.js";
@@ -26,10 +26,10 @@ function breakerRoutesOf(config, r) {
26
26
  return r.circuitBreaker ? deploymentGatewayRoots(config).slice(0, -1) : [];
27
27
  }
28
28
  function deploymentGatewayKey(config) {
29
- return config.gatewayBaseUrl !== undefined ? config.gatewayApiKey : undefined;
29
+ return config.gatewayBaseUrl !== undefined ? declaredCredential(config.gatewayApiKey) : undefined;
30
30
  }
31
31
  function degradeDeclaredRoot(fallbackBaseUrl, config) {
32
- const armed = Boolean(deploymentGatewayKey(config)) && isOffDeploymentRoot(fallbackBaseUrl, config);
32
+ const armed = deploymentGatewayKey(config) !== undefined && isOffDeploymentRoot(fallbackBaseUrl, config);
33
33
  return armed ? config.gatewayBaseUrl : openaiRouteBaseUrl(fallbackBaseUrl, config.gatewayBaseUrl);
34
34
  }
35
35
  export const FAST_FAIL_MAX_RETRIES = 2;
@@ -110,7 +110,7 @@ export function createBrainAssembly(config, deps = {}) {
110
110
  brainRoutes.anthropic
111
111
  : constructRouteBrain(`degrade target "${degradeTo}"`, [fallbackModel.baseUrl, config.gatewayBaseUrl], () => createOpenAIBrain({
112
112
  ...(fbDeclaredRoot !== undefined ? { baseUrl: fbDeclaredRoot } : {}),
113
- ...(fbDeploymentKey ? { apiKey: fbDeploymentKey } : {}),
113
+ ...(fbDeploymentKey !== undefined ? { apiKey: fbDeploymentKey } : {}),
114
114
  ...(config.gatewayMaxRetries !== undefined ? { maxRetries: config.gatewayMaxRetries } : {}),
115
115
  fetchImpl,
116
116
  ...timeouts,
@@ -240,7 +240,7 @@ export function brainSummary(config) {
240
240
  if (declaresOwnCredential) {
241
241
  return { reactiveDegradeRoutePairing: "per-model-declared", reactiveDegradeRouteRefusal: null };
242
242
  }
243
- const verdict = adjudicateModelRoute({ id: target.id, baseUrl: target.baseUrl }, resolveRouteCredential(((key) => (key ? { configApiKey: key } : {}))(deploymentGatewayKey(config))), { baseUrl: degradeDeclaredRoot(target.baseUrl, config) });
243
+ const verdict = adjudicateModelRoute({ id: target.id, baseUrl: target.baseUrl }, resolveRouteCredential(((key) => (key !== undefined ? { configApiKey: key } : {}))(deploymentGatewayKey(config))), { baseUrl: degradeDeclaredRoot(target.baseUrl, config) });
244
244
  return verdict.ok
245
245
  ? { reactiveDegradeRoutePairing: `ok:${verdict.posture}`, reactiveDegradeRouteRefusal: null }
246
246
  : {
package/dist/budget.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * ④ createTracer — core's content-free TraceEvents → /metrics (spend, first-token, tool calls).
6
6
  * ⑤ cappedCeiling — clamp a caller's requested per-task budget DOWN to the operator ceiling.
7
7
  */
8
- import { type Model, type ModelPricing, type TracerHook } from "@sema-agent/core";
8
+ import { type AccountRow, type Model, type ModelPricing, type TracerHook } from "@sema-agent/core";
9
9
  import type { Metrics } from "./observability/metrics.js";
10
10
  import type { QuotaTracker } from "./observability/cost-quota.js";
11
11
  import type { FleetUsageBins } from "./fleet-client.js";
@@ -116,23 +116,25 @@ export declare function createTracer(metrics: Pick<Metrics, "inc" | "observe">,
116
116
  * (tokens×quotaWeight,weight-at-burn 固化)、micro-USD 同轴。装配点与 createTracer 同一处(main.ts),
117
117
  * 传同一组实例——两臂永不分家。
118
118
  *
119
- * 已知残差(codex R3 medium,记档):cost 源=core SideQueryResult.usage.cost.total(brain 层计价),
120
- * OpenAI cache-heavy 输入按全价入账(tracer 的 e.costMicroUsd 是 cache-family-aware 价)——方向=多收
121
- * (保守,绝不少收);根修=core 在 SideQueryResult 上回权威 costMicroUsd(已提货 core)。model 标签/
119
+ * 金额源 = 引擎定价的账行 `SideQueryResult.account.costMicroUsd`(core 7.59.0:与 run 的旁路调用同一只定价函数、
120
+ * 按部署价表、按实际作答的模型)—— 与 tracer 的 `e.costMicroUsd` 同一口径;缺席 = 那只模型没有价表 = **未知**(不编 0)。
121
+ * 适配器自报的 `usage.cost.total`(cache 命中按全价)不是金额源(7.58.x 及更早读它,cache-heavy 时多收)。model 标签 /
122
122
  * weight 键用**路由身份 r.model**(池配置有界)非 servedModel(provider 上报,无界)。
123
123
  */
124
- export declare function createSideQueryAccountant(metrics: Pick<Metrics, "inc">, costQuota?: QuotaTracker, fleetUsage?: Pick<FleetUsageBins, "record">, fleetLease?: Pick<FleetLeaseManager, "recordSpend">, quotaWeightFor?: (model: string) => number): (principal: string | undefined, r: {
125
- model: string;
126
- usage?: {
127
- input?: number;
128
- output?: number;
129
- cacheRead?: number;
130
- cacheWrite?: number;
131
- cost?: {
132
- total?: number;
133
- };
124
+ export interface SideQueryAccountingInput {
125
+ readonly model: string;
126
+ /** 引擎归一的计数(`input` 已是 uncached 量,见函数体 [ref] 注)。 */
127
+ readonly usage?: {
128
+ readonly input?: number;
129
+ readonly output?: number;
130
+ readonly cacheRead?: number;
131
+ readonly cacheWrite?: number;
134
132
  };
135
- }) => void;
133
+ /** 引擎定价的账行(`origin: "side_query"`);只读它的 `costMicroUsd`。 */
134
+ readonly account?: AccountRow;
135
+ }
136
+ export type SideQueryAccounting = (principal: string | undefined, r: SideQueryAccountingInput) => void;
137
+ export declare function createSideQueryAccountant(metrics: Pick<Metrics, "inc">, costQuota?: QuotaTracker, fleetUsage?: Pick<FleetUsageBins, "record">, fleetLease?: Pick<FleetLeaseManager, "recordSpend">, quotaWeightFor?: (model: string) => number): SideQueryAccounting;
136
138
  /**
137
139
  * ⑤ Resolve a per-task budget: honor the caller's requested value but never let it EXCEED the operator
138
140
  * ceiling. `0`/unset ceiling = no limit (returns the caller's value, or undefined). A non-positive /
package/dist/budget.js CHANGED
@@ -144,8 +144,8 @@ export function createSideQueryAccountant(metrics, costQuota, fleetUsage, fleetL
144
144
  const cacheRead = typeof r.usage?.cacheRead === "number" ? r.usage.cacheRead : 0;
145
145
  const cacheWrite = typeof r.usage?.cacheWrite === "number" ? r.usage.cacheWrite : 0;
146
146
  const promptTokens = input + cacheRead + cacheWrite;
147
- const costTotal = typeof r.usage?.cost?.total === "number" ? r.usage.cost.total : undefined;
148
- const micro = costTotal !== undefined ? Math.round(costTotal * 1_000_000) : undefined;
147
+ const costMicro = r.account?.costMicroUsd;
148
+ const micro = typeof costMicro === "number" && Number.isFinite(costMicro) ? Math.round(costMicro) : undefined;
149
149
  if (micro !== undefined && micro > 0) {
150
150
  metrics.inc("model_cost_micro_usd_total", { model: r.model }, micro);
151
151
  if (principal)
@@ -34,6 +34,7 @@
34
34
  */
35
35
  import { type McpServerSpec } from "@sema-agent/core";
36
36
  import type { DeclarationRefusal } from "../request-declaration-refusal.js";
37
+ import { type McpDraft, type PeerDesk } from "../peer-seat.js";
37
38
  /**
38
39
  * 本面的**拒码闭集**(设计稿 §2 的四枚)。闭集写成型,是为了让 {@link MCP_PROBE_HTTP_STATUS} 那张表
39
40
  * 「漏一枚 = 编译红」—— [ref] 的安全轴纪律:词表是闭集,未处置的成员必须是编译错误而不是运行期惊喜。
@@ -163,25 +164,29 @@ export interface McpProbeRefusal {
163
164
  readonly facts?: DeclarationRefusal["facts"];
164
165
  }
165
166
  /**
166
- * `POST …/probe` 的体读器:闭形、逐条点名、零静默丢。成功 ⇒ 交给 core 的 `specs`(**原样**转发被读出来的
167
- * 条目,`McpServerSpec` 的可选键一个都不重写 —— 重写就是在 core 的型上做第二次投影)。
167
+ * `POST …/probe` 的体读器:闭形、逐条点名、零静默丢。成功 ⇒ 每条申报的**草稿**(被读出来的条目经 `toMcpDraft` 拆成声明 + 件,
168
+ * 声明里 `McpServerSpec` 的可选键一个都不重写 —— 重写就是在 core 的型上做第二次投影)。
168
169
  *
169
170
  * ## 申报「能不能原样用」:问提交腿 fresh 门**同一只**回答者,不另判
170
171
  * 本面只判自己那一层(体是对象、顶层只受理 `mcpServers`、这个键必填);`mcpServers` 本身 —— 列表的形、上限、每条的键名与键值 —— 全部交给
171
172
  * `task-mcp.ts` 的 `requestMcpDeclarationRefusal`,拒(码 + 句 + `unknownKeys` + 撞帽 / url 带凭据两形的机读位)原样转述:同一份申报在两扇门上只有一个答案,零拨号之前就给。
172
- * 回答者受理的申报由**同一只**读器(`validateRequestMcp`)交回,读器的产物就是申报本身(只差判官自己的合法归一),经 `toCoreMcpServerSpec`
173
- * 得到的就是一条任务提交会交给引擎的那一份 —— 本面拨的正是它。读器只在回答者受理之后才跑,所以它对重放存量 body 才有的降级留痕
174
- * (`source` 写坏的 F 类丢弃)不会在一次被拒的探测上虚记。
173
+ * 回答者受理的申报由**同一只**读器(`validateRequestMcp`)交回,读器的产物就是申报本身(只差判官自己的合法归一),经 `toMcpDraft`
174
+ * 拆出的草稿就是一条任务提交会交给铸点的那一份 —— 走查在自己的租约下铸它(见 {@link createMcpProbeWalk}),本面拨的正是铸出的声明。读器只在回答者受理之后才跑,
175
+ * 所以它对重放存量 body 才有的降级留痕(`source` 写坏的 F 类丢弃)不会在一次被拒的探测上虚记。
175
176
  *
176
- * ## 唯一一处按门分的后果:声明了 `assertionHeader`(引擎尚无断言头座)
177
+ * ## 唯一一处按门分的后果:声明了 `assertionHeader`(本部署的对端座对断言一种引用恒拒、没有断言来源)
177
178
  * 事实只有一个、读它的谓词只有一只(`specWithholdsMcpAssertionHeader`,读发送开关 `MCP_ASSERTION_HEADER_SENT`):这台 server 声明的断言头本版**承载、不发送**,交给引擎的规格里没有它。
178
179
  * 新提交照挂并给运维一行 info(`mcp_assertion_header_not_sent`;settings 面同读法);本面**整条拒** —— 拨出去的不是申报的那一份,一台握手放行、
179
180
  * 调用才要断言的对端会被答成 connected,而它的调用会被拒。判据同一只、后果按门分(与重放腿对同一组身份头「降级到升级前读法」同一个姿势);
180
- * 引擎长出同名座的那天,开关翻真,`toCoreMcpServerSpec` 的剥键与这一拒一起退役(`mcp-assertion-header.ts` 的退役门编译红)。
181
+ * 开关与它的退役门在 `mcp-assertion-header.ts`(押在对端座上)。
182
+ *
183
+ * ## 带件的申报(`transport.headers` / `transport.env`):与任务提交同一条路
184
+ * 件进草稿、不进声明;走查在自己的宿主租约下把件登记进部署的对端座,交给引擎的声明只带一只引用,引擎在起子进程 / 发请求时向同一只座要 ——
185
+ * 拨出去的就是申报的那一份,件形的判(多行值、协议自有头名 …)也是任务那一份判。
181
186
  */
182
187
  export declare function readMcpProbeBody(raw: unknown): {
183
188
  ok: true;
184
- specs: McpServerSpec[];
189
+ drafts: McpDraft[];
185
190
  } | {
186
191
  ok: false;
187
192
  refusal: McpProbeRefusal;
@@ -194,8 +199,28 @@ export declare function readMcpProbeBody(raw: unknown): {
194
199
  * 无 principal(单用户部署上恒如此)折成 `local`:那台机器上只有一个人。
195
200
  */
196
201
  export declare function buildMcpProbeIdentity(principal: string | undefined): string;
197
- /** 缓存键 = `(身份, sha256(规范化 specs))`。**纯数据** ⇒ `build*`。 */
198
- export declare function buildMcpProbeCacheKey(principal: string | undefined, specs: readonly McpServerSpec[]): string;
202
+ /**
203
+ * 一次探测问的是什么 —— 两条口各一臂,**谁写的申报**就是判别位:
204
+ * · `deployment`(`GET /v1/capabilities/mcp`)= 本部署名册里这个场景挂的声明。它们起服时已在名册租约下铸过(件在对端座里、声明只带引用),
205
+ * 走查直接拨、不开租约、不再登记;
206
+ * · `caller`(`POST …/probe`)= 调用方自带申报的草稿(声明 + 件)。走查在自己的宿主租约下经唯一铸点登记件,见 {@link createMcpProbeWalk}。
207
+ * 两臂的声明都由同一只座作答。缓存键、走查、失败归属(谁写的申报谁的错)都读这一只输入。
208
+ */
209
+ export type McpProbeInput = {
210
+ readonly declaredBy: "deployment";
211
+ readonly specs: readonly McpServerSpec[];
212
+ } | {
213
+ readonly declaredBy: "caller";
214
+ readonly drafts: readonly McpDraft[];
215
+ };
216
+ /** 这次探测申报了几台(零台 ⇒ 诚实空面,不进缓存、不占限速、不开租约)。 */
217
+ export declare function countMcpProbeDeclarations(input: McpProbeInput): number;
218
+ /**
219
+ * 缓存键 = `(身份, sha256(规范化的整份输入))`。**对输入算**:键在缓存命中 / 在途帽 / 限速三道前置拒里就要用,那时还没有登记任何件(登记在走查里),
220
+ * 所以只能对问的那一份算 —— 调用方臂的件在键内(只差凭据的两份申报是两次走查,与件写在声明里时同义),申报方也在键内(同一份声明在两臂上是两件事)。
221
+ * 部署臂的声明带的是引用,同一进程同内容同 id,换了名册的件就换了 id。键只在进程内的表里用,不出门。**纯数据** ⇒ `build*`。
222
+ */
223
+ export declare function buildMcpProbeCacheKey(principal: string | undefined, input: McpProbeInput): string;
199
224
  /** 限速键(设计稿 §3:`mcp-probe:<身份>`)。**纯数据** ⇒ `build*`。 */
200
225
  export declare function buildMcpProbeRateKey(principal: string | undefined): string;
201
226
  /** 本域独占的运行期状态(每 server 实例一份 —— 模块级会把缓存与限速窗跨实例串味)。 */
@@ -281,7 +306,7 @@ export interface McpProbeWalk {
281
306
  readonly answer: Promise<McpProbeFaceBody>;
282
307
  readonly dials: Promise<unknown>;
283
308
  }
284
- export declare function createMcpProbeWalk(specs: readonly McpServerSpec[], principal: string | undefined, now?: () => number): McpProbeWalk;
309
+ export declare function createMcpProbeWalk(input: McpProbeInput, principal: string | undefined, desk: PeerDesk, now?: () => number): McpProbeWalk;
285
310
  /**
286
311
  * 下标对齐的**内部断言**没过(行数 ≠ 申报数,或读数条数 ≠ 行数):core 的 `@contract mcp.probe.index_aligned` 在今天结构上保证它不发生,
287
312
  * 所以它一旦发生,是**这台服务内部的读数违约**,不是调用方的申报写错 —— 修申报修不好它。**具名型**而不是按文案或按「非 Incomplete 的 reject」分诊:
@@ -4,7 +4,8 @@ import { createFixedWindowRateLimiter } from "../device-enrollment.js";
4
4
  import { canonicalJsonStringify } from "@sema-agent/core";
5
5
  import { keyClosureClause, scanKeyClosure } from "../request-key-closure.js";
6
6
  import { requestMcpDeclarationRefusal, validateRequestMcp } from "../task-mcp.js";
7
- import { specWithholdsMcpAssertionHeader, toCoreMcpServerSpec } from "../mcp-assertion-header.js";
7
+ import { specWithholdsMcpAssertionHeader, toMcpDraft } from "../mcp-assertion-header.js";
8
+ import { mintDeclaration } from "../peer-seat.js";
8
9
  import { projectWiringManifestMcpRows } from "../trace/project.js";
9
10
  import { buildBoundedToolNames } from "../panel-tool-names.js";
10
11
  export const MCP_PROBE_REFUSAL_CODES = [
@@ -80,13 +81,26 @@ export function readMcpProbeBody(raw) {
80
81
  "Probe the entry without the key to see how the server answers without it"),
81
82
  };
82
83
  }
83
- return { ok: true, specs: validated.ok.map(toCoreMcpServerSpec) };
84
+ return { ok: true, drafts: validated.ok.map(toMcpDraft) };
84
85
  }
85
86
  export function buildMcpProbeIdentity(principal) {
86
87
  return principal !== undefined && principal.length > 0 ? principal : "local";
87
88
  }
88
- export function buildMcpProbeCacheKey(principal, specs) {
89
- return `${buildMcpProbeIdentity(principal)}::${createHash("sha256").update(canonicalJsonStringify(specs), "utf8").digest("hex")}`;
89
+ export function countMcpProbeDeclarations(input) {
90
+ switch (input.declaredBy) {
91
+ case "deployment":
92
+ return input.specs.length;
93
+ case "caller":
94
+ return input.drafts.length;
95
+ default: {
96
+ const unknownArm = input;
97
+ void unknownArm;
98
+ throw new Error("mcp probe: an input arm this module does not know (the arm set is closed: deployment / caller)");
99
+ }
100
+ }
101
+ }
102
+ export function buildMcpProbeCacheKey(principal, input) {
103
+ return `${buildMcpProbeIdentity(principal)}::${createHash("sha256").update(canonicalJsonStringify(input), "utf8").digest("hex")}`;
90
104
  }
91
105
  export function buildMcpProbeRateKey(principal) {
92
106
  return `mcp-probe:${buildMcpProbeIdentity(principal)}`;
@@ -155,7 +169,8 @@ export function buildMcpProbeFaceRows(rows, readings) {
155
169
  function isStringList(v) {
156
170
  return Array.isArray(v) && Array.from(v).every((t) => typeof t === "string");
157
171
  }
158
- export function createMcpProbeWalk(specs, principal, now = Date.now) {
172
+ export function createMcpProbeWalk(input, principal, desk, now = Date.now) {
173
+ const { specs, lease } = probeDeclarations(input, desk);
159
174
  const bound = buildMcpProbeWalkTimeoutMs(specs.length);
160
175
  const controller = new AbortController();
161
176
  const dials = probeMcpServers(specs, {
@@ -163,7 +178,10 @@ export function createMcpProbeWalk(specs, principal, now = Date.now) {
163
178
  timeoutMs: MCP_PROBE_VERDICT_TIMEOUT_MS,
164
179
  concurrency: MCP_PROBE_CONCURRENCY,
165
180
  signal: controller.signal,
181
+ peerSeat: desk.seat,
166
182
  });
183
+ if (lease !== undefined)
184
+ void dials.then(() => lease.release(), () => lease.release());
167
185
  dials.catch(() => undefined);
168
186
  let timer;
169
187
  const deadline = new Promise((_resolve, reject) => {
@@ -189,6 +207,27 @@ export function createMcpProbeWalk(specs, principal, now = Date.now) {
189
207
  answer.catch(() => undefined);
190
208
  return { answer, dials };
191
209
  }
210
+ function probeDeclarations(input, desk) {
211
+ switch (input.declaredBy) {
212
+ case "deployment":
213
+ return { specs: input.specs };
214
+ case "caller": {
215
+ const lease = desk.lease("probe");
216
+ try {
217
+ return { specs: input.drafts.map((draft) => mintDeclaration(desk, draft, lease)), lease };
218
+ }
219
+ catch (err) {
220
+ lease.release();
221
+ throw err;
222
+ }
223
+ }
224
+ default: {
225
+ const unknownArm = input;
226
+ void unknownArm;
227
+ throw new Error("mcp probe: an input arm this module does not know (the arm set is closed: deployment / caller)");
228
+ }
229
+ }
230
+ }
192
231
  export class McpProbeMisaligned extends Error {
193
232
  constructor(message) {
194
233
  super(message);
@@ -85,7 +85,7 @@ export interface ScenarioContext {
85
85
  /**
86
86
  * [ref] / [ref]:**委派树根的见证**(停驻挂点的属主来源)—— 根会话 id + 调用方判断那一刻读到的根行住客(`delegated-session-owner.ts` 的 `DelegationRootWitness`)。
87
87
  * 由**每一个**接了停驻挂点的取用方显式交出(一条读法,没有回落):请求腿 = 本请求经鉴权解析的会话与受理时那一读(`boot/resolve-spec.ts`);`/decide` 赎回面 = 行上的
88
- * `rootSessionId` 与赎回腿 claim 前后两读的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它**只**喂停驻挂点,不挂任何会话级设施(那是 {@link sessionId} 的事,
88
+ * `rootSessionId` 与赎回腿写口放行的那一位住客(`parked-revive-surface.ts`,交不交座都交)。它**只**喂停驻挂点,不挂任何会话级设施(那是 {@link sessionId} 的事,
89
89
  * 判据是「这只 bundle 是不是在那只会话上取用的」,与属主来源是两个独立判据)。缺席 = 没有根可交(boot 期探针、run-local、行上没有根)⇒ 律给哨兵。
90
90
  * 挂点在停驻那一刻再读一次根行:住客不是见证的那一位(删了、同 id 被重新登记)⇒ 停驻否决 —— 不按新住客晋升或认领。
91
91
  */
@@ -33,12 +33,13 @@ export declare const CAPABILITY_FACT_WHY: {
33
33
  readonly subagent_output_face_absent: "the background sub-agent output face is not wired";
34
34
  readonly task_handle_faces_absent: "the background task-handle output/stop faces are not wired";
35
35
  readonly session_head_face_absent: "the session store has no by-id head read (sessionStorage.headOf — owner, occupant and leaf of a session row in one read)";
36
+ readonly execution_placement_seat_absent: "the session store has no execution placement seat (sessionStorage.executionPlacement — the occupant and the execution placement cell of a root session row in one read)";
36
37
  readonly checkpoint_store_absent: "no durable checkpoint store is wired (DURABLE_APPROVAL)";
37
38
  readonly session_audit_absent: "no session audit view is wired (needs a durable session store)";
38
39
  readonly session_watch_absent: "the session watch registry is not wired";
39
40
  readonly session_lister_absent: "no session enumerator is wired (session store or run store listSessions)";
40
41
  readonly session_fork_face_absent: "the session store has no fork face";
41
- readonly session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / patchSessionMeta)";
42
+ readonly session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / writeSessionRowCells)";
42
43
  readonly session_purge_absent: "no session purge coordinator is wired";
43
44
  readonly session_policy_store_absent: "no session policy store is wired";
44
45
  readonly store_backend_absent: "no store backend is wired (DB_BACKEND=memory, multi-tenant bare boot, or half-configured SQL)";
@@ -87,6 +88,7 @@ export declare const CAPABILITY_FACT_WHY: {
87
88
  readonly not_k8s_lane: "the execution lane is not the k8s pod sandbox (REMOTE_EXEC=k8s)";
88
89
  readonly workspace_snapshot_store_absent: "no workspace snapshot store is configured (MINIO_ENDPOINT / MINIO_ACCESS_KEY / MINIO_SECRET_KEY)";
89
90
  readonly workspace_cache_off: "the build-cache volume per workspace space is off (WORKSPACE_CACHE=off, the default)";
91
+ readonly deployment_mod_packages_absent: "no operator-declared mod package was loaded at boot (MODS_ROOT / MODS_PACKAGES)";
90
92
  };
91
93
  export type CapabilityFactWhy = keyof typeof CAPABILITY_FACT_WHY;
92
94
  /** 不可用臂。 */
@@ -127,6 +129,13 @@ type HeadReadingSessionStore = WithMethods<OwnerAwareSessionStore, "headOf">;
127
129
  export declare function sessionOwnership(d: Pick<Deps, "sessionStorage">): Fact<"session_head_face_absent", {
128
130
  sessionStorage: HeadReadingSessionStore;
129
131
  }>;
132
+ /**
133
+ * 执行放置读面在场:会话店带执行席(`executionPlacement`:一次行读 = 住客 + 执行放置格;SQL 两孪生与 local 恒带,引擎缺省的内存会话店没有)。
134
+ * 见证 = 那只席 —— `GET /v1/sessions/:id/execution-placement` 读它,且只读它(属主门判这一读的住客)。
135
+ */
136
+ export declare function executionPlacementRead(d: Pick<Deps, "sessionStorage">): Fact<"execution_placement_seat_absent", {
137
+ seat: NonNullable<OwnerAwareSessionStore["executionPlacement"]>;
138
+ }>;
130
139
  export declare function mcpReconnect(d: Pick<Deps, "runStore" | "sessionStorage">): Fact<"run_store_absent" | "session_head_face_absent", {
131
140
  runStore: Store<"runStore">;
132
141
  sessionStorage: HeadReadingSessionStore;
@@ -147,11 +156,11 @@ export declare function sessionList(d: Pick<Deps, "sessionStorage" | "runStore">
147
156
  export declare function sessionFork(d: Pick<Deps, "sessionStorage">): Fact<"session_fork_face_absent" | "session_head_face_absent", {
148
157
  sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "fork">;
149
158
  }>;
150
- /** 会话行可写位(`PATCH /v1/sessions/:id`):会话店的头读(属主 + 化身一次读 —— 门判属主、写与读回按化身条件)∧ 行写口(写后按同一住客读回)。
159
+ /** 会话行可写位(`PATCH /v1/sessions/:id`):会话店的头读(属主 + 化身一次读 —— 门判属主,那一读就是写原语的行期望)∧ 行格写原语(锁内判、提交后另读应答行)。
151
160
  * 三只 durable 店(SQL 双生 / local)都带;内存 dev 店没有行写口 ⇒ 501。
152
- * 本面**没有**独立能力位(契约附录 B.2c 登记):老 worker 对这一动词答 405,本事实为假的部署答 501。 */
161
+ * 本面**没有**独立能力位(契约附录 B.2c 登记):老 worker 对这一动词答 405,本事实为假的部署答 501;条件写也没有 —— 列表行上有 `rowTag` 即支持。 */
153
162
  export declare function sessionPatch(d: Pick<Deps, "sessionStorage">): Fact<"session_row_faces_absent", {
154
- sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "patchSessionMeta">;
163
+ sessionStorage: WithMethods<OwnerAwareSessionStore, "headOf" | "writeSessionRowCells">;
155
164
  }>;
156
165
  export declare function sessionDelete(d: Pick<Deps, "purgeSession" | "sessionStorage">): Fact<"session_purge_absent" | "session_head_face_absent", {
157
166
  purge: Store<"purgeSession">;
@@ -161,11 +170,11 @@ export declare function sessionPolicy(d: Pick<Deps, "sessionPolicyStore" | "sess
161
170
  policyStore: Store<"sessionPolicyStore">;
162
171
  sessionStorage: HeadReadingSessionStore;
163
172
  }>;
164
- type SyncSessionStore = WithMethods<OwnerAwareSessionStore, "exportEntries" | "exportEntriesStream" | "beginImportStaging" | "headOf" | "sessionSummaryOf" | "patchSessionMeta">;
173
+ type SyncSessionStore = WithMethods<OwnerAwareSessionStore, "exportEntries" | "exportEntriesStream" | "beginImportStaging" | "headOf" | "sessionSummaryOf" | "writeSessionRowCells">;
165
174
  type SessionSyncWhy = "store_backend_absent" | "file_history_store_absent" | "session_export_absent" | "session_import_staging_absent" | "session_row_faces_absent" | "policy_purge_absent";
166
175
  /** 会话对等同步的**对话半族**(manifest / entries / plan / import 两相):后端 ∧ 文件历史店 ∧ 导出两面 ∧ staged 导入面 ∧
167
- * 会话行三口(门读头 `headOf` —— 属主 + 化身一次读,属主判门、化身给 identical 短路腿;manifest 带 `title` / `pinned`;导入经唯一写口按导入落定的
168
- * 那一位住客重放它们)∧ policy 店能清(overwrite-dst 的 commit 要擦目的端旧 policy 行)。
176
+ * 会话行三口(门读头 `headOf` —— 属主 + 化身一次读,属主判门、化身给 identical 短路腿;manifest 带 `title` / `pinned`;导入经行格写原语以 `replay` 写者
177
+ * 按导入落定的那一位住客重放它们)∧ policy 店能清(overwrite-dst 的 commit 要擦目的端旧 policy 行)。
169
178
  * 文件历史的 blob 搬运是另一只事实。 */
170
179
  export declare function sessionSync(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy, {
171
180
  backend: Store<"backend">;
@@ -355,6 +364,11 @@ export declare function workspaceSpace(c: Pick<ServiceConfig, "remoteExec">): Fa
355
364
  export declare function workspaceCache(c: Pick<ServiceConfig, "remoteExec">): Fact<"not_k8s_lane" | "workspace_cache_off", {
356
365
  cache: WorkspaceCacheCapability;
357
366
  }>;
367
+ /** 运维声明的 mod 包:本进程起服装上了几只(部署座装配口 `assembleDeploymentMods` 的读数;本服务自铸的部署注册不算)。
368
+ * `/health.mods.deploymentPackages`(投 `count`)与 caps `modsDeploymentPackages`(投 `.available`,false ⇒ 键缺席)同调这一只。 */
369
+ export declare function deploymentModPackages(d: Pick<Deps, "deploymentModPackages">): Fact<"deployment_mod_packages_absent", {
370
+ count: number;
371
+ }>;
358
372
  /** 自唤醒调度器挂在宿主 env 上:`SCHEDULER_ENABLED` ∧ 单用户 ∧ host 车道。装配(`boot/execution-env.ts`)与能力位同调。 */
359
373
  export declare function hostScheduler(c: Pick<ServiceConfig, "schedulerEnabled" | "requirePrincipal" | "remoteExec">): Fact<"scheduler_disabled" | "multi_tenant_deployment" | "not_host_lane">;
360
374
  /** 引擎能力词的事实(core `ENGINE_CAPABILITIES` 每词一只谓词,值 = 本进程的事实;`/v1/capabilities` 以顶层布尔键展开它们)—— 住在
@@ -13,12 +13,13 @@ export const CAPABILITY_FACT_WHY = {
13
13
  subagent_output_face_absent: "the background sub-agent output face is not wired",
14
14
  task_handle_faces_absent: "the background task-handle output/stop faces are not wired",
15
15
  session_head_face_absent: "the session store has no by-id head read (sessionStorage.headOf — owner, occupant and leaf of a session row in one read)",
16
+ execution_placement_seat_absent: "the session store has no execution placement seat (sessionStorage.executionPlacement — the occupant and the execution placement cell of a root session row in one read)",
16
17
  checkpoint_store_absent: "no durable checkpoint store is wired (DURABLE_APPROVAL)",
17
18
  session_audit_absent: "no session audit view is wired (needs a durable session store)",
18
19
  session_watch_absent: "the session watch registry is not wired",
19
20
  session_lister_absent: "no session enumerator is wired (session store or run store listSessions)",
20
21
  session_fork_face_absent: "the session store has no fork face",
21
- session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / patchSessionMeta)",
22
+ session_row_faces_absent: "the session store has no session-row faces (headOf / sessionSummaryOf / writeSessionRowCells)",
22
23
  session_purge_absent: "no session purge coordinator is wired",
23
24
  session_policy_store_absent: "no session policy store is wired",
24
25
  store_backend_absent: "no store backend is wired (DB_BACKEND=memory, multi-tenant bare boot, or half-configured SQL)",
@@ -67,6 +68,7 @@ export const CAPABILITY_FACT_WHY = {
67
68
  not_k8s_lane: "the execution lane is not the k8s pod sandbox (REMOTE_EXEC=k8s)",
68
69
  workspace_snapshot_store_absent: "no workspace snapshot store is configured (MINIO_ENDPOINT / MINIO_ACCESS_KEY / MINIO_SECRET_KEY)",
69
70
  workspace_cache_off: "the build-cache volume per workspace space is off (WORKSPACE_CACHE=off, the default)",
71
+ deployment_mod_packages_absent: "no operator-declared mod package was loaded at boot (MODS_ROOT / MODS_PACKAGES)",
70
72
  };
71
73
  const no = (why) => ({ available: false, why });
72
74
  const yes = (w) => ({ available: true, ...w });
@@ -98,6 +100,10 @@ export function sessionOwnership(d) {
98
100
  const s = d.sessionStorage;
99
101
  return headReadOf(s) !== undefined ? yes({ sessionStorage: s }) : no("session_head_face_absent");
100
102
  }
103
+ export function executionPlacementRead(d) {
104
+ const seat = d.sessionStorage?.executionPlacement;
105
+ return seat !== undefined ? yes({ seat }) : no("execution_placement_seat_absent");
106
+ }
101
107
  export function mcpReconnect(d) {
102
108
  const runs = durableRuns(d);
103
109
  if (!runs.available)
@@ -132,7 +138,7 @@ export function sessionFork(d) {
132
138
  }
133
139
  export function sessionPatch(d) {
134
140
  const s = d.sessionStorage;
135
- if (headReadOf(s) === undefined || s?.patchSessionMeta === undefined)
141
+ if (headReadOf(s) === undefined || s?.writeSessionRowCells === undefined)
136
142
  return no("session_row_faces_absent");
137
143
  return yes({ sessionStorage: s });
138
144
  }
@@ -162,7 +168,7 @@ export function sessionSync(d) {
162
168
  return no("session_export_absent");
163
169
  if (s.beginImportStaging === undefined)
164
170
  return no("session_import_staging_absent");
165
- if (headReadOf(s) === undefined || s.sessionSummaryOf === undefined || s.patchSessionMeta === undefined)
171
+ if (headReadOf(s) === undefined || s.sessionSummaryOf === undefined || s.writeSessionRowCells === undefined)
166
172
  return no("session_row_faces_absent");
167
173
  if (overwriteWipeIncapable(d.sessionPolicyStore))
168
174
  return no("policy_purge_absent");
@@ -391,6 +397,10 @@ export function workspaceCache(c) {
391
397
  return no("workspace_cache_off");
392
398
  return yes({ cache: { mount: rx.workspaceCache.mount, size: rx.workspaceCache.size } });
393
399
  }
400
+ export function deploymentModPackages(d) {
401
+ const n = d.deploymentModPackages;
402
+ return n !== undefined && n > 0 ? yes({ count: n }) : no("deployment_mod_packages_absent");
403
+ }
394
404
  export function hostScheduler(c) {
395
405
  if (c.schedulerEnabled !== true)
396
406
  return no("scheduler_disabled");
@@ -7,15 +7,22 @@ export declare const MAX_CHECKPOINT_ID_CHARS = 128;
7
7
  export declare function withoutCheckpointToken(text: string, token: unknown): string;
8
8
  /** 持久层读出的 `checkpointId` 过信任边界:是串、非空、不超长、不含 token(大小写不敏感)⇒ 原值;否则 `undefined`。判据全文见本文件头注。 */
9
9
  export declare function trustedCheckpointId(raw: unknown, token: unknown): string | undefined;
10
- /** 带 `checkpointId` 当 join 键的 durable 面(计数 detail 的 `face`):运维队列行、停驻收件行,与 7.137.0 起的 park 账本行(`GET /v1/runs/:id/events` 的 `suspended` / `needs_review`,写时判一次)。 */
11
- export type DurableCheckpointFace = "approvals-queue" | "assistant-inbox" | "run-events-park";
10
+ /**
11
+ * 带 `checkpointId` 当 join 键的面(计数 detail 的 `face`):运维队列行、停驻收件行、park 账本行(`GET /v1/runs/:id/events` 的 `suspended` /
12
+ * `needs_review`,写时判一次),与回决门族的 200 体(`decision-receipt`:`/decide` / `/resume` / `/plan_review` 执行**前**从选中的那一行捕获一次,
13
+ * 结清证据带它 —— 语义属主 = `gate-settlement.ts`)。四面同一只读法、同一个计数。
14
+ */
15
+ export type DurableCheckpointFace = "approvals-queue" | "assistant-inbox" | "run-events-park" | "decision-receipt";
16
+ /** 一行的身份片段:读得出可信值 ⇒ `{ checkpointId }`;读不出 ⇒ `{}`(键缺席)。由调用方原样展开进行投影 / 结清证据。 */
17
+ export type GateIdentity = {
18
+ readonly checkpointId?: string;
19
+ };
12
20
  /**
13
21
  * durable 读面的一行 → 它的身份片段,**由调用方原样展开进行投影**(`...durableRowIdentity(face, raw, token)`):读得出可信值 ⇒ `{ checkpointId }`;
14
22
  * 读不出 ⇒ `{}`(这一行**照列**,键缺席)+ 计一次(见本文件头注「durable 面的 join 键」)。
15
23
  * `raw === undefined` = 行上没有这一格(`why=absent`,老行);在场却没过信任边界(非串 / 空串 / 超长 / 含 token / 读不出)= `why=untrusted`。
16
- * 三处读面(两只店的 `listPending` + 收件 handler)与 park 账本行的唯一构造器(`trace/project.ts` 的 `parkEventData`)只经这一只 —— 读法、计数、缺席形各只有一份。
24
+ * 三处读面(两只店的 `listPending` + 收件 handler)、park 账本行的唯一构造器(`trace/project.ts` 的 `parkEventData`)与回决门族三条续跑腿的执行前捕获点
25
+ * (`http/resume-legs.ts`:`/decide` 在分流之前一次、`/resume`、`/plan_review`)只经这一只 —— 读法、计数、缺席形各只有一份。
17
26
  */
18
- export declare function durableRowIdentity(face: DurableCheckpointFace, raw: unknown, token: unknown): {
19
- readonly checkpointId?: string;
20
- };
27
+ export declare function durableRowIdentity(face: DurableCheckpointFace, raw: unknown, token: unknown): GateIdentity;
21
28
  //# sourceMappingURL=checkpoint-identity.d.ts.map
@@ -109,7 +109,7 @@ export const CONFIG_CATALOG = [
109
109
  r("CONFIG_LKG_PATH", "integrations", "path", "LKG 落盘路径(设了 ⇒ 派生一条读拒行 = 这条绝对路径:根锚定,只守这一个文件,经符号链接的目录时引擎沿链连目标一起守;大小写不敏感;用户仓里同尾的路径读得到;空串拒启)", { derivedDefaultNote: "缺席 ⇒ 配置根(SEMA_CONFIG_DIR,缺省 ~/.sema)下按 worker + 凭证身份分箱派生", configKey: "configLkgPath" }),
110
110
  r("CONFIG_LOCAL_DIR", "integrations", "path", "本地配置源根(config.d/<domain>.json);兼作数据根回落链一环", { configKey: "configLocalDir", danger: DATA }),
111
111
  r("CONFIG_LOCAL_OWNER_UID", "integrations", "number", "本地配置源读之前的目录信任判官多信的那一个属主 uid(本服务用户与 root 之外 —— userns-remap 的 bind-mount、运维用户持有的配置);只放宽属主判据,组 / 他人可写照拒;形错拒启", { configKey: "configLocalOwnerUid", danger: SEC, derivedDefaultNote: "缺席 = config.d 路径上的目录与文档只许属于本服务用户或 root" }),
112
- r("CONFIG_PROVIDER", "integrations", "enum", "配置源双模选择(闭集,逐字比较;认不出的词 ⇒ 拒启,S-841)", { enumValues: CONFIG_PROVIDER_WORDS, derivedDefaultNote: `缺席:${WEB_ADMIN_ENV.url} 在场 ⇒ remote,否则纯 env(无管道)`, configKey: "configProvider" }),
112
+ r("CONFIG_PROVIDER", "integrations", "enum", `配置源双模选择(闭集,逐字比较;认不出的词 ⇒ 拒启;remote 而 ${WEB_ADMIN_ENV.url} 缺席 ⇒ 拒启 —— remote 的配置只来自那只中心)`, { enumValues: CONFIG_PROVIDER_WORDS, derivedDefaultNote: `缺席:${WEB_ADMIN_ENV.url} 在场 ⇒ remote,否则纯 env(无管道)`, configKey: "configProvider" }),
113
113
  r("CONFIG_REQUIRE_ROSTER", "integrations", "boolean", "远程 registry 非 dryRun 时布防 ready 门:roster 未落地 ⇒ 计费提交 503 + /health ready:false(严格 'true')", { staticDefault: "false" }),
114
114
  r("CORS_ORIGIN", "auth", "csv", "CORS 白名单(单值 v1 兼容回显;多值按请求 Origin 匹配 + Vary;未设=无 CORS 面)", { danger: SEC, configKey: "corsOrigins" }),
115
115
  r("COST_QUOTA_WINDOW_SEC", "limitsHttp", "number", "per-principal 成本配额窗长(秒);SQL 腿窗长进桶主键 ⇒ center 腿显式 deferred(重启生效)", { staticDefault: "86400", danger: BILL, configKey: "costQuotaWindowSec", center: cLimits("costQuotaWindowSec", { timing: "restart", restartReason: "cost-quota-window" }) }),
@@ -139,7 +139,7 @@ export const CONFIG_CATALOG = [
139
139
  r("DOCKER_NETWORK", "orchestration", "enum", "local-docker 容器网络模式", { enumValues: ["none", "bridge", "host"], staticDefault: "bridge", danger: SEC }),
140
140
  r("DOCKER_PATH", "orchestration", "path", "docker 二进制路径"),
141
141
  r("DOCKER_PIDS_LIMIT", "orchestration", "number", "local-docker fork-bomb 背栓(--pids-limit;非法值回 adapter 默认 512+warn)", { danger: SEC, derivedDefaultNote: "缺席 ⇒ adapter 默认 512" }),
142
- r("DOCKER_SANDBOX_ENV", "orchestration", "secret", "local-docker 车道每条 docker exec 以 -e 注入的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/日志;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
142
+ r("DOCKER_SANDBOX_ENV", "orchestration", "secret", "local-docker 车道每条 docker exec 以 -e 注入的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/日志;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮 / 点名本服务自有凭据名(会把本服务的凭据装进模型读得到的沙箱;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
143
143
  r("DRAIN_GRACE_MS", "limitsHttp", "number", "SIGTERM 优雅排空窗(ms;期间新计费提交 503+Retry-After)。出厂默认是**服务器部署**的取值;壳自 spawn 的引擎会被壳注入更短的窗 ⇒ 排壳形关机预算时以本行的 effectiveValue(= 本进程实际生效值)为准,不照抄 staticDefault", { staticDefault: String(10 * 60 * 1000), configKey: "drainGraceMs", center: cLimits("drainGraceMs") }),
144
144
  r("DRAIN_SECOND_SIGNAL_MIN_GAP_MS", "limitsHttp", "number", `排空期「第二发信号 = 硬停」的最小间隔(ms;锚 = 本次排空的第一发停止信号 —— SIGTERM / SIGHUP 升级进的排空,入口那一发就是它;排空口 / 租约被拒 / 附着租约自退进的排空,到达的第一发被吸收、不缩短期限。SIGTERM / SIGINT 与锚相隔不足 ⇒ 同一拍的重复投递,一行 drain_duplicate_signal_ignored 后忽略、排空继续;0 = 关,恒按第二发硬停;须为 [${DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS.minMs}, ${DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS.maxMs}] 内十进制整数(上界 = DRAIN_GRACE_MS 地板),小数 / 负数 / 越界拒启)`, { staticDefault: String(DRAIN_SECOND_SIGNAL_MIN_GAP_DEFAULT_MS), configKey: "drainSecondSignalMinGapMs" }),
145
145
  r("DURABLE_APPROVAL", "approval", "boolean", "durable suspend/resume HITL(需 SQL 店;决定 checkpointStore 与 /v1/approvals 面的存在性)", { danger: SEC, derivedDefaultNote: "posture 三态(S-178):显式词恒赢,缺席 = 单用户(REQUIRE_PRINCIPAL≠true)且有耐久店 ⇒ on / 多租户或无耐久店 ⇒ off;生效来源见 GET /v1/diagnostics/wiring 的 serverGates.durableApproval.source", configKey: "durableApproval" }),
@@ -151,7 +151,7 @@ export const CONFIG_CATALOG = [
151
151
  r("E2B_LIVENESS_MS", "orchestration", "number", LIVENESS_KNOB_SEMANTICS("e2b"), { derivedDefaultNote: LIVENESS_KNOB_DEFAULT_NOTE }),
152
152
  r("E2B_MOUNT_PATH", "orchestration", "path", "e2b 工作区根(resume 用当前值,改前先 drain 挂起任务)"),
153
153
  r("E2B_ORPHAN_RECLAIM", "orchestration", "boolean", "崩溃遗留沙盒回收腿(boot 一次+周期;判据保守,拿不准恒不杀)", { staticDefault: "true", danger: BILL }),
154
- r("E2B_SANDBOX_ENV", "orchestration", "secret", "转发进 e2b 沙箱的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/事件日志;与 LSP_ENV_ALLOW / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
154
+ r("E2B_SANDBOX_ENV", "orchestration", "secret", "转发进 e2b 沙箱的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值不进 spec/center/事件日志;与 LSP_ENV_ALLOW / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮 / 点名本服务自有凭据名(会把本服务的凭据装进模型读得到的沙箱;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)", { danger: SEC }),
155
155
  r("E2B_SANDBOX_MAX_MS", "orchestration", "number", "e2b 沙箱最长存活(ms)", { staticDefault: "3600000", danger: BILL }),
156
156
  r("E2B_TEMPLATE", "orchestration", "string", "e2b 模板名(缺省 adapter 基础模板)"),
157
157
  r("E2B_TIMEOUT_MS", "orchestration", "number", "e2b 单命令总超时(ms)"),
@@ -167,7 +167,11 @@ export const CONFIG_CATALOG = [
167
167
  r("FLEET_LEASE_OUTAGE_MAX_MS", "integrations", "number", "一台实例「活着而不服务」的最长时长 T_max(ms),两处读它:① 服务租约中心不可达的容忍上限 —— 租约过期满这么久 ⇒ 新计费提交 503 state.lease_expired(取消 / HITL 应答 / 续跑 / 读面照放行,在飞不动,/readyz 不翻),只在 fleet 成员 ∧ 中心宣告 servingLease 能力位时生效;② 排空口 POST /v1/admin/drain 的期限上界 —— deadlineAt 离此刻超过它 ⇒ 400 request.field_invalid,成员与非成员同读;< 60000(租约 TTL 地板)或非整数拒启", { danger: SEC, staticDefault: String(FLEET_LEASE_OUTAGE_MAX_DEFAULT_MS), configKey: "fleetLeaseOutageMaxMs" }),
168
168
  r("FLEET_SCOPE", "integrations", "string", "本引擎所在的租户 scope(配置渲染器对每台受管引擎写,缺省 scope 也写;手接的引擎缺席 = 缺省 scope;唯一读者 = 排空口 POST /v1/admin/drain 的身份比对,请求不带 scope 也读成缺省 scope)。在场必须是 scope id 形(小写字母 / 数字 / 内部连字符,1–64;空串拒启);与 FLEET_GENERATION 不联动(成员缺席 ⇒ 缺省 scope)。续租体与心跳不带它(scope 由中心凭证绑定)", { danger: SEC, staticDefault: GLOBAL_SCOPE, configKey: "fleetScope" }),
169
169
  r("FORK_ENABLED", "orchestration", "boolean", "CC /fork(core Fork 工具)装配开关", { derivedDefaultNote: "posture 三态:缺席 = 单用户 ⇒ on / 多租户 ⇒ off(per-principal entitlement 另判)", configKey: "forkEnabled" }),
170
- r("GATEWAY_MAX_RETRIES", "modelPlane", "number", "openai 兼容腿每次调用重试上限", { derivedDefaultNote: "缺席 ⇒ 不传引擎,引擎默认当家" }),
170
+ r("GATEWAY_MAX_RETRIES", "modelPlane", "number", "openai 兼容腿每次调用重试上限", {
171
+ derivedDefaultNote: "缺席 ⇒ 按外层拓扑分两态(启动日志 `brain` 字段的 `gatewayRetryCap` 回显哪一态):配了备用网关(`MODEL_GATEWAY_FALLBACK_URLS`)/ 开了断路器开关(`MODEL_CIRCUIT_BREAKER`,单路网关上也算)/ 开了反应式降级(配着 `MODEL_DEGRADE_TO` 且 `MODEL_DEGRADE_REACTIVE` 开)" +
172
+ "⇒ 网关各路 server 传 2(`fast-fail:2`),引擎的 `SEMA_MAX_RETRIES` 被遮蔽(降级兜底腿不吃这条收窄:不设时它不传,引擎默认当家);没有这些快切层 ⇒ 不传(`engine-default`),引擎默认当家(读 `SEMA_MAX_RETRIES`,没设是 10)。" +
173
+ "设了恒赢(`env:<n>`):原样传给引擎(降级兜底腿也吃显式值)并遮蔽 `SEMA_MAX_RETRIES`",
174
+ }),
171
175
  r("GIT_API_BASEURL", "integrations", "url", "repo 工具的 Git host API base", { configKey: "gitApiBaseUrl" }),
172
176
  r("GIT_API_KIND", "integrations", "enum", "Git host API 方言", { enumValues: ["gitea", "github"], staticDefault: "gitea", configKey: "gitApiKind" }),
173
177
  r("GIT_API_TOKEN", "integrations", "secret", "repo 工具的 Git host 凭据", { danger: SEC }),
@@ -204,10 +208,10 @@ export const CONFIG_CATALOG = [
204
208
  r("K8S_LIVENESS_MS", "orchestration", "number", LIVENESS_KNOB_SEMANTICS("k8s"), { derivedDefaultNote: LIVENESS_KNOB_DEFAULT_NOTE }),
205
209
  r("K8S_MEMORY", "orchestration", "string", "沙箱 pod 内存限额(2Gi 默认曾被真 OOM)"),
206
210
  r("K8S_MOUNT_PATH", "orchestration", "path", "k8s 工作区挂载路径"),
207
- r("K8S_NAMESPACE", "orchestration", "string", "沙箱 pod namespace"),
211
+ r("K8S_NAMESPACE", "orchestration", "string", "沙箱 pod 所在的 namespace(REMOTE_EXEC=k8s 必需件,与 K8S_SANDBOX_IMAGE 同级:缺席、空串或只有空白 ⇒ 起服拒,拒句点名本旋钮;服务不带内置缺省 —— 部署的声明是唯一来源,随包 chart 已显式设为 sandbox.namespace;只在 REMOTE_EXEC=k8s 被选中时求值)"),
208
212
  r("K8S_RUNTIME_CLASS", "orchestration", "string", "沙箱 pod runtimeClass(Kata 等)"),
209
213
  r("K8S_SANDBOX_BROKER_IMAGE", "orchestration", "string", "成员 git 凭据代理容器的镜像(k8s 沙箱 pod 的 containers[1],只挂在成员 run 的 pod 上;建议填本引擎自身镜像 —— 代理是本包里固定路径的一只程序,命令固定);不设 ⇒ 成员 git 凭据平面关(GET /v1/capabilities 的 credentialPlane.sandboxGit = broker_image_unset),任何 pod 都不挂代理,pod 形逐字节同不设时;只在 REMOTE_EXEC=k8s 被选中时求值"),
210
- r("K8S_SANDBOX_ENV", "orchestration", "secret", `转发进 k8s 沙箱 pod 容器 env 的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值只进该 pod 自己的 Secret —— pod spec 的容器 env 只带 secretKeyRef 引用、不带值,Secret 随 pod 由集群回收;不进工作区 / 快照 / center / 事件日志;沙箱命名空间的 Role 要 secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")},起服问不许即拒启;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;与包源派生 env 撞名时显式名单胜;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)`, { danger: SEC }),
214
+ r("K8S_SANDBOX_ENV", "orchestration", "secret", `转发进 k8s 沙箱 pod 容器 env 的本进程 env 点名表(NAME,NAME;点到的键从 worker env 原样取,值只进该 pod 自己的 Secret —— pod spec 的容器 env 只带 secretKeyRef 引用、不带值,Secret 随 pod 由集群回收;不进工作区 / 快照 / center / 事件日志;沙箱命名空间的 Role 要 secrets ${SANDBOX_SECRET_SEAT_VERBS.env.join(" / ")},起服问不许即拒启;与 LSP_ENV_ALLOW / E2B_SANDBOX_ENV / DOCKER_SANDBOX_ENV 同一只解析器与「点名放行」谓词:形错 / 点名名单型旋钮 / 点名本服务自有凭据名(会把本服务的凭据装进模型读得到的沙箱;判官 = 引擎拒白名单的同一只)拒启且不回显值;本进程环境里没有的名按序号 warn、不转发;与包源派生 env 撞名时显式名单胜;只在本车道被选中时求值;原文按凭据类对待:只回在场位、不进任何子进程)`, { danger: SEC }),
211
215
  r("K8S_SANDBOX_IMAGE", "orchestration", "string", "k8s 车道沙箱镜像(REMOTE_EXEC=k8s 必需件)"),
212
216
  r("K8S_SANDBOX_IPV6", "orchestration", "enum", "k8s 沙箱 pod 的 IPv6:disabled = pod 级 sysctl 关 IPv6(net.ipv6.conf.all / default.disable_ipv6=1;两只都不在 k8s 的 safe sysctl 表里 ⇒ 每个节点 kubelet 要 --allowed-unsafe-sysctls 点名,否则 pod 起不来;沙箱 ns 不能 enforce PodSecurity baseline / restricted);enabled = 不动 pod(pod 保留平台给的 IPv6,只执行 IPv4 的出网策略管不到它,起服自检每次一行 sandbox_egress_policy_gap{kind: ipv6_enabled});词表外拒启", { enumValues: SANDBOX_IPV6_WORDS, staticDefault: SANDBOX_IPV6_DEFAULT, danger: SEC }),
213
217
  r("K8S_TIMEOUT_MS", "orchestration", "number", "k8s 沙箱 pod 寿命(activeDeadlineSeconds,ms;整只 pod 的泄漏护栏,后台任务超时也被它钳;各条命令的超时见工具超时)"),
@@ -352,6 +356,8 @@ export const CONFIG_CATALOG = [
352
356
  },
353
357
  center: cModels("models[].vision"),
354
358
  }),
359
+ r("MODS_PACKAGES", "integrations", "opaque", "部署座装载的 mod 包声明(JSON 数组,每项闭集 { name, dir, tier, options? }:name = 包自己的名、逐字同;dir 绝对路径、真实路径须在 MODS_ROOT 之下且是目录;tier ∈ prepend / user / append 宿主必填;options 原样交包的 register)。读包只有引擎的读包者,本服务不读包内文件;形错 / 越根 / 读包者拒 / 名不同 / 引擎准入拒 ⇒ 拒启,一行拒句点名哪一席或哪只包(本服务写的句子不回显声明的值;读包者 / 准入交回的话原样透传、凭据形换记号,可能点名包目录);起服装配一次,改声明或换包要重启;本目录只回在场位与长度(不回显声明);options 不是凭据通道(本服务不替包扣凭据:宿主车道 inheritEnv \"all\" 下子进程照样继承这根旋钮与包自己读的变量)", { danger: SEC, derivedDefaultNote: "缺席 / 空串 = 不声明 ⇒ 部署座只有本服务自铸的注册,/health 与 /v1/capabilities 逐字节同没有这根旋钮的版本" }),
360
+ r("MODS_ROOT", "integrations", "path", "声明的 mod 包允许所在的根(绝对路径;包的真实路径按路径分量严格落在它的真实路径之下 —— 符号链接出根、前缀相似目录、.. 遍历、根本身都拒启;建议只读物料树)。声明了包而没设它 ⇒ 拒启;单设它而不声明包 = 无事(形照判)", { danger: SEC, configKey: "modsDeclaration", derivedDefaultNote: "缺席 ⇒ 不许声明任何包", resolve: (c) => c.modsDeclaration.root ?? null }),
355
361
  r("MYSQL_DATABASE", "store", "string", "MySQL 协议库名(选中该引擎时必填)", { danger: DATA }),
356
362
  r("MYSQL_HOST", "store", "string", "MySQL 协议主机(在场即算 SQL 信号,参与 DB_BACKEND 默认推导)", { danger: DATA }),
357
363
  r("MYSQL_PASSWORD", "store", "secret", "MySQL 协议口令", { danger: SEC }),
@@ -403,8 +409,8 @@ export const CONFIG_CATALOG = [
403
409
  r("RESOURCE_SUSPEND_TOTAL_TOKENS", "approval", "number", "跨片 token 总额(0=不设;与 MAX_TASK_TOKENS 的 per-slice 窗是两根轴)", { staticDefault: "0", danger: BILL, configKey: "resourceSuspendTotalTokens" }),
404
410
  r("RESOURCE_SUSPEND_TTL_SEC", "approval", "number", "resource/preempt checkpoint 的弃置 GC TTL(秒;0 ⇒ core 默认 30d)", { staticDefault: "0", danger: DATA, configKey: "resourceSuspendTtlSec" }),
405
411
  r("RETENTION_MAX_AGE_DAYS", "auth", "number", "托管留存期声明(core 启动期能力校验;真删除归 sweep lane)", { danger: DATA }),
406
- r("RETENTION_MODE", "auth", "enum", "留存 sweep 灰度档(拼错拒启 —— audit-only 谎成 enforce 两个方向都致命)", { enumValues: ["audit-only", "enforce"], staticDefault: "audit-only", danger: DATA, resolve: (c) => c.retentionSweep.mode }),
407
- r("RETENTION_SWEEP_INTERVAL_SEC", "auth", "number", "留存 sweep 节律(秒;0=lane 关)", { staticDefault: "0", danger: DATA }),
412
+ r("RETENTION_MODE", "auth", "enum", "留存 sweep 灰度档(拼错拒启 —— audit-only 谎成 enforce 两个方向都致命;enforce 而 RETENTION_MAX_AGE_DAYS 缺、或 RETENTION_SWEEP_INTERVAL_SEC 缺 / 为 0 ⇒ 拒启)", { enumValues: ["audit-only", "enforce"], staticDefault: "audit-only", danger: DATA, resolve: (c) => c.retentionSweep.mode }),
413
+ r("RETENTION_SWEEP_INTERVAL_SEC", "auth", "number", "留存 sweep 节律(秒;0=lane 关;> 0 而 RETENTION_MAX_AGE_DAYS 缺 ⇒ 拒启)", { staticDefault: "0", danger: DATA }),
408
414
  r("REWIND_SNAPSHOT_MAX_MB", "store", "number", "已退役(S-15 整树快照纪元退役):设了只 boot warn 一次,零行为", { envTiming: "inert" }),
409
415
  r("ROSTER_RETENTION_MS", "orchestration", "number", "agent_roster 行 TTL(ms;SQL twins 扩展面)", { staticDefault: String(30 * 24 * 60 * 60 * 1000), danger: DATA, configKey: "rosterRetentionMs" }),
410
416
  r("ROUTER_ENABLED", "orchestration", "boolean", "A 价值路由(per-task 编排自动决策;ship-dark)", { staticDefault: "false", configKey: "routerEnabled" }),