@sema-agent/server 7.137.0 → 7.139.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/MIGRATION.md +600 -142
  2. package/README.md +7 -3
  3. package/README.zh-CN.md +6 -3
  4. package/USAGE.md +132 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/wire.d.ts +3 -3
  8. package/dist/approval-card.d.ts +23 -16
  9. package/dist/approval-card.js +1 -0
  10. package/dist/audit.js +1 -0
  11. package/dist/background-agent-name.d.ts +5 -0
  12. package/dist/background-agent-name.js +5 -0
  13. package/dist/bench/s1/arms.d.ts +1 -1
  14. package/dist/bench/s1/arms.js +1 -3
  15. package/dist/bench/s1/run-firm.js +2 -2
  16. package/dist/boot/budget-tracing.d.ts +1 -12
  17. package/dist/boot/deployment-mods.d.ts +46 -16
  18. package/dist/boot/deployment-mods.js +82 -6
  19. package/dist/boot/device-lane.d.ts +8 -3
  20. package/dist/boot/device-lane.js +7 -2
  21. package/dist/boot/execution-env.d.ts +4 -2
  22. package/dist/boot/execution-env.js +16 -24
  23. package/dist/boot/execution-lane.d.ts +1 -1
  24. package/dist/boot/governance-seams.d.ts +12 -18
  25. package/dist/boot/governance-seams.js +10 -24
  26. package/dist/boot/leader.d.ts +3 -0
  27. package/dist/boot/leader.js +1 -0
  28. package/dist/boot/memory-consolidation.js +2 -2
  29. package/dist/boot/org-delivery.js +15 -2
  30. package/dist/boot/resolve-spec.d.ts +4 -1
  31. package/dist/boot/resolve-spec.js +29 -19
  32. package/dist/boot/retention-lane.d.ts +14 -8
  33. package/dist/boot/retention-lane.js +2 -8
  34. package/dist/boot/runner-deps.d.ts +10 -4
  35. package/dist/boot/runner-deps.js +2 -0
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-04-stores.d.ts +1 -12
  40. package/dist/boot/stage-05-execution-env.d.ts +3 -12
  41. package/dist/boot/stage-05-execution-env.js +8 -5
  42. package/dist/boot/stage-06-runners.d.ts +3 -12
  43. package/dist/boot/stage-06-runners.js +5 -3
  44. package/dist/boot/stage-07-capability-layer.d.ts +3 -12
  45. package/dist/boot/stage-07-capability-layer.js +2 -2
  46. package/dist/boot/stage-08-reapers.d.ts +3 -12
  47. package/dist/boot/stage-09-leader.d.ts +3 -12
  48. package/dist/boot/stage-09-leader.js +2 -3
  49. package/dist/boot/stage-10-http-server.d.ts +3 -12
  50. package/dist/boot/stage-10-http-server.js +5 -3
  51. package/dist/boot/stores.js +4 -4
  52. package/dist/boot/web-admin.d.ts +5 -2
  53. package/dist/boot/web-admin.js +5 -5
  54. package/dist/brain.js +5 -5
  55. package/dist/budget.d.ts +17 -15
  56. package/dist/budget.js +2 -2
  57. package/dist/capabilities/mcp-probe.d.ts +36 -11
  58. package/dist/capabilities/mcp-probe.js +44 -5
  59. package/dist/capabilities/scenarios.d.ts +1 -1
  60. package/dist/capability-facts.d.ts +21 -7
  61. package/dist/capability-facts.js +13 -3
  62. package/dist/checkpoint-identity.d.ts +13 -6
  63. package/dist/config-catalog.js +14 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +19 -24
  67. package/dist/config-provider.js +27 -12
  68. package/dist/config-types.d.ts +25 -12
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +52 -20
  71. package/dist/delegated-session-owner.d.ts +2 -2
  72. package/dist/deployment-shape.d.ts +7 -7
  73. package/dist/device-enrollment.d.ts +41 -2
  74. package/dist/device-enrollment.js +27 -12
  75. package/dist/device-store.d.ts +58 -85
  76. package/dist/device-store.js +19 -49
  77. package/dist/device-ws-hub.js +2 -1
  78. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  79. package/dist/exec-cut.d.ts +60 -0
  80. package/dist/exec-cut.js +36 -0
  81. package/dist/execution-lane-caps.d.ts +19 -0
  82. package/dist/execution-lane-caps.js +10 -0
  83. package/dist/execution-placement.d.ts +259 -0
  84. package/dist/execution-placement.js +199 -0
  85. package/dist/field-conflict.d.ts +3 -2
  86. package/dist/field-conflict.js +1 -0
  87. package/dist/gate-settlement.d.ts +71 -0
  88. package/dist/gate-settlement.js +40 -0
  89. package/dist/hooks/classic-stations.d.ts +1 -0
  90. package/dist/hooks/classic-stations.js +1 -0
  91. package/dist/hooks/command-spawn.d.ts +2 -2
  92. package/dist/hooks/hook-runner.js +14 -14
  93. package/dist/hosted-posture.d.ts +2 -2
  94. package/dist/http/admission.js +10 -19
  95. package/dist/http/checkpoint-ctx.d.ts +21 -12
  96. package/dist/http/checkpoint-ctx.js +4 -2
  97. package/dist/http/claimed-run.d.ts +1 -1
  98. package/dist/http/dispatch.d.ts +4 -0
  99. package/dist/http/dispatch.js +3 -0
  100. package/dist/http/durable-run-leg.js +12 -6
  101. package/dist/http/execution-context.d.ts +218 -0
  102. package/dist/http/execution-context.js +330 -0
  103. package/dist/http/memory-compliance-failure-reply.js +3 -0
  104. package/dist/http/resume-legs.d.ts +5 -11
  105. package/dist/http/resume-legs.js +179 -104
  106. package/dist/http/route-ctx.d.ts +44 -59
  107. package/dist/http/route-ctx.js +2 -5
  108. package/dist/http/routes/a2a-serve.js +10 -4
  109. package/dist/http/routes/agents-roster.d.ts +1 -1
  110. package/dist/http/routes/agents-roster.js +5 -1
  111. package/dist/http/routes/approvals-assistant.js +6 -6
  112. package/dist/http/routes/background.d.ts +29 -1
  113. package/dist/http/routes/background.js +29 -2
  114. package/dist/http/routes/capabilities.js +12 -10
  115. package/dist/http/routes/devices.d.ts +13 -19
  116. package/dist/http/routes/devices.js +21 -26
  117. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  118. package/dist/http/routes/mcp-reconnect.js +7 -5
  119. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  120. package/dist/http/routes/memory-origin.d.ts +1 -1
  121. package/dist/http/routes/rules.js +3 -3
  122. package/dist/http/routes/runs.js +11 -7
  123. package/dist/http/routes/session-sync.js +110 -15
  124. package/dist/http/routes/sessions.d.ts +6 -0
  125. package/dist/http/routes/sessions.js +119 -13
  126. package/dist/http/routes/side-query.d.ts +12 -4
  127. package/dist/http/routes/side-query.js +6 -8
  128. package/dist/http/routes/tasks.js +800 -782
  129. package/dist/http/server.d.ts +61 -39
  130. package/dist/http/server.js +11 -0
  131. package/dist/http/session-inherit-env.d.ts +3 -4
  132. package/dist/http/session-inherit-env.js +1 -1
  133. package/dist/http/wire-types.d.ts +22 -18
  134. package/dist/identity-source.d.ts +1 -1
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.js +1 -0
  137. package/dist/leader/wire.d.ts +7 -0
  138. package/dist/leader/wire.js +5 -4
  139. package/dist/mcp-assertion-header.d.ts +51 -40
  140. package/dist/mcp-assertion-header.js +10 -11
  141. package/dist/mcp-authorization-face.d.ts +27 -0
  142. package/dist/mcp-authorization-face.js +15 -0
  143. package/dist/memory-operator-faces.d.ts +13 -4
  144. package/dist/memory-operator-faces.js +1 -17
  145. package/dist/memory-sync-client.d.ts +53 -14
  146. package/dist/memory-sync-client.js +187 -92
  147. package/dist/memory-sync.d.ts +1 -1
  148. package/dist/memory-sync.js +3 -2
  149. package/dist/model-route-gap.d.ts +6 -22
  150. package/dist/model-route-gap.js +7 -5
  151. package/dist/mods-declaration.d.ts +110 -0
  152. package/dist/mods-declaration.js +109 -0
  153. package/dist/observability/cost-taxonomy.d.ts +2 -2
  154. package/dist/observability/err-text.d.ts +5 -0
  155. package/dist/observability/err-text.js +9 -0
  156. package/dist/observability/fail-open.d.ts +17 -1
  157. package/dist/observability/fail-open.js +17 -1
  158. package/dist/observability/run-terminal.js +0 -1
  159. package/dist/observability/secret-env-scrub.d.ts +1 -1
  160. package/dist/observability/secret-env-scrub.js +1 -1
  161. package/dist/orchestration/workflow-notify-journal.js +4 -4
  162. package/dist/org-memory-admission.d.ts +4 -3
  163. package/dist/org-memory-admission.js +6 -6
  164. package/dist/parked-decide.d.ts +49 -11
  165. package/dist/parked-decide.js +25 -26
  166. package/dist/parked-revive-surface.d.ts +12 -15
  167. package/dist/parked-revive-surface.js +3 -6
  168. package/dist/peer-seat.d.ts +156 -0
  169. package/dist/peer-seat.js +273 -0
  170. package/dist/permission-rule-vocab.d.ts +7 -7
  171. package/dist/permission-rule-vocab.js +3 -3
  172. package/dist/plain-string-record.d.ts +38 -0
  173. package/dist/plain-string-record.js +38 -0
  174. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  175. package/dist/plugins/approval-ask-store-file.js +11 -0
  176. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  177. package/dist/plugins/approval-ask-store-memory.js +12 -0
  178. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  179. package/dist/plugins/approval-ask-store-sql.js +30 -12
  180. package/dist/plugins/background-agent-store-sql.js +6 -3
  181. package/dist/plugins/caching-session-store.d.ts +11 -2
  182. package/dist/plugins/caching-session-store.js +15 -3
  183. package/dist/plugins/checkpoint-store-sql.d.ts +21 -25
  184. package/dist/plugins/checkpoint-store-sql.js +13 -15
  185. package/dist/plugins/device-store-sql.d.ts +25 -51
  186. package/dist/plugins/device-store-sql.js +49 -103
  187. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  188. package/dist/plugins/execution-placement-sql.js +223 -0
  189. package/dist/plugins/file-history-store-sql.d.ts +7 -6
  190. package/dist/plugins/file-history-store-sql.js +8 -7
  191. package/dist/plugins/file-run-store.d.ts +6 -1
  192. package/dist/plugins/file-run-store.js +4 -0
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  194. package/dist/plugins/fork-routing-session-store.js +16 -0
  195. package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
  196. package/dist/plugins/k8s-pod-reaper.js +3 -3
  197. package/dist/plugins/local-checkpoint-store.d.ts +1 -11
  198. package/dist/plugins/local-checkpoint-store.js +0 -1
  199. package/dist/plugins/local-session-store.d.ts +183 -45
  200. package/dist/plugins/local-session-store.js +412 -105
  201. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  202. package/dist/plugins/mailbox-store-sql.js +103 -15
  203. package/dist/plugins/memory-key-guards.d.ts +4 -0
  204. package/dist/plugins/memory-key-guards.js +1 -0
  205. package/dist/plugins/memory-run-store.d.ts +1 -1
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +117 -6
  209. package/dist/plugins/one-time-migrations.js +383 -14
  210. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
  212. package/dist/plugins/permission-rule-store-sql.js +34 -29
  213. package/dist/plugins/pg-pool.d.ts +7 -3
  214. package/dist/plugins/pg-session-storage.d.ts +41 -22
  215. package/dist/plugins/pg-session-storage.js +136 -55
  216. package/dist/plugins/remote-env-adb.d.ts +22 -4
  217. package/dist/plugins/remote-env-adb.js +70 -62
  218. package/dist/plugins/remote-env-device.d.ts +32 -12
  219. package/dist/plugins/remote-env-device.js +18 -17
  220. package/dist/plugins/remote-env-e2b.d.ts +19 -3
  221. package/dist/plugins/remote-env-e2b.js +41 -42
  222. package/dist/plugins/remote-env-file-error.d.ts +2 -0
  223. package/dist/plugins/remote-env-file-error.js +1 -1
  224. package/dist/plugins/remote-env-host.d.ts +23 -8
  225. package/dist/plugins/remote-env-host.js +66 -70
  226. package/dist/plugins/remote-env-k8s.d.ts +13 -16
  227. package/dist/plugins/remote-env-k8s.js +61 -54
  228. package/dist/plugins/remote-env-local-docker.d.ts +30 -5
  229. package/dist/plugins/remote-env-local-docker.js +46 -59
  230. package/dist/plugins/remote-env-ssh.d.ts +18 -4
  231. package/dist/plugins/remote-env-ssh.js +72 -56
  232. package/dist/plugins/remote-shell.d.ts +100 -3
  233. package/dist/plugins/remote-shell.js +166 -2
  234. package/dist/plugins/retention-store-sql.d.ts +23 -8
  235. package/dist/plugins/retention-store-sql.js +13 -1
  236. package/dist/plugins/run-store-sql.d.ts +13 -3
  237. package/dist/plugins/run-store-sql.js +5 -0
  238. package/dist/plugins/schema-consistency.d.ts +15 -5
  239. package/dist/plugins/schema-consistency.js +14 -8
  240. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  241. package/dist/plugins/schema-drift-sentence.js +38 -0
  242. package/dist/plugins/session-fork.d.ts +63 -12
  243. package/dist/plugins/session-fork.js +38 -21
  244. package/dist/plugins/session-ownership.d.ts +7 -0
  245. package/dist/plugins/session-ownership.js +5 -0
  246. package/dist/plugins/session-row-sql.d.ts +22 -0
  247. package/dist/plugins/session-row-sql.js +81 -0
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  250. package/dist/plugins/session-workspace-cell.js +38 -0
  251. package/dist/plugins/store-backend.d.ts +1 -1
  252. package/dist/plugins/store-backend.js +26 -14
  253. package/dist/plugins/store-contracts.d.ts +25 -5
  254. package/dist/plugins/tidb-pool.d.ts +12 -7
  255. package/dist/plugins/tidb-pool.js +15 -3
  256. package/dist/plugins/tidb-session-store.d.ts +74 -28
  257. package/dist/plugins/tidb-session-store.js +132 -53
  258. package/dist/plugins/tool-result-store-sql.d.ts +16 -8
  259. package/dist/plugins/tool-result-store-sql.js +26 -17
  260. package/dist/plugins/worktree-isolation.d.ts +3 -2
  261. package/dist/plugins/worktree-isolation.js +1 -7
  262. package/dist/project-identity.d.ts +1 -14
  263. package/dist/project-identity.js +0 -4
  264. package/dist/project-memory.d.ts +9 -15
  265. package/dist/project-memory.js +5 -4
  266. package/dist/request-key-closure.js +1 -1
  267. package/dist/request-value-closure.d.ts +6 -7
  268. package/dist/request-value-closure.js +1 -3
  269. package/dist/rules-consent.js +6 -4
  270. package/dist/run-local.d.ts +6 -0
  271. package/dist/run-local.js +36 -26
  272. package/dist/runs.d.ts +9 -2
  273. package/dist/runs.js +9 -2
  274. package/dist/sandbox-git-plane.d.ts +2 -2
  275. package/dist/security.d.ts +38 -12
  276. package/dist/security.js +8 -2
  277. package/dist/server-secret-env.d.ts +15 -8
  278. package/dist/server-secret-env.js +4 -2
  279. package/dist/session-children-retire.d.ts +27 -9
  280. package/dist/session-children-retire.js +9 -5
  281. package/dist/session-incarnation.d.ts +19 -10
  282. package/dist/session-incarnation.js +5 -3
  283. package/dist/session-row.d.ts +114 -5
  284. package/dist/session-row.js +55 -5
  285. package/dist/session-titler.d.ts +2 -2
  286. package/dist/session-workspace.d.ts +130 -0
  287. package/dist/session-workspace.js +83 -0
  288. package/dist/spec-fields.d.ts +1 -1
  289. package/dist/standing-answer-grant.d.ts +2 -13
  290. package/dist/standing-answer-grant.js +0 -7
  291. package/dist/task-a2a.d.ts +44 -14
  292. package/dist/task-a2a.js +46 -20
  293. package/dist/task-cwd.d.ts +6 -1
  294. package/dist/task-mcp.d.ts +33 -20
  295. package/dist/task-mcp.js +46 -22
  296. package/dist/tool-approval.d.ts +38 -8
  297. package/dist/tool-approval.js +57 -13
  298. package/dist/trace/core-keyset-guard.d.ts +33 -18
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +2 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +3 -0
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/project.d.ts +26 -7
  306. package/dist/trace/project.js +30 -3
  307. package/dist/trace/redact.js +42 -13
  308. package/dist/trace/self-minted-wire.d.ts +240 -12
  309. package/dist/trace/self-minted-wire.js +100 -4
  310. package/dist/trace/wire-projection-faces.d.ts +6 -6
  311. package/dist/trace/wire-projection-faces.js +6 -5
  312. package/dist/url-refusal.d.ts +1 -1
  313. package/dist/user-authored-text.d.ts +2 -2
  314. package/dist/user-authored-text.js +16 -1
  315. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  316. package/dist/web-admin-client/apply-effective.js +20 -10
  317. package/dist/web-admin-client/center-request.d.ts +3 -2
  318. package/dist/web-admin-client/center-request.js +2 -3
  319. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  320. package/dist/web-admin-client/skills-mcp.js +32 -18
  321. package/dist/web-admin-client/types.d.ts +11 -0
  322. package/package.json +3 -3
  323. package/wire-changes/server@7.138.0.json +446 -0
  324. package/wire-changes/server@7.139.0.json +348 -0
  325. package/dist/http/device-placement.d.ts +0 -175
  326. package/dist/http/device-placement.js +0 -145
  327. package/dist/http/mcp-remote-text.d.ts +0 -5
  328. package/dist/http/mcp-remote-text.js +0 -7
@@ -3,8 +3,8 @@ import { z } from "zod";
3
3
  import { applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, isValidDurableScope, parseRuleText, readRowBehavior, screenRuleSyncState, PERMISSION_RULE_WRITER, RULE_ADD_ORIGINS, RULE_APPROVAL_KINDS, RULE_APPROVAL_RECORD_SCHEMA, RULE_APPROVAL_STATES, RULE_BEHAVIORS, RULE_SYNC_DROP_CODES, EDITED_RULE_BREADTH_WARNING_CODES, PERSISTED_RULE_MATCHES, EMPTY_DURABLE_RULE_PARTITION, PERMISSION_RULES_LATER_GRAMMAR_CODE, SESSION_RULES_GRAMMAR, readRuleGrammarStamp, readRuleOwner, principalNameOf, readRuleOffer2, } from "@sema-agent/core";
4
4
  import { dialectProtocolJsonEncoder, sqlDbNowMs, SQL_DB_NOW_MS } from "./sql-driver.js";
5
5
  import { isMissingColumnError } from "./sql-errors.js";
6
+ import { describeProbedTableDrift } from "./schema-drift-sentence.js";
6
7
  import { canonicalJsonStringify } from "@sema-agent/core";
7
- import { isPersistedRuleTool } from "../permission-rule-vocab.js";
8
8
  import { ensureIndexes } from "./ensure-index.js";
9
9
  import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, SqlJsonColumnError } from "./sql-json-column.js";
10
10
  import { redactSecrets } from "../trace/redact.js";
@@ -31,7 +31,7 @@ const PersistedRuleRowSchema = z
31
31
  .object({
32
32
  behavior: z.string().optional(),
33
33
  rule: z.string(),
34
- tool: z.string().min(1).refine(isPersistedRuleTool, { message: "not a tool the persisted-rule grammar speaks for" }),
34
+ tool: z.string().min(1),
35
35
  match: z.enum(PERSISTED_RULE_MATCHES),
36
36
  command: z.string(),
37
37
  scope: DurableRuleScopeSchema,
@@ -145,8 +145,8 @@ export const TIDB_PERMISSION_RULE_STATEMENTS = [
145
145
  -- version:**数据格式版本**(= core \`RuleApprovalRecord.schema\`,本形恒 4 —— core 7.9.0 #625 由 3 升,
146
146
  -- 代码里的单点是 RULE_APPROVAL_RECORD_SCHEMA;OCC 守卫另在 rev,两轴禁混,schema-naming 门③ 白名单
147
147
  -- 登记)。读侧对非 4 的行(含上一形的 3)交还 design/375 §4.5 的
148
- -- StaleRuleApprovalRecord 信封(identity 键 only)—— 本仓 SCHEMA POLICY 是删表重建,重建后的表
149
- -- 不该有这种行,这一臂是「未来再换形」的防御位,绝不静默 widen 成一条本形担保不了的记录。
148
+ -- StaleRuleApprovalRecord 信封(identity 键 only)—— 这一臂是「未来再换形」的防御位,
149
+ -- 绝不静默 widen 成一条本形担保不了的记录。
150
150
  version INT NOT NULL,
151
151
  -- offers_json:core \`RuleOffer2[]\`(design/375 §4.1)—— 按 index 引用 candidates 的 OPTION 结构,
152
152
  -- **绝不存规则文本副本**(显示三元组由 core \`ruleOffersOfRecord\` 从候选文本投影;存副本=造一个
@@ -241,13 +241,11 @@ export async function assertPermissionRuleApprovalSchema(query, dialect) {
241
241
  `#340 card-edit columns (command / edited_json) and the design/375 record-form columns ` +
242
242
  `(version / offers_json / selected_offer): the approval record now stores its OPTION structure and the ` +
243
243
  `chosen offer, and the store refuses to read rows whose record-form version it cannot vouch for. ` +
244
- `This repository ships no ` +
245
- `ALTER TABLE migrations, so the table must be recreated: run \`DROP TABLE ${PERMISSION_RULE_APPROVAL_TABLE};\` on the ` +
246
- `${dialect === "pg" ? "PostgreSQL" : "MySQL-protocol"} backend and restart — the schema is recreated at boot. ` +
247
- `The cost is bounded: this table holds pending/settled approval RECORDS (the audit trail of who said yes to which ` +
248
- `rule), not the rules themselves — persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched. Dropping it ` +
249
- `loses in-flight CC-import previews (re-runnable) and the historical record trail. ` +
250
- `Underlying probe error: ${err instanceof Error ? err.message : String(err)}`);
244
+ `This table holds pending/settled approval RECORDS (the audit trail of who said yes to which ` +
245
+ `rule), not the rules themselves — persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched; ` +
246
+ `an in-place ALTER keeps the record trail.\n` +
247
+ `Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
248
+ (await describeProbedTableDrift(query, dialect, [PERMISSION_RULE_APPROVAL_TABLE])));
251
249
  }
252
250
  }
253
251
  export async function assertPermissionRuleTicketSchema(query, dialect) {
@@ -261,12 +259,10 @@ export async function assertPermissionRuleTicketSchema(query, dialect) {
261
259
  `the #265 A7 three-state redemption columns (MINTED → CLAIMED → SETTLED, the claim generation that fences a superseded ` +
262
260
  `claimant, and the lane binding that keeps cc-import and local-import tickets from being interchangeable): without them a ` +
263
261
  `local-import ticket can be claimed but never settled, so a redemption that already wrote rules to the store answers its ` +
264
- `owner with a retry-later it can never satisfy. This repository ships no ALTER TABLE migrations, so the table must be recreated: run ` +
265
- `\`DROP TABLE ${PERMISSION_RULE_TICKET_TABLE};\` on the ${dialect === "pg" ? "PostgreSQL" : "MySQL-protocol"} backend and ` +
266
- `restart — the schema is recreated at boot. The cost is bounded and small: this table holds minute-TTL single-use import ` +
267
- `tickets (a governance transient that dies on expiry), so dropping it only makes anyone mid-preview re-run prepare; ` +
268
- `persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched. ` +
269
- `Underlying probe error: ${err instanceof Error ? err.message : String(err)}`);
262
+ `owner with a retry-later it can never satisfy. This table holds minute-TTL single-use import ` +
263
+ `tickets (a governance transient that dies on expiry); persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched.\n` +
264
+ `Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
265
+ (await describeProbedTableDrift(query, dialect, [PERMISSION_RULE_TICKET_TABLE])));
270
266
  }
271
267
  }
272
268
  export const PERMISSION_RULE_INDEXES = [
@@ -387,6 +383,19 @@ function decodeBucketRow(ownerKey, row) {
387
383
  const rules = rulesRaw.map((r) => ({ ...r, behavior: readBucketRowBehavior(r.behavior, "rule row", ownerKey) }));
388
384
  const tombstones = tombstonesRaw.map((t) => ({ ...t, behavior: readBucketRowBehavior(t.behavior, "tombstone", ownerKey) }));
389
385
  const quarantined = quarantinedRaw.map((q) => ({ ...q, behavior: readBucketRowBehavior(q.behavior, "quarantined row", ownerKey) }));
386
+ refuseRowsTheValidatorRefuses(ownerKey, rules, tombstones);
387
+ return {
388
+ actor: String(row.actor ?? ""),
389
+ counter: Number(row.counter ?? 0),
390
+ rev: Number(row.rev ?? 0),
391
+ rules,
392
+ tombstones,
393
+ quarantined,
394
+ ...(observedVector !== undefined ? { observedVector } : {}),
395
+ ...(grammar !== undefined ? { grammar } : {}),
396
+ };
397
+ }
398
+ function refuseRowsTheValidatorRefuses(ownerKey, rules, tombstones) {
390
399
  const badTombstone = tombstones.find((t) => {
391
400
  const parsed = parseRuleText(t.rule, t.behavior);
392
401
  return "reject" in parsed || parsed.rule.rule !== t.rule;
@@ -394,21 +403,11 @@ function decodeBucketRow(ownerKey, row) {
394
403
  if (badTombstone !== undefined) {
395
404
  throw new BucketRefusedError(`permission_rule bucket ${ownerKey} carries a tombstone whose rule text the single validator refuses or does not spell canonically`, `(${badTombstone.rule}) — refusing the whole bucket rather than keeping a rule alive under a tombstone that can never match it`);
396
405
  }
397
- const screened = screenRuleSyncState({ rules, tombstones });
406
+ const screened = screenRuleSyncState({ rules: [...rules], tombstones: [...tombstones] });
398
407
  if (screened.rejected.length > 0) {
399
408
  const names = screened.rejected.map((r) => `${r.rule}(${r.reason})`).join(", ");
400
409
  throw new BucketRefusedError(`permission_rule bucket ${ownerKey} carries rows the single validator refuses`, `[${names}] — refusing the whole bucket rather than authorizing a rule whose text and matcher metadata disagree`);
401
410
  }
402
- return {
403
- actor: String(row.actor ?? ""),
404
- counter: Number(row.counter ?? 0),
405
- rev: Number(row.rev ?? 0),
406
- rules,
407
- tombstones,
408
- quarantined,
409
- ...(observedVector !== undefined ? { observedVector } : {}),
410
- ...(grammar !== undefined ? { grammar } : {}),
411
- };
412
411
  }
413
412
  function fencedCasWhere(dialect, firstPlaceholder, ownerKey, cas) {
414
413
  const ph = (offset) => (dialect === "tidb" ? "?" : `$${firstPlaceholder + offset}`);
@@ -422,6 +421,12 @@ async function writeBucket(exec, dialect, ownerKey, cur, next, nowMs) {
422
421
  if (!writable.success) {
423
422
  throw new Error(`refusing to write a permission_rule bucket this backend could not read back: ${writable.error.message}`);
424
423
  }
424
+ try {
425
+ refuseRowsTheValidatorRefuses(ownerKey, next.rules, next.tombstones);
426
+ }
427
+ catch (e) {
428
+ throw new Error(`refusing to write a permission_rule bucket this backend could not read back: ${e.message}`);
429
+ }
425
430
  const body = { rules: next.rules, tombstones: next.tombstones, quarantined: cur.quarantined, ...(cur.observedVector !== undefined ? { observedVector: cur.observedVector } : {}) };
426
431
  const enc = dialectProtocolJsonEncoder(dialect);
427
432
  const where = fencedCasWhere(dialect, 7, ownerKey, { column: "rev", expected: cur.rev });
@@ -529,7 +534,7 @@ class SqlDurableRulePartition {
529
534
  },
530
535
  apply: async (delta, opts) => {
531
536
  if (delta.kind === "sync-join") {
532
- throw new Error("the SQL permission-rule backend does not implement the sync-join landing pipeline (core's applySyncJoin is not on the package's public export face); " +
537
+ throw new Error("the SQL permission-rule backend does not implement the sync-join landing arm; " +
533
538
  "no sync client is wired in this deployment, so this arm has no caller — see permission-rule-store-sql.ts header");
534
539
  }
535
540
  assertWriteDeltaScopeDurable(delta);
@@ -10,9 +10,13 @@
10
10
  * (run-store + checkpoint); the remaining tidb-* tables are added as their PG stores land (tracked).
11
11
  *
12
12
  * ─────────────────────────────── SCHEMA POLICY (clay 裁 2026-07-26) ───────────────────────────────
13
- * THIS CODE IS THE SINGLE SOURCE OF TRUTH for the PG schema. The stack is not yet in production and runs
14
- * against a single local operator's database, so a schema change is DROP-AND-RECREATE (drop the database,
15
- * boot, `ensurePgSchema` rebuilds it) — NOT an in-place migration.
13
+ * THIS CODE IS THE SINGLE SOURCE OF TRUTH for the PG schema, and there is NO in-place migration seam in this statement array: a database that
14
+ * lags behind the code is refused at boot with the exact `ALTER TABLE … ADD COLUMN …` statements printed, and the
15
+ * deployer runs them themselves: the column-set check and its refusal never alter a database. The only DDL this
16
+ * process runs by itself on a table that already exists is idempotent index creation (`ensureIndex`: indexes only,
17
+ * never a column) and the registered one-time migrations (each has a window and a registry row in
18
+ * `one-time-migrations.ts`) — adding / changing / renaming a column or dropping a table is done by those migrations
19
+ * and by nothing else.
16
20
  *
17
21
  * Consequence, and it is a hard rule: **do NOT add new `ALTER TABLE` seams here.** Every column / default /
18
22
  * constraint change is folded into its own `CREATE TABLE`, and this array stays pure `CREATE TABLE` +
@@ -1,19 +1,22 @@
1
1
  import { BaseSessionStorage, type AcquiredSession, type PlacedSessionRow, type SessionHead, type SessionMetadata, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry, type SessionWriteOptions } from "@sema-agent/core";
2
2
  import type { Pool, PoolClient } from "pg";
3
3
  import type { SessionSummary } from "./store-contracts.js";
4
- import { type SessionRowPatch } from "../session-row.js";
4
+ import { type ClientSessionRowWrite, type ReplaySessionRowWrite, type ReplaySessionRowWriteOutcome, type SessionRowPatch, type SessionRowWriteOutcome } from "../session-row.js";
5
5
  import { type PlacementAcquireOpts } from "./session-placement.js";
6
6
  import { type OrphanOwnerLog } from "../delegated-session-owner.js";
7
7
  import { type StagingHandle } from "../session-sync-kernel.js";
8
8
  import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
9
- import { type SessionFace } from "../session-incarnation.js";
9
+ import type { SessionWorkspace } from "../session-workspace.js";
10
+ import type { RetentionDeclaration } from "@sema-agent/core";
10
11
  import { type IndexSpec } from "./ensure-index.js";
12
+ import { type ForkTarget, type ForkToOutcome } from "./session-fork.js";
13
+ import { type ExecutionPlacementSeat } from "../execution-placement.js";
11
14
  /**
12
15
  * PG-dialect DDL for the L1 session log, translated from tidb-pool.ts SCHEMA_STATEMENTS:
13
16
  * JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3), inline `KEY`/`UNIQUE KEY`→separate CREATE INDEX (UNIQUE for uq_session_event_entry).
14
17
  *
15
- * SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are
16
- * drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead.
18
+ * SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, there is no in-place
19
+ * migration, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead.
17
20
  */
18
21
  export declare const PG_SESSION_SCHEMA: string[];
19
22
  /** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensureSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
@@ -55,8 +58,8 @@ export declare class PgSessionStorage extends BaseSessionStorage {
55
58
  */
56
59
  export declare class PgSessionStore implements SessionStore {
57
60
  private readonly pool;
58
- /** [ref] 车1:托管留存声明(TiDB 孪生同格)。读法见 `retention-store-sql.ts` 的 {@link MANAGED_RETENTION}。 */
59
- readonly retention: import("@sema-agent/core").RetentionDeclaration;
61
+ /** 托管留存声明 = 装配交给它的词(TiDB 孪生同格)。读法见 `retention-store-sql.ts` 的 {@link MANAGED_RETENTION}。 */
62
+ readonly retention: RetentionDeclaration;
60
63
  /** [ref] C18(core 5.48.0 [ref]):placement 声明(TiDB 孪生同格,义务逐条见
61
64
  * `src/plugins/session-placement.ts` 顶注)。 */
62
65
  readonly placements: {
@@ -68,8 +71,13 @@ export declare class PgSessionStore implements SessionStore {
68
71
  private readonly pending;
69
72
  /** 委派子代孤行那一行 warn 的去处(TiDB 孪生同格)。 */
70
73
  private readonly log;
74
+ /** 执行席(TiDB 孪生同格;实现与语句的唯一属主 = `execution-placement-sql.ts`,本店只交自己的池)。 */
75
+ readonly executionPlacement: ExecutionPlacementSeat;
76
+ /** 本店的池包成的 SqlDriver(TiDB 孪生同格):执行席与会话行格写原语的事务都经它借连接。 */
77
+ private readonly db;
71
78
  constructor(pool: Pool, opts?: {
72
79
  readonly log?: OrphanOwnerLog;
80
+ readonly retention?: RetentionDeclaration;
73
81
  });
74
82
  acquire(sessionId?: string, opts?: PlacementAcquireOpts): Promise<AcquiredSession>;
75
83
  private load;
@@ -118,13 +126,14 @@ export declare class PgSessionStore implements SessionStore {
118
126
  }): Promise<SessionSummary[]>;
119
127
  /** @see TiDBSessionStore.sessionSummaryOf — the PG twin (same projection, run-preview subqueries scoped to the id). */
120
128
  sessionSummaryOf(sessionId: string): Promise<SessionSummary | undefined>;
121
- /** @see TiDBSessionStore.patchSessionMeta — the PG twin (the only writer of a user-set title / pin; the UPDATE and the read-back
122
- * both conditioned on the verified occupant's incarnation; `updated_at` untouched). The read-back is a second statement, not a
123
- * `RETURNING` CTE: the outer SELECT of a data-modifying CTE reads the pre-UPDATE snapshot of `session_meta`. */
124
- patchSessionMeta(sessionId: string, patch: SessionRowPatch, face: SessionFace): Promise<SessionSummary | undefined>;
125
- /** @see TiDBSessionStore.selectSummaries — the PG twin. `where` already carries `$n` placeholders numbered over `params`;
129
+ /** @see TiDBSessionStore.listRowOf — the PG twin. */
130
+ private listRowOf;
131
+ /** @see TiDBSessionStore.writeSessionRowCells — the PG twin (the same SQL half, `session-row-sql.ts`; only the statement text differs). */
132
+ writeSessionRowCells(sessionId: string, cells: SessionRowPatch, how: ClientSessionRowWrite): Promise<SessionRowWriteOutcome<SessionSummary>>;
133
+ writeSessionRowCells(sessionId: string, cells: SessionRowPatch, how: ReplaySessionRowWrite): Promise<ReplaySessionRowWriteOutcome<SessionSummary>>;
134
+ /** @see TiDBSessionStore.selectListRows — the PG twin. `where` already carries `$n` placeholders numbered over `params`;
126
135
  * the run scope and the LIMIT take the next numbers (PG binds by number, so text order does not matter). */
127
- private selectSummaries;
136
+ private selectListRows;
128
137
  /** @see TiDBSessionStore.probeTitle — the PG twin. */
129
138
  probeTitle(sessionId: string): Promise<"none" | "untitled" | "titled">;
130
139
  /** @see TiDBSessionStore.setTitleIfNull — the PG twin (the auto-titler's NULL-only write). */
@@ -135,9 +144,18 @@ export declare class PgSessionStore implements SessionStore {
135
144
  * `query_timeout` rejects AND pg-pool destroys that client, so a lock-stuck baseline write does not keep a pooled
136
145
  * connection). */
137
146
  recordInstructionSource(sessionId: string, expected: InstructionSourceBaseline, source: string | null): Promise<void>;
138
- /** @see TiDBSessionStore.fork — copy the WHOLE durable history (full session_event log, compaction floor bypassed,
139
- * NOT wake's bounded tail) to a NEW uuidv7 session, re-seq dense from 0, ids/parents verbatim, owner=caller. */
147
+ /** @see TiDBSessionStore.readSessionWorkspace — the PG twin (same projection-as-text, same cell owner). */
148
+ readSessionWorkspace(sessionId: string): Promise<SessionWorkspace | undefined>;
149
+ /** @see TiDBSessionStore.recordSessionWorkspace — the PG twin (whole-cell overwrite fenced to the occupant; `pgSafeJsonStringify` + `::jsonb`, like every PG JSON write;
150
+ * the general query surface — the pool-wide `DB_QUERY_TIMEOUT_MS` server-side `statement_timeout` bounds it, no per-call client timer). */
151
+ recordSessionWorkspace(sessionId: string, incarnation: string, workspace: SessionWorkspace): Promise<void>;
152
+ /** @see TiDBSessionStore.fork — core 契约 `fork(sourceId, owner?)` = {@link forkTo} 的投影(新铸 uuidv7 目标,`forkByFreshId`;三店同一只)。 */
140
153
  fork(sourceId: string, owner?: string | null): Promise<string | null>;
154
+ /** @see TiDBSessionStore.forkTo — fork 续写的店契约(PG 孪生逐字同义):目标行 meta 先、主键排他;撞已在 ⇒ 回滚后在新视图读目标按属主与 fork 键分类;
155
+ * 读不到 ⇒ 整笔重跑一次,再不行 ⇒ {@link ForkTargetUnsettledError}。 */
156
+ forkTo(sourceId: string, owner: string | null, target: ForkTarget): Promise<ForkToOutcome | null>;
157
+ /** @see TiDBSessionStore.forkToOnce — 一次尝试(PG 孪生):拷**整份**持久日志(压缩地板绕过,不是 wake 的有界尾),seq 从 0 重铸稠密,id / 父 / 载荷原样。 */
158
+ private forkToOnce;
141
159
  /** @see TiDBSessionStore.exportEntries — 2c session-sync EXPORT: the FULL durable session_event log (compaction floor
142
160
  * bypassed, NOT wake's tail) as `SessionTreeEntry[]`, oldest-first, verbatim. null if the source is unknown. */
143
161
  exportEntries(sessionId: string): Promise<SessionTreeEntry[] | null>;
@@ -155,18 +173,19 @@ export declare class PgSessionStore implements SessionStore {
155
173
  batchSize?: number;
156
174
  }): Promise<AsyncIterable<SessionTreeEntry> | null>;
157
175
  /** @see TiDBSessionStore.importEntries — 2c session-sync IMPORT: core `validateEntriesForImport` gate FIRST (fail-closed),
158
- * then persist its verbatim output (re-seq dense from 0, ids/parents/payload/ts unchanged) in ONE txn with
159
- * session_meta LAST as the commit point; owner = the RE-STAMPED authenticated principal (never the bundle's). */
176
+ * then persist its verbatim output (re-seq dense from 0, ids/parents/payload/ts unchanged) in ONE txn, **lock-or-create, meta first**
177
+ * (读写序律:占行 → 锁行判是不是本次占下的 → 锁定读认领 → 事件);owner = the RE-STAMPED authenticated principal (never the bundle's). */
160
178
  importEntries(sessionId: string, owner: string | null, entries: SessionTreeEntry[]): Promise<void>;
161
179
  /** @see TiDBSessionStore.replaceEntries — 2c (§7/§8) IDEMPOTENT REPLACE: core `validateEntriesForImport` gate FIRST
162
- * (fail-closed), then DELETE events + the owner-guarded meta delete (`owner IS NOT DISTINCT FROM $n` = the PG `<=>`,
163
- * defense-in-depth), then re-insert via the SHARED body (entries + session_meta LAST as the commit point), ALL in
180
+ * (fail-closed), then the owner-guarded meta delete (`owner IS NOT DISTINCT FROM $n` = the PG `<=>`, defense-in-depth), then the
181
+ * SHARED body (session_meta first, the in-txn claim read, then the old events out and the new ones in), ALL in
164
182
  * ONE txn. Safe to run OVER an existing session (fast-forward / §8 retry) — unlike importEntries' fresh-only INSERT. */
165
183
  replaceEntries(sessionId: string, owner: string | null, entries: SessionTreeEntry[]): Promise<void>;
166
- /** @see TiDBSessionStore.insertValidatedLog — shared insert half of importEntries / replaceEntries (ONE source, no
167
- * drift): entries re-seq dense from 0 (ids/parents/payload/ts verbatim), THEN session_meta LAST as the commit point.
184
+ /** @see TiDBSessionStore.writeImportedLog — the shared write half of importEntries / replaceEntries (ONE source, no drift):
185
+ * session_meta FIRST (create = occupy the row, an existing one ⇒ refused; replace = plain INSERT after the caller's owner-guarded
186
+ * delete), the in-txn claim read on THIS connection (读写序律), then the entries re-seq dense from 0 (ids/parents/payload/ts verbatim).
168
187
  * Runs inside the caller's open txn (`conn` already in BEGIN); the caller owns COMMIT/ROLLBACK + the validate gate. */
169
- private insertValidatedLog;
188
+ private writeImportedLog;
170
189
  /** @see TiDBSessionStore.beginImportStaging — 2c P1d-β PUSH staging: stream batches into the shadow id
171
190
  * `${realSessionId}#stg-${token}` (route-minted token), then commit (atomic swap) / abort. */
172
191
  beginImportStaging(realSessionId: string, token: string): StagingHandle;
@@ -180,7 +199,7 @@ export declare class PgSessionStore implements SessionStore {
180
199
  sweepStagingSessions(): Promise<number>;
181
200
  /** @see TiDBSessionStore.deleteSession — purge session_meta + session_event; idempotent (false if absent).
182
201
  * Owner-guarded on session_meta.owner (`IS NOT DISTINCT FROM` = the PG `<=>`); the event purge is gated on the
183
- * owner-matched meta delete (session_event has no owner column). */
202
+ * owner-matched meta delete (session_event has no owner column). A live run claim read inside the txn ⇒ `SessionActiveRunError`. */
184
203
  deleteSession(sessionId: string, owner: string | null): Promise<boolean>;
185
204
  get size(): number;
186
205
  dispose(): void;