@sema-agent/server 7.142.0 → 7.144.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 (301) hide show
  1. package/MIGRATION.md +608 -0
  2. package/USAGE.md +63 -36
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +7 -5
  5. package/dist/approval-ask-audit-store.js +12 -6
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +155 -39
  9. package/dist/approval-card.js +111 -31
  10. package/dist/approval-queue-kind.d.ts +27 -0
  11. package/dist/approval-queue-kind.js +6 -0
  12. package/dist/approval-reconciler.d.ts +8 -8
  13. package/dist/approval-reconciler.js +3 -3
  14. package/dist/audit.js +4 -2
  15. package/dist/boot/budget-tracing.d.ts +1 -1
  16. package/dist/boot/execution-env.js +1 -1
  17. package/dist/boot/governance-seams.d.ts +26 -41
  18. package/dist/boot/governance-seams.js +61 -28
  19. package/dist/boot/late-binds.d.ts +7 -4
  20. package/dist/boot/late-binds.js +3 -1
  21. package/dist/boot/leader.js +2 -4
  22. package/dist/boot/memory-consolidation.d.ts +0 -8
  23. package/dist/boot/memory-consolidation.js +3 -3
  24. package/dist/boot/reapers.js +5 -4
  25. package/dist/boot/resolve-spec.d.ts +1 -1
  26. package/dist/boot/resolve-spec.js +8 -8
  27. package/dist/boot/runner-deps.d.ts +14 -6
  28. package/dist/boot/runner-deps.js +6 -17
  29. package/dist/boot/shutdown.d.ts +9 -0
  30. package/dist/boot/shutdown.js +18 -2
  31. package/dist/boot/stage-01-config.js +2 -0
  32. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  33. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  34. package/dist/boot/stage-03-store-backend.js +1 -2
  35. package/dist/boot/stage-04-stores.d.ts +5 -2
  36. package/dist/boot/stage-04-stores.js +3 -5
  37. package/dist/boot/stage-05-execution-env.d.ts +5 -2
  38. package/dist/boot/stage-06-runners.d.ts +5 -2
  39. package/dist/boot/stage-06-runners.js +1 -3
  40. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  41. package/dist/boot/stage-07-capability-layer.js +6 -2
  42. package/dist/boot/stage-08-reapers.d.ts +5 -2
  43. package/dist/boot/stage-09-leader.d.ts +5 -2
  44. package/dist/boot/stage-10-http-server.d.ts +5 -2
  45. package/dist/boot/stage-10-http-server.js +4 -1
  46. package/dist/boot/stores.d.ts +5 -2
  47. package/dist/boot/stores.js +7 -7
  48. package/dist/boot/web-admin.d.ts +5 -1
  49. package/dist/boot/web-admin.js +31 -19
  50. package/dist/capabilities/hands-lane.d.ts +9 -39
  51. package/dist/capabilities/hands-lane.js +8 -13
  52. package/dist/capabilities/mcp-probe.d.ts +3 -2
  53. package/dist/capabilities/scenarios.d.ts +23 -17
  54. package/dist/capabilities/scenarios.js +2 -2
  55. package/dist/capabilities/skills.d.ts +1 -17
  56. package/dist/capabilities/skills.js +0 -8
  57. package/dist/capability-facts.d.ts +8 -8
  58. package/dist/capability-facts.js +4 -4
  59. package/dist/card-void.d.ts +6 -9
  60. package/dist/config-catalog.js +1 -1
  61. package/dist/config-d-migration.d.ts +2 -0
  62. package/dist/config-dir-trust.js +58 -29
  63. package/dist/config-invariants.d.ts +7 -1
  64. package/dist/config-invariants.js +7 -0
  65. package/dist/config-provider.d.ts +10 -0
  66. package/dist/config-provider.js +15 -4
  67. package/dist/config-root-migration.d.ts +13 -0
  68. package/dist/config-root-migration.js +99 -0
  69. package/dist/config-types.d.ts +5 -5
  70. package/dist/config.d.ts +4 -3
  71. package/dist/config.js +1 -1
  72. package/dist/delegated-session-owner.d.ts +35 -151
  73. package/dist/delegated-session-owner.js +1 -83
  74. package/dist/device-ws-protocol.d.ts +1 -0
  75. package/dist/device-ws-protocol.js +2 -1
  76. package/dist/entry-mode-clamp-notice.d.ts +1 -1
  77. package/dist/env-model-table-gate.d.ts +53 -0
  78. package/dist/env-model-table-gate.js +53 -0
  79. package/dist/execution-placement.d.ts +7 -4
  80. package/dist/fleet/fleet-bus.d.ts +28 -52
  81. package/dist/fleet/fleet-bus.js +35 -100
  82. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  83. package/dist/fleet/fleet-reconciler.js +1 -1
  84. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  85. package/dist/fleet/subagent-tail-bus.js +15 -28
  86. package/dist/hooks/classic-stations.d.ts +3 -1
  87. package/dist/hooks/classic-stations.js +2 -0
  88. package/dist/hooks/hook-runner.js +28 -7
  89. package/dist/host-decision.d.ts +54 -20
  90. package/dist/host-decision.js +42 -14
  91. package/dist/http/admission.d.ts +1 -1
  92. package/dist/http/admission.js +7 -3
  93. package/dist/http/approval-sweeps.js +11 -8
  94. package/dist/http/caller-trust.d.ts +1 -1
  95. package/dist/http/durable-run-leg.js +2 -2
  96. package/dist/http/engine-refusal.d.ts +16 -0
  97. package/dist/http/engine-refusal.js +17 -0
  98. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  99. package/dist/http/memory-compliance-failure-reply.js +4 -6
  100. package/dist/http/owner-access.d.ts +11 -0
  101. package/dist/http/owner-access.js +13 -0
  102. package/dist/http/principal-gate.d.ts +1 -1
  103. package/dist/http/refusal-body.d.ts +7 -3
  104. package/dist/http/refusal-body.js +1 -0
  105. package/dist/http/resume-legs.d.ts +21 -7
  106. package/dist/http/resume-legs.js +82 -53
  107. package/dist/http/resume-restatement.d.ts +39 -0
  108. package/dist/http/resume-restatement.js +25 -0
  109. package/dist/http/route-ctx.d.ts +35 -10
  110. package/dist/http/route-ctx.js +1 -1
  111. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  112. package/dist/http/routes/approvals-assistant.js +143 -31
  113. package/dist/http/routes/capabilities.js +11 -2
  114. package/dist/http/routes/memory-policy.d.ts +2 -2
  115. package/dist/http/routes/memory-policy.js +1 -1
  116. package/dist/http/routes/notify-wake.js +23 -25
  117. package/dist/http/routes/rules.js +48 -13
  118. package/dist/http/routes/runs.js +9 -8
  119. package/dist/http/routes/session-memory-sync.d.ts +34 -6
  120. package/dist/http/routes/session-memory-sync.js +27 -10
  121. package/dist/http/routes/session-sync.js +13 -20
  122. package/dist/http/routes/sessions.d.ts +2 -2
  123. package/dist/http/routes/sessions.js +22 -23
  124. package/dist/http/routes/tasks.js +27 -49
  125. package/dist/http/server.d.ts +13 -7
  126. package/dist/http/server.js +2 -2
  127. package/dist/http/stored-body-replay.js +15 -4
  128. package/dist/http/wire-types.d.ts +17 -7
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js +1 -0
  131. package/dist/lane-home-probe.d.ts +15 -0
  132. package/dist/lane-home-probe.js +4 -0
  133. package/dist/leader/leader.js +5 -2
  134. package/dist/leader/wire.d.ts +7 -1
  135. package/dist/leader/wire.js +6 -5
  136. package/dist/leg-facts.d.ts +37 -0
  137. package/dist/leg-facts.js +15 -0
  138. package/dist/memory-bundle-engine.d.ts +1 -4
  139. package/dist/memory-bundle-engine.js +2 -2
  140. package/dist/memory-operator-faces.d.ts +30 -66
  141. package/dist/memory-operator-faces.js +17 -88
  142. package/dist/memory-scope-stores.d.ts +38 -40
  143. package/dist/memory-scope-stores.js +51 -36
  144. package/dist/memory-scope.d.ts +0 -9
  145. package/dist/memory-scope.js +0 -9
  146. package/dist/memory-sync-client.js +14 -3
  147. package/dist/memory-sync.d.ts +20 -4
  148. package/dist/memory-sync.js +23 -4
  149. package/dist/model-plane-face.d.ts +13 -7
  150. package/dist/model-plane-face.js +2 -1
  151. package/dist/observability/corrupt-read-seat.d.ts +5 -9
  152. package/dist/observability/corrupt-read-seat.js +1 -2
  153. package/dist/observability/fail-open.d.ts +30 -10
  154. package/dist/observability/fail-open.js +27 -10
  155. package/dist/observability/run-terminal.d.ts +1 -1
  156. package/dist/observability/run-terminal.js +6 -2
  157. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  158. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  159. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  160. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  161. package/dist/orchestration/workflow-park-decision.js +5 -3
  162. package/dist/org-delivery-gate.d.ts +11 -0
  163. package/dist/org-delivery-gate.js +19 -1
  164. package/dist/parked-decide.d.ts +13 -9
  165. package/dist/parked-decide.js +7 -7
  166. package/dist/parked-revive-surface.d.ts +6 -7
  167. package/dist/parked-revive-surface.js +1 -1
  168. package/dist/peer-inbound-face.d.ts +122 -0
  169. package/dist/peer-inbound-face.js +123 -0
  170. package/dist/permission-rule-list.d.ts +13 -9
  171. package/dist/permission-rule-list.js +7 -3
  172. package/dist/plugins/approval-ask-store-file.js +18 -6
  173. package/dist/plugins/approval-ask-store-memory.js +8 -6
  174. package/dist/plugins/approval-ask-store-sql.d.ts +28 -13
  175. package/dist/plugins/approval-ask-store-sql.js +30 -11
  176. package/dist/plugins/caching-session-store.d.ts +0 -3
  177. package/dist/plugins/caching-session-store.js +0 -3
  178. package/dist/plugins/checkpoint-store-sql.d.ts +45 -38
  179. package/dist/plugins/checkpoint-store-sql.js +108 -45
  180. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  181. package/dist/plugins/file-history-store-sql.js +24 -19
  182. package/dist/plugins/file-run-store.d.ts +29 -0
  183. package/dist/plugins/file-run-store.js +97 -8
  184. package/dist/plugins/fork-routing-session-store.d.ts +8 -1
  185. package/dist/plugins/fork-routing-session-store.js +6 -0
  186. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  187. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  188. package/dist/plugins/local-checkpoint-store.d.ts +6 -8
  189. package/dist/plugins/local-checkpoint-store.js +5 -4
  190. package/dist/plugins/local-session-store.d.ts +69 -30
  191. package/dist/plugins/local-session-store.js +133 -57
  192. package/dist/plugins/local-session-window.d.ts +4 -2
  193. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  194. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  195. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  196. package/dist/plugins/mailbox-store-sql.js +76 -7
  197. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  198. package/dist/plugins/memory-sync-store-pg.js +21 -0
  199. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  200. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  201. package/dist/plugins/one-time-migrations.d.ts +44 -14
  202. package/dist/plugins/one-time-migrations.js +118 -15
  203. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  204. package/dist/plugins/org-delivery-quota-store.js +2 -12
  205. package/dist/plugins/park-commit-watch.d.ts +1 -1
  206. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  207. package/dist/plugins/permission-rule-store-file.js +15 -2
  208. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  209. package/dist/plugins/permission-rule-store-sql.js +35 -2
  210. package/dist/plugins/pg-session-storage.d.ts +1 -9
  211. package/dist/plugins/pg-session-storage.js +2 -19
  212. package/dist/plugins/remote-env-device.d.ts +8 -11
  213. package/dist/plugins/remote-env-device.js +6 -3
  214. package/dist/plugins/remote-env-host.d.ts +8 -4
  215. package/dist/plugins/remote-env-host.js +7 -9
  216. package/dist/plugins/remote-env-k8s.d.ts +37 -24
  217. package/dist/plugins/remote-env-k8s.js +50 -17
  218. package/dist/plugins/remote-shell.js +12 -2
  219. package/dist/plugins/retention-store-sql.d.ts +2 -2
  220. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  221. package/dist/plugins/sandbox-read-floor.js +2 -7
  222. package/dist/plugins/schema-consistency.d.ts +5 -1
  223. package/dist/plugins/session-fork.d.ts +1 -1
  224. package/dist/plugins/session-ownership.d.ts +9 -0
  225. package/dist/plugins/session-ownership.js +6 -0
  226. package/dist/plugins/session-store.d.ts +13 -16
  227. package/dist/plugins/session-store.js +9 -10
  228. package/dist/plugins/sql-errors.d.ts +10 -1
  229. package/dist/plugins/sql-errors.js +13 -0
  230. package/dist/plugins/sql-json-column.d.ts +24 -2
  231. package/dist/plugins/sql-json-column.js +38 -3
  232. package/dist/plugins/store-backend.d.ts +23 -28
  233. package/dist/plugins/store-backend.js +12 -3
  234. package/dist/plugins/store-contracts.d.ts +29 -5
  235. package/dist/plugins/store-contracts.js +4 -1
  236. package/dist/plugins/task-attachment-store.d.ts +2 -2
  237. package/dist/plugins/task-attachment-store.js +37 -52
  238. package/dist/plugins/tidb-session-store.d.ts +2 -14
  239. package/dist/plugins/tidb-session-store.js +2 -20
  240. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  241. package/dist/plugins/tool-result-store-sql.js +23 -2
  242. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  243. package/dist/plugins/wiring-section-codec.js +55 -0
  244. package/dist/plugins/workspace-fill.d.ts +1 -1
  245. package/dist/rule-entry-list.d.ts +3 -2
  246. package/dist/rule-entry-list.js +5 -1
  247. package/dist/rules-consent.d.ts +28 -5
  248. package/dist/rules-consent.js +40 -28
  249. package/dist/run-local.js +11 -6
  250. package/dist/runs.d.ts +12 -8
  251. package/dist/runs.js +10 -7
  252. package/dist/runtime-governance.d.ts +1 -1
  253. package/dist/security.d.ts +0 -4
  254. package/dist/server-secret-env.d.ts +4 -0
  255. package/dist/session-error-wire.d.ts +34 -23
  256. package/dist/session-error-wire.js +8 -3
  257. package/dist/session-incarnation.d.ts +3 -3
  258. package/dist/session-notify-door.d.ts +106 -0
  259. package/dist/session-notify-door.js +97 -0
  260. package/dist/session-sync.d.ts +9 -14
  261. package/dist/session-sync.js +5 -5
  262. package/dist/session-workspace.d.ts +3 -13
  263. package/dist/session-workspace.js +0 -9
  264. package/dist/standing-answer-grant.d.ts +5 -0
  265. package/dist/standing-answer-grant.js +10 -0
  266. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  267. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  268. package/dist/task-mcp.d.ts +1 -1
  269. package/dist/task-settings.d.ts +11 -8
  270. package/dist/task-settings.js +31 -11
  271. package/dist/tool-approval.d.ts +55 -35
  272. package/dist/tool-approval.js +112 -74
  273. package/dist/trace/core-keyset-guard.d.ts +12 -9
  274. package/dist/trace/engine-notice-wire.d.ts +1 -1
  275. package/dist/trace/engine-notice-wire.js +4 -2
  276. package/dist/trace/exit-seat.d.ts +7 -1
  277. package/dist/trace/exit-seat.js +1 -0
  278. package/dist/trace/ledger-sink.d.ts +2 -2
  279. package/dist/trace/ledger-sink.js +12 -4
  280. package/dist/trace/model-segment.d.ts +74 -25
  281. package/dist/trace/model-segment.js +141 -32
  282. package/dist/trace/project.d.ts +15 -6
  283. package/dist/trace/project.js +12 -4
  284. package/dist/trace/redact.d.ts +72 -9
  285. package/dist/trace/redact.js +1509 -471
  286. package/dist/trace/self-minted-wire.d.ts +598 -47
  287. package/dist/trace/self-minted-wire.js +190 -20
  288. package/dist/trace/wire-projection-faces.d.ts +1 -1
  289. package/dist/trace/wire-projection-faces.js +1 -1
  290. package/dist/verifier-pause-card.d.ts +33 -5
  291. package/dist/verifier-pause-card.js +15 -10
  292. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  293. package/dist/web-admin-client/apply-effective.js +90 -10
  294. package/dist/workspace-space.d.ts +19 -3
  295. package/dist/workspace-space.js +8 -4
  296. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  297. package/package.json +3 -2
  298. package/wire-changes/server@7.143.0.json +1167 -0
  299. package/wire-changes/server@7.144.0.json +291 -0
  300. package/dist/session-records-skipped-notice.d.ts +0 -21
  301. package/dist/session-records-skipped-notice.js +0 -27
@@ -9,7 +9,7 @@ import { ensureIndexes } from "./ensure-index.js";
9
9
  import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, isJsonColumnBodyProblem, jsonColumnText, jsonColumnTextExpr, readNonNullJsonValueColumn, readOpaqueJsonValueColumn, } from "./sql-json-column.js";
10
10
  import { incarnationFromCell, sessionFaceFromRow } from "../session-incarnation.js";
11
11
  import { RUN_HOLDER_DEATH_CODES, RUN_ORPHANED_ERROR, RUN_STALLED_ERROR, StoreBootRefusalError } from "./store-contracts.js";
12
- import { PERMISSION_RULE_TABLE, purgeUndurableScopeRows } from "./permission-rule-store-sql.js";
12
+ import { PERMISSION_RULE_TABLE, SqlDurableRulePartitionProvider, isSqlBucketRefusal, isSqlBucketVanished, listRuleBucketOwners, purgeUndurableScopeRows } from "./permission-rule-store-sql.js";
13
13
  import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
14
14
  import { readJsonObjectColumn } from "./sql-json-column.js";
15
15
  import { retireStoredCardWords } from "../retired-card-words.js";
@@ -18,6 +18,7 @@ import { CLAIM_OWNERLESS_PLACED_SQL, claimOwnerlessParams, isOrphanSessionOwner,
18
18
  import { MAILBOX_KEYED_TABLES, mailboxKeyDeleteSql, storedMailboxKeyless } from "./mailbox-store-sql.js";
19
19
  import { SESSION_META_PLACEMENT_COLUMNS, backfillWriterStatement, countOrphanBindingsStatement, migrateDeviceBindingsStatement } from "./execution-placement-sql.js";
20
20
  import { APPROVAL_ASK_ENDING_CAUSE_COLUMN, APPROVAL_ASK_EXECUTION_LANE_COLUMN, APPROVAL_ASK_PARK_TRIGGER_COLUMN, APPROVAL_ASK_TABLE } from "./approval-ask-store-sql.js";
21
+ import { retireImportedLayerRootAllows } from "./imported-layer-root-retirement.js";
21
22
  import { isUnusableArchive } from "../execution-placement.js";
22
23
  const RETIRED_SESSION_RULE_BUCKETS = ["commandAllow", "commandDeny"];
23
24
  export function buildMigrationReceipts() {
@@ -63,6 +64,8 @@ export function buildMigrationReceipts() {
63
64
  askCauseColumnsChanged: 0,
64
65
  askParkTriggersMoved: 0,
65
66
  askJournalRecordsUpgraded: 0,
67
+ importedLayerRootAllowsRetired: [],
68
+ importedLayerRootBucketsSkipped: [],
66
69
  };
67
70
  }
68
71
  function completedReport(r) {
@@ -116,7 +119,9 @@ function changedAnything(r) {
116
119
  r.localArchiveSnapshotsRecovered > 0 ||
117
120
  r.askCauseColumnsChanged > 0 ||
118
121
  r.askParkTriggersMoved > 0 ||
119
- r.askJournalRecordsUpgraded > 0);
122
+ r.askJournalRecordsUpgraded > 0 ||
123
+ r.importedLayerRootAllowsRetired.length > 0 ||
124
+ r.importedLayerRootBucketsSkipped.length > 0);
120
125
  }
121
126
  function readingsSnapshot(r) {
122
127
  return {
@@ -131,6 +136,8 @@ function readingsSnapshot(r) {
131
136
  executionPlacementSessionsUnreadable: [...r.executionPlacementSessionsUnreadable],
132
137
  localArchivesKeptStamped: [...r.localArchivesKeptStamped],
133
138
  localArchivesUnreadable: [...r.localArchivesUnreadable],
139
+ importedLayerRootAllowsRetired: [...r.importedLayerRootAllowsRetired],
140
+ importedLayerRootBucketsSkipped: [...r.importedLayerRootBucketsSkipped],
134
141
  };
135
142
  }
136
143
  function receiptSentence(r) {
@@ -141,6 +148,7 @@ function receiptSentence(r) {
141
148
  ...r.undurableScopeRuleRows.map((x) => `removed ${x.kind} in permission-rule bucket ${x.ownerKey} (${x.behavior} ${x.tool}, scope root ${JSON.stringify(x.scopeRoot)})`),
142
149
  ...r.sessionRuleRowsWithOldGrammarEntries.map((x) => `${x.policyKey} (session ${x.sessionId}): toolAllowDropped=${JSON.stringify(x.toolAllowDropped)}`),
143
150
  ...r.sessionRuleRowsWithUnreadableDeny.map((x) => `${x.policyKey} (session ${x.sessionId}): left as stored, toolDenyUnreadable=${JSON.stringify(x.toolDenyUnreadable)}${x.retiredBuckets !== undefined ? `, retiredBuckets=${JSON.stringify(x.retiredBuckets)}` : ""}`),
151
+ ...r.importedLayerRootAllowsRetired.map((x) => `retired ${x.addsRetired} imported add(s) of an allow ${x.tool} rule in permission-rule bucket ${x.ownerKey} (${x.stillLive ? "the rule stays in effect through another approval" : "the rule no longer takes effect"})`),
144
152
  ];
145
153
  return [counts.join(", "), ...rows].filter((part) => part !== "").join("; ");
146
154
  }
@@ -396,17 +404,17 @@ export const ONE_TIME_MIGRATIONS = [
396
404
  introducedIn: "7.133.0",
397
405
  releasedOn: "2026-10-21",
398
406
  removableAfter: "2026-11-20",
399
- removal: "删 migrateOn 的 M23 步(`inheritPlacedSessionOwners`:placed ∧ 属主 NULL 的行按 session_id 键集分页单趟扫描 + 同一条语句连读根 / 父两行 + 按认领句回写属主)与 `PLACED_OWNER_SCAN_PAGE` / `placedOwnerScanSql` / `scannedPlacement` / `scannedFaces` / `scannedPlacedSources`(`isOrphanSessionOwner` 若再无别的读者一并删);" +
400
- "**同窗同删的另一半**(认领:按律给升级前写下的无主子代行写属主 —— 停驻挂点对宿主无主行做的就是本条对那一行的单行步):`delegated-session-owner.ts` 的 `CLAIM_OWNERLESS_PLACED_SQL` / `claimOwnerlessParams` / `OwnerlessClaim` / " +
401
- "`settleDelegatedOwner` 的认领一步(删后它只剩树比对与属主比对)/ `DelegationTreeStore.claimOwnerless`," +
402
- "两只 SQL 店(`tidb-session-store.ts` / `pg-session-storage.ts`)与 local 店(`local-session-store.ts` 的 `claimOwnerless` 字段与 `claimOwnerlessPlaced`)的 `claimOwnerless`、`CachingSessionStore` 的转发、`OwnerAwareSessionStore.claimOwnerless`、`delegatedOwnerHostOf` 对它的「与 `placementOf` 同在或同缺」;" +
407
+ removal: "删 migrateOn 的 M23 步(`inheritPlacedSessionOwners`:placed ∧ 属主 NULL 的行按 session_id 键集分页单趟扫描 + 同一条语句连读根 / 父两行 + 按认领句回写属主)与 `PLACED_OWNER_SCAN_PAGE` / `placedOwnerScanSql` / `scannedPlacement` / `scannedFaces` / `scannedPlacedSources`;" +
408
+ "**同窗同删的另一半**(旧律的判据与写句 —— 7.144.0 起建行与停驻挂点都不再读它们,M23 是唯一读者):`delegated-session-owner.ts` 头注 M23 一节与 `judgeDelegatedOwner` / `inheritedOwnerOf` / `ownerSourcesOf` / " +
409
+ "`orphanSessionOwner` / `isOrphanSessionOwner` / `SourceOwnerReading` / `InheritedOwner` / `PlacementSources` / `CLAIM_OWNERLESS_PLACED_SQL` / `claimOwnerlessParams`;" +
403
410
  "报告、日志行与 `NO_SQL_MIGRATIONS` 的 `placedSessionOwnersInherited` / `placedSessionOwnersOrphaned` / `placedSessionOwnersRemaining` 与 `placed_session_owners_orphaned` 那一行 warn;" +
404
411
  "`test/one-time-migrations.test.ts` 的 M23 组与 `test/one-time-migrations-db-integration.test.ts` 的 M23 格。" +
405
- "**不随本条删**:属主为 NULL 的 placed 行只对 fleet 调用方放行(`security.ts` 的 `ownerlessRowOpen` / `sessionOwnerCellOf` 与各门读 `placementOf` 的那一次)—— 那是常设的读面律",
412
+ "**不随本条删**:`ORPHAN_SESSION_OWNER_PREFIX` 与它在 `security.ts` 保留主体前缀里的登记(已落库的行可能带哨兵,永久保留);" +
413
+ "属主为 NULL 的 placed 行只对 fleet 调用方放行(`security.ts` 的 `ownerlessRowOpen` / `sessionOwnerCellOf` 与各门读 `placementOf` 的那一次)—— 那是常设的读面律",
406
414
  afterRemoval: "会话面的读面律(常设,不随本条删)接住:跳过了带本条的版本直接升的库里,属主为 NULL 的存量 placed 子代行只对 fleet 调用方放行(出示 service 凭据、不报主体;dev-open)," +
407
415
  "其余调用方答 404(与别人的行同体)—— 出路是升级时先过一次带本条的版本,或运维按 `placement_root_session_id`(缺则 `placement_parent_session_id`)那一行的属主手工回填、" +
408
- "推不出的写一个任何主体都不匹配的值;停驻挂点读到无主的宿主子代行 ⇒ 回到比对的既有臂:无主 ≠ 律给的属主 ⇒ 停驻否决(fail-closed,响亮;出路同上);" +
409
- "建行那一笔的继承律不随本条删(那是常设的写法,不是迁移)",
416
+ "推不出的写一个任何主体都不匹配的值;停驻挂点只比对宿主行属主与引擎交来的属主(复活腿交那一行自己的属主),不写无主行;" +
417
+ "建行那一笔记 `placement.owner` 不随本条删(那是常设的写法 —— core 盒义务 7,不是迁移)",
410
418
  reportKeys: ["placedSessionOwnersInherited", "placedSessionOwnersOrphaned", "placedSessionOwnersRemaining"],
411
419
  },
412
420
  {
@@ -563,7 +571,7 @@ export const ONE_TIME_MIGRATIONS = [
563
571
  "`local_archive_kept_stamped` / `local_archive_unreadable` 两行 warn、读数行 note 里的 M33 句与头注 M33 段;`test/local-archive-owner.test.ts` 里标题含 `P3` / `P4` / `P5` / `P6` / `F1` / `F2` / `F3` 的格与 `legacyRoot` / `writeArchive` / `boot` / `M33_ZERO` / `m33Of` 助手。" +
564
572
  "**不随本条删**:行格的 `createdAt` / `forkedFrom` 两键(常设的数据形)、`LocalArchiveSnapshotsPresentError` / `assertNoArchiveSnapshots` / `LOCAL_ARCHIVE_SNAPSHOT_DIR` 与 `LocalBackend.ensureSchema` 里调它的那一句、" +
565
573
  "`session-error-wire.ts` 的 `StampedSessionArchiveError` / `STAMPED_SESSION_ARCHIVE_SENTENCE` / `sessionErrorWireOf` 与本店两处带戳判(fork 的源、改日志推送的落点)、行上缺建档时刻的 F 类读法(`server.local-session-row.created-at-absent`)",
566
- afterRemoval: "三只常设臂接住:① 数据根下的快照目录非空 ⇒ 拒启(`config.local_archive_snapshot_present`,点名文件与两条出路);② 跳过了带本条的版本直接升的数据根(或本条留着的存档),带属主戳的存档被 fork 与改日志的推送同一只具名拒(409 `conflict` + 固定句,零写 / 行格净零写)," +
574
+ afterRemoval: "三只常设臂接住:① 数据根下的快照目录非空 ⇒ 拒启(`config.local_archive_snapshot_present`,点名文件与两条出路);② 跳过了带本条的版本直接升的数据根(或本条留着的存档),带属主戳的存档被 fork 与改日志的推送同一只具名拒(409 `conflict.session_archive_stamped` + 固定句,零写 / 行格净零写)," +
567
575
  "读 / 续跑 / 拉取照常 —— 出路 = 删掉会话后重推,或升级时先过一次带本条的版本并在窗内起服;③ 行上没有建档时刻的格(同一类数据根)⇒ 列表 / 会话视图 / 交出的元数据读纪元(F 类 tag 计数)",
568
576
  reportKeys: ["localArchiveRowFactsBackfilled", "localArchivesAnonymized", "localArchivesKeptStamped", "localArchivesUnreadable", "localArchiveSnapshotsRecovered"],
569
577
  },
@@ -583,6 +591,47 @@ export const ONE_TIME_MIGRATIONS = [
583
591
  "② local —— 信封号 1 的日志记录走 File 问账店「认不出的信封号」拒启(`unknown envelope version`,点名文件与出路:用写下它的那一版起服一次,或移开文件)",
584
592
  reportKeys: ["askCauseColumnsChanged", "askParkTriggersMoved", "askJournalRecordsUpgraded"],
585
593
  },
594
+ {
595
+ id: "M35",
596
+ introducedIn: "7.143.0",
597
+ releasedOn: "2026-10-31",
598
+ removableAfter: "2026-11-30",
599
+ removal: "删 `config-root-migration.ts` 整只文件与两个入口的调用(`boot/stage-02-web-admin-pull.ts` 目录信任判官之后、`run-local.ts` 同一位置各两行 + import);" +
600
+ "`test/env-model-table-gate.test.ts` 里标题以 `迁移` 起头的那一组;部署文档里「起服自动铸 config.env-models.json」那一句。" +
601
+ "**不随本条删**:模型面闸 `env-model-table-gate.ts`、`LocalConfigProvider` 读决定(etag 覆盖)、目录信任判官的根级文档名单(常设)",
602
+ afterRemoval: "常设的模型面闸接住:跳过了带本条的版本直接升的本地根(或运行记录在场而决定缺席的根),决定缺席读作 kept ⇒ env 模型表已声明时管模型面的本地目录被组拒 " +
603
+ "`config.catalog_replaces_env_models`,拒句点名被顶替的 env 模型与两条出路(在配置根写 `config.env-models.json` = `{\"envModels\":\"replaced\"}`,或撤掉 MODEL_ID / MODEL_CHEAP_ID)",
604
+ reportKeys: [],
605
+ },
606
+ {
607
+ id: "M36",
608
+ introducedIn: "7.143.0",
609
+ releasedOn: "2026-10-31",
610
+ removableAfter: "2026-11-30",
611
+ removal: "**删码前提**:本服务已不支持回滚到引擎 7.61.0 之前的版本(更早的引擎的导入门会重新铸出这种 add,本条要在每次起服把它们收掉)—— 窗关时仍支持这种回滚 ⇒ 本行两格顺延(改日期,并在本注里写明为什么),不删。" +
612
+ "删什么:`src/plugins/imported-layer-root-retirement.ts` 整个文件;migrateStepsOn 的 M36 步(规则表与 `grammar` 列的在场探针 + 对 `retireImportedLayerRootAllows` 的调用)与握锁连接上的 `query` 口" +
613
+ "(`LockedMigrationDb` 与 `mysqlDb` / `pgDb` 里的那一员,若届时再无别的步骤用它);`permission-rule-store-sql.ts` 的 `listRuleBucketOwners` / `isSqlBucketRefusal` / `isSqlBucketVanished` / `RuleBucketVanishedError`(取点那一句的具名类,届时若再无别的读者按类判它,收回成裸错)/ `IMPORT_RECORD_KIND`;" +
614
+ "`permission-rule-store-file.ts` 的 `FileRuleApprovalRecordStore.importRecordOwners`;`store-backend.ts` 的 `LocalBackend.runOneTimeMigrations` 里 M36 那一腿(规则目录在场判与那一处调用)与报告两键的那两行;" +
615
+ "本文件的 `createSqlImportedLayerRootSource` 与 `importedLayerRootAllowsRetired` / `importedLayerRootBucketsSkipped`(报告 / 收据 / `changedAnything` / `readingsSnapshot` / `readingFields` / `receiptSentence` / `NO_SQL_MIGRATIONS` 的排除表)、" +
616
+ "`imported_layer_root_allow_retired` / `imported_layer_root_bucket_skipped` 两行 warn 与 `importedLayerRootSkipNote`、读数行 note 里的 M36 句与头注 M36 段;" +
617
+ "`test/imported-layer-root-retirement.test.ts`、`test/imported-layer-root-retirement-db-integration.test.ts`(连同 `scripts/db-integration-files.json` 里它那一行)与 `test/helpers/imported-layer-root-fixture.ts` 整文件。" +
618
+ "**不随本条删**:`SqlDurableRulePartitionProvider` 收「方言 + 执行口」的那一形(`BucketSql`;常设,池照旧满足它)",
619
+ afterRemoval: "没有响亮臂(如实):删码之后,跳过了带本条的版本直接升的库(或回滚到引擎 7.61.0 之前、在其上又导入过的库),存量的这种全局 `/x` allow 照旧在每个项目根放行,本服务不再点名 —— " +
620
+ "出路 = 升级时先过一次带本条的版本并起服;或运维列出桶里出处为导入(`adds[].origin` = `imported-cc`)、scope 为全局、从 `/` 写起的 allow(`GET /v1/rules`)并撤掉(`DELETE /v1/rules`,撤的是这条规则的全部批准)",
621
+ reportKeys: ["importedLayerRootAllowsRetired", "importedLayerRootBucketsSkipped"],
622
+ },
623
+ {
624
+ id: "M37",
625
+ introducedIn: "7.143.0",
626
+ releasedOn: "2026-10-31",
627
+ removableAfter: "2026-11-30",
628
+ removal: "删 `approval-card.ts` 的 `renameRetiredSourceKey` 与 `readStoredCardEnvelope` 里调它的那一步(回到直接把传入的那一只交 M18 改写)、" +
629
+ "fail-open tag `server.approval-card.retired-card-key-read`(`observability/fail-open.ts` 与 `docs/FAIL-OPEN-CENSUS.md` 那一行)、" +
630
+ "`test/approval-card-source-key-m37.test.ts` 整只文件、本文件头注 M37 段",
631
+ afterRemoval: "既有坏行臂接住(响亮,不再改名):仍带旧键的存卡(跳过了带本条的版本直接升的库、窗关之后还在写的 7.142.x 副本)整卡读不出 —— 断连重放跳过 + 一次 warn、" +
632
+ "幂等重入走 park、回决口按要人",
633
+ reportKeys: [],
634
+ },
586
635
  ];
587
636
  export function migrationWindowOpen(window, today) {
588
637
  return window.removableAfter === null || today <= window.removableAfter;
@@ -633,6 +682,10 @@ export const NO_SQL_MIGRATIONS = {
633
682
  };
634
683
  function mysqlDb(conn) {
635
684
  return {
685
+ async query(sql, params) {
686
+ const [r] = await conn.query(sql, params === undefined ? [] : [...params]);
687
+ return Array.isArray(r) ? { rows: r, affected: 0 } : { rows: [], affected: Number(r.affectedRows ?? 0) };
688
+ },
636
689
  async rows(sql, params) {
637
690
  const [rows] = params === undefined ? await conn.query(sql) : await conn.query(sql, [...params]);
638
691
  return rows;
@@ -645,6 +698,10 @@ function mysqlDb(conn) {
645
698
  }
646
699
  function pgDb(client) {
647
700
  return {
701
+ async query(sql, params) {
702
+ const r = await client.query(sql, params === undefined ? [] : [...params]);
703
+ return { rows: r.rows, affected: r.rowCount ?? 0 };
704
+ },
648
705
  async rows(sql, params) {
649
706
  const r = params === undefined ? await client.query(sql) : await client.query(sql, [...params]);
650
707
  return r.rows;
@@ -675,6 +732,9 @@ async function columnExists(db, dialect, table, column) {
675
732
  const sql = `SELECT 1 AS present FROM information_schema.columns WHERE table_schema = ${scope} AND table_name = '${table}' AND column_name = '${column}'`;
676
733
  return (await db.rows(sql)).length > 0;
677
734
  }
735
+ export function createSqlImportedLayerRootSource(exec) {
736
+ return { candidateOwners: () => listRuleBucketOwners(exec), durable: new SqlDurableRulePartitionProvider(exec), isWholeBucketRefusal: isSqlBucketRefusal, isVanishedBucket: isSqlBucketVanished };
737
+ }
678
738
  export async function runSqlOneTimeMigrations(dialect, pool, input) {
679
739
  return dialect === "mysql" ? withMysqlLock(pool, (db) => migrateOn(db, "mysql", input)) : withPgLock(pool, (db) => migrateOn(db, "pg", input));
680
740
  }
@@ -734,6 +794,9 @@ async function migrateStepsOn(db, dialect, receipts, input) {
734
794
  await inheritPlacedSessionOwners(db, dialect, receipts);
735
795
  if ((await tableExists(db, dialect, PERMISSION_RULE_TABLE)) && (await columnExists(db, dialect, PERMISSION_RULE_TABLE, "grammar")))
736
796
  await purgeUndurableScopeRows(db, dialect, receipts);
797
+ if ((await tableExists(db, dialect, PERMISSION_RULE_TABLE)) && (await columnExists(db, dialect, PERMISSION_RULE_TABLE, "grammar"))) {
798
+ await retireImportedLayerRootAllows(createSqlImportedLayerRootSource({ dialect, query: (sql, params) => db.query(sql, params) }), receipts);
799
+ }
737
800
  await moveWorkflowJournalScope(db, dialect, receipts);
738
801
  if (await tableExists(db, dialect, RETIRED_BREAKER_TABLE))
739
802
  await dropRetiredBreakerTable(db, dialect, receipts);
@@ -1624,10 +1687,10 @@ export async function inheritPlacedSessionOwners(db, dialect, receipts) {
1624
1687
  const sessionId = String(r.session_id);
1625
1688
  after = sessionId;
1626
1689
  const incarnation = incarnationFromCell(sessionId, r.incarnation);
1627
- const judged = judgeDelegatedOwner(sessionId, scannedPlacement(r), scannedFaces(r));
1628
- const owner = judged.inherited.owner;
1690
+ const inherited = judgeDelegatedOwner(sessionId, scannedPlacement(r), scannedFaces(r));
1691
+ const owner = inherited.owner;
1629
1692
  if (owner === null) {
1630
- if (judged.inherited.kind === "inherited" && scannedPlacedSources(r).has(judged.inherited.from))
1693
+ if (inherited.kind === "inherited" && scannedPlacedSources(r).has(inherited.from))
1631
1694
  receipts.placedSessionOwnersRemaining += 1;
1632
1695
  continue;
1633
1696
  }
@@ -1687,6 +1750,8 @@ function readingFields(r) {
1687
1750
  askCauseColumnsChanged: r.askCauseColumnsChanged,
1688
1751
  askParkTriggersMoved: r.askParkTriggersMoved,
1689
1752
  askJournalRecordsUpgraded: r.askJournalRecordsUpgraded,
1753
+ importedLayerRootAllowsRetired: r.importedLayerRootAllowsRetired.length,
1754
+ importedLayerRootBucketsSkipped: r.importedLayerRootBucketsSkipped.length,
1690
1755
  };
1691
1756
  }
1692
1757
  export function logOneTimeMigrations(log, backend, report) {
@@ -1744,7 +1809,11 @@ export function logOneTimeMigrations(log, backend, report) {
1744
1809
  "M34: the approval ask table's single cause column denied_reason — the reason a row was moved to the delivery surface while it is PARKING or PARKED, " +
1745
1810
  "the reason it ended without a human answer while it is VOID or DENIED, overwritten by the second when a parked row was closed — renamed ending_cause, " +
1746
1811
  "a column park_trigger added, and the word on PARKING and PARKED rows moved into park_trigger; on the local backend the approval ask journal is rewritten " +
1747
- "once with record envelope 2, its envelope-1 records read with the same meaning). Each step " +
1812
+ "once with record envelope 2, its envelope-1 records read with the same meaning; " +
1813
+ "M36: allow approvals that an import before engine 7.61.0 stored as global rules from a settings file's user-layer path written from `/` — which the user layer reads at its " +
1814
+ "configuration directory and a global rule reads at every task's project root — retired by tombstones naming exactly those approvals (a rule that also holds an approval a person " +
1815
+ "gave directly stays in effect; deny and ask rules are never retired), one imported_layer_root_allow_retired line per rule; a bucket that could not be read or written, or that another replica deleted while it was being written, is named by an " +
1816
+ "imported_layer_root_bucket_skipped line on every boot). Each step " +
1748
1817
  "runs on every boot until its window closes (the release that introduced it + 30 days; the per-step date is in " +
1749
1818
  "removableAfter, null while that release is not published yet) and is deleted in the first minor after that — start a " +
1750
1819
  "version that still carries a step at least once before upgrading past its deletion.",
@@ -1789,7 +1858,7 @@ function logReceiptRows(log, backend, r) {
1789
1858
  ...(row.errno !== undefined ? { errno: row.errno } : {}),
1790
1859
  note: "a local session that has runs (and either no session-metadata cell — it was written before the cell existed and has not been read since — or a fork-created cell) has an archive the server cannot read, " +
1791
1860
  "so its execution placement could not be backfilled. The session was skipped and nothing was written or changed: boot is not blocked, and every request that needs the " +
1792
- "session keeps answering the archive's own fault (fault names it: corrupt_session = the session header cannot be read; invalid_session = the stored log's structure is broken; " +
1861
+ "session keeps answering the archive's own fault (fault names it: corrupt_session = the session header cannot be read, or the stored log does not form one tree; " +
1793
1862
  "storage = reading the archive file itself failed — errno names it, e.g. EACCES = no permission, EIO = disk I/O error, ERR_STRING_TOO_LONG = the file is too large to read) until the " +
1794
1863
  "archive file under the data root's sessions directory is readable again — restored from a kept copy, or (storage) its permissions or disk repaired; the next boot then backfills its placement as for any other session. " +
1795
1864
  "(Removing the archive file ends the warning but places nothing: the session then no longer exists on this server — except a fork-created session, whose cell stays and reads as a fork that has not landed: retry the same fork, or delete the session.) The session is named on every boot until then",
@@ -1847,6 +1916,23 @@ function logReceiptRows(log, backend, r) {
1847
1916
  note: removedRuleRowNote(row.kind),
1848
1917
  });
1849
1918
  }
1919
+ for (const row of r.importedLayerRootAllowsRetired) {
1920
+ log.warn("imported_layer_root_allow_retired", {
1921
+ backend,
1922
+ ownerKey: row.ownerKey,
1923
+ tool: row.tool,
1924
+ addsRetired: row.addsRetired,
1925
+ stillLive: row.stillLive,
1926
+ note: "an allow rule imported from a settings file's user layer by an import before engine 7.61.0 was written from `/` — the user layer reads such a path at its own configuration " +
1927
+ "directory — and was stored as a global rule, which reads it at every task's project root: it let that path be acted on in every project without a question. A one-time migration " +
1928
+ "retired the imported approval of it (a tombstone naming exactly that approval). stillLive false = the rule no longer takes effect and an action it covered asks again; stillLive true = " +
1929
+ "the rule stays in effect through another approval of it (one a person gave directly). To carry the rule again, spell its directory out (`//<directory>/…`, or `~/<path>` under the home) " +
1930
+ "and approve it again. This line is written once, by the boot that retired it — keep it; the rule text is not on it (list the bucket's rules to see what remains)",
1931
+ });
1932
+ }
1933
+ for (const bucket of r.importedLayerRootBucketsSkipped) {
1934
+ log.warn("imported_layer_root_bucket_skipped", { backend, ownerKey: bucket.ownerKey, reason: bucket.reason, why: bucket.why, note: importedLayerRootSkipNote(bucket.reason) });
1935
+ }
1850
1936
  for (const bucket of r.undurableScopeRuleBucketsUnreadable) {
1851
1937
  log.warn("permission_rule_bucket_unreadable", {
1852
1938
  backend,
@@ -1925,6 +2011,23 @@ export async function runAndLogOneTimeMigrations(log, backend) {
1925
2011
  }
1926
2012
  logOneTimeMigrations(log, backend.kind, report);
1927
2013
  }
2014
+ function importedLayerRootSkipNote(reason) {
2015
+ const head = "the one-time retirement of allow approvals that an import before engine 7.61.0 stored as global rules from a user-layer path written from `/` (read at every project root) did not finish in this permission-rule bucket: ";
2016
+ switch (reason) {
2017
+ case "bucket_unreadable":
2018
+ return `${head}the bucket could not be read. The read path refuses such a bucket in whole as well, so none of its rules takes effect; once it is repaired, the next boot retires what it selects. Named on every boot until then`;
2019
+ case "vanished":
2020
+ return `${head}the bucket was deleted (by another replica) while this step was writing to it. Nothing is left to retire and none of its rules takes effect; not a boot refusal`;
2021
+ case "not_writable":
2022
+ return `${head}it holds approvals the retirement selects, but no tombstone could be written (the bucket is served read-only — a rule-store adoption in progress — or the store refused the tombstone), so those allow rules keep taking effect at every project root. Finish the adoption or repair the store and restart; named on every boot until then`;
2023
+ case "contended":
2024
+ return `${head}every write lost to a concurrent writer. Those allow rules keep taking effect until a later boot retires them; named on every boot until then`;
2025
+ default: {
2026
+ const unknown = reason;
2027
+ throw new Error(`M36: no log sentence for skip reason ${JSON.stringify(unknown)}`);
2028
+ }
2029
+ }
2030
+ }
1928
2031
  function removedRuleRowNote(kind) {
1929
2032
  switch (kind) {
1930
2033
  case "rule":
@@ -101,7 +101,7 @@ export declare class SqlOrgDeliveryQuotaStore implements OrgDeliveryQuotaStore {
101
101
  take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<boolean>;
102
102
  /**
103
103
  * 一个记账事务:库钟先读(池上一条值语句,不在事务里留普通 SELECT),判过 ⇒ 提交,判拒 ⇒ 回滚(零残留)。
104
- * 🔴 **引擎判了死锁 ⇒ 整事务重来**(有界,`isDeadlockError` 是全仓唯一的可重试锁故障判据):被挑中的一方已整事务回滚、锁全放,
104
+ * 🔴 **引擎判了死锁 ⇒ 整事务重来**(`retryOnDeadlock`:全仓唯一的重来写法、唯一的上界与判据):被挑中的一方已整事务回滚、锁全放,
105
105
  * 重来时读-判-写全部重做,语义等价。真 InnoDB(REPEATABLE READ)上这条路是真的:窗前进时按收件人前缀删旧对偶行要取范围 / 间隙锁,
106
106
  * 两位相邻收件人同时翻窗、各自往两人之间的间隙里插新对偶行 ⇒ 互等(TiDB 无间隙锁、PG 读已提交不取间隙锁)。谁当牺牲者是引擎的任意选择,
107
107
  * 抛给调用方等于把一次内部仲裁当成投递失败。锁等待超时**不**重来(延迟信号,照抛)。
@@ -2,7 +2,7 @@ import { join } from "node:path";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { atomicWriteFile, ensureDir } from "@sema-agent/core";
4
4
  import { mysqlDriver, pgDriver, sqlDbNowMs } from "./sql-driver.js";
5
- import { isDeadlockError } from "./sql-errors.js";
5
+ import { retryOnDeadlock } from "./sql-errors.js";
6
6
  import { alignedWindow } from "../observability/cost-quota.js";
7
7
  export const ORG_DELIVERY_SENDER_QUOTA_TABLE = "org_delivery_sender_quota";
8
8
  export const ORG_DELIVERY_RECIPIENT_QUOTA_TABLE = "org_delivery_recipient_quota";
@@ -122,7 +122,6 @@ export class FileOrgDeliveryQuotaStore extends MemoryOrgDeliveryQuotaStore {
122
122
  atomicWriteFile(this.tmpDir, this.path, `${JSON.stringify(snapshot)}\n`);
123
123
  }
124
124
  }
125
- const DEADLOCK_RETRY_LIMIT = 3;
126
125
  export class SqlOrgDeliveryQuotaStore {
127
126
  db;
128
127
  constructor(db) {
@@ -138,16 +137,7 @@ export class SqlOrgDeliveryQuotaStore {
138
137
  return this.inTx(ORG_DELIVERY_RECIPIENT_QUOTA_TABLE, policy, (conn, at) => this.takeIn(conn, fromScope, toScope, at, policy));
139
138
  }
140
139
  async inTx(table, policy, body) {
141
- for (let tries = 0;; tries++) {
142
- try {
143
- return await this.inTxOnce(table, policy, body);
144
- }
145
- catch (err) {
146
- if (tries < DEADLOCK_RETRY_LIMIT && isDeadlockError(this.db.dialect, err))
147
- continue;
148
- throw err;
149
- }
150
- }
140
+ return retryOnDeadlock(this.db.dialect, () => this.inTxOnce(table, policy, body));
151
141
  }
152
142
  async inTxOnce(table, policy, body) {
153
143
  const at = quotaWindowStart(await sqlDbNowMs(this.db, table), policy.windowMs);
@@ -28,7 +28,7 @@ import type { CheckpointStore } from "@sema-agent/core";
28
28
  /**
29
29
  * 一只**已提交**的审批停车行说它握着哪些调用(停车行自己的陈述,原样,不是推断):
30
30
  * · `sessionId` —— 行停住的会话 `cp.sessionId`(执行这次调用的会话:委派 / 后台子代的行落在**子会话**上)。core 铸行用的是 prepare-task 的
31
- * 同一个 `sessionId`,它也是同一次调用的 ask 上的 `sourceTaskId`(`askSourceIdentity`)⇒ 订阅者按**相等**配,不做别名(车 SO:
31
+ * 同一个 `sessionId`,它也是同一次调用的 ask 上的 `sourceSessionId`(`askSourceIdentity`)⇒ 订阅者按**相等**配,不做别名(车 SO:
32
32
  * 调用 id 只在 run 内唯一,宿主会话若当子代的等价别名,宿主停车行会冒充子代的提交);
33
33
  * · `toolCallIds` —— 停在门前的那只调用(`pendingAction.toolCallId`)∪ 同一条助手消息里**尚未执行**的调用
34
34
  * (`batchToolCallIds − completedCallIds`,core d.ts「#k+1..N are still pending」):那些调用随这一行一起被持久挂起,
@@ -2,7 +2,7 @@ import { FileDurableRulePartitionProvider, type RuleApprovalRecord, type RuleApp
2
2
  import { type RuleImportTicket, type RuleTicketPurpose, type RuleTicketReclaimResult, type RuleTicketRedeemResult, type RuleTicketSnapshot } from "./permission-rule-store-sql.js";
3
3
  import type { PermissionRuleStoreBundle } from "../rules-consent.js";
4
4
  import type { Logger } from "../observability/logger.js";
5
- import { type RuleCandidate } from "@sema-agent/core";
5
+ import { type RuleCandidate, type RuleOwner } from "@sema-agent/core";
6
6
  /**
7
7
  * `RuleApprovalRecordStore` 的 File 形。
8
8
  *
@@ -26,6 +26,13 @@ export declare class FileRuleApprovalRecordStore implements RuleApprovalRecordSt
26
26
  get(id: string): Promise<RuleApprovalRecord | StaleRuleApprovalRecord | undefined>;
27
27
  create(record: RuleApprovalRecord): Promise<void>;
28
28
  cas(id: string, expectRev: number, next: RuleApprovalRecord): Promise<boolean>;
29
+ /**
30
+ * 一次性迁移 M36(窗口见 `plugins/one-time-migrations.ts` 登记表)在 File 店能叫出名字的桶:本店**导入记录**点名过的每一个属主(去重)。
31
+ * 引擎 File 分区的桶文件按属主名的单向摘要命名、分区后端没有列桶口,记录是本店唯一叫得出桶属主的地方(SQL 店直接列规则表;File 侧的缺口见
32
+ * `imported-layer-root-retirement.ts` 头注)。上一形的记录(Stale 信封)读不出种类 ⇒ 属主读得出就算上(多读一只桶零写,少读一只会漏)。
33
+ * 损坏闸合着 ⇒ 抛(读不全记录就叫不全桶;与本面其余口同一条 fail-closed)。
34
+ */
35
+ importRecordOwners(): Promise<RuleOwner[]>;
29
36
  /** 与 SQL 侧同名方法同义(超帽拒绝时收掉 `prepareCcImport` 已落盘的那条 pending 记录)。
30
37
  * `state === "pending"` 是硬的:已确认/已兑付的记录是一次真人同意的审计事实。 */
31
38
  discardPendingRecord(recordId: string): Promise<boolean>;
@@ -87,6 +94,8 @@ export declare class FileRuleImportTicketStore {
87
94
  * 那一条:过期只挡开始一次兑付,不挡做完一次已经开始的)。抢到之后**换一代认领**。 */
88
95
  reclaim(ticketId: string, principal: string, purpose: RuleTicketPurpose, minClaimAgeMs: number): Promise<RuleTicketReclaimResult>;
89
96
  }
97
+ /** 三面束在数据根下的目录名(唯一一处;束在第一次装配时建它 —— 没开过规则店的数据根下没有它)。 */
98
+ export declare const FILE_PERMISSION_RULE_DIR = "permission-rules";
90
99
  /** local 车道的三面束 + 生命周期。`dispose()` 释放 core File durable 分区 provider 的写锁(见 {@link createFilePermissionRuleStores})。 */
91
100
  export interface FilePermissionRuleStores extends PermissionRuleStoreBundle {
92
101
  durable: FileDurableRulePartitionProvider;
@@ -4,7 +4,7 @@ import { readdirSync } from "node:fs";
4
4
  import { performance } from "node:perf_hooks";
5
5
  import { FileDurableRulePartitionProvider, AppendLog, ensureDir, } from "@sema-agent/core";
6
6
  import { z } from "zod";
7
- import { DurableRuleScopeSchema, RuleOfferColumn, buildRulePayloadHash, recordOwnerOf, refusedOwnerSentence } from "./permission-rule-store-sql.js";
7
+ import { DurableRuleScopeSchema, IMPORT_RECORD_KIND, RuleOfferColumn, buildRulePayloadHash, recordOwnerOf, refusedOwnerSentence } from "./permission-rule-store-sql.js";
8
8
  import { replayJsonlGuarded } from "../observability/corrupt-read-seat.js";
9
9
  import { EDITED_RULE_BREADTH_WARNING_CODES, RULE_APPROVAL_KINDS, RULE_APPROVAL_RECORD_SCHEMA, RULE_APPROVAL_STATES, RULE_BEHAVIORS, readRuleOwner } from "@sema-agent/core";
10
10
  const RuleDotSchema = z.object({ actor: z.string().min(1), counter: z.number().int().nonnegative().safe() }).strict();
@@ -173,6 +173,18 @@ export class FileRuleApprovalRecordStore {
173
173
  this.rows.set(id, structuredClone(next));
174
174
  return true;
175
175
  }
176
+ async importRecordOwners() {
177
+ this.gate.assertUsable();
178
+ const owners = [];
179
+ for (const r of this.rows.values()) {
180
+ if (!("staleSchema" in r) && r.kind !== IMPORT_RECORD_KIND)
181
+ continue;
182
+ const owner = recordOwnerOf(r);
183
+ if (owner !== undefined)
184
+ owners.push(owner);
185
+ }
186
+ return owners;
187
+ }
176
188
  async discardPendingRecord(recordId) {
177
189
  this.gate.assertUsable();
178
190
  const cur = this.rows.get(recordId);
@@ -319,8 +331,9 @@ export class FileRuleImportTicketStore {
319
331
  return { ok: true, approvalId: row.approvalId, payloadHash: row.payloadHash, claimId };
320
332
  }
321
333
  }
334
+ export const FILE_PERMISSION_RULE_DIR = "permission-rules";
322
335
  export function createFilePermissionRuleStores(root, opts) {
323
- const dir = join(root, "permission-rules");
336
+ const dir = join(root, FILE_PERMISSION_RULE_DIR);
324
337
  ensureDir(dir);
325
338
  const durable = opts?.onError ? new FileDurableRulePartitionProvider(dir, opts.onError) : new FileDurableRulePartitionProvider(dir);
326
339
  const approvals = new FileRuleApprovalRecordStore(dir, opts?.warn);
@@ -158,6 +158,8 @@ export declare function buildRuleBucketChecksum(body: {
158
158
  /** 这只桶的行写在哪一版规则文法里(`SESSION_RULES_GRAMMAR` 的数);缺席 = 存量无戳行(列 NULL)。 */
159
159
  grammar?: number;
160
160
  }): string;
161
+ /** 一只桶要的全部 SQL 能力:方言 + 一只执行口(池,或一次性迁移握着锁的那一条连接 —— M36 在那条连接上经同一只写面落墓碑)。 */
162
+ type BucketSql = Pick<SqlDriver, "dialect" | "query">;
161
163
  /**
162
164
  * SQL 双方言的 {@link DurableRulePartitionProvider} —— [ref] 里的 **durable 分区后端**
163
165
  * (`user` + `project` 两源的 OR-Set CRDT),**不是**引擎接缝本身:
@@ -170,7 +172,7 @@ export declare function buildRuleBucketChecksum(body: {
170
172
  export declare class SqlDurableRulePartitionProvider implements DurableRulePartitionProvider {
171
173
  private readonly db;
172
174
  private readonly now;
173
- constructor(db: SqlDriver, now?: () => number);
175
+ constructor(db: BucketSql, now?: () => number);
174
176
  forPrincipal(principal: string | undefined): DurableRulePartition;
175
177
  forLocalOwner(): DurableRulePartition;
176
178
  }
@@ -182,6 +184,33 @@ export declare function recordOwnerOf(record: {
182
184
  readonly owner?: unknown;
183
185
  readonly principal?: unknown;
184
186
  }): RuleOwner | undefined;
187
+ /**
188
+ * 一次性迁移 M36(窗口见 `plugins/one-time-migrations.ts` 登记表)要读的桶:**规则表里的每一只桶**(按 `owner_key` 分页,与 M11 同一只走法)。
189
+ * 不从审批记录推:收编腿把规则桶整桶改键到新身份、而审批史按 D2 留在旧身份名下(`src/adoption/plan.ts` 的 `permission_rule#owner_key` 腿与
190
+ * `permission-rule-approval-history` 一员)—— 从记录推出的属主集在收编之后漏掉新桶。属主读法只有引擎的 `readRuleOwner`(与本店读口同一只);
191
+ * 读不出属主的行不点名任何可解析的桶(读腿同样解析不到它),不返回。`db` 是池或迁移握锁的那一条连接。
192
+ */
193
+ export declare function listRuleBucketOwners(db: Pick<SqlDriver, "dialect" | "query">): Promise<RuleOwner[]>;
194
+ /**
195
+ * 取 dot 那一步「建行之后、读行之前」这只桶被并发删掉了(另一只副本删桶恰落在这一窗里)。具名类 ⇒ 调用方按类判(M36 退役读作「无可退役」),不按文案。
196
+ */
197
+ export declare class RuleBucketVanishedError extends Error {
198
+ readonly ownerKey: string;
199
+ constructor(ownerKey: string);
200
+ }
201
+ /** 这只抛出物是不是本店的「桶在写它的那一步里没了」({@link RuleBucketVanishedError})。 */
202
+ export declare function isSqlBucketVanished(e: unknown): boolean;
203
+ /**
204
+ * 这只读桶抛出物是不是**本店读腿的整桶拒** —— 判的是读腿({@link SqlDurableRulePartition} 的 `list` / 写的读基)**真往外交的**那两类,不是判官内部的抛出形:
205
+ * · {@link BucketRefusedError} —— 判官四道(文法戳 / 指纹 / 行的 behavior / 引擎校验器)的拒;
206
+ * · {@link StoreCorruptError} —— 某只 JSON 列的体读不出(`not-json` / `malformed`),读腿在 {@link refusingUnreadableColumns} 把判官抛的列错误折成的店拒绝契约。
207
+ * 两类都是这一行的确定性判决:原样再读也读不出,读腿对它同样整桶拒(零规则),所以它什么都不放行。
208
+ * 别的抛出物**不是**这一类:连接 / 超时 / 权限(一次读失败证明不了以后也读不出);以及仍以 {@link SqlJsonColumnError} 穿出读腿的唯一一形 `not-text`
209
+ * (列没按文本投影:读腿与解码点漂了,是码缺陷不是坏数据 —— 按列错误类判它会把一次码漂读成「这只桶坏了」)。
210
+ */
211
+ export declare function isSqlBucketRefusal(e: unknown): boolean;
212
+ /** 导入记录的种类词(引擎闭集 `RULE_APPROVAL_KINDS` 的一员;`imported-cc` 出处由它派生)。 */
213
+ export declare const IMPORT_RECORD_KIND = "import";
185
214
  /** 写口拒句(两只店同一句):属主引擎读不出,记录不落。 */
186
215
  export declare function refusedOwnerSentence(recordId: string): string;
187
216
  /**
@@ -542,4 +571,5 @@ export interface PermissionRuleStores {
542
571
  reapExpired(nowMs: number): Promise<number>;
543
572
  }
544
573
  export declare function createSqlPermissionRuleStores(db: SqlDriver, now?: () => number): PermissionRuleStores;
574
+ export {};
545
575
  //# sourceMappingURL=permission-rule-store-sql.d.ts.map
@@ -6,7 +6,7 @@ import { isMissingColumnError } from "./sql-errors.js";
6
6
  import { describeProbedTableDrift } from "./schema-drift-sentence.js";
7
7
  import { canonicalJsonStringify } from "@sema-agent/core";
8
8
  import { ensureIndexes } from "./ensure-index.js";
9
- import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, SqlJsonColumnError } from "./sql-json-column.js";
9
+ import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, SqlJsonColumnError, StoreCorruptError } from "./sql-json-column.js";
10
10
  import { redactSecrets } from "../trace/redact.js";
11
11
  export function writerOfSqlRuleStore(store) {
12
12
  const w = Reflect.get(store, PERMISSION_RULE_WRITER);
@@ -508,7 +508,7 @@ class SqlDurableRulePartition {
508
508
  const { rows } = await this.db.query(this.q(`SELECT actor, counter, grammar FROM ${PERMISSION_RULE_TABLE} WHERE owner_key = ?`, `SELECT actor, counter, grammar FROM ${PERMISSION_RULE_TABLE} WHERE owner_key = $1`), [this.ownerKey]);
509
509
  const row = rows[0];
510
510
  if (row === undefined)
511
- throw new Error(`permission_rule bucket ${this.ownerKey} vanished while minting a dot`);
511
+ throw new RuleBucketVanishedError(this.ownerKey);
512
512
  readBucketStamp(this.ownerKey, row.grammar);
513
513
  const cur = Number(row.counter);
514
514
  const next = cur + 1;
@@ -593,6 +593,39 @@ export class SqlDurableRulePartitionProvider {
593
593
  export function recordOwnerOf(record) {
594
594
  return readRuleOwner(record.owner ?? { kind: "principal", principal: record.principal });
595
595
  }
596
+ export async function listRuleBucketOwners(db) {
597
+ const owners = [];
598
+ let after = "";
599
+ for (;;) {
600
+ const { rows } = await db.query(db.dialect === "mysql"
601
+ ? `SELECT owner_key, owner_kind, principal FROM ${PERMISSION_RULE_TABLE} WHERE owner_key > ? ORDER BY owner_key LIMIT ${UNDURABLE_PURGE_PAGE}`
602
+ : `SELECT owner_key, owner_kind, principal FROM ${PERMISSION_RULE_TABLE} WHERE owner_key > $1 ORDER BY owner_key LIMIT ${UNDURABLE_PURGE_PAGE}`, [after]);
603
+ for (const row of rows) {
604
+ after = String(row["owner_key"]);
605
+ const principal = row["principal"] === null || row["principal"] === undefined ? undefined : String(row["principal"]);
606
+ const owner = readRuleOwner({ kind: row["owner_kind"], ...(principal !== undefined ? { principal } : {}) });
607
+ if (owner !== undefined)
608
+ owners.push(owner);
609
+ }
610
+ if (rows.length < UNDURABLE_PURGE_PAGE)
611
+ return owners;
612
+ }
613
+ }
614
+ export class RuleBucketVanishedError extends Error {
615
+ ownerKey;
616
+ constructor(ownerKey) {
617
+ super(`permission_rule bucket ${ownerKey} vanished while minting a dot`);
618
+ this.name = "RuleBucketVanishedError";
619
+ this.ownerKey = ownerKey;
620
+ }
621
+ }
622
+ export function isSqlBucketVanished(e) {
623
+ return e instanceof RuleBucketVanishedError;
624
+ }
625
+ export function isSqlBucketRefusal(e) {
626
+ return e instanceof BucketRefusedError || e instanceof StoreCorruptError;
627
+ }
628
+ export const IMPORT_RECORD_KIND = "import";
596
629
  export function refusedOwnerSentence(recordId) {
597
630
  return `refusing to create approval record ${recordId}: its owner is not one the engine reads as an owner (a principal name must be a non-blank string; the kind must be a member of the owner set) — nothing was written`;
598
631
  }
@@ -3,7 +3,6 @@ import type { Pool, PoolClient } from "pg";
3
3
  import type { SessionSummary } from "./store-contracts.js";
4
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
- import { type OrphanOwnerLog } from "../delegated-session-owner.js";
7
6
  import { type StagingHandle } from "../session-sync-kernel.js";
8
7
  import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
9
8
  import type { SessionWorkspace } from "../session-workspace.js";
@@ -71,26 +70,19 @@ export declare class PgSessionStore implements SessionStore {
71
70
  readonly durability: "durable";
72
71
  /** In-flight acquisitions keyed by id, so concurrent acquire(sameId) in one process share one. */
73
72
  private readonly pending;
74
- /** 委派子代孤行那一行 warn 的去处(TiDB 孪生同格)。 */
75
- private readonly log;
76
73
  /** 执行席(TiDB 孪生同格;实现与语句的唯一属主 = `execution-placement-sql.ts`,本店只交自己的池)。 */
77
74
  readonly executionPlacement: ExecutionPlacementSeat;
78
75
  /** 本店的池包成的 SqlDriver(TiDB 孪生同格):执行席与会话行格写原语的事务都经它借连接。 */
79
76
  private readonly db;
80
77
  constructor(pool: Pool, opts?: {
81
- readonly log?: OrphanOwnerLog;
82
78
  readonly retention?: RetentionDeclaration;
83
79
  });
84
80
  acquire(sessionId?: string, opts?: PlacementAcquireOpts): Promise<AcquiredSession>;
85
81
  private load;
86
82
  /** Idempotently create a session_meta row with an owner (core `SessionStore.register`). Existing owner is never overwritten. */
87
83
  register(sessionId: string, owner: string | null): Promise<void>;
88
- /** acquire 的建行(唯一一处;[ref] 委派继承律,只住在 `createPlacedSessionRow`,本店交既有读写口 —— TiDB 孪生同名方法同注)。 */
84
+ /** acquire 的建行(唯一一处;placed 会话的属主 = `placement.owner` 原样,core 7.62.0 [ref] 盒义务 7 —— TiDB 孪生同名方法同注)。 */
89
85
  private createOnAcquire;
90
- /** [ref] 委派继承律的认领口(TiDB 孪生 {@link TiDBSessionStore.claimOwnerless} 同义;句 = `CLAIM_OWNERLESS_PLACED_SQL`,规则在 `delegated-session-owner.ts`)。 */
91
- claimOwnerless(sessionId: string, incarnation: string, owner: string): Promise<boolean>;
92
- /** 若干来源行的会话面(属主 + 化身)一次读回(TiDB 孪生同义;活住客的投影 `sessionFaceFromRow`,空化身 ⇒ 响亮拒)。 */
93
- private sourceFaces;
94
86
  /** The one session_meta INSERT. Existing owner is never overwritten.
95
87
  * [ref]:`placement` 与行同一条 INSERT;`DO NOTHING` 臂 ⇒ 已存在行的元组永不被重写(first-write 不可变)。 */
96
88
  private insertMeta;
@@ -10,8 +10,6 @@ import { pgSafeJsonStringify } from "./pg-safe-json.js";
10
10
  import { toIso } from "./sql-row-helpers.js";
11
11
  import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SESSION_DURABILITY, SESSION_PLACEMENTS, } from "./session-placement.js";
12
12
  import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
13
- import { CLAIM_OWNERLESS_PLACED_SQL, claimOwnerlessParams, createPlacedSessionRow } from "../delegated-session-owner.js";
14
- import { createLogger } from "../observability/logger.js";
15
13
  import { classifySyncRelationshipByIds, SyncConflictError, StagedCommitOwnerChangedError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
16
14
  import { isPgUniqueViolation } from "./sql-errors.js";
17
15
  import { BASELINE_IO_DEADLINE_MS, decodeInstructionSource, encodeInstructionSource } from "../instruction-source-notice.js";
@@ -19,7 +17,7 @@ import { SESSION_META_WORKSPACE_COLUMN, decodeSessionWorkspaceCell, encodeSessio
19
17
  import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
20
18
  import { SESSION_META_INCARNATION_COLUMN, carriedRowCells, headFromRow, incarnationFromCell, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
21
19
  import { ensureIndexes } from "./ensure-index.js";
22
- import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue } from "./session-ownership.js";
20
+ import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue, placedSessionOwnerOf } from "./session-ownership.js";
23
21
  import { selectForkRows } from "@sema-agent/core";
24
22
  import { FORK_LOG_ROW_SHAPE, ForkTargetUnsettledError, classifyForkTarget, forkByFreshId, forkPointOf } from "./session-fork.js";
25
23
  import { pgDriver } from "./sql-driver.js";
@@ -191,12 +189,10 @@ export class PgSessionStore {
191
189
  placements = SESSION_PLACEMENTS;
192
190
  durability = SESSION_DURABILITY;
193
191
  pending = new Map();
194
- log;
195
192
  executionPlacement;
196
193
  db;
197
194
  constructor(pool, opts = {}) {
198
195
  this.pool = pool;
199
- this.log = opts.log ?? createLogger();
200
196
  this.retention = opts.retention ?? UNMANAGED_RETENTION;
201
197
  this.db = pgDriver(pool);
202
198
  this.executionPlacement = createSqlExecutionPlacementSeat(this.db);
@@ -244,20 +240,7 @@ export class PgSessionStore {
244
240
  await this.insertMeta(sessionId, owner, undefined);
245
241
  }
246
242
  async createOnAcquire(sessionId, placement) {
247
- if (placement === undefined)
248
- return this.insertMeta(sessionId, null, undefined);
249
- await createPlacedSessionRow(sessionId, placement, {
250
- readFaces: (ids) => this.sourceFaces(ids),
251
- insert: (owner) => this.insertMeta(sessionId, owner, placement),
252
- readOwner: async () => (await this.headOf(sessionId))?.owner,
253
- }, this.log);
254
- }
255
- async claimOwnerless(sessionId, incarnation, owner) {
256
- return ((await this.pool.query(CLAIM_OWNERLESS_PLACED_SQL.pg, [...claimOwnerlessParams(sessionId, incarnation, owner)])).rowCount ?? 0) > 0;
257
- }
258
- async sourceFaces(ids) {
259
- const res = await this.pool.query(`SELECT session_id, owner, incarnation FROM session_meta WHERE session_id IN (${ids.map((_, i) => `$${i + 1}`).join(", ")})`, [...ids]);
260
- return new Map(res.rows.map((r) => [String(r.session_id), sessionFaceFromRow(String(r.session_id), r.owner ?? null, r.incarnation)]));
243
+ await this.insertMeta(sessionId, placement === undefined ? null : placedSessionOwnerOf(sessionId, placement), placement);
261
244
  }
262
245
  async insertMeta(sessionId, owner, placement) {
263
246
  const now = new Date();