@sema-agent/server 7.144.0 → 7.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/MIGRATION.md +621 -0
  2. package/README.md +3 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +233 -54
  5. package/deploy/facts/CHANGES.json +25 -0
  6. package/deploy/facts/README.md +57 -0
  7. package/deploy/facts/lanes.json +54 -0
  8. package/deploy/facts/lanes.schema.json +57 -0
  9. package/deploy/facts/sandbox-rbac.json +113 -0
  10. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  11. package/deploy/facts/sealed-key.json +9 -0
  12. package/deploy/facts/sealed-key.schema.json +52 -0
  13. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  14. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  15. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  16. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  17. package/deploy/sema-up/chart/values.yaml +7 -0
  18. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  19. package/dist/adoption/import-limits.d.ts +6 -0
  20. package/dist/adoption/import-limits.js +7 -0
  21. package/dist/adoption/import.d.ts +62 -0
  22. package/dist/adoption/import.js +107 -0
  23. package/dist/adoption/wire.d.ts +52 -0
  24. package/dist/adoption/wire.js +9 -0
  25. package/dist/approval-ask-machine.d.ts +2 -2
  26. package/dist/approval-card.d.ts +3 -12
  27. package/dist/approval-card.js +0 -4
  28. package/dist/approval-gate-currency.d.ts +1 -1
  29. package/dist/approval-gate-currency.js +1 -1
  30. package/dist/approval-reconciler.d.ts +1 -1
  31. package/dist/audit.d.ts +2 -21
  32. package/dist/audit.js +0 -9
  33. package/dist/boot/deployment-mods.d.ts +11 -1
  34. package/dist/boot/deployment-mods.js +15 -2
  35. package/dist/boot/device-lane.js +2 -0
  36. package/dist/boot/engine-lease.d.ts +193 -21
  37. package/dist/boot/engine-lease.js +146 -20
  38. package/dist/boot/execution-env.d.ts +4 -0
  39. package/dist/boot/execution-env.js +12 -0
  40. package/dist/boot/exit-boundary.d.ts +50 -0
  41. package/dist/boot/exit-boundary.js +32 -0
  42. package/dist/boot/exit-last.d.ts +20 -4
  43. package/dist/boot/exit-last.js +21 -4
  44. package/dist/boot/governance-seams.js +1 -0
  45. package/dist/boot/memory-consolidation.d.ts +29 -17
  46. package/dist/boot/memory-consolidation.js +26 -15
  47. package/dist/boot/reapers.d.ts +12 -4
  48. package/dist/boot/reapers.js +39 -15
  49. package/dist/boot/resolve-spec.d.ts +2 -0
  50. package/dist/boot/resolve-spec.js +38 -15
  51. package/dist/boot/runner-deps.js +1 -1
  52. package/dist/boot/session-faces.d.ts +1 -1
  53. package/dist/boot/session-faces.js +6 -4
  54. package/dist/boot/shutdown.js +27 -9
  55. package/dist/boot/stage-01-config.js +1 -1
  56. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  57. package/dist/boot/stage-03-store-backend.js +2 -2
  58. package/dist/boot/stage-04-stores.d.ts +1 -0
  59. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  60. package/dist/boot/stage-05-execution-env.js +3 -3
  61. package/dist/boot/stage-06-runners.d.ts +3 -0
  62. package/dist/boot/stage-06-runners.js +11 -10
  63. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  64. package/dist/boot/stage-07-capability-layer.js +7 -2
  65. package/dist/boot/stage-08-reapers.d.ts +3 -0
  66. package/dist/boot/stage-08-reapers.js +3 -3
  67. package/dist/boot/stage-09-leader.d.ts +4 -1
  68. package/dist/boot/stage-10-http-server.d.ts +4 -1
  69. package/dist/boot/stage-10-http-server.js +4 -3
  70. package/dist/boot/stores.d.ts +1 -0
  71. package/dist/boot/stores.js +35 -19
  72. package/dist/boot/workflow-orchestration.d.ts +1 -1
  73. package/dist/boot/workflow-orchestration.js +2 -1
  74. package/dist/capabilities/composite-members.d.ts +3 -1
  75. package/dist/capabilities/composite-members.js +3 -1
  76. package/dist/capabilities/scenarios.d.ts +2 -2
  77. package/dist/capability-facts.d.ts +18 -1
  78. package/dist/capability-facts.js +25 -7
  79. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  80. package/dist/config-catalog.js +13 -4
  81. package/dist/config-d-migration.d.ts +3 -2
  82. package/dist/config-provider.d.ts +2 -2
  83. package/dist/config-types.d.ts +43 -4
  84. package/dist/config.d.ts +6 -1
  85. package/dist/config.js +67 -11
  86. package/dist/deleted-session-ids.d.ts +19 -0
  87. package/dist/deleted-session-ids.js +26 -0
  88. package/dist/deploy-facts.d.ts +155 -0
  89. package/dist/deploy-facts.js +94 -0
  90. package/dist/device-ws-hub.d.ts +48 -3
  91. package/dist/device-ws-hub.js +48 -2
  92. package/dist/error-code-family.d.ts +35 -0
  93. package/dist/error-code-family.js +26 -0
  94. package/dist/fleet/drain-entry.d.ts +39 -3
  95. package/dist/fleet/drain-entry.js +6 -0
  96. package/dist/fleet/fleet-bus.d.ts +15 -4
  97. package/dist/fleet/fleet-bus.js +17 -3
  98. package/dist/hooks/branch-transcript.d.ts +1 -1
  99. package/dist/hooks/branch-transcript.js +1 -0
  100. package/dist/hooks/classic-stations.d.ts +25 -8
  101. package/dist/hooks/classic-stations.js +29 -3
  102. package/dist/hooks/hook-runner.d.ts +33 -16
  103. package/dist/hooks/hook-runner.js +166 -73
  104. package/dist/hooks/hook-source.d.ts +14 -2
  105. package/dist/hooks/hook-source.js +8 -0
  106. package/dist/http/active-run-conflict.d.ts +1 -1
  107. package/dist/http/active-run-conflict.js +1 -1
  108. package/dist/http/admission.js +13 -2
  109. package/dist/http/checkpoint-ctx.d.ts +60 -71
  110. package/dist/http/checkpoint-ctx.js +35 -40
  111. package/dist/http/dispatch.js +18 -2
  112. package/dist/http/durable-run-leg.d.ts +5 -0
  113. package/dist/http/durable-run-leg.js +8 -6
  114. package/dist/http/execution-context.d.ts +4 -0
  115. package/dist/http/execution-context.js +9 -0
  116. package/dist/http/health-self-report.d.ts +6 -2
  117. package/dist/http/health-self-report.js +3 -2
  118. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  119. package/dist/http/memory-compliance-failure-reply.js +2 -15
  120. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  121. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  122. package/dist/http/principal-gate.d.ts +35 -12
  123. package/dist/http/principal-gate.js +16 -12
  124. package/dist/http/request-guards.d.ts +1 -1
  125. package/dist/http/request-guards.js +5 -5
  126. package/dist/http/resume-legs.d.ts +22 -0
  127. package/dist/http/resume-legs.js +31 -20
  128. package/dist/http/route-ctx.d.ts +26 -10
  129. package/dist/http/route-table.js +2 -0
  130. package/dist/http/routes/adoption.d.ts +11 -0
  131. package/dist/http/routes/adoption.js +80 -6
  132. package/dist/http/routes/agents-roster.js +1 -0
  133. package/dist/http/routes/approvals-assistant.d.ts +20 -1
  134. package/dist/http/routes/approvals-assistant.js +29 -7
  135. package/dist/http/routes/background.js +1 -0
  136. package/dist/http/routes/capabilities.js +4 -1
  137. package/dist/http/routes/diagnostics.d.ts +9 -14
  138. package/dist/http/routes/diagnostics.js +10 -20
  139. package/dist/http/routes/engine.d.ts +31 -0
  140. package/dist/http/routes/engine.js +81 -0
  141. package/dist/http/routes/memory-bundle.js +3 -0
  142. package/dist/http/routes/memory-consolidation.js +3 -5
  143. package/dist/http/routes/memory-origin.d.ts +1 -1
  144. package/dist/http/routes/memory-origin.js +2 -4
  145. package/dist/http/routes/memory-policy.js +5 -1
  146. package/dist/http/routes/observability.js +3 -6
  147. package/dist/http/routes/rules.d.ts +1 -1
  148. package/dist/http/routes/rules.js +5 -2
  149. package/dist/http/routes/runs.js +7 -3
  150. package/dist/http/routes/session-sync.js +24 -25
  151. package/dist/http/routes/sessions-list.d.ts +1 -1
  152. package/dist/http/routes/sessions.js +4 -0
  153. package/dist/http/routes/tasks.js +35 -14
  154. package/dist/http/routes/trace-usage.js +1 -1
  155. package/dist/http/run-concurrency-cap.d.ts +86 -0
  156. package/dist/http/run-concurrency-cap.js +54 -0
  157. package/dist/http/run-meta.d.ts +14 -7
  158. package/dist/http/run-meta.js +5 -2
  159. package/dist/http/server.d.ts +27 -16
  160. package/dist/http/server.js +21 -3
  161. package/dist/http/stored-body-replay.d.ts +9 -6
  162. package/dist/http/stored-body-replay.js +19 -5
  163. package/dist/http/submit-ctx.d.ts +12 -0
  164. package/dist/http/submit-ctx.js +23 -0
  165. package/dist/http/wire-types.d.ts +8 -3
  166. package/dist/json-body-limit.d.ts +8 -0
  167. package/dist/json-body-limit.js +2 -0
  168. package/dist/leader/diffout.d.ts +1 -1
  169. package/dist/local-data-root.d.ts +2 -2
  170. package/dist/memory-operator-faces.d.ts +9 -4
  171. package/dist/memory-scope-stores.d.ts +9 -7
  172. package/dist/memory-scope-stores.js +3 -14
  173. package/dist/memory-scope.d.ts +36 -0
  174. package/dist/memory-scope.js +32 -1
  175. package/dist/net-address.d.ts +53 -0
  176. package/dist/net-address.js +111 -0
  177. package/dist/observability/fail-open.d.ts +28 -12
  178. package/dist/observability/fail-open.js +28 -12
  179. package/dist/orchestration/workflow-notify-journal.js +2 -3
  180. package/dist/org-delivery-gate.js +1 -1
  181. package/dist/peer-directory.d.ts +6 -12
  182. package/dist/peer-directory.js +5 -1
  183. package/dist/plugins/approval-ask-store-file.d.ts +16 -2
  184. package/dist/plugins/approval-ask-store-file.js +21 -1
  185. package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
  186. package/dist/plugins/approval-ask-store-memory.js +11 -8
  187. package/dist/plugins/caching-session-store.d.ts +6 -1
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  190. package/dist/plugins/checkpoint-store-face.js +152 -0
  191. package/dist/plugins/file-run-store.d.ts +13 -7
  192. package/dist/plugins/file-run-store.js +12 -13
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  194. package/dist/plugins/fork-routing-session-store.js +2 -2
  195. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  196. package/dist/plugins/local-checkpoint-store.d.ts +16 -5
  197. package/dist/plugins/local-checkpoint-store.js +25 -6
  198. package/dist/plugins/local-session-store.d.ts +80 -21
  199. package/dist/plugins/local-session-store.js +79 -22
  200. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  201. package/dist/plugins/memory-engine-pg.js +96 -214
  202. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  203. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  204. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  205. package/dist/plugins/memory-engine-tidb.js +97 -227
  206. package/dist/plugins/memory-key-guards.d.ts +1 -1
  207. package/dist/plugins/memory-origin-law.d.ts +3 -3
  208. package/dist/plugins/memory-run-store.d.ts +2 -0
  209. package/dist/plugins/memory-run-store.js +6 -0
  210. package/dist/plugins/one-time-migrations.d.ts +32 -56
  211. package/dist/plugins/one-time-migrations.js +27 -119
  212. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  213. package/dist/plugins/permission-rule-store-file.js +8 -1
  214. package/dist/plugins/pg-pool.js +1 -1
  215. package/dist/plugins/pg-session-storage.d.ts +17 -4
  216. package/dist/plugins/pg-session-storage.js +8 -4
  217. package/dist/plugins/run-store-sql.d.ts +4 -0
  218. package/dist/plugins/run-store-sql.js +5 -2
  219. package/dist/plugins/schema-ensure-legs.js +2 -2
  220. package/dist/plugins/session-fork.d.ts +31 -9
  221. package/dist/plugins/session-fork.js +3 -2
  222. package/dist/plugins/session-placement.d.ts +4 -2
  223. package/dist/plugins/session-store.d.ts +1 -1
  224. package/dist/plugins/sql-json-column.d.ts +5 -1
  225. package/dist/plugins/store-backend.d.ts +11 -8
  226. package/dist/plugins/store-backend.js +8 -7
  227. package/dist/plugins/store-contracts.d.ts +1 -11
  228. package/dist/plugins/store-contracts.js +0 -9
  229. package/dist/plugins/store-sweep.d.ts +63 -0
  230. package/dist/plugins/store-sweep.js +48 -0
  231. package/dist/plugins/tidb-pool.js +1 -1
  232. package/dist/plugins/tidb-session-store.d.ts +16 -3
  233. package/dist/plugins/tidb-session-store.js +8 -4
  234. package/dist/prompt-screen.d.ts +18 -0
  235. package/dist/prompt-screen.js +5 -0
  236. package/dist/rules-consent.d.ts +56 -51
  237. package/dist/rules-consent.js +86 -14
  238. package/dist/run-acceptance.d.ts +40 -10
  239. package/dist/run-acceptance.js +38 -5
  240. package/dist/run-cancel-context.d.ts +4 -1
  241. package/dist/run-cancel-context.js +2 -1
  242. package/dist/runs.js +2 -2
  243. package/dist/sandbox-egress-policy.js +6 -11
  244. package/dist/sandbox-rbac-rules.d.ts +88 -0
  245. package/dist/sandbox-rbac-rules.js +80 -0
  246. package/dist/sealed-key-layout.d.ts +17 -0
  247. package/dist/sealed-key-layout.js +4 -0
  248. package/dist/sealed-key.js +5 -5
  249. package/dist/security.d.ts +48 -9
  250. package/dist/security.js +9 -2
  251. package/dist/session-agent.d.ts +39 -0
  252. package/dist/session-agent.js +16 -0
  253. package/dist/session-error-wire.d.ts +4 -4
  254. package/dist/session-notify-door.d.ts +5 -3
  255. package/dist/session-resident-background.d.ts +57 -0
  256. package/dist/session-resident-background.js +20 -0
  257. package/dist/session-sync-kernel.d.ts +53 -14
  258. package/dist/session-sync-kernel.js +70 -1
  259. package/dist/session-sync.d.ts +5 -3
  260. package/dist/session-workspace.d.ts +1 -0
  261. package/dist/session-workspace.js +1 -0
  262. package/dist/sighup-idle.d.ts +9 -7
  263. package/dist/sighup-idle.js +4 -5
  264. package/dist/spec-fields.d.ts +16 -0
  265. package/dist/spec-fields.js +7 -0
  266. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  267. package/dist/stored-request-env-credentials-m38.js +8 -0
  268. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  269. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +33 -429
  270. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +70 -209
  271. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  272. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  273. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  274. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  275. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  276. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  277. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  278. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  279. package/dist/task-settings.d.ts +59 -4
  280. package/dist/task-settings.js +50 -4
  281. package/dist/tool-approval.d.ts +2 -2
  282. package/dist/trace/core-keyset-guard.d.ts +8 -7
  283. package/dist/trace/engine-notice-wire.d.ts +1 -1
  284. package/dist/trace/engine-notice-wire.js +2 -0
  285. package/dist/trace/exit-seat.d.ts +6 -0
  286. package/dist/trace/exit-seat.js +1 -0
  287. package/dist/trace/model-segment.d.ts +3 -2
  288. package/dist/trace/model-segment.js +16 -8
  289. package/dist/trace/project.js +9 -0
  290. package/dist/trace/redact.d.ts +79 -4
  291. package/dist/trace/redact.js +523 -123
  292. package/dist/trace/self-minted-wire.d.ts +391 -1
  293. package/dist/trace/self-minted-wire.js +145 -0
  294. package/dist/trace/wire-projection-faces.d.ts +1 -1
  295. package/dist/trace/wire-projection-faces.js +1 -1
  296. package/dist/usage-analytics.d.ts +4 -0
  297. package/package.json +12 -4
  298. package/scripts/drain-check-local.mjs +8 -29
  299. package/scripts/drain-check.mysql.sql +3 -24
  300. package/scripts/drain-check.pg.sql +3 -24
  301. package/skills/update-config.md +1 -1
  302. package/wire-changes/server@7.145.0.json +146 -0
  303. package/wire-changes/server@7.146.0.json +3221 -0
  304. package/dist/approval-batch-census.d.ts +0 -27
  305. package/dist/approval-batch-census.js +0 -27
@@ -0,0 +1,358 @@
1
+ import { LandingsNeedAdmission, admittingLandings, computeEntryRev, requireLandingsAdmitted, } from "@sema-agent/core";
2
+ import { memoryEntryKeyWidthRefusal } from "./memory-key-guards.js";
3
+ import { pgHasUnstorable } from "./pg-safe-json.js";
4
+ import { ambiguousOriginRefusal, createBatchCommittedBaseline, distilledWhitewashRefusal, originWhitewashRefusal, rememberBatchCommitted, unknownPatchOpRefusal, } from "./memory-origin-law.js";
5
+ const FIRST_SUFFIX_STEP = 2;
6
+ const candidateAt = (slug, n) => (n === FIRST_SUFFIX_STEP ? slug : `${slug}-${n - 1}`);
7
+ const slugKey = (scope, slug) => JSON.stringify([scope, slug]);
8
+ const distinctLandings = (ls) => {
9
+ const seen = new Set();
10
+ return ls.filter((l) => {
11
+ const key = slugKey(l.scope, l.slug);
12
+ if (seen.has(key))
13
+ return false;
14
+ seen.add(key);
15
+ return true;
16
+ });
17
+ };
18
+ const unadmittedOf = (admitted, landings) => {
19
+ try {
20
+ requireLandingsAdmitted(admitted, landings);
21
+ return [];
22
+ }
23
+ catch (err) {
24
+ if (err instanceof LandingsNeedAdmission)
25
+ return err.landings;
26
+ throw err;
27
+ }
28
+ };
29
+ async function planSqlPatch(patch, reads, baseline, claims, unstorableReason, suffixFrom) {
30
+ const conflict = (c) => ({ kind: "conflict", conflict: c });
31
+ const unknownOp = unknownPatchOpRefusal(patch.op);
32
+ if (unknownOp !== undefined)
33
+ return conflict({ op: patch.op, id: patch.id, reason: unknownOp });
34
+ if (patch.op !== "delete" && patch.entry !== undefined && patch.entry.id !== patch.id) {
35
+ return conflict({ op: patch.op, id: patch.id, reason: `patch id ${JSON.stringify(patch.id)} != entry id ${JSON.stringify(patch.entry.id)} (malformed patch refused)` });
36
+ }
37
+ if (patch.op !== "delete" && patch.entry !== undefined) {
38
+ const refusal = memoryEntryKeyWidthRefusal(patch.entry.scope, patch.entry.slug);
39
+ if (refusal !== undefined)
40
+ return conflict({ op: patch.op, id: patch.id, reason: refusal });
41
+ }
42
+ if (patch.op !== "delete" && patch.entry !== undefined) {
43
+ const refusal = ambiguousOriginRefusal(patch.entry.frontmatter);
44
+ if (refusal !== undefined)
45
+ return conflict({ op: patch.op, id: patch.id, reason: refusal });
46
+ }
47
+ if (patch.op === "add") {
48
+ const entry = patch.entry;
49
+ if (!entry)
50
+ return conflict({ op: "add", id: patch.id, reason: "add patch without an entry" });
51
+ if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
52
+ return conflict({ op: "add", id: entry.id, reason: unstorableReason });
53
+ }
54
+ const prior = await reads.rowOf(entry.id);
55
+ const baseFm = rememberBatchCommitted(baseline, entry.id, prior?.frontmatter);
56
+ const originRefusal = originWhitewashRefusal("add", baseFm, entry.frontmatter);
57
+ if (originRefusal !== undefined)
58
+ return conflict({ op: "add", id: entry.id, reason: originRefusal });
59
+ const distilledRefusal = distilledWhitewashRefusal("add", baseFm, entry.frontmatter);
60
+ if (distilledRefusal !== undefined)
61
+ return conflict({ op: "add", id: entry.id, reason: distilledRefusal });
62
+ if (patch.guard === "absent" && prior !== undefined) {
63
+ if (prior.rev !== computeEntryRev(entry)) {
64
+ return conflict({ op: "add", id: entry.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev: prior.rev });
65
+ }
66
+ if (prior.scope !== entry.scope || prior.slug !== entry.slug) {
67
+ return conflict({
68
+ op: "add",
69
+ id: entry.id,
70
+ reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${prior.scope}/${prior.slug}`)}; add-if-absent refuses to duplicate)`,
71
+ currentRev: prior.rev,
72
+ });
73
+ }
74
+ }
75
+ if (prior !== undefined && prior.scope !== entry.scope) {
76
+ return conflict({ op: "add", id: entry.id, reason: `id already exists in scope ${JSON.stringify(prior.scope)} (cross-scope add refused)` });
77
+ }
78
+ let n = suffixFrom;
79
+ let slug = candidateAt(entry.slug, n);
80
+ for (;; n++, slug = candidateAt(entry.slug, n)) {
81
+ const derivedRefusal = memoryEntryKeyWidthRefusal(entry.scope, slug);
82
+ if (derivedRefusal !== undefined) {
83
+ return conflict({ op: "add", id: entry.id, reason: `${derivedRefusal} (slug collision suffix "-${n - 1}" no longer fits the column — shorten the entry name)` });
84
+ }
85
+ if (!claims.has(slugKey(entry.scope, slug)) && !(await reads.idsAt(entry.scope, slug)).some((id) => id !== entry.id))
86
+ break;
87
+ }
88
+ const stored = { ...entry, slug };
89
+ const landings = [];
90
+ if (prior !== undefined && prior.slug !== slug)
91
+ landings.push({ id: entry.id, scope: prior.scope, slug: prior.slug });
92
+ landings.push({ id: entry.id, scope: entry.scope, slug });
93
+ return {
94
+ kind: "add",
95
+ stored,
96
+ rev: computeEntryRev(stored),
97
+ prior: prior !== undefined ? { scope: prior.scope, slug: prior.slug } : undefined,
98
+ frontmatter: entry.frontmatter,
99
+ suffixAt: n,
100
+ landings,
101
+ };
102
+ }
103
+ const current = await reads.rowOf(patch.id);
104
+ if (current === undefined)
105
+ return conflict({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
106
+ const baseFm = rememberBatchCommitted(baseline, patch.id, current.frontmatter);
107
+ if (patch.op === "update" && patch.entry !== undefined) {
108
+ if (current.frontmatter.provenance?.kind === "repo_file") {
109
+ const next = patch.entry.frontmatter;
110
+ const stripsProvenance = next.provenance === undefined;
111
+ const stripsTrust = current.frontmatter.trust !== undefined && next.trust === undefined;
112
+ if (stripsProvenance || stripsTrust) {
113
+ return conflict({
114
+ op: "update",
115
+ id: patch.id,
116
+ reason: `repo_file provenance whitewash refused: update drops ${stripsProvenance ? "provenance" : "trust"} from a repo-ingested entry (malformed patch refused)`,
117
+ });
118
+ }
119
+ }
120
+ const originRefusal = originWhitewashRefusal("update", baseFm, patch.entry.frontmatter);
121
+ if (originRefusal !== undefined)
122
+ return conflict({ op: "update", id: patch.id, reason: originRefusal });
123
+ const distilledRefusal = distilledWhitewashRefusal("update", baseFm, patch.entry.frontmatter);
124
+ if (distilledRefusal !== undefined)
125
+ return conflict({ op: "update", id: patch.id, reason: distilledRefusal });
126
+ }
127
+ if (patch.baseRev !== undefined && patch.baseRev !== current.rev) {
128
+ return conflict({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: current.rev });
129
+ }
130
+ const at = { scope: current.scope, slug: current.slug };
131
+ if (patch.op === "delete") {
132
+ return { kind: "delete", id: patch.id, currentRev: current.rev, current: at, baseRev: patch.baseRev, landings: [{ id: patch.id, ...at }] };
133
+ }
134
+ const entry = patch.entry;
135
+ if (!entry)
136
+ return conflict({ op: "update", id: patch.id, reason: "update patch without an entry" });
137
+ if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
138
+ return conflict({ op: "update", id: patch.id, reason: unstorableReason });
139
+ }
140
+ const moves = current.scope !== entry.scope || current.slug !== entry.slug;
141
+ return {
142
+ kind: "update",
143
+ entry,
144
+ rev: computeEntryRev(entry),
145
+ currentRev: current.rev,
146
+ current: at,
147
+ baseRev: patch.baseRev,
148
+ landings: [...(moves ? [{ id: patch.id, ...at }] : []), { id: entry.id, scope: entry.scope, slug: entry.slug }],
149
+ };
150
+ }
151
+ class CallerThrow extends Error {
152
+ thrown;
153
+ constructor(thrown) {
154
+ super("caller confirm threw");
155
+ this.thrown = thrown;
156
+ }
157
+ }
158
+ function duplicatePositions(patches) {
159
+ const seen = new Set();
160
+ const dup = new Set();
161
+ patches.forEach((p, i) => {
162
+ if (p.op === "delete")
163
+ return;
164
+ if (seen.has(p.id))
165
+ dup.add(i);
166
+ else
167
+ seen.add(p.id);
168
+ });
169
+ return dup;
170
+ }
171
+ async function predictLandings(patches, from, duplicateAt, reads, unstorableReason, baseline, claims, suffixFloor) {
172
+ const overlay = new Map();
173
+ const view = {
174
+ rowOf: async (id) => (overlay.has(id) ? (overlay.get(id) ?? undefined) : reads.rowOf(id)),
175
+ idsAt: async (scope, slug) => {
176
+ const ids = (await reads.idsAt(scope, slug)).filter((id) => !overlay.has(id));
177
+ for (const [id, row] of overlay)
178
+ if (row !== null && row.scope === scope && row.slug === slug)
179
+ ids.push(id);
180
+ return ids;
181
+ },
182
+ };
183
+ const scratchBaseline = new Map(baseline);
184
+ const scratchClaims = new Set(claims);
185
+ const landings = [];
186
+ for (let i = from; i < patches.length; i++) {
187
+ if (duplicateAt.has(i))
188
+ continue;
189
+ let plan;
190
+ let targetHeld = false;
191
+ try {
192
+ plan = await planSqlPatch(patches[i], view, scratchBaseline, scratchClaims, unstorableReason, suffixFloor.get(i) ?? FIRST_SUFFIX_STEP);
193
+ if (plan.kind === "update") {
194
+ const { id, scope, slug } = plan.entry;
195
+ targetHeld = (await view.idsAt(scope, slug)).some((holder) => holder !== id);
196
+ }
197
+ }
198
+ catch {
199
+ continue;
200
+ }
201
+ if (plan.kind === "conflict")
202
+ continue;
203
+ landings.push(...plan.landings);
204
+ if (plan.kind === "add") {
205
+ overlay.set(plan.stored.id, { scope: plan.stored.scope, slug: plan.stored.slug, rev: plan.rev, frontmatter: plan.frontmatter });
206
+ scratchClaims.add(slugKey(plan.stored.scope, plan.stored.slug));
207
+ }
208
+ else if (plan.kind === "update") {
209
+ if (!targetHeld)
210
+ overlay.set(plan.entry.id, { scope: plan.entry.scope, slug: plan.entry.slug, rev: plan.rev, frontmatter: plan.entry.frontmatter });
211
+ }
212
+ else {
213
+ overlay.set(plan.id, null);
214
+ }
215
+ }
216
+ return landings;
217
+ }
218
+ function movedAfterAdmission(patch, unasked) {
219
+ const l = unasked[0];
220
+ return {
221
+ op: patch.op,
222
+ id: patch.id,
223
+ reason: `landing moved after admission (${JSON.stringify(`${l.scope}/${l.slug}`)} was not admitted: a concurrent writer moved the entry or took the name after this batch was asked about and began writing); not written — the next apply asks about it again`,
224
+ };
225
+ }
226
+ export async function applySqlPatches(patches, opts, leg) {
227
+ const report = { applied: [], conflicts: [] };
228
+ const duplicateAt = duplicatePositions(patches);
229
+ const baseline = createBatchCommittedBaseline();
230
+ const claims = new Set();
231
+ const suffixFloor = new Map();
232
+ const history = [];
233
+ const preparedAt = new Map();
234
+ const admit = opts?.admit;
235
+ let mayHaveWritten = false;
236
+ const callerConfirm = opts?.confirm;
237
+ const confirm = () => {
238
+ if (callerConfirm === undefined)
239
+ return;
240
+ try {
241
+ callerConfirm();
242
+ }
243
+ catch (thrown) {
244
+ throw new CallerThrow(thrown);
245
+ }
246
+ };
247
+ const record = (plan) => {
248
+ if (plan.kind === "add") {
249
+ claims.add(slugKey(plan.stored.scope, plan.stored.slug));
250
+ report.applied.push({ op: "add", id: plan.stored.id, slug: plan.stored.slug });
251
+ if (leg.appendHistory)
252
+ history.push({ id: plan.stored.id, rev: plan.rev, op: "add", scope: plan.stored.scope, snapshot: { ...plan.stored, rev: plan.rev }, writtenAtMs: leg.now() });
253
+ }
254
+ else if (plan.kind === "update") {
255
+ report.applied.push({ op: "update", id: plan.entry.id, slug: plan.entry.slug });
256
+ if (leg.appendHistory)
257
+ history.push({ id: plan.entry.id, rev: plan.rev, prevRev: plan.currentRev, op: "update", scope: plan.entry.scope, snapshot: { ...plan.entry, rev: plan.rev }, writtenAtMs: leg.now() });
258
+ }
259
+ else {
260
+ report.applied.push({ op: "delete", id: plan.id, slug: plan.current.slug });
261
+ if (leg.appendHistory)
262
+ history.push({ id: plan.id, rev: `tombstone:${plan.currentRev}`, prevRev: plan.currentRev, op: "delete", scope: plan.current.scope, writtenAtMs: leg.now() });
263
+ }
264
+ };
265
+ const predictFrom = (from) => predictLandings(patches, from, duplicateAt, leg.reads, leg.unstorableReason, baseline, claims, suffixFloor);
266
+ const commitOne = async (patch, k, admitted) => {
267
+ let issued = false;
268
+ const confirmThenIssue = () => {
269
+ confirm();
270
+ issued = true;
271
+ };
272
+ try {
273
+ for (;;) {
274
+ issued = false;
275
+ const plan = await planSqlPatch(patch, leg.reads, baseline, claims, leg.unstorableReason, suffixFloor.get(k) ?? FIRST_SUFFIX_STEP);
276
+ if (plan.kind === "conflict") {
277
+ report.conflicts.push(plan.conflict);
278
+ return [];
279
+ }
280
+ if (admitted !== undefined) {
281
+ const unasked = unadmittedOf(admitted, plan.landings);
282
+ if (unasked.length > 0)
283
+ return unasked;
284
+ }
285
+ let outcome;
286
+ if (plan.kind === "delete")
287
+ outcome = await leg.writes.remove(plan, confirmThenIssue);
288
+ else {
289
+ let prepared = preparedAt.get(k);
290
+ if (prepared === undefined) {
291
+ prepared = { value: await leg.writes.prepare(patch.entry) };
292
+ preparedAt.set(k, prepared);
293
+ }
294
+ outcome = plan.kind === "add" ? await leg.writes.add(plan, prepared.value, confirmThenIssue) : await leg.writes.update(plan, prepared.value, confirmThenIssue);
295
+ }
296
+ switch (outcome.kind) {
297
+ case "committed":
298
+ mayHaveWritten = true;
299
+ record(plan);
300
+ return [];
301
+ case "lost":
302
+ report.conflicts.push(outcome.conflict);
303
+ return [];
304
+ case "slug-taken":
305
+ if (plan.kind === "add")
306
+ suffixFloor.set(k, plan.suffixAt + 1);
307
+ continue;
308
+ case "moved":
309
+ continue;
310
+ default: {
311
+ const unknown = outcome;
312
+ throw new Error(`unknown write outcome ${JSON.stringify(unknown)}`);
313
+ }
314
+ }
315
+ }
316
+ }
317
+ catch (err) {
318
+ if (err instanceof CallerThrow)
319
+ throw err;
320
+ if (issued)
321
+ mayHaveWritten = true;
322
+ report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
323
+ return [];
324
+ }
325
+ };
326
+ let k = 0;
327
+ const attempt = async (admitted) => {
328
+ if (admitted !== undefined)
329
+ requireLandingsAdmitted(admitted, await predictFrom(k));
330
+ while (k < patches.length) {
331
+ const patch = patches[k];
332
+ if (duplicateAt.has(k)) {
333
+ report.conflicts.push({ op: patch.op, id: patch.id, reason: "duplicate id in batch: another add/update for this id is already planned (copied file keeping its frontmatter id?)" });
334
+ k++;
335
+ continue;
336
+ }
337
+ const unasked = await commitOne(patch, k, admitted);
338
+ if (unasked.length > 0 && admitted !== undefined && !mayHaveWritten) {
339
+ throw new LandingsNeedAdmission(distinctLandings([...unasked, ...unadmittedOf(admitted, await predictFrom(k))]));
340
+ }
341
+ if (unasked.length > 0)
342
+ report.conflicts.push(movedAfterAdmission(patch, unasked));
343
+ k++;
344
+ }
345
+ };
346
+ try {
347
+ await admittingLandings(admit, attempt);
348
+ }
349
+ catch (err) {
350
+ throw err instanceof CallerThrow ? err.thrown : err;
351
+ }
352
+ finally {
353
+ if (leg.appendHistory && history.length > 0)
354
+ await leg.appendHistory(history);
355
+ }
356
+ return report;
357
+ }
358
+ //# sourceMappingURL=memory-engine-sql-apply.js.map
@@ -1,5 +1,6 @@
1
1
  import type { MemoryHistoryAppendRow } from "./memory-sync-store-pg.js";
2
2
  import type { PgEmbedder } from "./pg-query.js";
3
+ import { type SqlApplyOpts } from "./memory-engine-sql-apply.js";
3
4
  import type { MemoryBackend, MemoryEntry, MemoryEntryHeader, NotePatch, PatchReport, ScoredMemoryEntry } from "@sema-agent/core";
4
5
  import type { Pool } from "mysql2/promise";
5
6
  /** Table names (single source) — SAME names as PG_MEMORY_ENGINE_TABLES (the two dialects never share
@@ -38,6 +39,8 @@ export declare class TiDBMemoryEngineBackend implements MemoryBackend {
38
39
  private readonly history?;
39
40
  /** Cumulative lost-row count — audit-line breakage must itself be auditable. */
40
41
  private historyRowsLost;
42
+ /** 交给共享驱动器的读口 / 写口 / history 冲刷(构造末尾铸一次)。 */
43
+ private readonly leg;
41
44
  /** [ref] rung indicator — TiDB v1 sits on the lexical floor (Pg twin parity surface). */
42
45
  get vectorMode(): "lexical";
43
46
  constructor(pool: Pool, opts?: TiDBMemoryEngineBackendOptions);
@@ -53,15 +56,38 @@ export declare class TiDBMemoryEngineBackend implements MemoryBackend {
53
56
  limit?: number;
54
57
  exposureBands?: boolean;
55
58
  }): Promise<ScoredMemoryEntry[]>;
56
- applyPatches(patches: readonly NotePatch[]): Promise<PatchReport>;
57
- private applyOne;
58
- /** The row's rev NOW, or undefined if the row is gone. The existence distinction is the whole point
59
- * (codex lens-3): a concurrent delete must not be mistaken for an idempotent already-at-target write. */
60
- private freshRevOrMissing;
61
- /** When the conditional write reports zero rows (a write landed inside the SELECT→write window), the
62
- * report's `currentRev` must be the rev NOW — re-reporting the pre-race SELECT value could claim
63
- * `baseRev === currentRev` alongside a "rev mismatch" reason. Row gone ⇒ fallback (Pg parity). */
64
- private freshRev;
59
+ /** core 落点问询协议的能力位:`applyPatches` 兑现 `opts.admit` / `opts.confirm`(读法见 `memory-engine-sql-apply.ts` 头注)。 */
60
+ readonly admitsLandings: true;
61
+ /** 判与驱动器只在 `memory-engine-sql-apply.ts` 一处(Pg 孪生同注);本腿只供读口、MySQL 协议方言写口(写语句绑定计划的投影)与 history 冲刷。
62
+ * `opts.anchoredRoot` 是带目录的后端的事,本腿没有目录 ⇒ 不读。 */
63
+ applyPatches(patches: readonly NotePatch[], opts?: SqlApplyOpts): Promise<PatchReport>;
64
+ private rowOf;
65
+ private idsAt;
66
+ /** 写不落之后的现读:这个 id 的行此刻的 rev 与投影(没了 ⇒ undefined)。 */
67
+ private freshRow;
68
+ /**
69
+ * add:拆成「计划时有行 ⇒ UPDATE by id / 没有 ⇒ INSERT」(见文件头:MySQL 的 ON DUPLICATE KEY UPDATE 会被 `(scope, slug)` 键抢占、改写他人行,
70
+ * 禁用)。UPDATE 腿只覆盖仍在计划投影上的行;零 AFFECTED 行 ⇒ 现读:行没了 = 被并发删掉 ⇒ 转 INSERT 腿、同一拼写(改前同);
71
+ * 行在别处 ⇒ `moved`;行还在计划的投影上且已是这一份内容 = 匹配但值逐字相同(连接未开 FOUND_ROWS 时只数改动行)⇒ 已落;
72
+ * 行还在计划的投影上却不是这一份内容 = 判与现读之间行被挪走又挪回 ⇒ 响亮抛(记成这一条的 io error 冲突,与 PG 孪生同答)。INSERT 腿的 ER_DUP_ENTRY 按键名分诊:
73
+ * PRIMARY = 同 id 的行在判与写之间被别的副本插入 ⇒ `moved`(驱动器按现状重判,guard / 跨 scope 拒照判);`uq_…scope_slug` = 名在计划之后
74
+ * 被占 ⇒ `slug-taken`。每次重发写语句前都调 confirm(它是检查,幂等)。
75
+ */
76
+ private writeAdd;
77
+ /** update:条件 = 判过的 rev **且**判过的投影(rev 是内容哈希、不含 scope / slug)。零 AFFECTED 行 ⇒ 这一条的 CAS 按 **rev** 判(core 契约:stale
78
+ * `baseRev` 的 update 是报告的冲突、带 `currentRev`,不按字节 —— 对手把行写成与本次 update 逐字节相同的目标态,这一条也是冲突,Pg 孪生 RETURNING
79
+ * 零行同答):
80
+ * · 一条什么都没改的 update(新 rev == 判过的 rev 且投影不动)在没开 FOUND_ROWS 的连接上匹配了也数 0 ⇒ 现读行仍在判过的 rev + 投影上 = 条件成立 = 已落;
81
+ * 这是零行唯一能是 applied 的形 —— 目标 rev 与判过的 rev 不同的 update 一定改动行(rev 列本身变了),零行即未匹配;
82
+ * 行被对手改走又改回判过的 rev 时,按 rev 它没变过(与 File 腿的比对、与共享判里「A→B→A 让 stale baseRev 重新当前」同一读法),这一条本来就是什么都没改 ⇒ 照样已落;
83
+ * · 内容未变而投影变了 = `moved`;其余 = CAS 冲突,`currentRev` 报现值。
84
+ * 🔴 行存在性是承重的:判与写之间行被并发删掉时 affectedRows 也是 0,现读对没了的行答 undefined ⇒ 落冲突(逐字相同的 update 也一样),两方言同答。 */
85
+ private writeUpdate;
86
+ /** delete:条件同 update;DELETE 的 affectedRows 数的是删掉的行(FOUND_ROWS 只影响 UPDATE):0 = 行变了 / 挪了 / 没了。 */
87
+ private writeDelete;
88
+ /** BEST-EFFORT history append(见 TiDBMemoryEngineBackendOptions.history 的如实取舍):entry 写已提交,审计行追加失败不许让报告
89
+ * 失败 —— 吞 + warn,永不抛;appendHistory 按 (id, rev) 幂等,调用方重试安全。 */
90
+ private appendHistory;
65
91
  getConsolidationCursor(scope: string): Promise<string | undefined>;
66
92
  setConsolidationCursor(scope: string, cursor: string): Promise<void>;
67
93
  }