@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
@@ -69,7 +69,7 @@ export interface JsonColumnMember {
69
69
  *
70
70
  * 🔴 存在的唯一理由是「别名位在那里不合法」,**不是**给读腿留第二条路:读腿一律用 {@link jsonColumnText}
71
71
  * (别名是它的产物的一部分,理由见那只函数)。今天整仓**三处**消费方,各自的「别名位不合法」都是真的:
72
- * · `one-time-migrations.ts` 的几条改写(M8 / M17 / M18 / M21 的候选扫描与按原文 CAS 回写)——
72
+ * · `one-time-migrations.ts` 的几条改写(M17 / M18 / M21 的候选扫描与按原文 CAS 回写)——
73
73
  * 它们要在 `WHERE` 里判这一列的**文本**,而 `WHERE` 没有别名位;
74
74
  * · `workflow-journal-store-sql.ts` 的 `loadPage`([ref] 车③a)—— 那一列的投影裹在一条
75
75
  * `CASE WHEN LENGTH(result) > ? THEN NULL ELSE <expr> END AS result_json` 里:**别名属于整条 CASE**
@@ -202,6 +202,10 @@ export declare class StoreCorruptError extends Error {
202
202
  /** 出事的坐标(`<table>.<column> for <identity>`,由 {@link SqlJsonColumnError.where} 原样带过来)——
203
203
  * 进 wire 的 `where` 字段,人按它去找那一行。 */
204
204
  readonly where: string;
205
+ /** 构造函数交进来的就是这一只列错误(类型面如实:折码只在体问题上产出本类,见 {@link foldJsonColumn});子类想在同一份因由上再带一格事实时按它再构造,不必断言。 */
206
+ readonly cause: SqlJsonColumnError & {
207
+ readonly problem: SqlJsonColumnBodyProblem;
208
+ };
205
209
  constructor(cause: SqlJsonColumnError & {
206
210
  readonly problem: SqlJsonColumnBodyProblem;
207
211
  }, sentence: string);
@@ -20,7 +20,7 @@ import { TiDBResumeAnchorStore, PgResumeAnchorStore } from "./resume-anchor-stor
20
20
  import { type SessionPolicyStoreLogger } from "../stores-sql/session-policy-store-sql.js";
21
21
  import type { ServiceConfig } from "../config-types.js";
22
22
  import { TiDBRunStore, PgRunStore } from "./run-store-sql.js";
23
- import { TiDBCheckpointStore, PgCheckpointStore } from "./checkpoint-store-sql.js";
23
+ import { TiDBCheckpointStore, PgCheckpointStore } from "../stores-sql/checkpoint-store-sql.js";
24
24
  import { TiDBImageIndex, PgImageIndex } from "./image-index-sql.js";
25
25
  import { TiDBImageBake, PgImageBake } from "./image-bake-store-sql.js";
26
26
  import { TiDBLeaderRunStore, PgLeaderRunStore } from "./leader-run-store-sql.js";
@@ -92,7 +92,7 @@ export type ServiceFileHistoryStore = FileHistoryStore & {
92
92
  * protected — never a synchronous external-store delete). Reaper-driven; SQL twins only. */
93
93
  sweepOrphanBlobs?(): Promise<number>;
94
94
  };
95
- /** SVC-2 (core CORE-7) WorkflowJournalStore — core's interface PLUS the service `deleteByRun` (GC extra). tidb/pg =
95
+ /** SVC-2 (core CORE-7) WorkflowJournalStore — core's interface PLUS the service read page and age sweep below. tidb/pg =
96
96
  * durable SQL twins (cross-replica resume journal); local = the service {@link FileWorkflowJournalStore}
97
97
  * (single-box but RESTART-durable crash-safe JSONL, replacing core's InMemory). The shared equivalence suite keeps
98
98
  * all three byte-matched (scope guard / idempotent-per-ordinal / oversize **refusal** —— [ref] / core 7.12.0
@@ -111,11 +111,14 @@ export type ServiceWorkflowJournalStore = WorkflowJournalStore & {
111
111
  resultJson: string | null;
112
112
  resultBytes: number;
113
113
  }>>;
114
- deleteByRun?(runId: string): Promise<number>;
115
- /** SVC-2 GC sweep (durable twins only): purge entries older than `maxAgeMs` — wired into the reaper to bound the
116
- * TaskResult-bearing table (the per-run deleteByRun has no run-store reap hook). Local InMemory omits it. */
114
+ /** SVC-2 GC sweep (durable twins only): purge entries older than `maxAgeMs` — the `workflow-journal-expired` leg of the backend sweep verb
115
+ * (`plugins/store-sweep.ts`, composed in `boot/stores.ts`) bounds the TaskResult-bearing table with it; the journal's one delete path (no per-run
116
+ * delete: the engine contract never had one). Local File / InMemory omit it. */
117
117
  reapExpired?(now: number, maxAgeMs: number): Promise<number>;
118
118
  };
119
+ /** 本部署有没有 workflow journal 店、是哪一只 —— 唯一读法:开了 self-orchestration 且有后端 ⇒ 后端的 journal 店,否则无。
120
+ * 两处读者同读它:workflow 编排段(交 Runner 与 journal HTTP 读面的那只)与持久层组合点(按龄清扫动词的 `workflow-journal-expired` 腿)。 */
121
+ export declare function workflowJournalOf(config: Pick<ServiceConfig, "selfOrchestrationEnabled">, backend: Pick<StoreBackend, "workflowJournal"> | undefined): ServiceWorkflowJournalStore | undefined;
119
122
  export type ImageIndex = TiDBImageIndex | PgImageIndex;
120
123
  export type ImageBake = TiDBImageBake | PgImageBake;
121
124
  /** [ref] 车4 件1:durable leader-run 登记表的双方言孪生(union 同族——TS 私有字段让具体类名义上不同)。 */
@@ -280,9 +283,9 @@ export interface StoreBackend {
280
283
  * until a 2026-07-25 doc-rot sweep caught it). core 1.145.0 added the seam this comment was waiting for:
281
284
  * `RunnerDeps.workflowJournalStore` (now `@sema-agent/core` `dist/core/types.d.ts`) + `journalStore` on the
282
285
  * run_workflow tool deps (`dist/orchestration/run-workflow-tool.d.ts`), and the boot chain consumes it
283
- * end-to-end: built in `boot/workflow-orchestration.ts` (`const workflowJournalStore = …backend.workflowJournal()`),
284
- * threaded into RunnerDeps (`boot/runner-deps.ts` 的 `workflowJournalStore`), reaped on the maintenance tick
285
- * (`boot/reapers.ts` 同名字段), and read by `GET /v1/workflows/:id/journal` (`http/routes/workflows.ts`, [ref]). */
286
+ * end-to-end: selected by {@link workflowJournalOf} (self-orchestration on ∧ a backend), built in `boot/workflow-orchestration.ts`,
287
+ * threaded into RunnerDeps (`boot/runner-deps.ts` 的 `workflowJournalStore`), aged out by the backend sweep verb's `workflow-journal-expired`
288
+ * leg (`boot/stores.ts`, same selector), and read by `GET /v1/workflows/:id/journal` (`http/routes/workflows.ts`, [ref]). */
286
289
  workflowJournal(): ServiceWorkflowJournalStore;
287
290
  /** [ref] §1 consumption sink for `RunnerDeps.onTaskOutcome` facts. REQUIRED on all backends:
288
291
  * tidb/pg = the outcome-ledger twins (SQL rows, mapped via coreOutcomeToLedgerRow + verbatim core_outcome
@@ -33,7 +33,7 @@ import { FileUserInputLedgerStore } from "./user-input-ledger-file.js";
33
33
  import { TiDBUserInputLedgerStore, PgUserInputLedgerStore } from "./user-input-ledger-sql.js";
34
34
  import { TiDBResumeAnchorStore, PgResumeAnchorStore } from "./resume-anchor-store-sql.js";
35
35
  import { TiDBSessionPolicyStore, PgSessionPolicyStore } from "../stores-sql/session-policy-store-sql.js";
36
- import { TiDBWorkflowJournalStore, PgWorkflowJournalStore } from "./workflow-journal-store-sql.js";
36
+ import { TiDBWorkflowJournalStore, PgWorkflowJournalStore } from "../stores-sql/workflow-journal-store-sql.js";
37
37
  import { TiDBFileHistoryStore, PgFileHistoryStore, FILE_HISTORY_BLOB_TABLE, FILE_HISTORY_BLOB_KEY_PREFIX } from "./file-history-store-sql.js";
38
38
  import { MinioBlobBackend, SqlBlobBackend } from "./blob-backend.js";
39
39
  import { buildDisplaySafeUrl } from "../trace/redact.js";
@@ -41,8 +41,8 @@ import { fileMemoryControlDirFor } from "../memory-scope.js";
41
41
  import { createTidbPool, ensureSchema as ensureTidbSchema } from "./tidb-pool.js";
42
42
  import { createPgPool, ensurePgSchema, pgPoolOptions } from "./pg-pool.js";
43
43
  import { TiDBRunStore, PgRunStore } from "./run-store-sql.js";
44
- import { TiDBCheckpointStore, PgCheckpointStore } from "./checkpoint-store-sql.js";
45
- import { TiDBToolResultStore, PgToolResultStore } from "./tool-result-store-sql.js";
44
+ import { TiDBCheckpointStore, PgCheckpointStore } from "../stores-sql/checkpoint-store-sql.js";
45
+ import { TiDBToolResultStore, PgToolResultStore } from "../stores-sql/tool-result-store-sql.js";
46
46
  import { TiDBImageIndex, PgImageIndex } from "./image-index-sql.js";
47
47
  import { TiDBImageBake, PgImageBake } from "./image-bake-store-sql.js";
48
48
  import { TiDBLeaderRunStore, PgLeaderRunStore } from "./leader-run-store-sql.js";
@@ -59,11 +59,14 @@ import { TiDBAdoptionLogStore, PgAdoptionLogStore } from "./adoption-log-sql.js"
59
59
  import { TiDBRetentionStore, PgRetentionStore, sqlStoreRetention } from "./retention-store-sql.js";
60
60
  import { TiDBRetentionLaneStore, PgRetentionLaneStore } from "./retention-lane-store-sql.js";
61
61
  import { createSqlPermissionRuleStores } from "./permission-rule-store-sql.js";
62
- import { FILE_PERMISSION_RULE_DIR, createFilePermissionRuleStores } from "./permission-rule-store-file.js";
62
+ import { FILE_PERMISSION_RULE_DIR, createFilePermissionRuleStores, fileRuleBucketOwners, isFileBucketDamaged } from "./permission-rule-store-file.js";
63
63
  import { retireImportedLayerRootAllows } from "./imported-layer-root-retirement.js";
64
64
  import { mysqlDriver, pgDriver } from "./sql-driver.js";
65
65
  import { storeDegradedReasonFor } from "../store-posture.js";
66
66
  import { openWithinWait } from "./store-open-wait.js";
67
+ export function workflowJournalOf(config, backend) {
68
+ return config.selfOrchestrationEnabled && backend ? backend.workflowJournal() : undefined;
69
+ }
67
70
  function historyBlobBackend(config, dialect, pool) {
68
71
  const s = config.snapshotBlobStore;
69
72
  if (!s)
@@ -298,17 +301,15 @@ class LocalBackend {
298
301
  await this.sessionStore.settleArchiveSnapshots();
299
302
  }
300
303
  async runOneTimeMigrations() {
301
- const holderDeathCodeRowsBackfilled = this.runStore.migrateLegacyHolderDeathCodes();
302
304
  const archives = await this.sessionStore.migrateLocalArchives();
303
305
  const placements = await backfillLocalExecutionPlacements(this.runStore.sessionIdsWithRuns(), this.sessionStore.executionPlacementBackfill, { lanes: this.executionLanes });
304
306
  const importedLayerRoot = { importedLayerRootAllowsRetired: [], importedLayerRootBucketsSkipped: [] };
305
307
  if (existsSync(join(this.fileBackend.root, FILE_PERMISSION_RULE_DIR))) {
306
308
  const rules = this.permissionRule();
307
- await retireImportedLayerRootAllows({ candidateOwners: () => rules.approvals.importRecordOwners(), durable: rules.durable, isWholeBucketRefusal: () => false, isVanishedBucket: () => false }, importedLayerRoot);
309
+ await retireImportedLayerRootAllows({ candidateOwners: () => fileRuleBucketOwners(rules), durable: rules.durable, isWholeBucketRefusal: isFileBucketDamaged, isVanishedBucket: () => false }, importedLayerRoot);
308
310
  }
309
311
  return {
310
312
  ...NO_SQL_MIGRATIONS,
311
- holderDeathCodeRowsBackfilled,
312
313
  executionPlacementsBackfilled: placements.backfilled,
313
314
  executionPlacementSessionsUnreadable: placements.unreadable,
314
315
  askExecutionLanesBackfilled: backfillLocalAskExecutionLanes(this.approvalAskStore, { lanes: this.executionLanes }),
@@ -168,20 +168,10 @@ export declare const RUN_HOLDER_DEATH_CODES: {
168
168
  readonly orphaned: "run.orphaned";
169
169
  };
170
170
  export type RunHolderDeathCode = (typeof RUN_HOLDER_DEATH_CODES)[keyof typeof RUN_HOLDER_DEATH_CODES];
171
- /**
172
- * 一次性迁移 **M6** 的判据(窗、删法与删后谁接住:窗口见 `plugins/one-time-migrations.ts` 登记表):7.116.0 之前写下的死亡判决行只有句子、码列为空 ——
173
- * 该行应有的码。两处用:local 腿的起服写回(`FileRunStore.migrateLegacyHolderDeathCodes`)与 SQL 两孪生行映射里的**读侧半场**(滚动升级窗里旧副本
174
- * 还会写这种行,起服写回覆盖不到;本函数随 M6 一起删)。只认两句落款的原字节(接管臂括注形按前缀认);码列已有值 / 非 `failed` / 别的句子 ⇒ 原样。
175
- */
176
- export declare function readLegacyHolderDeathCode(row: {
177
- readonly status: string;
178
- readonly error: string | null;
179
- readonly errorCode: string | null;
180
- }): string | null;
181
171
  /**
182
172
  * run 行上是不是一份**持有者死亡判决**:`failed`,且行上的码是 {@link RUN_HOLDER_DEATH_CODES} 之一。判决只说「持有它的那个进程死在这条腿收场之前」,
183
173
  * 不说是谁 —— 持有者是谁读行上的 `instanceId`(判决不改它)。读者 = 用户输入受理账本的收敛判词(`src/user-input-ledger.ts` `judgeOpen`)。
184
- * 旧行(只有句子)由一次性迁移 M6 补上码(起服写回 + SQL 滚动窗的读侧半场,{@link readLegacyHolderDeathCode}),所以这里不再按句子判。
174
+ * 只认码、不按句子判:7.116.0 起两只死亡判决的写者恒同写码;只有句子、码列为空的行(更早的写者铸的)不是死亡判决(随包 MIGRATION 写了)。
185
175
  * 正常失败(别的码 / 无码)/ park 过期收割(`approval.expired`:腿 park 过)都**不是**死亡判决。
186
176
  */
187
177
  export declare function isHolderDeathVerdict(run: Pick<RunRecord, "status" | "errorCode">): boolean;
@@ -8,15 +8,6 @@ export function buildRunOrphanedError(heldBy) {
8
8
  }
9
9
  export const RUN_HOLDER_DEATH_CODES = { stalled: "run.stalled", orphaned: "run.orphaned" };
10
10
  const RUN_HOLDER_DEATH_CODE_WORDS = new Set(Object.values(RUN_HOLDER_DEATH_CODES));
11
- export function readLegacyHolderDeathCode(row) {
12
- if (row.errorCode !== null || row.status !== "failed" || row.error === null)
13
- return row.errorCode;
14
- if (row.error === RUN_STALLED_ERROR)
15
- return RUN_HOLDER_DEATH_CODES.stalled;
16
- if (row.error === RUN_ORPHANED_ERROR || row.error.startsWith(`${RUN_ORPHANED_ERROR} (`))
17
- return RUN_HOLDER_DEATH_CODES.orphaned;
18
- return null;
19
- }
20
11
  export function isHolderDeathVerdict(run) {
21
12
  return run.status === "failed" && run.errorCode !== null && RUN_HOLDER_DEATH_CODE_WORDS.has(run.errorCode);
22
13
  }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 后端级按龄清扫动词 —— 一个后端的按龄清扫只有一只动词 `sweep({ nowMs })`,答每条腿删了几行。
3
+ *
4
+ * ## 律(一条)
5
+ * 维护 tick 只调这一只动词,不逐店探「有没有某个按龄删的方法」;每条腿的界只有一种读法({@link buildStoreSweepBounds}:部署旋钮 → 引擎的词 `maxAgeMs`,
6
+ * 即工具结果店 `ToolResultStore.reap(now, { maxAgeMs })`、名册 `RosterGcOptions.maxAgeMs` 的那个词;journal 店的按龄删同收 `maxAgeMs`),**每次清扫现读** —— `TOOL_RESULT_TTL_SEC` 是热键,
7
+ * 改了下一拍就按新值删;没给界的腿,或本后端那只座没有按龄删的面,一行不删、答 0。
8
+ * 形照引擎 SQL 后端包的同名动词(`SqlStorageBackend.sweep` / `SqlSweepLeg` / `SqlSweepReceipt`):腿名逐字用它的词。
9
+ *
10
+ * ## 射程(如实)
11
+ * 今天的三条腿:`tool-results-aged`(工具结果店的契约成员 `reap`)、`roster-aged`(名册 SQL 孪生的按龄删;File / 内存名册没有这一面 ⇒ 0)与
12
+ * `workflow-journal-expired`(journal SQL 孪生的按龄删 `reapExpired`,见 {@link createJournalSweepLeg};只在开了 self-orchestration 且有后端时有这只店,
13
+ * core 的 File journal 店没有这一面 ⇒ 0)。引擎包的腿闭集另有 `file-history-orphan-blobs`,随它的座搬进 `src/stores-sql/` 时并进来;信箱的 `reap` 是按收件箱
14
+ * 作用域的契约成员,引擎包的清扫腿里没有它,本动词也不收。实现仍是各座自己的方法;目录搬进引擎包之后,SQL 后端的这只动词就是包的 `sweep`。
15
+ *
16
+ * ## 失败
17
+ * 腿互不牵连:一条腿抛(同步抛或拒)不拦别的腿。全腿成功 ⇒ 答回执;有腿失败 ⇒ 以 {@link StoreSweepError} 拒,带上成功腿的计数与失败腿的原因,
18
+ * 调用方按腿各自上报。
19
+ */
20
+ import type { ServiceConfig } from "../config.js";
21
+ /** 本后端跑的清扫腿(闭集;词与引擎 SQL 后端包的 `SqlSweepLeg` 同字)。 */
22
+ export declare const STORE_SWEEP_LEGS: readonly ["roster-aged", "tool-results-aged", "workflow-journal-expired"];
23
+ export type StoreSweepLeg = (typeof STORE_SWEEP_LEGS)[number];
24
+ /** 一次清扫每条腿删了几行。 */
25
+ export type StoreSweepReceipt = Readonly<Record<StoreSweepLeg, number>>;
26
+ /** 一条腿的界(部署陈述;词 = 引擎的 `maxAgeMs`)。 */
27
+ export interface StoreSweepBound {
28
+ readonly maxAgeMs: number;
29
+ }
30
+ /** 各腿的界(缺一条 = 那条腿不删)。 */
31
+ export type StoreSweepBounds = Readonly<Partial<Record<StoreSweepLeg, StoreSweepBound>>>;
32
+ /**
33
+ * 部署旋钮 → 各腿的界:本仓唯一的读法。`TOOL_RESULT_TTL_SEC`(秒,> 0,热键)→ `tool-results-aged`;`ROSTER_RETENTION_MS`(毫秒,下限 1 分钟)→ `roster-aged`;
34
+ * `WORKFLOW_JOURNAL_RETENTION_MS`(毫秒,下限 1 分钟)→ `workflow-journal-expired`。
35
+ * 组合点把它包成读法函数交给 {@link createStoreSweep},每次清扫现读一次 —— 交起服那一刻的值会让热发布的新界不生效。
36
+ */
37
+ export declare function buildStoreSweepBounds(config: Pick<ServiceConfig, "toolResultTtlSec" | "rosterRetentionMs" | "workflowJournalRetentionMs">): StoreSweepBounds;
38
+ /** 一条腿的实现:删掉存了超过 `bound.maxAgeMs` 的行,答删了几行。 */
39
+ export type StoreSweepLegRun = (nowMs: number, bound: StoreSweepBound) => Promise<number> | number;
40
+ /**
41
+ * journal 店的按龄删 → `workflow-journal-expired` 腿:截止线 = 动词交来的 `nowMs` − 动词交来的 `maxAgeMs`(界每次清扫现读,腿不自存)。
42
+ * 店没有这一面(core 的 File / 内存 journal 店)或没有店(self-orchestration 关 / 无后端)⇒ 无腿,动词答 0。
43
+ */
44
+ export declare function createJournalSweepLeg(store: {
45
+ reapExpired?(now: number, maxAgeMs: number): Promise<number>;
46
+ } | undefined): StoreSweepLegRun | undefined;
47
+ export interface StoreSweep {
48
+ sweep(input: {
49
+ readonly nowMs: number;
50
+ }): Promise<StoreSweepReceipt>;
51
+ }
52
+ /** 有腿失败的那次清扫:`receipt` 里失败腿记 0,`failed` 按腿带原因。 */
53
+ export declare class StoreSweepError extends Error {
54
+ readonly receipt: StoreSweepReceipt;
55
+ readonly failed: ReadonlyMap<StoreSweepLeg, unknown>;
56
+ constructor(receipt: StoreSweepReceipt, failed: ReadonlyMap<StoreSweepLeg, unknown>);
57
+ }
58
+ export declare function createStoreSweep(spec: {
59
+ readonly legs: Readonly<Partial<Record<StoreSweepLeg, StoreSweepLegRun>>>;
60
+ /** 界的读法:每次清扫调一次(只收函数 —— 起服那一刻的界对象交不进来)。 */
61
+ readonly bounds: () => StoreSweepBounds;
62
+ }): StoreSweep;
63
+ //# sourceMappingURL=store-sweep.d.ts.map
@@ -0,0 +1,48 @@
1
+ export const STORE_SWEEP_LEGS = ["roster-aged", "tool-results-aged", "workflow-journal-expired"];
2
+ export function buildStoreSweepBounds(config) {
3
+ return {
4
+ "roster-aged": { maxAgeMs: config.rosterRetentionMs },
5
+ "tool-results-aged": { maxAgeMs: config.toolResultTtlSec * 1000 },
6
+ "workflow-journal-expired": { maxAgeMs: config.workflowJournalRetentionMs },
7
+ };
8
+ }
9
+ export function createJournalSweepLeg(store) {
10
+ const reap = store?.reapExpired?.bind(store);
11
+ return reap === undefined ? undefined : (nowMs, { maxAgeMs }) => reap(nowMs, maxAgeMs);
12
+ }
13
+ export class StoreSweepError extends Error {
14
+ receipt;
15
+ failed;
16
+ constructor(receipt, failed) {
17
+ super(`store sweep: leg(s) ${[...failed.keys()].join(", ")} failed`);
18
+ this.receipt = receipt;
19
+ this.failed = failed;
20
+ this.name = "StoreSweepError";
21
+ }
22
+ }
23
+ export function createStoreSweep(spec) {
24
+ const runLeg = async (leg, nowMs, bounds) => {
25
+ const run = spec.legs[leg];
26
+ const bound = bounds[leg];
27
+ if (run === undefined || bound === undefined)
28
+ return { leg, removed: 0 };
29
+ try {
30
+ return { leg, removed: await run(nowMs, bound) };
31
+ }
32
+ catch (error) {
33
+ return { leg, error };
34
+ }
35
+ };
36
+ return {
37
+ async sweep({ nowMs }) {
38
+ const bounds = spec.bounds();
39
+ const settled = await Promise.all(STORE_SWEEP_LEGS.map((leg) => runLeg(leg, nowMs, bounds)));
40
+ const receipt = Object.fromEntries(settled.map((s) => [s.leg, "removed" in s ? s.removed : 0]));
41
+ const failed = new Map(settled.flatMap((s) => ("error" in s ? [[s.leg, s.error]] : [])));
42
+ if (failed.size > 0)
43
+ throw new StoreSweepError(receipt, failed);
44
+ return receipt;
45
+ },
46
+ };
47
+ }
48
+ //# sourceMappingURL=store-sweep.js.map
@@ -16,7 +16,7 @@ import { PRINCIPAL_MAX_UTF8_BYTES } from "../security.js";
16
16
  import { ensureIndexes } from "./ensure-index.js";
17
17
  import { CENTRAL_SCHEMA_INDEXES } from "./schema-indexes.js";
18
18
  import { SESSION_INDEXES } from "./pg-session-storage.js";
19
- import { TOOL_RESULT_INDEXES } from "./tool-result-store-sql.js";
19
+ import { TOOL_RESULT_INDEXES } from "../stores-sql/tool-result-store-sql.js";
20
20
  import { COST_QUOTA_INDEXES } from "./pg-cost-quota.js";
21
21
  import { RATE_LIMIT_INDEXES } from "./pg-rate-limiter.js";
22
22
  import { OUTCOME_LEDGER_INDEXES } from "./outcome-ledger-sql.js";
@@ -16,10 +16,10 @@ import { type InstructionSourceBaseline } from "../instruction-source-notice.js"
16
16
  import type { SessionWorkspace } from "../session-workspace.js";
17
17
  import type { RetentionDeclaration } from "@sema-agent/core";
18
18
  import type { SessionSummary } from "./store-contracts.js";
19
- import { type ClientSessionRowWrite, type ReplaySessionRowWrite, type ReplaySessionRowWriteOutcome, type SessionRowPatch, type SessionRowWriteOutcome } from "../session-row.js";
19
+ import { type ClientSessionRowWrite, type ReplaySessionRowWrite, type ReplaySessionRowWriteOutcome, type SessionRowAnswer, type SessionRowPatch, type SessionRowWriteOutcome } from "../session-row.js";
20
20
  import { type PlacementAcquireOpts } from "./session-placement.js";
21
21
  import { type StagingHandle } from "../session-sync-kernel.js";
22
- import { type ForkTarget, type ForkToOutcome } from "./session-fork.js";
22
+ import { type ForkPlacement, type ForkTarget, type ForkToOutcome } from "./session-fork.js";
23
23
  import { type ExecutionPlacementSeat } from "../execution-placement.js";
24
24
  export declare class TiDBSessionStore implements SessionStore {
25
25
  private readonly pool;
@@ -130,6 +130,17 @@ export declare class TiDBSessionStore implements SessionStore {
130
130
  limit: number;
131
131
  q?: string;
132
132
  }): Promise<SessionSummary[]>;
133
+ /** {@link listSessions} with each row's occupant (owner + incarnation) from the same SELECT — `OwnerAwareSessionStore.listSessionRows`; the incarnation never enters the row. */
134
+ listSessionRows(opts: {
135
+ owner?: string;
136
+ includeUnowned?: boolean;
137
+ cursor?: {
138
+ lastActivityAt: string;
139
+ sessionId: string;
140
+ };
141
+ limit: number;
142
+ q?: string;
143
+ }): Promise<Array<SessionRowAnswer<SessionSummary>>>;
133
144
  /** ONE session's list row — {@link listSessions}' projection (same SELECT, same mapper) scoped to one id; `undefined` = not a
134
145
  * row of the list face (no such session / placed). The run-preview subqueries are scoped to the same id (an index read on
135
146
  * `task_run.session_id`, not the whole-ledger aggregate the list pays). */
@@ -194,7 +205,9 @@ export declare class TiDBSessionStore implements SessionStore {
194
205
  * We instead SELECT the entire `session_event` log ordered by seq — every durable entry, compaction floor
195
206
  * bypassed — and re-seq it dense from 0 into the new session, ids/parents/payload byte-verbatim.
196
207
  */
197
- fork(sourceId: string, owner?: string | null): Promise<string | null>;
208
+ fork(sourceId: string, owner?: string | null, opts?: {
209
+ placement?: ForkPlacement;
210
+ }): Promise<string | null>;
198
211
  /**
199
212
  * **fork 续写的店契约**(三店同一只私有体;core `fork` 是它的投影):把源会话的整份历史拷进调用方给的目标 id。
200
213
  * 1. **原子目标创建**:事务首句 `INSERT INTO session_meta (…, fork_key) VALUES (:target, …)`,主键即排他(meta 先,随后拷事件、COMMIT);
@@ -152,6 +152,9 @@ export class TiDBSessionStore {
152
152
  }
153
153
  }
154
154
  async listSessions(opts) {
155
+ return (await this.listSessionRows(opts)).map((a) => a.row);
156
+ }
157
+ async listSessionRows(opts) {
155
158
  const params = [];
156
159
  const where = ["sm.placement_kind IS NULL"];
157
160
  if (opts.owner !== undefined) {
@@ -166,7 +169,7 @@ export class TiDBSessionStore {
166
169
  where.push("(sm.updated_at < ? OR (sm.updated_at = ? AND sm.session_id < ?))");
167
170
  params.push(new Date(opts.cursor.lastActivityAt), new Date(opts.cursor.lastActivityAt), opts.cursor.sessionId);
168
171
  }
169
- return (await this.selectListRows({ where, params, limit: opts.limit })).map((a) => a.row);
172
+ return this.selectListRows({ where, params, limit: opts.limit });
170
173
  }
171
174
  async sessionSummaryOf(sessionId) {
172
175
  return (await this.listRowOf(sessionId))?.row;
@@ -246,8 +249,8 @@ export class TiDBSessionStore {
246
249
  async recordSessionWorkspace(sessionId, incarnation, workspace) {
247
250
  await this.pool.query("UPDATE session_meta SET workspace = ? WHERE session_id = ? AND incarnation = ?", [encodeSessionWorkspaceCell(workspace, JSON.stringify, sessionId), sessionId, incarnation]);
248
251
  }
249
- async fork(sourceId, owner) {
250
- return forkByFreshId((s, o, t) => this.forkTo(s, o, t), sourceId, owner);
252
+ async fork(sourceId, owner, opts) {
253
+ return forkByFreshId((s, o, t) => this.forkTo(s, o, t), sourceId, owner, opts);
251
254
  }
252
255
  async forkTo(sourceId, owner, target) {
253
256
  for (let attempt = 0; attempt < 2; attempt++) {
@@ -275,7 +278,8 @@ export class TiDBSessionStore {
275
278
  try {
276
279
  await conn.beginTransaction();
277
280
  try {
278
- await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, fork_key) VALUES (?,?,?,?,?,?,?,?)", [target.id, forkOwner, now, now, forkLeafId, eventRows.length, mintSessionIncarnation(), target.key ?? null]);
281
+ await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, fork_key, " +
282
+ "placement_kind, placement_scope, placement_parent_session_id, placement_root_session_id, placement_handle, placed_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", [target.id, forkOwner, now, now, forkLeafId, eventRows.length, mintSessionIncarnation(), target.key ?? null, ...placementInsertValues(target.placement, now)]);
279
283
  }
280
284
  catch (err) {
281
285
  if (!isMysqlDupKeyError(err))
@@ -6,16 +6,13 @@
6
6
  * 会被交付,只有屏判完才知道;本服务存 / 转目标的每张面(run 行预览、续跑输入、标题器取材)因此只能在交付之后写交付的那一份
7
7
  * (律的属主 = `run-acceptance.ts`)。屏**不在**的腿上没有「屏前」:交付的就是请求原文,提交那一刻就知道 —— 与没有屏这回事之前逐字同。
8
8
  *
9
- * ## 判据(一条)
10
- * 两座任一注册的 `uses.events` 覆盖屏听的任一站 ⇒ 有屏。`uses.events` 是注册**声明**的事件全集(名字或 `<前缀>.*`);引擎准入保证一张注册挂上的
11
- * handler 不越出它声明的事件(越出 = 准入拒),所以「声明里没有」⇒ 这条腿的总线上**一定**没有屏 —— 判据只会多判有屏(声明了、`register`
12
- * 时没挂),不会漏判。多判的代价是这条腿的那几张面等到交付才写(写的仍是交付的那一份),不是放行。
13
- *
14
- * ## 过渡(引擎包根今天没有导出这一判据)
15
- * 屏听哪两站、`<前缀>.*` 怎么覆盖,读的是引擎自己的判据(引擎的 `promptScreenHasHandlers` 问的就是这两站;前缀形的展开同引擎准入的读法)。
16
- * 引擎在包根导出「一组注册声明了 prompt 屏」的判据之后,{@link PROMPT_SCREEN_STATIONS} 与 {@link covers} 一起退役,本函数改调引擎那一只 —— 读口换、判据不变。
9
+ * ## 判据(一条,引擎的)
10
+ * 引擎的 `promptScreenDeclaredBy`:两座的注册并起来,任一张的 `uses.events`(名字或 `<前缀>.*`,按引擎准入的读法展开)选中屏听的任一站
11
+ * (引擎的 `PROMPT_SCREEN_STATIONS`)⇒ 有屏。引擎准入保证一张注册挂上的 handler 不越出它声明的事件(越出 = 准入拒),所以「声明里没有」⇒
12
+ * 这条腿的总线上**一定**没有屏 —— 判据只会多判有屏(声明了、`register` 时没挂),不会漏判。多判的代价是这条腿的那几张面等到交付才写
13
+ * (写的仍是交付的那一份),不是放行。站名表与前缀展开只住在引擎里:引擎给屏加一站,本服务同一拍就认。
17
14
  */
18
- import type { ModRegistration } from "@sema-agent/core";
15
+ import { type ModRegistration } from "@sema-agent/core";
19
16
  /** 这条腿的两座(缺席的座 = 没有注册)里有没有一张注册声明了 prompt 屏。 */
20
17
  export declare function promptScreenDeclared(seats: ReadonlyArray<ReadonlyArray<Pick<ModRegistration, "uses">> | undefined>): boolean;
21
18
  //# sourceMappingURL=prompt-screen.d.ts.map
@@ -1,8 +1,5 @@
1
- const PROMPT_SCREEN_STATIONS = ["prompt.submit", "classic.UserPromptSubmit"];
2
- function covers(declared, station) {
3
- return declared === station || (declared.endsWith(".*") && declared.length > 2 && station.startsWith(declared.slice(0, -1)));
4
- }
1
+ import { promptScreenDeclaredBy } from "@sema-agent/core";
5
2
  export function promptScreenDeclared(seats) {
6
- return seats.some((seat) => seat?.some((registration) => registration.uses.events.some((declared) => PROMPT_SCREEN_STATIONS.some((station) => covers(declared, station)))) === true);
3
+ return promptScreenDeclaredBy(seats.flatMap((seat) => seat ?? []));
7
4
  }
8
5
  //# sourceMappingURL=prompt-screen.js.map
@@ -1,5 +1,5 @@
1
1
  import { type DirectWritableRuleBehavior, type RemovalLiveness } from "./permission-rule-vocab.js";
2
- import { type RuleOwner, type ImportPreview, type ImportedSettingsLayer, type PersistedRule, type RuleBehavior, type RuleCandidate, type EffectivePermissionRule, type RemoveResult, type RuleWriteCommitted, type EditedRuleTextPrecheck, type RuleScope, type RuleOffer } from "@sema-agent/core";
2
+ import { type RuleOwner, type ImportPreview, type ImportedSettingsLayer, type PersistedRule, type RuleBehavior, type RuleCandidate, type EffectivePermissionRule, type RemoveResult, type RuleRefusalCode, type RuleWriteCommitted, type EditedRuleTextPrecheck, type RuleScope, type RuleOffer } from "@sema-agent/core";
3
3
  import type { DurableRulePartitionProvider, PermissionRuleStoreProvider, RuleApprovalRecordStore } from "@sema-agent/core";
4
4
  import { type RuleImportTicket, type RuleTicketPurpose, type RuleTicketReclaimResult, type RuleTicketRedeemResult, type RuleTicketSnapshot } from "./plugins/permission-rule-store-sql.js";
5
5
  /**
@@ -192,31 +192,22 @@ export type LocalImportRefusalCode =
192
192
  | "not_importable";
193
193
  /** 兑付回执的**成员级终态**(闭集,机读;`detail` 是给人看的那一半)。两只 redeem 口(cc-import / local-import)同一张表。
194
194
  *
195
- * 🔴 **引擎的成员拒一律落 `indeterminate`,本仓不铸 `refused`**:core 的 `RedeemedBatchMember` 拒绝臂只带一个**自由文本**
196
- * `reason`,而它装的东西两类都有 —— 裁定(引擎 7.62.0 对旧导入记录里从 `/` 写起的全局规则答 `unsupported.layer_root:`;
197
- * 批里的收紧没落、同批放行被扣下的 `withheld:`)与店侧成因(读不出店 / 写面抛 / OCC 用尽 —— 写面抛时那一条**可能已经落了**)。
198
- * 按串去猜「这是裁定还是瞬时」正是本仓明令禁止的自造判读,所以一律 `indeterminate`(安全方向:不谎报落了,也不担保没落),
199
- * `detail` 原样带引擎的话 —— 人读得到出路(例:那句 `unsupported.layer_root:` 自己说「重新 prepare,这一条会披露在 skipped」)。
200
- * `refused` 留在词表里是给**带类型的**判别位到货那一天(引擎给拒绝臂一个机读的「裁定 / 瞬时」位之后,裁定那一类落 `refused`):
201
- * 它进了**落盘回执的边界 schema**(`ImportOutcomeSchema`;`redeemed_outcome` 列回读同一张词表),滚动升级窗里先升的进程写下的
202
- * `refused`,后升的进程读得回。⚠️ 预览面**不用**这个词:那一面的拒绝形是 `admitted:false + LocalImportRefusalCode`
203
- * ({@link LocalImportPreviewMember}),两面词表**不同**。 */
195
+ * 🔴 **引擎拒的成员,结局只读引擎的两词 `committed`**(core 7.63.0 [ref],`RedeemedBatchMember` 拒臂必填):`no` ⇒ `refused`
196
+ * (引擎确知这一条没落 —— 裁定,如旧导入记录里从 `/` 写起的全局规则的 `unsupported.layer_root`;同批放行被扣下的 `withheld`)、
197
+ * `unknown` ⇒ `indeterminate`(写面抛 / 读回读不出 —— 那一条**可能已经落了**)。本仓不按串判,不另写第二份判据。
198
+ * 它进了**落盘回执的边界 schema**(`ImportOutcomeSchema`;`redeemed_outcome` 列回读同一张词表)。⚠️ 预览面**不用**这个词表:那一面的拒绝形是
199
+ * `admitted:false + LocalImportRefusalCode`({@link LocalImportPreviewMember}),两面词表**不同**。 */
204
200
  export type ImportMemberOutcome =
205
201
  /** 这一次真的写进店里了。 */
206
202
  "persisted"
207
203
  /** 等价规则**已经在店**(引擎的 `deduped`)—— 同意早就生效,这次什么都不用做。 */
208
204
  | "no-op"
209
- /** 这条被拒了、确知没落(留给带类型判别位的词位,本版不铸 —— 见上)。 */
205
+ /** 引擎拒了这一条,并答 `committed: "no"` —— 确知没落。重来同一条拒因(`reason`)会得同一个答,出路在 `detail`(引擎原话)。 */
210
206
  | "refused"
211
- /** **不知道落没落**:引擎在这一条上答了拒,而拒因只有自由文本。如实编,禁猜(猜"成了"会谎报一次没发生的授权,
212
- * 猜"没成"会让人以为可以盲目重来,而重来可能撞上一条其实已经存在的规则 —— 对账读 `GET /v1/rules`,重来走一次新的导入,幂等)。 */
207
+ /** 引擎拒了这一条,并答 `committed: "unknown"` —— **不知道落没落**。如实编,禁猜。这一词**不进落定的回执**(落定律:任一成员
208
+ * 结局不知 ⇒ 不落定、503 同票重走,见 {@link unsettledDetailOf});词表留着它,是因为 7.145.x 及更早落定的票行(`redeemed_outcome`)
209
+ * 里有它,回放读那份存量。 */
213
210
  | "indeterminate";
214
- /** `indeterminate` 的成因(闭集,一词)。
215
- * 「兑付走本身没走完」**不是**一个成员终态:那一形没有完整成员表,兑付不落定(放回认领、503 `state.rule_import_retry`,
216
- * 同一张票重走交出完整表)—— 所以没有第二个词。 */
217
- export type ImportIndeterminateCode =
218
- /** 引擎在这一条上答了拒(`RedeemedBatchMember` 的 `refused` 臂),而拒因只有自由文本 ⇒ 落不了裁定,如实说"不知道"。 */
219
- "store_refused";
220
211
  /** prepare 面的一行。判别式联合:被收下的行**没有**拒因字段可读,被拒的行**必然**带拒因 ——
221
212
  * 「admitted 却带 reason」这种矛盾态在类型上不可表达。
222
213
  * 收下的**收紧**(deny / ask)在 prepare 当场经直写接缝落店,行带它的结局 `outcome`(`persisted` = 这次写了 / `no-op` = 等价规则已在店);
@@ -236,24 +227,26 @@ export type LocalImportPreviewMember = {
236
227
  };
237
228
  /** 一条收紧在 prepare 当场落店的结局(与兑付回执的 `persisted` / `no-op` 同词同义;直写接缝 `addPersistedRule` 的 `added` / `no-op`)。 */
238
229
  export type LocalImportTighteningOutcome = "persisted" | "no-op";
239
- /** 兑付回执的一行(两只 redeem 口同形;唯一铸点 {@link buildImportOutcomeMembers})。 */
230
+ /** 兑付回执的一行(两只 redeem 口同形;唯一铸点 {@link buildImportOutcomeMembers})。`reason` / `detail` 在场 ⇔ 引擎拒了这一条
231
+ * (`refused` / `indeterminate`):`reason` = 引擎的闭集拒因码(`RuleRefusalCode`,core 属主,逐字),`detail` = 引擎给人看的那句话。 */
240
232
  export interface ImportOutcomeMember {
241
233
  key: ImportRuleKey;
242
234
  outcome: ImportMemberOutcome;
243
- reason?: ImportIndeterminateCode;
235
+ reason?: RuleRefusalCode;
244
236
  detail?: string;
245
237
  }
246
238
  /**
247
239
  * 一次兑付的回执整只 —— **两只 redeem 口同一张**(cc-import / local-import 的 200 体都是 `{ members, rev }`,路由同一个铸点),
248
240
  * local-import 另把它**逐字**写进票行 `redeemed_outcome`(回放同源:回放答的就是它)。
249
241
  *
250
- * 🔴 **落定律(一条,两口同读)**:兑付走完、拿到引擎的**完整成员表** ⇒ 这次兑付落定,回执逐成员交出(引擎的成员拒落
251
- * `indeterminate`,见 {@link ImportMemberOutcome}),票不放回、不答 503:cc-import 一次性用掉、答 200 回执;local-import 把回执
242
+ * 🔴 **落定律(一条,两口同读)**:兑付走完、拿到引擎的完整成员表、**且每个成员的结局都确定**(`persisted` / `no-op` / 引擎答
243
+ * `committed: "no"` 的 `refused`)⇒ 这次兑付落定,回执逐成员交出,票不放回、不答 503:cc-import 一次性用掉、答 200 回执;local-import 把回执
252
244
  * 落进票行(SETTLED)后答 200 —— 落定这一跳答不成(落定写抛 / 认领被租约接管而新持有者还没落定)⇒ 照旧答 409
253
245
  * `conflict.rule_import_in_flight`,同票再来读到的是权威的那一份回执(那一跳不改成员结局,只决定哪一份是权威)。**没有**完整
254
- * 成员表(引擎在走之前整批拒 / 走到一半抛 / confirm 输给并发写者 / 店在走之前抛)⇒ 不落定:放回认领、503
246
+ * 成员表(引擎在走之前整批拒 / confirm 输给并发写者 / 店在走之前抛 / 循环里仍抛出来的异常),或任一成员结局**不知**(引擎答
247
+ * `committed: "unknown"`:规则店的写抛 / 读回读不出,引擎 7.64.0 起还有成员循环里审批记录店的记 dot CAS / dot 分配失败)⇒ 不落定:放回认领、503
255
248
  * `state.rule_import_retry`,同一张票重来就是重走一遍 —— 兑付按引擎的设计幂等(记录里的 dot 台账),重走交出完整表,
256
- * 被打断的那一走已落的成员读 `no-op`。成员拒**不**按票自动重试:一条永久被拒的成员(旧记录里的 `unsupported.layer_root`)
249
+ * 被打断的那一走已落的成员读 `no-op`。确知的成员拒**不**按票自动重试:一条永久被拒的成员(旧记录里的 `unsupported.layer_root`)
257
250
  * 若走重试臂,客户端会 503 到票过期、临期放不回 ⇒ 404,已落成员不撤、被拒成员永不落 —— 7.144.0 及更早 cc-import 口就是这一形。
258
251
  */
259
252
  export interface ImportOutcome {
@@ -346,12 +339,12 @@ export type RuleImportPrepared = {
346
339
  * `state.rule_import_retry`;`state-unreadable` ⇒ 503 `state.rule_ticket_unreadable`。分类保留只为服务端日志/诊断与
347
340
  * 上述三分支的判据。 */
348
341
  export type RuleImportRedeemed =
349
- /** 兑付走完、拿到完整成员表 ⇒ 落定(成员里有引擎拒的也在这一臂,那几行 `indeterminate`)。 */
342
+ /** 兑付走完、拿到完整成员表且每个成员结局确定 ⇒ 落定(引擎确知没落的成员也在这一臂,那几行 `refused`)。 */
350
343
  {
351
344
  ok: true;
352
345
  outcome: ImportOutcome;
353
346
  }
354
- /** `retryable` = 这次失败**没有裁定任何事**、也**没有完整成员表**(store 抛错 / CAS 冲突 / 引擎走之前整批拒 / 走到一半抛),
347
+ /** `retryable` = 这次兑付**没有落定**(store 抛错 / CAS 冲突 / 引擎走之前整批拒 / 循环里仍抛出来的异常 / 某个成员结局不知),
355
348
  * 认领已放回,属主原样重试即重走。
356
349
  * 它与裁定性拒绝(载荷被改写、记录不存在)分家是承重的:把两者塌成一格,一次数据库抖动就会被
357
350
  * 客户端读成「这张票永远不能用了」。⚠️ wire 面**不再**折 404:`retryable === true` ⇒ 503