@sema-agent/server 7.150.0 → 7.151.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 (341) hide show
  1. package/MIGRATION.md +185 -0
  2. package/USAGE.md +53 -25
  3. package/deploy/sema-up/README.md +7 -1
  4. package/deploy/sema-up/chart/Chart.yaml +1 -1
  5. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  6. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  7. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  8. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  9. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  10. package/deploy/sema-up/chart/values.yaml +8 -1
  11. package/deploy/sema-up/cluster-up.sh +1 -0
  12. package/deploy/sema-up/kube-up.sh +1 -1
  13. package/deploy/sema-up/lib/flagshape.sh +1 -1
  14. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  15. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  16. package/dist/adoption/import.js +3 -3
  17. package/dist/approval-ask-machine.d.ts +1 -1
  18. package/dist/approval-card.d.ts +2 -2
  19. package/dist/approval-gate-currency.d.ts +1 -1
  20. package/dist/auth-bridge.d.ts +20 -0
  21. package/dist/auth-bridge.js +9 -0
  22. package/dist/background-session-reap.d.ts +1 -1
  23. package/dist/bake-runner/main.d.ts +4 -2
  24. package/dist/bind-host.d.ts +2 -3
  25. package/dist/bind-host.js +2 -4
  26. package/dist/boot/budget-tracing.js +1 -1
  27. package/dist/boot/engine-lease.d.ts +5 -0
  28. package/dist/boot/engine-lease.js +1 -0
  29. package/dist/boot/execution-env.d.ts +8 -14
  30. package/dist/boot/execution-env.js +54 -17
  31. package/dist/boot/execution-lane.js +32 -5
  32. package/dist/boot/late-binds.d.ts +8 -4
  33. package/dist/boot/late-binds.js +7 -1
  34. package/dist/boot/memory-consolidation.d.ts +3 -2
  35. package/dist/boot/memory-consolidation.js +6 -6
  36. package/dist/boot/reapers.d.ts +5 -0
  37. package/dist/boot/reapers.js +12 -1
  38. package/dist/boot/resolve-spec.d.ts +3 -3
  39. package/dist/boot/resolve-spec.js +31 -22
  40. package/dist/boot/runner-deps.d.ts +9 -2
  41. package/dist/boot/runner-deps.js +3 -3
  42. package/dist/boot/session-age-out.d.ts +36 -0
  43. package/dist/boot/session-age-out.js +101 -0
  44. package/dist/boot/session-faces.d.ts +5 -14
  45. package/dist/boot/session-faces.js +9 -5
  46. package/dist/boot/stage-01-config.js +2 -0
  47. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  48. package/dist/boot/stage-05-execution-env.js +2 -2
  49. package/dist/boot/stage-06-runners.d.ts +7 -4
  50. package/dist/boot/stage-06-runners.js +15 -6
  51. package/dist/boot/stage-07-capability-layer.d.ts +7 -4
  52. package/dist/boot/stage-07-capability-layer.js +2 -1
  53. package/dist/boot/stage-08-reapers.d.ts +7 -4
  54. package/dist/boot/stage-08-reapers.js +4 -2
  55. package/dist/boot/stage-09-leader.d.ts +11 -5
  56. package/dist/boot/stage-09-leader.js +12 -3
  57. package/dist/boot/stage-10-http-server.d.ts +11 -5
  58. package/dist/boot/stage-10-http-server.js +3 -6
  59. package/dist/boot/web-admin.js +3 -1
  60. package/dist/boot/workflow-orchestration.d.ts +7 -2
  61. package/dist/boot/workflow-orchestration.js +24 -7
  62. package/dist/bounded-rotation.d.ts +29 -0
  63. package/dist/bounded-rotation.js +24 -0
  64. package/dist/capability-facts.d.ts +22 -13
  65. package/dist/capability-facts.js +28 -18
  66. package/dist/center-credential.d.ts +25 -6
  67. package/dist/center-credential.js +25 -5
  68. package/dist/config-catalog.d.ts +26 -7
  69. package/dist/config-catalog.js +14 -11
  70. package/dist/config-invariants.d.ts +2 -1
  71. package/dist/config-invariants.js +4 -4
  72. package/dist/config-types.d.ts +10 -4
  73. package/dist/config.d.ts +51 -2
  74. package/dist/config.js +35 -24
  75. package/dist/deployment-shape.d.ts +9 -1
  76. package/dist/deployment-shape.js +2 -1
  77. package/dist/device-protocol.d.ts +5 -4
  78. package/dist/device-protocol.js +1 -1
  79. package/dist/device-ws-hub.js +3 -2
  80. package/dist/device-ws-protocol.d.ts +63 -10
  81. package/dist/device-ws-protocol.js +56 -25
  82. package/dist/engine-identity.d.ts +19 -7
  83. package/dist/engine-identity.js +10 -2
  84. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  85. package/dist/execution-env-refusal.d.ts +23 -0
  86. package/dist/execution-env-refusal.js +5 -0
  87. package/dist/execution-lane-caps.d.ts +3 -1
  88. package/dist/field-conflict.d.ts +1 -1
  89. package/dist/file-history-capture.d.ts +11 -4
  90. package/dist/file-history-capture.js +9 -6
  91. package/dist/file-history-disclosure.d.ts +7 -5
  92. package/dist/file-history-disclosure.js +7 -5
  93. package/dist/fleet/drain-entry.d.ts +4 -0
  94. package/dist/hooks/hook-runner.js +2 -2
  95. package/dist/host-lsp-manager.d.ts +2 -2
  96. package/dist/http/admission.js +17 -2
  97. package/dist/http/approval-sweeps.js +5 -5
  98. package/dist/http/checkpoint-ctx.d.ts +2 -0
  99. package/dist/http/checkpoint-ctx.js +1 -0
  100. package/dist/http/dispatch.d.ts +2 -1
  101. package/dist/http/dispatch.js +34 -27
  102. package/dist/http/durable-run-leg.js +16 -16
  103. package/dist/http/health-self-report.d.ts +9 -1
  104. package/dist/http/health-self-report.js +2 -0
  105. package/dist/http/owner-access.d.ts +31 -11
  106. package/dist/http/owner-access.js +37 -6
  107. package/dist/http/resume-ctx-read.js +25 -3
  108. package/dist/http/resume-legs.d.ts +2 -1
  109. package/dist/http/resume-legs.js +259 -79
  110. package/dist/http/route-ctx.d.ts +18 -8
  111. package/dist/http/route-table.d.ts +1 -1
  112. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  113. package/dist/http/routes/agents-roster.js +2 -3
  114. package/dist/http/routes/approvals-assistant.js +4 -3
  115. package/dist/http/routes/background.d.ts +3 -3
  116. package/dist/http/routes/capabilities.js +8 -5
  117. package/dist/http/routes/fleet.js +10 -8
  118. package/dist/http/routes/projects.d.ts +3 -2
  119. package/dist/http/routes/projects.js +4 -5
  120. package/dist/http/routes/runs.js +102 -36
  121. package/dist/http/routes/session-sync.d.ts +4 -3
  122. package/dist/http/routes/session-sync.js +172 -77
  123. package/dist/http/routes/sessions-list.js +13 -7
  124. package/dist/http/routes/sessions.js +10 -6
  125. package/dist/http/routes/tasks.js +30 -16
  126. package/dist/http/routes/trace-usage.js +2 -2
  127. package/dist/http/server.d.ts +21 -27
  128. package/dist/http/server.js +2 -2
  129. package/dist/http/submit-ctx.js +5 -4
  130. package/dist/http/wire-types.d.ts +14 -4
  131. package/dist/identity-source.d.ts +20 -3
  132. package/dist/identity-source.js +14 -0
  133. package/dist/index.d.ts +4 -0
  134. package/dist/lane-home-probe.d.ts +3 -7
  135. package/dist/lane-home-probe.js +0 -1
  136. package/dist/leader/leader.d.ts +2 -1
  137. package/dist/leg-facts.d.ts +13 -5
  138. package/dist/leg-facts.js +2 -1
  139. package/dist/memory-scope.d.ts +5 -4
  140. package/dist/memory-scope.js +4 -4
  141. package/dist/memory-sync-client.d.ts +30 -2
  142. package/dist/memory-sync-client.js +16 -9
  143. package/dist/observability/err-text.d.ts +7 -0
  144. package/dist/observability/err-text.js +5 -0
  145. package/dist/observability/fail-open.d.ts +7 -3
  146. package/dist/observability/fail-open.js +7 -3
  147. package/dist/observability/metrics.js +1 -0
  148. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  149. package/dist/orchestration/workflow-notify-journal.js +12 -1
  150. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  151. package/dist/orchestration/workflow-park-decision.js +49 -10
  152. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  153. package/dist/orchestration/workflow-park-holder.js +98 -0
  154. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  155. package/dist/orchestration/workflow-record-fence.js +42 -0
  156. package/dist/owner-faces.d.ts +1 -1
  157. package/dist/parked-decide.d.ts +104 -53
  158. package/dist/parked-decide.js +153 -117
  159. package/dist/peer-directory.d.ts +2 -2
  160. package/dist/peer-inbound-face.d.ts +2 -6
  161. package/dist/peer-inbound-face.js +0 -3
  162. package/dist/permission-mode-admission.d.ts +41 -5
  163. package/dist/permission-mode-admission.js +29 -3
  164. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  165. package/dist/plugins/adoption-log-sql.js +7 -1
  166. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  167. package/dist/plugins/approval-ask-store-file.js +8 -0
  168. package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
  169. package/dist/plugins/approval-ask-store-memory.js +28 -9
  170. package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
  171. package/dist/plugins/approval-ask-store-sql.js +34 -5
  172. package/dist/plugins/approval-exemption-store.js +3 -0
  173. package/dist/plugins/approval-nonce-store.js +2 -0
  174. package/dist/plugins/breaker-state-sql.js +2 -0
  175. package/dist/plugins/caching-session-store.d.ts +9 -15
  176. package/dist/plugins/caching-session-store.js +6 -0
  177. package/dist/plugins/device-store-sql.js +6 -0
  178. package/dist/plugins/error-origin.d.ts +18 -0
  179. package/dist/plugins/error-origin.js +10 -0
  180. package/dist/plugins/execution-placement-sql.js +6 -6
  181. package/dist/plugins/image-bake-store-sql.js +6 -0
  182. package/dist/plugins/image-index-sql.js +4 -0
  183. package/dist/plugins/landed-attendants.d.ts +212 -0
  184. package/dist/plugins/landed-attendants.js +161 -0
  185. package/dist/plugins/leader-run-store-sql.js +4 -0
  186. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  187. package/dist/plugins/local-session-live-reference.js +39 -0
  188. package/dist/plugins/local-session-store.d.ts +71 -33
  189. package/dist/plugins/local-session-store.js +129 -27
  190. package/dist/plugins/memory-engine-pg.js +4 -0
  191. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  192. package/dist/plugins/memory-engine-tidb.js +4 -0
  193. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  194. package/dist/plugins/memory-sync-store-pg.js +5 -0
  195. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  196. package/dist/plugins/one-time-migrations.d.ts +57 -63
  197. package/dist/plugins/one-time-migrations.js +162 -90
  198. package/dist/plugins/org-delivery-quota-store.js +4 -1
  199. package/dist/plugins/outcome-ledger-sql.js +2 -0
  200. package/dist/plugins/permission-rule-store-sql.js +11 -4
  201. package/dist/plugins/pg-cost-quota.js +4 -0
  202. package/dist/plugins/pg-pool.js +24 -1
  203. package/dist/plugins/pg-rate-limiter.js +2 -0
  204. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  205. package/dist/plugins/posix-shell-fs.js +4 -1
  206. package/dist/plugins/remote-env-adb.d.ts +19 -15
  207. package/dist/plugins/remote-env-adb.js +41 -15
  208. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  209. package/dist/plugins/remote-env-connect-seat.js +72 -0
  210. package/dist/plugins/remote-env-device.d.ts +22 -5
  211. package/dist/plugins/remote-env-device.js +106 -8
  212. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  213. package/dist/plugins/remote-env-e2b.js +42 -32
  214. package/dist/plugins/remote-env-file-error.js +6 -2
  215. package/dist/plugins/remote-env-host.d.ts +17 -0
  216. package/dist/plugins/remote-env-host.js +30 -38
  217. package/dist/plugins/remote-env-k8s.d.ts +41 -39
  218. package/dist/plugins/remote-env-k8s.js +53 -30
  219. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  220. package/dist/plugins/remote-env-local-docker.js +34 -41
  221. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  222. package/dist/plugins/remote-env-ssh.js +60 -59
  223. package/dist/plugins/remote-shell.d.ts +98 -1
  224. package/dist/plugins/remote-shell.js +218 -0
  225. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  226. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  227. package/dist/plugins/retention-lane-store-sql.js +4 -0
  228. package/dist/plugins/retention-sql.d.ts +20 -2
  229. package/dist/plugins/retention-sql.js +11 -0
  230. package/dist/plugins/run-store-sql.d.ts +21 -2
  231. package/dist/plugins/run-store-sql.js +31 -7
  232. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  233. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  234. package/dist/plugins/schema-consistency.d.ts +4 -2
  235. package/dist/plugins/schema-consistency.js +19 -2
  236. package/dist/plugins/send-file-ledger.js +3 -0
  237. package/dist/plugins/serving-requirement.d.ts +26 -7
  238. package/dist/plugins/serving-requirement.js +11 -4
  239. package/dist/plugins/session-birth.d.ts +6 -2
  240. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  241. package/dist/plugins/session-ext-table.d.ts +14 -1
  242. package/dist/plugins/session-ext-table.js +5 -1
  243. package/dist/plugins/session-row-sql.d.ts +49 -2
  244. package/dist/plugins/session-row-sql.js +56 -13
  245. package/dist/plugins/session-store-sql.d.ts +34 -18
  246. package/dist/plugins/session-store-sql.js +98 -17
  247. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  248. package/dist/plugins/shared-memory-store-sql.js +6 -2
  249. package/dist/plugins/sql-driver.d.ts +2 -1
  250. package/dist/plugins/sql-driver.js +18 -3
  251. package/dist/plugins/sql-errors.d.ts +11 -6
  252. package/dist/plugins/sql-errors.js +5 -6
  253. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  254. package/dist/plugins/stop-then-start-sentence.js +14 -10
  255. package/dist/plugins/stop-then-start.d.ts +109 -0
  256. package/dist/plugins/stop-then-start.js +104 -0
  257. package/dist/plugins/store-backend.d.ts +40 -13
  258. package/dist/plugins/store-backend.js +169 -27
  259. package/dist/plugins/store-boundary.d.ts +57 -0
  260. package/dist/plugins/store-boundary.js +139 -0
  261. package/dist/plugins/store-contracts.d.ts +17 -0
  262. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  263. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  264. package/dist/plugins/store-fault.d.ts +26 -7
  265. package/dist/plugins/store-fault.js +18 -2
  266. package/dist/plugins/task-attachment-store.js +9 -0
  267. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  268. package/dist/plugins/task-list-store-sql.js +10 -8
  269. package/dist/plugins/tidb-cost-quota.js +4 -0
  270. package/dist/plugins/tidb-pool.js +2 -1
  271. package/dist/plugins/tidb-rate-limiter.js +4 -0
  272. package/dist/plugins/user-input-ledger-sql.js +4 -0
  273. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  274. package/dist/plugins/workflow-run-store-sql.js +64 -4
  275. package/dist/plugins/workspace-fill.d.ts +4 -7
  276. package/dist/plugins/workspace-fill.js +2 -1
  277. package/dist/plugins/write-behind-counter.js +5 -0
  278. package/dist/project-context.d.ts +0 -2
  279. package/dist/project-context.js +4 -8
  280. package/dist/project-registry.d.ts +46 -0
  281. package/dist/project-registry.js +44 -0
  282. package/dist/request-key-closure.js +1 -1
  283. package/dist/request-value-closure.d.ts +4 -0
  284. package/dist/request-value-closure.js +10 -0
  285. package/dist/run-acceptance.d.ts +3 -2
  286. package/dist/run-acceptance.js +4 -6
  287. package/dist/run-local.js +1 -0
  288. package/dist/runs.d.ts +37 -8
  289. package/dist/runs.js +53 -12
  290. package/dist/runtime-governance.d.ts +5 -4
  291. package/dist/security.d.ts +30 -32
  292. package/dist/security.js +41 -7
  293. package/dist/server-secret-env.d.ts +12 -10
  294. package/dist/server-secret-env.js +24 -15
  295. package/dist/session-bindings.d.ts +82 -0
  296. package/dist/session-bindings.js +18 -0
  297. package/dist/session-children-retire.d.ts +2 -2
  298. package/dist/session-children-retire.js +2 -6
  299. package/dist/session-deletion.d.ts +16 -1
  300. package/dist/session-error-wire.d.ts +3 -3
  301. package/dist/session-error-wire.js +3 -3
  302. package/dist/session-incarnation.d.ts +10 -0
  303. package/dist/session-incarnation.js +10 -1
  304. package/dist/session-kind.d.ts +57 -0
  305. package/dist/session-kind.js +22 -0
  306. package/dist/session-row.d.ts +21 -1
  307. package/dist/session-row.js +7 -1
  308. package/dist/session-sync-kernel.d.ts +24 -14
  309. package/dist/session-sync-kernel.js +3 -6
  310. package/dist/session-sync.d.ts +4 -98
  311. package/dist/session-sync.js +1 -71
  312. package/dist/session-titler.d.ts +10 -3
  313. package/dist/session-titler.js +19 -6
  314. package/dist/ssh-host-key.d.ts +5 -0
  315. package/dist/ssh-host-key.js +3 -0
  316. package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
  317. package/dist/stores-sql/file-history-store-sql.js +108 -70
  318. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  319. package/dist/stores-sql/pg-session-storage.js +37 -13
  320. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  321. package/dist/stores-sql/retention-store-sql.js +2 -10
  322. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  323. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  324. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  325. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  326. package/dist/stores-sql/tidb-session-store.js +37 -13
  327. package/dist/submission-exit.d.ts +3 -2
  328. package/dist/submission-exit.js +9 -1
  329. package/dist/task-cwd.d.ts +2 -2
  330. package/dist/task-settings.d.ts +6 -5
  331. package/dist/terminal.d.ts +33 -2
  332. package/dist/terminal.js +139 -9
  333. package/dist/tool-approval.d.ts +140 -6
  334. package/dist/tool-approval.js +165 -72
  335. package/dist/trace/self-minted-wire.d.ts +290 -27
  336. package/dist/trace/self-minted-wire.js +101 -13
  337. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
  338. package/package.json +2 -2
  339. package/wire-changes/server@7.151.0.json +762 -0
  340. package/dist/http/session-inherit-env.d.ts +0 -36
  341. package/dist/http/session-inherit-env.js +0 -6
@@ -19,7 +19,7 @@ import type { QuestionThrottle } from "./question.js";
19
19
  import type { UnattendedApprovalPolicy } from "./tool-approval.js";
20
20
  import type { InfraCostRates } from "./observability/cost-taxonomy.js";
21
21
  import type { Autonomy, CommandRule } from "./runtime-governance.js";
22
- import type { CenterCredentialSource } from "./center-credential.js";
22
+ import type { CenterCredentialSource, DeclaredCredentialOrigin } from "./center-credential.js";
23
23
  import type { GitApiKind } from "./git-api-kind.js";
24
24
  import type { CustomPkgSource } from "./sandbox-pkg-source.js";
25
25
  import type { MemoryEngineBackend, StoreBackend as StoreBackendWord } from "@sema-agent/settings-schema/execution-lanes";
@@ -828,8 +828,9 @@ export interface ServiceConfigFlat {
828
828
  * models/roles; mutateInPlace keeps the reference. */
829
829
  tiers: Record<string, string>;
830
830
  /** 项目登记簿(settings-schema `projects` 域):键 = projectId(小写规范 UUID),值 = settings-schema 的 `ProjectRegistration` **原样**
831
- * (本仓不持第二份项目型、不挑键 —— 形与判官只在 settings-schema)。读者:`GET /v1/projects` 读面(`http/routes/projects.ts`);
832
- * `defaultScopes` 作 `TaskSpec.memory.scopes` 的种子(v2 scope 键串,OPEN 值域 —— 本表只登记不解释)与 org 记忆准入的部署 scope 集。
831
+ * (本仓不持第二份项目型、不挑键 —— 形与判官只在 settings-schema)。按调用方读(可见性判 + 按 id 取)只经 `project-registry.ts`:`GET /v1/projects` 读面
832
+ * (`http/routes/projects.ts`)、项目上下文继承、`defaultScopes` 作 `TaskSpec.memory.scopes` 的种子(v2 scope 键串,OPEN 值域 —— 本表只登记不解释);
833
+ * 部署级聚合(org 记忆准入的部署 scope 集,`boot/org-memory.ts`)整表读。
833
834
  * NO env source —— 只由 applyEffective 经 settings-schema 的视图面读函数判过后填(mutateInPlace,boot + refresh 整表替换);
834
835
  * 本地腿恒空(settings-schema 的本地读取集不收 `projects`)。 */
835
836
  projects: Record<string, ProjectRegistration>;
@@ -2340,12 +2341,17 @@ export interface ServiceConfigFlat {
2340
2341
  * `liveBaseUrl`(编排器片 2,env `SEMA_WEB_ADMIN_LIVE_URL`):fleet 活性组(心跳 / 注销、服务租约 —— settings-schema `FLEET_LIVE_PATHS`)的基址,
2341
2342
  * 给「管理面在就绪门后、活性面另走一条不看就绪的入口」的部署;缺席 ⇒ 活性组也打 `baseUrl`(这条缺省只在 `centerFetch` 读)。
2342
2343
  * `webBaseUrl`(7.121.0,env `SEMA_WEB_ADMIN_WEB_URL`):这个中心的 **web 面固定基址**,运维声明、引擎原样转述到 `/health.center.webBaseUrl`
2343
- * (壳按它拼会话深链;路径怎么拼归壳)。起服时判成「可拼路径的基址」:http(s)、不带凭据 / query / fragment,否则拒启;缺席即缺席,引擎不拼不猜。 */
2344
+ * (壳按它拼会话深链;路径怎么拼归壳)。起服时判成「可拼路径的基址」:http(s)、不带凭据 / query / fragment,否则拒启;缺席即缺席,引擎不拼不猜。
2345
+ * `assertionToken`([ref]):web-admin 断言令牌(`SEMA_WEB_ADMIN_ASSERTION_TOKEN` / `_FILE`,二选一,都设拒启)的**声明读数**,非秘密投影 ——
2346
+ * 声明在 ⇒ 来源两形之一(`env` / `file` + 绝对路径);没声明 ⇒ 这一格缺席(`loadConfig` 只在声明在时写它;缺席只有一种读法 = 没声明)。
2347
+ * 值不进配置:本版只读声明、不向中心出示;读者 = `/health.center.assertionToken` 与起服日志 `center_assertion_token`。读口与 `credential` 同一只
2348
+ * (`center-credential.ts` 的 `readWebAdminCredentialDeclaration`)。 */
2344
2349
  webAdmin?: {
2345
2350
  baseUrl: string;
2346
2351
  liveBaseUrl?: string;
2347
2352
  webBaseUrl?: string;
2348
2353
  credential: CenterCredentialSource;
2354
+ assertionToken?: DeclaredCredentialOrigin;
2349
2355
  dryRun: boolean;
2350
2356
  worker?: string;
2351
2357
  };
package/dist/config.d.ts CHANGED
@@ -124,7 +124,10 @@ export declare function parseConfigProvider(): ConfigProviderWord | undefined;
124
124
  /** F10 (codex audit): drain + log BOTH pre-logger diagnostic collectors (S20 soft-knob warnings + [ref]④ boot
125
125
  * notices) in one place. EVERY entrypoint that calls loadConfig() then builds a logger must call this right
126
126
  * after (main.ts, run-local.ts) — a new entry that forgets it would silently drop operator-facing diagnostics
127
- * (run-local historically did exactly that), so the drain lives beside the collectors, not in one entrypoint. */
127
+ * (run-local historically did exactly that), so the drain lives beside the collectors, not in one entrypoint.
128
+ * Draining is repeatable: a read made AFTER the boot drain (the execution-lane composition step reads the env of a lane the config file chose;
129
+ * `boot/execution-lane.ts`) calls it again right after, so its soft-knob rejects and knob registrations reach the log instead of piling up
130
+ * undrained — the polarity table (debug) is then printed again, now covering that read too. */
128
131
  export declare function logConfigDiagnostics(logger: {
129
132
  warn: (event: string, fields?: Record<string, unknown>) => void;
130
133
  info?: (event: string, fields?: Record<string, unknown>) => void;
@@ -192,10 +195,56 @@ export declare function buildUnpricedCeilingNotice(models: Record<string, Model>
192
195
  export type EntryDeclarableLane = Extract<ExecutionLane, "host" | "none">;
193
196
  /**
194
197
  * 这两条车道的配置形(唯一铸点):env 声明了它们时由 {@link loadConfig} 的车道链调,入口程序自身声明它们时由执行车道合成步调 —— 坐标 env 同一读法。
195
- * DUAL-MODE §5:`host` = 在这台机器上跑、无容器(坐标 `HOST_WORKSPACE_BASE` / `HOST_COMMAND_TIMEOUT_MS` 可选,无必需 env)。
198
+ * DUAL-MODE §5:`host` = 在这台机器上跑、无容器(坐标 `HOST_WORKSPACE_BASE` / `HOST_COMMAND_TIMEOUT_MS` 可选,无必需 env;读数见 {@link parseHostLaneEnv})。
196
199
  * 契约 18.0.0:`none` = 部署声明「智能体的工具没有执行环境」(零字段、无必需 env)。
197
200
  */
198
201
  export declare function entryDeclarableRemoteExec(lane: EntryDeclarableLane): RemoteExecConfig;
202
+ /** `host` 车道的配置块(型从 {@link RemoteExecConfig} 判别联合取,不另写第二份字段表)。 */
203
+ type HostRemoteExec = Extract<RemoteExecConfig, {
204
+ provider: "host";
205
+ }>;
206
+ /** `local-docker` 车道的配置块(同上)。 */
207
+ type LocalDockerRemoteExec = Extract<RemoteExecConfig, {
208
+ provider: "local-docker";
209
+ }>;
210
+ /** env 一侧对 `host` 车道的读数(块去掉判别位)。 */
211
+ export type HostEnvReading = Omit<HostRemoteExec, "provider">;
212
+ /** env 一侧对 `local-docker` 车道的读数(块去掉判别位;`image` 改可选 —— `DOCKER_IMAGE` 是本车道的必需 env,读数本身不判必需,判官是车道必需 env 门)。 */
213
+ export type LocalDockerEnvReading = Omit<LocalDockerRemoteExec, "provider" | "image"> & {
214
+ image?: string;
215
+ };
216
+ /**
217
+ * **`host` 车道的 env 读数**(唯一读者):`HOST_WORKSPACE_BASE` / `HOST_COMMAND_TIMEOUT_MS`。env 声明路径({@link entryDeclarableRemoteExec})、入口自身声明、
218
+ * 文件腿(`config.d/remote-exec.json` 选定 host 车道时,车道参数仍由 env 读)读的都是这一只。求值时点:`REMOTE_EXEC` 声明的车道在 `loadConfig` 里求值(早于文件);
219
+ * 文件选定而 env 没声明它 ⇒ 执行车道合成步现读;没被选中的车道不求值 —— 那里它们是无关配置。
220
+ */
221
+ export declare function parseHostLaneEnv(): HostEnvReading;
222
+ /**
223
+ * **`local-docker` 车道的 env 读数**(唯一读者):`DOCKER_*` 的全部坐标与车道参数(含容器帽、pids 限额、丢 capability、带外 env 名单)。env 声明路径
224
+ * ({@link loadConfig} 的车道链)与文件腿(`config.d/remote-exec.json` 选定 local-docker 车道时)读的是这一只:文件只定「哪条车道」,车道参数仍只有 env 一处可写,
225
+ * 文件里有同名格的那几格由文件胜(`FILE_LANE_CELL_ENV` 列的五格)。只在本车道被选中(env 声明,或文件选定)时求值 —— 其它车道上它们是无关配置。
226
+ * `singleUserTurnkey` = 本部署是不是单用户姿态(`REQUIRE_PRINCIPAL !== "true"`;名单型旋钮 `DOCKER_SANDBOX_ENV` 的姿态判)。
227
+ */
228
+ export declare function parseLocalDockerLaneEnv(singleUserTurnkey: boolean): LocalDockerEnvReading;
229
+ /**
230
+ * **文件格 ↔ env 键的对表**(`config.d/remote-exec.json` 与 env 对「同一件事」各有一个名字):文件选定车道后,块 = env 读数 ∪ 文件格,**同名格文件赢**;
231
+ * 两处在同一格上给了不同的值 ⇒ 文件赢并响亮点名那一格的 env 键(`remote_exec_file_overrides`,执行车道合成步)。表序 = 点名序。
232
+ * 格名取块的字段名(`satisfies` 钉住:块改名而表不跟 ⇒ 编译红);env 键须是车道表里这条车道的坐标键、且上面两只读者真的读它(`test/remote-exec-file-lane-env-params.test.ts` 钉)。
233
+ * 文件腿读不到 env 键字面 —— 键名只住在读者与这张表里。
234
+ */
235
+ export declare const FILE_LANE_CELL_ENV: {
236
+ readonly host: {
237
+ readonly workspaceBase: "HOST_WORKSPACE_BASE";
238
+ readonly commandTimeoutMs: "HOST_COMMAND_TIMEOUT_MS";
239
+ };
240
+ readonly "local-docker": {
241
+ readonly image: "DOCKER_IMAGE";
242
+ readonly mountPath: "DOCKER_MOUNT_PATH";
243
+ readonly memory: "DOCKER_MEMORY";
244
+ readonly cpus: "DOCKER_CPUS";
245
+ readonly network: "DOCKER_NETWORK";
246
+ };
247
+ };
199
248
  /** [ref] N8/N9 — the BOOLEAN member of this module's env-parser family (`env`/`env2`/`numEnv`/
200
249
  * `numEnvBounded`/`optFinitePositiveEnv`/`enumEnv`/`headerNameEnv`). Until now booleans were the
201
250
  * one type parsed by a hand-written literal comparison at every single site, and that is exactly why the same
package/dist/config.js CHANGED
@@ -49,7 +49,7 @@ import { AUTONOMY_MODES } from "./runtime-governance.js";
49
49
  import { deploymentRuleRefusal } from "./rule-issue-reading.js";
50
50
  import { MAX_NAMED_INERT_ENTRIES, allowLayerEntryCountIssue, describeInertRuleEntries, inertRuleEntriesOf, inertRuleEntryGuidance, ruleEntryListShapeOk } from "./rule-entry-list.js";
51
51
  import { readReadDenyEntry } from "./read-deny-entry.js";
52
- import { createCenterCredentialSource, readCenterCredentialDeclaration } from "./center-credential.js";
52
+ import { createCenterCredentialSource, credentialOriginOf, readWebAdminCredentialDeclaration } from "./center-credential.js";
53
53
  import { parseCenterCredentialRenewLeadMs } from "./center-credential-renewer.js";
54
54
  import { catalogBrainLane, modelProviderRefusal } from "./model-provider.js";
55
55
  import { modelRouteUrlRefusal } from "./model-route-url.js";
@@ -408,15 +408,39 @@ function parseDeviceRelayUrlEnv(raw) {
408
408
  export function entryDeclarableRemoteExec(lane) {
409
409
  switch (lane) {
410
410
  case "host":
411
- return {
412
- provider: "host",
413
- ...(process.env.HOST_WORKSPACE_BASE ? { workspaceBase: process.env.HOST_WORKSPACE_BASE } : {}),
414
- ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("HOST_COMMAND_TIMEOUT_MS")),
415
- };
411
+ return { provider: "host", ...parseHostLaneEnv() };
416
412
  case "none":
417
413
  return { provider: "none" };
418
414
  }
419
415
  }
416
+ export function parseHostLaneEnv() {
417
+ return {
418
+ ...(process.env.HOST_WORKSPACE_BASE ? { workspaceBase: process.env.HOST_WORKSPACE_BASE } : {}),
419
+ ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("HOST_COMMAND_TIMEOUT_MS")),
420
+ };
421
+ }
422
+ export function parseLocalDockerLaneEnv(singleUserTurnkey) {
423
+ return {
424
+ ...(process.env.DOCKER_IMAGE ? { image: process.env.DOCKER_IMAGE } : {}),
425
+ ...(process.env.DOCKER_MOUNT_PATH ? { mountPath: process.env.DOCKER_MOUNT_PATH } : {}),
426
+ ...(process.env.DOCKER_PATH ? { dockerPath: process.env.DOCKER_PATH } : {}),
427
+ ...(process.env.DOCKER_HOST ? { dockerHost: process.env.DOCKER_HOST } : {}),
428
+ ...(process.env.DOCKER_MEMORY ? { memory: process.env.DOCKER_MEMORY } : {}),
429
+ ...((n) => (n !== undefined ? { cpus: n } : {}))(optNumEnvStrict("DOCKER_CPUS")),
430
+ ...((n) => (n !== undefined ? { pidsLimit: n } : {}))(optFinitePositiveEnv("DOCKER_PIDS_LIMIT")),
431
+ ...(boolEnv("DOCKER_DROP_CAPS", false) ? { dropAllCaps: true } : {}),
432
+ ...(process.env.DOCKER_NETWORK
433
+ ? { network: enumEnv("DOCKER_NETWORK", "bridge", ["none", "bridge", "host"]) }
434
+ : {}),
435
+ ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("DOCKER_COMMAND_TIMEOUT_MS")),
436
+ ...((names) => (names !== undefined ? { env: allowlistedEnv(names, process.env) } : {}))(parseEnvNameAllowlist("DOCKER_SANDBOX_ENV", singleUserTurnkey)),
437
+ ...((capacity) => (capacity !== undefined ? { capacity } : {}))(parseLocalDockerCapacityEnv()),
438
+ };
439
+ }
440
+ export const FILE_LANE_CELL_ENV = {
441
+ host: { workspaceBase: "HOST_WORKSPACE_BASE", commandTimeoutMs: "HOST_COMMAND_TIMEOUT_MS" },
442
+ "local-docker": { image: "DOCKER_IMAGE", mountPath: "DOCKER_MOUNT_PATH", memory: "DOCKER_MEMORY", cpus: "DOCKER_CPUS", network: "DOCKER_NETWORK" },
443
+ };
420
444
  const envNamesNoLane = (raw) => raw === undefined || raw === "";
421
445
  function declaredExecutionLane(raw) {
422
446
  if (envNamesNoLane(raw))
@@ -2127,23 +2151,8 @@ function parseOrchestrationDomain(ctx) {
2127
2151
  ? entryDeclarableRemoteExec(declaredLane)
2128
2152
  :
2129
2153
  declaredLane === "local-docker" && process.env.DOCKER_IMAGE
2130
- ? {
2131
- provider: "local-docker",
2132
- image: process.env.DOCKER_IMAGE,
2133
- ...(process.env.DOCKER_MOUNT_PATH ? { mountPath: process.env.DOCKER_MOUNT_PATH } : {}),
2134
- ...(process.env.DOCKER_PATH ? { dockerPath: process.env.DOCKER_PATH } : {}),
2135
- ...(process.env.DOCKER_HOST ? { dockerHost: process.env.DOCKER_HOST } : {}),
2136
- ...(process.env.DOCKER_MEMORY ? { memory: process.env.DOCKER_MEMORY } : {}),
2137
- ...((n) => (n !== undefined ? { cpus: n } : {}))(optNumEnvStrict("DOCKER_CPUS")),
2138
- ...((n) => (n !== undefined ? { pidsLimit: n } : {}))(optFinitePositiveEnv("DOCKER_PIDS_LIMIT")),
2139
- ...(boolEnv("DOCKER_DROP_CAPS", false) ? { dropAllCaps: true } : {}),
2140
- ...(process.env.DOCKER_NETWORK
2141
- ? { network: enumEnv("DOCKER_NETWORK", "bridge", ["none", "bridge", "host"]) }
2142
- : {}),
2143
- ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("DOCKER_COMMAND_TIMEOUT_MS")),
2144
- ...((names) => (names !== undefined ? { env: allowlistedEnv(names, process.env) } : {}))(parseEnvNameAllowlist("DOCKER_SANDBOX_ENV", singleUserTurnkey)),
2145
- ...((capacity) => (capacity !== undefined ? { capacity } : {}))(parseLocalDockerCapacityEnv()),
2146
- }
2154
+ ?
2155
+ { provider: "local-docker", ...parseLocalDockerLaneEnv(singleUserTurnkey), image: process.env.DOCKER_IMAGE }
2147
2156
  :
2148
2157
  declaredLane === "device"
2149
2158
  ? {
@@ -2488,12 +2497,14 @@ function parseCenterBaseUrl(name, raw, role) {
2488
2497
  }
2489
2498
  function parseWebAdmin(baseUrl, requirePrincipal, liveBaseUrl, webBaseUrl) {
2490
2499
  const worker = process.env[WEB_ADMIN_ENV.worker] || undefined;
2491
- const declared = readCenterCredentialDeclaration();
2500
+ const declared = readWebAdminCredentialDeclaration("access");
2501
+ const assertion = credentialOriginOf(readWebAdminCredentialDeclaration("assertion"));
2492
2502
  return {
2493
2503
  baseUrl,
2494
2504
  ...(liveBaseUrl !== undefined ? { liveBaseUrl } : {}),
2495
2505
  ...(webBaseUrl !== undefined ? { webBaseUrl } : {}),
2496
2506
  credential: createCenterCredentialSource(declared.from === "file" ? { ...declared, multiTenant: requirePrincipal } : declared, worker),
2507
+ ...(assertion.from !== "absent" ? { assertionToken: assertion } : {}),
2497
2508
  dryRun: boolEnv(WEB_ADMIN_ENV.dryRun, false),
2498
2509
  worker,
2499
2510
  };
@@ -17,7 +17,7 @@
17
17
  * `holds` 的入参型 = 所声明轴读入形的交叉({@link DeploymentShapeInput}),所以调用方递完整 `ServiceConfig` 或只递那几键的窄形都行。
18
18
  *
19
19
  * ## 什么进表、什么不进
20
- * 进表的是**形规则**:只由部署形事实决定的布尔(去重后 15 行;同一条规则的多个消费者读同一行,不各成一行)。
20
+ * 进表的是**形规则**:只由部署形事实决定的布尔(去重后 16 行;同一条规则的多个消费者读同一行,不各成一行)。
21
21
  * 把一行与**非形事实**(锁键、合规档位、审批意图、请求身份、请求体)合取的能力判据是**消费者**,住在它自己的模块
22
22
  * (`mcpInjectionHonored` = 锁 ∧ 合规 ∧ `!multiTenant`;`taskHooksHonored`;身份门 …),读行、不读原始键。
23
23
  * 车道表(`execution-lane-caps.ts`)按车道词键控的布尔列(`laneIsolated` 等)是车道轴自己的事实表,不是「部署」的谓词;行读它们。
@@ -111,6 +111,14 @@ export declare const DEPLOYMENT_SHAPE_PREDICATES: Readonly<{
111
111
  * 一次性迁移 M48 的输入(`plugins/store-backend.ts`:有边界 ⇒ 不改写哨兵属主)。
112
112
  */
113
113
  identityBoundary: DeploymentShapePredicate<"principal" | "identity">;
114
+ /**
115
+ * 「这台部署接没接**过凭据门**的来源」的问法 —— 身份来源律 5(`identity-source.ts` 头注)在部署上的投影:配置接了的来源里有凭据门认的那一类
116
+ * (service 凭据,或鉴权桥 issuer —— 含中心回退;`passesCredentialGate` 那一列)。**不是** {@link DEPLOYMENT_SHAPE_PREDICATES.identityBoundary}:
117
+ * 那一行把 `REQUIRE_PRINCIPAL` / 只读 trace 凭据 / 直连门也算作边界(它们让主体头不再是 dev-open 的自报),本行只问「有没有一类凭据过得了门」——
118
+ * 三样都不过,所以只配其中之一的部署两行答案相反,这是两问,不是一问两答。没接 ⇒ 写门(问请求)对每一次请求都拒(`ALLOW_UNAUTHED_WRITES` 之外)。
119
+ * 读者:记忆整理阀门的启动期告警(`boot/stage-06-runners.ts`;「这台部署上 run 口对谁都开不了」)。请求面不读本行:写门问的是请求。
120
+ */
121
+ credentialGateSource: DeploymentShapePredicate<"identity">;
114
122
  /**
115
123
  * 租户轴的问法。今天与 {@link DEPLOYMENT_SHAPE_PREDICATES.principalRequired} 读**同一个声明**([ref] ①:托管 / 多租 ⇔ `REQUIRE_PRINCIPAL=true`,
116
124
  * 签发方配置是身份验签轴、不算租户证据)—— 两个问题、一根轴、一个读口;「鉴权必需」与「多租形」拆成两个声明时只改这一行的判官。
@@ -1,5 +1,5 @@
1
1
  import { capabilitiesFor, executionLaneCaps, executionLaneOf, handsOnWorkerFilePlane, laneWiresExecutionEnv } from "./execution-lane-caps.js";
2
- import { configuredIdentitySources } from "./identity-source.js";
2
+ import { configuredIdentitySources, passesCredentialGate } from "./identity-source.js";
3
3
  function readPrincipalAxis(deployment) {
4
4
  return { declared: deployment.requirePrincipal === true };
5
5
  }
@@ -54,6 +54,7 @@ const VM_ISOLATION_RUNTIME_CLASSES = new Set(["kata", "kata-qemu", "kata-clh", "
54
54
  export const DEPLOYMENT_SHAPE_PREDICATES = Object.freeze({
55
55
  principalRequired: createPredicate(["principal"], "身份轴:运维声明了 REQUIRE_PRINCIPAL=true —— 每个调用方都必须带一个验过的主体。", ({ principal }) => principal.declared),
56
56
  identityBoundary: createPredicate(["principal", "identity"], "身份轴:这台部署有身份边界 —— 声明了 REQUIRE_PRINCIPAL,或配置接了任一已验身份来源(service 凭据 / 鉴权桥 / 直连门),或声明了只读 trace 凭据。", ({ principal, identity }) => principal.declared || identity.sources.length > 0 || identity.traceTokenDeclared),
57
+ credentialGateSource: createPredicate(["identity"], "身份轴:这台部署接了一类过凭据门的来源 —— service 凭据,或鉴权桥(登录令牌);只开 REQUIRE_PRINCIPAL / 只配 trace 凭据 / 只开直连门都不算。", ({ identity }) => identity.sources.some(passesCredentialGate)),
57
58
  multiTenant: createPredicate(["principal"], "租户轴:这台部署服务不止一个主人(托管 / 多租;C-R100 ① 由 REQUIRE_PRINCIPAL=true 声明)。", ({ principal }) => principal.declared),
58
59
  callerCwd: createPredicate(["lane", "principal"], "车道 × 租户 / 设备归属:调用方送来的 cwd(与 settings.env)被尊重 —— host 车道且单主,或 device 车道。", ({ lane, principal }) => lane.caps !== undefined && capabilityHolds(lane.caps.callerCwd, principal)),
59
60
  callerOwnsWorkerDisk: createPredicate(["lane", "principal"], "车道 × 租户:手就在本 worker 的盘上且部署只有一个主人 —— 这块盘上的路径就是调用方自己的。", ({ lane, principal }) => lane.lane !== undefined && handsOnWorkerFilePlane(lane.lane) && !principal.declared),
@@ -7,11 +7,12 @@
7
7
  *
8
8
  * 为什么是精选而不是把 `device-ws-protocol.ts` 整只暴露:那个模块里还有**服务端**自己的半场(帧解析与准入、
9
9
  * 验签、各种铸 id)。把它们变成公开面,等于替实现细节背上 semver。这里只再导出 executor **会用到**的:
10
- * 闭集常量、两向帧型、构造握手签名字节所需的两只纯函数,以及两份「随协议修订号走」的事实:结局码按修订号分行的增量表
11
- * (`DEVICE_OUTCOME_ERROR_CODES_BY_REVISION` + 取集函数 `deviceOutcomeErrorCodesAt`:executor 按自己声明的修订号裁剪会发的词)与
10
+ * 闭集常量、两向帧型、构造握手签名字节所需的两只纯函数,以及三份「随协议修订号走」的事实:结局码按修订号分行的增量表
11
+ * (`DEVICE_OUTCOME_ERROR_CODES_BY_REVISION` + 取集函数 `deviceOutcomeErrorCodesAt`:executor 按自己声明的修订号裁剪会发的词)、指令 kind 按修订号分行的增量表
12
+ * (`DEVICE_INSTRUCTION_KINDS_BY_REVISION` + 取集函数 `deviceInstructionKindsAt`:executor 按自己声明的修订号裁剪 `hello.supports` —— 高于它的 kind 声明了也不会下发)与
12
13
  * helloAck 数值位的界表(`DEVICE_HELLO_ACK_BOUNDS` + 判据 `deviceHelloAckNumberFlaw`:executor 读到越界值 ⇒ 协议违例)。要加名字 = 改这只文件 + 同批改
13
14
  * `test/device-protocol-subpath.test.ts` 的闭集(新增公开面必须是一次有意的动作)。
14
15
  */
15
- export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
16
- export type { DeviceFrameType, DeviceServerFrameType, DeviceHelloRejectCode, DeviceByeReason, DeviceGoodbyeReason, DeviceChunkKind, DeviceCancelState, DeviceInstructionKind, DeviceOutcomeErrorCode, DeviceProtocolRevision, DeviceHelloAckNumericField, WireFileInfo, WireWriteExpectation, DeviceInstructionOutcome, DeviceInstructionArgsByKind, DeviceChallengeFrame, DeviceHelloAckFrame, DeviceHelloRejectFrame, DeviceInstructionFrame, DevicePayloadFrame, DeviceServerFrame, DeviceHelloFrame, DeviceFrame, DeviceResultFrame, DeviceChunkFrame, DeviceGoodbyeFrame, DeviceHeartbeatFrame, } from "./device-ws-protocol.js";
16
+ export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_INSTRUCTION_KINDS_BY_REVISION, DEVICE_BOUND_READ_OPS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceInstructionKindsAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
17
+ export type { DeviceFrameType, DeviceServerFrameType, DeviceHelloRejectCode, DeviceByeReason, DeviceGoodbyeReason, DeviceChunkKind, DeviceCancelState, DeviceInstructionKind, DeviceBoundReadOp, DeviceOutcomeErrorCode, DeviceProtocolRevision, DeviceHelloAckNumericField, WireFileInfo, WireWriteExpectation, DeviceInstructionOutcome, DeviceInstructionArgsByKind, DeviceChallengeFrame, DeviceHelloAckFrame, DeviceHelloRejectFrame, DeviceInstructionFrame, DevicePayloadFrame, DeviceServerFrame, DeviceHelloFrame, DeviceFrame, DeviceResultFrame, DeviceChunkFrame, DeviceGoodbyeFrame, DeviceHeartbeatFrame, } from "./device-ws-protocol.js";
17
18
  //# sourceMappingURL=device-protocol.d.ts.map
@@ -1,2 +1,2 @@
1
- export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
1
+ export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_INSTRUCTION_KINDS_BY_REVISION, DEVICE_BOUND_READ_OPS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceInstructionKindsAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
2
2
  //# sourceMappingURL=device-protocol.js.map
@@ -5,7 +5,7 @@ import { WebSocketServer } from "ws";
5
5
  import { DEVICE_DRAINING_CODE, DEVICE_ERROR_CODES, DEVICE_ERROR_STATUS, assertDeviceIdShape, } from "./device-store.js";
6
6
  import { MAX_TIMER_DELAY_MS } from "./config-types.js";
7
7
  import { canonicalAddress, createTrustedProxySet } from "./net-address.js";
8
- import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKind, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, deviceProtocolRevisionRefusal, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
8
+ import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKindAt, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, deviceProtocolRevisionRefusal, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
9
9
  const OUTCOME_UNKNOWN_SENTENCE = "outcome unknown — the command may have already executed on the device; verify its effect before re-running";
10
10
  const SETTLED_MEMO_MAX = 512;
11
11
  const DRAIN_RETRY_AFTER_SEC = 15;
@@ -66,6 +66,7 @@ const ALLOWED_SUCCESS_OUTCOME_KINDS = {
66
66
  remove: ["void"],
67
67
  createTempDir: ["write"],
68
68
  createTempFile: ["write"],
69
+ openBound: ["stat", "read"],
69
70
  };
70
71
  const HELLO_ACK_FIELD_SOURCES = {
71
72
  heartbeatIntervalMs: "option heartbeatIntervalMs",
@@ -500,7 +501,7 @@ export function createDeviceWsHub(options) {
500
501
  conn.workspaceRoot = frame.workspaceRoot;
501
502
  const supported = new Set();
502
503
  for (const s of frame.supports) {
503
- const k = asInstructionKind(s);
504
+ const k = asInstructionKindAt(s, frame.protocolVersion);
504
505
  if (k !== null)
505
506
  supported.add(k);
506
507
  }
@@ -5,16 +5,20 @@ export declare const DEVICE_WS_PATH = "/v1/device/ws";
5
5
  * 本 server 铸/认的协议**修订号**(wire 上的 `protocolVersion`)。
6
6
  *
7
7
  * 规则(真源 = 协议文档 `docs/DEVICE-EXECUTOR-PROTOCOL.md` §2.1「Protocol revisions」段,此处只转述):加帧 / 加字段 = additive 不升号;
8
- * 其余变更一律升号并在增量表加一行,已发布的行不改 —— **server 受理的闭集(executor → server 方向,今天 = 结局 `errorCode` 词集)加词 = 升号**,
9
- * **语义变更(server 下发的帧意思变了)= 升号**。修订号是 executor 在发 hello 之前唯一能读到的「这台 server 受理什么、发来的帧是什么意思」的事实
10
- * (challenge 帧带它),所以 server 受理的词集必须是修订号的函数({@link DEVICE_OUTCOME_ERROR_CODES_BY_REVISION},协议文档同名表),不另发第二份列表;
11
- * 闭集变了而修订号没变 = 同一个修订号两种受理集(7.132.0 给结局码加 `liveness_no_output` 时没抬号,7.136.0 补到 2)。类型锁:抬了号而表没有这一行 ⇒ 编译红。
8
+ * 其余变更一律升号并在增量表加一行,已发布的行不改 —— **指令两向的闭集加词 = 升号**:server 受理的结局 `errorCode` 词集(executor → server)
9
+ * 与 server 下发的指令 kind 集(server → executor),各一张按修订号分行的表({@link DEVICE_OUTCOME_ERROR_CODES_BY_REVISION} /
10
+ * {@link DEVICE_INSTRUCTION_KINDS_BY_REVISION},同一组行键;协议文档是同一张修订号表的两栏);**语义变更(server 下发的帧意思变了)= 升号**。
11
+ * 修订号是 executor 在发 hello 之前唯一能读到的「这台 server 受理什么、会发来什么、发来的帧是什么意思」的事实(challenge 帧带它),所以两个闭集
12
+ * 都必须是修订号的函数,不另发第二份列表;闭集变了而修订号没变 = 同一个修订号两种集合(7.132.0 给结局码加 `liveness_no_output` 时没抬号,7.136.0 补到 2)。
13
+ * 下发方向的读法:汇聚端只认**这条连接协商的修订号**那一份 kind 集({@link asInstructionKindAt}),高于它的 kind 与认不出的词同读 —— 恒不下发。
14
+ * 类型锁:抬了号而任一张表没有这一行 ⇒ 编译红。
12
15
  */
13
16
  export declare const DEVICE_PROTOCOL_VERSION: DeviceProtocolRevision;
14
17
  /**
15
18
  * 受理下沿:低于它 ⇒ `helloReject: protocol_version_unsupported`(带 `minProtocolVersion` 与一句 {@link deviceProtocolRevisionRefusal},响亮拒,不静默降级,[ref])。
16
19
  * 兼容窗 = [MIN, 当前]。律(协议文档 §2.1 规则句):升号的变更旧修订的 executor 守不住 ⇒ 同一版把下沿抬到那一修订号 —— 旧 executor 在 hello 被拒一次,
17
20
  * 而不是逐调用失败。今天 = 5:修订号 5 起路径只锚不折(下沿理由见 {@link DEVICE_FLOOR_CHANGE}),写给修订号 ≤ 4 的 executor 认的是折过的路径。
21
+ * 修订号 6(kind 集加 `openBound`)不抬下沿:那个 kind 只派给协商修订号 ≥ 6 的连接,修订号 5 的 executor 收不到它 ⇒ 守得住。
18
22
  * 这是**本 server** 的受理下沿,不是 executor 协商时的下界(executor 一侧修订号是累积的:实现了 5 的照样能按 4 服务老 server)。
19
23
  */
20
24
  export declare const DEVICE_MIN_PROTOCOL_VERSION: DeviceProtocolRevision;
@@ -71,11 +75,44 @@ export type DeviceCancelState = (typeof DEVICE_CANCEL_STATES)[number];
71
75
  */
72
76
  export declare const DEVICE_INSTRUCTION_STATES: readonly ["queued", "dispatch_committed", "terminal", "terminal_never_started"];
73
77
  export type DeviceInstructionState = (typeof DEVICE_INSTRUCTION_STATES)[number];
74
- /** 指令 kind ↔ core 的 FileSystem+Shell 面 1:1(§5.1;双端穷举 switch)。 */
75
- export declare const DEVICE_INSTRUCTION_KINDS: readonly ["exec", "execStream", "readTextFile", "readTextLines", "readBinaryFile", "writeFile", "writeFileExclusive", "writeFileGuarded", "appendFile", "fileInfo", "listDir", "canonicalPath", "exists", "readLink", "createDir", "remove", "createTempDir", "createTempFile", "statBatch"];
76
- export type DeviceInstructionKind = (typeof DEVICE_INSTRUCTION_KINDS)[number];
77
- /** 认得就收窄,认不出就 null(**不猜**:未知 kind 恒不下发,fail-closed 方向)。 */
78
- export declare function asInstructionKind(v: string): DeviceInstructionKind | null;
78
+ /**
79
+ * 指令 kind ↔ core 的 FileSystem+Shell 面 1:1(§5.1;双端穷举 switch)—— **按修订号分行的增量表,是这个闭集唯一的一份来源**(与结局码同一条律):
80
+ * 修订号 N 的 kind 集 = 行 ≤ N 的并、按行序({@link deviceInstructionKindsAt}),{@link DEVICE_INSTRUCTION_KINDS} 是当前修订号的那一份(派生)。
81
+ * 汇聚端对一条连接只认它协商的修订号那一份({@link asInstructionKindAt}):executor 在 `hello.supports` 里声明了一个高于自己修订号的 kind,与声明了
82
+ * 一个认不出的词同读 —— 不进声明集、恒不下发。已发布修订号的行不许改(测试冻结了每个修订号的集合哈希);加 kind = 抬 {@link DEVICE_PROTOCOL_VERSION} + 加一行。
83
+ * 行键与 {@link DEVICE_OUTCOME_ERROR_CODES_BY_REVISION} 同一组(`satisfies` 锁:少一行 / 多一行 ⇒ 编译红)。
84
+ */
85
+ export declare const DEVICE_INSTRUCTION_KINDS_BY_REVISION: {
86
+ readonly 1: readonly ["exec", "execStream", "readTextFile", "readTextLines", "readBinaryFile", "writeFile", "writeFileExclusive", "writeFileGuarded", "appendFile", "fileInfo", "listDir", "canonicalPath", "exists", "readLink", "createDir", "remove", "createTempDir", "createTempFile", "statBatch"];
87
+ readonly 2: readonly [];
88
+ readonly 3: readonly [];
89
+ readonly 4: readonly [];
90
+ readonly 5: readonly [];
91
+ /**
92
+ * 7.151.0:绑定读 —— 判过的那只对象就是读到的那只。协议没有跨指令的句柄,所以 `BoundFileObject` 的每一答是一条指令
93
+ * ({@link DeviceInstructionArgsByKind}`.openBound.op` 四选一):执行器在本机打开这条路径(叶链接不跟)、核对这只打开的对象此刻就在这条路径上
94
+ * (且 `identity` / `kind` 在场时等于它们)、经这一次打开作答、关掉。executor 必须实现才答得出 ⇒ 加词抬号;只派给协商修订号 ≥ 6 的连接,
95
+ * 修订号 5 的 executor 收不到它(受理下沿不动)。presence-typed(同 `writeFileGuarded` / `readLink`):执行器在 `hello.supports` 声明才装这一面;
96
+ * 没声明 ⇒ 这一面缺席(引擎不绑定读,附件不附),**不许**用 `fileInfo` + `readBinaryFile` 仿真。
97
+ */
98
+ readonly 6: readonly ["openBound"];
99
+ };
100
+ export type DeviceInstructionKind = (typeof DEVICE_INSTRUCTION_KINDS_BY_REVISION)[DeviceProtocolRevision][number];
101
+ /**
102
+ * 协议修订号 `revision` 下发的指令 kind 全集(行 ≤ revision 的并,按行序 —— 协议文档 §3.1 的表同序)。executor 按**自己声明的修订号**取这一份,
103
+ * 决定 `hello.supports` 里能声明哪些 kind。不是本包认得的修订号 ⇒ 抛 `RangeError`(不静默给空集或全集)。
104
+ */
105
+ export declare function deviceInstructionKindsAt(revision: number): readonly DeviceInstructionKind[];
106
+ /** 当前修订号下发的 kind 全集(派生自增量表;§3.1 的表就是它)。 */
107
+ export declare const DEVICE_INSTRUCTION_KINDS: readonly DeviceInstructionKind[];
108
+ /** `openBound` 指令的四个答(一个 `BoundFileObject` 成员一个;`open` 是开答)。 */
109
+ export declare const DEVICE_BOUND_READ_OPS: readonly ["open", "size", "readBytes", "list"];
110
+ export type DeviceBoundReadOp = (typeof DEVICE_BOUND_READ_OPS)[number];
111
+ /**
112
+ * 认词 **按协商修订号**:`v` 在修订号 `revision` 的 kind 集里就收窄,不在就 null(**不猜**:高于协商修订号的 kind 与认不出的词同读,恒不下发,fail-closed 方向)。
113
+ * 不是本包认得的修订号 ⇒ 抛 `RangeError`(汇聚端在 hello 的版本窗之后才调它,窗外到不了这里;到了就是响亮的缺陷,不静默给全集)。
114
+ */
115
+ export declare function asInstructionKindAt(v: string, revision: number): DeviceInstructionKind | null;
79
116
  /**
80
117
  * 结果帧的错误码闭集 = core 的 `FileErrorCode ∪ ExecutionErrorCode`(§5.1「error code 全闭集」:
81
118
  * 未知值映射为协议错误而非透传 string)—— **按修订号分行的增量表,是这个闭集唯一的一份来源**:
@@ -88,6 +125,7 @@ export declare const DEVICE_OUTCOME_ERROR_CODES_BY_REVISION: {
88
125
  readonly 3: readonly ["name_too_long"];
89
126
  readonly 4: readonly ["symlink_loop"];
90
127
  readonly 5: readonly [];
128
+ readonly 6: readonly [];
91
129
  };
92
130
  /** 本包认得的协议修订号(= 增量表的行键)。 */
93
131
  export type DeviceProtocolRevision = keyof typeof DEVICE_OUTCOME_ERROR_CODES_BY_REVISION;
@@ -151,7 +189,9 @@ export type DeviceInstructionOutcome = {
151
189
  } | {
152
190
  ok: true;
153
191
  kind: "read";
154
- } | {
192
+ }
193
+ /** `identity` 是 additive 扩键(`openBound` 开答:被打开对象的 `<dev>:<inode>`,之后每一答的对拍凭据)。 */
194
+ | {
155
195
  ok: true;
156
196
  kind: "stat";
157
197
  info?: WireFileInfo;
@@ -159,6 +199,7 @@ export type DeviceInstructionOutcome = {
159
199
  existsValue?: boolean;
160
200
  canonicalPath?: string;
161
201
  linkTarget?: string | null;
202
+ identity?: string;
162
203
  }
163
204
  /** 写面的**落盘对象收据**(§4.3.1 / core `WriteReceipt`)。`created` 是 additive 扩键(车A-4):
164
205
  * core 的收据形要求它,缺席 = adapter 只能猜「是新建还是覆盖」,而猜出来的收据就是假收据。 */
@@ -255,6 +296,18 @@ export interface DeviceInstructionArgsByKind {
255
296
  statBatch: {
256
297
  paths: string[];
257
298
  };
299
+ /**
300
+ * 绑定读的一答。`op`:`open` ⇒ `stat` 结局带 `identity` 与 `info`(`kind` 只许 `file` / `dir`);`size` ⇒ `stat` 带 `info`(`size` = 此刻大小);
301
+ * `readBytes` ⇒ `read` 结局 + `data` 片(大小 > `max` ⇒ `invalid`,一个字节不读);`list` ⇒ `stat` 带 `entries`(经这只打开的目录列,链接不跟)。
302
+ * `identity` / `kind` 在场(开答之后的三答)⇒ 这一次打开的对象须与它们都相等,否则 `precondition_failed`;开后不在这条路径上同拒。
303
+ */
304
+ openBound: {
305
+ path: string;
306
+ op: DeviceBoundReadOp;
307
+ identity?: string;
308
+ kind?: "file" | "directory";
309
+ max?: number;
310
+ };
258
311
  }
259
312
  export type DeviceChallengeFrame = {
260
313
  t: "challenge";
@@ -1,7 +1,7 @@
1
1
  import { createPublicKey, randomBytes, randomInt, verify as edVerify } from "node:crypto";
2
2
  import { MAX_TIMER_DELAY_MS, inWholeNumberBounds, wholeNumberBoundsRule } from "./config-types.js";
3
3
  export const DEVICE_WS_PATH = "/v1/device/ws";
4
- export const DEVICE_PROTOCOL_VERSION = 5;
4
+ export const DEVICE_PROTOCOL_VERSION = 6;
5
5
  export const DEVICE_MIN_PROTOCOL_VERSION = 5;
6
6
  const DEVICE_FLOOR_CHANGE = 'since server 7.150.0 every path an instruction carries (args.path, args.paths, cwd) arrives unfolded, with "." / ".." / empty segments kept for the device\'s filesystem to resolve';
7
7
  export function deviceProtocolRevisionRefusal(declared) {
@@ -24,30 +24,54 @@ export const DEVICE_GOODBYE_REASONS = ["shutdown", "sleep", "user_stop"];
24
24
  export const DEVICE_CHUNK_KINDS = ["stdout", "stderr", "data", "exit"];
25
25
  export const DEVICE_CANCEL_STATES = ["not_started", "killed"];
26
26
  export const DEVICE_INSTRUCTION_STATES = ["queued", "dispatch_committed", "terminal", "terminal_never_started"];
27
- export const DEVICE_INSTRUCTION_KINDS = [
28
- "exec",
29
- "execStream",
30
- "readTextFile",
31
- "readTextLines",
32
- "readBinaryFile",
33
- "writeFile",
34
- "writeFileExclusive",
35
- "writeFileGuarded",
36
- "appendFile",
37
- "fileInfo",
38
- "listDir",
39
- "canonicalPath",
40
- "exists",
41
- "readLink",
42
- "createDir",
43
- "remove",
44
- "createTempDir",
45
- "createTempFile",
46
- "statBatch",
47
- ];
48
- const INSTRUCTION_KIND_SET = new Set(DEVICE_INSTRUCTION_KINDS);
49
- export function asInstructionKind(v) {
50
- return INSTRUCTION_KIND_SET.has(v) ? v : null;
27
+ export const DEVICE_INSTRUCTION_KINDS_BY_REVISION = {
28
+ 1: [
29
+ "exec",
30
+ "execStream",
31
+ "readTextFile",
32
+ "readTextLines",
33
+ "readBinaryFile",
34
+ "writeFile",
35
+ "writeFileExclusive",
36
+ "writeFileGuarded",
37
+ "appendFile",
38
+ "fileInfo",
39
+ "listDir",
40
+ "canonicalPath",
41
+ "exists",
42
+ "readLink",
43
+ "createDir",
44
+ "remove",
45
+ "createTempDir",
46
+ "createTempFile",
47
+ "statBatch",
48
+ ],
49
+ 2: [],
50
+ 3: [],
51
+ 4: [],
52
+ 5: [],
53
+ 6: ["openBound"],
54
+ };
55
+ export function deviceInstructionKindsAt(revision) {
56
+ if (!Number.isInteger(revision) || revision < 1 || revision > DEVICE_PROTOCOL_VERSION) {
57
+ throw new RangeError(`device-ws: no instruction-kind set for protocol revision ${String(revision)} (this package knows revisions 1..${DEVICE_PROTOCOL_VERSION})`);
58
+ }
59
+ const out = [];
60
+ for (const [rev, kinds] of Object.entries(DEVICE_INSTRUCTION_KINDS_BY_REVISION)) {
61
+ if (Number(rev) <= revision)
62
+ out.push(...kinds);
63
+ }
64
+ return out;
65
+ }
66
+ export const DEVICE_INSTRUCTION_KINDS = deviceInstructionKindsAt(DEVICE_PROTOCOL_VERSION);
67
+ export const DEVICE_BOUND_READ_OPS = ["open", "size", "readBytes", "list"];
68
+ const INSTRUCTION_KIND_SETS = new Map(Object.keys(DEVICE_INSTRUCTION_KINDS_BY_REVISION).map((rev) => [Number(rev), new Set(deviceInstructionKindsAt(Number(rev)))]));
69
+ export function asInstructionKindAt(v, revision) {
70
+ const kinds = INSTRUCTION_KIND_SETS.get(revision);
71
+ if (kinds === undefined) {
72
+ throw new RangeError(`device-ws: no instruction-kind set for protocol revision ${String(revision)} (this package knows revisions 1..${DEVICE_PROTOCOL_VERSION})`);
73
+ }
74
+ return kinds.has(v) ? v : null;
51
75
  }
52
76
  export const DEVICE_OUTCOME_ERROR_CODES_BY_REVISION = {
53
77
  1: [
@@ -75,6 +99,7 @@ export const DEVICE_OUTCOME_ERROR_CODES_BY_REVISION = {
75
99
  3: ["name_too_long"],
76
100
  4: ["symlink_loop"],
77
101
  5: [],
102
+ 6: [],
78
103
  };
79
104
  export function deviceOutcomeErrorCodesAt(revision) {
80
105
  if (!Number.isInteger(revision) || revision < 1 || revision > DEVICE_PROTOCOL_VERSION) {
@@ -232,6 +257,12 @@ function parseOutcome(v) {
232
257
  return null;
233
258
  out.linkTarget = v.linkTarget;
234
259
  }
260
+ if (v.identity !== undefined) {
261
+ const id = str(v.identity);
262
+ if (id === null)
263
+ return null;
264
+ out.identity = id;
265
+ }
235
266
  return out;
236
267
  }
237
268
  case "write": {
@@ -5,9 +5,11 @@
5
5
  * 与本仓的人面汇点同轴);`isolationScope` = **带场景的主体**(只在请求带了场景时有;引擎按它分登记域 / offload 租界 / 后台登记 / peer 目录 / 工作流 scope,
6
6
  * 引擎的读法是「隔离格缺席 ⇒ 读 `principal`」)。没带场景的请求只有 `principal`,与今天逐字节同。检查点的分区走本仓自己供的 `scope` 格。
7
7
  *
8
- * 今天的引擎还没有隔离格:{@link taskSpecIdentityOf} 是**唯一的落点**,今天只写 `principal`;隔离格到货后改那一行(钉在 `test/scenario-subject.test.ts`)。
9
- * 落点之前引擎自己按 `spec.principal` 分的那几面按人分(同一个人的各场景在那几面互见)—— 本仓镜像这几面的读口(工作流读面、后台登记簿的停止标记、
10
- * leader 子任务的 spec)同读 {@link taskSpecIdentityOf},读到的就是引擎写下的那一个值,不各写一份。
8
+ * 今天的引擎还没有隔离格:{@link taskSpecIdentityOf} 是**唯一的落点**,今天只写 `principal`;隔离格到货后改那一行(钉在 `test/scenario-subject.test.ts`),
9
+ * {@link engineScopeOf} 同一提交换读(钉在 `test/workflow-scope-core-parity.test.ts`)。
10
+ * 落点之前引擎自己按 `spec.principal` 分的那几面按人分(同一个人的各场景在那几面互见)。本仓读这几面(工作流行的 `scope` 列、后台登记簿与它的停止标记、
11
+ * 会话信箱盒与被扣来信的队列、名册)时「一只主体 ⇒ 那一格 scope」只有一只换算 {@link engineScopeOf},读到的就是引擎写下的那一个值,不各写一份;
12
+ * leader 子任务与提交腿的 spec 同经落点 {@link taskSpecIdentityOf}。
11
13
  */
12
14
  import { type Person, type Subject, type SubjectParts } from "./owner-brands.js";
13
15
  /** 引擎交界的身份(本仓的类型;二元)。 */
@@ -20,15 +22,25 @@ export interface EngineIdentity {
20
22
  export declare function specIdentityOf(parts: SubjectParts | undefined): EngineIdentity;
21
23
  /**
22
24
  * 落进 `TaskSpec` 的身份格(**唯一落点**)。今天的引擎没有隔离格 ⇒ 只写 `principal`,`isolationScope` 在这里不落(引擎按人分它自己的那几面);
23
- * 引擎的隔离格到货 ⇒ 这里加一格,别处不动。
25
+ * 引擎的隔离格到货 ⇒ 这里加一格,同一提交里 {@link engineScopeOf} 改读 core 的 `isolationScopeOf`(身份格闭集型在那里编译红,逼读法表态),别处不动。
24
26
  */
25
27
  export declare function taskSpecIdentityOf(parts: SubjectParts | undefined): {
26
28
  readonly principal?: string;
27
29
  };
28
30
  /**
29
- * 引擎按身份分的那几面落下的 **scope**(core 写侧 `spec.principal ?? "default"` 的同一条读法;工作流行的 `scope` 列就是它):一只主体 ⇒ 落点 {@link taskSpecIdentityOf}
30
- * 写下的人;匿名 ⇒ 单机形的租户键 `"default"`(`owner-faces.ts` 的 `LEGACY_UNOWNED_AMNESTY_TENANT`)。读者只在属主存取器(`http/owner-access.ts`):工作流按 id 的门
31
- * (调用方一侧按它换成引擎身份再与行的 scope 比)与工作流列表的属主过滤同读这一只;承认之后 journal / 流按承认的那一行的 scope 读。
31
+ * 🔴 **一只主体在引擎按身份分的那几面上的 scope —— 唯一一只换算**(工作流行的 `scope` 列 / 后台登记簿 / 会话信箱盒与被扣来信的队列 / 停止标记 / 名册:
32
+ * 引擎写下它们时用的那一个值)。规则 = core 写侧那一条,落在本仓交给引擎的身份格({@link taskSpecIdentityOf})上 ⇒ {@link scopeOfLanded}:
33
+ * · core 7.66.0(本仓钉的版本):工作流行 `scope` = `ctx.principal ?? 挂载 scope`(`createRunWorkflowTool` 的 `execute` 里的 `taskScope`;`startWorkflow` 缺席落
34
+ * `"default"`)—— `ctx.principal` 是 Runner 填的 `spec.principal`;挂载 scope 与后台登记簿 / 被扣来信队列同一个量,即 Runner 准备任务时算的任务 scope
35
+ * `registryScope ?? spec.principal ?? "default"`(同一个值挂进 `run_workflow`、交给信箱排空腿开 held 队列)。本仓不供 `registryScope` ⇒ 各面同值 = 落下的
36
+ * `principal`,匿名 = `"default"`。
37
+ * · core 的下一形([ref] 隔离格随 7.68.0 到货;[ref] 同版根导出 `callScopeOf` / `isolationScopeOf`):`callScopeOf(ctx, 挂载) = ctx.isolationScope ?? 挂载.scope`,
38
+ * Runner 把 `ctx.isolationScope` 填成 `isolationScopeOf(spec) = spec.isolationScope || spec.principal`;落点只写 `principal` 时两形同值。
39
+ * **随 core [ref] 到货换读、退本读法**:提货车让落点写出隔离格的同一提交里,这里改读 core 根导出的 `isolationScopeOf`(落下的身份格 ⇒ `?? "default"`),
40
+ * {@link scopeOfLanded} 退役 —— 落点多一格而读法没表态 = 编译红(身份格闭集,见它)。真 core 对拍钉:`test/workflow-scope-core-parity.test.ts`。
41
+ * 工作流行「归谁」只在属主存取器经它判(`http/owner-access.ts` 的 `workflowScopeOf`:列表 / 按 id / 舰队流同读)。
32
42
  */
33
43
  export declare function engineScopeOf(subject: Subject | undefined): string;
44
+ /** 一只**持久的**属主串(会话 / run 行的属主列、续跑腿交来的属主、请求鉴权句柄的纯串主体)在那几面上的 scope:先过内部恢复管线,再经 {@link engineScopeOf};无主 ⇒ 匿名那一格。 */
45
+ export declare function engineScopeOfOwner(owner: string | null | undefined): string;
34
46
  //# sourceMappingURL=engine-identity.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { partsOf } from "./owner-brands.js";
2
- import { LEGACY_UNOWNED_AMNESTY_TENANT } from "./owner-faces.js";
2
+ import { LEGACY_UNOWNED_AMNESTY_TENANT, recoveredSubject } from "./owner-faces.js";
3
3
  export function specIdentityOf(parts) {
4
4
  if (parts === undefined)
5
5
  return { principal: undefined };
@@ -10,6 +10,14 @@ export function taskSpecIdentityOf(parts) {
10
10
  return principal === undefined ? {} : { principal };
11
11
  }
12
12
  export function engineScopeOf(subject) {
13
- return taskSpecIdentityOf(subject === undefined ? undefined : partsOf(subject)).principal ?? LEGACY_UNOWNED_AMNESTY_TENANT;
13
+ return scopeOfLanded(taskSpecIdentityOf(subject === undefined ? undefined : partsOf(subject)));
14
+ }
15
+ export function engineScopeOfOwner(owner) {
16
+ return engineScopeOf(recoveredSubject(owner));
17
+ }
18
+ function scopeOfLanded(landed) {
19
+ const { principal, ...unread } = landed;
20
+ unread;
21
+ return principal ?? LEGACY_UNOWNED_AMNESTY_TENANT;
14
22
  }
15
23
  //# sourceMappingURL=engine-identity.js.map