@sema-agent/server 7.138.0 → 7.140.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 (332) hide show
  1. package/MIGRATION.md +457 -7
  2. package/README.md +7 -4
  3. package/README.zh-CN.md +6 -4
  4. package/USAGE.md +91 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/runner.js +1 -1
  8. package/dist/adoption/sql.js +1 -1
  9. package/dist/adoption/wire.d.ts +3 -3
  10. package/dist/approval-card.d.ts +26 -26
  11. package/dist/bench/s1/arms.d.ts +1 -1
  12. package/dist/bench/s1/arms.js +1 -3
  13. package/dist/bench/s1/live-deps.js +3 -2
  14. package/dist/bench/s1/row.d.ts +5 -2
  15. package/dist/bench/s1/row.js +2 -22
  16. package/dist/bench/s1/run-firm.js +2 -2
  17. package/dist/boot/adoption.js +1 -1
  18. package/dist/boot/device-lane.d.ts +8 -3
  19. package/dist/boot/device-lane.js +7 -2
  20. package/dist/boot/execution-env.d.ts +4 -2
  21. package/dist/boot/execution-env.js +28 -34
  22. package/dist/boot/execution-lane.d.ts +9 -1
  23. package/dist/boot/execution-lane.js +6 -1
  24. package/dist/boot/governance-seams.d.ts +3 -2
  25. package/dist/boot/governance-seams.js +9 -11
  26. package/dist/boot/memory-boundary.d.ts +14 -51
  27. package/dist/boot/memory-boundary.js +10 -20
  28. package/dist/boot/memory-consolidation.d.ts +15 -11
  29. package/dist/boot/memory-consolidation.js +25 -14
  30. package/dist/boot/resolve-spec.d.ts +4 -6
  31. package/dist/boot/resolve-spec.js +10 -13
  32. package/dist/boot/retention-lane.d.ts +5 -5
  33. package/dist/boot/retention-lane.js +0 -6
  34. package/dist/boot/runner-deps.d.ts +6 -4
  35. package/dist/boot/runner-deps.js +3 -1
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  40. package/dist/boot/stage-03-store-backend.js +2 -3
  41. package/dist/boot/stage-04-stores.d.ts +2 -6
  42. package/dist/boot/stage-04-stores.js +5 -5
  43. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  44. package/dist/boot/stage-05-execution-env.js +2 -2
  45. package/dist/boot/stage-06-runners.d.ts +2 -6
  46. package/dist/boot/stage-06-runners.js +2 -3
  47. package/dist/boot/stage-07-capability-layer.d.ts +2 -6
  48. package/dist/boot/stage-08-reapers.d.ts +2 -6
  49. package/dist/boot/stage-09-leader.d.ts +2 -6
  50. package/dist/boot/stage-09-leader.js +1 -2
  51. package/dist/boot/stage-10-http-server.d.ts +2 -6
  52. package/dist/boot/stage-10-http-server.js +7 -6
  53. package/dist/boot/stores.d.ts +3 -6
  54. package/dist/boot/stores.js +27 -40
  55. package/dist/boot/task-list-lane.d.ts +1 -1
  56. package/dist/boot/task-list-lane.js +1 -1
  57. package/dist/boot/web-admin.js +37 -11
  58. package/dist/capabilities/execution-lane.d.ts +2 -2
  59. package/dist/capabilities/mcp-probe.js +1 -1
  60. package/dist/capabilities/scenarios.d.ts +1 -1
  61. package/dist/capability-facts.d.ts +15 -7
  62. package/dist/capability-facts.js +8 -3
  63. package/dist/config-catalog.js +9 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +33 -37
  67. package/dist/config-provider.js +51 -30
  68. package/dist/config-types.d.ts +21 -7
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +46 -16
  71. package/dist/delegated-session-owner.d.ts +4 -3
  72. package/dist/delegated-session-owner.js +1 -1
  73. package/dist/deployment-shape.d.ts +10 -9
  74. package/dist/deployment-shape.js +4 -4
  75. package/dist/device-enrollment.d.ts +41 -2
  76. package/dist/device-enrollment.js +27 -12
  77. package/dist/device-store.d.ts +58 -85
  78. package/dist/device-store.js +19 -49
  79. package/dist/device-ws-hub.js +2 -1
  80. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  81. package/dist/exec-cut.d.ts +60 -0
  82. package/dist/exec-cut.js +36 -0
  83. package/dist/execution-lane-caps.d.ts +115 -105
  84. package/dist/execution-lane-caps.js +76 -82
  85. package/dist/execution-placement.d.ts +259 -0
  86. package/dist/execution-placement.js +199 -0
  87. package/dist/field-conflict.d.ts +3 -2
  88. package/dist/field-conflict.js +1 -0
  89. package/dist/hosted-posture.d.ts +2 -2
  90. package/dist/http/admission.js +8 -19
  91. package/dist/http/checkpoint-ctx.d.ts +21 -12
  92. package/dist/http/checkpoint-ctx.js +4 -2
  93. package/dist/http/claimed-run.d.ts +1 -1
  94. package/dist/http/durable-run-leg.js +9 -5
  95. package/dist/http/execution-context.d.ts +218 -0
  96. package/dist/http/execution-context.js +330 -0
  97. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  98. package/dist/http/memory-compliance-failure-reply.js +5 -0
  99. package/dist/http/memory-layer-reply.d.ts +30 -0
  100. package/dist/http/memory-layer-reply.js +24 -0
  101. package/dist/http/resume-legs.js +63 -36
  102. package/dist/http/retired-service-deps.d.ts +1 -1
  103. package/dist/http/retired-service-deps.js +1 -1
  104. package/dist/http/route-ctx.d.ts +14 -8
  105. package/dist/http/routes/adoption.js +1 -1
  106. package/dist/http/routes/background.d.ts +29 -1
  107. package/dist/http/routes/background.js +29 -2
  108. package/dist/http/routes/devices.d.ts +13 -19
  109. package/dist/http/routes/devices.js +21 -26
  110. package/dist/http/routes/memory-bundle.js +3 -0
  111. package/dist/http/routes/memory-compliance.js +8 -1
  112. package/dist/http/routes/memory-consolidation.js +12 -1
  113. package/dist/http/routes/memory-origin.js +14 -2
  114. package/dist/http/routes/memory-policy.js +5 -0
  115. package/dist/http/routes/session-sync.js +110 -15
  116. package/dist/http/routes/sessions.d.ts +6 -0
  117. package/dist/http/routes/sessions.js +143 -22
  118. package/dist/http/routes/side-query.d.ts +12 -4
  119. package/dist/http/routes/side-query.js +4 -5
  120. package/dist/http/routes/tasks.js +41 -33
  121. package/dist/http/server.d.ts +40 -44
  122. package/dist/http/server.js +13 -2
  123. package/dist/http/session-inherit-env.d.ts +3 -4
  124. package/dist/http/session-inherit-env.js +1 -1
  125. package/dist/http/wire-types.d.ts +8 -12
  126. package/dist/identity-source.d.ts +1 -1
  127. package/dist/identity-source.js +1 -1
  128. package/dist/index.d.ts +1 -0
  129. package/dist/lane-home-probe.d.ts +68 -42
  130. package/dist/lane-home-probe.js +53 -30
  131. package/dist/leader/wire.js +5 -4
  132. package/dist/memory-bundle-engine.d.ts +16 -9
  133. package/dist/memory-bundle-engine.js +29 -6
  134. package/dist/memory-operator-faces.d.ts +85 -30
  135. package/dist/memory-operator-faces.js +136 -30
  136. package/dist/memory-project-layer.d.ts +3 -21
  137. package/dist/memory-project-layer.js +11 -8
  138. package/dist/memory-scope-stores.d.ts +73 -0
  139. package/dist/memory-scope-stores.js +86 -0
  140. package/dist/memory-scope.d.ts +29 -5
  141. package/dist/memory-scope.js +16 -4
  142. package/dist/memory-sync-client.d.ts +70 -18
  143. package/dist/memory-sync-client.js +215 -117
  144. package/dist/memory-sync.d.ts +1 -1
  145. package/dist/memory-sync.js +3 -2
  146. package/dist/observability/cost-taxonomy.d.ts +2 -2
  147. package/dist/observability/fail-open.d.ts +12 -0
  148. package/dist/observability/fail-open.js +12 -0
  149. package/dist/observability/run-terminal.js +0 -1
  150. package/dist/orchestration/workflow-notify-journal.js +4 -4
  151. package/dist/org-memory-admission.d.ts +4 -3
  152. package/dist/org-memory-admission.js +6 -6
  153. package/dist/parked-decide.d.ts +34 -9
  154. package/dist/parked-decide.js +12 -19
  155. package/dist/parked-revive-surface.d.ts +12 -15
  156. package/dist/parked-revive-surface.js +3 -6
  157. package/dist/peer-seat.d.ts +13 -7
  158. package/dist/peer-seat.js +37 -3
  159. package/dist/plugins/adoption-log-sql.js +4 -4
  160. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  161. package/dist/plugins/approval-ask-store-file.js +11 -0
  162. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  163. package/dist/plugins/approval-ask-store-memory.js +12 -0
  164. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  165. package/dist/plugins/approval-ask-store-sql.js +44 -26
  166. package/dist/plugins/approval-nonce-store.js +4 -4
  167. package/dist/plugins/blob-backend.d.ts +4 -4
  168. package/dist/plugins/blob-backend.js +7 -7
  169. package/dist/plugins/breaker-state-sql.js +2 -2
  170. package/dist/plugins/caching-session-store.d.ts +6 -2
  171. package/dist/plugins/caching-session-store.js +9 -3
  172. package/dist/plugins/checkpoint-index-columns.js +2 -2
  173. package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
  174. package/dist/plugins/checkpoint-store-sql.js +21 -23
  175. package/dist/plugins/device-store-sql.d.ts +25 -51
  176. package/dist/plugins/device-store-sql.js +68 -122
  177. package/dist/plugins/ensure-index.d.ts +1 -2
  178. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  179. package/dist/plugins/execution-placement-sql.js +223 -0
  180. package/dist/plugins/file-history-store-sql.d.ts +9 -8
  181. package/dist/plugins/file-history-store-sql.js +9 -9
  182. package/dist/plugins/file-run-store.d.ts +6 -1
  183. package/dist/plugins/file-run-store.js +4 -0
  184. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  185. package/dist/plugins/fork-routing-session-store.js +16 -0
  186. package/dist/plugins/image-bake-store-sql.js +9 -9
  187. package/dist/plugins/image-index-sql.js +11 -11
  188. package/dist/plugins/leader-run-store-sql.js +4 -4
  189. package/dist/plugins/local-session-store.d.ts +149 -50
  190. package/dist/plugins/local-session-store.js +382 -107
  191. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  192. package/dist/plugins/mailbox-store-sql.js +4 -4
  193. package/dist/plugins/memory-engine-tidb.js +5 -5
  194. package/dist/plugins/memory-key-guards.d.ts +4 -0
  195. package/dist/plugins/memory-key-guards.js +1 -0
  196. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  197. package/dist/plugins/memory-run-store.d.ts +1 -1
  198. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  199. package/dist/plugins/one-time-migrations.d.ts +117 -8
  200. package/dist/plugins/one-time-migrations.js +408 -38
  201. package/dist/plugins/org-delivery-quota-store.js +2 -2
  202. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  203. package/dist/plugins/outcome-ledger-sql.js +2 -2
  204. package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
  205. package/dist/plugins/permission-rule-store-sql.js +29 -32
  206. package/dist/plugins/pg-pool.d.ts +7 -3
  207. package/dist/plugins/pg-session-storage.d.ts +31 -20
  208. package/dist/plugins/pg-session-storage.js +120 -52
  209. package/dist/plugins/remote-env-adb.d.ts +18 -19
  210. package/dist/plugins/remote-env-adb.js +91 -66
  211. package/dist/plugins/remote-env-device.d.ts +23 -31
  212. package/dist/plugins/remote-env-device.js +19 -17
  213. package/dist/plugins/remote-env-e2b.d.ts +27 -21
  214. package/dist/plugins/remote-env-e2b.js +91 -45
  215. package/dist/plugins/remote-env-file-error.d.ts +3 -1
  216. package/dist/plugins/remote-env-file-error.js +9 -3
  217. package/dist/plugins/remote-env-host.d.ts +31 -34
  218. package/dist/plugins/remote-env-host.js +91 -72
  219. package/dist/plugins/remote-env-k8s.d.ts +13 -29
  220. package/dist/plugins/remote-env-k8s.js +63 -55
  221. package/dist/plugins/remote-env-local-docker.d.ts +24 -12
  222. package/dist/plugins/remote-env-local-docker.js +49 -61
  223. package/dist/plugins/remote-env-ssh.d.ts +11 -19
  224. package/dist/plugins/remote-env-ssh.js +74 -57
  225. package/dist/plugins/remote-shell.d.ts +100 -3
  226. package/dist/plugins/remote-shell.js +166 -2
  227. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  228. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  229. package/dist/plugins/retention-lane-store-sql.js +2 -2
  230. package/dist/plugins/retention-store-sql.d.ts +10 -7
  231. package/dist/plugins/retention-store-sql.js +13 -7
  232. package/dist/plugins/run-store-sql.d.ts +13 -3
  233. package/dist/plugins/run-store-sql.js +20 -15
  234. package/dist/plugins/schema-consistency.d.ts +21 -11
  235. package/dist/plugins/schema-consistency.js +15 -9
  236. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  237. package/dist/plugins/schema-drift-sentence.js +38 -0
  238. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  239. package/dist/plugins/schema-ensure-legs.js +2 -2
  240. package/dist/plugins/schema-live-columns.d.ts +1 -1
  241. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  242. package/dist/plugins/session-fork.d.ts +54 -0
  243. package/dist/plugins/session-fork.js +38 -1
  244. package/dist/plugins/session-row-sql.d.ts +22 -0
  245. package/dist/plugins/session-row-sql.js +81 -0
  246. package/dist/plugins/session-rules-column.d.ts +1 -1
  247. package/dist/plugins/session-rules-column.js +1 -1
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  250. package/dist/plugins/session-workspace-cell.js +1 -1
  251. package/dist/plugins/shared-memory-store-sql.js +2 -2
  252. package/dist/plugins/sql-driver.d.ts +10 -5
  253. package/dist/plugins/sql-driver.js +6 -6
  254. package/dist/plugins/sql-errors.js +1 -1
  255. package/dist/plugins/store-backend.d.ts +5 -7
  256. package/dist/plugins/store-backend.js +23 -11
  257. package/dist/plugins/store-contracts.d.ts +25 -5
  258. package/dist/plugins/task-list-store-sql.js +11 -11
  259. package/dist/plugins/tidb-pool.d.ts +12 -7
  260. package/dist/plugins/tidb-pool.js +13 -7
  261. package/dist/plugins/tidb-session-storage.js +4 -4
  262. package/dist/plugins/tidb-session-store.d.ts +57 -26
  263. package/dist/plugins/tidb-session-store.js +127 -59
  264. package/dist/plugins/tool-result-store-sql.d.ts +5 -4
  265. package/dist/plugins/tool-result-store-sql.js +21 -13
  266. package/dist/plugins/user-input-ledger-sql.js +2 -2
  267. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  268. package/dist/plugins/workflow-run-store-sql.js +19 -19
  269. package/dist/plugins/write-behind-counter.d.ts +2 -3
  270. package/dist/plugins/write-behind-counter.js +5 -5
  271. package/dist/project-memory.d.ts +9 -15
  272. package/dist/project-memory.js +5 -4
  273. package/dist/request-key-closure.js +1 -1
  274. package/dist/request-value-closure.d.ts +6 -7
  275. package/dist/request-value-closure.js +1 -3
  276. package/dist/resource-suspend.d.ts +14 -12
  277. package/dist/resource-suspend.js +1 -1
  278. package/dist/resource-window.d.ts +4 -3
  279. package/dist/run-local.d.ts +6 -0
  280. package/dist/run-local.js +34 -35
  281. package/dist/runs.d.ts +10 -5
  282. package/dist/runs.js +52 -66
  283. package/dist/security.d.ts +38 -12
  284. package/dist/security.js +8 -2
  285. package/dist/server-secret-env.d.ts +9 -5
  286. package/dist/session-children-retire.d.ts +27 -9
  287. package/dist/session-children-retire.js +9 -5
  288. package/dist/session-incarnation.d.ts +20 -10
  289. package/dist/session-incarnation.js +5 -3
  290. package/dist/session-policy-wire.d.ts +1 -1
  291. package/dist/session-row.d.ts +114 -5
  292. package/dist/session-row.js +55 -5
  293. package/dist/session-titler.d.ts +2 -2
  294. package/dist/sql-engine-posture.d.ts +1 -1
  295. package/dist/sql-engine-posture.js +1 -1
  296. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  297. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  298. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  299. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  300. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  301. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  302. package/dist/task-a2a.d.ts +1 -1
  303. package/dist/task-a2a.js +5 -6
  304. package/dist/task-cwd.d.ts +6 -1
  305. package/dist/task-mcp.d.ts +22 -9
  306. package/dist/task-mcp.js +17 -9
  307. package/dist/terminal.d.ts +27 -0
  308. package/dist/terminal.js +6 -0
  309. package/dist/tool-approval.d.ts +6 -0
  310. package/dist/tool-approval.js +8 -1
  311. package/dist/trace/project.d.ts +1 -0
  312. package/dist/trace/project.js +1 -0
  313. package/dist/trace/redact.d.ts +3 -1
  314. package/dist/trace/redact.js +80 -28
  315. package/dist/trace/self-minted-wire.d.ts +169 -2
  316. package/dist/trace/self-minted-wire.js +54 -1
  317. package/dist/url-refusal.d.ts +1 -1
  318. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  319. package/dist/web-admin-client/apply-effective.js +20 -10
  320. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  321. package/dist/web-admin-client/candidate-gate.js +1 -1
  322. package/dist/web-admin-client/http-client.d.ts +5 -4
  323. package/dist/web-admin-client/http-client.js +2 -2
  324. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  325. package/dist/web-admin-client/read-warnings.js +5 -9
  326. package/dist/web-admin-client/skills-mcp.js +3 -2
  327. package/dist/web-admin-client/types.d.ts +6 -0
  328. package/package.json +3 -3
  329. package/wire-changes/server@7.139.0.json +348 -0
  330. package/wire-changes/server@7.140.0.json +184 -0
  331. package/dist/http/device-placement.d.ts +0 -175
  332. package/dist/http/device-placement.js +0 -145
@@ -129,6 +129,33 @@ export declare function nestedPauseOf(terminal: TerminalCause): PausedCause | un
129
129
  * status 恒 `"failed"`)。因由形下两条路径合成一句话,规则从二变一。
130
130
  */
131
131
  export declare function pausedCauseOf(terminal: TerminalCause): PausedCause | undefined;
132
+ /**
133
+ * **宿主边界上的诚实终局** —— 宿主 run 行停不停、停在哪个词上,只问这一只判官。
134
+ *
135
+ * · 本腿自己的 `paused` ⇒ 原样(它就是宿主腿的停驻);
136
+ * · `failed.nestedPause` 且 `result.sessionId === hostSessionId` ⇒ 把那次停驻**整只**提成本腿的终局因由
137
+ * (门 / 凭据 / `checkpointId` 同址;结果的其余格 —— `stats` / `verification` / … —— 原样);
138
+ * · 其余 ⇒ **同一引用**原样(真失败;或嵌套停驻的卡不在宿主会话上)。
139
+ *
140
+ * 为什么判据是「停驻的那条腿跑在宿主会话上」:宿主的续跑链按会话把一张卡连回 run —— 决定腿按卡的会话找行
141
+ * (`getActiveTaskId`)与续跑输入(`getCtx`),取消按 run 的会话找待决卡,过期收割按会话相等连行与卡。卡在宿主会话上,
142
+ * 这条 run 才兑现得了它;判官只把兑现得了的停驻判成停驻。verify 的实现腿与修复轮跑在宿主会话上 ⇒ 提;cascade
143
+ * 每级被引擎剥掉会话、级上的卡落在级自己现铸的会话上 ⇒ 不提(照常终局)。这不是按组合器分的特例:引擎让级上的卡落到
144
+ * 宿主可连的会话上的那一天,答案随事实翻,本函数一个字不改。读 `result.sessionId` 而不去店里读卡:它与卡行的会话是同一次
145
+ * `runTask` 的同一个量,零 I/O。
146
+ *
147
+ * 前提:结果出自 core 的组合器(可信产者)—— `failed.nestedPause` 只由引擎的嵌套边界包停驻铸,`paused` 只在卡行写入确认之后返回。
148
+ * 判官**不**验证那张卡在不在、是不是这一张、此刻什么态;会话相等不是对卡的校验。验证器**自己**的停驻
149
+ * (`verification.verifierPause`)不在结果因由里,本函数看不见它 —— 那一形照常终局。
150
+ *
151
+ * 纯函数,不读店、不抛。凭据随提升上来,摘除仍归 {@link sealResultForExit}(调用方照旧先 graft 后封口)。
152
+ * 判官只答「该不该停驻」;认领保不保得住是停驻写口**写成功**与否的事(行写口对 `running` / `suspended` 行 CAS)。
153
+ * `hostSessionId` 缺席 = 没有宿主会话 ⇒ 没有续跑链兑现得了嵌套停驻 ⇒ 原样(相等判自然为假,不另设臂)。
154
+ */
155
+ export declare function atHostBoundary<T extends {
156
+ readonly terminal: TerminalCause;
157
+ readonly sessionId: string;
158
+ }>(result: T, hostSessionId: string | undefined): T;
132
159
  /**
133
160
  * **持久 blob 的平面读面** —— 把一条**任何年代**的持久终局结果读成五词 `status` + 三个平面文本格。
134
161
  *
package/dist/terminal.js CHANGED
@@ -45,6 +45,12 @@ export function nestedPauseOf(terminal) {
45
45
  export function pausedCauseOf(terminal) {
46
46
  return terminal.kind === "paused" ? terminal : nestedPauseOf(terminal);
47
47
  }
48
+ export function atHostBoundary(result, hostSessionId) {
49
+ const parked = nestedPauseOf(result.terminal);
50
+ if (parked === undefined || result.sessionId !== hostSessionId)
51
+ return result;
52
+ return { ...result, terminal: parked };
53
+ }
48
54
  export function persistedPlaneOf(result) {
49
55
  if (result === null || typeof result !== "object")
50
56
  return {};
@@ -1,3 +1,4 @@
1
+ import type { ExecutionLane } from "./execution-lane-caps.js";
1
2
  import { type ApprovalDecidedBy, type HostSettledBy, type RetiredDecisionKeyFacts } from "./host-decision.js";
2
3
  import type { IncomingMessage } from "node:http";
3
4
  import { type AskClass, type AskRequest, type AskOutcome, type PermissionResult, type CheckpointGate, type PendingAction, type PersistedRuleMandate, type ReadRootGrantCandidate, type RuleOffer, type AutoModeFallbackCause, type BoundGrantAbsence, type BoundSkillGrants, type ToolApprovalCard, type ReopenReason } from "@sema-agent/core";
@@ -872,6 +873,8 @@ interface ToolApprovalRunContextBase {
872
873
  taskId: string;
873
874
  sessionId?: string;
874
875
  owner: string | null;
876
+ /** 这条腿的执行车道 —— 装配点写所在边界执行上下文的 `ctx.lane`(`http/execution-context.ts`)。出处带车道:这只席造的问在铸行时记下它。 */
877
+ executionLane: ExecutionLane;
875
878
  abortSignal?: AbortSignal;
876
879
  /** [ref]([ref] §3.1 askId 派生的腿轴;车3 刀 3a 换轴:原 `leg?: number` → `legKey?: string`)。
877
880
  * = `sha256(resume checkpoint token)` 的 hex,**首腿缺席折空串**(空串是首腿的真值,不是「未知」)。
@@ -1770,6 +1773,7 @@ export declare class ToolApprovalCoordinator {
1770
1773
  owner: string | null;
1771
1774
  taskId: string;
1772
1775
  sessionId?: string;
1776
+ executionLane: ExecutionLane;
1773
1777
  }, why: LegUnattended) => ((req: AskRequest) => Promise<AskOutcome>);
1774
1778
  /**
1775
1779
  * 🔴 session grant 短路前的**持久出处复核**([ref] 的 codex R1-[high] 补丁;[ref] 换判据;[ref] / SN-C1 换读口)。
@@ -1968,6 +1972,8 @@ export declare class ToolApprovalCoordinator {
1968
1972
  /** [ref] 车3 刀 3b(§7.3):本腿的 walltime deadline —— 与 `legKey` 同源同理由,随**出处**走
1969
1973
  * (子代经继承链拿到的是宿主腿的闭包,窗必须按宿主腿的剩余 walltime 算)。 */
1970
1974
  legDeadlineMonotonic?: number;
1975
+ /** 宿主腿的执行车道(装配点写执行上下文的 `ctx.lane`);子代经继承链冻同一闭包 ⇒ 子代的问记宿主腿的车道。 */
1976
+ executionLane: ExecutionLane;
1971
1977
  }) => ((req: AskRequest, signal?: AbortSignal) => Promise<AskOutcome>);
1972
1978
  /** 广播版裁决路径——`ask()`(ALS,恒单元素数组)与 `boundAsk`([ref]四多活集合,可能多元素)共用。
1973
1979
  * 全体 `ctxs` 保证同一 (owner, sessionId)(streamKey 分组不变式;单元素数组平凡成立)。
@@ -1015,7 +1015,7 @@ export class ToolApprovalCoordinator {
1015
1015
  }
1016
1016
  boundUnattendedAsk = (identity, why) => {
1017
1017
  return async (req) => {
1018
- const origin = { owner: identity.owner, taskId: identity.taskId, ...(identity.sessionId !== undefined ? { sessionId: identity.sessionId } : {}), legKey: "" };
1018
+ const origin = { owner: identity.owner, taskId: identity.taskId, ...(identity.sessionId !== undefined ? { sessionId: identity.sessionId } : {}), legKey: "", executionLane: identity.executionLane };
1019
1019
  if (await this.standingGrantSettles(origin, req, this.governanceForcedOf(origin, req)))
1020
1020
  return true;
1021
1021
  return this.unattendedAskOutcome({ ...why, taskId: identity.taskId, owner: identity.owner, toolName: req.toolName });
@@ -1267,6 +1267,7 @@ export class ToolApprovalCoordinator {
1267
1267
  owner: ctx.owner,
1268
1268
  ...(ctx.sessionId !== undefined ? { sessionId: ctx.sessionId } : {}),
1269
1269
  legKey: ctx.legKey ?? "",
1270
+ executionLane: ctx.executionLane,
1270
1271
  ...(ctx.legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic: ctx.legDeadlineMonotonic } : {}),
1271
1272
  }, [ctx], req, signal);
1272
1273
  };
@@ -1279,6 +1280,7 @@ export class ToolApprovalCoordinator {
1279
1280
  owner: identity.owner,
1280
1281
  ...(identity.sessionId !== undefined ? { sessionId: identity.sessionId } : {}),
1281
1282
  legKey: identity.legKey ?? "",
1283
+ executionLane: identity.executionLane,
1282
1284
  ...(identity.legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic: identity.legDeadlineMonotonic } : {}),
1283
1285
  }, live, req, signal);
1284
1286
  };
@@ -1383,6 +1385,7 @@ export class ToolApprovalCoordinator {
1383
1385
  const card = this.askStore ? buildApprovalCard(frame, req, req.requiresRealApproval === true) : undefined;
1384
1386
  let cardForFrame = card;
1385
1387
  let persistedExpiresAtMs = expiresAtMs;
1388
+ let entryExecutionLane = origin.executionLane;
1386
1389
  let lateEnsuredRow;
1387
1390
  let lateTerminalRow;
1388
1391
  let abandonedAs;
@@ -1422,6 +1425,7 @@ export class ToolApprovalCoordinator {
1422
1425
  sourceTaskId,
1423
1426
  sessionId: origin.sessionId ?? origin.taskId,
1424
1427
  owner: origin.owner,
1428
+ executionLane: origin.executionLane,
1425
1429
  batchId,
1426
1430
  toolCallId: req.toolCallId,
1427
1431
  legKey,
@@ -1458,6 +1462,7 @@ export class ToolApprovalCoordinator {
1458
1462
  return existingOrCreated.inserted ? this.landUnattendedOutcome(unattended, existingOrCreated.row) : unattended;
1459
1463
  }
1460
1464
  persistedExpiresAtMs = existingOrCreated.row.expiresAtMs;
1465
+ entryExecutionLane = existingOrCreated.row.executionLane;
1461
1466
  cardForFrame = persistedEnvelope.card;
1462
1467
  if (cardForFrame.governanceForced === true)
1463
1468
  frame.governanceForced = true;
@@ -1936,6 +1941,7 @@ export class ToolApprovalCoordinator {
1936
1941
  ...(entryDeploymentListQuestion ? { deploymentListQuestion: true } : {}),
1937
1942
  registeredAtMs: Date.now(),
1938
1943
  expiresAtMs: persistedExpiresAtMs,
1944
+ executionLane: entryExecutionLane,
1939
1945
  ...(ruleLaneMaterial !== undefined ? { ruleLane: ruleLaneMaterial } : {}),
1940
1946
  ...(effectiveGovernanceForced ? { governanceForced: true } : {}),
1941
1947
  ...(req.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
@@ -2899,6 +2905,7 @@ export class ToolApprovalCoordinator {
2899
2905
  forceParkNow: release,
2900
2906
  settleParkRoute: (cause) => leave({ outcome: SETTLE_OUTCOME.EXPIRED, cause, parked: this.unattendedRoutesToPark }),
2901
2907
  owner: row.owner,
2908
+ executionLane: row.executionLane,
2902
2909
  ...(row.sessionId !== row.taskId ? { sessionId: row.sessionId } : {}),
2903
2910
  ...(card.fromSubagent === true ? { originTaskId: row.sourceTaskId } : {}),
2904
2911
  toolName: card.toolName,
@@ -1016,6 +1016,7 @@ export declare function brainStatusEventData(ev: {
1016
1016
  providerConditionSource?: string;
1017
1017
  waitSegment?: string;
1018
1018
  sleptMs?: number;
1019
+ seat?: string;
1019
1020
  eventId?: string;
1020
1021
  parentToolCallId?: string;
1021
1022
  }): FrameData<{
@@ -822,6 +822,7 @@ export function brainStatusEventData(ev) {
822
822
  ...(num(ev.timeoutMs) ? { timeoutMs: ev.timeoutMs } : {}),
823
823
  ...(typeof ev.waitSegment === "string" && ev.waitSegment.length > 0 ? { waitSegment: ev.waitSegment } : {}),
824
824
  ...(num(ev.sleptMs) ? { sleptMs: ev.sleptMs } : {}),
825
+ ...(typeof ev.seat === "string" && ev.seat.length > 0 ? { seat: ev.seat } : {}),
825
826
  ...(num(ev.errorStatus) ? { errorStatus: ev.errorStatus } : {}),
826
827
  ...(typeof ev.errClass === "string" && ev.errClass.length > 0 ? { errClass: ev.errClass } : {}),
827
828
  ...(typeof ev.providerCondition === "string" && ev.providerCondition.length > 0 ? { providerCondition: ev.providerCondition } : {}),
@@ -54,6 +54,8 @@ export declare function resetArmPoolBudgetForTest(): void;
54
54
  * 闭集:加一个档而不在 {@link armPool} 的档表里处置 ⇒ **编译**红。
55
55
  */
56
56
  type RedactionScope = "free-text" | "bounded-unit";
57
+ /** 测试座:{@link unitCountWithin} 的数组形(`table` 须是合法的已并表:升序、两两不交不相接)。 */
58
+ export declare function unitCountWithinForTest(table: ReadonlyArray<readonly [number, number]>, from: number, to: number, max: number): boolean;
57
59
  /** 本模块会写进文本的全部替换 token(`«…»` 字面),从三张表现算 —— 表改这里自动跟,不另抄一份。
58
60
  * 🔴 **[ref] v2 修复轮起它只剩一个语义:闭形闭集的加载期校验**。运行期「这一段是不是一枚记号」已经由
59
61
  * {@link credentialSpans} 的闭**形**那一支一处答完({@link opaqueUnitEnd}),按闭**集**再认一遍的
@@ -67,7 +69,7 @@ declare const DISPLAY_SAFE_URL_TOKEN = "\u00ABredacted:url\u00BB";
67
69
  export { DISPLAY_SAFE_URL_TOKEN };
68
70
  /**
69
71
  * 🔴 **取证相的重扫模式(测试座,[ref])** —— 生产恒 `"incremental"`;`"full"` 是**参照语义** = 「没有可复用的上一次执行」:
70
- * 每级五条取证臂整段重跑、URL 臂每段重扫,既不读足迹也不回放(池把每一级的脏区间当作「未知」交下去,与级 0 同一个读法)。
72
+ * 每级全部取证臂整段重跑、URL 臂每段重扫,既不读足迹也不回放(池把每一级的脏区间当作「未知」交下去,与级 0 同一个读法)。
71
73
  * 证据表的建法(级 0 记号档 + 逐级折入)与收敛判据(脏区间为空)两种模式是同一条,所以两种模式只差「复用与否」这一位 ——
72
74
  * 增量重扫的全部正确性主张只有一句:**任何输入上两种模式输出逐字相同**(`test/forensic-incremental-rescan.test.ts` 并跑比对;
73
75
  * 折入本身与整表重建的对拍是那个测试文件里的一份测试本地参照)。
@@ -1168,21 +1168,37 @@ function unitCountWithin(scan, from, to, max) {
1168
1168
  return true;
1169
1169
  noteEvidenceRead(scan, from);
1170
1170
  noteEvidenceRead(scan, to);
1171
- const st = scan.table.starts;
1172
- if (st.length === 0)
1173
- return false;
1174
- const k = firstCredentialSpanFrom(scan.table, from);
1175
- if (k >= st.length || st[k] >= to)
1171
+ const t = scan.table;
1172
+ const lo = firstCredentialSpanFrom(t, from);
1173
+ let a = lo;
1174
+ let b = t.ends.length;
1175
+ while (a < b) {
1176
+ const mid = (a + b) >>> 1;
1177
+ if (t.ends[mid] <= to)
1178
+ a = mid + 1;
1179
+ else
1180
+ b = mid;
1181
+ }
1182
+ if (a === lo)
1176
1183
  return false;
1177
- let n = 0;
1178
- for (let p = from; p < to;) {
1179
- if (n > max)
1180
- return false;
1181
- const unit = opaqueUnitEnd(scan, p);
1182
- p = unit > 0 && unit <= to ? unit : p + 1;
1183
- n += 1;
1184
+ const saved = unitSavings(t);
1185
+ return to - from - (saved[a] - saved[lo]) <= max;
1186
+ }
1187
+ const UNIT_SAVINGS = new WeakMap();
1188
+ function unitSavings(t) {
1189
+ let saved = UNIT_SAVINGS.get(t);
1190
+ if (saved === undefined) {
1191
+ const n = t.starts.length;
1192
+ saved = new Float64Array(n + 1);
1193
+ for (let k = 0; k < n; k++)
1194
+ saved[k + 1] = saved[k] + (t.ends[k] - t.starts[k] - 1);
1195
+ UNIT_SAVINGS.set(t, saved);
1184
1196
  }
1185
- return n <= max;
1197
+ return saved;
1198
+ }
1199
+ export function unitCountWithinForTest(table, from, to, max) {
1200
+ const t = { starts: Int32Array.from(table, (x) => x[0]), ends: Int32Array.from(table, (x) => x[1]) };
1201
+ return unitCountWithin(buildForensicScan(t, 1), from, to, max);
1186
1202
  }
1187
1203
  function collectSsh2FenceSpans(scan, text, span, isHead) {
1188
1204
  let cachedFrom = 0;
@@ -1241,16 +1257,20 @@ function pemFenceLineEnd(text, labelFrom) {
1241
1257
  }
1242
1258
  return isPemFenceLabel(text, labelFrom, close) ? close + PEM_FENCE_CLOSE.length : PEM_LINE_INVALID;
1243
1259
  }
1244
- function collectPemFenceSpans(text, span, isHead) {
1260
+ function collectPemFenceSpans(scan, text, span, isHead) {
1245
1261
  let endFrom = -1;
1246
1262
  let endAt = -1;
1247
1263
  let endAfter = -1;
1264
+ const visibleEndLine = (b) => {
1265
+ const after = pemFenceLineEnd(text, b + PEM_END_OPEN.length);
1266
+ return after >= 0 && !inOpaqueUnit(scan, b) ? after : -1;
1267
+ };
1248
1268
  const earliestEndFence = (from) => {
1249
1269
  if (endFrom >= 0 && from >= endFrom && (endAt < 0 || endAt >= from))
1250
1270
  return;
1251
1271
  let b = text.indexOf(PEM_END_OPEN, from);
1252
1272
  let after = -1;
1253
- while (b >= 0 && (after = pemFenceLineEnd(text, b + PEM_END_OPEN.length)) < 0)
1273
+ while (b >= 0 && (after = visibleEndLine(b)) < 0)
1254
1274
  b = text.indexOf(PEM_END_OPEN, b + 1);
1255
1275
  endFrom = from;
1256
1276
  endAt = b;
@@ -1260,6 +1280,10 @@ function collectPemFenceSpans(text, span, isHead) {
1260
1280
  const fence = text.indexOf(PEM_FENCE_OPEN, from);
1261
1281
  if (fence < 0)
1262
1282
  return;
1283
+ if (inOpaqueUnit(scan, fence)) {
1284
+ from = fence + 1;
1285
+ continue;
1286
+ }
1263
1287
  const bodyFrom = pemFenceLineEnd(text, fence + PEM_FENCE_OPEN.length);
1264
1288
  if (bodyFrom === PEM_LINE_INVALID) {
1265
1289
  from = fence + 1;
@@ -1272,7 +1296,7 @@ function collectPemFenceSpans(text, span, isHead) {
1272
1296
  span(fence, text.length, true);
1273
1297
  return;
1274
1298
  }
1275
- if (endAt - bodyFrom > PEM_FENCE_BODY_MAX) {
1299
+ if (!unitCountWithin(scan, bodyFrom, endAt, PEM_FENCE_BODY_MAX)) {
1276
1300
  from = fence + 1;
1277
1301
  continue;
1278
1302
  }
@@ -1610,7 +1634,7 @@ let forensicRescanMode = "incremental";
1610
1634
  export function setForensicRescanModeForTest(mode) {
1611
1635
  forensicRescanMode = mode;
1612
1636
  }
1613
- function foldCredentialSpans(prev, spans, from) {
1637
+ function foldCredentialSpans(prev, spans, from, admit) {
1614
1638
  const cap = spans.length - from;
1615
1639
  if (cap === 0)
1616
1640
  return { next: prev, dirty: NO_CREDENTIAL_SPANS };
@@ -1619,6 +1643,8 @@ function foldCredentialSpans(prev, spans, from) {
1619
1643
  let m = 0;
1620
1644
  for (let i = from; i < spans.length; i++) {
1621
1645
  const sp = spans[i];
1646
+ if (admit !== undefined && !admit(sp))
1647
+ continue;
1622
1648
  const k = firstCredentialSpanFrom(prev, sp.start + 1) - 1;
1623
1649
  if (k >= 0 && prev.ends[k] >= sp.end)
1624
1650
  continue;
@@ -1742,7 +1768,7 @@ function buildForensicScan(table, armCount) {
1742
1768
  hdr: { search: 0, contentEnd: 0, next: 0, hitLimit: false, jsonEnd: false },
1743
1769
  };
1744
1770
  }
1745
- function advanceEvidence(scan, table, dirty) {
1771
+ function useEvidenceView(scan, table, dirty) {
1746
1772
  scan.table = table;
1747
1773
  scan.cursor = 0;
1748
1774
  scan.dirty = dirty;
@@ -2417,7 +2443,7 @@ export function structuralScannerForTest(arm) {
2417
2443
  case "json-secret-field":
2418
2444
  return { declared: new RegExp(JSON_SECRET_FIELD_PATTERN[0].source, JSON_SECRET_FIELD_PATTERN[0].flags), spans: collect(collectJsonSecretFieldSpans) };
2419
2445
  case "pem-fence":
2420
- return { declared: new RegExp(PEM_FENCE_PATTERN[0].source, PEM_FENCE_PATTERN[0].flags), spans: collect(collectPemFenceSpans) };
2446
+ return { declared: new RegExp(PEM_FENCE_PATTERN[0].source, PEM_FENCE_PATTERN[0].flags), spans: collect((text, span, isHead) => collectPemFenceSpans(buildForensicScan(NO_CREDENTIAL_SPANS, 1), text, span, isHead)) };
2421
2447
  }
2422
2448
  }
2423
2449
  let ppkScanBytes = 0;
@@ -2574,6 +2600,7 @@ const armPool = (() => {
2574
2600
  retry: boundary === undefined ? undefined : (text, at, out) => collectStickySpans(boundary, text, at, out),
2575
2601
  headSrc: boundary === undefined ? undefined : headSrc,
2576
2602
  headFirst: boundary === undefined ? undefined : headFirst,
2603
+ family: undefined,
2577
2604
  };
2578
2605
  };
2579
2606
  const scannerMember = (token, order, arm, rank = ARM_RANK.structural, lexical = false) => {
@@ -2588,9 +2615,12 @@ const armPool = (() => {
2588
2615
  retry: undefined,
2589
2616
  headSrc: undefined,
2590
2617
  headFirst: undefined,
2618
+ family: undefined,
2591
2619
  };
2592
2620
  };
2593
- const forensicMember = (token, order, arm) => {
2621
+ const forensicMember = (token, order, arm, family = undefined, view = "all") => {
2622
+ if (view === "other-families" && family === undefined)
2623
+ throw new Error(`redact: forensic arm ${token} reads the other-families evidence view but declares no credential family`);
2594
2624
  const repl = spanRepl(token);
2595
2625
  const rank = ARM_RANK.structural;
2596
2626
  return {
@@ -2603,11 +2633,13 @@ const armPool = (() => {
2603
2633
  retry: undefined,
2604
2634
  headSrc: undefined,
2605
2635
  headFirst: undefined,
2636
+ family,
2637
+ view,
2606
2638
  };
2607
2639
  };
2608
2640
  const structuralScannerMember = (row, order) => {
2609
2641
  if (row === PEM_FENCE_PATTERN)
2610
- return scannerMember(row[1], order, (text, _json, _eat, span, isHead) => collectPemFenceSpans(text, span, isHead));
2642
+ return forensicMember(row[1], order, (scan, text, _json, _eat, span, isHead) => collectPemFenceSpans(scan, text, span, isHead), "pem-armor", "other-families");
2611
2643
  if (row === SSH2_FENCE_PATTERN)
2612
2644
  return forensicMember(row[1], order, (scan, text, _json, _eat, span, isHead) => collectSsh2FenceSpans(scan, text, span, isHead));
2613
2645
  if (row === URL_CREDENTIAL_PATTERN)
@@ -2620,7 +2652,7 @@ const armPool = (() => {
2620
2652
  for (const row of STRUCTURAL_SECRET_PATTERNS)
2621
2653
  members.push(structuralScannerMember(row, members.length));
2622
2654
  members.push(forensicMember(PPK_CONTAINER_TOKEN, members.length, (scan, text, _json, eat, span, isHead) => collectPpkContainerSpans(scan, text, eat, span, isHead)));
2623
- members.push(forensicMember(PEM_FRAGMENT_TOKEN, members.length, (scan, text, json, _eat, span) => collectPemFragmentSpans(scan, text, json, span)));
2655
+ members.push(forensicMember(PEM_FRAGMENT_TOKEN, members.length, (scan, text, json, _eat, span) => collectPemFragmentSpans(scan, text, json, span), "pem-armor"));
2624
2656
  members.push(forensicMember(HEADLESS_PPK_TOKEN, members.length, (scan, text, _json, _eat, span, isHead) => collectHeadlessPpkSpans(scan, text, span, isHead)));
2625
2657
  members.push(scannerMember(ANCHORED_VALUE_TOKEN, members.length, (text, json, _eat, span, isHead) => collectAnchoredValueSpans(text, json, span, isHead), ARM_RANK.keyword, true));
2626
2658
  for (const row of KEYWORD_SECRET_PATTERNS)
@@ -2636,6 +2668,13 @@ const armPool = (() => {
2636
2668
  const retryMembers = members.filter((m) => m.retry !== undefined);
2637
2669
  const phase1 = members.filter((m) => m.phase === 1);
2638
2670
  const phase2 = members.filter((m) => m.phase === 2);
2671
+ const familyOfOrder = members.map((m) => m.family);
2672
+ const viewKeyOf = (m) => {
2673
+ switch (m.view) {
2674
+ case "all": return undefined;
2675
+ case "other-families": return m.family;
2676
+ }
2677
+ };
2639
2678
  const laneOf = (scope) => {
2640
2679
  const inScope = (m) => {
2641
2680
  switch (scope) {
@@ -2643,7 +2682,9 @@ const armPool = (() => {
2643
2682
  case "bounded-unit": return !m.lexical;
2644
2683
  }
2645
2684
  };
2646
- return { phase1: phase1.filter(inScope), phase2: phase2.filter(inScope), retry: retryMembers.filter(inScope) };
2685
+ const lanePhase2 = phase2.filter(inScope);
2686
+ const viewKeys = [...new Set(lanePhase2.map(viewKeyOf))];
2687
+ return { phase1: phase1.filter(inScope), phase2: lanePhase2, retry: retryMembers.filter(inScope), viewKeys, viewOf: lanePhase2.map((m) => viewKeys.indexOf(viewKeyOf(m))) };
2647
2688
  };
2648
2689
  const LANES = {
2649
2690
  "free-text": laneOf("free-text"),
@@ -2694,18 +2735,22 @@ const armPool = (() => {
2694
2735
  m.collect(text, json, eat, spans, isHead);
2695
2736
  closeCoveragePositions(0);
2696
2737
  if (lane.phase2.length > 0) {
2697
- const scan = buildForensicScan(credentialSpans(text), lane.phase2.length);
2738
+ const tokens = credentialSpans(text);
2739
+ const scan = buildForensicScan(tokens, lane.phase2.length);
2698
2740
  const reuse = forensicRescanMode === "incremental";
2699
2741
  const foot = scan.armFoot;
2742
+ const views = lane.viewKeys.map((key) => ({ key, table: tokens, dirty: undefined }));
2700
2743
  let folded = 0;
2701
2744
  for (let level = 0;; level += 1) {
2702
2745
  const before = spans.length;
2703
2746
  for (let j = 0; j < lane.phase2.length; j++) {
2704
- const dirty = scan.dirty;
2747
+ const view = views[lane.viewOf[j]];
2748
+ const dirty = view.dirty;
2705
2749
  if (dirty !== undefined && footprintClean(dirty, foot[2 * j], foot[2 * j + 1])) {
2706
2750
  forensicSkips += 1;
2707
2751
  continue;
2708
2752
  }
2753
+ useEvidenceView(scan, view.table, dirty);
2709
2754
  scan.footLo = FOOT_NONE;
2710
2755
  scan.footHi = -1;
2711
2756
  lane.phase2[j].collect(scan, text, json, level === 0 ? eat : undefined, spans, isHead);
@@ -2715,11 +2760,18 @@ const armPool = (() => {
2715
2760
  }
2716
2761
  closeCoveragePositions(before);
2717
2762
  forensicLevels += 1;
2718
- const grown = foldCredentialSpans(scan.table, spans, folded);
2763
+ let grew = false;
2764
+ for (const view of views) {
2765
+ const key = view.key;
2766
+ const grown = foldCredentialSpans(view.table, spans, folded, key === undefined ? undefined : (sp) => familyOfOrder[sp.order] !== key);
2767
+ if (grown.dirty.starts.length > 0)
2768
+ grew = true;
2769
+ view.table = grown.next;
2770
+ view.dirty = reuse ? grown.dirty : undefined;
2771
+ }
2719
2772
  folded = spans.length;
2720
- if (grown.dirty.starts.length === 0)
2773
+ if (!grew)
2721
2774
  break;
2722
- advanceEvidence(scan, grown.next, reuse ? grown.dirty : undefined);
2723
2775
  }
2724
2776
  }
2725
2777
  poolSpanCount += spans.length;