@sema-agent/server 7.145.0 → 7.146.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 (275) hide show
  1. package/MIGRATION.md +492 -0
  2. package/USAGE.md +218 -47
  3. package/deploy/facts/CHANGES.json +25 -0
  4. package/deploy/facts/README.md +57 -0
  5. package/deploy/facts/lanes.json +54 -0
  6. package/deploy/facts/lanes.schema.json +57 -0
  7. package/deploy/facts/sandbox-rbac.json +113 -0
  8. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  9. package/deploy/facts/sealed-key.json +9 -0
  10. package/deploy/facts/sealed-key.schema.json +52 -0
  11. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  12. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  13. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  14. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  15. package/deploy/sema-up/chart/values.yaml +7 -0
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  17. package/dist/adoption/import-limits.d.ts +6 -0
  18. package/dist/adoption/import-limits.js +7 -0
  19. package/dist/adoption/import.d.ts +62 -0
  20. package/dist/adoption/import.js +107 -0
  21. package/dist/adoption/wire.d.ts +52 -0
  22. package/dist/adoption/wire.js +9 -0
  23. package/dist/approval-ask-machine.d.ts +2 -2
  24. package/dist/approval-card.d.ts +3 -12
  25. package/dist/approval-card.js +0 -4
  26. package/dist/approval-gate-currency.d.ts +1 -1
  27. package/dist/approval-gate-currency.js +1 -1
  28. package/dist/approval-reconciler.d.ts +1 -1
  29. package/dist/boot/deployment-mods.d.ts +11 -1
  30. package/dist/boot/deployment-mods.js +15 -2
  31. package/dist/boot/device-lane.js +2 -0
  32. package/dist/boot/engine-lease.d.ts +193 -21
  33. package/dist/boot/engine-lease.js +146 -20
  34. package/dist/boot/execution-env.d.ts +4 -0
  35. package/dist/boot/execution-env.js +12 -0
  36. package/dist/boot/exit-boundary.d.ts +50 -0
  37. package/dist/boot/exit-boundary.js +32 -0
  38. package/dist/boot/exit-last.d.ts +20 -4
  39. package/dist/boot/exit-last.js +21 -4
  40. package/dist/boot/governance-seams.js +1 -0
  41. package/dist/boot/memory-consolidation.d.ts +29 -17
  42. package/dist/boot/memory-consolidation.js +26 -15
  43. package/dist/boot/reapers.d.ts +12 -4
  44. package/dist/boot/reapers.js +39 -15
  45. package/dist/boot/resolve-spec.d.ts +2 -0
  46. package/dist/boot/resolve-spec.js +38 -15
  47. package/dist/boot/runner-deps.js +1 -1
  48. package/dist/boot/session-faces.js +3 -1
  49. package/dist/boot/shutdown.js +27 -9
  50. package/dist/boot/stage-01-config.js +1 -1
  51. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  52. package/dist/boot/stage-03-store-backend.js +2 -2
  53. package/dist/boot/stage-04-stores.d.ts +1 -0
  54. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  55. package/dist/boot/stage-05-execution-env.js +3 -3
  56. package/dist/boot/stage-06-runners.d.ts +3 -0
  57. package/dist/boot/stage-06-runners.js +11 -10
  58. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  59. package/dist/boot/stage-07-capability-layer.js +7 -2
  60. package/dist/boot/stage-08-reapers.d.ts +3 -0
  61. package/dist/boot/stage-08-reapers.js +3 -3
  62. package/dist/boot/stage-09-leader.d.ts +3 -0
  63. package/dist/boot/stage-10-http-server.d.ts +3 -0
  64. package/dist/boot/stage-10-http-server.js +3 -2
  65. package/dist/boot/stores.d.ts +1 -0
  66. package/dist/boot/stores.js +35 -19
  67. package/dist/boot/workflow-orchestration.d.ts +1 -1
  68. package/dist/boot/workflow-orchestration.js +2 -1
  69. package/dist/capabilities/composite-members.d.ts +3 -1
  70. package/dist/capabilities/composite-members.js +3 -1
  71. package/dist/capabilities/scenarios.d.ts +2 -2
  72. package/dist/capability-facts.d.ts +18 -1
  73. package/dist/capability-facts.js +25 -7
  74. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  75. package/dist/config-catalog.js +13 -4
  76. package/dist/config-provider.d.ts +2 -2
  77. package/dist/config-types.d.ts +43 -4
  78. package/dist/config.d.ts +6 -1
  79. package/dist/config.js +67 -11
  80. package/dist/deleted-session-ids.d.ts +19 -0
  81. package/dist/deleted-session-ids.js +26 -0
  82. package/dist/deploy-facts.d.ts +155 -0
  83. package/dist/deploy-facts.js +94 -0
  84. package/dist/device-ws-hub.d.ts +48 -3
  85. package/dist/device-ws-hub.js +48 -2
  86. package/dist/error-code-family.d.ts +35 -0
  87. package/dist/error-code-family.js +26 -0
  88. package/dist/fleet/drain-entry.d.ts +39 -3
  89. package/dist/fleet/drain-entry.js +6 -0
  90. package/dist/fleet/fleet-bus.d.ts +2 -1
  91. package/dist/hooks/branch-transcript.d.ts +1 -1
  92. package/dist/hooks/branch-transcript.js +1 -0
  93. package/dist/hooks/classic-stations.d.ts +25 -8
  94. package/dist/hooks/classic-stations.js +29 -3
  95. package/dist/hooks/hook-runner.d.ts +33 -16
  96. package/dist/hooks/hook-runner.js +166 -73
  97. package/dist/hooks/hook-source.d.ts +14 -2
  98. package/dist/hooks/hook-source.js +8 -0
  99. package/dist/http/active-run-conflict.d.ts +1 -1
  100. package/dist/http/active-run-conflict.js +1 -1
  101. package/dist/http/admission.js +11 -1
  102. package/dist/http/checkpoint-ctx.d.ts +59 -71
  103. package/dist/http/checkpoint-ctx.js +34 -40
  104. package/dist/http/dispatch.js +18 -2
  105. package/dist/http/durable-run-leg.d.ts +5 -0
  106. package/dist/http/durable-run-leg.js +1 -0
  107. package/dist/http/execution-context.d.ts +4 -0
  108. package/dist/http/execution-context.js +9 -0
  109. package/dist/http/health-self-report.d.ts +6 -2
  110. package/dist/http/health-self-report.js +3 -2
  111. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  112. package/dist/http/memory-compliance-failure-reply.js +2 -15
  113. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  114. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  115. package/dist/http/principal-gate.d.ts +35 -12
  116. package/dist/http/principal-gate.js +16 -12
  117. package/dist/http/request-guards.d.ts +1 -1
  118. package/dist/http/request-guards.js +5 -5
  119. package/dist/http/resume-legs.d.ts +22 -0
  120. package/dist/http/resume-legs.js +26 -17
  121. package/dist/http/route-ctx.d.ts +11 -10
  122. package/dist/http/route-table.js +2 -0
  123. package/dist/http/routes/adoption.d.ts +11 -0
  124. package/dist/http/routes/adoption.js +80 -6
  125. package/dist/http/routes/agents-roster.js +1 -0
  126. package/dist/http/routes/approvals-assistant.js +2 -1
  127. package/dist/http/routes/background.js +1 -0
  128. package/dist/http/routes/capabilities.js +4 -1
  129. package/dist/http/routes/diagnostics.d.ts +9 -14
  130. package/dist/http/routes/diagnostics.js +10 -20
  131. package/dist/http/routes/engine.d.ts +31 -0
  132. package/dist/http/routes/engine.js +81 -0
  133. package/dist/http/routes/memory-bundle.js +3 -0
  134. package/dist/http/routes/memory-consolidation.js +3 -5
  135. package/dist/http/routes/memory-origin.d.ts +1 -1
  136. package/dist/http/routes/memory-origin.js +2 -4
  137. package/dist/http/routes/memory-policy.js +5 -1
  138. package/dist/http/routes/observability.js +3 -6
  139. package/dist/http/routes/runs.js +7 -3
  140. package/dist/http/routes/session-sync.js +12 -25
  141. package/dist/http/routes/sessions-list.d.ts +1 -1
  142. package/dist/http/routes/sessions.js +4 -0
  143. package/dist/http/routes/tasks.js +23 -5
  144. package/dist/http/routes/trace-usage.js +1 -1
  145. package/dist/http/run-concurrency-cap.d.ts +86 -0
  146. package/dist/http/run-concurrency-cap.js +54 -0
  147. package/dist/http/server.d.ts +15 -12
  148. package/dist/http/server.js +18 -3
  149. package/dist/http/stored-body-replay.d.ts +9 -6
  150. package/dist/http/stored-body-replay.js +19 -5
  151. package/dist/http/wire-types.d.ts +8 -3
  152. package/dist/json-body-limit.d.ts +8 -0
  153. package/dist/json-body-limit.js +2 -0
  154. package/dist/leader/diffout.d.ts +1 -1
  155. package/dist/local-data-root.d.ts +2 -2
  156. package/dist/memory-operator-faces.d.ts +9 -4
  157. package/dist/memory-scope-stores.d.ts +9 -7
  158. package/dist/memory-scope-stores.js +3 -14
  159. package/dist/memory-scope.d.ts +36 -0
  160. package/dist/memory-scope.js +32 -1
  161. package/dist/net-address.d.ts +53 -0
  162. package/dist/net-address.js +111 -0
  163. package/dist/observability/fail-open.d.ts +14 -10
  164. package/dist/observability/fail-open.js +14 -10
  165. package/dist/orchestration/workflow-notify-journal.js +2 -3
  166. package/dist/org-delivery-gate.js +1 -1
  167. package/dist/peer-directory.d.ts +6 -12
  168. package/dist/peer-directory.js +5 -1
  169. package/dist/plugins/caching-session-store.d.ts +3 -1
  170. package/dist/plugins/caching-session-store.js +3 -0
  171. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  172. package/dist/plugins/checkpoint-store-face.js +152 -0
  173. package/dist/plugins/file-run-store.d.ts +0 -6
  174. package/dist/plugins/file-run-store.js +1 -12
  175. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  176. package/dist/plugins/fork-routing-session-store.js +2 -2
  177. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  178. package/dist/plugins/local-checkpoint-store.d.ts +2 -2
  179. package/dist/plugins/local-checkpoint-store.js +2 -1
  180. package/dist/plugins/local-session-store.d.ts +28 -5
  181. package/dist/plugins/local-session-store.js +32 -8
  182. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  183. package/dist/plugins/memory-engine-pg.js +96 -214
  184. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  185. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  186. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  187. package/dist/plugins/memory-engine-tidb.js +97 -227
  188. package/dist/plugins/memory-key-guards.d.ts +1 -1
  189. package/dist/plugins/memory-origin-law.d.ts +3 -3
  190. package/dist/plugins/one-time-migrations.d.ts +32 -56
  191. package/dist/plugins/one-time-migrations.js +25 -117
  192. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  193. package/dist/plugins/permission-rule-store-file.js +8 -1
  194. package/dist/plugins/pg-pool.js +1 -1
  195. package/dist/plugins/pg-session-storage.d.ts +17 -4
  196. package/dist/plugins/pg-session-storage.js +8 -4
  197. package/dist/plugins/run-store-sql.js +2 -2
  198. package/dist/plugins/schema-ensure-legs.js +2 -2
  199. package/dist/plugins/session-fork.d.ts +31 -9
  200. package/dist/plugins/session-fork.js +3 -2
  201. package/dist/plugins/session-placement.d.ts +4 -2
  202. package/dist/plugins/sql-json-column.d.ts +5 -1
  203. package/dist/plugins/store-backend.d.ts +11 -8
  204. package/dist/plugins/store-backend.js +8 -7
  205. package/dist/plugins/store-contracts.d.ts +1 -11
  206. package/dist/plugins/store-contracts.js +0 -9
  207. package/dist/plugins/store-sweep.d.ts +63 -0
  208. package/dist/plugins/store-sweep.js +48 -0
  209. package/dist/plugins/tidb-pool.js +1 -1
  210. package/dist/plugins/tidb-session-store.d.ts +16 -3
  211. package/dist/plugins/tidb-session-store.js +8 -4
  212. package/dist/prompt-screen.d.ts +6 -9
  213. package/dist/prompt-screen.js +2 -5
  214. package/dist/rules-consent.d.ts +20 -27
  215. package/dist/rules-consent.js +82 -6
  216. package/dist/run-cancel-context.d.ts +4 -1
  217. package/dist/run-cancel-context.js +2 -1
  218. package/dist/runs.js +1 -1
  219. package/dist/sandbox-egress-policy.js +6 -11
  220. package/dist/sandbox-rbac-rules.d.ts +88 -0
  221. package/dist/sandbox-rbac-rules.js +80 -0
  222. package/dist/sealed-key-layout.d.ts +17 -0
  223. package/dist/sealed-key-layout.js +4 -0
  224. package/dist/sealed-key.js +5 -5
  225. package/dist/security.d.ts +38 -6
  226. package/dist/security.js +9 -2
  227. package/dist/session-notify-door.d.ts +5 -3
  228. package/dist/session-resident-background.d.ts +57 -0
  229. package/dist/session-resident-background.js +20 -0
  230. package/dist/session-sync-kernel.d.ts +53 -14
  231. package/dist/session-sync-kernel.js +70 -1
  232. package/dist/session-sync.d.ts +5 -3
  233. package/dist/session-workspace.d.ts +1 -0
  234. package/dist/session-workspace.js +1 -0
  235. package/dist/sighup-idle.d.ts +9 -7
  236. package/dist/sighup-idle.js +4 -5
  237. package/dist/spec-fields.d.ts +16 -0
  238. package/dist/spec-fields.js +7 -0
  239. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  240. package/dist/stored-request-env-credentials-m38.js +8 -0
  241. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  242. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
  243. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
  244. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  245. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  246. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  247. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  248. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  249. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  250. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  251. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  252. package/dist/task-settings.d.ts +59 -4
  253. package/dist/task-settings.js +50 -4
  254. package/dist/tool-approval.d.ts +2 -2
  255. package/dist/trace/core-keyset-guard.d.ts +8 -7
  256. package/dist/trace/engine-notice-wire.d.ts +1 -1
  257. package/dist/trace/engine-notice-wire.js +2 -0
  258. package/dist/trace/exit-seat.d.ts +6 -0
  259. package/dist/trace/exit-seat.js +1 -0
  260. package/dist/trace/project.js +9 -0
  261. package/dist/trace/redact.d.ts +13 -2
  262. package/dist/trace/redact.js +305 -24
  263. package/dist/trace/self-minted-wire.d.ts +326 -8
  264. package/dist/trace/self-minted-wire.js +125 -7
  265. package/dist/trace/wire-projection-faces.d.ts +1 -1
  266. package/dist/trace/wire-projection-faces.js +1 -1
  267. package/dist/usage-analytics.d.ts +4 -0
  268. package/package.json +12 -4
  269. package/scripts/drain-check-local.mjs +8 -29
  270. package/scripts/drain-check.mysql.sql +3 -24
  271. package/scripts/drain-check.pg.sql +3 -24
  272. package/skills/update-config.md +1 -1
  273. package/wire-changes/server@7.146.0.json +3221 -0
  274. package/dist/approval-batch-census.d.ts +0 -27
  275. package/dist/approval-batch-census.js +0 -27
@@ -92,7 +92,10 @@ kind: Service
92
92
  metadata: { name: sema-minio, namespace: sema }
93
93
  spec: { selector: { app: sema-minio }, ports: [{ name: s3, port: 9000 }, { name: console, port: 9001 }] }
94
94
  ---
95
- # ── 沙箱 lane RBAC(k8s+kata;pod 五动词 + 缓存卷四动词 + 沙箱秘密座 create + 出网自检的两只只读:本 ns 的 NetworkPolicy、集群的节点表)────────────────────────────────
95
+ # ── 沙箱 lane RBAC(k8s+kata):pod 生命周期 / exec / log、出网自检的两只只读(本 ns 的 NetworkPolicy、集群的节点表)恒授;
96
+ # 缓存卷的 persistentvolumeclaims 与沙箱秘密座的 secrets create 只在对应引擎旋钮(WORKSPACE_CACHE=volume / K8S_SANDBOX_ENV)开着时授 ——
97
+ # 本清单的引擎 env 两个都没设,所以这两条规则渲成注释块,开了旋钮就取消注释。
98
+ # 「哪条规则由哪个开关决定」只写在 server 源码的规则表 src/sandbox-rbac-rules.ts;下面两个规则区由 scripts/gen-deploy-lanes.ts 从它生成,不要手改。────────────────────────────────
96
99
  apiVersion: v1
97
100
  kind: ServiceAccount
98
101
  metadata: { name: sema-runner, namespace: sema-sandbox }
@@ -109,29 +112,38 @@ apiVersion: rbac.authorization.k8s.io/v1
109
112
  kind: Role
110
113
  metadata: { name: sema-runner, namespace: sema-sandbox }
111
114
  rules:
115
+ # @generated-begin sandbox-role-rules
116
+ # 沙箱 pod 的生命周期:remote-env-k8s.ts#createPod 建(POST pods)并读就绪(GET pods/<名>)· remote-env-k8s.ts#listSandboxPods 按标签列(GET pods?labelSelector)· remote-env-k8s.ts#reconnect 读存活(GET pods/<名>)· remote-env-k8s.ts#deletePod 删(DELETE pods/<名>)
117
+ # 兼容保留:chart 一直授着,适配器没有 watch 调用
112
118
  - apiGroups: [""]
113
119
  resources: [pods]
114
120
  verbs: [get, list, watch, create, delete]
121
+ # 在沙箱 pod 里执行命令:remote-env-k8s.ts#execUrl 拼 pods/<名>/exec 的连接地址
122
+ # 兼容保留:chart 一直授着,适配器没有 attach 调用
115
123
  - apiGroups: [""]
116
124
  resources: [pods/exec, pods/attach]
117
- verbs: [create, get]
125
+ verbs: [get, create]
126
+ # 兼容保留:chart 一直授着,适配器没有读日志的调用
118
127
  - apiGroups: [""]
119
128
  resources: [pods/log]
120
129
  verbs: [get]
121
- # 按工作区空间的构建缓存卷(WORKSPACE_CACHE=volume):连沙箱时按名读、没有就建;空间结束(会话删除 / 留存 sweep)按标签回收
122
- - apiGroups: [""]
123
- resources: [persistentvolumeclaims]
124
- verbs: [get, create, delete, deletecollection]
125
- # 沙箱秘密座:K8S_SANDBOX_ENV 点名的值只进每只 pod 自己的 Secret(pod spec 只带 secretKeyRef;Secret 属于 pod,随 pod 由集群回收)
126
- # 动词 = 适配器为 env Secret 真发的调用:create;不读回(无 get)、不删(随属主 pod 由集群 GC)。名单非空而缺它 ⇒ server 起服拒(起服 SelfSubjectAccessReview 问的正是它)
127
- # 成员 git 凭据平面(本版恒关)打开时,租约 Secret 还要 patch —— 那时再加
128
- - apiGroups: [""]
129
- resources: [secrets]
130
- verbs: [create]
131
- # 起服的出网自检读本 ns 的 NetworkPolicy(只读)
130
+ # 按工作区空间的构建缓存卷:remote-env-k8s.ts#ensureCacheClaim 按名读、没有就建(GET / POST persistentvolumeclaims)· remote-env-k8s.ts#cacheClaimBound 按名读 · remote-env-k8s.ts#reclaimSpaceCache 空间结束按标签回收(DELETE persistentvolumeclaims?labelSelector = deletecollection);缺它 ⇒ 缓存卷拿不到,适配器按 fail-open 照起、不挂卷(计数 server.workspace-cache.unavailable)
131
+ # 兼容保留:chart 一直授着,适配器回收只发按标签的 deletecollection,没有按名 delete 的调用
132
+ # 默认不授(本清单的 server env 没有 WORKSPACE_CACHE=volume):设了它就取消下面三行的注释:
133
+ # - apiGroups: [""]
134
+ # resources: [persistentvolumeclaims]
135
+ # verbs: [get, create, delete, deletecollection]
136
+ # 沙箱秘密座:动词取自 SANDBOX_SECRET_SEAT_VERBS.env —— 起服门(boot/execution-env.ts ensureSandboxSecretSeat)问的与 remote-env-k8s.ts#createOwnedSecret 为 env Secret 真发的(POST secrets)是同一行;起服门只在有效转发集合非空(名单点到的键在服务进程环境里有值)时问:答 denied ⇒ server 起服拒,问不到 ⇒ 告警 sandbox_secret_seat_unverified 照起;名单非空而有效集合为空时本行是保守多授(安装器看不到服务进程的运行时环境,引擎此时既不问也不调)
137
+ # 默认不授(本清单的 server env 没有 K8S_SANDBOX_ENV=NAME,NAME):设了它就取消下面三行的注释:
138
+ # - apiGroups: [""]
139
+ # resources: [secrets]
140
+ # verbs: [create]
141
+ # 起服的出网自检读本 ns 的 NetworkPolicy 集合:remote-env-k8s.ts#egressPolicyGaps(GET .../networkpolicies)
142
+ # 兼容保留:chart 一直授着,适配器只读集合(list),没有按名 get
132
143
  - apiGroups: [networking.k8s.io]
133
144
  resources: [networkpolicies]
134
145
  verbs: [get, list]
146
+ # @generated-end sandbox-role-rules
135
147
  ---
136
148
  apiVersion: rbac.authorization.k8s.io/v1
137
149
  kind: RoleBinding
@@ -139,14 +151,18 @@ metadata: { name: sema-runner, namespace: sema-sandbox }
139
151
  roleRef: { apiGroup: rbac.authorization.k8s.io, kind: Role, name: sema-runner }
140
152
  subjects: [{ kind: ServiceAccount, name: sema-runner, namespace: sema-sandbox }]
141
153
  ---
142
- # 出网自检读节点表(集群级对象 ⇒ ClusterRole;只读两动词)。与 chart 的 sandbox-rbac.yaml 同形。
154
+ # 出网自检读节点表(集群级对象 ⇒ ClusterRole + Binding 给同一只服务账号)。与 chart 的 sandbox-rbac.yaml 读同一张规则表。
143
155
  apiVersion: rbac.authorization.k8s.io/v1
144
156
  kind: ClusterRole
145
157
  metadata: { name: sema-runner-nodes-sema-sandbox }
146
158
  rules:
159
+ # @generated-begin sandbox-clusterrole-rules
160
+ # 出网自检读节点表(节点是集群级对象 ⇒ ClusterRole + Binding 给同一只服务账号):remote-env-k8s.ts#egressPolicyGaps(GET /api/v1/nodes)
161
+ # 兼容保留:chart 一直授着,适配器只读集合(list),没有按名 get
147
162
  - apiGroups: [""]
148
163
  resources: [nodes]
149
164
  verbs: [get, list]
165
+ # @generated-end sandbox-clusterrole-rules
150
166
  ---
151
167
  apiVersion: rbac.authorization.k8s.io/v1
152
168
  kind: ClusterRoleBinding
@@ -0,0 +1,6 @@
1
+ export declare const ADOPTION_IMPORT_MAX_SESSIONS_DEFAULT = 100;
2
+ export declare const ADOPTION_IMPORT_MAX_SESSIONS_FLOOR = 1;
3
+ export declare const ADOPTION_IMPORT_MAX_SESSION_BYTES_DEFAULT: number;
4
+ export declare const ADOPTION_IMPORT_MAX_SESSION_BYTES_FLOOR: number;
5
+ export declare const ADOPTION_IMPORT_MAX_SESSION_BYTES_CEILING: number;
6
+ //# sourceMappingURL=import-limits.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { MAX_JSON_BODY_BYTES } from "../json-body-limit.js";
2
+ export const ADOPTION_IMPORT_MAX_SESSIONS_DEFAULT = 100;
3
+ export const ADOPTION_IMPORT_MAX_SESSIONS_FLOOR = 1;
4
+ export const ADOPTION_IMPORT_MAX_SESSION_BYTES_DEFAULT = 6 * 1024 * 1024;
5
+ export const ADOPTION_IMPORT_MAX_SESSION_BYTES_FLOOR = 1024 * 1024;
6
+ export const ADOPTION_IMPORT_MAX_SESSION_BYTES_CEILING = MAX_JSON_BODY_BYTES - Buffer.byteLength(JSON.stringify({ sessions: [] }), "utf8");
7
+ //# sourceMappingURL=import-limits.js.map
@@ -0,0 +1,62 @@
1
+ import type { AdoptionLogStore, AdoptionRow } from "../plugins/adoption-log-sql.js";
2
+ import { type ImportStagingStore } from "../session-sync-kernel.js";
3
+ import { type AdoptionImportCapability, type AdoptionImportResult } from "./wire.js";
4
+ /**
5
+ * 幂等键 → 云端会话 id(②)。sha256 的原像是 `JSON.stringify([域, adoptionId, clientSessionId])` —— JSON 数组的编码是**单射**的(拿分隔符拼接不是:
6
+ * 任一半里出现分隔符就能伪造另一对),取前 16 字节,版本半字节写 `8`(RFC 9562 自定义形)、变体写 `10`,铸成 canonical uuid。
7
+ * 会话 id 的形门(`security.ts` 的 `isUuidShape`)收任何版本的 canonical uuid,所以这一只 id 在每扇带会话 id 的门上都可达;
8
+ * 版本 8 也让它与 core 铸的 uuidv7 永不同形(不会撞上一只普通会话)。
9
+ */
10
+ export declare function buildAdoptionImportSessionId(adoptionId: string, clientSessionId: string): string;
11
+ /** 一条收编行对一位调用者的判(①;闭集四臂,门按臂穷举下发)。 */
12
+ export type AdoptionImportBinding = {
13
+ readonly kind: "bound";
14
+ readonly adoptionId: string;
15
+ readonly toPrincipal: string;
16
+ } | {
17
+ readonly kind: "absent";
18
+ } | {
19
+ readonly kind: "not_source";
20
+ } | {
21
+ readonly kind: "not_adopted";
22
+ };
23
+ /** ① 的唯一判官:行不在 ⇒ `absent`;调用者不**逐字**等于源主体 ⇒ `not_source`(先于收编态:不是源主体的调用方读不出这一行走到了哪);
24
+ * 收编没走完 / 被拒 ⇒ `not_adopted`;否则 `bound`(目的地 = 行的目的主体)。 */
25
+ export declare function judgeAdoptionImportBinding(row: AdoptionRow | null, caller: string): AdoptionImportBinding;
26
+ /** 两只帽的当前值(配置 env 腿解析过的那一份;数字属主 `import-limits.ts`)。 */
27
+ export interface AdoptionImportLimits {
28
+ readonly adoptionImportMaxSessions: number;
29
+ readonly adoptionImportMaxSessionBytes: number;
30
+ }
31
+ /**
32
+ * 能力位 `adoptionImport` 的唯一铸点:部署半不在 / 没有已验身份 ⇒ 缺席;按调用者读它作为源主体的那一行(`from_principal` 唯一,恰一行或没有),
33
+ * 过 ① 的同一只判官,`bound` 才在场。读收编日志失败 ⇒ 缺席并走登记过的 F 类臂(能力面不为一次库抖动整只 500;缺席的方向是「入口藏起来」)。
34
+ */
35
+ export declare function readAdoptionImportCapability(face: {
36
+ readonly available: false;
37
+ } | {
38
+ readonly available: true;
39
+ readonly backend: {
40
+ adoptionLog(): AdoptionLogStore;
41
+ };
42
+ }, caller: string | undefined, limits: AdoptionImportLimits): Promise<AdoptionImportCapability | undefined>;
43
+ /** 请求体的形(恰 `{sessions: [...]}`)。读不出 ⇒ `undefined`(路由答 400 `request.body_shape`)。 */
44
+ export declare function readAdoptionImportBody(raw: unknown): readonly unknown[] | undefined;
45
+ /** 导入要的会话店那几口:只有暂存导入核(「已导过」由提交的属主判答,不读头);`evict` 在场 ⇒ 提交后丢掉缓存层的热句柄(提交经原始店写,绕过了缓存 —— 第二阶段同理)。 */
46
+ export type AdoptionImportSessionStore = ImportStagingStore & {
47
+ evict?(sessionId: string): void;
48
+ };
49
+ export interface AdoptionImportTarget {
50
+ readonly adoptionId: string;
51
+ readonly toPrincipal: string;
52
+ readonly maxSessionBytes: number;
53
+ readonly sessionStorage: AdoptionImportSessionStore;
54
+ }
55
+ /**
56
+ * 逐元素跑一批(顺序跑:体已整只在内存里且 ≤ JSON 体上限,逐个落暂存 + 提交)。每个元素的判序固定:
57
+ * 信封形(`invalid_envelope`)→ 同批重复 id(`duplicate_client_session_id`:同批第一个读得出这个 id 的元素认领它,不论它自己的结局)
58
+ * → 字节帽(`too_large`)→ 导入(②③;条目日志没过 core 的导入门 ⇒ `invalid_envelope`)。
59
+ * 店故障原样上抛(整请求 5xx;已落的元素重投答 `already_imported`)。
60
+ */
61
+ export declare function runAdoptionImport(target: AdoptionImportTarget, sessions: readonly unknown[]): Promise<AdoptionImportResult[]>;
62
+ //# sourceMappingURL=import.d.ts.map
@@ -0,0 +1,107 @@
1
+ import { createHash } from "node:crypto";
2
+ import { SessionError } from "@sema-agent/core";
3
+ import { createStagedLogFeed, MalformedImportEntryError, newStagingToken, StagedCommitOwnerChangedError } from "../session-sync-kernel.js";
4
+ import { STAGED_IMPORT_INVALID_SENTENCE } from "../session-error-wire.js";
5
+ import { recordFailOpen } from "../observability/fail-open.js";
6
+ import { AdoptionImportBodySchema, AdoptionImportEnvelopeSchema, ADOPTION_IMPORT_CLIENT_SESSION_ID_MAX_CHARS } from "./wire.js";
7
+ export function buildAdoptionImportSessionId(adoptionId, clientSessionId) {
8
+ const b = Buffer.from(createHash("sha256").update(JSON.stringify(["sema.adoption-import", adoptionId, clientSessionId])).digest().subarray(0, 16));
9
+ b[6] = (b[6] & 0x0f) | 0x80;
10
+ b[8] = (b[8] & 0x3f) | 0x80;
11
+ const hex = b.toString("hex");
12
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13
+ }
14
+ export function judgeAdoptionImportBinding(row, caller) {
15
+ if (row === null)
16
+ return { kind: "absent" };
17
+ if (row.fromPrincipal !== caller)
18
+ return { kind: "not_source" };
19
+ switch (row.state) {
20
+ case "adopted":
21
+ return { kind: "bound", adoptionId: row.adoptionId, toPrincipal: row.toPrincipal };
22
+ case "in_flight":
23
+ case "rejected":
24
+ return { kind: "not_adopted" };
25
+ default: {
26
+ const unknownState = row.state;
27
+ throw new Error(`adoption import: unknown adoption state ${JSON.stringify(unknownState)}`);
28
+ }
29
+ }
30
+ }
31
+ export async function readAdoptionImportCapability(face, caller, limits) {
32
+ if (!face.available || caller === undefined)
33
+ return undefined;
34
+ let row;
35
+ try {
36
+ row = await face.backend.adoptionLog().getByFrom(caller);
37
+ }
38
+ catch (err) {
39
+ recordFailOpen("server.capabilities.adoption-import-unreadable", err instanceof Error ? err.name : "non-error throw");
40
+ return undefined;
41
+ }
42
+ const binding = judgeAdoptionImportBinding(row, caller);
43
+ return binding.kind === "bound" ? { adoptionId: binding.adoptionId, maxSessions: limits.adoptionImportMaxSessions, maxSessionBytes: limits.adoptionImportMaxSessionBytes } : undefined;
44
+ }
45
+ export function readAdoptionImportBody(raw) {
46
+ const parsed = AdoptionImportBodySchema.safeParse(raw);
47
+ return parsed.success ? parsed.data.sessions : undefined;
48
+ }
49
+ const INVALID_ENVELOPE_SHAPE = `a session envelope is exactly {clientSessionId, entries}: clientSessionId a string of 1-${ADOPTION_IMPORT_CLIENT_SESSION_ID_MAX_CHARS} characters, entries an array of session entries (oldest first) — no other keys`;
50
+ function envelopeBytes(raw) {
51
+ return Buffer.byteLength(JSON.stringify(raw), "utf8");
52
+ }
53
+ export async function runAdoptionImport(target, sessions) {
54
+ const claimed = new Set();
55
+ const results = [];
56
+ for (const raw of sessions) {
57
+ const parsed = AdoptionImportEnvelopeSchema.safeParse(raw);
58
+ if (!parsed.success) {
59
+ results.push({ outcome: "rejected", code: "invalid_envelope", detail: INVALID_ENVELOPE_SHAPE });
60
+ continue;
61
+ }
62
+ const { clientSessionId, entries } = parsed.data;
63
+ if (claimed.has(clientSessionId)) {
64
+ results.push({ clientSessionId, outcome: "rejected", code: "duplicate_client_session_id" });
65
+ continue;
66
+ }
67
+ claimed.add(clientSessionId);
68
+ const bytes = envelopeBytes(raw);
69
+ if (bytes > target.maxSessionBytes) {
70
+ results.push({ clientSessionId, outcome: "rejected", code: "too_large", count: bytes, cap: target.maxSessionBytes });
71
+ continue;
72
+ }
73
+ results.push(await importOne(target, clientSessionId, entries));
74
+ }
75
+ return results;
76
+ }
77
+ async function importOne(target, clientSessionId, entries) {
78
+ const sessionId = buildAdoptionImportSessionId(target.adoptionId, clientSessionId);
79
+ const store = target.sessionStorage;
80
+ const handle = store.beginImportStaging(sessionId, newStagingToken());
81
+ try {
82
+ const feed = createStagedLogFeed(handle);
83
+ for (const e of entries)
84
+ await feed.push(e);
85
+ await feed.finish();
86
+ }
87
+ catch (e) {
88
+ await handle.abort().catch(() => undefined);
89
+ if (e instanceof MalformedImportEntryError)
90
+ return { clientSessionId, outcome: "rejected", code: "invalid_envelope", detail: e.message };
91
+ if (e instanceof SessionError && e.code === "invalid_session")
92
+ return { clientSessionId, outcome: "rejected", code: "invalid_envelope", detail: STAGED_IMPORT_INVALID_SENTENCE };
93
+ throw e;
94
+ }
95
+ try {
96
+ await handle.commit(target.toPrincipal, { expectedOwner: undefined });
97
+ }
98
+ catch (e) {
99
+ await handle.abort().catch(() => undefined);
100
+ if (e instanceof StagedCommitOwnerChangedError)
101
+ return { clientSessionId, outcome: "already_imported", sessionId };
102
+ throw e;
103
+ }
104
+ store.evict?.(sessionId);
105
+ return { clientSessionId, outcome: "imported", sessionId };
106
+ }
107
+ //# sourceMappingURL=import.js.map
@@ -253,4 +253,56 @@ export declare const AdoptionRequestSchema: z.ZodObject<{
253
253
  fromPrincipal: z.ZodString;
254
254
  toPrincipal: z.ZodString;
255
255
  }, z.core.$strict>;
256
+ /** 请求体:恰一键 `sessions`(会话信封数组)。`.strict()` —— 写面纪律;请求体里**没有**点名目的地的位置(目的地 = 收编行的目的主体)。 */
257
+ export declare const AdoptionImportBodySchema: z.ZodObject<{
258
+ sessions: z.ZodArray<z.ZodUnknown>;
259
+ }, z.core.$strict>;
260
+ /** `clientSessionId` 的长度上界(调用方本地 id;不进任何列 —— 它只进派生 id 的哈希原像,并在结局里原样回显)。 */
261
+ export declare const ADOPTION_IMPORT_CLIENT_SESSION_ID_MAX_CHARS = 255;
262
+ /**
263
+ * 一个会话信封 = 调用方本地的一只会话:`clientSessionId`(它的本地 id,幂等键的一半)+ `entries`(会话的条目日志,最老在前 —— 与会话同步
264
+ * 推送面逐行流的同一种条目,由 core 的导入门判)。恰这两键:多一个不认识的键 ⇒ 整个元素 `rejected` / `invalid_envelope`(不静默跳过)。
265
+ */
266
+ export declare const AdoptionImportEnvelopeSchema: z.ZodObject<{
267
+ clientSessionId: z.ZodString;
268
+ entries: z.ZodArray<z.ZodUnknown>;
269
+ }, z.core.$strict>;
270
+ export type AdoptionImportEnvelope = z.infer<typeof AdoptionImportEnvelopeSchema>;
271
+ /** `rejected` 的具名码**闭集**(三词,穷举;消费方按码给用户话):超字节 / 信封形不认识(含条目日志没过 core 的导入门)/ 同一批里第二个带同一 id 的元素。
272
+ * 跨批重投同一 id 不是 `duplicate_client_session_id` —— 那是 `already_imported`(幂等)。 */
273
+ export declare const ADOPTION_IMPORT_REJECT_CODES: readonly ["too_large", "invalid_envelope", "duplicate_client_session_id"];
274
+ export type AdoptionImportRejectCode = (typeof ADOPTION_IMPORT_REJECT_CODES)[number];
275
+ /**
276
+ * 一个元素的结局(结果数组与请求的 `sessions` **按位对应**:N 个进 ⇒ N 个出)。`clientSessionId` 在信封读得出时回显(信封形不认识时缺席 —— 位置就是对应关系)。
277
+ * · `imported` / `already_imported`:带云端 `sessionId`(= `(adoptionId, clientSessionId)` 的纯函数,两次答同一个);
278
+ * · `rejected` + `too_large`:带量到的信封字节 `count` 与当时的帽 `cap`;
279
+ * · `rejected` + `invalid_envelope`:带一句 `detail`(固定句,不回显条目内容);
280
+ * · `rejected` + `duplicate_client_session_id`:同批第一个带这个 id 的元素认领它,之后的都拒(不静默去重 —— 「提交了 N 条」与「云上有 N-1 条」对不上账)。
281
+ */
282
+ export type AdoptionImportResult = {
283
+ readonly clientSessionId: string;
284
+ readonly outcome: "imported" | "already_imported";
285
+ readonly sessionId: string;
286
+ } | {
287
+ readonly clientSessionId: string;
288
+ readonly outcome: "rejected";
289
+ readonly code: "too_large";
290
+ readonly count: number;
291
+ readonly cap: number;
292
+ } | {
293
+ readonly clientSessionId: string;
294
+ readonly outcome: "rejected";
295
+ readonly code: "duplicate_client_session_id";
296
+ } | {
297
+ readonly clientSessionId?: string;
298
+ readonly outcome: "rejected";
299
+ readonly code: "invalid_envelope";
300
+ readonly detail: string;
301
+ };
302
+ /** 能力位 `adoptionImport` 的值(present-iff 调用者是一条已收编行的源主体):导入口的 id + 两只帽的**当前值**(客户端据此分批,不撞 400 再收缩)。 */
303
+ export interface AdoptionImportCapability {
304
+ readonly adoptionId: string;
305
+ readonly maxSessions: number;
306
+ readonly maxSessionBytes: number;
307
+ }
256
308
  //# sourceMappingURL=wire.d.ts.map
@@ -77,4 +77,13 @@ export const AdoptionRequestSchema = z
77
77
  toPrincipal: z.string().min(1).max(190),
78
78
  })
79
79
  .strict();
80
+ export const AdoptionImportBodySchema = z.object({ sessions: z.array(z.unknown()) }).strict();
81
+ export const ADOPTION_IMPORT_CLIENT_SESSION_ID_MAX_CHARS = 255;
82
+ export const AdoptionImportEnvelopeSchema = z
83
+ .object({
84
+ clientSessionId: z.string().min(1).max(ADOPTION_IMPORT_CLIENT_SESSION_ID_MAX_CHARS),
85
+ entries: z.array(z.unknown()),
86
+ })
87
+ .strict();
88
+ export const ADOPTION_IMPORT_REJECT_CODES = ["too_large", "invalid_envelope", "duplicate_client_session_id"];
80
89
  //# sourceMappingURL=wire.js.map
@@ -36,8 +36,8 @@ export declare function canAskTransition(from: AskState, to: AskState): boolean;
36
36
  export declare function canBatchTransition(from: BatchState, to: BatchState): boolean;
37
37
  /**
38
38
  * `AskRequest.boundInputHash` 的**边界窄读**(唯一一只):ask 身份第四轴的入参那一半与行上 `bound_input_hash` 列(收敛器判据 1 的对账键)读的都是它。
39
- * core 在闸站铸值(`onAsk({ ...bare, boundInputHash: boundInputHashOf(presented.value), … })`,core 5.15.0 起每一只经 `resolveAsk` 的问都带);
40
- * `boundInputHashOf` 不在 core 的公开导出面上(包 `exports` 只有 `.` / `./bench` / `./fixtures`),本服务既算不出也不该算 —— 只原样读。
39
+ * core 在闸站铸值(`onAsk({ ...bare, boundInputHash: exactBoundInputHashOf(req.toolName, presented.value), … })`,core 5.15.0 起每一只经 `resolveAsk` 的问都带;
40
+ * 7.63.0 起摘的是 `{ tool, input }`,此前只摘入参);`exactBoundInputHashOf` 不在 core 的公开导出面上(包 `exports` 只有 `.` / `./bench` / `./fixtures`),本服务既算不出也不该算 —— 只原样读。
41
41
  * 非字符串 / 空串一律按缺席:一个形不对的摘要比没有摘要更危险(它会让「硬相等」这道门在一个垃圾值上偶然成立)。
42
42
  * 钉:`test/stream-approval-on-e2e.test.ts` 件4(正控 / 缺席 / 空串三臂)。
43
43
  */
@@ -54,7 +54,7 @@ export declare const MAX_RULE_OFFER_BATCH_MEMBERS = 8;
54
54
  /**
55
55
  * **一条**「不再询问」OFFER 的形(core 5.58.0 / [ref] §3.1 —— **BREAKING**,取代退役的
56
56
  * `RuleSuggestion`)。同步腿(`ApprovalCardSchema.ruleOffers` / `card_json`)与耐久腿(durable park 行的
57
- * `PendingCheckpoint.ruleOffers`,由 `plugins/checkpoint-store-sql.ts` 窄读)**共用这一份**。
57
+ * `PendingCheckpoint.ruleOffers`,由 `plugins/checkpoint-store-face.ts` 的 `boundedRuleOffers` 窄读)**共用这一份**。
58
58
  *
59
59
  * 🔴 单一属主(宪法 [ref]「schema 单一属主禁复制」):两条腿投的是 core 的**同一个** `RuleOffer`
60
60
  * (同步腿 = `AskRequest.ruleOffers`,耐久腿 = `PendingAction.ruleOffers`,core
@@ -138,7 +138,7 @@ export interface ReadRuleOffer {
138
138
  readonly offer: RuleOffer;
139
139
  }
140
140
  /**
141
- * **规则提议列表的唯一读者**(core 7.55.0 [ref] P1 阶段二)—— 两条腿同调:耐久腿(`checkpoint-store-sql.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行)
141
+ * **规则提议列表的唯一读者**(core 7.55.0 [ref] P1 阶段二)—— 两条腿同调:耐久腿(`checkpoint-store-face.ts` `boundedRuleOffers`:铸行落列、回读列、LOCAL 孪生读寄存行)
142
142
  * 与同步腿(`tool-approval.ts` `boundRuleOfferTexts`:活 ask 的 `AskRequest.ruleOffers`)。判官是 core 的 `readRuleOffers`:逐元素判、保原始下标、多余键逐级剥、
143
143
  * 闭集词(offer / 成员的 `kind`、`match`)不认 ⇒ 整只丢(batch 不拆成员)、无 `kind` 的存量成员读作 command、明细座不是「每个计数段一行」⇒ 只丢座。
144
144
  * 修前本仓自己一份不限长 zod 形,前面垫两只预筛(无 `kind` 成员的回填、明细座的座级筛)—— 读的是 core 铸的形,读法却是本仓一份;core 对两者的 76 种形逐一对过,不同的三种是本仓的明细座行数帽(留在这里)与两种非 JSON 值(数组带属性、类实例)。
@@ -149,15 +149,6 @@ export interface ReadRuleOffer {
149
149
  * 缺席(`undefined`)= 没有提议,答空、不计。展示帽(条数、成员前缀、扫描窗)、脱敏与截长归调用方 —— 它们是各腿的展示纪律,不是读法。
150
150
  */
151
151
  export declare function readRuleOfferList(raw: unknown): readonly ReadRuleOffer[];
152
- /**
153
- * 一份(已解码的)规则提议列表里,**带着无 `kind` 存量成员**的 batch offer 有几只 —— 判官是 core `readRuleOffers` 给每只读出的 offer 打的 `kindlessForm` 记号
154
- * (「这一只 batch 里至少一个成员是经无 `kind` 的存量形读的」;与 {@link readRuleOfferList} 同一只读者,不是本仓自己再写一遍「成员没有 `kind` 键」)。
155
- * 起服普查(`approval-batch-census.ts`)用它给存量行记数:读者那条存量臂退役的前提是「零行还靠它读」。
156
- *
157
- * **只数,不落任何痕迹**:读不出的元素(`dropped`)与整只值不是列表(`problem`)是 {@link readRuleOfferList} 的计数口径(`server.rule-offers.offer-dropped`),这里不重复记,
158
- * 它们也不是「靠存量臂读出来」的 —— 一个读不出的无 `kind` 成员(缺文本键)退役前后同样被丢,不改变任何一行的读法,所以不计入。
159
- */
160
- export declare function countKindlessBatchOffers(raw: unknown): number;
161
152
  /**
162
153
  * 卡面/帧面共用的 offer **投影型**(= {@link RuleOfferSchema} 的输出形)。判别位 `kind` 上闭集,
163
154
  * 消费端(SDK/cli 渲染)按 core 契约分臂;`batch.rules` 成员是判别联合(`command` | `directoryRead`),
@@ -518,7 +509,7 @@ export declare function parkRowFacts(stored: unknown): ParkRowFacts;
518
509
  * 本仓**不重算哈希**(core 的 `boundInputHashOf` 不在公开导出面上,清单校验读口 `readBoundBinding` 同样不导出),所以**不许**拿寄存行 `pendingAction` 上的原清单直接投 ——
519
510
  * 原值上的清单是未经哈希校验的(这正是它此前不上队列行的原因,见 `trace/core-keyset-guard.ts` ⑧b 记账的旧注)。两只店各自拿到「这一行的摘要」的办法不同
520
511
  * (LOCAL 孪生本来就握着 core 对同一行投的摘要;SQL 孪生在判官要的那一次整行读里调 core 的 `summarizeCheckpoint` —— 两位与 `rowVerdict` 同一次读、
521
- * 同一份按字节摘要的记忆,见 `plugins/checkpoint-store-sql.ts` 的 `storedRowProjections`),
512
+ * 同一份按字节摘要的记忆,见 `stores-sql/checkpoint-store-sql.ts` 的 `storedRowProjections`),
522
513
  * 但投影只有这一只:OMIT 契约 —— 缺席即缺席,恒不铸 `undefined` 值的键。
523
514
  *
524
515
  * `boundGrants` 是**部署文本**(技能名、清单条目):本函数不脱敏、不转义,与收件箱行逐字同口径 —— 渲染按上下文转义是客户端的事(契约同句)。
@@ -64,10 +64,6 @@ export function readRuleOfferList(raw) {
64
64
  reading.dropped.forEach((d) => recordOfferDropped(d.problem, d.index));
65
65
  return reading.offers.map(withDetailSeatBounded);
66
66
  }
67
- export function countKindlessBatchOffers(raw) {
68
- const reading = readRuleOffers(raw);
69
- return "problem" in reading ? 0 : reading.offers.filter((o) => o.kindlessForm === true).length;
70
- }
71
67
  function withoutOverCapDetailSeat(item, index) {
72
68
  if (typeof item !== "object" || item === null)
73
69
  return item;
@@ -65,7 +65,7 @@
65
65
  * (时刻与方向两处自 core 7.56.0 [ref] 起由筛判:I10 / I11。trace 投影读同一种记录、经同一只筛,零改即得 I10 —— 坏时刻在两个读者那里是同一个答法。)
66
66
  */
67
67
  import { type Checkpoint, type CheckpointToken, type SettlementKind } from "@sema-agent/core";
68
- import { type PendingRowBinding } from "./plugins/checkpoint-store-sql.js";
68
+ import { type PendingRowBinding } from "./plugins/checkpoint-store-face.js";
69
69
  import { type ParkedGateRead } from "./tool-approval.js";
70
70
  /**
71
71
  * 决断方回显的「我看到的那道门」—— 门的两个身份面之一(两面的来历与读法见模块头注「`approval_stale` 律」)。
@@ -1,5 +1,5 @@
1
1
  import { REOPEN_REASONS, checkpointRevOf, screenGateOutcome } from "@sema-agent/core";
2
- import { approvalDecisionOfWinner } from "./plugins/checkpoint-store-sql.js";
2
+ import { approvalDecisionOfWinner } from "./plugins/checkpoint-store-face.js";
3
3
  import {} from "./tool-approval.js";
4
4
  import { APPROVAL_GATE_KINDS } from "./approval-content-kind.js";
5
5
  import { trustedCheckpointId } from "./checkpoint-identity.js";
@@ -1,7 +1,7 @@
1
1
  import type { AskRow, ApprovalAskStore } from "./plugins/approval-ask-store-sql.js";
2
2
  import type { UnattendedApprovalPolicy } from "./tool-approval.js";
3
3
  import type { BatchState } from "./approval-ask-machine.js";
4
- import type { CheckpointAskCandidate } from "./plugins/checkpoint-store-sql.js";
4
+ import type { CheckpointAskCandidate } from "./plugins/checkpoint-store-face.js";
5
5
  import { type RunRecord } from "./plugins/store-contracts.js";
6
6
  import type { Logger } from "./observability/logger.js";
7
7
  import type { Metrics } from "./observability/metrics.js";
@@ -40,11 +40,21 @@ export interface LoadedModPackage {
40
40
  /** 读包者交回的三件字节摘要(`ModPackageRegistration.digest`,按给值记)—— 认得出「装的是哪几份字节」,不是代码完整性凭据。 */
41
41
  readonly digest: string;
42
42
  }
43
- /** 装配的结果:部署座的注册(自铸在前、声明在后,整列已过引擎准入)与装上的声明包(只数声明的包,自铸的不算)。 */
43
+ /** 装配的结果:部署座的注册(自铸在前、声明在后,整列已过引擎准入)、装上的声明包(只数声明的包,自铸的不算)与部署座的链站点式样。 */
44
44
  export interface DeploymentModsAssembly {
45
45
  readonly registrations: readonly ModRegistration<EngineDollar>[];
46
46
  readonly loaded: readonly LoadedModPackage[];
47
+ /** 部署座在**任务座之下**挂了链成员(不是观察者)的站点式样 —— 引擎这一次准入的记录读出({@link belowTaskChainPatternsOf})。读者:请求 `settings.hooks` 托管车道的只许收紧判据(`hooks/hook-runner.ts` 的 `managedTightenOnlyOn`)。 */
48
+ readonly belowTaskChainPatterns: readonly string[];
47
49
  }
50
+ /**
51
+ * 部署座在**任务座之下**挂了链成员的站点式样(去重,按准入序)。「之下」按引擎的跑序读:先按档(`MOD_TIERS` 的序),同档里部署座在任务座之前 ⇒
52
+ * 只有档排在任务座档之后的部署注册(今天是 `append`)在任务座之下;`prepend` 与同档 `user` 的部署注册在任务座之上(它们先判、再在答回来的结果上判,运维 handler 恒在请求钩子之上)。
53
+ * 每张准入了的、站在任务座之下的部署注册取 `events`(引擎记下的、它真挂了 handler 的式样)减去 `observe`(那张注册在该式样上只挂了观察者)。
54
+ * 读的是引擎的准入记录,不是注册自报的 `uses` —— 一处事实一个读法。式样的文法(精确站名或 `<前缀>.*`)由读者按引擎的定义读(`hooks/hook-runner.ts` 的 `chainsBelowTaskOn`)。
55
+ * 是**上界**:记录不带匹配器,带匹配器的 handler 在不中的那一次派发里不进链(引擎按派发取链)⇒ 读者只拿它收紧、从不拿它换挂法或放宽。
56
+ */
57
+ export declare function belowTaskChainPatternsOf(records: readonly ModAdmissionRecord[]): readonly string[];
48
58
  /** 部署座的唯一装配口(两只起服入口同调;三段与失败见文件头注)。 */
49
59
  export declare function assembleDeploymentMods(input: {
50
60
  readonly metrics: Pick<Metrics, "inc">;
@@ -1,6 +1,6 @@
1
1
  import { realpathSync, statSync } from "node:fs";
2
2
  import { isAbsolute, relative, sep } from "node:path";
3
- import { admitModChain, KERNEL_CONTRACT_VERSION, loadModPackage } from "@sema-agent/core";
3
+ import { admitModChain, KERNEL_CONTRACT_VERSION, loadModPackage, MOD_TIERS } from "@sema-agent/core";
4
4
  import { createBrandIdentityRegistration } from "../capabilities/brand-identity.js";
5
5
  import { createPermissionDeniedMeter, createToolTracer } from "../observability/tool-trace.js";
6
6
  import { errorCodeOf, errorText } from "../observability/err-text.js";
@@ -14,6 +14,19 @@ export function createDeploymentMods(input) {
14
14
  ...(input.brandIdentity === true ? [createBrandIdentityRegistration()] : []),
15
15
  ].map((registration) => ({ ...registration, provenance: MOD_PROVENANCE.minted }));
16
16
  }
17
+ const TASK_SEAT_TIER = "user";
18
+ export function belowTaskChainPatternsOf(records) {
19
+ const out = new Set();
20
+ const taskTier = MOD_TIERS.indexOf(TASK_SEAT_TIER);
21
+ for (const r of records) {
22
+ if (r.seat !== "deployment" || "refusedBy" in r || MOD_TIERS.indexOf(r.tier) <= taskTier)
23
+ continue;
24
+ for (const p of r.events)
25
+ if (!(r.observe ?? []).includes(p))
26
+ out.add(p);
27
+ }
28
+ return [...out];
29
+ }
17
30
  export async function assembleDeploymentMods(input) {
18
31
  const minted = createDeploymentMods(input);
19
32
  const resolved = resolveDeclaredPackages(input.declaration);
@@ -25,7 +38,7 @@ export async function assembleDeploymentMods(input) {
25
38
  const loaded = resolved.map(({ pkg }, i) => ({ name: pkg.name, tier: admittedRecordOf(records, pkg.name).tier, contract: KERNEL_CONTRACT_VERSION, digest: declared[i].digest }));
26
39
  for (const row of loaded)
27
40
  input.logger.info("mods_package_loaded", { name: sanitizeWireText(row.name), tier: row.tier, contract: row.contract, digest: row.digest });
28
- return { registrations, loaded };
41
+ return { registrations, loaded, belowTaskChainPatterns: belowTaskChainPatternsOf(records) };
29
42
  }
30
43
  function fsCauseOf(e) {
31
44
  const code = errorCodeOf(e);
@@ -30,12 +30,14 @@ export function createDeviceLane(ctx) {
30
30
  ...(knobs?.reconnectGraceMs != null ? { reconnectGraceMs: knobs.reconnectGraceMs } : {}),
31
31
  ...(knobs?.maxInflightPerDevice != null ? { maxInflightPerDevice: knobs.maxInflightPerDevice } : {}),
32
32
  ...(knobs?.maxPreAuthPerRemote !== undefined ? { maxPreAuthConnectionsPerRemote: knobs.maxPreAuthPerRemote } : {}),
33
+ ...(knobs?.trustedProxyCidrs !== undefined ? { trustedProxyCidrs: knobs.trustedProxyCidrs } : {}),
33
34
  ...(knobs?.supersede ? { supersede: knobs.supersede } : {}),
34
35
  });
35
36
  logger.info("device_lane_enabled", {
36
37
  replicaId,
37
38
  maxInflightPerDevice: knobs?.maxInflightPerDevice ?? 4,
38
39
  maxPreAuthPerRemote: knobs?.maxPreAuthPerRemote ?? 8,
40
+ trustedProxyCidrs: knobs?.trustedProxyCidrs?.length ?? 0,
39
41
  enrollRateLimit: `${DEVICE_ENROLL_RATE_POLICY.limit}/${DEVICE_ENROLL_RATE_POLICY.windowMs / 1000}s per caller identity (per replica; independent of RATE_LIMIT_RPM)`,
40
42
  });
41
43
  return { store, enrollment, hub, seat };