@sema-agent/server 7.145.0 → 7.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/MIGRATION.md +492 -0
  2. package/USAGE.md +218 -47
  3. package/deploy/facts/CHANGES.json +25 -0
  4. package/deploy/facts/README.md +57 -0
  5. package/deploy/facts/lanes.json +54 -0
  6. package/deploy/facts/lanes.schema.json +57 -0
  7. package/deploy/facts/sandbox-rbac.json +113 -0
  8. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  9. package/deploy/facts/sealed-key.json +9 -0
  10. package/deploy/facts/sealed-key.schema.json +52 -0
  11. package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
  12. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  13. package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
  14. package/deploy/sema-up/chart/templates/server.yaml +4 -0
  15. package/deploy/sema-up/chart/values.yaml +7 -0
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
  17. package/dist/adoption/import-limits.d.ts +6 -0
  18. package/dist/adoption/import-limits.js +7 -0
  19. package/dist/adoption/import.d.ts +62 -0
  20. package/dist/adoption/import.js +107 -0
  21. package/dist/adoption/wire.d.ts +52 -0
  22. package/dist/adoption/wire.js +9 -0
  23. package/dist/approval-ask-machine.d.ts +2 -2
  24. package/dist/approval-card.d.ts +3 -12
  25. package/dist/approval-card.js +0 -4
  26. package/dist/approval-gate-currency.d.ts +1 -1
  27. package/dist/approval-gate-currency.js +1 -1
  28. package/dist/approval-reconciler.d.ts +1 -1
  29. package/dist/boot/deployment-mods.d.ts +11 -1
  30. package/dist/boot/deployment-mods.js +15 -2
  31. package/dist/boot/device-lane.js +2 -0
  32. package/dist/boot/engine-lease.d.ts +193 -21
  33. package/dist/boot/engine-lease.js +146 -20
  34. package/dist/boot/execution-env.d.ts +4 -0
  35. package/dist/boot/execution-env.js +12 -0
  36. package/dist/boot/exit-boundary.d.ts +50 -0
  37. package/dist/boot/exit-boundary.js +32 -0
  38. package/dist/boot/exit-last.d.ts +20 -4
  39. package/dist/boot/exit-last.js +21 -4
  40. package/dist/boot/governance-seams.js +1 -0
  41. package/dist/boot/memory-consolidation.d.ts +29 -17
  42. package/dist/boot/memory-consolidation.js +26 -15
  43. package/dist/boot/reapers.d.ts +12 -4
  44. package/dist/boot/reapers.js +39 -15
  45. package/dist/boot/resolve-spec.d.ts +2 -0
  46. package/dist/boot/resolve-spec.js +38 -15
  47. package/dist/boot/runner-deps.js +1 -1
  48. package/dist/boot/session-faces.js +3 -1
  49. package/dist/boot/shutdown.js +27 -9
  50. package/dist/boot/stage-01-config.js +1 -1
  51. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  52. package/dist/boot/stage-03-store-backend.js +2 -2
  53. package/dist/boot/stage-04-stores.d.ts +1 -0
  54. package/dist/boot/stage-05-execution-env.d.ts +3 -0
  55. package/dist/boot/stage-05-execution-env.js +3 -3
  56. package/dist/boot/stage-06-runners.d.ts +3 -0
  57. package/dist/boot/stage-06-runners.js +11 -10
  58. package/dist/boot/stage-07-capability-layer.d.ts +3 -0
  59. package/dist/boot/stage-07-capability-layer.js +7 -2
  60. package/dist/boot/stage-08-reapers.d.ts +3 -0
  61. package/dist/boot/stage-08-reapers.js +3 -3
  62. package/dist/boot/stage-09-leader.d.ts +3 -0
  63. package/dist/boot/stage-10-http-server.d.ts +3 -0
  64. package/dist/boot/stage-10-http-server.js +3 -2
  65. package/dist/boot/stores.d.ts +1 -0
  66. package/dist/boot/stores.js +35 -19
  67. package/dist/boot/workflow-orchestration.d.ts +1 -1
  68. package/dist/boot/workflow-orchestration.js +2 -1
  69. package/dist/capabilities/composite-members.d.ts +3 -1
  70. package/dist/capabilities/composite-members.js +3 -1
  71. package/dist/capabilities/scenarios.d.ts +2 -2
  72. package/dist/capability-facts.d.ts +18 -1
  73. package/dist/capability-facts.js +25 -7
  74. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  75. package/dist/config-catalog.js +13 -4
  76. package/dist/config-provider.d.ts +2 -2
  77. package/dist/config-types.d.ts +43 -4
  78. package/dist/config.d.ts +6 -1
  79. package/dist/config.js +67 -11
  80. package/dist/deleted-session-ids.d.ts +19 -0
  81. package/dist/deleted-session-ids.js +26 -0
  82. package/dist/deploy-facts.d.ts +155 -0
  83. package/dist/deploy-facts.js +94 -0
  84. package/dist/device-ws-hub.d.ts +48 -3
  85. package/dist/device-ws-hub.js +48 -2
  86. package/dist/error-code-family.d.ts +35 -0
  87. package/dist/error-code-family.js +26 -0
  88. package/dist/fleet/drain-entry.d.ts +39 -3
  89. package/dist/fleet/drain-entry.js +6 -0
  90. package/dist/fleet/fleet-bus.d.ts +2 -1
  91. package/dist/hooks/branch-transcript.d.ts +1 -1
  92. package/dist/hooks/branch-transcript.js +1 -0
  93. package/dist/hooks/classic-stations.d.ts +25 -8
  94. package/dist/hooks/classic-stations.js +29 -3
  95. package/dist/hooks/hook-runner.d.ts +33 -16
  96. package/dist/hooks/hook-runner.js +166 -73
  97. package/dist/hooks/hook-source.d.ts +14 -2
  98. package/dist/hooks/hook-source.js +8 -0
  99. package/dist/http/active-run-conflict.d.ts +1 -1
  100. package/dist/http/active-run-conflict.js +1 -1
  101. package/dist/http/admission.js +11 -1
  102. package/dist/http/checkpoint-ctx.d.ts +59 -71
  103. package/dist/http/checkpoint-ctx.js +34 -40
  104. package/dist/http/dispatch.js +18 -2
  105. package/dist/http/durable-run-leg.d.ts +5 -0
  106. package/dist/http/durable-run-leg.js +1 -0
  107. package/dist/http/execution-context.d.ts +4 -0
  108. package/dist/http/execution-context.js +9 -0
  109. package/dist/http/health-self-report.d.ts +6 -2
  110. package/dist/http/health-self-report.js +3 -2
  111. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  112. package/dist/http/memory-compliance-failure-reply.js +2 -15
  113. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  114. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  115. package/dist/http/principal-gate.d.ts +35 -12
  116. package/dist/http/principal-gate.js +16 -12
  117. package/dist/http/request-guards.d.ts +1 -1
  118. package/dist/http/request-guards.js +5 -5
  119. package/dist/http/resume-legs.d.ts +22 -0
  120. package/dist/http/resume-legs.js +26 -17
  121. package/dist/http/route-ctx.d.ts +11 -10
  122. package/dist/http/route-table.js +2 -0
  123. package/dist/http/routes/adoption.d.ts +11 -0
  124. package/dist/http/routes/adoption.js +80 -6
  125. package/dist/http/routes/agents-roster.js +1 -0
  126. package/dist/http/routes/approvals-assistant.js +2 -1
  127. package/dist/http/routes/background.js +1 -0
  128. package/dist/http/routes/capabilities.js +4 -1
  129. package/dist/http/routes/diagnostics.d.ts +9 -14
  130. package/dist/http/routes/diagnostics.js +10 -20
  131. package/dist/http/routes/engine.d.ts +31 -0
  132. package/dist/http/routes/engine.js +81 -0
  133. package/dist/http/routes/memory-bundle.js +3 -0
  134. package/dist/http/routes/memory-consolidation.js +3 -5
  135. package/dist/http/routes/memory-origin.d.ts +1 -1
  136. package/dist/http/routes/memory-origin.js +2 -4
  137. package/dist/http/routes/memory-policy.js +5 -1
  138. package/dist/http/routes/observability.js +3 -6
  139. package/dist/http/routes/runs.js +7 -3
  140. package/dist/http/routes/session-sync.js +12 -25
  141. package/dist/http/routes/sessions-list.d.ts +1 -1
  142. package/dist/http/routes/sessions.js +4 -0
  143. package/dist/http/routes/tasks.js +23 -5
  144. package/dist/http/routes/trace-usage.js +1 -1
  145. package/dist/http/run-concurrency-cap.d.ts +86 -0
  146. package/dist/http/run-concurrency-cap.js +54 -0
  147. package/dist/http/server.d.ts +15 -12
  148. package/dist/http/server.js +18 -3
  149. package/dist/http/stored-body-replay.d.ts +9 -6
  150. package/dist/http/stored-body-replay.js +19 -5
  151. package/dist/http/wire-types.d.ts +8 -3
  152. package/dist/json-body-limit.d.ts +8 -0
  153. package/dist/json-body-limit.js +2 -0
  154. package/dist/leader/diffout.d.ts +1 -1
  155. package/dist/local-data-root.d.ts +2 -2
  156. package/dist/memory-operator-faces.d.ts +9 -4
  157. package/dist/memory-scope-stores.d.ts +9 -7
  158. package/dist/memory-scope-stores.js +3 -14
  159. package/dist/memory-scope.d.ts +36 -0
  160. package/dist/memory-scope.js +32 -1
  161. package/dist/net-address.d.ts +53 -0
  162. package/dist/net-address.js +111 -0
  163. package/dist/observability/fail-open.d.ts +14 -10
  164. package/dist/observability/fail-open.js +14 -10
  165. package/dist/orchestration/workflow-notify-journal.js +2 -3
  166. package/dist/org-delivery-gate.js +1 -1
  167. package/dist/peer-directory.d.ts +6 -12
  168. package/dist/peer-directory.js +5 -1
  169. package/dist/plugins/caching-session-store.d.ts +3 -1
  170. package/dist/plugins/caching-session-store.js +3 -0
  171. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  172. package/dist/plugins/checkpoint-store-face.js +152 -0
  173. package/dist/plugins/file-run-store.d.ts +0 -6
  174. package/dist/plugins/file-run-store.js +1 -12
  175. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  176. package/dist/plugins/fork-routing-session-store.js +2 -2
  177. package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
  178. package/dist/plugins/local-checkpoint-store.d.ts +2 -2
  179. package/dist/plugins/local-checkpoint-store.js +2 -1
  180. package/dist/plugins/local-session-store.d.ts +28 -5
  181. package/dist/plugins/local-session-store.js +32 -8
  182. package/dist/plugins/memory-engine-pg.d.ts +29 -6
  183. package/dist/plugins/memory-engine-pg.js +96 -214
  184. package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
  185. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  186. package/dist/plugins/memory-engine-tidb.d.ts +35 -9
  187. package/dist/plugins/memory-engine-tidb.js +97 -227
  188. package/dist/plugins/memory-key-guards.d.ts +1 -1
  189. package/dist/plugins/memory-origin-law.d.ts +3 -3
  190. package/dist/plugins/one-time-migrations.d.ts +32 -56
  191. package/dist/plugins/one-time-migrations.js +25 -117
  192. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  193. package/dist/plugins/permission-rule-store-file.js +8 -1
  194. package/dist/plugins/pg-pool.js +1 -1
  195. package/dist/plugins/pg-session-storage.d.ts +17 -4
  196. package/dist/plugins/pg-session-storage.js +8 -4
  197. package/dist/plugins/run-store-sql.js +2 -2
  198. package/dist/plugins/schema-ensure-legs.js +2 -2
  199. package/dist/plugins/session-fork.d.ts +31 -9
  200. package/dist/plugins/session-fork.js +3 -2
  201. package/dist/plugins/session-placement.d.ts +4 -2
  202. package/dist/plugins/sql-json-column.d.ts +5 -1
  203. package/dist/plugins/store-backend.d.ts +11 -8
  204. package/dist/plugins/store-backend.js +8 -7
  205. package/dist/plugins/store-contracts.d.ts +1 -11
  206. package/dist/plugins/store-contracts.js +0 -9
  207. package/dist/plugins/store-sweep.d.ts +63 -0
  208. package/dist/plugins/store-sweep.js +48 -0
  209. package/dist/plugins/tidb-pool.js +1 -1
  210. package/dist/plugins/tidb-session-store.d.ts +16 -3
  211. package/dist/plugins/tidb-session-store.js +8 -4
  212. package/dist/prompt-screen.d.ts +6 -9
  213. package/dist/prompt-screen.js +2 -5
  214. package/dist/rules-consent.d.ts +20 -27
  215. package/dist/rules-consent.js +82 -6
  216. package/dist/run-cancel-context.d.ts +4 -1
  217. package/dist/run-cancel-context.js +2 -1
  218. package/dist/runs.js +1 -1
  219. package/dist/sandbox-egress-policy.js +6 -11
  220. package/dist/sandbox-rbac-rules.d.ts +88 -0
  221. package/dist/sandbox-rbac-rules.js +80 -0
  222. package/dist/sealed-key-layout.d.ts +17 -0
  223. package/dist/sealed-key-layout.js +4 -0
  224. package/dist/sealed-key.js +5 -5
  225. package/dist/security.d.ts +38 -6
  226. package/dist/security.js +9 -2
  227. package/dist/session-notify-door.d.ts +5 -3
  228. package/dist/session-resident-background.d.ts +57 -0
  229. package/dist/session-resident-background.js +20 -0
  230. package/dist/session-sync-kernel.d.ts +53 -14
  231. package/dist/session-sync-kernel.js +70 -1
  232. package/dist/session-sync.d.ts +5 -3
  233. package/dist/session-workspace.d.ts +1 -0
  234. package/dist/session-workspace.js +1 -0
  235. package/dist/sighup-idle.d.ts +9 -7
  236. package/dist/sighup-idle.js +4 -5
  237. package/dist/spec-fields.d.ts +16 -0
  238. package/dist/spec-fields.js +7 -0
  239. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  240. package/dist/stored-request-env-credentials-m38.js +8 -0
  241. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  242. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
  243. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
  244. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  245. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  246. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  247. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  248. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
  249. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  250. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  251. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  252. package/dist/task-settings.d.ts +59 -4
  253. package/dist/task-settings.js +50 -4
  254. package/dist/tool-approval.d.ts +2 -2
  255. package/dist/trace/core-keyset-guard.d.ts +8 -7
  256. package/dist/trace/engine-notice-wire.d.ts +1 -1
  257. package/dist/trace/engine-notice-wire.js +2 -0
  258. package/dist/trace/exit-seat.d.ts +6 -0
  259. package/dist/trace/exit-seat.js +1 -0
  260. package/dist/trace/project.js +9 -0
  261. package/dist/trace/redact.d.ts +13 -2
  262. package/dist/trace/redact.js +305 -24
  263. package/dist/trace/self-minted-wire.d.ts +326 -8
  264. package/dist/trace/self-minted-wire.js +125 -7
  265. package/dist/trace/wire-projection-faces.d.ts +1 -1
  266. package/dist/trace/wire-projection-faces.js +1 -1
  267. package/dist/usage-analytics.d.ts +4 -0
  268. package/package.json +12 -4
  269. package/scripts/drain-check-local.mjs +8 -29
  270. package/scripts/drain-check.mysql.sql +3 -24
  271. package/scripts/drain-check.pg.sql +3 -24
  272. package/skills/update-config.md +1 -1
  273. package/wire-changes/server@7.146.0.json +3221 -0
  274. package/dist/approval-batch-census.d.ts +0 -27
  275. package/dist/approval-batch-census.js +0 -27
@@ -1,10 +1,10 @@
1
1
  import { jaccardDistance, termSet } from "@sema-agent/core";
2
2
  import { readFrontmatterColumn } from "./memory-engine-vector-util.js";
3
3
  import { decodeJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
4
- import { computeEntryRev, serializeEntryFile } from "@sema-agent/core";
5
- import { pgHasUnstorable } from "./pg-safe-json.js";
6
- import { assertMemoryScopeWidth, memoryEntryKeyWidthRefusal } from "./memory-key-guards.js";
7
- import { ambiguousOriginRefusal, createBatchCommittedBaseline, exposureBandOf, exposureCarriage, originWhitewashRefusal, rememberBatchCommitted, distilledWhitewashRefusal, distilledCarriage, unknownPatchOpRefusal, } from "./memory-origin-law.js";
4
+ import { serializeEntryFile } from "@sema-agent/core";
5
+ import { assertMemoryScopeWidth } from "./memory-key-guards.js";
6
+ import { exposureBandOf, exposureCarriage, distilledCarriage } from "./memory-origin-law.js";
7
+ import { applySqlPatches, } from "./memory-engine-sql-apply.js";
8
8
  import { isMysqlDupKeyError } from "./sql-errors.js";
9
9
  import { ensureIndexes } from "./ensure-index.js";
10
10
  import { MEMORY_ENGINE_INDEXES, PG_MEMORY_ENGINE_TABLES } from "./memory-engine-pg.js";
@@ -40,6 +40,7 @@ const isDupEntry = isMysqlDupKeyError;
40
40
  function isPrimaryKeyDup(err) {
41
41
  return isDupEntry(err) && /for key '[^']*PRIMARY'/i.test(String(err.message ?? ""));
42
42
  }
43
+ const AT_PLANNED_PROJECTION = "CAST(scope AS BINARY) = CAST(? AS BINARY) AND CAST(slug AS BINARY) = CAST(? AS BINARY)";
43
44
  function inPlaceholders(count) {
44
45
  return Array.from({ length: count }, () => "?").join(", ");
45
46
  }
@@ -56,6 +57,7 @@ export class TiDBMemoryEngineBackend {
56
57
  clock;
57
58
  history;
58
59
  historyRowsLost = 0;
60
+ leg;
59
61
  get vectorMode() {
60
62
  return "lexical";
61
63
  }
@@ -66,6 +68,18 @@ export class TiDBMemoryEngineBackend {
66
68
  }
67
69
  this.clock = opts.now ?? Date.now;
68
70
  this.history = opts.history;
71
+ this.leg = {
72
+ reads: { rowOf: (id) => this.rowOf(id), idsAt: (scope, slug) => this.idsAt(scope, slug) },
73
+ writes: {
74
+ prepare: async () => undefined,
75
+ add: (w, prepared, confirm) => this.writeAdd(w, prepared, confirm),
76
+ update: (w, prepared, confirm) => this.writeUpdate(w, prepared, confirm),
77
+ remove: (w, confirm) => this.writeDelete(w, confirm),
78
+ },
79
+ unstorableReason: "unstorable_bytes (utf8mb4 cannot store NUL/lone surrogates without mangling; strip them at the source — the store never rewrites content)",
80
+ now: () => this.clock(),
81
+ ...(this.history !== undefined ? { appendHistory: (rows) => this.appendHistory(rows) } : {}),
82
+ };
69
83
  }
70
84
  async selectRows(sql, params) {
71
85
  const [rows] = await this.pool.query(sql, params);
@@ -141,242 +155,98 @@ export class TiDBMemoryEngineBackend {
141
155
  scored.sort((a, b) => (bands ? exposureBandOf(a) - exposureBandOf(b) : 0) || a.score - b.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
142
156
  return scored.slice(0, limit);
143
157
  }
144
- async applyPatches(patches) {
145
- const report = { applied: [], conflicts: [] };
146
- const nonDeleteIds = new Set();
147
- const plannedSlugs = new Set();
148
- const historyRows = [];
149
- const originBaseline = createBatchCommittedBaseline();
150
- for (const patch of patches) {
151
- try {
152
- if (patch.op !== "delete") {
153
- if (nonDeleteIds.has(patch.id)) {
154
- 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?)" });
155
- continue;
156
- }
157
- nonDeleteIds.add(patch.id);
158
- }
159
- await this.applyOne(patch, report, plannedSlugs, historyRows, originBaseline);
160
- }
161
- catch (err) {
162
- report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
163
- }
164
- }
165
- if (this.history && historyRows.length > 0) {
166
- try {
167
- await this.history.appendHistory(historyRows);
168
- }
169
- catch (err) {
170
- this.historyRowsLost += historyRows.length;
171
- console.warn(`TiDBMemoryEngineBackend: best-effort history append failed (${historyRows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
172
- }
173
- }
174
- return report;
158
+ admitsLandings = true;
159
+ async applyPatches(patches, opts) {
160
+ return applySqlPatches(patches, opts, this.leg);
161
+ }
162
+ async rowOf(id) {
163
+ const rows = await this.selectRows(`SELECT slug, rev, scope, ${jsonColumnText("mysql", "frontmatter")} FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
164
+ const r = rows[0];
165
+ if (r === undefined)
166
+ return undefined;
167
+ return { scope: String(r.scope), slug: String(r.slug), rev: String(r.rev), frontmatter: readFrontmatter(r.frontmatter, id) };
175
168
  }
176
- async applyOne(patch, report, plannedSlugs, historyRows, originBaseline) {
169
+ async idsAt(scope, slug) {
170
+ const rows = await this.selectRows(`SELECT id FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE scope = ? AND slug = ?`, [scope, slug]);
171
+ return rows.map((r) => String(r.id));
172
+ }
173
+ async freshRow(id) {
174
+ const rows = await this.selectRows(`SELECT rev, scope, slug FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
175
+ const r = rows[0];
176
+ return r === undefined ? undefined : { rev: String(r.rev), scope: String(r.scope), slug: String(r.slug) };
177
+ }
178
+ async writeAdd({ stored, rev, prior }, _prepared, confirm) {
177
179
  const T = TIDB_MEMORY_ENGINE_TABLES.entry;
178
- {
179
- const refusal = unknownPatchOpRefusal(patch.op);
180
- if (refusal !== undefined) {
181
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
182
- return;
183
- }
184
- }
185
- if (patch.op !== "delete" && patch.entry !== undefined && patch.entry.id !== patch.id) {
186
- report.conflicts.push({ op: patch.op, id: patch.id, reason: `patch id ${JSON.stringify(patch.id)} != entry id ${JSON.stringify(patch.entry.id)} (malformed patch refused)` });
187
- return;
188
- }
189
- if (patch.op !== "delete" && patch.entry !== undefined) {
190
- const refusal = memoryEntryKeyWidthRefusal(patch.entry.scope, patch.entry.slug);
191
- if (refusal !== undefined) {
192
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
193
- return;
194
- }
195
- }
196
- if (patch.op !== "delete" && patch.entry !== undefined) {
197
- const refusal = ambiguousOriginRefusal(patch.entry.frontmatter);
198
- if (refusal !== undefined) {
199
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
200
- return;
201
- }
202
- }
203
- if (patch.op === "add") {
204
- const entry = patch.entry;
205
- if (!entry) {
206
- report.conflicts.push({ op: "add", id: patch.id, reason: "add patch without an entry" });
207
- return;
208
- }
209
- if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
210
- report.conflicts.push({ op: "add", id: entry.id, reason: "unstorable_bytes (utf8mb4 cannot store NUL/lone surrogates without mangling; strip them at the source — the store never rewrites content)" });
211
- return;
212
- }
213
- const prior = await this.selectRows(`SELECT scope, slug, rev, ${jsonColumnText("mysql", "frontmatter")} FROM ${T} WHERE id = ?`, [entry.id]);
214
- const priorRow = prior.length > 0 ? prior[0] : undefined;
215
- let existsById = priorRow !== undefined;
216
- {
217
- const committedBaseFm = rememberBatchCommitted(originBaseline, entry.id, priorRow !== undefined ? readFrontmatter(priorRow.frontmatter, entry.id) : undefined);
218
- const refusal = originWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
219
- if (refusal !== undefined) {
220
- report.conflicts.push({ op: "add", id: entry.id, reason: refusal });
221
- return;
222
- }
223
- const dRefusal = distilledWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
224
- if (dRefusal !== undefined) {
225
- report.conflicts.push({ op: "add", id: entry.id, reason: dRefusal });
226
- return;
227
- }
228
- }
229
- if (patch.guard === "absent" && priorRow) {
230
- const currentRev = String(priorRow.rev);
231
- if (currentRev !== computeEntryRev(entry)) {
232
- report.conflicts.push({ op: "add", id: entry.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev });
233
- return;
234
- }
235
- if (String(priorRow.scope) !== entry.scope || String(priorRow.slug) !== entry.slug) {
236
- report.conflicts.push({ op: "add", id: entry.id, reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${String(priorRow.scope)}/${String(priorRow.slug)}`)}; add-if-absent refuses to duplicate)`, currentRev });
237
- return;
238
- }
239
- }
240
- if (priorRow) {
241
- const held = String(priorRow.scope);
242
- if (held !== entry.scope) {
243
- report.conflicts.push({ op: "add", id: entry.id, reason: `id already exists in scope ${JSON.stringify(held)} (cross-scope add refused)` });
244
- return;
245
- }
246
- }
247
- let slug = entry.slug;
248
- for (let n = 2;; n++) {
249
- const derivedRefusal = memoryEntryKeyWidthRefusal(entry.scope, slug);
250
- if (derivedRefusal !== undefined) {
251
- report.conflicts.push({ op: "add", id: entry.id, reason: `${derivedRefusal} (slug collision suffix "-${n - 1}" no longer fits the column — shorten the entry name)` });
252
- return;
253
- }
254
- const key = `${entry.scope}|${slug}`;
255
- if (!plannedSlugs.has(key)) {
256
- const taken = await this.selectRows(`SELECT id FROM ${T} WHERE scope = ? AND slug = ?`, [entry.scope, slug]);
257
- const otherId = taken.find((r) => String(r.id) !== entry.id);
258
- if (!otherId) {
259
- const stored = { ...entry, slug };
260
- const rev = computeEntryRev(stored);
261
- const sizeBytes = Buffer.byteLength(serializeEntryFile(stored), "utf8");
262
- try {
263
- if (existsById) {
264
- const res = await this.write(`UPDATE ${T} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ?`, [stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes, stored.id]);
265
- if (res.affectedRows === 0) {
266
- const still = await this.selectRows(`SELECT id FROM ${T} WHERE id = ?`, [stored.id]);
267
- if (still.length === 0) {
268
- existsById = false;
269
- continue;
270
- }
271
- }
272
- }
273
- else {
274
- await this.write(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)`, [stored.id, stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes]);
275
- }
180
+ const sizeBytes = Buffer.byteLength(serializeEntryFile(stored), "utf8");
181
+ let overwrite = prior;
182
+ for (;;) {
183
+ try {
184
+ if (overwrite !== undefined) {
185
+ const params = [stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes, stored.id, overwrite.scope, overwrite.slug];
186
+ confirm();
187
+ const res = await this.write(`UPDATE ${T} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ? AND ${AT_PLANNED_PROJECTION}`, params);
188
+ if (res.affectedRows === 0) {
189
+ const fresh = await this.freshRow(stored.id);
190
+ if (fresh === undefined) {
191
+ overwrite = undefined;
192
+ continue;
276
193
  }
277
- catch (err) {
278
- if (isDupEntry(err)) {
279
- if (isPrimaryKeyDup(err)) {
280
- existsById = true;
281
- continue;
282
- }
283
- slug = `${entry.slug}-${n}`;
284
- continue;
285
- }
286
- throw err;
194
+ if (fresh.scope !== overwrite.scope || fresh.slug !== overwrite.slug)
195
+ return { kind: "moved" };
196
+ if (fresh.rev !== rev) {
197
+ throw new Error(`memory-engine: the add of ${JSON.stringify(stored.id)} wrote no row, yet the row is still at the planned projection with other content — refusing to report it either way`);
287
198
  }
288
- plannedSlugs.add(key);
289
- report.applied.push({ op: "add", id: stored.id, slug: stored.slug });
290
- if (this.history)
291
- historyRows.push({ id: stored.id, rev, op: "add", scope: stored.scope, snapshot: { ...stored, rev }, writtenAtMs: this.clock() });
292
- return;
293
199
  }
294
200
  }
295
- slug = `${entry.slug}-${n}`;
296
- }
297
- }
298
- const cur = await this.selectRows(`SELECT slug, rev, scope, ${jsonColumnText("mysql", "frontmatter")} FROM ${T} WHERE id = ?`, [patch.id]);
299
- if (cur.length === 0) {
300
- report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
301
- return;
302
- }
303
- const currentRev = String(cur[0].rev);
304
- const currentSlug = String(cur[0].slug);
305
- const currentScope = String(cur[0].scope);
306
- const committedFm = readFrontmatter(cur[0].frontmatter, patch.id);
307
- const committedBaseFm = rememberBatchCommitted(originBaseline, patch.id, committedFm);
308
- if (patch.op === "update" && patch.entry !== undefined) {
309
- if (committedFm.provenance?.kind === "repo_file") {
310
- const next = patch.entry.frontmatter;
311
- const stripsProvenance = next.provenance === undefined;
312
- const stripsTrust = committedFm.trust !== undefined && next.trust === undefined;
313
- if (stripsProvenance || stripsTrust) {
314
- report.conflicts.push({
315
- op: "update",
316
- id: patch.id,
317
- reason: `repo_file provenance whitewash refused: update drops ${stripsProvenance ? "provenance" : "trust"} from a repo-ingested entry (malformed patch refused)`,
318
- });
319
- return;
201
+ else {
202
+ const params = [stored.id, stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes];
203
+ confirm();
204
+ await this.write(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)`, params);
320
205
  }
321
206
  }
322
- const refusal = originWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
323
- if (refusal !== undefined) {
324
- report.conflicts.push({ op: "update", id: patch.id, reason: refusal });
325
- return;
326
- }
327
- const dRefusal = distilledWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
328
- if (dRefusal !== undefined) {
329
- report.conflicts.push({ op: "update", id: patch.id, reason: dRefusal });
330
- return;
331
- }
332
- }
333
- if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
334
- report.conflicts.push({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev });
335
- return;
336
- }
337
- if (patch.op === "delete") {
338
- const res = await this.write(`DELETE FROM ${T} WHERE id = ? AND rev = ?`, [patch.id, currentRev]);
339
- if (res.affectedRows === 0) {
340
- report.conflicts.push({ op: "delete", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: await this.freshRev(patch.id, currentRev) });
341
- return;
207
+ catch (err) {
208
+ if (!isDupEntry(err))
209
+ throw err;
210
+ return isPrimaryKeyDup(err) ? { kind: "moved" } : { kind: "slug-taken" };
342
211
  }
343
- report.applied.push({ op: "delete", id: patch.id, slug: currentSlug });
344
- if (this.history)
345
- historyRows.push({ id: patch.id, rev: `tombstone:${currentRev}`, prevRev: currentRev, op: "delete", scope: currentScope, writtenAtMs: this.clock() });
346
- return;
347
- }
348
- const entry = patch.entry;
349
- if (!entry) {
350
- report.conflicts.push({ op: "update", id: patch.id, reason: "update patch without an entry" });
351
- return;
212
+ return { kind: "committed" };
352
213
  }
353
- if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
354
- report.conflicts.push({ op: "update", id: patch.id, reason: "unstorable_bytes (utf8mb4 cannot store NUL/lone surrogates without mangling; strip them at the source — the store never rewrites content)" });
214
+ }
215
+ async writeUpdate({ entry, rev, currentRev, current, baseRev }, _prepared, confirm) {
216
+ const params = [entry.scope, entry.slug, JSON.stringify(entry.frontmatter), entry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(entry), "utf8"), entry.id, currentRev, current.scope, current.slug];
217
+ confirm();
218
+ const res = await this.write(`UPDATE ${TIDB_MEMORY_ENGINE_TABLES.entry} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ? AND rev = ? AND ${AT_PLANNED_PROJECTION}`, params);
219
+ if (res.affectedRows > 0)
220
+ return { kind: "committed" };
221
+ const fresh = await this.freshRow(entry.id);
222
+ const atPlanned = fresh !== undefined && fresh.rev === currentRev && fresh.scope === current.scope && fresh.slug === current.slug;
223
+ const writesNothingNew = rev === currentRev && entry.scope === current.scope && entry.slug === current.slug;
224
+ if (atPlanned && writesNothingNew)
225
+ return { kind: "committed" };
226
+ if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
227
+ return { kind: "moved" };
228
+ return { kind: "lost", conflict: { op: "update", id: entry.id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
229
+ }
230
+ async writeDelete({ id, currentRev, current, baseRev }, confirm) {
231
+ confirm();
232
+ const res = await this.write(`DELETE FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ? AND rev = ? AND ${AT_PLANNED_PROJECTION}`, [id, currentRev, current.scope, current.slug]);
233
+ if (res.affectedRows > 0)
234
+ return { kind: "committed" };
235
+ const fresh = await this.freshRow(id);
236
+ if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
237
+ return { kind: "moved" };
238
+ return { kind: "lost", conflict: { op: "delete", id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
239
+ }
240
+ async appendHistory(rows) {
241
+ if (!this.history)
355
242
  return;
243
+ try {
244
+ await this.history.appendHistory(rows);
356
245
  }
357
- const rev = computeEntryRev(entry);
358
- const res = await this.write(`UPDATE ${T} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ? AND rev = ?`, [entry.scope, entry.slug, JSON.stringify(entry.frontmatter), entry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(entry), "utf8"), entry.id, currentRev]);
359
- if (res.affectedRows === 0) {
360
- const fresh = await this.freshRevOrMissing(entry.id);
361
- if (fresh === rev) {
362
- report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
363
- if (this.history)
364
- historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
365
- return;
366
- }
367
- report.conflicts.push({ op: "update", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: fresh ?? currentRev });
368
- return;
246
+ catch (err) {
247
+ this.historyRowsLost += rows.length;
248
+ console.warn(`TiDBMemoryEngineBackend: best-effort history append failed (${rows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
369
249
  }
370
- report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
371
- if (this.history)
372
- historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
373
- }
374
- async freshRevOrMissing(id) {
375
- const rows = await this.selectRows(`SELECT rev FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
376
- return rows.length > 0 ? String(rows[0].rev) : undefined;
377
- }
378
- async freshRev(id, fallback) {
379
- return (await this.freshRevOrMissing(id)) ?? fallback;
380
250
  }
381
251
  async getConsolidationCursor(scope) {
382
252
  const rows = await this.selectRows(`SELECT \`cursor\` FROM ${TIDB_MEMORY_ENGINE_TABLES.cursor} WHERE scope = ?`, [scope]);
@@ -22,7 +22,7 @@ export declare const MEMORY_SYNC_PEER_COLUMN_CHARS = 190;
22
22
  export declare function assertSlugWidth(slug: string): void;
23
23
  export declare function assertMemoryScopeWidth(scope: string): void;
24
24
  /**
25
- * 一个 entry 写(add / update)的两个键宽一起判 —— 两方言的 `applyOne` 在**任何 I/O 之前**调用它。
25
+ * 一个 entry 写(add / update)的两个键宽一起判 —— 两方言共用的判(`memory-engine-sql-apply.ts` 的 `planSqlPatch`)在**任何 I/O 之前**调用它。
26
26
  *
27
27
  * 为什么两条腿共用一个入口而不是各自展开:add 与 update 写的是**同两列**(update 的
28
28
  * `SET scope = …, slug = …` 会改盘也会改名),R5 那批只护住了 add ⇒ 一次改名就能把超宽 slug 送进
@@ -30,8 +30,8 @@
30
30
  * ① **判据本身**({@link originWhitewashRefusal}):`committedOriginOf` / `originEquals` 都用 core 的
31
31
  * 导出实现,**不重写** —— 它们要处理 `frontmatter.origin` 与「保留在 `extra` 里的 origin 形字节块」
32
32
  * 两种承载形(legacy / 外来),自己写一份近似的等于给洗白留一条旁路。
33
- * ② **批次基线**({@link rememberBatchOrigin}):两支 SQL 后端逐条 patch 直打真库(没有 File backend
34
- * 那种「先规划整批再落盘」的阶段),所以同批 `delete` 之后再 `add` 时,库里已经没有那一行了 ——
33
+ * ② **批次基线**({@link rememberBatchCommitted}):两支 SQL 后端的提交阶段逐条 patch 现判、直打真库(落点问询的
34
+ * 计划阶段只是只读预测,不是 File backend 那种「先规划整批再落盘」),所以同批 `delete` 之后再 `add` 时,库里已经没有那一行了 ——
35
35
  * 只看当下的库会把它误判成合法新生命。基线 map 按**本批第一次触碰**记下该 id 的已提交 origin,
36
36
  * 之后同批的任何 op 都按那一份判。⇒「同批 delete+re-add 拒 / 已提交墓碑后 add 放」这条分界
37
37
  * (core 契约逐字要求的那条)才成立。
@@ -128,7 +128,7 @@ export declare function rememberBatchCommitted(baseline: BatchCommittedBaseline,
128
128
  /**
129
129
  * 未知 op 拼写的**前置**拒绝(codex R1-[high],验真后采纳;**既有**缺口,不是本批引入)。
130
130
  *
131
- * 病:两支 SQL 后端的 `applyOne` 形状是「`if (op === "add") {…}` → 落到 update/delete 段」,而段内
131
+ * 病:两支 SQL 后端当时各一份的 `applyOne`(今两腿共用的判 `memory-engine-sql-apply.ts` 的 `planSqlPatch`)形状是「`if (op === "add") {…}` → 落到 update/delete 段」,而段内
132
132
  * 的两道白洗守卫(repo_file provenance / 本模块的 origin 不可变律)都写成 `if (patch.op === "update")`。
133
133
  * ⇒ 一个**词表外**的 op(`"upsert"` / 打错的字 / 将来 core 加的新词)会:跳过两道守卫 → 走到 update
134
134
  * 的 SQL → 把行改掉 → 在 `report.applied` 里报成一次 update。TypeScript 的联合型是**编译期**的,
@@ -24,7 +24,7 @@
24
24
  * ⇒ 换成本段:**升一次级把存量字节改完,兼容臂当场删干净**。代价是每一条在它的窗内每次启动都要跑一遍(第二次起全是
25
25
  * 零命中的空转);收益是窗关之后可以把那一条连同它的 SQL 一起删,而读腿从引入那一版起就只有**一种**读法。
26
26
  *
27
- * ## 已退役的 M1–M5 与 M14
27
+ * ## 已退役的 M1–M8 与 M14
28
28
  * 退役的整树快照索引表(M1)、退役的单座 steering 列(M2)、被上游改了名的闭集词 `unresolvable` → `ancestor_marked`(M3)三条的改写、计数与读数
29
29
  * 窗关后已全部删码,登记行一并删。跳过了它们直接升的库由起服对账一族的拒启臂接住(`schema-consistency.ts` 头注「第二道对账」一节:两件退役 schema
30
30
  * 任一在场 ⇒ 拒启、点名出路;先于一切建表)—— 那一道没有窗,所以不在本文件里。本段入口({@link runSqlOneTimeMigrations})不问这一问。
@@ -36,27 +36,18 @@
36
36
  * 出路是运维给那些行各填一只互不相同的随机令牌,或删会话(MIGRATION 写了升级序)。
37
37
  * LKG 的 formatVersion 1 迁移(M14:7.98.0 及以前写在默认路径的旧缓存文件迁进身份箱;非店迁移,不写库)同样已删码(本版提前于窗关删),登记行一并删;它没有自己的拒启臂 —— 那是缓存文件、不是数据:
38
38
  * `CONFIG_LKG_PATH` 指到旧文件 ⇒ `loadLkg` 的 1 臂答 `config_lkg_unusable`(env 兜底),默认路径上的旧文件名不是身份箱的文件名形、不再被读,中心可达时第一份干净候选照常写出身份箱。
39
+ * M6 / M7 / M8 同样已删码(本版删;三条的窗 2026-11-04 … 2026-11-05 关,发版日前都已关),登记行一并删。逐条写跳过了它直接升的库(以及滚动升级窗里旧副本新写的旧形行)由谁接住:
40
+ * ① run 死亡判决码回填(M6;连同 SQL 行映射里的读侧半场):没有响亮臂 —— 只有句子、码列为空的 `failed` 行(只有 ≤7.115.x 的写者铸得出;7.116.0 起的写者恒同写码)不再被判成持有者死亡:
41
+ * 用户输入受理账本的收敛判词(`user-input-ledger.ts` `judgeOpen`)把它落到「其余」臂 `leg_over`(补落 `settled{leg_end}`、不告知),那条 run 上丢掉的 steer 不再告诉用户;`GET /v1/runs/:id` 上 `errorCode` 缺席、只剩 `error` 句子。
42
+ * ② 停驻行 allow 读法记号的拒臂(M7):不写库,删的是 allow 读法记号的写点与「按记号判」的读法;拒臂留为按写者版本的**永久门**(`http/checkpoint-ctx.ts` 顶注「allow 读法问」)——
43
+ * 体里带非空 allow、而行的写者版本证不出 ≥ 7.117.0(缺席 / 读不出 / 更早)⇒ 续跑重放拒 409 `checkpoint.unsupported_version`(响亮,出路 = 取消后作为新任务重提)。
44
+ * 这一门不随窗走:日历窗关不证明旧行不在。已存行上的记号键原样留着、无人读;7.117.0–7.123.x 写下、带非空 allow 的行(有记号、没有写者版本)同样拒 —— 证据只认写者版本一个源。
45
+ * 反向的一格(如实登记):本版写下的行不再带这只记号,滚动升级 / 回滚窗里仍跑 7.145.x 及以前的副本读到**任何**体里带非空 allow 的本版行(提交体从壳透传的
46
+ * CC settings 常带它)时照它自己的一问判,由那一版答 409 `checkpoint.unsupported_version`(带写者 / 读者两版本键;响亮,出路 = 由本版副本续跑)。
47
+ * ③ 停驻行披露位换名(M8):没有响亮臂 —— 仍带旧键 `shadowedRule` 的停驻行在运维待批队列上只缺结构化披露 `allowRuleShadowed`;旧键的文本仍经脱敏叶表「认不得的键按内容脱敏」一条
48
+ * 脱敏后原样显示(`observability/run-terminal.ts` `redactRiskDescriptor`),卡上 `message` 里引擎写好的那句话不受影响。
39
49
  *
40
50
  * ## 窗内的迁移(逐条的失败方向刻意不同)
41
- * · **M6 run 死亡判决码** —— 7.116.0 起 run 店的两只死亡判决(失联收割 / 重启孤儿回收)在行上同写机读码(`error_code` =
42
- * `run.stalled` / `run.orphaned`,词表属主 `store-contracts.ts` 的 `RUN_HOLDER_DEATH_CODES`),读者(`isHolderDeathVerdict`)只认码。
43
- * 存量行只有句子、码列空 ⇒ **写回半场**:起服把「`failed` ∧ 码列空 ∧ 句子是那两句(接管臂的括注形按前缀认)」的行补上码
44
- * (SQL 两条 `UPDATE`;local 腿 = `FileRunStore.migrateLegacyHolderDeathCodes`)。**读侧半场**:滚动升级窗里 ≤7.115.x 的副本还会写只有句子的行
45
- * (起服写回覆盖不到窗内新写的行)⇒ SQL 两孪生的行映射经 `readLegacyHolderDeathCode` 把这种行读成码 —— 它是本条的一半,窗关随本条一起删
46
- * (见登记表 M6 的 `removal`)。local 车道没有滚动窗(数据根独占:窗内不会有旧写者与本进程并存),读侧半场不在 File 店上。
47
- *
48
- * · **M7 停驻行 allow 读法记号的拒臂**(7.117.0,core 7.42.0)—— 不是改写,是**持久数据「响亮拒」那一半**:续跑重放体里带非空
49
- * `settings.permissions.allow`、而 ctx 上的读法记号不是当前的 `"allow_layer"`(名单时代无记号 / 表态时代 `"statement"`)⇒ 认领之前 409、行字节不动。
50
- * 规则、两句拒句与写点在 `http/checkpoint-ctx.ts`;本条只登记它的窗(7.115.0 引入的同一只拒臂当时没有登记,7.117.0 起它覆盖两代旧词,登记在这里)。
51
- * 没有读数键(它不写库)。
52
- * · **M8 停驻行披露位换名**(7.117.0,core 7.42.0 [ref])—— `checkpoint.risk_descriptor` 里 7.41.x 引擎写下的 `shadowedRule`(字符串:命中却清不掉的
53
- * 持久 allow 规则原文)在 7.42.0 引擎里换成 `allowRuleShadowed: { member, entries, omitted? }[]`,旧键不再有人读。旧键只由规则店成员铸
54
- * (core 7.41.2 `gate-lanes.ts` 的披露臂是它唯一的铸点;本仓的策略从不自铸它)⇒ **一次性改写**:`{ ..., shadowedRule: v }` →
55
- * `{ ..., allowRuleShadowed: [{ member: "persisted", entries: [v] }] }`(旧值是引擎拼好的「最多五条 + and N more」一串,原样作为一条条目,不拆)。
56
- * 列是 TEXT(两方言),改写在应用侧解析 + 按 `token` CAS 回写(`WHERE risk_descriptor = <读到的原文>`;第二跑零命中)。**没有读侧半场**:滚动窗里
57
- * 旧副本新写的旧键行只缺结构化披露(卡上 `message` 那句话引擎已经写好),旧键的文本由脱敏叶表的「认不得的键按内容脱敏」一条兜住
58
- * (`observability/run-terminal.ts` `redactRiskDescriptor`)—— 不为它开第二种读法。local 车道没有这一列(停驻行在引擎自己的 File 店里,本仓
59
- * 没有合法缝改写那些字节,盘上格式归引擎):旧键留在原地、不被读,文本同样经脱敏叶表兜住。
60
51
  * · **M9 park 指针索引改主键**(7.118.0,core 7.44.0 [ref])—— `workflow_agent_session` 的主键由 `(session_id)` 改成 `(session_id, run_id)`:
61
52
  * 停驻持有者有了引擎写的位(`parkedBy` / `generation`)之后,判决要看到点名同一个子会话的每一条记录(续跑链 / 分叉),单列主键下后写覆盖先写。
62
53
  * 表是派生投影 ⇒ **复制 + 原子换名**:照中央 DDL 建新形暂存表 → 一条 `INSERT … SELECT` 整表复制 → 正表换成待删名、暂存表换成正表名、删待删旧表
@@ -71,7 +62,7 @@
71
62
  * (起服时没有 principal,把它判给任何人都是编造)。本条是一只**窗内才生效的行为臂**:窗开着时,带 principal 的第一次提交(attach)认领
72
63
  * 这种会话(写进那一格,一行 info `session_owner_claimed`);窗关之后(运行期读本表 M10 行的 `removableAfter`,见 {@link migrationWindowOpen})
73
64
  * 它照今天答无主,删码因此是零行为变化。认领的安全前提是单用户:local 后端起服门拒 `REQUIRE_PRINCIPAL=true`,授权口也只在
74
- * `REQUIRE_PRINCIPAL` 关时把 principal 递给店认领。没有起服读数(它不在起服时写库,与 M7 同形)。
65
+ * `REQUIRE_PRINCIPAL` 关时把 principal 递给店认领。没有起服读数(它不在起服时写库)。
75
66
  * · **M11 持久规则里 scope 不被引擎收的行**(7.120.0,引擎 7.46.0)—— 7.119.0 及更早的本仓入口(`/v1/rules` 写口、两条导入面)按
76
67
  * 「root 非空」收 project scope,引擎 7.45 也收;引擎 7.46.0 把 project root 收窄成**完整绝对路径**(`isValidDurableScope`),本仓入口
77
68
  * 同版改调同一只谓词。存量的 `project:myproj` 一类行在新引擎的读侧被丢(每次 run 一条 `permission.rule_row_dropped`),而撤销口删不动它
@@ -86,7 +77,7 @@
86
77
  * ⚠️ **够不到的一格(如实登记)**:local 车道的持久规则在**引擎自己的** File 分区里 —— 引擎的写面对这种 scope 的加 / 墓碑一律拒,
87
78
  * 本仓没有合法缝删它们,改那份盘上格式是下游改上游。那里的存量坏行照旧由引擎读侧丢并告知;出路候引擎给
88
79
  * 一条删除缝。
89
- * · **M12 停驻行模式词读法记号的拒臂**(7.122.0)—— 与 M7 同形,持久数据「响亮拒」那一半:7.122.0 起一条 run 的模式词只有存储体顶层 `permissionMode`
80
+ * · **M12 停驻行模式词读法记号的拒臂**(7.122.0)—— 持久数据「响亮拒」那一半:7.122.0 起一条 run 的模式词只有存储体顶层 `permissionMode`
90
81
  * 一个源(提交入口盖运维 `AUTONOMY=plan` 的地板一次),更早的行体里是请求原词、运维的 plan 由治理层每段重钳。续跑重放之前:本部署此刻有入口地板 ∧
91
82
  * ctx 上没有当前记号 `"entry_word"` ∧ 体的生效词被地板钳会变 ⇒ 认领之前 409、行字节不动。规则、拒句与写点在 `http/checkpoint-ctx.ts` 顶注第三问。
92
83
  * 没有读数键(它不写库)。
@@ -158,9 +149,9 @@
158
149
  * 不改写存下的字节(体按原样留在 ctx 里),是一只**窗内才生效的行为臂** —— 窗开着时(运行期读本表 M19 行的 `removableAfter`,见 {@link migrationWindowOpen}),
159
150
  * **只在续跑重放腿**、**只对判官判不过的那一格**按升级前的读法重读一次(`stored-request-tool-axes-m19.ts`),产物再交同一只判官(不过 ⇒ 整条不进的原臂),
160
151
  * 真挂上的这类 server 各一行运维 warn `mcp_tool_axes_read_as_before_upgrade`;窗关之后照今天答(整条不进),删码因此是零行为变化。
161
- * 窗 = 发布日 + 30 天 = 停驻行的终局兜底窗缺省(`APPROVAL_TERMINAL_BACKSTOP_MS` 缺省 30 天)—— 与 M7 / M12 同一条论证。没有起服读数(它不写库)。
152
+ * 窗 = 发布日 + 30 天 = 停驻行的终局兜底窗缺省(`APPROVAL_TERMINAL_BACKSTOP_MS` 缺省 30 天)—— 窗关时缺省部署上升级前停驻的行都已被收割。没有起服读数(它不写库)。
162
153
  * 窗按**发布日**算、停驻行的期限按**停驻时刻**算 ⇒ 三类部署会有升级前停驻的行活过窗、窗关后回到「整条不进」:发布后才升级的部署(发布日到它升级那天之间
163
- * 停驻的行)、把 `APPROVAL_TERMINAL_BACKSTOP_MS` 调长的部署、滚动升级里仍跑 7.129.x 的副本在窗内新写的行。与 M7 / M18 一样如实登记,不为它们加长窗。
154
+ * 停驻的行)、把 `APPROVAL_TERMINAL_BACKSTOP_MS` 调长的部署、滚动升级里仍跑 7.129.x 的副本在窗内新写的行。与 M18 一样如实登记,不为它们加长窗。
164
155
  * **A2A 一面**(core 7.53.0 [ref] 提货批,同一只重读座、同一个窗,不另立迁移号):请求体 `a2aPeers[].toolAxes` 的判官也换成了引擎的 `readToolAxes`,7.131.x 的 A2A 读者
165
156
  * 对每只 skill 的记录只挑三个轴、多余成员静默忽略 ⇒ 续跑重放腿同一只重读座按 **7.131.x 的 A2A 读法**重读一次(重读座按面分读者:两面升级前的读法不同 ——
166
157
  * 7.131.x 的 A2A 读者对已知轴写坏是整条丢对端,重读照旧整条丢,不把 7.131.x 当时没挂上的对端救活),真挂上的对端一行 `a2a_tool_axes_read_as_before_upgrade`。窗仍按 7.130.0 的发布日算 ——
@@ -227,7 +218,7 @@
227
218
  * · **M25 单用户记忆项目层换键形**(7.133.0)—— 不在店里、不在起服里(与 M10 同为**窗内才存在的行为臂**,但它是改写):项目层键从 `repo:<sha256(项目根)[:24]>`
228
219
  * (7.98.0–7.132.x)换成带主体、跨设备的 `userrepo:<属主段>/<档>.<摘要>`(文法 `project-layer-key.ts`)。退役键是路径哈希、反推不出路径 ⇒ 起服没法枚举改写;
229
220
  * 改为**每个项目第一次跑任务时**由项目层准备一步(`memory-project-layer.ts` `createMemoryProjectLayers`)把该 checkout 的 `repo:` 层经 core `migrateScope`
230
- * 折进新键(File 与两只 SQL 孪生同一条;id 保留、CAS,冲突留原地下次再试)。本条不写起服读数(`reportKeys` 空,与 M7 / M10 同形);折了什么由运行期 info
221
+ * 折进新键(File 与两只 SQL 孪生同一条;id 保留、CAS,冲突留原地下次再试)。本条不写起服读数(`reportKeys` 空,与 M10 同形);折了什么由运行期 info
231
222
  * `memory_project_layer_folded` 说。常设的另一条律(`r` 档时本 checkout 的 `p` 档折进当前档)不是迁移,不随本条删。
232
223
  * **曾属本条的另一半已退役(如实)**:同步客户端腿的旧游标文件 `sync-cursor-<peer>.json`(只按 peer 分区)的收编臂。引擎 7.59.0 起游标必带店绑定 `store`,
233
224
  * 升级前落盘的旧文件都没有这一员,收编的形判从不认它 ⇒ 臂对任何存量文件都不可达,已整条删码(收编函数、守卫旗标、日志行一并删,零引用有钉:
@@ -256,7 +247,7 @@
256
247
  * `http/checkpoint-ctx.ts` 末段「凭据位密封」;本处不重列)在 `checkpoint_ctx` 里只以封签存在,续跑上下文读口对凭据位上的明文答 409 `conflict.checkpoint_ctx_unsealable`(`reason:"plaintext"`)。升级之前写下的
257
248
  * 行是明文 ⇒ **起服扫一遍、原地封好**:不在本文件的迁移段里(封要保管店的封签器,而本段跑在建店的 web-admin 运行时能交给它之前的店层 ——
258
249
  * 与 M10 / M19 / M25 同为在本段之外跑的条目),编排在 `checkpoint-ctx-seal-m28.ts`(起服第 6 段,checkpoint 店建成之后、任何路由装配之前调一次),
259
- * 店腿是两孪生共有的 ctx 行改写腿 `rewriteCtxRows`(`checkpoint-store-sql.ts` `CheckpointCtxRowsRewriter`;M30 用同一只;SQL:键集分页 + 按原文 CAS、`updated_at_ms` 不动;local:逐档原子重写、信封的 `updatedAt` 不动),
250
+ * 店腿是两孪生共有的 ctx 行改写腿 `rewriteCtxRows`(`checkpoint-store-face.ts` `CheckpointCtxRowsRewriter`;M30 用同一只;SQL:键集分页 + 按原文 CAS、`updated_at_ms` 不动;local:逐档原子重写、信封的 `updatedAt` 不动),
260
251
  * 行改写是读写两侧同一只封口(`sealStoredCheckpointCtxM28`),封的是「读口会答 `plaintext` 的每一个值」(与开口同一只判词)—— 7.135.0 闭集加了一位
261
252
  * (command 条目的 `plugin.options`)之后,7.134.0 写下的带记号行在那一位上的明文也落在这一条里、同窗补封(本条没有新窗);7.136.0 再加四位(子进程的命令行:MCP stdio 传输与
262
253
  * command 条目各自的 `command` / `args`,第 3 代)同理 —— 无记号行与 7.134.0 / 7.135.0 写下的第 1 / 2 代行上的明文命令行同窗补封。不删行、不改续跑语义;读不出的行计数不动;已封与不带凭据的行零写。读数不进
@@ -357,6 +348,14 @@
357
348
  * 本版之前铸的卡信封(`approval_ask.card_json` / local 问账)上那一格还是旧名,`.strict()` 的卡 schema 只认新名。存卡的唯一读者入口 `readStoredCardEnvelope`
358
349
  * 在 M18 的读侧改写与 schema 之前把它改名(`approval-card.ts` 的 `renameRetiredSourceKey`,交浅拷贝、零写回,响亮计数)。不起服改写:存卡的寿命以分钟计、
359
350
  * 升级前结清在途审批是部署前置(MIGRATION 本版第 17 条),读侧接住的是滚动升级窗里旧副本新写的与升级前已结仍被读的那几行。没有读数键。
351
+ * · **M38 续跑重放腿上的存量 `settings.env` 凭据条目**(7.146.0)—— 凭据不进 `settings.env` 是本版的新规则(判据 `task-settings.ts` 的 `settingsEnvCredentialIssue`:名字是本进程的凭据变量名,
352
+ * 或值是秘密形 ⇒ 新提交 `400 request.env_credential_refused`)。升级前受理、存下的请求体(`checkpoint_ctx`;凭据位已由 M28 封好)里老壳写进去的这类条目,续跑一重放就撞同一只判据。
353
+ * 与 M19 / M20 同形:不改写存下的字节,是一只**窗内才生效的行为臂** —— 窗开着时(运行期读本表 M38 行的 `removableAfter`,`stored-request-env-credentials-m38.ts`),
354
+ * **只在续跑重放腿**,`resolveSpec` 把判据命中的键从这条腿唯一读到的那一份 `settings.env` 里剥掉(收窄方向:凭据离开模型的 shell 与 hooks,引擎自己用的凭据从进程环境取;剥空 = 空表,
355
+ * 登记它覆盖会话上一条登记 —— 会话 shell env 注册表「缺席 = 留着上一条」,不铸空表就把上一条留给了 shell),
356
+ * 恰一行运维 warn `settings_env_credentials_dropped`(按命中类计数,不带键名与值),任务照续;存体续跑预判窗内不拦。窗关之后 ⇒ 预判与 `resolveSpec` 同一只判据拒
357
+ * (续跑口 409 `resume_blocked_by_policy`,`blockedBy` = 本码),删码因此是零行为变化。窗 = 发布日 + 30 天 = 停驻行的终局兜底窗缺省(与 M19 / M20 同一条论证与同三类逃出窗的部署:
358
+ * 发布后才升级的、调长了 `APPROVAL_TERMINAL_BACKSTOP_MS` 的、滚动升级里旧副本在窗内新写的行),另一类如实登记:窗内续跑过、又停驻到窗外的任务,写回的存体仍带那些条目(本条零写)。没有起服读数(它不写库)。
360
359
  *
361
360
  * ## 收据账(一次起服一只,每一条迁移同一只)
362
361
  * 每一步把它**已提交**的改写 / 删除与点名读数当场记进同一只收据账({@link MigrationReceipts}):计数随每次提交累加、行随每次提交追加、形读数在那一步落定时写。走完 ⇒
@@ -366,8 +365,7 @@
366
365
  * 如实的残余:提交与那一行日志之间进程被杀、或一条提交的确认在连接上丢了 —— 收据没有耐久载体(不为短命的迁移另建迁移账表:有 schema 形可当「跑过了」标记的几条用它自己的形 —— M9 的主键宽度、M17 的列名;改值类的几条没有这种标记,为它们造一张账表 / 一个旋钮,就是给一条短命的迁移留一份长命的状态)。
367
366
  *
368
367
  * ## 幂等
369
- * 改写的几条都可重复跑(M6:`WHERE error_code IS NULL`;
370
- * M8 / M18:字样扫描 + CAS 回写 —— 写过的行不再命中;M17 的改写只在改名那一拍跑,第二跑列名已是新名 ⇒ 零读零写;续判时已带戳的行零动作;
368
+ * 改写的几条都可重复跑(M18:字样扫描 + CAS 回写 —— 写过的行不再命中;M17 的改写只在改名那一拍跑,第二跑列名已是新名 ⇒ 零读零写;续判时已带戳的行零动作;
371
369
  * M24:正表 scope 列在场探针 —— 换名之后只补收尾(删待删旧表),换名之前被打断则暂存表删掉重建、回填只补缺的属主记录(`NOT EXISTS`);
372
370
  * M27:只按判官挑 —— 删过的键不再被扫到)。并发起动由 {@link runSqlOneTimeMigrations} 的 advisory 锁 + 每步的后置条件判据兜住(见那里)。
373
371
  */
@@ -383,12 +381,6 @@ import { type ImportedLayerRootAllowRetired, type ImportedLayerRootBucketSkipped
383
381
  import { type LocalPlacementBackfillSeat, type UnusableArchiveWord } from "../execution-placement.js";
384
382
  /** 迁移读数(启动日志一行写全;测试按它断言,不靠日志文本)。 */
385
383
  export interface OneTimeMigrationReport {
386
- /** M6:本次给「只有句子」的死亡判决行补上机读码的 run 行数(SQL `task_run` / local `run.json`)。非零 = 这次迁移真写了存量行,必须让运维看见。 */
387
- readonly holderDeathCodeRowsBackfilled: number;
388
- /** M8:本次把 `checkpoint.risk_descriptor` 的旧披露键 `shadowedRule` 改写成 `allowRuleShadowed` 的行数(SQL 独有;local 恒 0)。非零 = 真写了存量行。 */
389
- readonly allowRuleShadowRowsMigrated: number;
390
- /** M8:带旧键字样、但这一格的 JSON 读不懂 ⇒ 没改写的行数(留给读口自己的响亮臂;非零 = 运维该看一眼这些行)。SQL 独有;local 恒 0。 */
391
- readonly allowRuleShadowRowsUnreadable: number;
392
384
  /** M9:workflow park 指针索引的主键 —— `reshaped` = 本次把只有 `session_id` 的主键改成 `(session_id, run_id)`;`current` = 早已是新形
393
385
  * (新库 / 第二跑);`file-ledger` = local 文件车道(账本一行本来就是一条 run 的指针集,没有主键可改)。 */
394
386
  readonly workflowParkIndexKey: "reshaped" | "current" | "file-ledger";
@@ -590,7 +582,7 @@ export declare class OneTimeMigrationInterruptedError extends Error {
590
582
  * 规则(窗长 30 天、窗关后的第一个 minor 删码、门怎么判)在本文件头注「窗」一节,只写那一次。
591
583
  */
592
584
  export interface OneTimeMigrationWindow {
593
- /** 本文件里的条目名(头注「窗内的迁移」的 M6…)。 */
585
+ /** 本文件里的条目名(头注「窗内的迁移」的 M9…)。 */
594
586
  readonly id: string;
595
587
  /** 引入这条迁移的版本 = 第一只含其代码的发布 tag(取证:`git log -S '<该条的常量名>' -- src/plugins/one-time-migrations.ts`
596
588
  * 找引入提交 → `git tag --contains <提交> --sort=creatordate` 取最早)。 */
@@ -616,7 +608,7 @@ export declare const ONE_TIME_MIGRATIONS: readonly OneTimeMigrationWindow[];
616
608
  /**
617
609
  * 一条登记行的窗**此刻**开着没有(`today` = UTC 日历日 YYYY-MM-DD):未发布形(`removableAfter: null`)⇒ 开;否则今天不晚于 `removableAfter` ⇒ 开
618
610
  * (窗关当天仍开,与到期门「今天严格晚于才红」同一条边界)。
619
- * 给**窗内才生效的行为臂**(M10 的认领、M19 / M20 的续跑重读)与本文件迁移段之外的起服扫描(M28 / M30)用:过了窗就停,不等删码车 —— 删码因此是零行为变化,而窗只写在本表这一处。
611
+ * 给**窗内才生效的行为臂**(M10 的认领、M19 / M20 的续跑重读、M38 的续跑剥键)与本文件迁移段之外的起服扫描(M28 / M30)用:过了窗就停,不等删码车 —— 删码因此是零行为变化,而窗只写在本表这一处。
620
612
  */
621
613
  export declare function migrationWindowOpen(window: Pick<OneTimeMigrationWindow, "removableAfter">, today: string): boolean;
622
614
  /**
@@ -625,8 +617,8 @@ export declare function migrationWindowOpen(window: Pick<OneTimeMigrationWindow,
625
617
  * 还没有日期可写)⇒ 响亮抛,不铸一句带空日期的句子。
626
618
  */
627
619
  export declare function migrationWindowEnd(id: string): string;
628
- /** local 车道上 SQL 独有的几条(M8 / M9 / M11 / M17 / M18 / M21 / M23 / M24 / M26 / M27 / M29)的读数(M6 与 M32 的回填两车道都有、M33 只在 local,local 腿的读数由 `LocalBackend.runOneTimeMigrations` 现算):那几张表 / 列在文件底座上从来不存在 ⇒ 如实答 absent / 0。 */
629
- export declare const NO_SQL_MIGRATIONS: Omit<OneTimeMigrationReport, "holderDeathCodeRowsBackfilled" | "executionPlacementsBackfilled" | "askExecutionLanesBackfilled" | "executionPlacementSessionsUnreadable" | "localArchiveRowFactsBackfilled" | "localArchivesAnonymized" | "localArchivesKeptStamped" | "localArchivesUnreadable" | "localArchiveSnapshotsRecovered" | "askJournalRecordsUpgraded" | "importedLayerRootAllowsRetired" | "importedLayerRootBucketsSkipped">;
620
+ /** local 车道上 SQL 独有的几条(M9 / M11 / M17 / M18 / M21 / M23 / M24 / M26 / M27 / M29)的读数(M32 的回填两车道都有、M33 只在 local,local 腿的读数由 `LocalBackend.runOneTimeMigrations` 现算):那几张表 / 列在文件底座上从来不存在 ⇒ 如实答 absent / 0。 */
621
+ export declare const NO_SQL_MIGRATIONS: Omit<OneTimeMigrationReport, "executionPlacementsBackfilled" | "askExecutionLanesBackfilled" | "executionPlacementSessionsUnreadable" | "localArchiveRowFactsBackfilled" | "localArchivesAnonymized" | "localArchivesKeptStamped" | "localArchivesUnreadable" | "localArchiveSnapshotsRecovered" | "askJournalRecordsUpgraded" | "importedLayerRootAllowsRetired" | "importedLayerRootBucketsSkipped">;
630
622
  /** 启动期的日志口(logger 的子集)。两级各有其用,见 {@link logOneTimeMigrations}。 */
631
623
  export interface MigrationLogSink {
632
624
  warn(msg: string, meta?: Record<string, unknown>): void;
@@ -653,7 +645,7 @@ export interface MigrationDb {
653
645
  * 每条改表 DDL 的成功判据仍是它的**后置条件**({@link execUntil}),「另一个副本抢先把同一张表换了形」不会把滚动升级变成启动失败循环。
654
646
  *
655
647
  * ## 次序(codex r1 [medium] 同轮)
656
- * 非破坏改写(M6–M9、M18:改值不丢信息 / 复制 + 换名)在前,破坏性步骤(M11 的删行、M24 丢下跨 scope 行的换名)排在最后;
648
+ * 非破坏改写(M9、M18:改值不丢信息 / 复制 + 换名)在前,破坏性步骤(M11 的删行、M24 丢下跨 scope 行的换名)排在最后;
657
649
  * M11 自己半途失败时,拒因自带已删的行(`purgeUndurableScopeRows`)—— 否则重试看不见已删的行,证据永久消失;M24 的丢行计数在换名提交之后进收据账。
658
650
  *
659
651
  * 本函数**不问**退役 schema:带着它的库在更早处就被 `ensureSchema()` 自身拒掉了(起服对账一族 `schema-consistency.ts` 的探针口,先于建表);走公开序列
@@ -783,23 +775,7 @@ export declare function oldGrammarEntriesOf(body: unknown, rev: number): OldGram
783
775
  * 终名改名提交之后才写;`current` = 起服时已是终名);点名的行随扫到追加。
784
776
  */
785
777
  export declare function migrateSessionRuleGrammar(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
786
- /** M8 一行改写的结论:改写后的文本 / 这一行不用动 / 读不懂(解析错误原样交出,调用方计数进读数)。 */
787
- export type ShadowedRuleRewrite = {
788
- readonly kind: "rewrite";
789
- readonly text: string;
790
- } | {
791
- readonly kind: "untouched";
792
- } | {
793
- readonly kind: "unreadable";
794
- readonly error: unknown;
795
- };
796
- /**
797
- * M8 的**一行**改写(纯函数;导出给钉用):`risk_descriptor` 的 JSON 文本里顶层带字符串 `shadowedRule` ⇒ 改写(旧键删、`allowRuleShadowed`
798
- * 由旧值铸一条 `persisted` 记录;行上已经有 `allowRuleShadowed` ⇒ 只删旧键,不并);不是对象 / 没有旧键 / 旧键不是字符串 ⇒ `untouched`;
799
- * JSON 读不懂 ⇒ `unreadable`(这一行不动,交给读口自己的响亮臂;迁移不替它猜,但把它数进读数,不静默)。
800
- */
801
- export declare function migrateShadowedRuleDescriptor(text: string): ShadowedRuleRewrite;
802
- /** M18 一行改写的结论(与 M8 同形,不共用型 —— 两条各自窗关各自删):改写后的文本 / 这一行不用动 / 读不懂(解析错误原样交出,调用方计数进读数)。 */
778
+ /** M18 一行改写的结论:改写后的文本 / 这一行不用动 / 读不懂(解析错误原样交出,调用方计数进读数)。 */
803
779
  export type RetiredCardWordsRowRewrite = {
804
780
  readonly kind: "rewrite";
805
781
  readonly text: string;