@sema-agent/server 7.138.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 +457 -7
- package/README.md +7 -4
- package/README.zh-CN.md +6 -4
- package/USAGE.md +91 -41
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +26 -26
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- 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/bench/s1/run-firm.js +2 -2
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/device-lane.d.ts +8 -3
- package/dist/boot/device-lane.js +7 -2
- package/dist/boot/execution-env.d.ts +4 -2
- package/dist/boot/execution-env.js +28 -34
- package/dist/boot/execution-lane.d.ts +9 -1
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/governance-seams.d.ts +3 -2
- package/dist/boot/governance-seams.js +9 -11
- 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 +25 -14
- package/dist/boot/resolve-spec.d.ts +4 -6
- package/dist/boot/resolve-spec.js +10 -13
- package/dist/boot/retention-lane.d.ts +5 -5
- package/dist/boot/retention-lane.js +0 -6
- package/dist/boot/runner-deps.d.ts +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.d.ts +0 -3
- package/dist/boot/session-faces.js +15 -8
- package/dist/boot/stage-02-web-admin-pull.js +2 -2
- 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-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -3
- 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-09-leader.js +1 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +7 -6
- 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 +37 -11
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/capabilities/mcp-probe.js +1 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +15 -7
- package/dist/capability-facts.js +8 -3
- package/dist/config-catalog.js +9 -8
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +33 -37
- package/dist/config-provider.js +51 -30
- package/dist/config-types.d.ts +21 -7
- package/dist/config.d.ts +33 -0
- package/dist/config.js +46 -16
- package/dist/delegated-session-owner.d.ts +4 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +10 -9
- package/dist/deployment-shape.js +4 -4
- package/dist/device-enrollment.d.ts +41 -2
- package/dist/device-enrollment.js +27 -12
- package/dist/device-store.d.ts +58 -85
- package/dist/device-store.js +19 -49
- package/dist/device-ws-hub.js +2 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -4
- package/dist/exec-cut.d.ts +60 -0
- package/dist/exec-cut.js +36 -0
- package/dist/execution-lane-caps.d.ts +115 -105
- package/dist/execution-lane-caps.js +76 -82
- package/dist/execution-placement.d.ts +259 -0
- package/dist/execution-placement.js +199 -0
- package/dist/field-conflict.d.ts +3 -2
- package/dist/field-conflict.js +1 -0
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +8 -19
- package/dist/http/checkpoint-ctx.d.ts +21 -12
- package/dist/http/checkpoint-ctx.js +4 -2
- package/dist/http/claimed-run.d.ts +1 -1
- package/dist/http/durable-run-leg.js +9 -5
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -0
- 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 +63 -36
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-ctx.d.ts +14 -8
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- 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/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +143 -22
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +4 -5
- package/dist/http/routes/tasks.js +41 -33
- package/dist/http/server.d.ts +40 -44
- package/dist/http/server.js +13 -2
- package/dist/http/session-inherit-env.d.ts +3 -4
- package/dist/http/session-inherit-env.js +1 -1
- package/dist/http/wire-types.d.ts +8 -12
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/index.d.ts +1 -0
- 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 +70 -18
- package/dist/memory-sync-client.js +215 -117
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.js +0 -1
- package/dist/orchestration/workflow-notify-journal.js +4 -4
- package/dist/org-memory-admission.d.ts +4 -3
- package/dist/org-memory-admission.js +6 -6
- package/dist/parked-decide.d.ts +34 -9
- package/dist/parked-decide.js +12 -19
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +13 -7
- package/dist/peer-seat.js +37 -3
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-file.d.ts +7 -0
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
- package/dist/plugins/approval-ask-store-sql.js +44 -26
- 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/caching-session-store.d.ts +6 -2
- package/dist/plugins/caching-session-store.js +9 -3
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
- package/dist/plugins/checkpoint-store-sql.js +21 -23
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +68 -122
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +151 -0
- package/dist/plugins/execution-placement-sql.js +223 -0
- package/dist/plugins/file-history-store-sql.d.ts +9 -8
- package/dist/plugins/file-history-store-sql.js +9 -9
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +4 -0
- package/dist/plugins/fork-routing-session-store.d.ts +6 -0
- package/dist/plugins/fork-routing-session-store.js +16 -0
- 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/local-session-store.d.ts +149 -50
- package/dist/plugins/local-session-store.js +382 -107
- 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-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +117 -8
- package/dist/plugins/one-time-migrations.js +408 -38
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
- package/dist/plugins/permission-rule-store-sql.js +29 -32
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +31 -20
- package/dist/plugins/pg-session-storage.js +120 -52
- package/dist/plugins/remote-env-adb.d.ts +18 -19
- package/dist/plugins/remote-env-adb.js +91 -66
- package/dist/plugins/remote-env-device.d.ts +23 -31
- package/dist/plugins/remote-env-device.js +19 -17
- package/dist/plugins/remote-env-e2b.d.ts +27 -21
- package/dist/plugins/remote-env-e2b.js +91 -45
- package/dist/plugins/remote-env-file-error.d.ts +3 -1
- package/dist/plugins/remote-env-file-error.js +9 -3
- package/dist/plugins/remote-env-host.d.ts +31 -34
- package/dist/plugins/remote-env-host.js +91 -72
- package/dist/plugins/remote-env-k8s.d.ts +13 -29
- package/dist/plugins/remote-env-k8s.js +63 -55
- package/dist/plugins/remote-env-local-docker.d.ts +24 -12
- package/dist/plugins/remote-env-local-docker.js +49 -61
- package/dist/plugins/remote-env-ssh.d.ts +11 -19
- package/dist/plugins/remote-env-ssh.js +74 -57
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- 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 +10 -7
- package/dist/plugins/retention-store-sql.js +13 -7
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +20 -15
- package/dist/plugins/schema-consistency.d.ts +21 -11
- package/dist/plugins/schema-consistency.js +15 -9
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- 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-fork.d.ts +54 -0
- package/dist/plugins/session-fork.js +38 -1
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-store.d.ts +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 +5 -7
- package/dist/plugins/store-backend.js +23 -11
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +13 -7
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +57 -26
- package/dist/plugins/tidb-session-store.js +127 -59
- package/dist/plugins/tool-result-store-sql.d.ts +5 -4
- package/dist/plugins/tool-result-store-sql.js +21 -13
- 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/project-memory.d.ts +9 -15
- package/dist/project-memory.js +5 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +6 -7
- package/dist/request-value-closure.js +1 -3
- 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.d.ts +6 -0
- package/dist/run-local.js +34 -35
- package/dist/runs.d.ts +10 -5
- package/dist/runs.js +52 -66
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +9 -5
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +20 -10
- package/dist/session-incarnation.js +5 -3
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-row.d.ts +114 -5
- package/dist/session-row.js +55 -5
- package/dist/session-titler.d.ts +2 -2
- 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.d.ts +1 -1
- package/dist/task-a2a.js +5 -6
- package/dist/task-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +22 -9
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +8 -1
- package/dist/trace/project.d.ts +1 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +169 -2
- package/dist/trace/self-minted-wire.js +54 -1
- package/dist/url-refusal.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +17 -3
- package/dist/web-admin-client/apply-effective.js +20 -10
- 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/dist/web-admin-client/skills-mcp.js +3 -2
- package/dist/web-admin-client/types.d.ts +6 -0
- package/package.json +3 -3
- package/wire-changes/server@7.139.0.json +348 -0
- package/wire-changes/server@7.140.0.json +184 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
|
@@ -9,6 +9,7 @@ import { recordFailOpen } from "../observability/fail-open.js";
|
|
|
9
9
|
import { durableRowIdentity, withoutCheckpointToken } from "../checkpoint-identity.js";
|
|
10
10
|
import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "./sql-driver.js";
|
|
11
11
|
import { isDupKeyError, isMissingColumnError, rowTooLargeOrSelf, StoreRowTooLargeError } from "./sql-errors.js";
|
|
12
|
+
import { describeProbedTableDrift } from "./schema-drift-sentence.js";
|
|
12
13
|
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
13
14
|
import { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
14
15
|
const CTX_REWRITE_PAGE = 500;
|
|
@@ -61,13 +62,10 @@ export async function assertCheckpointColumnSchema(query, dialect) {
|
|
|
61
62
|
throw err;
|
|
62
63
|
throw new Error(`checkpoint is missing the column ${column} — refusing to start. ` +
|
|
63
64
|
`On this table ${breaksAt} — at runtime, after a healthy-looking boot. ` +
|
|
64
|
-
"
|
|
65
|
-
"`
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"durable parks (suspended approvals/reviews awaiting a decision) — those cards are lost and their runs must be " +
|
|
69
|
-
"re-triggered; `checkpoint_ctx`, run rows and every other persistent face are untouched. " +
|
|
70
|
-
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}`);
|
|
65
|
+
"The table holds IN-FLIGHT durable parks (suspended approvals/reviews awaiting a decision), so the way forward is an in-place " +
|
|
66
|
+
"ALTER that keeps them; `checkpoint_ctx`, run rows and every other persistent face are untouched.\n" +
|
|
67
|
+
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
|
|
68
|
+
(await describeProbedTableDrift(query, dialect, ["checkpoint"])));
|
|
71
69
|
}
|
|
72
70
|
}
|
|
73
71
|
}
|
|
@@ -345,8 +343,8 @@ export class SqlCheckpointStore {
|
|
|
345
343
|
this.logger = logger;
|
|
346
344
|
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
347
345
|
}
|
|
348
|
-
q(
|
|
349
|
-
return this.db.dialect === "
|
|
346
|
+
q(mysql, pg) {
|
|
347
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
350
348
|
}
|
|
351
349
|
json(value, label) {
|
|
352
350
|
return dialectProtocolJsonEncoder(this.db.dialect)(value, label);
|
|
@@ -355,7 +353,7 @@ export class SqlCheckpointStore {
|
|
|
355
353
|
return isDupKeyError(this.db.dialect, e);
|
|
356
354
|
}
|
|
357
355
|
ph(n) {
|
|
358
|
-
return this.db.dialect === "
|
|
356
|
+
return this.db.dialect === "mysql" ? "?" : `$${n}`;
|
|
359
357
|
}
|
|
360
358
|
pendingRowQuery(select, sessionId, scope, binding) {
|
|
361
359
|
const params = [sessionId];
|
|
@@ -426,8 +424,8 @@ export class SqlCheckpointStore {
|
|
|
426
424
|
}
|
|
427
425
|
}
|
|
428
426
|
async get(token) {
|
|
429
|
-
const { rows } = await this.db.query(this.q(`SELECT version, status, ${jsonColumnText("
|
|
430
|
-
`${jsonColumnText("
|
|
427
|
+
const { rows } = await this.db.query(this.q(`SELECT version, status, ${jsonColumnText("mysql", "checkpoint")}, ${jsonColumnText("mysql", "outcome")}, reopen_reason, rev, ` +
|
|
428
|
+
`${jsonColumnText("mysql", "pending_steer_queue")}, ${jsonColumnText("mysql", "execution_outcome")}, execution_at_ms FROM checkpoint WHERE token = ?`, `SELECT version, status, ${jsonColumnText("pg", "checkpoint")}, ${jsonColumnText("pg", "outcome")}, reopen_reason, rev, ` +
|
|
431
429
|
`${jsonColumnText("pg", "pending_steer_queue")}, ${jsonColumnText("pg", "execution_outcome")}, execution_at_ms FROM checkpoint WHERE token = $1`), [token]);
|
|
432
430
|
const r = rows[0];
|
|
433
431
|
if (!r)
|
|
@@ -482,7 +480,7 @@ export class SqlCheckpointStore {
|
|
|
482
480
|
}
|
|
483
481
|
async recordExecutionOutcome(token, scope, gate) {
|
|
484
482
|
for (let attempt = 0; attempt < EXECUTION_RECORD_CAS_ATTEMPTS; attempt++) {
|
|
485
|
-
const { rows } = await this.db.query(this.q(`SELECT scope, status, ${jsonColumnText("
|
|
483
|
+
const { rows } = await this.db.query(this.q(`SELECT scope, status, ${jsonColumnText("mysql", "execution_outcome")} FROM checkpoint WHERE token = ?`, `SELECT scope, status, ${jsonColumnText("pg", "execution_outcome")} FROM checkpoint WHERE token = $1`), [token]);
|
|
486
484
|
const row = rows[0];
|
|
487
485
|
const facts = row === undefined
|
|
488
486
|
? undefined
|
|
@@ -506,7 +504,7 @@ export class SqlCheckpointStore {
|
|
|
506
504
|
async setPendingSteer(token, scope, steer) {
|
|
507
505
|
const clean = validatePendingSteer(steer);
|
|
508
506
|
for (let attempt = 0; attempt < STEER_CAS_ATTEMPTS; attempt++) {
|
|
509
|
-
const { rows } = await this.db.query(this.q(`SELECT status, ${jsonColumnText("
|
|
507
|
+
const { rows } = await this.db.query(this.q(`SELECT status, ${jsonColumnText("mysql", "pending_steer_queue")}, pending_steer_rev FROM checkpoint WHERE token = ? AND scope = ?`, `SELECT status, ${jsonColumnText("pg", "pending_steer_queue")}, pending_steer_rev FROM checkpoint WHERE token = $1 AND scope = $2`), [token, scope]);
|
|
510
508
|
const row = rows[0];
|
|
511
509
|
if (!row || row.status !== "pending")
|
|
512
510
|
return false;
|
|
@@ -539,12 +537,12 @@ export class SqlCheckpointStore {
|
|
|
539
537
|
}
|
|
540
538
|
async reapExpired(cutoff) {
|
|
541
539
|
const res = await this.db.query(this.q("UPDATE checkpoint SET status = 'expired', decided_at_ms = ? " +
|
|
542
|
-
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= ? AND COALESCE(${CHECKPOINT_FACET_SQL.
|
|
540
|
+
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= ? AND COALESCE(${CHECKPOINT_FACET_SQL.mysql}, '') <> 'A') OR (terminal_at_ms IS NOT NULL AND terminal_at_ms <= ?))`, "UPDATE checkpoint SET status = 'expired', decided_at_ms = $1 " +
|
|
543
541
|
`WHERE status = 'pending' AND ((deadline IS NOT NULL AND deadline <= $2 AND COALESCE(${CHECKPOINT_FACET_SQL.pg}, '') <> 'A') OR (terminal_at_ms IS NOT NULL AND terminal_at_ms <= $3))`), [Date.now(), cutoff, cutoff]);
|
|
544
542
|
return res.affected;
|
|
545
543
|
}
|
|
546
544
|
async listExpiredApprovalGates(cutoff, limit = 100) {
|
|
547
|
-
const { rows } = await this.db.query(this.q(`SELECT session_id, scope FROM checkpoint WHERE status = 'pending' AND deadline IS NOT NULL AND deadline <= ? AND ${CHECKPOINT_FACET_SQL.
|
|
545
|
+
const { rows } = await this.db.query(this.q(`SELECT session_id, scope FROM checkpoint WHERE status = 'pending' AND deadline IS NOT NULL AND deadline <= ? AND ${CHECKPOINT_FACET_SQL.mysql} = 'A' ORDER BY ${CHECKPOINT_SWEEP_ORDER_SQL} LIMIT ?`, `SELECT session_id, scope FROM checkpoint WHERE status = 'pending' AND deadline IS NOT NULL AND deadline <= $1 AND ${CHECKPOINT_FACET_SQL.pg} = 'A' ORDER BY ${CHECKPOINT_SWEEP_ORDER_SQL} LIMIT $2`), [cutoff, limit]);
|
|
548
546
|
return rows.map((r) => ({ sessionId: String(r.session_id), scope: String(r.scope) }));
|
|
549
547
|
}
|
|
550
548
|
async listPending(scope) {
|
|
@@ -593,7 +591,7 @@ export class SqlCheckpointStore {
|
|
|
593
591
|
return out.sort((a, b) => (b.riskDescriptor?.severity ?? 0) - (a.riskDescriptor?.severity ?? 0) || a.createdAt - b.createdAt);
|
|
594
592
|
}
|
|
595
593
|
async readParkedSkillCardFacts(token) {
|
|
596
|
-
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("
|
|
594
|
+
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("mysql", "checkpoint")} FROM checkpoint WHERE token = ? AND status = 'pending'`, `SELECT ${jsonColumnText("pg", "checkpoint")} FROM checkpoint WHERE token = $1 AND status = 'pending'`), [token]);
|
|
597
595
|
const r = rows[0];
|
|
598
596
|
if (r === undefined)
|
|
599
597
|
return {};
|
|
@@ -616,7 +614,7 @@ export class SqlCheckpointStore {
|
|
|
616
614
|
}
|
|
617
615
|
}
|
|
618
616
|
async listByScope(scope) {
|
|
619
|
-
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("
|
|
617
|
+
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("mysql", "checkpoint")}, status FROM checkpoint WHERE status = 'pending' AND scope = ? ORDER BY created_at_ms ASC LIMIT 500`, `SELECT ${jsonColumnText("pg", "checkpoint")}, status FROM checkpoint WHERE status = 'pending' AND scope = $1 ORDER BY created_at_ms ASC LIMIT 500`), [scope]);
|
|
620
618
|
const out = [];
|
|
621
619
|
for (const r of rows) {
|
|
622
620
|
const cp = refusing("a checkpoint nobody can resume", () => decodeCheckpointColumn(r.checkpoint, `in the ${scope} scheduler view`));
|
|
@@ -635,7 +633,7 @@ export class SqlCheckpointStore {
|
|
|
635
633
|
return rows[0] ? String(rows[0].token) : null;
|
|
636
634
|
}
|
|
637
635
|
async findCheckpointCandidatesForAsk(scope, sessionId, toolCallId, sinceMs) {
|
|
638
|
-
const { rows } = await this.db.query(this.q(`SELECT token, status, created_at_ms, tool_call_id, bound_input_hash, version, ${jsonColumnText("
|
|
636
|
+
const { rows } = await this.db.query(this.q(`SELECT token, status, created_at_ms, tool_call_id, bound_input_hash, version, ${jsonColumnText("mysql", "checkpoint")} FROM checkpoint ` +
|
|
639
637
|
"WHERE scope=? AND session_id=? AND created_at_ms>=? AND (tool_call_id=? OR tool_call_id IS NULL) ORDER BY created_at_ms ASC", `SELECT token, status, created_at_ms, tool_call_id, bound_input_hash, version, ${jsonColumnText("pg", "checkpoint")} FROM checkpoint ` +
|
|
640
638
|
"WHERE scope=$1 AND session_id=$2 AND created_at_ms>=$3 AND (tool_call_id=$4 OR tool_call_id IS NULL) ORDER BY created_at_ms ASC"), [scope, sessionId, sinceMs, toolCallId]);
|
|
641
639
|
const out = [];
|
|
@@ -673,7 +671,7 @@ export class SqlCheckpointStore {
|
|
|
673
671
|
return out;
|
|
674
672
|
}
|
|
675
673
|
async findDecidedApprovalsForBinding(sessionId, boundCallId) {
|
|
676
|
-
const { rows } = await this.db.query(this.q(`SELECT scope, bound_input_hash, ${jsonColumnText("
|
|
674
|
+
const { rows } = await this.db.query(this.q(`SELECT scope, bound_input_hash, ${jsonColumnText("mysql", "outcome")}, ${jsonColumnText("mysql", "execution_outcome")} FROM checkpoint ` +
|
|
677
675
|
`WHERE session_id=? AND tool_call_id=? AND status='resolved' AND decided_at_ms IS NOT NULL ORDER BY decided_at_ms DESC LIMIT ${DECIDED_REPLAY_SCAN_CAP}`, `SELECT scope, bound_input_hash, ${jsonColumnText("pg", "outcome")}, ${jsonColumnText("pg", "execution_outcome")} FROM checkpoint ` +
|
|
678
676
|
`WHERE session_id=$1 AND tool_call_id=$2 AND status='resolved' AND decided_at_ms IS NOT NULL ORDER BY decided_at_ms DESC LIMIT ${DECIDED_REPLAY_SCAN_CAP}`), [sessionId, boundCallId]);
|
|
679
677
|
return rows.map((r) => {
|
|
@@ -735,14 +733,14 @@ export class SqlCheckpointStore {
|
|
|
735
733
|
}
|
|
736
734
|
}
|
|
737
735
|
async getCtx(sessionId) {
|
|
738
|
-
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("
|
|
736
|
+
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("mysql", "ctx")} FROM checkpoint_ctx WHERE session_id=?`, `SELECT ${jsonColumnText("pg", "ctx")} FROM checkpoint_ctx WHERE session_id=$1`), [sessionId]);
|
|
739
737
|
return rows[0] ? refusing("a resume context nobody can read", () => decodeCtxColumn(rows[0].ctx, `for session ${JSON.stringify(sessionId)}`)) : null;
|
|
740
738
|
}
|
|
741
739
|
async rewriteCtxRows(rewrite) {
|
|
742
740
|
const out = { scanned: 0, rewritten: 0, valuesRewritten: 0, unreadable: 0, tooLarge: 0 };
|
|
743
741
|
let after = "";
|
|
744
742
|
for (;;) {
|
|
745
|
-
const { rows } = await this.db.query(this.q(`SELECT session_id, ${jsonColumnText("
|
|
743
|
+
const { rows } = await this.db.query(this.q(`SELECT session_id, ${jsonColumnText("mysql", "ctx")} FROM checkpoint_ctx WHERE session_id > ? ORDER BY session_id LIMIT ${CTX_REWRITE_PAGE}`, `SELECT session_id, ${jsonColumnText("pg", "ctx")} FROM checkpoint_ctx WHERE session_id > $1 ORDER BY session_id LIMIT ${CTX_REWRITE_PAGE}`), [after]);
|
|
746
744
|
for (const row of rows) {
|
|
747
745
|
const sessionId = String(row.session_id);
|
|
748
746
|
after = sessionId;
|
|
@@ -791,7 +789,7 @@ export class SqlCheckpointStore {
|
|
|
791
789
|
}
|
|
792
790
|
async deleteBySession(sessionId, owner) {
|
|
793
791
|
const ownerGuard = this.q("EXISTS (SELECT 1 FROM session_meta sm WHERE sm.session_id = ? AND sm.owner <=> ?)", "EXISTS (SELECT 1 FROM session_meta sm WHERE sm.session_id = $1 AND sm.owner IS NOT DISTINCT FROM $2)");
|
|
794
|
-
const params = this.db.dialect === "
|
|
792
|
+
const params = this.db.dialect === "mysql" ? [sessionId, sessionId, owner] : [sessionId, owner];
|
|
795
793
|
const res = await this.db.query(this.q(`DELETE FROM checkpoint WHERE session_id = ? AND ${ownerGuard}`, `DELETE FROM checkpoint WHERE session_id = $1 AND ${ownerGuard}`), params);
|
|
796
794
|
await this.db.query(this.q(`DELETE FROM checkpoint_ctx WHERE session_id = ? AND ${ownerGuard}`, `DELETE FROM checkpoint_ctx WHERE session_id = $1 AND ${ownerGuard}`), params);
|
|
797
795
|
return res.affected;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* device lane
|
|
2
|
+
* device lane 三表持久层(design/device-executor-lane-v2 §6)—— `DeviceStore` 双方言实现
|
|
3
3
|
* (`TiDBDeviceStore` / `PgDeviceStore`,SINGLE-FILE DUAL-DIALECT,[ref] A12 形:一个
|
|
4
4
|
* `SqlDeviceStore` 接 `SqlDriver`,两个薄 ctor 子类落方言绑定)。语义真源 = `../device-store.js`
|
|
5
5
|
* (类型 + 闭集 + InMemory 参照实现),准入链 = `../device-enrollment.js`。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* 三张表:
|
|
8
8
|
* · `devices` —— 设备注册簿 + presence 投影(单设备单活连 ⇒ 1:1,省一次 join,§6 注①)
|
|
9
9
|
* · `device_enroll_tokens` —— 一次性 enrollment 凭据(明文一现,落库只有 sha256)
|
|
10
|
-
* · `device_sessions` —— **根会话**↔设备绑定(resume 路由真源,§4.5)
|
|
11
10
|
* · `device_audit` —— 安全轴事件审计(§4.8 标「审计行」的 8 个 event)
|
|
11
|
+
* **根会话 ↔ 设备绑定不在本店的表里**:它是根会话行(`session_meta`)上这一位住客的执行格 writer(device, D)(列与语句的唯一属主 =
|
|
12
|
+
* `execution-placement-sql.ts`;规则在 `../execution-placement.ts` 头注)。读只经会话店的执行席 `seat.read(root)`;本店只有两只写 ——
|
|
13
|
+
* 首绑 {@link SqlDeviceStore.placeDeviceExecution} 与换绑 {@link SqlDeviceStore.rebindDeviceExecution},各是一只事务,锁序全局一条:设备行 → 根 `session_meta` → `task_*`。
|
|
12
14
|
* 刻意**没有** `device_instructions` 表:指令 pending 表是内存态(§6 注③——指令比 run 短命,落库只会
|
|
13
15
|
* 造「表里 pending、run 已死」的僵尸行;at-most-once 靠 §5.3 投递边界,不靠指令落库)。
|
|
14
16
|
*
|
|
@@ -26,7 +28,6 @@
|
|
|
26
28
|
*
|
|
27
29
|
* ── 方言差异(A12 doctrine:每处显式写在调用点)────────────────────────────────────────────────────
|
|
28
30
|
* - `?`(位置序) vs `$n`(显式编号);动态 WHERE(`listAudit`)靠 `ph(dialect, n)` 生成。
|
|
29
|
-
* - `INSERT IGNORE` vs `ON CONFLICT (pk) DO NOTHING`(`bindSession` 的首绑 CAS)。
|
|
30
31
|
* - `AUTO_INCREMENT` vs `BIGSERIAL`;`JSON` vs `JSONB`(+ `$n::jsonb` 显式 cast)。
|
|
31
32
|
* - `KEY …` 内联 vs 独立 `CREATE INDEX IF NOT EXISTS`。
|
|
32
33
|
* - 回读名单:两方言**同走**同事务 `UPDATE` 后 `SELECT`(PG 本可用 RETURNING,为保单一读路径不用——
|
|
@@ -46,19 +47,18 @@
|
|
|
46
47
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
47
48
|
import type { Pool as PgPool } from "pg";
|
|
48
49
|
import { type SqlDriver } from "./sql-driver.js";
|
|
49
|
-
import { type AcquireConnectionInput, type AcquireConnectionResult, type AppendAuditInput, type
|
|
50
|
+
import { type AcquireConnectionInput, type AcquireConnectionResult, type AppendAuditInput, type ConsumeEnrollTokenInput, type ConsumeEnrollTokenResult, type DeviceAdmissionView, type DeviceAuditRow, type DeviceEnrollTokenRow, type DeviceOwner, type DeviceRow, type DeviceStore, type HeartbeatConnectionInput, type IssueEnrollTokenInput, type ListAuditFilter, type PlaceDeviceExecutionInput, type PlaceDeviceExecutionResult, type RebindDeviceExecutionInput, type RebindDeviceExecutionResult, type RevokeDeviceInput, type RevokeDeviceResult } from "../device-store.js";
|
|
50
51
|
import { type IndexSpec } from "./ensure-index.js";
|
|
51
52
|
/**
|
|
52
53
|
* ── 命名(**落库一律单数**,与设计稿的复数形不同)──────────────────────────────────────────────────
|
|
53
|
-
* design v2 §6 的 DDL 写的是 `devices` / `
|
|
54
|
+
* design v2 §6 的 DDL 写的是 `devices` / `device_enrollment_tokens` / `device_audit`(复数),但本仓有一条
|
|
54
55
|
* 常驻机器门:`test/schema-naming-invariants.test.ts` 判据① —— 建表的表名必须在 `TABLE_VOCABULARY` 闭集里
|
|
55
56
|
* **且词表全是单数形**。[ref] 车1 的 `retention_hold` / `retention_tombstone` 是同一处先例(那份设计稿同样
|
|
56
|
-
* 写的复数,落库单数)
|
|
57
|
+
* 写的复数,落库单数)。所以三张表落库名为 `device` / `device_enroll_token` /
|
|
57
58
|
* `device_audit`,**表结构与设计稿逐列一致**,只有名字随仓规。新表 = 先进词表再建。
|
|
58
59
|
*/
|
|
59
60
|
export declare const DEVICES_TABLE = "device";
|
|
60
61
|
export declare const DEVICE_ENROLL_TOKENS_TABLE = "device_enroll_token";
|
|
61
|
-
export declare const DEVICE_SESSIONS_TABLE = "device_session";
|
|
62
62
|
export declare const DEVICE_AUDIT_TABLE = "device_audit";
|
|
63
63
|
export declare const TIDB_DEVICE_STATEMENTS: readonly string[];
|
|
64
64
|
/** {@link TIDB_DEVICE_STATEMENTS} 的遍历壳(集成测试用;生产装配由中央 ensureSchema 展开同一份数组)。 */
|
|
@@ -134,55 +134,29 @@ export declare class SqlDeviceStore implements DeviceStore {
|
|
|
134
134
|
heartbeatConnection(input: HeartbeatConnectionInput): Promise<boolean>;
|
|
135
135
|
releaseConnection(deviceId: string, generation: number): Promise<boolean>;
|
|
136
136
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* 的旧版本,于是把 session 绑到一台**刚被吊销**的设备上(double-admit 形)。锁读在两引擎都是当前读 ——
|
|
141
|
-
* 前提写在 {@link SqlTxConn.begin} 的 @contract txn.read-semantics。这把锁在 `devices` 表上,与下面
|
|
142
|
-
* 被插入的 `device_session` 行不是同一行。
|
|
143
|
-
*
|
|
144
|
-
* 🔴 形 B · cas-insert([ref] / [ref])—— 本站点是全仓 `INSERT IGNORE` 的**正当用法**:
|
|
145
|
-
* `INSERT IGNORE` / `ON CONFLICT DO NOTHING` 的 affected(1/0)是引擎对「谁赢」的**权威**回答,而
|
|
146
|
-
* `ON DUPLICATE KEY UPDATE pk = pk` 的 affected 新行/既有行都是 1、分不出赢家 ⇒ 这里换不得动词。
|
|
147
|
-
* 代价必须付清:**同一事务此后不得对被插入的那一行做加锁读**。InnoDB 下撞重复键的 IGNORE 在既有行
|
|
148
|
-
* 取 **S 锁**,随后的 `SELECT … FOR UPDATE` 要升 X;两个并发首绑各持一把 S 互等 ⇒ ER_LOCK_DEADLOCK
|
|
149
|
-
* (TiDB 悲观事务无共享锁,这一形在它上面恒绿 —— 双库门看不见)。于是两条路径分家:
|
|
150
|
-
* · **赢家**(affected === 1):行是自己刚插的,回执用**入参 + 插入时刻**直接构造,零回读。插入时刻
|
|
151
|
-
* 仍由 **DB 时钟**给出(插入前一句 `SELECT NOW(3)` / `SELECT now()`,再把它当参数写进 INSERT)——
|
|
152
|
-
* 时间权威留在 DB,回执里的 `boundAtMs` 与落库值**逐字节同一个**,不是应用侧的近似。
|
|
153
|
-
* · **输家**(affected === 0):**结束当前事务**,在**新事务**里 `SELECT … FOR UPDATE` 观察。那一刻
|
|
154
|
-
* 赢家已提交,读到的是一把干净的 X 锁(无升级);判 同 deviceId = 幂等成功,异 deviceId =
|
|
155
|
-
* `conflict`(无未定义态)。设备状态门在输家路径上已经过完,不需要重来。
|
|
137
|
+
* 设备行的**当前读**(`FOR UPDATE`):首绑 / 换绑两只事务的第一句(全局锁序的第一把:设备行 → 根 `session_meta` → `task_*`)。
|
|
138
|
+
* 普通读下,一次与吊销并发的绑定会读到「还 active」的旧版本,于是把会话绑到一台**刚被吊销**的设备上(double-admit 形);锁读在两引擎都是当前读 ——
|
|
139
|
+
* 前提写在 {@link SqlTxConn.begin} 的 @contract txn.read-semantics。行不在 / 不是该属主的 ⇒ `undefined`(反枚举同形)。
|
|
156
140
|
*/
|
|
157
|
-
|
|
141
|
+
private lockDeviceStatus;
|
|
158
142
|
/**
|
|
159
|
-
* 首绑
|
|
143
|
+
* §4.3.2 首绑(§3.3 转换表 place / bind 两行)—— **一只事务**:锁设备行(active ∧ 属主)→ 锁定读根会话行的执行格 → 判官
|
|
144
|
+
* {@link settledDeviceBindOutcome}(与内存参照实现同一只)→ absent 用 place 语句、writer(device, ∅) 用 bind 语句,写只按住客谓词。
|
|
160
145
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* 并发输家不会互等([ref] 的死锁形正是那次升级)。
|
|
166
|
-
*
|
|
167
|
-
* 行不在 = 赢家的绑定在这一瞬被 `unbindSession` 删了(真实可能,不是不变量破)。这仍然是**响亮**的:
|
|
168
|
-
* 首绑既没成、也说不出冲突对象,折成任何一种业务回执都是撒谎([ref]:未知失败不伪装成正常拒绝)。
|
|
146
|
+
* 不读认领:这是认领持有者自己的初始放置写(读写序律唯一的例外,`execution-placement-sql.ts` 头注)。锁序:设备行 → 根 `session_meta`。
|
|
147
|
+
* 持着根行的锁判过「可写」之后那句 UPDATE 不可能 0 行 —— 0 行即驱动 / 引擎异常,响亮抛,不折成业务分支([ref])。
|
|
148
|
+
* 并发两只首绑在根行锁上串行:输家的锁定读看到赢家的格 ⇒ 同设备 `same`(幂等成功)/ 异设备 `device_conflict`(单赢家,无未定义态);
|
|
149
|
+
* 修前的 `INSERT IGNORE` 撞键 S 锁升级死锁形([ref])在这里不存在 —— 两边取的都是同一行的 X 锁,没有升级。
|
|
169
150
|
*/
|
|
170
|
-
|
|
151
|
+
placeDeviceExecution(input: PlaceDeviceExecutionInput): Promise<PlaceDeviceExecutionResult>;
|
|
171
152
|
/**
|
|
172
|
-
* O4 显式换绑(2026-08-30 v2 稿 §2)——
|
|
173
|
-
* `
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* · 设备行必须当前读 —— 快照读会把「与吊销并发的换绑」绑到一台刚被吊销的设备上(double-admit 形);
|
|
178
|
-
* · 绑定行必须当前读且**持锁到提交** —— 两个并发换绑(同 expectedRev)在锁上串行:赢家 rev+1 提交,
|
|
179
|
-
* 输家的锁读看到新 rev ⇒ 走 `rev_conflict` 携当前行(单赢家,无未定义态)。锁读判等之后,CAS
|
|
180
|
-
* UPDATE(`rev = ?` 谓词 + `rev+1` 恒变列)在持锁下不可能 0 行 —— 0 行即驱动/引擎异常,响亮抛,
|
|
181
|
-
* 不折成业务分支([ref]:未知失败不伪装成正常拒绝)。
|
|
153
|
+
* O4 显式换绑(2026-08-30 v2 稿 §2;§3.3 转换表 rebind 行)—— **一只事务**:锁目标设备行(在 / 属 owner / 未吊销)→ 读写序律那一读
|
|
154
|
+
* {@link lockRootAndReadClaim}(用本事务自己的连接先 `FOR UPDATE` 锁根 `session_meta` 行,再新语句锁定读 `task_active`;有认领 ⇒ `active_run`,
|
|
155
|
+
* 什么都不写 —— 这一读是「换绑不与在飞 run 交错」的**保证**,路由的池级 `getActiveTaskId` 只作早拒)→ 锁定读执行格 → 判官
|
|
156
|
+
* {@link settledDeviceRebindOutcome}(住客 ∧ 两属主列 ∧ rev;幂等短路先于写)→ CAS(`execution_rev + 1` 恒变列)→ `session_rebound` 审计行,同一事务提交。
|
|
157
|
+
* 审计写不进去 = 整次换绑失败(fail-closed,[ref])。持锁判过之后 CAS 不可能 0 行 —— 0 行即引擎异常,响亮抛。三形语义 oracle = `InMemoryDeviceStore.rebindDeviceExecution`。
|
|
182
158
|
*/
|
|
183
|
-
|
|
184
|
-
getSessionBinding(rootSessionId: string): Promise<DeviceSessionRow | null>;
|
|
185
|
-
deleteByRootSession(rootSessionId: string): Promise<number>;
|
|
159
|
+
rebindDeviceExecution(input: RebindDeviceExecutionInput): Promise<RebindDeviceExecutionResult>;
|
|
186
160
|
appendAudit(input: AppendAuditInput): Promise<void>;
|
|
187
161
|
/** 审计写的**唯一**语句(池级与事务内共用;`SqlExec` 是两者的公共面)。 */
|
|
188
162
|
private insertAuditOn;
|