@sema-agent/server 7.139.0 → 7.140.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.
- package/MIGRATION.md +181 -0
- package/USAGE.md +19 -13
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/approval-card.d.ts +6 -6
- package/dist/bench/s1/live-deps.js +3 -2
- package/dist/bench/s1/row.d.ts +5 -2
- package/dist/bench/s1/row.js +2 -22
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/execution-env.js +12 -10
- package/dist/boot/execution-lane.d.ts +8 -0
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/memory-boundary.d.ts +14 -51
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +15 -11
- package/dist/boot/memory-consolidation.js +23 -12
- package/dist/boot/resolve-spec.d.ts +3 -5
- package/dist/boot/resolve-spec.js +2 -4
- package/dist/boot/runner-deps.d.ts +3 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +2 -6
- package/dist/boot/stage-03-store-backend.js +2 -3
- package/dist/boot/stage-04-stores.d.ts +2 -6
- package/dist/boot/stage-04-stores.js +5 -5
- package/dist/boot/stage-05-execution-env.d.ts +2 -6
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -6
- package/dist/boot/stage-08-reapers.d.ts +2 -6
- package/dist/boot/stage-09-leader.d.ts +2 -6
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +5 -4
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +27 -40
- package/dist/boot/task-list-lane.d.ts +1 -1
- package/dist/boot/task-list-lane.js +1 -1
- package/dist/boot/web-admin.js +35 -9
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/config-catalog.js +2 -1
- package/dist/config-provider.d.ts +14 -13
- package/dist/config-provider.js +24 -18
- package/dist/config-types.d.ts +11 -2
- package/dist/config.js +2 -1
- package/dist/delegated-session-owner.d.ts +2 -1
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +9 -8
- package/dist/deployment-shape.js +4 -4
- package/dist/execution-lane-caps.d.ts +97 -106
- package/dist/execution-lane-caps.js +67 -83
- package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
- package/dist/http/memory-compliance-failure-reply.js +5 -0
- package/dist/http/memory-layer-reply.d.ts +30 -0
- package/dist/http/memory-layer-reply.js +24 -0
- package/dist/http/resume-legs.js +13 -16
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +8 -1
- package/dist/http/routes/memory-consolidation.js +12 -1
- package/dist/http/routes/memory-origin.js +14 -2
- package/dist/http/routes/memory-policy.js +5 -0
- package/dist/http/routes/sessions.js +28 -11
- package/dist/http/routes/tasks.js +4 -2
- package/dist/http/server.d.ts +5 -25
- package/dist/http/server.js +2 -2
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/lane-home-probe.d.ts +68 -42
- package/dist/lane-home-probe.js +53 -30
- package/dist/leader/wire.js +5 -4
- package/dist/memory-bundle-engine.d.ts +16 -9
- package/dist/memory-bundle-engine.js +29 -6
- package/dist/memory-operator-faces.d.ts +85 -30
- package/dist/memory-operator-faces.js +136 -30
- package/dist/memory-project-layer.d.ts +3 -21
- package/dist/memory-project-layer.js +11 -8
- package/dist/memory-scope-stores.d.ts +73 -0
- package/dist/memory-scope-stores.js +86 -0
- package/dist/memory-scope.d.ts +29 -5
- package/dist/memory-scope.js +16 -4
- package/dist/memory-sync-client.d.ts +20 -7
- package/dist/memory-sync-client.js +31 -13
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-sql.js +14 -14
- package/dist/plugins/approval-nonce-store.js +4 -4
- package/dist/plugins/blob-backend.d.ts +4 -4
- package/dist/plugins/blob-backend.js +7 -7
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.js +16 -16
- package/dist/plugins/device-store-sql.js +19 -19
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +8 -8
- package/dist/plugins/execution-placement-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.js +4 -4
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/mailbox-store-sql.d.ts +2 -1
- package/dist/plugins/mailbox-store-sql.js +4 -4
- package/dist/plugins/memory-engine-tidb.js +5 -5
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +10 -9
- package/dist/plugins/one-time-migrations.js +36 -36
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
- package/dist/plugins/permission-rule-store-sql.js +16 -16
- package/dist/plugins/remote-env-adb.d.ts +7 -24
- package/dist/plugins/remote-env-adb.js +22 -5
- package/dist/plugins/remote-env-device.d.ts +2 -28
- package/dist/plugins/remote-env-device.js +2 -1
- package/dist/plugins/remote-env-e2b.d.ts +18 -26
- package/dist/plugins/remote-env-e2b.js +51 -4
- package/dist/plugins/remote-env-file-error.d.ts +1 -1
- package/dist/plugins/remote-env-file-error.js +8 -2
- package/dist/plugins/remote-env-host.d.ts +19 -35
- package/dist/plugins/remote-env-host.js +26 -3
- package/dist/plugins/remote-env-k8s.d.ts +3 -14
- package/dist/plugins/remote-env-k8s.js +3 -2
- package/dist/plugins/remote-env-local-docker.d.ts +4 -15
- package/dist/plugins/remote-env-local-docker.js +5 -4
- package/dist/plugins/remote-env-ssh.d.ts +4 -24
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/resume-anchor-store-sql.js +2 -2
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +2 -2
- package/dist/plugins/retention-store-sql.d.ts +1 -1
- package/dist/plugins/retention-store-sql.js +6 -6
- package/dist/plugins/run-store-sql.js +15 -15
- package/dist/plugins/schema-consistency.d.ts +6 -6
- package/dist/plugins/schema-consistency.js +1 -1
- package/dist/plugins/schema-ensure-legs.d.ts +2 -3
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.js +1 -1
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-workspace-cell.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.js +1 -1
- package/dist/plugins/shared-memory-store-sql.js +2 -2
- package/dist/plugins/sql-driver.d.ts +10 -5
- package/dist/plugins/sql-driver.js +6 -6
- package/dist/plugins/sql-errors.js +1 -1
- package/dist/plugins/store-backend.d.ts +4 -6
- package/dist/plugins/store-backend.js +6 -6
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.js +5 -5
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.js +13 -13
- package/dist/plugins/tool-result-store-sql.d.ts +2 -2
- package/dist/plugins/tool-result-store-sql.js +3 -3
- package/dist/plugins/user-input-ledger-sql.js +2 -2
- package/dist/plugins/workflow-journal-store-sql.js +5 -5
- package/dist/plugins/workflow-run-store-sql.js +19 -19
- package/dist/plugins/write-behind-counter.d.ts +2 -3
- package/dist/plugins/write-behind-counter.js +5 -5
- package/dist/resource-suspend.d.ts +14 -12
- package/dist/resource-suspend.js +1 -1
- package/dist/resource-window.d.ts +4 -3
- package/dist/run-local.js +14 -19
- package/dist/runs.d.ts +8 -4
- package/dist/runs.js +49 -65
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-incarnation.js +1 -1
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
- package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
- package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
- package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
- package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
- package/dist/task-a2a.js +5 -6
- package/dist/task-mcp.d.ts +20 -7
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +58 -0
- package/dist/trace/self-minted-wire.js +16 -0
- package/dist/web-admin-client/candidate-gate.d.ts +11 -7
- package/dist/web-admin-client/candidate-gate.js +1 -1
- package/dist/web-admin-client/http-client.d.ts +5 -4
- package/dist/web-admin-client/http-client.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +7 -17
- package/dist/web-admin-client/read-warnings.js +5 -9
- package/package.json +2 -2
- package/wire-changes/server@7.140.0.json +184 -0
|
@@ -73,7 +73,7 @@ export function storedMailboxKeyless(scopeKey, handle) {
|
|
|
73
73
|
}
|
|
74
74
|
export const MAILBOX_KEYED_TABLES = [MAILBOX_TABLE, MAILBOX_MSG_TABLE, MAILBOX_TOMBSTONE_TABLE];
|
|
75
75
|
export function mailboxKeyDeleteSql(dialect, table) {
|
|
76
|
-
return dialect === "
|
|
76
|
+
return dialect === "mysql" ? `DELETE FROM ${table} WHERE scope_key = ? AND handle = ?` : `DELETE FROM ${table} WHERE scope_key = $1 AND handle = $2`;
|
|
77
77
|
}
|
|
78
78
|
function bufToStr(v) {
|
|
79
79
|
return Buffer.isBuffer(v) ? v.toString("utf8") : String(v);
|
|
@@ -298,7 +298,7 @@ export class TiDBMailboxStore {
|
|
|
298
298
|
if (tomb.length > 0)
|
|
299
299
|
throw tombstonedRecipientError(scope, handle);
|
|
300
300
|
if (rec.id !== undefined) {
|
|
301
|
-
const [held] = await c.query(`SELECT seq, from_id, content, sent_at_ms, ${jsonColumnText("
|
|
301
|
+
const [held] = await c.query(`SELECT seq, from_id, content, sent_at_ms, ${jsonColumnText("mysql", "hop_chain")}, ${jsonColumnText("mysql", "peer_meta")}, decision, record_id FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = ? AND handle = ? AND record_id = ? FOR UPDATE`, [scope, handle, rec.id]);
|
|
302
302
|
const replay = replayedSeq(held, scope, handle, this.logger, { ...rec, content: asUtf8Stored(rec.content), ...(rec.from !== undefined ? { from: asUtf8Stored(rec.from) } : {}) });
|
|
303
303
|
if (replay !== undefined)
|
|
304
304
|
return replay;
|
|
@@ -323,7 +323,7 @@ export class TiDBMailboxStore {
|
|
|
323
323
|
bufToStr(box.lease_owner) !== owner) {
|
|
324
324
|
return null;
|
|
325
325
|
}
|
|
326
|
-
const [msgs] = (await c.query(`SELECT seq, from_id, content, sent_at_ms, ${jsonColumnText("
|
|
326
|
+
const [msgs] = (await c.query(`SELECT seq, from_id, content, sent_at_ms, ${jsonColumnText("mysql", "hop_chain")}, ${jsonColumnText("mysql", "peer_meta")}, decision, record_id FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = ? AND handle = ? ORDER BY seq FOR UPDATE`, [scope, handle]));
|
|
327
327
|
if (msgs.length === 0)
|
|
328
328
|
return null;
|
|
329
329
|
const maxSeq = Number(msgs[msgs.length - 1].seq);
|
|
@@ -377,7 +377,7 @@ export class TiDBMailboxStore {
|
|
|
377
377
|
return;
|
|
378
378
|
await this.tx(async (c) => {
|
|
379
379
|
for (const table of MAILBOX_KEYED_TABLES)
|
|
380
|
-
await c.query(mailboxKeyDeleteSql("
|
|
380
|
+
await c.query(mailboxKeyDeleteSql("mysql", table), [scope, handle]);
|
|
381
381
|
});
|
|
382
382
|
}
|
|
383
383
|
async reap(scope, now, opts) {
|
|
@@ -108,14 +108,14 @@ export class TiDBMemoryEngineBackend {
|
|
|
108
108
|
const uniq = [...new Set(scopes)];
|
|
109
109
|
if (uniq.length === 0)
|
|
110
110
|
return [];
|
|
111
|
-
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("
|
|
111
|
+
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("mysql", "frontmatter")}, rev, mtime_ms, size_bytes FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE scope IN (${inPlaceholders(uniq.length)}) ORDER BY id`, uniq);
|
|
112
112
|
return rows.map((r) => this.headerFromRow(r));
|
|
113
113
|
}
|
|
114
114
|
async getByIds(ids) {
|
|
115
115
|
const uniq = [...new Set(ids)];
|
|
116
116
|
if (uniq.length === 0)
|
|
117
117
|
return [];
|
|
118
|
-
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("
|
|
118
|
+
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("mysql", "frontmatter")}, body, rev, mtime_ms, size_bytes FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id IN (${inPlaceholders(uniq.length)}) ORDER BY id`, uniq);
|
|
119
119
|
return rows.map((r) => this.entryFromRow(r));
|
|
120
120
|
}
|
|
121
121
|
async search(query, scopes, opts) {
|
|
@@ -128,7 +128,7 @@ export class TiDBMemoryEngineBackend {
|
|
|
128
128
|
if (q.size === 0)
|
|
129
129
|
return [];
|
|
130
130
|
const uniq = [...new Set(scopes)];
|
|
131
|
-
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("
|
|
131
|
+
const rows = await this.selectRows(`SELECT id, scope, slug, ${jsonColumnText("mysql", "frontmatter")}, body, rev, mtime_ms, size_bytes FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE scope IN (${inPlaceholders(uniq.length)})`, uniq);
|
|
132
132
|
const scored = [];
|
|
133
133
|
for (const raw of rows) {
|
|
134
134
|
const r = raw;
|
|
@@ -210,7 +210,7 @@ export class TiDBMemoryEngineBackend {
|
|
|
210
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
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
const prior = await this.selectRows(`SELECT scope, slug, rev, ${jsonColumnText("
|
|
213
|
+
const prior = await this.selectRows(`SELECT scope, slug, rev, ${jsonColumnText("mysql", "frontmatter")} FROM ${T} WHERE id = ?`, [entry.id]);
|
|
214
214
|
const priorRow = prior.length > 0 ? prior[0] : undefined;
|
|
215
215
|
let existsById = priorRow !== undefined;
|
|
216
216
|
{
|
|
@@ -295,7 +295,7 @@ export class TiDBMemoryEngineBackend {
|
|
|
295
295
|
slug = `${entry.slug}-${n}`;
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
|
-
const cur = await this.selectRows(`SELECT slug, rev, scope, ${jsonColumnText("
|
|
298
|
+
const cur = await this.selectRows(`SELECT slug, rev, scope, ${jsonColumnText("mysql", "frontmatter")} FROM ${T} WHERE id = ?`, [patch.id]);
|
|
299
299
|
if (cur.length === 0) {
|
|
300
300
|
report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
|
|
301
301
|
return;
|
|
@@ -126,7 +126,7 @@ export class SqlMemoryOptOutGrantStore {
|
|
|
126
126
|
}
|
|
127
127
|
export class TiDBMemoryOptOutGrantStore extends SqlMemoryOptOutGrantStore {
|
|
128
128
|
constructor(pool, now) {
|
|
129
|
-
super(mysqlDriver(pool), "
|
|
129
|
+
super(mysqlDriver(pool), "mysql", now);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
export class PgMemoryOptOutGrantStore extends SqlMemoryOptOutGrantStore {
|
|
@@ -46,7 +46,7 @@ export class TiDBMemorySyncStore {
|
|
|
46
46
|
this.claimLeaseMs = lease;
|
|
47
47
|
}
|
|
48
48
|
async getCursor(scope, peer) {
|
|
49
|
-
const [rows] = await this.pool.query(`SELECT ${jsonColumnText("
|
|
49
|
+
const [rows] = await this.pool.query(`SELECT ${jsonColumnText("mysql", "base_revs")}, updated_at_ms FROM ${TIDB_MEMORY_SYNC_TABLES.syncCursor} WHERE scope = ? AND peer = ?`, [scope, peer]);
|
|
50
50
|
const row = rows[0];
|
|
51
51
|
if (!row)
|
|
52
52
|
return undefined;
|
|
@@ -72,7 +72,7 @@ export class TiDBMemorySyncStore {
|
|
|
72
72
|
if (limit <= 0)
|
|
73
73
|
return [];
|
|
74
74
|
const leasedUntilMs = nowMs + this.claimLeaseMs;
|
|
75
|
-
const [candidates] = await this.pool.query(`SELECT id, scope, entry_id, ${jsonColumnText("
|
|
75
|
+
const [candidates] = await this.pool.query(`SELECT id, scope, entry_id, ${jsonColumnText("mysql", "payload")}, attempts, next_attempt_at_ms, last_error
|
|
76
76
|
FROM ${TIDB_MEMORY_SYNC_TABLES.pushQueue}
|
|
77
77
|
WHERE next_attempt_at_ms <= ?
|
|
78
78
|
ORDER BY next_attempt_at_ms, id
|
|
@@ -137,7 +137,7 @@ export class TiDBMemoryHistoryStore {
|
|
|
137
137
|
ON DUPLICATE KEY UPDATE id = id`, params);
|
|
138
138
|
}
|
|
139
139
|
async historyOf(id) {
|
|
140
|
-
const [rows] = await this.pool.query(`SELECT id, rev, prev_rev, op, scope, ${jsonColumnText("
|
|
140
|
+
const [rows] = await this.pool.query(`SELECT id, rev, prev_rev, op, scope, ${jsonColumnText("mysql", "snapshot")}, written_at_ms
|
|
141
141
|
FROM ${TIDB_MEMORY_SYNC_TABLES.history}
|
|
142
142
|
WHERE id = ?
|
|
143
143
|
ORDER BY written_at_ms ASC, rev ASC`, [id]);
|
|
@@ -333,6 +333,7 @@
|
|
|
333
333
|
import type { Pool as MysqlPool } from "mysql2/promise";
|
|
334
334
|
import type { Pool as PgPool } from "pg";
|
|
335
335
|
import { type AllowEntryInertReason, type GateKind } from "@sema-agent/core";
|
|
336
|
+
import { type SqlDialect } from "./sql-driver.js";
|
|
336
337
|
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
337
338
|
import { type UndurableScopeRuleRow, type UnreadableRuleBucket } from "./permission-rule-store-sql.js";
|
|
338
339
|
import type { SchemaProbeRead } from "./schema-live-columns.js";
|
|
@@ -577,7 +578,7 @@ export interface MigrationDb {
|
|
|
577
578
|
* 本函数**不问**退役 schema:带着它的库在更早处就被 `ensureSchema()` 自身拒掉了(起服对账一族 `schema-consistency.ts` 的探针口,先于建表);走公开序列
|
|
578
579
|
* `createStoreBackend()` → `ensureSchema()` → `runOneTimeMigrations()` 的嵌入方与本服务的起服序列一样,有这一问、零动作。
|
|
579
580
|
*/
|
|
580
|
-
export declare function runSqlOneTimeMigrations(dialect:
|
|
581
|
+
export declare function runSqlOneTimeMigrations(dialect: SqlDialect, pool: MysqlPool | PgPool, input: ExecutionPlacementSwitchInput): Promise<OneTimeMigrationReport>;
|
|
581
582
|
/** M32 的起服拒码(确定的拒启表态:再等也等不来另一个答案;不是线上 wire 码,与 `config.schema_mismatch` 同一族)。 */
|
|
582
583
|
export declare const EXECUTION_PLACEMENT_SWITCH_REFUSED_CODE = "config.execution_placement_switch_refused";
|
|
583
584
|
/** 拒因闭集:`fence` = 切换开始之后退役绑定表里又出现了行(旧版副本 / 手工写下的);`backfill_ambiguous` = 车道表不止一项而还有要回填的存量。 */
|
|
@@ -599,14 +600,14 @@ export interface ExecutionPlacementSwitchInput {
|
|
|
599
600
|
* M32 的 **DDL 前只读探针**(与退役 schema 探针同层、同一只调用点:`store-backend.ts` 的 `withRetiredSchemaProbe`,先于第一条 CREATE):围栏与回填前提。
|
|
600
601
|
* 拒在任何 DDL 之前 ⇒ 库零写。全新库(没有 `session_meta`)不判。纯读,不取 schema 锁(与退役 schema 探针同理)。
|
|
601
602
|
*/
|
|
602
|
-
export declare function assertExecutionPlacementSwitchAdmissible(read: SchemaProbeRead, dialect:
|
|
603
|
+
export declare function assertExecutionPlacementSwitchAdmissible(read: SchemaProbeRead, dialect: SqlDialect, input: ExecutionPlacementSwitchInput): Promise<void>;
|
|
603
604
|
/** 探针口(入参形与本文件的迁移段入口 {@link runSqlOneTimeMigrations} 同:方言 + 它的池;借一条连接,用完即还)。 */
|
|
604
|
-
export declare function assertExecutionPlacementSwitchAdmissibleOnPool(dialect:
|
|
605
|
+
export declare function assertExecutionPlacementSwitchAdmissibleOnPool(dialect: SqlDialect, pool: MysqlPool | PgPool, input: ExecutionPlacementSwitchInput): Promise<void>;
|
|
605
606
|
/**
|
|
606
607
|
* M32(规则与理由见头注 M32 段):切换已收尾(八列在 ∧ 两张绑定表都不在)⇒ 零动作;否则先复判围栏(探针之后、锁内这一刻又有旧版副本写进行 ⇒ 同一只拒),
|
|
607
608
|
* 再按步骤表逐步收敛。跑在一次性迁移的锁里(与别的迁移步同一条连接)。导出给真库钉驱动「每步中断后续跑」。
|
|
608
609
|
*/
|
|
609
|
-
export declare function switchExecutionPlacement(db: MigrationDb, dialect:
|
|
610
|
+
export declare function switchExecutionPlacement(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts, input: ExecutionPlacementSwitchInput): Promise<void>;
|
|
610
611
|
/** {@link backfillLocalExecutionPlacements} 的结果:回填了几只会话 · 读不出而被跳过的会话(点名)。 */
|
|
611
612
|
export interface LocalPlacementBackfill {
|
|
612
613
|
readonly backfilled: number;
|
|
@@ -644,7 +645,7 @@ export declare function backfillLocalAskExecutionLanes(store: {
|
|
|
644
645
|
* ⑤ **原子换名**:TiDB 一条 `RENAME TABLE 正 TO 待删, 暂存 TO 正`,之后删待删旧表;PG 两条换名、删旧表与主键约束名改回常规名在**同一个事务**里({@link execAtomically})
|
|
645
646
|
* —— 中途死 = 整段回滚,盘上回到「正表旧形 + 暂存表」,下一次起动从 ① 重来。每一条 DDL 按后置条件收敛({@link execUntil} / {@link execAtomically})。
|
|
646
647
|
*/
|
|
647
|
-
export declare function moveWorkflowJournalScope(db: MigrationDb, dialect:
|
|
648
|
+
export declare function moveWorkflowJournalScope(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
|
|
648
649
|
/**
|
|
649
650
|
* M17 —— 一份存量规则体带哪几只退役命令桶(纯函数,点名判据):只认**对象上自有**的 `commandAllow` / `commandDeny` 键(不论值形 —— 坏形的退役桶照样是退役桶);
|
|
650
651
|
* 不是对象 / 没有这两个键 / 条目文字里出现同名字样 ⇒ 空。不改写:新文法写不出旧命令桶的拒(头注 M17 段 ③)。
|
|
@@ -685,7 +686,7 @@ export declare function oldGrammarEntriesOf(body: unknown, rev: number): OldGram
|
|
|
685
686
|
* 读数都记在收据账上(`sessionRuleColumn` 在落定时写:表不在(中央 DDL 之前被调到)⇒ `no-table`,不编读数;`renamed` = 本次把终名发布出来(含从进行中的名续判到底的那一次),
|
|
686
687
|
* 终名改名提交之后才写;`current` = 起服时已是终名);点名的行随扫到追加。
|
|
687
688
|
*/
|
|
688
|
-
export declare function migrateSessionRuleGrammar(db: MigrationDb, dialect:
|
|
689
|
+
export declare function migrateSessionRuleGrammar(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
|
|
689
690
|
/** M8 一行改写的结论:改写后的文本 / 这一行不用动 / 读不懂(解析错误原样交出,调用方计数进读数)。 */
|
|
690
691
|
export type ShadowedRuleRewrite = {
|
|
691
692
|
readonly kind: "rewrite";
|
|
@@ -738,7 +739,7 @@ export declare function parkedRowRepairOf(gateKindCell: unknown, gate: unknown,
|
|
|
738
739
|
* 否则门上加 `approvalCard: "question"`、其余字节原样,经写腿的同一只编码器回写,按原文 CAS(MySQL 协议两边 `CAST(… AS BINARY)`,PG `text` 等值)+ `status = 'pending'`。
|
|
739
740
|
* 每一次提交当场记进收据账。
|
|
740
741
|
*/
|
|
741
|
-
export declare function repairParkedRows(db: MigrationDb, dialect:
|
|
742
|
+
export declare function repairParkedRows(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
|
|
742
743
|
/**
|
|
743
744
|
* M29 —— 存量停驻行的 `approval_card` 列回填(规则、为什么、够不到的一格见头注 M29 段):列不在 ⇒ 延后(零扫描);只扫 `status = 'pending'` ∧ 列为 NULL ∧ 审批门型的行,
|
|
744
745
|
* 按 `token` 键集分页,每行单独读整只文档、交给写口用的**同一只**判官({@link judgeCheckpointIndexCells} → `buildCheckpointIndexCells`,core `checkpointIndexFacts`):答出词 ⇒
|
|
@@ -746,7 +747,7 @@ export declare function repairParkedRows(db: MigrationDb, dialect: "tidb" | "pg"
|
|
|
746
747
|
* 文档的门不是审批门)⇒ 不写;文档读不出、或派生读不了它(缺门 / 缺寄存行)⇒ 计数不写;答出的词超过列的容量(判官 {@link judgeCheckpointIndexCells} 的 `card_too_long`,
|
|
747
748
|
* MySQL 协议 TEXT 65,535 UTF-8 字节)⇒ 计数 + 点名不写(同一个态度:一行手改数据不许挡整只部署起服)。每一次提交当场记进收据账。
|
|
748
749
|
*/
|
|
749
|
-
export declare function backfillParkedApprovalCards(db: MigrationDb, dialect:
|
|
750
|
+
export declare function backfillParkedApprovalCards(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
|
|
750
751
|
/**
|
|
751
752
|
* M23 —— 存量 placed 子代行的属主回填,**每次起服单趟、幂等**(规则、为什么、够不到的一格见头注 M23 段):键集分页扫完 placed ∧ 属主 NULL 的行,每一行按唯一判据判
|
|
752
753
|
* (`judgeDelegatedOwner`,建行那一笔与停驻挂点同一只:来源顺序根、父;属主 = 这一读见证到的):
|
|
@@ -757,7 +758,7 @@ export declare function backfillParkedApprovalCards(db: MigrationDb, dialect: "t
|
|
|
757
758
|
* · 扫到的任何一行化身为空 ⇒ 响亮拒(不论判不判得出属主;来源行同一条律)。
|
|
758
759
|
* 不重扫、不拒启:残余由下一次起服或那一行的下一次停驻定下,期间只对 fleet 调用方放行(头注 M23 段)。
|
|
759
760
|
*/
|
|
760
|
-
export declare function inheritPlacedSessionOwners(db: MigrationDb, dialect:
|
|
761
|
+
export declare function inheritPlacedSessionOwners(db: MigrationDb, dialect: SqlDialect, receipts: MigrationReceipts): Promise<void>;
|
|
761
762
|
/**
|
|
762
763
|
* 启动日志的读数行。零命中(第二跑起的常态)也照发 —— 「跑过了、什么都没改」与「压根没跑」必须可分辨。
|
|
763
764
|
*
|
|
@@ -602,7 +602,7 @@ function pgDb(client) {
|
|
|
602
602
|
};
|
|
603
603
|
}
|
|
604
604
|
async function tableExists(db, dialect, table) {
|
|
605
|
-
const sql = dialect === "
|
|
605
|
+
const sql = dialect === "mysql"
|
|
606
606
|
? `SELECT 1 AS present FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '${table}'`
|
|
607
607
|
: `SELECT 1 AS present FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = '${table}'`;
|
|
608
608
|
return (await db.rows(sql)).length > 0;
|
|
@@ -617,12 +617,12 @@ async function execUntil(db, sql, postcondition) {
|
|
|
617
617
|
}
|
|
618
618
|
}
|
|
619
619
|
async function columnExists(db, dialect, table, column) {
|
|
620
|
-
const scope = dialect === "
|
|
620
|
+
const scope = dialect === "mysql" ? "DATABASE()" : "current_schema()";
|
|
621
621
|
const sql = `SELECT 1 AS present FROM information_schema.columns WHERE table_schema = ${scope} AND table_name = '${table}' AND column_name = '${column}'`;
|
|
622
622
|
return (await db.rows(sql)).length > 0;
|
|
623
623
|
}
|
|
624
624
|
export async function runSqlOneTimeMigrations(dialect, pool, input) {
|
|
625
|
-
return dialect === "
|
|
625
|
+
return dialect === "mysql" ? withMysqlLock(pool, (db) => migrateOn(db, "mysql", input)) : withPgLock(pool, (db) => migrateOn(db, "pg", input));
|
|
626
626
|
}
|
|
627
627
|
async function withMysqlLock(pool, run) {
|
|
628
628
|
const conn = await pool.getConnection();
|
|
@@ -663,10 +663,10 @@ async function migrateOn(db, dialect, input) {
|
|
|
663
663
|
return completedReport(receipts);
|
|
664
664
|
}
|
|
665
665
|
async function migrateStepsOn(db, dialect, receipts, input) {
|
|
666
|
-
receipts.holderDeathCodeRowsBackfilled += await db.exec(dialect === "
|
|
666
|
+
receipts.holderDeathCodeRowsBackfilled += await db.exec(dialect === "mysql"
|
|
667
667
|
? "UPDATE task_run SET error_code = ? WHERE status = 'failed' AND error_code IS NULL AND error = ?"
|
|
668
668
|
: "UPDATE task_run SET error_code = $1 WHERE status = 'failed' AND error_code IS NULL AND error = $2", [RUN_HOLDER_DEATH_CODES.stalled, RUN_STALLED_ERROR]);
|
|
669
|
-
receipts.holderDeathCodeRowsBackfilled += await db.exec(dialect === "
|
|
669
|
+
receipts.holderDeathCodeRowsBackfilled += await db.exec(dialect === "mysql"
|
|
670
670
|
? "UPDATE task_run SET error_code = ? WHERE status = 'failed' AND error_code IS NULL AND (error = ? OR error LIKE ?)"
|
|
671
671
|
: "UPDATE task_run SET error_code = $1 WHERE status = 'failed' AND error_code IS NULL AND (error = $2 OR error LIKE $3)", [RUN_HOLDER_DEATH_CODES.orphaned, RUN_ORPHANED_ERROR, `${RUN_ORPHANED_ERROR} (%`]);
|
|
672
672
|
await migrateShadowedRuleKey(db, dialect, receipts);
|
|
@@ -727,7 +727,7 @@ function switchComplete(s) {
|
|
|
727
727
|
return s.placementColumns.size === SESSION_META_PLACEMENT_COLUMNS.length && (!s.askTable || s.askLaneColumn) && !s.bindingTable && !s.parkedTable;
|
|
728
728
|
}
|
|
729
729
|
function askLaneBackfillSql(dialect) {
|
|
730
|
-
return dialect === "
|
|
730
|
+
return dialect === "mysql"
|
|
731
731
|
? `UPDATE ${APPROVAL_ASK_TABLE} a LEFT JOIN session_meta sm ON sm.session_id = a.session_id AND sm.placement_kind IS NULL SET a.execution_lane = COALESCE(sm.execution_lane, ?) WHERE a.execution_lane = ''`
|
|
732
732
|
: `UPDATE ${APPROVAL_ASK_TABLE} a SET execution_lane = COALESCE((SELECT sm.execution_lane FROM session_meta sm WHERE sm.session_id = a.session_id AND sm.placement_kind IS NULL), $1) WHERE a.execution_lane = ''`;
|
|
733
733
|
}
|
|
@@ -735,7 +735,7 @@ async function parkedRelationNamesWithRetiredPrefix(db) {
|
|
|
735
735
|
const rows = await db.rows(`SELECT i.relname AS name FROM pg_index x JOIN pg_class i ON i.oid = x.indexrelid JOIN pg_class t ON t.oid = x.indrelid WHERE t.relname = '${PARKED_DEVICE_BINDING_TABLE}' AND t.relnamespace = current_schema()::regnamespace AND i.relname LIKE '${RETIRED_DEVICE_BINDING_TABLE}\\_%'`);
|
|
736
736
|
return rows.map((r) => String(r["name"])).filter((name) => name.startsWith(`${RETIRED_DEVICE_BINDING_TABLE}_`) && !name.startsWith(PARKED_DEVICE_BINDING_TABLE));
|
|
737
737
|
}
|
|
738
|
-
const bindingRootKey = (dialect, alias) => (dialect === "
|
|
738
|
+
const bindingRootKey = (dialect, alias) => (dialect === "mysql" ? `CONVERT(${alias}.root_session_id USING utf8mb4) COLLATE utf8mb4_bin` : `${alias}.root_session_id`);
|
|
739
739
|
async function refuseOnSwitchFence(read, dialect, shape) {
|
|
740
740
|
if (!switchStarted(shape) || !shape.bindingTable)
|
|
741
741
|
return;
|
|
@@ -744,7 +744,7 @@ async function refuseOnSwitchFence(read, dialect, shape) {
|
|
|
744
744
|
return;
|
|
745
745
|
const roots = rows.slice(0, FENCE_ROOTS_SHOWN).map((r) => (Buffer.isBuffer(r["root"]) ? r["root"].toString("utf8") : String(r["root"])));
|
|
746
746
|
const more = rows.length > FENCE_ROOTS_SHOWN ? ` (and more — the table holds over ${FENCE_ROOTS_SHOWN} rows)` : "";
|
|
747
|
-
const rename = dialect === "
|
|
747
|
+
const rename = dialect === "mysql" ? `RENAME TABLE ${RETIRED_DEVICE_BINDING_TABLE} TO ${PARKED_DEVICE_BINDING_TABLE};` : `ALTER TABLE ${RETIRED_DEVICE_BINDING_TABLE} RENAME TO ${PARKED_DEVICE_BINDING_TABLE};`;
|
|
748
748
|
const adopt = shape.parkedTable
|
|
749
749
|
? `DELETE FROM ${PARKED_DEVICE_BINDING_TABLE} WHERE root_session_id IN (SELECT root_session_id FROM ${RETIRED_DEVICE_BINDING_TABLE}); INSERT INTO ${PARKED_DEVICE_BINDING_TABLE} (${BINDING_COLUMNS}) SELECT ${BINDING_COLUMNS} FROM ${RETIRED_DEVICE_BINDING_TABLE}; DELETE FROM ${RETIRED_DEVICE_BINDING_TABLE};`
|
|
750
750
|
: rename;
|
|
@@ -795,10 +795,10 @@ export async function assertExecutionPlacementSwitchAdmissible(read, dialect, in
|
|
|
795
795
|
await refuseOnAmbiguousBackfill(read, dialect, shape, input.lanes);
|
|
796
796
|
}
|
|
797
797
|
export async function assertExecutionPlacementSwitchAdmissibleOnPool(dialect, pool, input) {
|
|
798
|
-
if (dialect === "
|
|
798
|
+
if (dialect === "mysql") {
|
|
799
799
|
const conn = await pool.getConnection();
|
|
800
800
|
try {
|
|
801
|
-
await assertExecutionPlacementSwitchAdmissible(async (sql) => (await conn.query(sql))[0], "
|
|
801
|
+
await assertExecutionPlacementSwitchAdmissible(async (sql) => (await conn.query(sql))[0], "mysql", input);
|
|
802
802
|
}
|
|
803
803
|
finally {
|
|
804
804
|
conn.release();
|
|
@@ -830,7 +830,7 @@ const EXECUTION_PLACEMENT_SWITCH_STEPS = [
|
|
|
830
830
|
const s = await shape();
|
|
831
831
|
if (!s.bindingTable || s.placementColumns.has("execution_role"))
|
|
832
832
|
return;
|
|
833
|
-
const sql = dialect === "
|
|
833
|
+
const sql = dialect === "mysql" ? `RENAME TABLE ${RETIRED_DEVICE_BINDING_TABLE} TO ${PARKED_DEVICE_BINDING_TABLE}` : `ALTER TABLE ${RETIRED_DEVICE_BINDING_TABLE} RENAME TO ${PARKED_DEVICE_BINDING_TABLE}`;
|
|
834
834
|
await execUntil(db, sql, async () => {
|
|
835
835
|
const after = await shape();
|
|
836
836
|
return after.parkedTable && !after.bindingTable;
|
|
@@ -862,7 +862,7 @@ const EXECUTION_PLACEMENT_SWITCH_STEPS = [
|
|
|
862
862
|
}
|
|
863
863
|
const ask = await shape();
|
|
864
864
|
if (ask.askTable && !ask.askLaneColumn) {
|
|
865
|
-
await execUntil(db, `ALTER TABLE ${APPROVAL_ASK_TABLE} ADD COLUMN ${APPROVAL_ASK_EXECUTION_LANE_COLUMN[dialect
|
|
865
|
+
await execUntil(db, `ALTER TABLE ${APPROVAL_ASK_TABLE} ADD COLUMN ${APPROVAL_ASK_EXECUTION_LANE_COLUMN[dialect]}`, async () => (await shape()).askLaneColumn);
|
|
866
866
|
receipts.executionPlacementColumnsAdded += 1;
|
|
867
867
|
}
|
|
868
868
|
},
|
|
@@ -973,7 +973,7 @@ async function dropRejectedMailboxKeys(db, dialect, receipts) {
|
|
|
973
973
|
for (const table of MAILBOX_KEYED_TABLES)
|
|
974
974
|
if (await tableExists(db, dialect, table))
|
|
975
975
|
present.push(table);
|
|
976
|
-
const p = (i) => (dialect === "
|
|
976
|
+
const p = (i) => (dialect === "mysql" ? "?" : `$${i}`);
|
|
977
977
|
for (const table of present) {
|
|
978
978
|
let after;
|
|
979
979
|
for (;;) {
|
|
@@ -1007,14 +1007,14 @@ const M24_OWNER_INCARNATION = "m24-backfill";
|
|
|
1007
1007
|
const M24_COPY_BATCH_BYTES = 32 * 1024 * 1024;
|
|
1008
1008
|
const M24_COPY_SCAN_PAGE = 1000;
|
|
1009
1009
|
function journalKeyBound(dialect, op, first) {
|
|
1010
|
-
const p = (i) => (dialect === "
|
|
1010
|
+
const p = (i) => (dialect === "mysql" ? "?" : `$${first + i}`);
|
|
1011
1011
|
return op === "after"
|
|
1012
1012
|
? `(${WORKFLOW_JOURNAL_TABLE}.run_id > ${p(0)} OR (${WORKFLOW_JOURNAL_TABLE}.run_id = ${p(1)} AND ordinal > ${p(2)}))`
|
|
1013
1013
|
: `(${WORKFLOW_JOURNAL_TABLE}.run_id < ${p(0)} OR (${WORKFLOW_JOURNAL_TABLE}.run_id = ${p(1)} AND ordinal <= ${p(2)}))`;
|
|
1014
1014
|
}
|
|
1015
1015
|
async function copyJournalInBatches(db, dialect) {
|
|
1016
1016
|
const T = WORKFLOW_JOURNAL_TABLE;
|
|
1017
|
-
const bytes = dialect === "
|
|
1017
|
+
const bytes = dialect === "mysql" ? "LENGTH(result)" : "OCTET_LENGTH(result)";
|
|
1018
1018
|
const copyHead = `INSERT INTO ${WORKFLOW_JOURNAL_STAGING} (run_id, incarnation, ordinal, call_key, result, created_at_ms) ` +
|
|
1019
1019
|
`SELECT ${T}.run_id, o.incarnation, ordinal, call_key, ${jsonColumnText(dialect, "result")}, created_at_ms FROM ${T} ` +
|
|
1020
1020
|
`JOIN ${WORKFLOW_JOURNAL_OWNER_TABLE} o ON o.run_id = ${T}.run_id AND o.scope = ${T}.${RETIRED_JOURNAL_SCOPE_COLUMN} WHERE `;
|
|
@@ -1053,7 +1053,7 @@ export async function moveWorkflowJournalScope(db, dialect, receipts) {
|
|
|
1053
1053
|
receipts.workflowJournalScopeColumn = "current";
|
|
1054
1054
|
return;
|
|
1055
1055
|
}
|
|
1056
|
-
const ddl = (dialect === "
|
|
1056
|
+
const ddl = (dialect === "mysql" ? SCHEMA_STATEMENTS : PG_SCHEMA_STATEMENTS).find((stmt) => stmt.includes(`CREATE TABLE IF NOT EXISTS ${T} (`));
|
|
1057
1057
|
if (ddl === undefined)
|
|
1058
1058
|
throw new Error(`one-time migration M24: the central schema carries no definition of ${T} — refusing to rebuild a table it cannot define`);
|
|
1059
1059
|
if (await exists(S))
|
|
@@ -1067,7 +1067,7 @@ export async function moveWorkflowJournalScope(db, dialect, receipts) {
|
|
|
1067
1067
|
await db.exec(ddl.replace(`CREATE TABLE IF NOT EXISTS ${T} (`, `CREATE TABLE IF NOT EXISTS ${S} (`));
|
|
1068
1068
|
await copyJournalInBatches(db, dialect);
|
|
1069
1069
|
const swapped = async () => !(await exists(S)) && (await exists(T)) && !(await legacy());
|
|
1070
|
-
if (dialect === "
|
|
1070
|
+
if (dialect === "mysql") {
|
|
1071
1071
|
await execUntil(db, `RENAME TABLE ${T} TO ${O}, ${S} TO ${T}`, swapped);
|
|
1072
1072
|
receipts.workflowJournalForeignScopeRowsRemoved += foreign;
|
|
1073
1073
|
await execUntil(db, `DROP TABLE IF EXISTS ${O}`, async () => !(await exists(O)));
|
|
@@ -1110,9 +1110,9 @@ const M17_PROVEN_GRAMMAR = 1;
|
|
|
1110
1110
|
const RETIRED_BUCKET_PATTERNS = ['%"commandDeny"%', '%"commandAllow"%'];
|
|
1111
1111
|
async function scanSessionRuleRows(db, dialect, column, patterns, visit) {
|
|
1112
1112
|
const text = jsonColumnTextExpr(dialect, column);
|
|
1113
|
-
const prefilter = patterns.length === 0 ? "" : ` AND (${patterns.map((_, i) => `${text} LIKE ${dialect === "
|
|
1114
|
-
const scan = dialect === "
|
|
1115
|
-
? `SELECT policy_key, session_id, rev, ${jsonColumnText("
|
|
1113
|
+
const prefilter = patterns.length === 0 ? "" : ` AND (${patterns.map((_, i) => `${text} LIKE ${dialect === "mysql" ? "?" : `$${i + 2}`}`).join(" OR ")})`;
|
|
1114
|
+
const scan = dialect === "mysql"
|
|
1115
|
+
? `SELECT policy_key, session_id, rev, ${jsonColumnText("mysql", column)} FROM ${SESSION_POLICY_TABLE} WHERE policy_key > ?${prefilter} ORDER BY policy_key LIMIT ${SESSION_RULES_SCAN_PAGE}`
|
|
1116
1116
|
: `SELECT policy_key, session_id, rev, ${jsonColumnText("pg", column)} FROM ${SESSION_POLICY_TABLE} WHERE policy_key > $1${prefilter} ORDER BY policy_key LIMIT ${SESSION_RULES_SCAN_PAGE}`;
|
|
1117
1117
|
let cursor = "";
|
|
1118
1118
|
for (;;) {
|
|
@@ -1137,7 +1137,7 @@ async function scanSessionRuleRows(db, dialect, column, patterns, visit) {
|
|
|
1137
1137
|
async function judgeOldGrammarRows(db, dialect, receipts) {
|
|
1138
1138
|
const column = OLD_GRAMMAR_SESSION_RULES_COLUMN;
|
|
1139
1139
|
const text = jsonColumnTextExpr(dialect, column);
|
|
1140
|
-
const cas = dialect === "
|
|
1140
|
+
const cas = dialect === "mysql"
|
|
1141
1141
|
? `UPDATE ${SESSION_POLICY_TABLE} SET ${column} = ? WHERE policy_key = ? AND CAST(${text} AS BINARY) = CAST(? AS BINARY)`
|
|
1142
1142
|
: `UPDATE ${SESSION_POLICY_TABLE} SET ${column} = $1::jsonb WHERE policy_key = $2 AND ${text} = $3`;
|
|
1143
1143
|
await scanSessionRuleRows(db, dialect, column, [], async (row) => {
|
|
@@ -1188,12 +1188,12 @@ export async function migrateSessionRuleGrammar(db, dialect, receipts) {
|
|
|
1188
1188
|
});
|
|
1189
1189
|
}
|
|
1190
1190
|
function renameSessionRulesColumnSql(dialect, from, to) {
|
|
1191
|
-
const definition = SESSION_RULES_COLUMN.
|
|
1192
|
-
return dialect === "
|
|
1191
|
+
const definition = SESSION_RULES_COLUMN.mysql.slice(SESSION_RULES_COLUMN.name.length);
|
|
1192
|
+
return dialect === "mysql" ? `ALTER TABLE ${SESSION_POLICY_TABLE} CHANGE COLUMN ${from} ${to}${definition}` : `ALTER TABLE ${SESSION_POLICY_TABLE} RENAME COLUMN ${from} TO ${to}`;
|
|
1193
1193
|
}
|
|
1194
1194
|
const WORKFLOW_PARK_INDEX_TABLE = "workflow_agent_session";
|
|
1195
1195
|
async function primaryKeyWidth(db, dialect, table) {
|
|
1196
|
-
const sql = dialect === "
|
|
1196
|
+
const sql = dialect === "mysql"
|
|
1197
1197
|
? `SELECT COUNT(*) AS n FROM information_schema.key_column_usage WHERE table_schema = DATABASE() AND table_name = '${table}' AND constraint_name = 'PRIMARY'`
|
|
1198
1198
|
: `SELECT COUNT(*) AS n FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ` +
|
|
1199
1199
|
`ON kcu.constraint_name = tc.constraint_name AND kcu.table_schema = tc.table_schema AND kcu.table_name = tc.table_name ` +
|
|
@@ -1207,10 +1207,10 @@ async function reshapeWorkflowParkIndex(db, dialect, receipts) {
|
|
|
1207
1207
|
const S = WORKFLOW_PARK_INDEX_STAGING;
|
|
1208
1208
|
const O = WORKFLOW_PARK_INDEX_RETIRED;
|
|
1209
1209
|
const exists = (t) => tableExists(db, dialect, t);
|
|
1210
|
-
const ddl = (dialect === "
|
|
1210
|
+
const ddl = (dialect === "mysql" ? SCHEMA_STATEMENTS : PG_SCHEMA_STATEMENTS).find((stmt) => stmt.includes(`CREATE TABLE IF NOT EXISTS ${T} (`));
|
|
1211
1211
|
if (ddl === undefined)
|
|
1212
1212
|
throw new Error(`one-time migration M9: the central schema carries no definition of ${T} — refusing to reshape a table it cannot rebuild`);
|
|
1213
|
-
const copyPointers = (to, from) => db.exec(dialect === "
|
|
1213
|
+
const copyPointers = (to, from) => db.exec(dialect === "mysql"
|
|
1214
1214
|
? `INSERT IGNORE INTO ${to} (session_id, run_id, agent_key, scope) SELECT session_id, run_id, agent_key, scope FROM ${from}`
|
|
1215
1215
|
: `INSERT INTO ${to} (session_id, run_id, agent_key, scope) SELECT session_id, run_id, agent_key, scope FROM ${from} ON CONFLICT DO NOTHING`);
|
|
1216
1216
|
const resumed = await exists(S);
|
|
@@ -1230,7 +1230,7 @@ async function reshapeWorkflowParkIndex(db, dialect, receipts) {
|
|
|
1230
1230
|
await db.exec(ddl.replace(`CREATE TABLE IF NOT EXISTS ${T} (`, `CREATE TABLE IF NOT EXISTS ${S} (`));
|
|
1231
1231
|
receipts.workflowParkIndexRowsCarried += await copyPointers(S, T);
|
|
1232
1232
|
const swapped = async () => !(await exists(S)) && (await exists(T)) && (await primaryKeyWidth(db, dialect, T)) !== 1;
|
|
1233
|
-
if (dialect === "
|
|
1233
|
+
if (dialect === "mysql") {
|
|
1234
1234
|
await execUntil(db, `RENAME TABLE ${T} TO ${O}, ${S} TO ${T}`, swapped);
|
|
1235
1235
|
await execUntil(db, `DROP TABLE IF EXISTS ${O}`, async () => !(await exists(O)));
|
|
1236
1236
|
}
|
|
@@ -1260,7 +1260,7 @@ async function execAtomically(db, statements, postcondition) {
|
|
|
1260
1260
|
}
|
|
1261
1261
|
}
|
|
1262
1262
|
async function finishParkIndexShape(db, dialect) {
|
|
1263
|
-
await ensureIndexes(async (sql, params) => (dialect === "
|
|
1263
|
+
await ensureIndexes(async (sql, params) => (dialect === "mysql" ? [await db.rows(sql, params)] : { rows: await db.rows(sql, params) }), dialect, CENTRAL_SCHEMA_INDEXES.filter((spec) => spec.table === WORKFLOW_PARK_INDEX_TABLE));
|
|
1264
1264
|
if (dialect !== "pg")
|
|
1265
1265
|
return;
|
|
1266
1266
|
const conventional = `${WORKFLOW_PARK_INDEX_TABLE}_pkey`;
|
|
@@ -1293,7 +1293,7 @@ async function migrateShadowedRuleKey(db, dialect, receipts) {
|
|
|
1293
1293
|
const like = `%"${RETIRED_SHADOWED_RULE_KEY}"%`;
|
|
1294
1294
|
let after = "";
|
|
1295
1295
|
for (;;) {
|
|
1296
|
-
const rows = await db.rows(dialect === "
|
|
1296
|
+
const rows = await db.rows(dialect === "mysql"
|
|
1297
1297
|
? `SELECT token, ${jsonColumnText(dialect, "risk_descriptor")} FROM checkpoint WHERE ${jsonColumnTextExpr(dialect, "risk_descriptor")} LIKE ? AND token > ? ORDER BY token LIMIT ${SHADOWED_RULE_BATCH}`
|
|
1298
1298
|
: `SELECT token, ${jsonColumnText(dialect, "risk_descriptor")} FROM checkpoint WHERE ${jsonColumnTextExpr(dialect, "risk_descriptor")} LIKE $1 AND token > $2 ORDER BY token LIMIT ${SHADOWED_RULE_BATCH}`, [like, after]);
|
|
1299
1299
|
for (const r of rows) {
|
|
@@ -1309,7 +1309,7 @@ async function migrateShadowedRuleKey(db, dialect, receipts) {
|
|
|
1309
1309
|
}
|
|
1310
1310
|
if (next.kind === "untouched")
|
|
1311
1311
|
continue;
|
|
1312
|
-
receipts.allowRuleShadowRowsMigrated += await db.exec(dialect === "
|
|
1312
|
+
receipts.allowRuleShadowRowsMigrated += await db.exec(dialect === "mysql"
|
|
1313
1313
|
? `UPDATE checkpoint SET risk_descriptor = ? WHERE token = ? AND ${jsonColumnTextExpr(dialect, "risk_descriptor")} = ?`
|
|
1314
1314
|
: `UPDATE checkpoint SET risk_descriptor = $1 WHERE token = $2 AND ${jsonColumnTextExpr(dialect, "risk_descriptor")} = $3`, [next.text, token, text]);
|
|
1315
1315
|
}
|
|
@@ -1342,7 +1342,7 @@ async function migrateRetiredCardWords(db, dialect, receipts) {
|
|
|
1342
1342
|
const cardText = jsonColumnTextExpr(dialect, "card_json");
|
|
1343
1343
|
let after = "";
|
|
1344
1344
|
for (;;) {
|
|
1345
|
-
const rows = await db.rows(dialect === "
|
|
1345
|
+
const rows = await db.rows(dialect === "mysql"
|
|
1346
1346
|
? `SELECT ask_id, ${jsonColumnText(dialect, "card_json")} FROM approval_ask WHERE (${cardText} LIKE ? OR ${cardText} LIKE ?) AND ask_id > ? ORDER BY ask_id LIMIT ${RETIRED_CARD_WORD_BATCH}`
|
|
1347
1347
|
: `SELECT ask_id, ${jsonColumnText(dialect, "card_json")} FROM approval_ask WHERE (${cardText} LIKE $1 OR ${cardText} LIKE $2) AND ask_id > $3 ORDER BY ask_id LIMIT ${RETIRED_CARD_WORD_BATCH}`, [...RETIRED_CARD_WORD_PATTERNS, after]);
|
|
1348
1348
|
for (const r of rows) {
|
|
@@ -1358,7 +1358,7 @@ async function migrateRetiredCardWords(db, dialect, receipts) {
|
|
|
1358
1358
|
}
|
|
1359
1359
|
if (next.kind === "untouched")
|
|
1360
1360
|
continue;
|
|
1361
|
-
receipts.retiredCardWordAskRowsRewritten += await db.exec(dialect === "
|
|
1361
|
+
receipts.retiredCardWordAskRowsRewritten += await db.exec(dialect === "mysql"
|
|
1362
1362
|
? `UPDATE approval_ask SET card_json = ? WHERE ask_id = ? AND CAST(${cardText} AS BINARY) = CAST(? AS BINARY)`
|
|
1363
1363
|
: `UPDATE approval_ask SET card_json = $1 WHERE ask_id = $2 AND ${cardText} = $3`, [next.text, askId, text]);
|
|
1364
1364
|
}
|
|
@@ -1398,7 +1398,7 @@ function m21Subtree(cell, where) {
|
|
|
1398
1398
|
}
|
|
1399
1399
|
}
|
|
1400
1400
|
export async function repairParkedRows(db, dialect, receipts) {
|
|
1401
|
-
const ph = (n) => (dialect === "
|
|
1401
|
+
const ph = (n) => (dialect === "mysql" ? "?" : `$${n}`);
|
|
1402
1402
|
const kinds = APPROVAL_GATE_KINDS;
|
|
1403
1403
|
const kindSlots = kinds.map((_, i) => ph(i + 1)).join(", ");
|
|
1404
1404
|
const scan = `SELECT token, session_id, gate_kind, ${jsonColumnText(dialect, "checkpoint", M21_GATE)}, ${jsonColumnText(dialect, "checkpoint", M21_PENDING_ACTION)} FROM checkpoint ` +
|
|
@@ -1441,7 +1441,7 @@ export async function repairParkedRows(db, dialect, receipts) {
|
|
|
1441
1441
|
continue;
|
|
1442
1442
|
}
|
|
1443
1443
|
const next = encode({ ...doc, gate: { ...gate, approvalCard: QUESTION_CARD } }, "checkpoint (M21 question-card repair)");
|
|
1444
|
-
receipts.parkedQuestionCardsWritten += await db.exec(dialect === "
|
|
1444
|
+
receipts.parkedQuestionCardsWritten += await db.exec(dialect === "mysql"
|
|
1445
1445
|
? `UPDATE checkpoint SET checkpoint = ? WHERE token = ? AND status = 'pending' AND CAST(${docText} AS BINARY) = CAST(? AS BINARY)`
|
|
1446
1446
|
: `UPDATE checkpoint SET checkpoint = $1::jsonb WHERE token = $2 AND status = 'pending' AND ${docText} = $3`, [next, token, String(full.checkpoint)]);
|
|
1447
1447
|
}
|
|
@@ -1454,7 +1454,7 @@ const readM29Document = createObjectColumnReader();
|
|
|
1454
1454
|
export async function backfillParkedApprovalCards(db, dialect, receipts) {
|
|
1455
1455
|
if (!(await columnExists(db, dialect, "checkpoint", "approval_card")))
|
|
1456
1456
|
return;
|
|
1457
|
-
const ph = (n) => (dialect === "
|
|
1457
|
+
const ph = (n) => (dialect === "mysql" ? "?" : `$${n}`);
|
|
1458
1458
|
const kinds = APPROVAL_GATE_KINDS;
|
|
1459
1459
|
const scan = `SELECT token FROM checkpoint WHERE status = 'pending' AND approval_card IS NULL AND gate_kind IN (${kinds.map((_, i) => ph(i + 1)).join(", ")}) ` +
|
|
1460
1460
|
`AND token > ${ph(kinds.length + 1)} ORDER BY token LIMIT ${PARKED_CARD_BACKFILL_PAGE}`;
|
|
@@ -1510,7 +1510,7 @@ function placedOwnerScanSql(dialect) {
|
|
|
1510
1510
|
"p.session_id AS parent_row, p.owner AS parent_owner, p.incarnation AS parent_incarnation, p.placement_kind AS parent_kind, " +
|
|
1511
1511
|
"c.placement_root_session_id AS root_id, c.placement_parent_session_id AS parent_id " +
|
|
1512
1512
|
"FROM session_meta c LEFT JOIN session_meta r ON r.session_id = NULLIF(c.placement_root_session_id, '') LEFT JOIN session_meta p ON p.session_id = NULLIF(c.placement_parent_session_id, '') " +
|
|
1513
|
-
`WHERE c.placement_kind IS NOT NULL AND c.owner IS NULL AND c.session_id > ${dialect === "
|
|
1513
|
+
`WHERE c.placement_kind IS NOT NULL AND c.owner IS NULL AND c.session_id > ${dialect === "mysql" ? "?" : "$1"} ORDER BY c.session_id LIMIT ${PLACED_OWNER_SCAN_PAGE}`);
|
|
1514
1514
|
}
|
|
1515
1515
|
function scannedPlacement(r) {
|
|
1516
1516
|
return {
|
|
@@ -128,8 +128,8 @@ export class SqlOrgDeliveryQuotaStore {
|
|
|
128
128
|
constructor(db) {
|
|
129
129
|
this.db = db;
|
|
130
130
|
}
|
|
131
|
-
q(
|
|
132
|
-
return this.db.dialect === "
|
|
131
|
+
q(mysql, pg) {
|
|
132
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
133
133
|
}
|
|
134
134
|
async admitAttempt(fromScope, policy) {
|
|
135
135
|
return this.inTx(ORG_DELIVERY_SENDER_QUOTA_TABLE, policy, (conn, at) => this.admitIn(conn, fromScope, at, policy));
|
|
@@ -87,8 +87,8 @@ export class SqlOutcomeLedger {
|
|
|
87
87
|
constructor(db) {
|
|
88
88
|
this.db = db;
|
|
89
89
|
}
|
|
90
|
-
q(
|
|
91
|
-
return this.db.dialect === "
|
|
90
|
+
q(mysql, pg) {
|
|
91
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
92
92
|
}
|
|
93
93
|
json(value) {
|
|
94
94
|
return dialectJsonEncoder(this.db.dialect)(value);
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { type PermissionRuleWriter, type DurableRulePartition, type DurableRulePartitionProvider, type RuleScope, type RuleSyncFrontier, type RuleBehavior, type RuleCandidate, type RuleApprovalRecord, type StaleRuleApprovalRecord, type RuleApprovalRecordStore, type RuleOwner } from "@sema-agent/core";
|
|
3
3
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
4
4
|
import type { PgQueryFn } from "./pg-query.js";
|
|
5
|
-
import { type SqlDriver } from "./sql-driver.js";
|
|
5
|
+
import { type SqlDriver, type SqlDialect } from "./sql-driver.js";
|
|
6
6
|
import { type IndexSpec } from "./ensure-index.js";
|
|
7
7
|
/**
|
|
8
8
|
* 一只 durable 分区的写面,或 `undefined`(该 backend 从引擎侧看是只读的)。
|
|
@@ -105,7 +105,7 @@ export declare function ensureTiDBPermissionRuleSchema(pool: MySqlPool): Promise
|
|
|
105
105
|
*/
|
|
106
106
|
export declare function assertPermissionRuleApprovalSchema(query: (sql: string) => Promise<{
|
|
107
107
|
rows: Record<string, unknown>[];
|
|
108
|
-
}>, dialect:
|
|
108
|
+
}>, dialect: SqlDialect): Promise<void>;
|
|
109
109
|
/**
|
|
110
110
|
* [ref] A7 升级前置断言 —— **拒启**(形与理由逐字照 {@link assertPermissionRuleApprovalSchema} 的配方,
|
|
111
111
|
* 那条头注写了这道门为什么必须是拒启而不是 warn:本仓不发 `ALTER TABLE`,`CREATE TABLE IF NOT EXISTS`
|
|
@@ -127,7 +127,7 @@ export declare function assertPermissionRuleApprovalSchema(query: (sql: string)
|
|
|
127
127
|
*/
|
|
128
128
|
export declare function assertPermissionRuleTicketSchema(query: (sql: string) => Promise<{
|
|
129
129
|
rows: Record<string, unknown>[];
|
|
130
|
-
}>, dialect:
|
|
130
|
+
}>, dialect: SqlDialect): Promise<void>;
|
|
131
131
|
/** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgPermissionRuleSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
132
132
|
export declare const PERMISSION_RULE_INDEXES: readonly IndexSpec[];
|
|
133
133
|
export declare function ensurePgPermissionRuleSchema(q: PgQueryFn): Promise<void>;
|
|
@@ -502,7 +502,7 @@ export interface UndurableScopePurgeDb {
|
|
|
502
502
|
* 读数写进调用方递进来的账(`into`,{@link UndurableScopePurgeReadings}):删掉的行在那只桶的回写提交之后追加 ⇒ 本函数半途抛出时,已删的行已经在账上;
|
|
503
503
|
* 错误**原样**上抛(不加工、不自铸拒因句 —— 收据由迁移段那一只收据账随拒因带走,[ref])。
|
|
504
504
|
*/
|
|
505
|
-
export declare function purgeUndurableScopeRows(db: UndurableScopePurgeDb, dialect:
|
|
505
|
+
export declare function purgeUndurableScopeRows(db: UndurableScopePurgeDb, dialect: SqlDialect, into: UndurableScopePurgeReadings, now?: () => number): Promise<void>;
|
|
506
506
|
/** 三个 SQL 面的一次性装配束(one driver, three faces)。`durable` = [ref] 的 durable 分区后端;
|
|
507
507
|
* 引擎接缝上的统一店由 `main.ts` 用 `createPermissionRuleStoreProvider({ durable })` 合成一次。 */
|
|
508
508
|
export interface PermissionRuleStores {
|