@sema-agent/server 7.139.0 → 7.141.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 +471 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +94 -26
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +37 -22
- package/dist/approval-card.js +6 -3
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +10 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +2 -2
- 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/device-lane.d.ts +11 -0
- package/dist/boot/device-lane.js +16 -0
- package/dist/boot/engine-lease.d.ts +24 -3
- package/dist/boot/engine-lease.js +9 -2
- package/dist/boot/execution-env.js +18 -12
- package/dist/boot/execution-lane.d.ts +8 -0
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/memory-boundary.d.ts +16 -53
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +16 -12
- package/dist/boot/memory-consolidation.js +24 -13
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/resolve-spec.d.ts +3 -5
- package/dist/boot/resolve-spec.js +9 -8
- package/dist/boot/runner-deps.d.ts +3 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +5 -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-05-execution-env.js +3 -1
- package/dist/boot/stage-06-runners.d.ts +2 -8
- package/dist/boot/stage-06-runners.js +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -7
- package/dist/boot/stage-07-capability-layer.js +8 -10
- package/dist/boot/stage-08-reapers.d.ts +2 -7
- package/dist/boot/stage-09-leader.d.ts +2 -7
- package/dist/boot/stage-10-http-server.d.ts +2 -7
- package/dist/boot/stage-10-http-server.js +6 -4
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +37 -44
- 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 +36 -9
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +9 -0
- package/dist/capability-facts.js +9 -0
- package/dist/card-void.d.ts +38 -0
- package/dist/card-void.js +23 -0
- package/dist/config-catalog.js +12 -8
- package/dist/config-provider.d.ts +18 -17
- package/dist/config-provider.js +28 -36
- package/dist/config-types.d.ts +36 -9
- package/dist/config.js +56 -46
- package/dist/delegated-session-owner.d.ts +23 -20
- package/dist/delegated-session-owner.js +2 -2
- package/dist/deployment-shape.d.ts +9 -8
- package/dist/deployment-shape.js +4 -4
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +3 -0
- package/dist/execution-config-root.d.ts +22 -0
- package/dist/execution-config-root.js +35 -0
- package/dist/execution-lane-caps.d.ts +145 -107
- package/dist/execution-lane-caps.js +144 -83
- package/dist/execution-placement.d.ts +3 -0
- package/dist/execution-placement.js +7 -0
- package/dist/fleet/drain-entry.d.ts +3 -0
- package/dist/hosted-posture.d.ts +8 -0
- package/dist/hosted-posture.js +4 -0
- package/dist/http/admission.js +3 -3
- package/dist/http/caller-trust.d.ts +3 -2
- package/dist/http/caller-trust.js +2 -1
- package/dist/http/dispatch.js +4 -0
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -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 +49 -35
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/diagnostics.d.ts +0 -19
- package/dist/http/routes/diagnostics.js +16 -2
- package/dist/http/routes/memory-bundle.d.ts +2 -2
- package/dist/http/routes/memory-bundle.js +4 -1
- package/dist/http/routes/memory-compliance.js +9 -2
- 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 +7 -2
- package/dist/http/routes/run-permission-mode.d.ts +75 -0
- package/dist/http/routes/run-permission-mode.js +170 -0
- package/dist/http/routes/session-sync.d.ts +3 -6
- package/dist/http/routes/session-sync.js +7 -2
- package/dist/http/routes/sessions.js +33 -15
- package/dist/http/routes/tasks.js +67 -68
- package/dist/http/run-read-face.js +3 -3
- package/dist/http/send.d.ts +1 -1
- package/dist/http/send.js +2 -2
- package/dist/http/server.d.ts +14 -27
- package/dist/http/server.js +2 -2
- package/dist/http/sse-log.d.ts +3 -8
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +3 -1
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- 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/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- 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-posture.d.ts +1 -1
- 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 +33 -9
- package/dist/memory-scope.js +17 -5
- package/dist/memory-sync-client.d.ts +34 -9
- package/dist/memory-sync-client.js +108 -28
- package/dist/observability/fail-open.d.ts +30 -2
- package/dist/observability/fail-open.js +30 -2
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +6 -2
- package/dist/observability/run-terminal.js +25 -26
- package/dist/observability/secret-env-scrub.d.ts +20 -1
- package/dist/observability/secret-env-scrub.js +14 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
- package/dist/orchestration/workflow-completion-inbox.js +13 -5
- package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/permission-mode-admission.d.ts +68 -0
- package/dist/permission-mode-admission.js +23 -0
- package/dist/permission-rule-list.d.ts +55 -6
- package/dist/permission-rule-list.js +52 -5
- 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/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +90 -19
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +23 -20
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +19 -9
- package/dist/plugins/execution-placement-sql.js +20 -9
- package/dist/plugins/file-history-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.js +4 -4
- package/dist/plugins/file-run-store.d.ts +2 -2
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/local-checkpoint-store.d.ts +10 -1
- package/dist/plugins/local-checkpoint-store.js +22 -0
- package/dist/plugins/local-session-store.d.ts +227 -35
- package/dist/plugins/local-session-store.js +518 -37
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- 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-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +52 -11
- package/dist/plugins/one-time-migrations.js +101 -39
- 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/pg-pool.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +3 -2
- 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 +40 -27
- package/dist/plugins/remote-env-e2b.js +180 -20
- 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 +22 -14
- package/dist/plugins/remote-env-k8s.js +150 -26
- package/dist/plugins/remote-env-local-docker.d.ts +27 -24
- package/dist/plugins/remote-env-local-docker.js +91 -24
- 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.d.ts +3 -3
- package/dist/plugins/run-store-sql.js +19 -18
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- 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-ownership.d.ts +2 -1
- package/dist/plugins/session-placement.d.ts +17 -4
- package/dist/plugins/session-placement.js +2 -1
- 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 +18 -20
- package/dist/plugins/session-store.js +4 -12
- 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 +35 -6
- package/dist/plugins/store-backend.js +27 -10
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.js +7 -6
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +16 -15
- 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-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/run-local.js +14 -19
- package/dist/runs.d.ts +47 -16
- package/dist/runs.js +112 -113
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +22 -4
- package/dist/session-error-wire.js +16 -0
- package/dist/session-incarnation.d.ts +10 -4
- package/dist/session-incarnation.js +1 -1
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +42 -1
- package/dist/session-sync-kernel.js +17 -0
- package/dist/session-sync.js +16 -4
- package/dist/sql-engine-coordinates.d.ts +49 -0
- package/dist/sql-engine-coordinates.js +27 -0
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- package/dist/standing-answer-grant.d.ts +31 -2
- package/dist/standing-answer-grant.js +14 -2
- package/dist/store-posture.d.ts +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-mcp.d.ts +21 -8
- package/dist/task-mcp.js +17 -9
- package/dist/task-settings.d.ts +52 -25
- package/dist/task-settings.js +91 -28
- package/dist/terminal.d.ts +103 -19
- package/dist/terminal.js +72 -20
- package/dist/trace/core-keyset-guard.d.ts +79 -2
- package/dist/trace/exit-seat.d.ts +7 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +395 -110
- package/dist/trace/self-minted-wire.d.ts +226 -2
- package/dist/trace/self-minted-wire.js +79 -0
- package/dist/verifier-pause-card.d.ts +8 -0
- package/dist/verifier-pause-card.js +19 -0
- package/dist/web-admin-client/apply-effective.d.ts +5 -7
- package/dist/web-admin-client/apply-effective.js +2 -2
- 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/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.140.0.json +184 -0
- package/wire-changes/server@7.141.0.json +367 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* · **列定义唯一属主**(两方言):中央 DDL(`tidb-pool.ts` 的 `CREATE TABLE session_meta`、`pg-session-storage.ts` 的 `PG_SESSION_SCHEMA`)内插
|
|
7
7
|
* {@link sessionMetaPlacementColumnsDdl}(先例:`SESSION_META_INCARNATION_COLUMN`);起服列册对账(`schema-consistency.ts`)从同一份建表文本解析期望列集。
|
|
8
8
|
* 存量库的加列只由一次性迁移做,`ensureSchema` 不 ALTER(SCHEMA POLICY)。
|
|
9
|
-
* · **语句唯一属主**:会话店(执行席、导入写口)与设备店(首绑 / 换绑)、一次性迁移(搬绑定 / 回填)的事务都借这里的语句,别处零手写。
|
|
9
|
+
* · **语句唯一属主**:会话店(执行席、导入写口)与设备店(首绑 / 换绑 / 绑定数)、一次性迁移(搬绑定 / 回填)的事务都借这里的语句,别处零手写。
|
|
10
10
|
* 语句是方言无关的 `{ text, values }`(调用方用自己的连接跑:SqlDriver 的 `SqlTxConn`、node-pg 的客户端、mysql2 的连接都行)。
|
|
11
11
|
*
|
|
12
12
|
* ## 住客谓词(写与 judged 复核的唯一定址)
|
|
@@ -35,35 +35,35 @@ export interface PlacementStatement {
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const SESSION_META_PLACEMENT_COLUMNS: readonly [{
|
|
37
37
|
readonly name: "execution_role";
|
|
38
|
-
readonly
|
|
38
|
+
readonly mysql: "execution_role VARCHAR(16) NULL";
|
|
39
39
|
readonly pg: "execution_role VARCHAR(16) COLLATE \"C\"";
|
|
40
40
|
}, {
|
|
41
41
|
readonly name: "execution_lane";
|
|
42
|
-
readonly
|
|
42
|
+
readonly mysql: "execution_lane VARCHAR(32) NULL";
|
|
43
43
|
readonly pg: "execution_lane VARCHAR(32) COLLATE \"C\"";
|
|
44
44
|
}, {
|
|
45
45
|
readonly name: "execution_device_id";
|
|
46
|
-
readonly
|
|
46
|
+
readonly mysql: "execution_device_id VARCHAR(64) NULL";
|
|
47
47
|
readonly pg: "execution_device_id VARCHAR(64) COLLATE \"C\"";
|
|
48
48
|
}, {
|
|
49
49
|
readonly name: "execution_device_owner_tenant";
|
|
50
|
-
readonly
|
|
50
|
+
readonly mysql: "execution_device_owner_tenant VARCHAR(190) NULL";
|
|
51
51
|
readonly pg: "execution_device_owner_tenant VARCHAR(190) COLLATE \"C\"";
|
|
52
52
|
}, {
|
|
53
53
|
readonly name: "execution_device_owner_subject";
|
|
54
|
-
readonly
|
|
54
|
+
readonly mysql: "execution_device_owner_subject VARCHAR(190) NULL";
|
|
55
55
|
readonly pg: "execution_device_owner_subject VARCHAR(190) COLLATE \"C\"";
|
|
56
56
|
}, {
|
|
57
57
|
readonly name: "execution_placed_at";
|
|
58
|
-
readonly
|
|
58
|
+
readonly mysql: "execution_placed_at DATETIME(3) NULL";
|
|
59
59
|
readonly pg: "execution_placed_at TIMESTAMPTZ(3)";
|
|
60
60
|
}, {
|
|
61
61
|
readonly name: "execution_rev";
|
|
62
|
-
readonly
|
|
62
|
+
readonly mysql: "execution_rev BIGINT NULL";
|
|
63
63
|
readonly pg: "execution_rev BIGINT";
|
|
64
64
|
}, {
|
|
65
65
|
readonly name: "fork_key";
|
|
66
|
-
readonly
|
|
66
|
+
readonly mysql: "fork_key VARCHAR(255) NULL";
|
|
67
67
|
readonly pg: "fork_key VARCHAR(255) COLLATE \"C\"";
|
|
68
68
|
}];
|
|
69
69
|
/** 中央 DDL 内插的那一段(列与列之间逗号分隔,不带首尾逗号)。 */
|
|
@@ -100,6 +100,16 @@ export declare function bindDeviceStatement(dialect: SqlDialect, root: string, o
|
|
|
100
100
|
}, now: Date): PlacementStatement;
|
|
101
101
|
/** rebind:writer(device, D) → writer(device, D'),按住客 ∧ 两属主列 ∧ rev 定址,`execution_rev + 1`(恒变列)。属主两列不动(换绑只在同一属主的设备之间)。 */
|
|
102
102
|
export declare function rebindDeviceStatement(dialect: SqlDialect, root: string, occupant: SessionFace, owner: DeviceOwner, expectedRev: number, targetDeviceId: string, now: Date): PlacementStatement;
|
|
103
|
+
/**
|
|
104
|
+
* 带设备列的根会话行(非委派分区行上 `execution_device_id` 非空):绑定数的读只用它**缩小**读的行 —— 一条绑定必有设备列,反之不然;
|
|
105
|
+
* 是不是一条绑定只由行的唯一解码 {@link placementCellFromRow} + `boundDeviceOf` 判(SQL 不另判一遍)。两方言同一句。
|
|
106
|
+
*/
|
|
107
|
+
export declare function deviceCellRowsStatement(): PlacementStatement;
|
|
108
|
+
/**
|
|
109
|
+
* 绑定数:根会话行上 writer(device, D) 的格数(设备店 `countDeviceBindings` 的读;只交一个数)。逐行过唯一解码 ⇒ 解码器拒的行
|
|
110
|
+
* (设备在而属主 / rev / 时刻缺、设备落在别的车道)原样抛 {@link ExecutionPlacementRowError},不当一条绑定数进去,也不当没有。
|
|
111
|
+
*/
|
|
112
|
+
export declare function countDeviceBindingsOn(conn: PlacementRowsOn): Promise<number>;
|
|
103
113
|
/** identical 臂补 mirror:absent / mirror → mirror,WHERE 住客谓词 ∧ 不是 writer。 */
|
|
104
114
|
export declare function markMirrorStatement(dialect: SqlDialect, root: string, occupant: SessionFace): PlacementStatement;
|
|
105
115
|
/** 回填(一次性迁移):无执行格、非委派分区、有 run 行的会话行 ⇒ writer(表唯一项)。幂等(第二次跑零行)。 */
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { isExecutionLane } from "../execution-lane-caps.js";
|
|
2
2
|
import { sessionFaceFromRow } from "../session-incarnation.js";
|
|
3
3
|
import { toIso } from "./sql-row-helpers.js";
|
|
4
|
-
import { WRITABLE, assertPlaceableLane, settledMirrorOutcome, settledPlaceOutcome, } from "../execution-placement.js";
|
|
4
|
+
import { WRITABLE, assertPlaceableLane, boundDeviceOf, settledMirrorOutcome, settledPlaceOutcome, } from "../execution-placement.js";
|
|
5
5
|
export const SESSION_META_PLACEMENT_COLUMNS = [
|
|
6
|
-
{ name: "execution_role",
|
|
7
|
-
{ name: "execution_lane",
|
|
8
|
-
{ name: "execution_device_id",
|
|
9
|
-
{ name: "execution_device_owner_tenant",
|
|
10
|
-
{ name: "execution_device_owner_subject",
|
|
11
|
-
{ name: "execution_placed_at",
|
|
12
|
-
{ name: "execution_rev",
|
|
13
|
-
{ name: "fork_key",
|
|
6
|
+
{ name: "execution_role", mysql: "execution_role VARCHAR(16) NULL", pg: `execution_role VARCHAR(16) COLLATE "C"` },
|
|
7
|
+
{ name: "execution_lane", mysql: "execution_lane VARCHAR(32) NULL", pg: `execution_lane VARCHAR(32) COLLATE "C"` },
|
|
8
|
+
{ name: "execution_device_id", mysql: "execution_device_id VARCHAR(64) NULL", pg: `execution_device_id VARCHAR(64) COLLATE "C"` },
|
|
9
|
+
{ name: "execution_device_owner_tenant", mysql: "execution_device_owner_tenant VARCHAR(190) NULL", pg: `execution_device_owner_tenant VARCHAR(190) COLLATE "C"` },
|
|
10
|
+
{ name: "execution_device_owner_subject", mysql: "execution_device_owner_subject VARCHAR(190) NULL", pg: `execution_device_owner_subject VARCHAR(190) COLLATE "C"` },
|
|
11
|
+
{ name: "execution_placed_at", mysql: "execution_placed_at DATETIME(3) NULL", pg: "execution_placed_at TIMESTAMPTZ(3)" },
|
|
12
|
+
{ name: "execution_rev", mysql: "execution_rev BIGINT NULL", pg: "execution_rev BIGINT" },
|
|
13
|
+
{ name: "fork_key", mysql: "fork_key VARCHAR(255) NULL", pg: `fork_key VARCHAR(255) COLLATE "C"` },
|
|
14
14
|
];
|
|
15
15
|
export function sessionMetaPlacementColumnsDdl(dialect) {
|
|
16
16
|
return SESSION_META_PLACEMENT_COLUMNS.map((c) => c[dialect]).join(",\n ");
|
|
@@ -64,6 +64,17 @@ export function rebindDeviceStatement(dialect, root, occupant, owner, expectedRe
|
|
|
64
64
|
`AND execution_device_owner_tenant = ${b.p(owner.tenant)} AND execution_device_owner_subject = ${b.p(owner.subject)} AND execution_rev = ${b.p(expectedRev)}`;
|
|
65
65
|
return { text: `UPDATE session_meta SET ${set} WHERE ${where}`, values: b.values };
|
|
66
66
|
}
|
|
67
|
+
export function deviceCellRowsStatement() {
|
|
68
|
+
return { text: `SELECT session_id, ${SESSION_META_PLACEMENT_READ_COLUMNS} FROM session_meta WHERE execution_device_id IS NOT NULL AND placement_kind IS NULL`, values: [] };
|
|
69
|
+
}
|
|
70
|
+
export async function countDeviceBindingsOn(conn) {
|
|
71
|
+
const s = deviceCellRowsStatement();
|
|
72
|
+
let bindings = 0;
|
|
73
|
+
for (const row of await conn(s.text, s.values))
|
|
74
|
+
if (boundDeviceOf(placementCellFromRow(text(row.session_id), row)) !== undefined)
|
|
75
|
+
bindings += 1;
|
|
76
|
+
return bindings;
|
|
77
|
+
}
|
|
67
78
|
export function markMirrorStatement(dialect, root, occupant) {
|
|
68
79
|
const b = binder(dialect);
|
|
69
80
|
return { text: `UPDATE session_meta SET execution_role = '${MIRROR}' WHERE ${occupantPredicate(dialect, b.p, root, occupant)} AND ${NOT_WRITER}`, values: b.values };
|
|
@@ -3,7 +3,7 @@ import type { Pool as PgPool } from "pg";
|
|
|
3
3
|
import { type FileHistoryRetentionPolicy, type ExecutionEnv, type FileHistoryStore, type FileHistoryResult, type FileHistoryTrackResult, type FileHistoryRestoreResult, type FileHistoryExport, type FileHistoryExportResult } from "@sema-agent/core";
|
|
4
4
|
import { type BlobBackend } from "./blob-backend.js";
|
|
5
5
|
import type { SyncBlobPutResult } from "./store-backend.js";
|
|
6
|
-
import { type SqlDriver } from "./sql-driver.js";
|
|
6
|
+
import { type SqlDriver, type SqlDialect } from "./sql-driver.js";
|
|
7
7
|
/** The file-history blob domain's SQL table (BlobBackend `table`/MinIO index binding + the A7 assert). */
|
|
8
8
|
export declare const FILE_HISTORY_BLOB_TABLE = "file_history_blob";
|
|
9
9
|
/** MinIO object-key prefix for this domain (snapshot epoch used "blobs/"; a separate prefix keeps the
|
|
@@ -196,5 +196,5 @@ export declare class PgFileHistoryStore extends SqlFileHistoryStore {
|
|
|
196
196
|
*/
|
|
197
197
|
export declare function assertFileHistorySchema(query: (sql: string) => Promise<{
|
|
198
198
|
rows: Record<string, unknown>[];
|
|
199
|
-
}>, dialect:
|
|
199
|
+
}>, dialect: SqlDialect): Promise<void>;
|
|
200
200
|
//# sourceMappingURL=file-history-store-sql.d.ts.map
|
|
@@ -33,13 +33,13 @@ export class SqlFileHistoryStore {
|
|
|
33
33
|
this.db = db;
|
|
34
34
|
this.pool = pool;
|
|
35
35
|
this.blobs = blobBackend ?? new SqlBlobBackend(this.db.dialect, this.pool, undefined, FILE_HISTORY_BLOB_TABLE);
|
|
36
|
-
this.boundaryKeep = resolveFileHistoryRetention(this.db.dialect === "
|
|
36
|
+
this.boundaryKeep = resolveFileHistoryRetention(this.db.dialect === "mysql" ? "TiDBFileHistoryStore" : "PgFileHistoryStore", opts?.retention);
|
|
37
37
|
}
|
|
38
|
-
q(
|
|
39
|
-
return this.db.dialect === "
|
|
38
|
+
q(mysql, pg) {
|
|
39
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
40
40
|
}
|
|
41
41
|
bool(v) {
|
|
42
|
-
return this.db.dialect === "
|
|
42
|
+
return this.db.dialect === "mysql" ? (v ? 1 : 0) : v;
|
|
43
43
|
}
|
|
44
44
|
leaseKey(scope, entryId) {
|
|
45
45
|
return `${scope}\x00${entryId}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type UsageRow } from "../usage-analytics.js";
|
|
2
2
|
import type { TaskStatus } from "@sema-agent/core";
|
|
3
|
-
import { StoreBootRefusalError, type FenceLanded, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
3
|
+
import { StoreBootRefusalError, type FenceLanded, type FencedRun, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
4
4
|
import type { RunStoreCheckpointProbe } from "./memory-run-store.js";
|
|
5
5
|
import type { LedgerEventType } from "../trace/ledger-events.js";
|
|
6
6
|
import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
|
|
@@ -149,7 +149,7 @@ export declare class FileRunStore implements InProcessClaimFence {
|
|
|
149
149
|
markResuming(taskId: string, instanceId: string): Promise<boolean>;
|
|
150
150
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
151
151
|
/** 认领当写栅栏用(契约 = `store-contracts.ts` 的 `InProcessClaimFence`):判、刷新活性(同步落盘)与 `write` 是同一个同步段。 */
|
|
152
|
-
whileHoldingClaim(sessionId: string, taskId: string, write: () => FenceLanded): boolean;
|
|
152
|
+
whileHoldingClaim(sessionId: string, taskId: string, write: (run: FencedRun) => FenceLanded): boolean;
|
|
153
153
|
getRun(taskId: string): Promise<RunRecord | undefined>;
|
|
154
154
|
/** Undo THIS submission's binding (key + body fingerprint → null) — called only where the submit surface refuses the submission
|
|
155
155
|
* before any work and terminalizes the row it just claimed (the sync leg's zero-work refusal, an execution-placement reject):
|
|
@@ -19,12 +19,20 @@
|
|
|
19
19
|
* 绝不打到 durable 店——那是 authorizer 的职权)。
|
|
20
20
|
* - `fork(sourceId)` → 源在哪店在哪店 fork(路由未知时 host 先试,null 再 transient);新 id 记路由。
|
|
21
21
|
* - `list`/`size`/`dispose` = transient 侧(host 店归 main runner 所有;不双列、不双清)。
|
|
22
|
+
* - 带 placement 的建(受信 spawner:后台子代,host 声明了委派分区)→ **host**(分区住 durable 店,名册钉住,见 {@link placed})。
|
|
23
|
+
*
|
|
24
|
+
* 规则一条:**一只后台子代的 durable 行在,它的转录就是 host 店委派分区里的一只 placed 行**(活过重启、随行同亡);transient 店只装
|
|
25
|
+
* 没有任何 durable 记录指着的会话(普通子任务、前台子代)。所以停驻不搬家:声明了分区的部署上,能停驻的后台子代生来就在 host 店
|
|
26
|
+
* (停驻挂点只验它在不在,`plugins/session-store.ts` 的 `attestChildSessionDurable`);host 不声明分区的部署没有停驻挂点(core 如实答 `no_park_lane`)。
|
|
27
|
+
*
|
|
28
|
+
* 声明面两条各读各的(引擎 `SessionStore.durability` / `placements` 两条注的分工,本类就是那条注里「瞬态车道与持久分区不同的路由店」):`placements` 从 host 逐字转发(分区的耐久);
|
|
29
|
+
* 顶层 `durability` **不转发、不声明** —— 它只说**未 placed** 的会话,而本店自己铸的未 placed 会话(无 id 的普通子任务、claim-create)住进程内短 TTL 店,
|
|
30
|
+
* 转发 host 的 `durable` 等于对子 Runner 的接线清单谎报「重启不丢」(引擎对缺席读 fail-closed 的 `process_local`,这里读法就是如实)。
|
|
22
31
|
*
|
|
23
32
|
* 路由表 LRU 上限 {@link ROUTE_MAX}:满额逐最老(refresh-on-use);被逐后下次 `acquire` 按上述规则重derive
|
|
24
33
|
* (requireExisting 的 host-first 重试仍落对店),中途 touch/noteTaskRun 缺路由=落 transient(no-op 级)。
|
|
25
34
|
*/
|
|
26
35
|
import { type SessionStore, type AcquiredSession, type SessionStoreSummary, type SessionPlacement, type PlacedSessionRow } from "@sema-agent/core";
|
|
27
|
-
import { type DelegationTree } from "../delegated-session-owner.js";
|
|
28
36
|
import type { ExecutionPlacementSeat } from "../execution-placement.js";
|
|
29
37
|
import type { ForkToFn } from "./session-fork.js";
|
|
30
38
|
/** acquire 选项形(core 5.48 SessionStore 契约):[ref] placement=受信 spawner 的分区建会话声明。 */
|
|
@@ -38,12 +46,7 @@ export declare class ForkRoutingSessionStore implements SessionStore {
|
|
|
38
46
|
private readonly route;
|
|
39
47
|
/** pin 时的店归属——unpin 恒回同店(LRU 逐出不拆对,见 pin/unpin)。 */
|
|
40
48
|
private readonly pinnedAt;
|
|
41
|
-
/** [ref]
|
|
42
|
-
* 逐出,而私店的 forget 只清 entries 缓存行、底层 repo 行不清且 sweep 扫不到(core session-store.js
|
|
43
|
-
* 亲读),逐出后 transient-first 的 requireExisting 会把陈旧快照端回给 revive。本集不逐出(上界=
|
|
44
|
-
* parked 子代数,天然小);pick/acquire 首查。 */
|
|
45
|
-
private readonly promoted;
|
|
46
|
-
/** [ref] placement 半场:placed id 名册(与 promoted 同姿势——不随路由 LRU 逐出)。placed 会话的
|
|
49
|
+
/** [ref] placement 半场:placed id 名册(不随路由 LRU 逐出)。placed 会话的
|
|
47
50
|
* 真居所恒=host(分区在 durable 店),任何形的 acquire/touch/release 都不得落 transient——
|
|
48
51
|
* 否则 transient 的 claim-create 会铸出同 id 影子会话,requireExisting 的 transient-first 顺序
|
|
49
52
|
* 会让影子遮蔽真转录(F-7 顺序对 placed 反向成害)。 */
|
|
@@ -76,31 +79,6 @@ export declare class ForkRoutingSessionStore implements SessionStore {
|
|
|
76
79
|
unpin(sessionId: string): void | Promise<void>;
|
|
77
80
|
noteTaskRun(sessionId: string, taskId: string, runId?: string): void | Promise<void>;
|
|
78
81
|
list(): Promise<SessionStoreSummary[]>;
|
|
79
|
-
/**
|
|
80
|
-
* [ref] 子代 park 晋升:把住在 transient(TTL)店的子会话**整树拷贝**进 host durable 店,然后
|
|
81
|
-
* 让该 id 从此路由到 host——`ensureChildSessionDurable` 的「主动晋升」半场(1.263 的只查不迁形在
|
|
82
|
-
* 拆店生产形下恒否决 park:子会话从不在 host 店,core 收 veto 即 expire checkpoint + settle failed,
|
|
83
|
-
* cli 真机 14ms~2s expired 即此)。
|
|
84
|
-
*
|
|
85
|
-
* 三步缺一不可:
|
|
86
|
-
* 1. 拷贝:transient 读整树(getEntries)+ 源 leaf → host 店 acquire(id)(durable 店的 acquire
|
|
87
|
-
* 缺行即建行)→ storage.appendEntry 逐条 verbatim(重复 id 容忍=幂等续迁:上次晋升半途崩的
|
|
88
|
-
* 残留行跳过)→ setLeafId(源 leaf)(分支树以源为准,不信 append 推进的 leaf)。
|
|
89
|
-
* 2. transient.forget(id):`requireExisting` 的 acquire 是 **transient-first**(F-7 裁定)——私店
|
|
90
|
-
* 副本不移除,revive 会续写进 1h TTL 副本,durable park 名存实亡。
|
|
91
|
-
* 3. 路由记 host(此后 touch/pin/release 全走 host;pinnedAt 若记着 transient 一并改写,
|
|
92
|
-
* unpin 不落错店)。
|
|
93
|
-
*
|
|
94
|
-
* 已在 host(路由或真行)⇒ 幂等直返。两店都无此会话 ⇒ 抛(调用方=park veto,诚实 fail-closed)。
|
|
95
|
-
*
|
|
96
|
-
* [ref]:宿主行**在建行那一笔里**带属主 `owner` —— 调用方按委派继承律算好(`delegated-session-owner.ts`:委派树根的属主,
|
|
97
|
-
* 推不出 ⇒ 孤行哨兵;`tree` = 判据读到的委派树,判断用:宿主行记着别的树 ⇒ 拒),这里经宿主店的首写登记写下、再按律定夺(core `register` 契约:登记不判授权,判在复读)。
|
|
98
|
-
* 宿主店里同 id 已有一行:记着这一棵委派树且无主 ⇒ 按同一条律认领(只有记录委派树的店);别的树的 / 属主不是它(别人先认领的空壳,或 local 店的无主空壳)⇒ 抛(停驻否决),
|
|
99
|
-
* 转录不拷进别人的行;宿主店记不了 / 读不回属主 ⇒ 同样抛 —— 晋升出一只无主的转录行就是把它交给任何拿到 id 的人。
|
|
100
|
-
*/
|
|
101
|
-
promoteToHost(sessionId: string, owner: string | null, tree: DelegationTree): Promise<void>;
|
|
102
|
-
/** 晋升的建行那一笔([ref],规则见 {@link promoteToHost} 头注):宿主店首写登记 `owner`,然后按律定下宿主行的属主(与停驻快路同一只 `settleDelegatedOwner`)。 */
|
|
103
|
-
private registerPromotedOwner;
|
|
104
82
|
fork(sourceId: string, owner?: string | null): Promise<string | null>;
|
|
105
83
|
get size(): number;
|
|
106
84
|
dispose(): void | Promise<void>;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { SessionError } from "@sema-agent/core";
|
|
2
2
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
3
|
-
import { delegatedOwnerHostOf, settleDelegatedOwner } from "../delegated-session-owner.js";
|
|
4
3
|
const ROUTE_MAX = 8192;
|
|
5
4
|
export class ForkRoutingSessionStore {
|
|
6
5
|
host;
|
|
7
6
|
transient;
|
|
8
7
|
route = new Map();
|
|
9
8
|
pinnedAt = new Map();
|
|
10
|
-
promoted = new Set();
|
|
11
9
|
placed = new Set();
|
|
12
10
|
placements;
|
|
13
11
|
listPlaced;
|
|
@@ -50,7 +48,7 @@ export class ForkRoutingSessionStore {
|
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
pick(id) {
|
|
53
|
-
if (this.
|
|
51
|
+
if (this.placed.has(id))
|
|
54
52
|
return this.host;
|
|
55
53
|
const r = this.route.get(id);
|
|
56
54
|
if (r !== undefined)
|
|
@@ -94,7 +92,7 @@ export class ForkRoutingSessionStore {
|
|
|
94
92
|
this.remember(sessionId, "host");
|
|
95
93
|
return a;
|
|
96
94
|
}
|
|
97
|
-
if (this.
|
|
95
|
+
if (this.placed.has(sessionId)) {
|
|
98
96
|
const a = await this.host.acquire(sessionId, opts);
|
|
99
97
|
this.remember(sessionId, "host");
|
|
100
98
|
return a;
|
|
@@ -187,63 +185,6 @@ export class ForkRoutingSessionStore {
|
|
|
187
185
|
list() {
|
|
188
186
|
return this.transient.list?.() ?? Promise.resolve([]);
|
|
189
187
|
}
|
|
190
|
-
async promoteToHost(sessionId, owner, tree) {
|
|
191
|
-
if (this.promoted.has(sessionId))
|
|
192
|
-
return;
|
|
193
|
-
if (this.route.get(sessionId) === "host") {
|
|
194
|
-
this.promoted.add(sessionId);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
let src;
|
|
198
|
-
try {
|
|
199
|
-
src = await this.transient.acquire(sessionId, { requireExisting: true });
|
|
200
|
-
}
|
|
201
|
-
catch {
|
|
202
|
-
const probe = await this.host.acquire(sessionId, { requireExisting: true });
|
|
203
|
-
await this.host.forget?.(probe.sessionId);
|
|
204
|
-
this.promoted.add(sessionId);
|
|
205
|
-
this.remember(sessionId, "host");
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const entries = await src.session.getEntries();
|
|
209
|
-
const leaf = await src.session.getLeafId();
|
|
210
|
-
await this.registerPromotedOwner(sessionId, owner, tree);
|
|
211
|
-
const dst = await this.host.acquire(sessionId);
|
|
212
|
-
try {
|
|
213
|
-
const storage = dst.session.getStorage();
|
|
214
|
-
const existing = new Set((await dst.session.getEntries()).map((e) => e.id));
|
|
215
|
-
for (const entry of entries) {
|
|
216
|
-
if (existing.has(entry.id))
|
|
217
|
-
continue;
|
|
218
|
-
await storage.appendEntry(entry);
|
|
219
|
-
}
|
|
220
|
-
await storage.setLeafId(leaf);
|
|
221
|
-
const verifyLeaf = await dst.session.getLeafId();
|
|
222
|
-
if (verifyLeaf !== leaf)
|
|
223
|
-
throw new Error(`session "${sessionId}" promotion verification failed (leaf mismatch after import)`);
|
|
224
|
-
}
|
|
225
|
-
finally {
|
|
226
|
-
await this.host.forget?.(sessionId);
|
|
227
|
-
}
|
|
228
|
-
try {
|
|
229
|
-
await this.transient.forget?.(sessionId);
|
|
230
|
-
}
|
|
231
|
-
catch {
|
|
232
|
-
}
|
|
233
|
-
if (this.pinnedAt.get(sessionId) === "transient")
|
|
234
|
-
this.pinnedAt.set(sessionId, "host");
|
|
235
|
-
this.promoted.add(sessionId);
|
|
236
|
-
this.remember(sessionId, "host");
|
|
237
|
-
}
|
|
238
|
-
async registerPromotedOwner(sessionId, owner, tree) {
|
|
239
|
-
const register = this.host.register;
|
|
240
|
-
const host = delegatedOwnerHostOf(this.host);
|
|
241
|
-
if (register === undefined || host === undefined) {
|
|
242
|
-
throw new Error(`session "${sessionId}" cannot be promoted: the host session store cannot record or read back a session owner (register / headOf; placementOf and claimOwnerless together or neither), so the promoted transcript would land ownerless`);
|
|
243
|
-
}
|
|
244
|
-
await register.call(this.host, sessionId, owner);
|
|
245
|
-
await settleDelegatedOwner(host, sessionId, owner, tree);
|
|
246
|
-
}
|
|
247
188
|
async fork(sourceId, owner) {
|
|
248
189
|
const routed = this.route.get(sourceId);
|
|
249
190
|
const tryFork = async (store, where) => {
|
|
@@ -145,7 +145,7 @@ export async function ensurePgImageBakeSchema(pool, poolName = "standard") {
|
|
|
145
145
|
}
|
|
146
146
|
const isDupKey = isDupKeyError;
|
|
147
147
|
function dupKeyName(dialect, err) {
|
|
148
|
-
if (dialect === "
|
|
148
|
+
if (dialect === "mysql") {
|
|
149
149
|
const msg = String(err?.sqlMessage ?? err?.message ?? "");
|
|
150
150
|
if (/uq_image_bake_event_line/i.test(msg))
|
|
151
151
|
return "uq_line";
|
|
@@ -169,8 +169,8 @@ export class SqlImageBake {
|
|
|
169
169
|
this.db = db;
|
|
170
170
|
this.poolName = poolName;
|
|
171
171
|
}
|
|
172
|
-
q(
|
|
173
|
-
return this.db.dialect === "
|
|
172
|
+
q(mysql, pg) {
|
|
173
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
174
174
|
}
|
|
175
175
|
insertParams(bakeId, input, now) {
|
|
176
176
|
return [
|
|
@@ -214,7 +214,7 @@ export class SqlImageBake {
|
|
|
214
214
|
const conn = await this.db.connect();
|
|
215
215
|
let inserted = false;
|
|
216
216
|
try {
|
|
217
|
-
if (this.db.dialect === "
|
|
217
|
+
if (this.db.dialect === "mysql") {
|
|
218
218
|
await conn.begin();
|
|
219
219
|
await conn.query("INSERT INTO image_bake_admit (pool) VALUES (?) ON DUPLICATE KEY UPDATE pool = pool", [this.poolName]);
|
|
220
220
|
await conn.query("SELECT pool FROM image_bake_admit WHERE pool = ? FOR UPDATE", [this.poolName]);
|
|
@@ -255,15 +255,15 @@ export class SqlImageBake {
|
|
|
255
255
|
return { created: true, bake };
|
|
256
256
|
}
|
|
257
257
|
async getBake(bakeId) {
|
|
258
|
-
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("
|
|
258
|
+
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("mysql")} FROM image_bake WHERE bake_id = ? LIMIT 1`, `SELECT ${bakeSelectCols("pg")} FROM image_bake WHERE bake_id = $1 LIMIT 1`), [bakeId]);
|
|
259
259
|
return rows[0] ? refusingBakeRow(() => mapRow(rows[0])) : null;
|
|
260
260
|
}
|
|
261
261
|
async getBakeByIdem(idemKey) {
|
|
262
|
-
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("
|
|
262
|
+
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("mysql")} FROM image_bake WHERE idem_key = ? LIMIT 1`, `SELECT ${bakeSelectCols("pg")} FROM image_bake WHERE idem_key = $1 LIMIT 1`), [idemKey]);
|
|
263
263
|
return rows[0] ? refusingBakeRow(() => mapRow(rows[0])) : null;
|
|
264
264
|
}
|
|
265
265
|
async findActiveByArgv(argv) {
|
|
266
|
-
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("
|
|
266
|
+
const { rows } = await this.db.query(this.q(`SELECT ${bakeSelectCols("mysql")} FROM image_bake WHERE status IN ('queued','running') AND argv = CAST(? AS JSON) ` +
|
|
267
267
|
"ORDER BY created_at DESC LIMIT 1", `SELECT ${bakeSelectCols("pg")} FROM image_bake WHERE status IN ('queued','running') AND argv = $1::jsonb ` +
|
|
268
268
|
"ORDER BY created_at DESC LIMIT 1"), [JSON.stringify(argv)]);
|
|
269
269
|
return rows[0] ? refusingBakeRow(() => mapRow(rows[0])) : null;
|
|
@@ -380,7 +380,7 @@ export class SqlImageBake {
|
|
|
380
380
|
return m == null ? 0 : Number(m);
|
|
381
381
|
}
|
|
382
382
|
async getEvents(bakeId, afterSeq) {
|
|
383
|
-
const { rows } = await this.db.query(this.q(`SELECT seq, line_ord, kind, level, ${jsonColumnText("
|
|
383
|
+
const { rows } = await this.db.query(this.q(`SELECT seq, line_ord, kind, level, ${jsonColumnText("mysql", "data")}, ts FROM image_bake_event WHERE bake_id = ? AND seq > ? ORDER BY seq ASC`, `SELECT seq, line_ord, kind, level, ${jsonColumnText("pg", "data")}, ts FROM image_bake_event WHERE bake_id = $1 AND seq > $2 ORDER BY seq ASC`), [bakeId, afterSeq]);
|
|
384
384
|
return rows.map((r) => ({
|
|
385
385
|
seq: Number(r.seq),
|
|
386
386
|
lineOrd: r.line_ord === null ? null : Number(r.line_ord),
|
|
@@ -401,7 +401,7 @@ export class SqlImageBake {
|
|
|
401
401
|
await this.tx(async (conn) => {
|
|
402
402
|
const res = await conn.query(this.q("UPDATE image_bake SET status=?, state=?, digest=?, repo=?, ref=?, index_id=?, exit_code=?, error=?, " +
|
|
403
403
|
"error_code=?, manifest_sha=?, tag=?, ingest_secret=NULL, updated_at=? WHERE bake_id=? AND status IN ('queued','running')", "UPDATE image_bake SET status=$1, state=$2, digest=$3, repo=$4, ref=$5, index_id=$6, exit_code=$7, error=$8, " +
|
|
404
|
-
"error_code=$9, manifest_sha=$10, tag=$11, ingest_secret=NULL, updated_at=$12 WHERE bake_id=$13 AND status IN ('queued','running')"), this.db.dialect === "
|
|
404
|
+
"error_code=$9, manifest_sha=$10, tag=$11, ingest_secret=NULL, updated_at=$12 WHERE bake_id=$13 AND status IN ('queued','running')"), this.db.dialect === "mysql" ? this.terminalParamsTidb(bakeId, t) : this.terminalParamsPg(bakeId, t));
|
|
405
405
|
affectedRows = res.affected;
|
|
406
406
|
await conn.query(this.q("DELETE FROM image_bake_lease WHERE pool = ? AND bake_id = ?", "DELETE FROM image_bake_lease WHERE pool = $1 AND bake_id = $2"), [this.poolName, bakeId]);
|
|
407
407
|
});
|
|
@@ -181,8 +181,8 @@ export class SqlImageIndex {
|
|
|
181
181
|
constructor(db) {
|
|
182
182
|
this.db = db;
|
|
183
183
|
}
|
|
184
|
-
q(
|
|
185
|
-
return this.db.dialect === "
|
|
184
|
+
q(mysql, pg) {
|
|
185
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
186
186
|
}
|
|
187
187
|
static idFor(repo, digest) {
|
|
188
188
|
return createHash("sha256").update(`${repo}@${digest}`).digest("hex").slice(0, 64);
|
|
@@ -216,7 +216,7 @@ export class SqlImageIndex {
|
|
|
216
216
|
status = EXCLUDED.status, visibility = EXCLUDED.visibility, tenant_id = EXCLUDED.tenant_id,
|
|
217
217
|
manifest_sha = EXCLUDED.manifest_sha, recipe_git_sha = EXCLUDED.recipe_git_sha,
|
|
218
218
|
generator_version = EXCLUDED.generator_version, build_date = EXCLUDED.build_date,
|
|
219
|
-
supersedes = EXCLUDED.supersedes, signed = EXCLUDED.signed, updated_at = EXCLUDED.updated_at`), this.db.dialect === "
|
|
219
|
+
supersedes = EXCLUDED.supersedes, signed = EXCLUDED.signed, updated_at = EXCLUDED.updated_at`), this.db.dialect === "mysql" ? tidbUpsertParams(e, id, now) : pgUpsertParams(e, id, now));
|
|
220
220
|
return id;
|
|
221
221
|
}
|
|
222
222
|
async registerBuilding(e) {
|
|
@@ -258,21 +258,21 @@ export class SqlImageIndex {
|
|
|
258
258
|
supersedes = EXCLUDED.supersedes,
|
|
259
259
|
signed = CASE WHEN sandbox_image_index.status = 'published'
|
|
260
260
|
THEN sandbox_image_index.signed ELSE EXCLUDED.signed END,
|
|
261
|
-
updated_at = EXCLUDED.updated_at`), this.db.dialect === "
|
|
261
|
+
updated_at = EXCLUDED.updated_at`), this.db.dialect === "mysql" ? tidbUpsertParams(e, id, now) : pgUpsertParams(e, id, now));
|
|
262
262
|
return id;
|
|
263
263
|
}
|
|
264
264
|
async getById(id) {
|
|
265
|
-
const { rows } = await this.db.query(this.q(`SELECT ${imageSelectCols("
|
|
265
|
+
const { rows } = await this.db.query(this.q(`SELECT ${imageSelectCols("mysql")} FROM sandbox_image_index WHERE id=? LIMIT 1`, `SELECT ${imageSelectCols("pg")} FROM sandbox_image_index WHERE id = $1 LIMIT 1`), [id]);
|
|
266
266
|
return rows[0] ? refusingImageRow(() => mapRow(rows[0])) : null;
|
|
267
267
|
}
|
|
268
268
|
async getByDigest(digest) {
|
|
269
|
-
const { rows } = await this.db.query(this.q(`SELECT ${imageSelectCols("
|
|
269
|
+
const { rows } = await this.db.query(this.q(`SELECT ${imageSelectCols("mysql")} FROM sandbox_image_index WHERE digest=? ORDER BY updated_at DESC LIMIT 1`, `SELECT ${imageSelectCols("pg")} FROM sandbox_image_index WHERE digest = $1 ORDER BY updated_at DESC LIMIT 1`), [digest]);
|
|
270
270
|
return rows[0] ? refusingImageRow(() => mapRow(rows[0])) : null;
|
|
271
271
|
}
|
|
272
272
|
async latestPublished(profile, viewer) {
|
|
273
|
-
if (this.db.dialect === "
|
|
273
|
+
if (this.db.dialect === "mysql") {
|
|
274
274
|
const vis = visibilityClauseTidb(viewer);
|
|
275
|
-
const { rows } = await this.db.query(`SELECT ${imageSelectCols("
|
|
275
|
+
const { rows } = await this.db.query(`SELECT ${imageSelectCols("mysql")} FROM sandbox_image_index
|
|
276
276
|
WHERE profile=? AND status='published' AND ${vis.sql}
|
|
277
277
|
ORDER BY (build_date IS NULL), build_date DESC, created_at DESC LIMIT 1`, [profile, ...vis.params]);
|
|
278
278
|
return rows[0] ? refusingImageRow(() => mapRow(rows[0])) : null;
|
|
@@ -286,7 +286,7 @@ export class SqlImageIndex {
|
|
|
286
286
|
async list(filter) {
|
|
287
287
|
const limit = Math.min(Math.max(1, filter.limit ?? DEFAULT_LIMIT), MAX_LIMIT);
|
|
288
288
|
let rawRows;
|
|
289
|
-
if (this.db.dialect === "
|
|
289
|
+
if (this.db.dialect === "mysql") {
|
|
290
290
|
const vis = visibilityClauseTidb(filter);
|
|
291
291
|
const where = [vis.sql];
|
|
292
292
|
const params = [...vis.params];
|
|
@@ -309,7 +309,7 @@ export class SqlImageIndex {
|
|
|
309
309
|
params.push(new Date(c.createdAt), new Date(c.createdAt), c.id);
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
|
-
const sql = `SELECT ${imageSelectCols("
|
|
312
|
+
const sql = `SELECT ${imageSelectCols("mysql")} FROM sandbox_image_index WHERE ${where.join(" AND ")} ` +
|
|
313
313
|
`ORDER BY created_at DESC, id DESC LIMIT ?`;
|
|
314
314
|
const { rows } = await this.db.query(sql, [...params, limit + 1]);
|
|
315
315
|
rawRows = rows;
|
|
@@ -359,7 +359,7 @@ export class SqlImageIndex {
|
|
|
359
359
|
return { entries, nextCursor };
|
|
360
360
|
}
|
|
361
361
|
async setStatus(id, status, opts) {
|
|
362
|
-
if (this.db.dialect === "
|
|
362
|
+
if (this.db.dialect === "mysql") {
|
|
363
363
|
const sets = ["status=?", "updated_at=?"];
|
|
364
364
|
const params = [status, new Date()];
|
|
365
365
|
if (opts && "supersedes" in opts) {
|
|
@@ -40,11 +40,14 @@ export declare function isLabelValue(v: string): boolean;
|
|
|
40
40
|
/**
|
|
41
41
|
* The volume names the adapter itself mints on a sandbox pod — the ONE table (a patch volume / volumeMount must not reuse one: it would collide
|
|
42
42
|
* with, or mount, the adapter's own volume). Today: the space's build-cache claim and the member-credential broker's lease volume. A volume the
|
|
43
|
-
* adapter adds later is added HERE, and the patch judge below refuses it with no second guard.
|
|
43
|
+
* adapter adds later is added HERE, and the patch judge below refuses it with no second guard. The two read-floor volumes carry the
|
|
44
|
+
* supervisor binary per architecture (read-only ConfigMap volumes; `sandbox-read-floor.ts`).
|
|
44
45
|
*/
|
|
45
46
|
export declare const ADAPTER_VOLUME_NAMES: {
|
|
46
47
|
readonly cache: "ws-cache";
|
|
47
48
|
readonly brokerLease: "sema-broker-lease";
|
|
49
|
+
readonly floorX86_64: "sema-floor-x86-64";
|
|
50
|
+
readonly floorAarch64: "sema-floor-aarch64";
|
|
48
51
|
};
|
|
49
52
|
/**
|
|
50
53
|
* The confined, ADDITIVE pod-spec patch. Every field is purely additive —
|
|
@@ -8,7 +8,12 @@ const LABEL_VALUE = /^(?:[A-Za-z0-9](?:[-A-Za-z0-9_.]{0,61}[A-Za-z0-9])?)?$/;
|
|
|
8
8
|
export function isLabelValue(v) {
|
|
9
9
|
return LABEL_VALUE.test(v);
|
|
10
10
|
}
|
|
11
|
-
export const ADAPTER_VOLUME_NAMES = {
|
|
11
|
+
export const ADAPTER_VOLUME_NAMES = {
|
|
12
|
+
cache: "ws-cache",
|
|
13
|
+
brokerLease: BROKER_VOLUME_NAME,
|
|
14
|
+
floorX86_64: "sema-floor-x86-64",
|
|
15
|
+
floorAarch64: "sema-floor-aarch64",
|
|
16
|
+
};
|
|
12
17
|
const RESERVED_VOLUME_NAMES = new Set(Object.values(ADAPTER_VOLUME_NAMES));
|
|
13
18
|
const agentContainerOf = (pod) => pod.spec.containers?.[0];
|
|
14
19
|
const POD_SPEC_PATCH_FIELDS = {
|
|
@@ -95,8 +95,8 @@ export class SqlLeaderRunStore {
|
|
|
95
95
|
constructor(db) {
|
|
96
96
|
this.db = db;
|
|
97
97
|
}
|
|
98
|
-
q(
|
|
99
|
-
return this.db.dialect === "
|
|
98
|
+
q(mysql, pg) {
|
|
99
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
100
100
|
}
|
|
101
101
|
async createRun(input) {
|
|
102
102
|
const id = uuidv7();
|
|
@@ -120,12 +120,12 @@ export class SqlLeaderRunStore {
|
|
|
120
120
|
return { created: true, run };
|
|
121
121
|
}
|
|
122
122
|
async getRun(id) {
|
|
123
|
-
const res = await this.db.query(this.q(`SELECT ${selectCols("
|
|
123
|
+
const res = await this.db.query(this.q(`SELECT ${selectCols("mysql")} FROM ${LEADER_RUN_TABLE} WHERE leader_run_id = ?`, `SELECT ${selectCols("pg")} FROM ${LEADER_RUN_TABLE} WHERE leader_run_id = $1`), [id]);
|
|
124
124
|
const row = res.rows[0];
|
|
125
125
|
return row ? mapRow(row) : undefined;
|
|
126
126
|
}
|
|
127
127
|
async getByIdem(idemKey) {
|
|
128
|
-
const res = await this.db.query(this.q(`SELECT ${selectCols("
|
|
128
|
+
const res = await this.db.query(this.q(`SELECT ${selectCols("mysql")} FROM ${LEADER_RUN_TABLE} WHERE idem_key = ?`, `SELECT ${selectCols("pg")} FROM ${LEADER_RUN_TABLE} WHERE idem_key = $1`), [idemKey]);
|
|
129
129
|
const row = res.rows[0];
|
|
130
130
|
return row ? mapRow(row) : undefined;
|
|
131
131
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Checkpoint, type CheckpointSummary, type CheckpointToken, type PendingSteerInput, type ReopenReason, type ResolveExpectation, type ExecutionOutcomeRecordWord, type GateOutcome, type ResumeOutcome, type StoreDurability, type StoreFidelity } from "@sema-agent/core";
|
|
2
|
-
import { type CheckpointAskCandidate, type CtxRowRewrite, type CtxRowsRewrite, type DecidedApprovalRecord, type PendingCheckpoint, type PendingRowBinding } from "./checkpoint-store-sql.js";
|
|
2
|
+
import { type CheckpointAskCandidate, type CtxClaimRewrite, type CtxRowRewrite, type CtxRowsRewrite, type DecidedApprovalRecord, type PendingCheckpoint, type PendingRowBinding } from "./checkpoint-store-sql.js";
|
|
3
|
+
import { type FencedRun, type InProcessClaimFence } from "./store-contracts.js";
|
|
3
4
|
import type { SealedCheckpointCtx } from "../http/checkpoint-ctx.js";
|
|
4
5
|
export interface LocalCheckpointStoreOptions {
|
|
5
6
|
/** taskId join for the pending card (the local FileRunStore's `getActiveTaskId`). Absent ⇒ `taskId: null`. */
|
|
@@ -7,6 +8,8 @@ export interface LocalCheckpointStoreOptions {
|
|
|
7
8
|
/** E21 owner guard (the LocalSessionStore's owner read, `headOf(id)?.owner`: `undefined` = no session row). Absent ⇒ owner guard degrades
|
|
8
9
|
* to null-owner-only (a non-null owner with no owner source purges NOTHING — fail-closed, mirrors the SQL EXISTS guard). */
|
|
9
10
|
readSessionOwner?: (sessionId: string) => Promise<string | null | undefined>;
|
|
11
|
+
/** ctx 改写的认领栅栏({@link LocalCheckpointStore.rewriteCtxWhileClaimed}):同一数据根上的文件 run 店(进程内栅栏形)。缺席 ⇒ 那一口响亮抛(装配缺陷)。 */
|
|
12
|
+
claims?: InProcessClaimFence;
|
|
10
13
|
}
|
|
11
14
|
export declare class LocalCheckpointStore {
|
|
12
15
|
/** [ref] 车1:托管留存声明 —— **诚实的 none**(与 local session 店同一条判据:本店的行没有按期删除的腿;
|
|
@@ -202,6 +205,12 @@ export declare class LocalCheckpointStore {
|
|
|
202
205
|
* 只收对象,读腿只认对象,两条腿一个类型。
|
|
203
206
|
*/
|
|
204
207
|
getCtx<T extends object = object>(sessionId: string): Promise<T | null>;
|
|
208
|
+
/**
|
|
209
|
+
* **认领栅栏下改写既有 ctx 行** —— 规则、结局闭集与 SQL 孪生 `SqlCheckpointStore.rewriteCtxWhileClaimed` 逐条同(那里是全文)。
|
|
210
|
+
* 本孪生的栅栏是进程内形(`store-contracts.ts` `InProcessClaimFence`):判认领、刷新活性、问腿判据与本口的落盘是**同一个同步段**(原子写本就同步),
|
|
211
|
+
* 中间没有让出,所以认领在写落定之前挪不动。只改既有档(档不在 ⇒ `context_absent`,不建档);形闸同 {@link LocalCheckpointStore.putCtx},在栅栏之前判。
|
|
212
|
+
*/
|
|
213
|
+
rewriteCtxWhileClaimed(sessionId: string, taskId: string, ctx: SealedCheckpointCtx, legHolds: (run: FencedRun) => boolean): Promise<CtxClaimRewrite>;
|
|
205
214
|
/**
|
|
206
215
|
* 🔴 **一次性迁移的 ctx 行改写店腿**(local 孪生;`checkpoint-store-sql.ts` `CheckpointCtxRowsRewriter`,判词与 SQL 孪生 `rewriteCtxRows` 逐条同):
|
|
207
216
|
* 逐档读(信封经读腿**同一只**判形 —— 读不出 ⇒ 计数、跳过、**不删**),`rewrite` 交回新体 ⇒ 信封原样(`sessionId` / `updatedAt` 不动:收割按 `updatedAt` 判)
|
|
@@ -11,6 +11,7 @@ import { quarantineUnreadableSidecar } from "./local-sidecar-quarantine.js";
|
|
|
11
11
|
import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, readStringArrayColumn } from "./sql-json-column.js";
|
|
12
12
|
import { UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
13
13
|
import { assertJsonColumnWritable, createObjectColumnReader } from "./sql-json-column.js";
|
|
14
|
+
import { FENCE_LANDED } from "./store-contracts.js";
|
|
14
15
|
function terminalAtOf(cp) {
|
|
15
16
|
return Math.max(cp.createdAt + TERMINAL_BACKSTOP_MS, (cp.deadline ?? 0) + TERMINAL_GRACE_MS);
|
|
16
17
|
}
|
|
@@ -326,6 +327,27 @@ export class LocalCheckpointStore {
|
|
|
326
327
|
const rec = refusingCtx(sessionId, () => decodeJsonColumn(readFileSync(p, "utf8"), createCtxRecordReader(), `checkpoint-ctx ${ctxFileOf(sessionId)} for session ${JSON.stringify(sessionId)}`));
|
|
327
328
|
return rec.sessionId === sessionId ? rec.ctx : null;
|
|
328
329
|
}
|
|
330
|
+
async rewriteCtxWhileClaimed(sessionId, taskId, ctx, legHolds) {
|
|
331
|
+
const claims = this.opts.claims;
|
|
332
|
+
if (claims === undefined)
|
|
333
|
+
throw new Error("LocalCheckpointStore.rewriteCtxWhileClaimed: no claim fence is bound to this store (wiring defect: the local backend binds its own run store)");
|
|
334
|
+
const rec = { sessionId, updatedAt: Date.now(), ctx };
|
|
335
|
+
const text = JSON.stringify(rec);
|
|
336
|
+
assertJsonColumnWritable(text, createCtxRecordReader(), `checkpoint ctx for session ${JSON.stringify(sessionId)} (local claim-fenced rewrite)`);
|
|
337
|
+
const path = join(this.ctxDir, ctxFileOf(sessionId));
|
|
338
|
+
let outcome = "context_absent";
|
|
339
|
+
const held = claims.whileHoldingClaim(sessionId, taskId, (run) => {
|
|
340
|
+
if (!legHolds(run)) {
|
|
341
|
+
outcome = "claim_released";
|
|
342
|
+
}
|
|
343
|
+
else if (existsSync(path)) {
|
|
344
|
+
atomicWriteFile(this.tmpDir, path, text);
|
|
345
|
+
outcome = "written";
|
|
346
|
+
}
|
|
347
|
+
return FENCE_LANDED;
|
|
348
|
+
});
|
|
349
|
+
return held ? outcome : "claim_released";
|
|
350
|
+
}
|
|
329
351
|
async rewriteCtxRows(rewrite) {
|
|
330
352
|
const out = { scanned: 0, rewritten: 0, valuesRewritten: 0, unreadable: 0, tooLarge: 0 };
|
|
331
353
|
for (const f of readdirSync(this.ctxDir)) {
|