@sema-agent/server 7.137.0 → 7.139.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 +600 -142
- package/README.md +7 -3
- package/README.zh-CN.md +6 -3
- package/USAGE.md +132 -41
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +23 -16
- package/dist/approval-card.js +1 -0
- package/dist/audit.js +1 -0
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- package/dist/bench/s1/run-firm.js +2 -2
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- 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 +16 -24
- package/dist/boot/execution-lane.d.ts +1 -1
- package/dist/boot/governance-seams.d.ts +12 -18
- package/dist/boot/governance-seams.js +10 -24
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/memory-consolidation.js +2 -2
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/resolve-spec.d.ts +4 -1
- package/dist/boot/resolve-spec.js +29 -19
- package/dist/boot/retention-lane.d.ts +14 -8
- package/dist/boot/retention-lane.js +2 -8
- package/dist/boot/runner-deps.d.ts +10 -4
- package/dist/boot/runner-deps.js +2 -0
- 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-04-stores.d.ts +1 -12
- package/dist/boot/stage-05-execution-env.d.ts +3 -12
- package/dist/boot/stage-05-execution-env.js +8 -5
- package/dist/boot/stage-06-runners.d.ts +3 -12
- package/dist/boot/stage-06-runners.js +5 -3
- package/dist/boot/stage-07-capability-layer.d.ts +3 -12
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -12
- package/dist/boot/stage-09-leader.d.ts +3 -12
- package/dist/boot/stage-09-leader.js +2 -3
- package/dist/boot/stage-10-http-server.d.ts +3 -12
- package/dist/boot/stage-10-http-server.js +5 -3
- package/dist/boot/stores.js +4 -4
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +5 -5
- package/dist/brain.js +5 -5
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +21 -7
- package/dist/capability-facts.js +13 -3
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +14 -8
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +19 -24
- package/dist/config-provider.js +27 -12
- package/dist/config-types.d.ts +25 -12
- package/dist/config.d.ts +33 -0
- package/dist/config.js +52 -20
- package/dist/delegated-session-owner.d.ts +2 -2
- package/dist/deployment-shape.d.ts +7 -7
- 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 +19 -0
- package/dist/execution-lane-caps.js +10 -0
- 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/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +1 -0
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +10 -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/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +3 -0
- package/dist/http/durable-run-leg.js +12 -6
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -0
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/resume-legs.d.ts +5 -11
- package/dist/http/resume-legs.js +179 -104
- package/dist/http/route-ctx.d.ts +44 -59
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +6 -6
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/capabilities.js +12 -10
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -5
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +11 -7
- package/dist/http/routes/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +119 -13
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +6 -8
- package/dist/http/routes/tasks.js +800 -782
- package/dist/http/server.d.ts +61 -39
- package/dist/http/server.js +11 -0
- 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 +22 -18
- package/dist/identity-source.d.ts +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-sync-client.d.ts +53 -14
- package/dist/memory-sync-client.js +187 -92
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/run-terminal.js +0 -1
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -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 +49 -11
- package/dist/parked-decide.js +25 -26
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +156 -0
- package/dist/peer-seat.js +273 -0
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- 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 +30 -12
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +11 -2
- package/dist/plugins/caching-session-store.js +15 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +21 -25
- package/dist/plugins/checkpoint-store-sql.js +13 -15
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +49 -103
- 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 +7 -6
- package/dist/plugins/file-history-store-sql.js +8 -7
- 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/k8s-pod-reaper.d.ts +2 -8
- package/dist/plugins/k8s-pod-reaper.js +3 -3
- package/dist/plugins/local-checkpoint-store.d.ts +1 -11
- package/dist/plugins/local-checkpoint-store.js +0 -1
- package/dist/plugins/local-session-store.d.ts +183 -45
- package/dist/plugins/local-session-store.js +412 -105
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +117 -6
- package/dist/plugins/one-time-migrations.js +383 -14
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
- package/dist/plugins/permission-rule-store-sql.js +34 -29
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +41 -22
- package/dist/plugins/pg-session-storage.js +136 -55
- package/dist/plugins/remote-env-adb.d.ts +22 -4
- package/dist/plugins/remote-env-adb.js +70 -62
- package/dist/plugins/remote-env-device.d.ts +32 -12
- package/dist/plugins/remote-env-device.js +18 -17
- package/dist/plugins/remote-env-e2b.d.ts +19 -3
- package/dist/plugins/remote-env-e2b.js +41 -42
- package/dist/plugins/remote-env-file-error.d.ts +2 -0
- package/dist/plugins/remote-env-file-error.js +1 -1
- package/dist/plugins/remote-env-host.d.ts +23 -8
- package/dist/plugins/remote-env-host.js +66 -70
- package/dist/plugins/remote-env-k8s.d.ts +13 -16
- package/dist/plugins/remote-env-k8s.js +61 -54
- package/dist/plugins/remote-env-local-docker.d.ts +30 -5
- package/dist/plugins/remote-env-local-docker.js +46 -59
- package/dist/plugins/remote-env-ssh.d.ts +18 -4
- package/dist/plugins/remote-env-ssh.js +72 -56
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- package/dist/plugins/retention-store-sql.d.ts +23 -8
- package/dist/plugins/retention-store-sql.js +13 -1
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +5 -0
- package/dist/plugins/schema-consistency.d.ts +15 -5
- package/dist/plugins/schema-consistency.js +14 -8
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- package/dist/plugins/session-fork.d.ts +63 -12
- package/dist/plugins/session-fork.js +38 -21
- package/dist/plugins/session-ownership.d.ts +7 -0
- package/dist/plugins/session-ownership.js +5 -0
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/store-backend.d.ts +1 -1
- package/dist/plugins/store-backend.js +26 -14
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +15 -3
- package/dist/plugins/tidb-session-store.d.ts +74 -28
- package/dist/plugins/tidb-session-store.js +132 -53
- package/dist/plugins/tool-result-store-sql.d.ts +16 -8
- package/dist/plugins/tool-result-store-sql.js +26 -17
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- 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/rules-consent.js +6 -4
- package/dist/run-local.d.ts +6 -0
- package/dist/run-local.js +36 -26
- package/dist/runs.d.ts +9 -2
- package/dist/runs.js +9 -2
- package/dist/sandbox-git-plane.d.ts +2 -2
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +15 -8
- package/dist/server-secret-env.js +4 -2
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +19 -10
- package/dist/session-incarnation.js +5 -3
- 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/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +1 -1
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +33 -20
- package/dist/task-mcp.js +46 -22
- package/dist/tool-approval.d.ts +38 -8
- package/dist/tool-approval.js +57 -13
- package/dist/trace/core-keyset-guard.d.ts +33 -18
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/project.d.ts +26 -7
- package/dist/trace/project.js +30 -3
- package/dist/trace/redact.js +42 -13
- package/dist/trace/self-minted-wire.d.ts +240 -12
- package/dist/trace/self-minted-wire.js +100 -4
- package/dist/trace/wire-projection-faces.d.ts +6 -6
- package/dist/trace/wire-projection-faces.js +6 -5
- package/dist/url-refusal.d.ts +1 -1
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -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/center-request.d.ts +3 -2
- package/dist/web-admin-client/center-request.js +2 -3
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +32 -18
- package/dist/web-admin-client/types.d.ts +11 -0
- package/package.json +3 -3
- package/wire-changes/server@7.138.0.json +446 -0
- package/wire-changes/server@7.139.0.json +348 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
- package/dist/http/mcp-remote-text.d.ts +0 -5
- package/dist/http/mcp-remote-text.js +0 -7
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { closeSync, copyFileSync, openSync, readSync, statSync, existsSync } from "node:fs";
|
|
2
|
+
import { isExecutionLane } from "../execution-lane-caps.js";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { AppendLog, atomicWriteFile, ensureDir } from "@sema-agent/core";
|
|
4
5
|
import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
|
|
@@ -295,6 +296,16 @@ export class FileApprovalAskStore {
|
|
|
295
296
|
replayStats() {
|
|
296
297
|
return { rejected: this.replayRejectedCount, corruptLines: this.corruptLineCount, records: this.records };
|
|
297
298
|
}
|
|
299
|
+
backfillExecutionLanes(lanes, refuse) {
|
|
300
|
+
const pending = this.core.exportRows().asks.filter((r) => !isExecutionLane(String(r.executionLane ?? ""))).length;
|
|
301
|
+
if (pending === 0)
|
|
302
|
+
return 0;
|
|
303
|
+
if (lanes.length !== 1)
|
|
304
|
+
refuse(pending);
|
|
305
|
+
const filled = this.core.fillMissingExecutionLanes(lanes[0]);
|
|
306
|
+
this.compact();
|
|
307
|
+
return filled;
|
|
308
|
+
}
|
|
298
309
|
dispose() {
|
|
299
310
|
this.log?.close();
|
|
300
311
|
this.log = undefined;
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* - resolveProvisional 故意不经 canAskTransition(同 SQL twin 头注:这是版本化补偿的例外通道)。
|
|
30
30
|
*/
|
|
31
31
|
import { type AskState, type BatchState } from "../approval-ask-machine.js";
|
|
32
|
+
import { type ExecutionLane } from "../execution-lane-caps.js";
|
|
32
33
|
import type { AskCallCoordinate, AskDecision, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, EnsureAskResult, DecideResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
|
|
33
34
|
/**
|
|
34
35
|
* [ref] 的 `updatedInput` **入店编码**——两 twin 共用的那一只(本函数是唯一真源)。
|
|
@@ -72,6 +73,11 @@ export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
|
|
|
72
73
|
* 两种可变性)。
|
|
73
74
|
*/
|
|
74
75
|
exportRows(): ApprovalAskRowsSnapshot;
|
|
76
|
+
/**
|
|
77
|
+
* 执行放置切换 ④b 的 local 腿(File 形的内核口;`FileApprovalAskStore.backfillExecutionLanes` 调):出处车道还没记下的行(升级前写下的日志 / 快照行
|
|
78
|
+
* 装回后这一格缺席)记成 `lane`(一元车道表的唯一项 —— 调用方判过)。返回改了的行数;只碰缺这一格的行。
|
|
79
|
+
*/
|
|
80
|
+
fillMissingExecutionLanes(lane: ExecutionLane): number;
|
|
75
81
|
/** [ref]:一行的**同步**点读(拷贝;纯读,零判定)—— File 形在写口的同步前缀里用它(见类顶注)。 */
|
|
76
82
|
peekAsk(askId: string): AskRow | null;
|
|
77
83
|
/** [ref]:把快照里的行**原样**装回两张 Map(同键覆盖)。零谓词、零状态机 —— 它不是一条转移,是重放
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
|
|
2
|
+
import { isExecutionLane } from "../execution-lane-caps.js";
|
|
2
3
|
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
3
4
|
import { askRowCarriesOwner, askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth, projectDecideReading } from "./approval-ask-store-sql.js";
|
|
4
5
|
function applyPatch(row, patch) {
|
|
@@ -41,6 +42,16 @@ export class InMemoryApprovalAskStore {
|
|
|
41
42
|
exportRows() {
|
|
42
43
|
return { asks: [...this.asks.values()].map((r) => ({ ...r })), batches: [...this.batches.values()].map((b) => ({ ...b })) };
|
|
43
44
|
}
|
|
45
|
+
fillMissingExecutionLanes(lane) {
|
|
46
|
+
let filled = 0;
|
|
47
|
+
for (const [askId, row] of this.asks) {
|
|
48
|
+
if (isExecutionLane(String(row.executionLane ?? "")))
|
|
49
|
+
continue;
|
|
50
|
+
this.asks.set(askId, { ...row, executionLane: lane });
|
|
51
|
+
filled += 1;
|
|
52
|
+
}
|
|
53
|
+
return filled;
|
|
54
|
+
}
|
|
44
55
|
peekAsk(askId) {
|
|
45
56
|
const row = this.asks.get(askId);
|
|
46
57
|
return row ? { ...row } : null;
|
|
@@ -74,6 +85,7 @@ export class InMemoryApprovalAskStore {
|
|
|
74
85
|
sourceTaskId: row.sourceTaskId,
|
|
75
86
|
sessionId: row.sessionId,
|
|
76
87
|
owner: row.owner ?? null,
|
|
88
|
+
executionLane: row.executionLane,
|
|
77
89
|
batchId: row.batchId,
|
|
78
90
|
toolCallId: row.toolCallId,
|
|
79
91
|
legKey: row.legKey,
|
|
@@ -44,6 +44,7 @@ import { type AskState, type BatchState } from "../approval-ask-machine.js";
|
|
|
44
44
|
import type { HostSettledBy } from "../host-decision.js";
|
|
45
45
|
import { type AskRowCause, type SettleCause } from "../approval-deny-reasons.js";
|
|
46
46
|
import { type IndexSpec } from "./ensure-index.js";
|
|
47
|
+
import { type ExecutionLane } from "../execution-lane-caps.js";
|
|
47
48
|
export type AskDecision = "approve" | "deny";
|
|
48
49
|
export interface AskRow {
|
|
49
50
|
askId: string;
|
|
@@ -52,6 +53,11 @@ export interface AskRow {
|
|
|
52
53
|
sessionId: string;
|
|
53
54
|
/** 租户 scope——哨兵归一在消费层(车2+),店里存原值(设计定稿 §3)。 */
|
|
54
55
|
owner: string | null;
|
|
56
|
+
/**
|
|
57
|
+
* 造这只问的那条执行的车道(审批出处带车道:问行唯一铸点 `ensureAsk` 与 `taskId` / `sessionId` 同处写;既有行命中一个字节不改)。
|
|
58
|
+
* 读根授权只读问自己记下的车道。存量行随执行放置切换的一次性迁移回填(SQL `approval_ask.execution_lane`、local 问账日志压实)。
|
|
59
|
+
*/
|
|
60
|
+
executionLane: ExecutionLane;
|
|
55
61
|
batchId: string;
|
|
56
62
|
toolCallId: string;
|
|
57
63
|
/** 车3 §3.2′ 换轴:数值 `leg` → `legKey`(= `sha256(resume token)` 的 hex,首腿空串)。语义与派生
|
|
@@ -174,6 +180,8 @@ export interface NewAskRow {
|
|
|
174
180
|
sourceTaskId: string;
|
|
175
181
|
sessionId: string;
|
|
176
182
|
owner?: string | null;
|
|
183
|
+
/** 出处的执行车道(必填;语义见 {@link AskRow.executionLane})。 */
|
|
184
|
+
executionLane: ExecutionLane;
|
|
177
185
|
batchId: string;
|
|
178
186
|
toolCallId: string;
|
|
179
187
|
legKey: string;
|
|
@@ -562,6 +570,14 @@ export interface ApprovalAskStore {
|
|
|
562
570
|
getBatch(batchId: string): Promise<BatchRow | null>;
|
|
563
571
|
}
|
|
564
572
|
export declare const APPROVAL_ASK_TABLE = "approval_ask";
|
|
573
|
+
/**
|
|
574
|
+
* `approval_ask.execution_lane` 的列定义(两方言;唯一属主)—— 建表 DDL 内联它,存量库的加列只由执行放置切换的一次性迁移做(`one-time-migrations.ts` M32 步 ②),
|
|
575
|
+
* 那一步也读这里的定义。`DEFAULT ''` 只为存量库一句加列;回填(同迁移步 ④b)之后没有 '' 行,读口对 '' 与词表外的值一律响亮拒({@link executionLaneColumnOf})。
|
|
576
|
+
*/
|
|
577
|
+
export declare const APPROVAL_ASK_EXECUTION_LANE_COLUMN: {
|
|
578
|
+
readonly mysql: "execution_lane VARCHAR(32) NOT NULL DEFAULT ''";
|
|
579
|
+
readonly pg: "execution_lane VARCHAR(32) COLLATE \"C\" NOT NULL DEFAULT ''";
|
|
580
|
+
};
|
|
565
581
|
export declare const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
566
582
|
/**
|
|
567
583
|
* TiDB/MySQL-protocol 侧的两条建表语句,**抽成导出数组**(车3 刀 3a):`tidb-pool.ts` 的
|
|
@@ -571,7 +587,8 @@ export declare const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
|
571
587
|
* 下面的 `ensureTiDBApprovalAskSchema` 保留为遍历这个数组的薄壳(集成测试直接调它建表,
|
|
572
588
|
* 不必为了建两张表去拉起整套中央 schema)。
|
|
573
589
|
*
|
|
574
|
-
* SCHEMA POLICY 同 `tidb-pool.ts` 头注:纯 CREATE,禁 ALTER 增量 seam
|
|
590
|
+
* SCHEMA POLICY 同 `tidb-pool.ts` 头注:纯 CREATE,禁 ALTER 增量 seam,加列直接改这里(新建库随它到货;带数据的存量库由列集对账拒启并打印 `ALTER`,部署者自己执行;
|
|
591
|
+
* 改列类型 / 可空性列集对账看不见,另走一次性迁移;只有空库 / 开发机可以整库重建〔销毁全部数据〕)
|
|
575
592
|
* (`docs/schema/baseline-mysql.sql` 是由这些文本机器录制出的**产物**,永不手改)。
|
|
576
593
|
*
|
|
577
594
|
* ── 列宽的**测量依据**([ref] A10;U2 逐列取证在档)──────────────────────────────────────────────────
|
|
@@ -619,18 +636,18 @@ export declare function ensurePgApprovalAskSchema(q: PgQueryFn): Promise<void>;
|
|
|
619
636
|
* [ref] 升级前置断言 —— **拒启**,不是 warn(形照 [ref] 的 `assertPermissionRuleApprovalSchema` /
|
|
620
637
|
* [ref] 的 `assertToolResultProvenanceSchema` 两条先例)。
|
|
621
638
|
*
|
|
622
|
-
* 病:本仓不发 `ALTER TABLE`(SCHEMA POLICY
|
|
639
|
+
* 病:本仓不发 `ALTER TABLE`(SCHEMA POLICY:代码是唯一真源,存量库缺列由部署者按拒启句打印的 ALTER 自己执行)。于是一台**没跟上**就升上来
|
|
623
640
|
* 的部署,`CREATE TABLE IF NOT EXISTS` 对存量 `approval_ask` 是空操作 —— 本车新加的
|
|
624
641
|
* `rule_command` / `rule_scope_root` 两列不在,而 `ensureAsk` 的 INSERT 与 `askCols` 的每一条读
|
|
625
642
|
* **无条件**引用它们。后果不是「少一个新功能」,是**整条流内审批协议**在那台机器上是坏的:
|
|
626
643
|
* · 每一只 ask 的 `ensureAsk` 撞 unknown column ⇒ 被 `noteStoreError` 吞掉 ⇒ 整只 ask 退回 park 路由
|
|
627
644
|
* (卡不落库、`GET /v1/approvals` 的重放面恒空、迟到决议腿恒 404);
|
|
628
645
|
* · 而 `/v1/capabilities` 的 `streamApproval` 仍然报 active ⇒「says yes ⟺ route works」整句为假。
|
|
629
|
-
*
|
|
646
|
+
* 没有这道断言,运维得不到**任何**「这次升级必须先给表加列」的信号 —— 正是 [ref]「禁静默降级」要挡的形。
|
|
630
647
|
*
|
|
631
648
|
* 判据 = **能力探测**(恒空的 `WHERE 1=0` 读)+ **方言的缺列错误码**(判据属主 `sql-errors.ts` 的
|
|
632
|
-
* {@link isMissingColumnError});其余错误**原样 rethrow**,一个字都不加工 ——
|
|
633
|
-
*
|
|
649
|
+
* {@link isMissingColumnError});其余错误**原样 rethrow**,一个字都不加工 —— 把一次瞬时故障诊断成「缺列」的拒因
|
|
650
|
+
* 比它要挡的缺陷更贵([ref] 那两轮收窄的结论逐字继承)。拒因的出路是**闭集三条**(与整库对账同一份,{@link describeProbedTableDrift}),没有销毁性的一条。
|
|
634
651
|
*
|
|
635
652
|
* 🔴 位置与两条先例同款:**不在** `ensureSchema` 里(那条通道的契约是「只发 CREATE」,有运行时门看着),
|
|
636
653
|
* 放在 DDL 之后、任何路由装配之前;且**只在流内审批协议真会上场时**跑(判据 = 与协调器同一个符号
|
|
@@ -2,8 +2,10 @@ import { mysqlDriver, pgDriver, dialectJsonEncoder } from "./sql-driver.js";
|
|
|
2
2
|
import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
|
|
3
3
|
import { APPROVAL_ENDING_CAUSES, causeOfAskRow } from "../approval-deny-reasons.js";
|
|
4
4
|
import { isDupKeyError, isMissingColumnError } from "./sql-errors.js";
|
|
5
|
+
import { describeProbedTableDrift } from "./schema-drift-sentence.js";
|
|
5
6
|
import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, readTriStateJsonValueColumn } from "./sql-json-column.js";
|
|
6
7
|
import { ensureIndexes } from "./ensure-index.js";
|
|
8
|
+
import { isExecutionLane } from "../execution-lane-caps.js";
|
|
7
9
|
export function assertIntegralEpochMs(field, value) {
|
|
8
10
|
if (!Number.isSafeInteger(value)) {
|
|
9
11
|
throw new TypeError(`approval-ask store: ${field} must be an integer epoch-ms (BIGINT column), got ${String(value)}`);
|
|
@@ -99,6 +101,17 @@ export function projectDecideReading(row, owner) {
|
|
|
99
101
|
return askRowCarriesOwner(row, owner) ? row : null;
|
|
100
102
|
}
|
|
101
103
|
export const APPROVAL_ASK_TABLE = "approval_ask";
|
|
104
|
+
export const APPROVAL_ASK_EXECUTION_LANE_COLUMN = {
|
|
105
|
+
mysql: "execution_lane VARCHAR(32) NOT NULL DEFAULT ''",
|
|
106
|
+
pg: `execution_lane VARCHAR(32) COLLATE "C" NOT NULL DEFAULT ''`,
|
|
107
|
+
};
|
|
108
|
+
function executionLaneColumnOf(raw, askId) {
|
|
109
|
+
const lane = typeof raw === "string" ? raw : "";
|
|
110
|
+
if (!isExecutionLane(lane)) {
|
|
111
|
+
throw new Error(`approval-ask-store: ask ${askId} carries execution_lane ${JSON.stringify(lane)}, which is not an execution lane — the execution placement switch migration backfills every row; refusing rather than guess the lane this ask was raised on`);
|
|
112
|
+
}
|
|
113
|
+
return lane;
|
|
114
|
+
}
|
|
102
115
|
export const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
103
116
|
export const TIDB_APPROVAL_ASK_STATEMENTS = [
|
|
104
117
|
`CREATE TABLE IF NOT EXISTS ${APPROVAL_BATCH_TABLE} (
|
|
@@ -118,6 +131,9 @@ export const TIDB_APPROVAL_ASK_STATEMENTS = [
|
|
|
118
131
|
source_task_id VARCHAR(255) NOT NULL,
|
|
119
132
|
session_id VARCHAR(64) NOT NULL,
|
|
120
133
|
owner VARCHAR(190) NULL,
|
|
134
|
+
-- execution_lane:造这只问的那条执行的车道(审批出处带车道;ensureAsk 铸行时写,既有行命中不改)。DEFAULT '' 只为存量库一句加列
|
|
135
|
+
-- (一次性迁移加列并按根会话放置回填,迁移后没有 '' 行)。
|
|
136
|
+
${APPROVAL_ASK_EXECUTION_LANE_COLUMN.mysql},
|
|
121
137
|
batch_id VARCHAR(64) NOT NULL,
|
|
122
138
|
tool_call_id VARCHAR(255) NOT NULL,
|
|
123
139
|
-- leg_key: 车3 §3.2′ 身份轴——sha256(resume checkpoint token) 的 hex(64 字符),首腿存空串。
|
|
@@ -172,7 +188,7 @@ export const TIDB_APPROVAL_ASK_STATEMENTS = [
|
|
|
172
188
|
UNIQUE KEY uq_approval_ask_idem (task_id, idempotency_key),
|
|
173
189
|
KEY idx_ask_task_state (task_id, state),
|
|
174
190
|
-- idx_ask_session_state: 车3 §5.1 的 sync 腿开流重放读口(listPendingBySession)的支撑索引。
|
|
175
|
-
-- 表尚未进生产
|
|
191
|
+
-- 表尚未进生产 ⇒ 此刻加索引零迁移成本,晚一车加就要动生产表。
|
|
176
192
|
KEY idx_ask_session_state (session_id, state),
|
|
177
193
|
KEY idx_ask_batch (batch_id),
|
|
178
194
|
KEY idx_ask_state (state)
|
|
@@ -206,6 +222,8 @@ export async function ensurePgApprovalAskSchema(q) {
|
|
|
206
222
|
source_task_id VARCHAR(255) COLLATE "C" NOT NULL,
|
|
207
223
|
session_id VARCHAR(64) COLLATE "C" NOT NULL,
|
|
208
224
|
owner VARCHAR(190) COLLATE "C",
|
|
225
|
+
-- execution_lane —— MySQL twin 逐字同形(语义见那侧注)。
|
|
226
|
+
${APPROVAL_ASK_EXECUTION_LANE_COLUMN.pg},
|
|
209
227
|
batch_id VARCHAR(64) COLLATE "C" NOT NULL,
|
|
210
228
|
tool_call_id VARCHAR(255) COLLATE "C" NOT NULL,
|
|
211
229
|
-- leg_key: 车3 §3.2′ 身份轴——sha256(resume checkpoint token) 的 hex(64 字符),首腿存空串
|
|
@@ -258,18 +276,16 @@ export async function assertApprovalAskRuleMaterialSchema(query, dialect) {
|
|
|
258
276
|
`persisted on the row too, so a replica that does not hold the waiting leg replays the approved bytes; every ask-row ` +
|
|
259
277
|
`write and read names these columns unconditionally, so on this table the whole in-stream approval protocol degrades silently (no card ` +
|
|
260
278
|
`is persisted, the replay list stays empty, late decisions 404) while /v1/capabilities still reports it active. ` +
|
|
261
|
-
`
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
`
|
|
265
|
-
|
|
266
|
-
`in-flight card falls back to the durable gate (\`POST /v1/approvals/:sessionId/decide\`). ` +
|
|
267
|
-
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}`);
|
|
279
|
+
`The table holds IN-FLIGHT approval asks (cards awaiting an answer) plus settled bookkeeping; the durable park face ` +
|
|
280
|
+
`(checkpoint rows) and the persisted rules themselves are untouched, so an in-flight card falls back to the durable gate ` +
|
|
281
|
+
`(\`POST /v1/approvals/:sessionId/decide\`) until the columns exist.\n` +
|
|
282
|
+
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
|
|
283
|
+
(await describeProbedTableDrift(query, dialect, [APPROVAL_ASK_TABLE])));
|
|
268
284
|
}
|
|
269
285
|
}
|
|
270
286
|
function askCols(dialect) {
|
|
271
287
|
return [
|
|
272
|
-
"ask_id, task_id, source_task_id, session_id, owner, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state",
|
|
288
|
+
"ask_id, task_id, source_task_id, session_id, owner, execution_lane, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state",
|
|
273
289
|
"provisional, rev, decision",
|
|
274
290
|
jsonColumnText(dialect, "decision_actor"),
|
|
275
291
|
"decision_note, settled_by",
|
|
@@ -307,6 +323,7 @@ function mapAskRowBody(r, askId) {
|
|
|
307
323
|
sourceTaskId: String(r.source_task_id),
|
|
308
324
|
sessionId: String(r.session_id),
|
|
309
325
|
owner: strOrNull(r.owner),
|
|
326
|
+
executionLane: executionLaneColumnOf(r.execution_lane, askId),
|
|
310
327
|
batchId: String(r.batch_id),
|
|
311
328
|
toolCallId: String(r.tool_call_id),
|
|
312
329
|
legKey: String(r.leg_key),
|
|
@@ -410,14 +427,15 @@ export class SqlApprovalAskStore {
|
|
|
410
427
|
try {
|
|
411
428
|
await conn.begin();
|
|
412
429
|
await conn.query(this.q(`INSERT IGNORE INTO ${APPROVAL_BATCH_TABLE} (batch_id, task_id, state, rev, created_at_ms, updated_at_ms) VALUES (?, ?, 'OPEN', 0, ?, ?)`, `INSERT INTO ${APPROVAL_BATCH_TABLE} (batch_id, task_id, state, rev, created_at_ms, updated_at_ms) VALUES ($1, $2, 'OPEN', 0, $3, $4) ON CONFLICT (batch_id) DO NOTHING`), [row.batchId, row.taskId, now, now]);
|
|
413
|
-
const askInsert = await conn.query(this.q(`INSERT IGNORE INTO ${APPROVAL_ASK_TABLE} (ask_id, task_id, source_task_id, session_id, owner, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state, provisional, rev, decision, decision_actor, decision_note, settled_by, decided_at_ms, denied_reason, gate_token, gate_bound_call_id, gate_bound_input_hash, idempotency_key, card_json, rule_command, rule_scope_root, schema_version, expires_at_ms, created_at_ms, updated_at_ms) ` +
|
|
414
|
-
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'STREAM_PENDING', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, ?, ?, ?, ?, ?, ?)", `INSERT INTO ${APPROVAL_ASK_TABLE} (ask_id, task_id, source_task_id, session_id, owner, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state, provisional, rev, decision, decision_actor, decision_note, settled_by, decided_at_ms, denied_reason, gate_token, gate_bound_call_id, gate_bound_input_hash, idempotency_key, card_json, rule_command, rule_scope_root, schema_version, expires_at_ms, created_at_ms, updated_at_ms) ` +
|
|
415
|
-
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'STREAM_PENDING', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $
|
|
430
|
+
const askInsert = await conn.query(this.q(`INSERT IGNORE INTO ${APPROVAL_ASK_TABLE} (ask_id, task_id, source_task_id, session_id, owner, execution_lane, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state, provisional, rev, decision, decision_actor, decision_note, settled_by, decided_at_ms, denied_reason, gate_token, gate_bound_call_id, gate_bound_input_hash, idempotency_key, card_json, rule_command, rule_scope_root, schema_version, expires_at_ms, created_at_ms, updated_at_ms) ` +
|
|
431
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'STREAM_PENDING', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?, ?, ?, ?, ?, ?, ?)", `INSERT INTO ${APPROVAL_ASK_TABLE} (ask_id, task_id, source_task_id, session_id, owner, execution_lane, batch_id, tool_call_id, leg_key, parent_tool_call_id, bound_input_hash, state, provisional, rev, decision, decision_actor, decision_note, settled_by, decided_at_ms, denied_reason, gate_token, gate_bound_call_id, gate_bound_input_hash, idempotency_key, card_json, rule_command, rule_scope_root, schema_version, expires_at_ms, created_at_ms, updated_at_ms) ` +
|
|
432
|
+
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 'STREAM_PENDING', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, $12, $13, $14, $15, $16, $17, $18) ON CONFLICT (ask_id) DO NOTHING"), [
|
|
416
433
|
row.askId,
|
|
417
434
|
row.taskId,
|
|
418
435
|
row.sourceTaskId,
|
|
419
436
|
row.sessionId,
|
|
420
437
|
row.owner ?? null,
|
|
438
|
+
row.executionLane,
|
|
421
439
|
row.batchId,
|
|
422
440
|
row.toolCallId,
|
|
423
441
|
row.legKey,
|
|
@@ -3,6 +3,7 @@ import { pgSafeJsonStringify, pgSanitizeText } from "./pg-safe-json.js";
|
|
|
3
3
|
import { isMysqlDupKeyError } from "./sql-errors.js";
|
|
4
4
|
import { ensureIndexes } from "./ensure-index.js";
|
|
5
5
|
import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
|
|
6
|
+
import { backgroundAgentNameOf } from "../background-agent-name.js";
|
|
6
7
|
export const BACKGROUND_AGENT_TABLE = "background_agent";
|
|
7
8
|
function summaryCols(dialect) {
|
|
8
9
|
return ("handle, owner, session_scoped, session_id, parent_session_id, root_session_id, name, agent_type, status, " +
|
|
@@ -11,12 +12,14 @@ function summaryCols(dialect) {
|
|
|
11
12
|
const readAgentRecordBody = createObjectColumnReader();
|
|
12
13
|
const readUsageBody = createObjectColumnReader();
|
|
13
14
|
function readRecordColumn(v, handle) {
|
|
15
|
+
let record;
|
|
14
16
|
try {
|
|
15
|
-
|
|
17
|
+
record = decodeJsonColumn(v, readAgentRecordBody, `${BACKGROUND_AGENT_TABLE}.record_json for handle ${handle}`);
|
|
16
18
|
}
|
|
17
19
|
catch (e) {
|
|
18
20
|
throw foldJsonColumn(e, (m) => `BackgroundAgentStore: ${m} — refusing rather than serve a hollow agent record`);
|
|
19
21
|
}
|
|
22
|
+
return { ...record, name: backgroundAgentNameOf(record) };
|
|
20
23
|
}
|
|
21
24
|
function readUsageColumn(v, handle) {
|
|
22
25
|
try {
|
|
@@ -45,7 +48,7 @@ function projParams(stored, json, text) {
|
|
|
45
48
|
stored.parentSessionId ?? null,
|
|
46
49
|
stored.rootSessionId ?? null,
|
|
47
50
|
(stored.sessionScoped ? stored.owner : stored.parentSessionId) ?? null,
|
|
48
|
-
|
|
51
|
+
text(backgroundAgentNameOf(stored)).slice(0, 255),
|
|
49
52
|
stored.agentType !== undefined ? text(stored.agentType).slice(0, 190) : null,
|
|
50
53
|
stored.status,
|
|
51
54
|
stored.spawnedAt,
|
|
@@ -68,7 +71,7 @@ function rowToSummary(r) {
|
|
|
68
71
|
...(r.session_id !== null && r.session_id !== undefined ? { sessionId: String(r.session_id) } : {}),
|
|
69
72
|
...(r.parent_session_id !== null && r.parent_session_id !== undefined ? { parentSessionId: String(r.parent_session_id) } : {}),
|
|
70
73
|
...(r.root_session_id !== null && r.root_session_id !== undefined ? { rootSessionId: String(r.root_session_id) } : {}),
|
|
71
|
-
...(r.name !== null && r.name !== undefined ? { name: String(r.name) } : {}),
|
|
74
|
+
name: backgroundAgentNameOf({ handle: String(r.handle), ...(r.name !== null && r.name !== undefined ? { name: String(r.name) } : {}) }),
|
|
72
75
|
...(r.agent_type !== null && r.agent_type !== undefined ? { agentType: String(r.agent_type) } : {}),
|
|
73
76
|
status: String(r.status),
|
|
74
77
|
spawnedAt: Number(r.spawned_at_ms),
|
|
@@ -3,6 +3,7 @@ import type { OwnerAwareSessionStore, SessionListItem } from "../security.js";
|
|
|
3
3
|
import type { StagingHandle } from "../session-sync-kernel.js";
|
|
4
4
|
import { type PlacementAcquireOpts } from "./session-placement.js";
|
|
5
5
|
import type { InstructionSourceStore } from "../instruction-source-notice.js";
|
|
6
|
+
import type { SessionWorkspaceStore } from "../session-workspace.js";
|
|
6
7
|
import type { OwnerlessClaim } from "../delegated-session-owner.js";
|
|
7
8
|
export interface CachingOptions {
|
|
8
9
|
/** Idle seconds a woken session is kept warm. 0 disables caching (pure passthrough). */
|
|
@@ -53,7 +54,7 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
53
54
|
private readonly onStaleHit?;
|
|
54
55
|
/** core `SessionStore.headOf` —— 按 id 读一行(属主 / 住客 / 叶子)的唯一读口,**纯转发、不经暖缓存**(答的是行,绝不从暖缓存里那只会话的元数据答 ——
|
|
55
56
|
* 缓存的会话活得比「另一只店删掉又重建了这一行」长)。内层店必有(本类的暖命中按它核新鲜)。🔴 必须转发:生产默认把真店包进本类,授权口 / 属主门 /
|
|
56
|
-
*
|
|
57
|
+
* k8s 工作区空间 / SSE 探针 / resume-at 读的都是本类。 */
|
|
57
58
|
readonly headOf: SessionHeadReader["headOf"];
|
|
58
59
|
readonly register?: (sessionId: string, owner: string | null) => Promise<void>;
|
|
59
60
|
/** [ref] 委派继承律的认领口,纯转发(写的是行上的属主那一格 —— 只 CAS 子行自己,不碰暖缓存里的会话;停驻挂点在默认部署上读的就是本类 —— 与 `placementOf` 同转发同缺:内店记录委派树 ⇒ 两只都在)。 */
|
|
@@ -71,12 +72,16 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
71
72
|
q?: string;
|
|
72
73
|
}) => Promise<SessionListItem[]>;
|
|
73
74
|
readonly fork?: (sourceId: string, owner: string | null) => Promise<string | null>;
|
|
75
|
+
/** fork 续写的店契约(原样转发;与 fork 同理绕过暖缓存 —— 读写的是持久行,新 id 本来就不在缓存里)。 */
|
|
76
|
+
readonly forkTo?: OwnerAwareSessionStore["forkTo"];
|
|
77
|
+
/** 执行席(原样转发:放置是会话**行**上的一格,缓存只缓存会话日志的暖句柄,不缓存行格 —— 读与写都直达内层店)。 */
|
|
78
|
+
readonly executionPlacement?: OwnerAwareSessionStore["executionPlacement"];
|
|
74
79
|
readonly deleteSession?: (sessionId: string, owner: string | null) => Promise<boolean>;
|
|
75
80
|
/** The session row's list projection for one id + its writable bits (`title` / `pinned`) — DURABLE, pure pass-through
|
|
76
81
|
* (they read / write `session_meta` / the local sidecars, never the warm cache). 🔴 Must forward (the retention / placements
|
|
77
82
|
* lesson): the production default wraps the real store in this class, and the route's fact `sessionPatch` reads THIS object. */
|
|
78
83
|
readonly sessionSummaryOf?: (sessionId: string) => Promise<SessionListItem | undefined>;
|
|
79
|
-
readonly
|
|
84
|
+
readonly writeSessionRowCells?: OwnerAwareSessionStore["writeSessionRowCells"];
|
|
80
85
|
/** The auto-titler's NULL-only title write (SQL twins + local sidecar carry it; pure pass-through). */
|
|
81
86
|
readonly setTitleIfNull?: (sessionId: string, title: string) => Promise<boolean>;
|
|
82
87
|
readonly probeTitle?: (sessionId: string) => Promise<"none" | "untitled" | "titled">;
|
|
@@ -85,6 +90,10 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
85
90
|
* 而装配点按「店上两个方法都在」判席 —— 不转发 = 默认部署上换源通告**静默不发**,且没有任何一处报错。 */
|
|
86
91
|
readonly readInstructionSource?: InstructionSourceStore["readInstructionSource"];
|
|
87
92
|
readonly recordInstructionSource?: InstructionSourceStore["recordInstructionSource"];
|
|
93
|
+
/** 会话行的位置与项目那一格(`session_meta.workspace` / local sidecar;`session-workspace.ts`),纯转发、不经暖缓存。
|
|
94
|
+
* 🔴 必须转发(同上一条教训):装配点与 resolveSpec 按「店上两个方法都在」判这一面 —— 不转发 = 默认部署上不记行、续跑腿不续声明项目,且没有任何一处报错。 */
|
|
95
|
+
readonly readSessionWorkspace?: SessionWorkspaceStore["readSessionWorkspace"];
|
|
96
|
+
readonly recordSessionWorkspace?: SessionWorkspaceStore["recordSessionWorkspace"];
|
|
88
97
|
/** 2c session-sync — delegated export/import seam, DURABLE (bypasses the warm cache exactly like
|
|
89
98
|
* list/fork: an export reads the full durable log, an import writes durable state). */
|
|
90
99
|
readonly exportEntries?: (sessionId: string) => Promise<SessionTreeEntry[] | null>;
|
|
@@ -12,13 +12,17 @@ export class CachingSessionStore {
|
|
|
12
12
|
claimOwnerless;
|
|
13
13
|
listSessions;
|
|
14
14
|
fork;
|
|
15
|
+
forkTo;
|
|
16
|
+
executionPlacement;
|
|
15
17
|
deleteSession;
|
|
16
18
|
sessionSummaryOf;
|
|
17
|
-
|
|
19
|
+
writeSessionRowCells;
|
|
18
20
|
setTitleIfNull;
|
|
19
21
|
probeTitle;
|
|
20
22
|
readInstructionSource;
|
|
21
23
|
recordInstructionSource;
|
|
24
|
+
readSessionWorkspace;
|
|
25
|
+
recordSessionWorkspace;
|
|
22
26
|
exportEntries;
|
|
23
27
|
listEntryIds;
|
|
24
28
|
exportEntriesStream;
|
|
@@ -55,8 +59,8 @@ export class CachingSessionStore {
|
|
|
55
59
|
this.listSessions = ownerAware.listSessions.bind(inner);
|
|
56
60
|
if (ownerAware.sessionSummaryOf)
|
|
57
61
|
this.sessionSummaryOf = ownerAware.sessionSummaryOf.bind(inner);
|
|
58
|
-
if (ownerAware.
|
|
59
|
-
this.
|
|
62
|
+
if (ownerAware.writeSessionRowCells)
|
|
63
|
+
this.writeSessionRowCells = ownerAware.writeSessionRowCells.bind(inner);
|
|
60
64
|
if (ownerAware.setTitleIfNull)
|
|
61
65
|
this.setTitleIfNull = ownerAware.setTitleIfNull.bind(inner);
|
|
62
66
|
if (ownerAware.probeTitle)
|
|
@@ -65,8 +69,16 @@ export class CachingSessionStore {
|
|
|
65
69
|
this.readInstructionSource = ownerAware.readInstructionSource.bind(inner);
|
|
66
70
|
if (ownerAware.recordInstructionSource)
|
|
67
71
|
this.recordInstructionSource = ownerAware.recordInstructionSource.bind(inner);
|
|
72
|
+
if (ownerAware.readSessionWorkspace)
|
|
73
|
+
this.readSessionWorkspace = ownerAware.readSessionWorkspace.bind(inner);
|
|
74
|
+
if (ownerAware.recordSessionWorkspace)
|
|
75
|
+
this.recordSessionWorkspace = ownerAware.recordSessionWorkspace.bind(inner);
|
|
68
76
|
if (ownerAware.fork)
|
|
69
77
|
this.fork = ownerAware.fork.bind(inner);
|
|
78
|
+
if (ownerAware.forkTo)
|
|
79
|
+
this.forkTo = ownerAware.forkTo.bind(inner);
|
|
80
|
+
if (ownerAware.executionPlacement)
|
|
81
|
+
this.executionPlacement = ownerAware.executionPlacement;
|
|
70
82
|
if (ownerAware.exportEntries)
|
|
71
83
|
this.exportEntries = ownerAware.exportEntries.bind(inner);
|
|
72
84
|
if (ownerAware.listEntryIds)
|
|
@@ -3,6 +3,7 @@ import type { Pool as PgPool } from "pg";
|
|
|
3
3
|
import { type ExecutionOutcomeRecordWord, type GateOutcome, type Checkpoint, type CheckpointGate, type CheckpointState, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type PendingSteerInput, type ResumeOutcome, type ResolvedOutcome, type ResolveExpectation, type ReopenReason, type RiskDescriptor, type StoreDurability, type StoreFidelity, type ToolApprovalCard } from "@sema-agent/core";
|
|
4
4
|
import { type ParkRowFacts, type RuleOfferProjection, type SkillCardFacts } from "../approval-card.js";
|
|
5
5
|
import { type SqlDialect, type SqlDriver } from "./sql-driver.js";
|
|
6
|
+
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
6
7
|
import type { SealedCheckpointCtx } from "../http/checkpoint-ctx.js";
|
|
7
8
|
/** ctx 行改写店腿的读数(两孪生同形):扫到的可读行 · 回写成的行 · 回写成的行里改写函数报的改动数 · 读不出的行 · 改写之后一行装不下的行。 */
|
|
8
9
|
export interface CtxRowsRewrite {
|
|
@@ -239,8 +240,8 @@ export declare function pendingRowPrecedes(a: {
|
|
|
239
240
|
*
|
|
240
241
|
* 🔴 为什么是一张表而不是每列一个 `assert*ColumnSchema` 函数([ref] 归一):[ref]① 那次是一列一函数,
|
|
241
242
|
* 本批 [ref] 又要加两列 —— 照抄就是第二、第三份三十行的同形代码,而它们**唯一的差别只有列名与那句话**。
|
|
242
|
-
* 探测法(恒空 `WHERE 1=0` 读 + 方言缺列码)、失败方向(
|
|
243
|
-
* (
|
|
243
|
+
* 探测法(恒空 `WHERE 1=0` 读 + 方言缺列码)、失败方向(只在**可证**缺列时才拒)、恢复动作
|
|
244
|
+
* (部署者按拒因打印的 ALTER 在原表上加列;表里是在飞的停驻,不动它)三者对整张表是同一条,所以规则只留一条,列变成数据:下一次加列
|
|
244
245
|
* 只加一行,不再多一条规则。
|
|
245
246
|
*/
|
|
246
247
|
export declare const CHECKPOINT_ADDED_COLUMNS: ReadonlyArray<{
|
|
@@ -253,14 +254,15 @@ export declare const CHECKPOINT_ADDED_COLUMNS: ReadonlyArray<{
|
|
|
253
254
|
* 依据是本仓 assert*Schema 探针族的真先例与失败方向本身)。[ref] 起判据对 {@link CHECKPOINT_ADDED_COLUMNS}
|
|
254
255
|
* **整张列册**跑(见那张表的头注:归一的理由)。
|
|
255
256
|
*
|
|
256
|
-
* 病:本仓不发 `ALTER TABLE`(SCHEMA POLICY
|
|
257
|
+
* 病:本仓不发 `ALTER TABLE`(SCHEMA POLICY:代码是唯一真源,存量库缺列由部署者按拒启句打印的 ALTER 自己执行)。一台**没跟上**就升上来的
|
|
257
258
|
* 部署,`CREATE TABLE IF NOT EXISTS` 对存量 `checkpoint` 是空操作 —— 后加的列不在,而写口与读口
|
|
258
259
|
* **无条件**引用它们。没有这道断言,服务照常过启动与健康检查,直到运行期才响,且首撞点在用户的
|
|
259
260
|
* 审批 / resume 路径上。
|
|
260
261
|
*
|
|
261
262
|
* 判据 = **能力探测**(恒空的 `WHERE 1=0` 读)+ **方言的缺列错误码**({@link isMissingColumnError},
|
|
262
|
-
* 判据属主 `sql-errors.ts`);其余错误**原样 rethrow**,一个字都不加工 ——
|
|
263
|
-
*
|
|
263
|
+
* 判据属主 `sql-errors.ts`);其余错误**原样 rethrow**,一个字都不加工 —— 把一次瞬时故障诊断成「缺列」的拒因
|
|
264
|
+
* 比它要挡的缺陷更贵([ref] 两轮收窄的结论逐字继承)。拒因的出路是**闭集三条**(与整库对账同一份,{@link describeProbedTableDrift}),
|
|
265
|
+
* 没有销毁性的一条:这张表里是在飞的停驻,出路是原表上加列。
|
|
264
266
|
*
|
|
265
267
|
* 位置:与三条先例同款,不在 `ensureSchema` 里(那条通道的契约是「只发 CREATE」),放在 boot 的
|
|
266
268
|
* store 装配段、路由装配之前;**无条件**跑(与 [ref] tool_result 探针同档)——checkpoint 表在两方言的
|
|
@@ -464,9 +466,9 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
464
466
|
protected readonly logger?: {
|
|
465
467
|
info?(msg: string, meta?: unknown): void;
|
|
466
468
|
} | undefined;
|
|
467
|
-
/**
|
|
468
|
-
*
|
|
469
|
-
readonly retention:
|
|
469
|
+
/** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法与「为什么 SQL 店答 managed 而三方法的实现体在
|
|
470
|
+
* `retention-store-sql.ts`」逐字见 {@link MANAGED_RETENTION}(扫车道开着时本店的 `checkpoint`/`checkpoint_ctx` 两表由那只聚合店按期清)。 */
|
|
471
|
+
readonly retention: RetentionDeclaration;
|
|
470
472
|
/**
|
|
471
473
|
* `CheckpointStore.durability` 声明([ref] 欠账,[ref] 件5)—— 行落在 MySQL-protocol / PostgreSQL 的
|
|
472
474
|
* `checkpoint` 表里,进程重启、副本轮换、整机重建都不丢 ⇒ `"durable"`,如实。
|
|
@@ -500,25 +502,13 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
500
502
|
* `wiring-governance-operator.test.ts` 的 [ref] 组;已上报上游求一个能表达该宽度的词。
|
|
501
503
|
*/
|
|
502
504
|
readonly fidelity: StoreFidelity;
|
|
503
|
-
/**
|
|
504
|
-
* `CheckpointStore.redecision` 声明(core 5.22.0 F-012 L2/L3;[ref] clay 裁放行)——**如实按能力判**:
|
|
505
|
-
* 本店的 {@link SqlCheckpointStore.reopen} 是真 CAS 实现(`resolved`→`pending` 原子翻回 + `reopen_reason`
|
|
506
|
-
* 权威列,[ref] D-1 的两条重开腿都走它),声明 `reopen: true` 是读数不是抬举。core 的沙箱准入
|
|
507
|
-
* 模式(pre-flight 要求 `redecision.reopen === true`,declaration never duck-typing——方法在场不算数)
|
|
508
|
-
* 由这一格武装:Kata 腿(`capabilities.isolation` 真声明)+ durable park 部署下,`sandbox_local` ask
|
|
509
|
-
* 自动放行并以 `permission.sandbox_admitted` durable 事件披露(缺席披露=core 侧变异恰红)。
|
|
510
|
-
* `validatingLease` **不声明**:本店没有 durable validating-lease 纪律,不承诺没有的东西。
|
|
511
|
-
* 翻向钉:`wiring-governance-operator.test.ts`(修前恰红,与本声明同 commit)。
|
|
512
|
-
*/
|
|
513
|
-
readonly redecision: {
|
|
514
|
-
readonly reopen: true;
|
|
515
|
-
};
|
|
516
505
|
/**
|
|
517
506
|
* `CheckpointStore.execution` 声明(core 7.7.0 [ref];[ref])——**必填**,且必须恰是 `{ outcome: true }`:
|
|
518
507
|
* 店在此承诺 {@link SqlCheckpointStore.recordExecutionOutcome} 是契约描述的那条真 CAS(谓词、四词、
|
|
519
|
-
* 冲突抛),且 {@link SqlCheckpointStore.reopen} 认这条记录。与 `durability`/`fidelity
|
|
520
|
-
*
|
|
521
|
-
*
|
|
508
|
+
* 冲突抛),且 {@link SqlCheckpointStore.reopen} 认这条记录。与 `durability`/`fidelity` 两格同一条
|
|
509
|
+
* 「声明而非鸭子判」姿势,区别只在这一格**不可缺席**:缺席的店(以及缺 `reopen` 动词的店 —— core 7.57.0 起它是必备
|
|
510
|
+
* 动词,原先的 `redecision` 声明格随之退役)会被 core 在 store 席的第一次读(`resolveCheckpointStore`)以
|
|
511
|
+
* `config.invalid_checkpoint_store` 拒启、句子点名缺的每一个成员 —— 那是契约的正确行为,
|
|
522
512
|
* 因为一台记不下「已决动作最后被怎么处置」的部署,它手里每一条 resolved 行在这条轴上都永远读不出来。
|
|
523
513
|
*/
|
|
524
514
|
readonly execution: {
|
|
@@ -526,7 +516,9 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
526
516
|
};
|
|
527
517
|
constructor(db: SqlDriver, logger?: {
|
|
528
518
|
info?(msg: string, meta?: unknown): void;
|
|
529
|
-
} | undefined
|
|
519
|
+
} | undefined, opts?: {
|
|
520
|
+
readonly retention?: RetentionDeclaration;
|
|
521
|
+
});
|
|
530
522
|
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
531
523
|
private q;
|
|
532
524
|
/** JSON column binding. TiDB: plain `JSON.stringify`, stored verbatim. PG: `pgProtocolJsonStringify` —
|
|
@@ -891,12 +883,16 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
891
883
|
export declare class TiDBCheckpointStore extends SqlCheckpointStore {
|
|
892
884
|
constructor(pool: MySqlPool, logger?: {
|
|
893
885
|
info?(msg: string, meta?: unknown): void;
|
|
886
|
+
}, opts?: {
|
|
887
|
+
readonly retention?: RetentionDeclaration;
|
|
894
888
|
});
|
|
895
889
|
}
|
|
896
890
|
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
897
891
|
export declare class PgCheckpointStore extends SqlCheckpointStore {
|
|
898
892
|
constructor(pool: PgPool, logger?: {
|
|
899
893
|
info?(msg: string, meta?: unknown): void;
|
|
894
|
+
}, opts?: {
|
|
895
|
+
readonly retention?: RetentionDeclaration;
|
|
900
896
|
});
|
|
901
897
|
}
|
|
902
898
|
//# sourceMappingURL=checkpoint-store-sql.d.ts.map
|
|
@@ -9,7 +9,8 @@ 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 {
|
|
12
|
+
import { describeProbedTableDrift } from "./schema-drift-sentence.js";
|
|
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;
|
|
15
16
|
export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
@@ -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
|
}
|
|
@@ -336,14 +334,14 @@ const EXECUTION_RECORD_CAS_ATTEMPTS = 8;
|
|
|
336
334
|
export class SqlCheckpointStore {
|
|
337
335
|
db;
|
|
338
336
|
logger;
|
|
339
|
-
retention
|
|
337
|
+
retention;
|
|
340
338
|
durability = "durable";
|
|
341
339
|
fidelity = "json";
|
|
342
|
-
redecision = { reopen: true };
|
|
343
340
|
execution = { outcome: true };
|
|
344
|
-
constructor(db, logger) {
|
|
341
|
+
constructor(db, logger, opts = {}) {
|
|
345
342
|
this.db = db;
|
|
346
343
|
this.logger = logger;
|
|
344
|
+
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
347
345
|
}
|
|
348
346
|
q(tidb, pg) {
|
|
349
347
|
return this.db.dialect === "tidb" ? tidb : pg;
|
|
@@ -798,13 +796,13 @@ export class SqlCheckpointStore {
|
|
|
798
796
|
}
|
|
799
797
|
}
|
|
800
798
|
export class TiDBCheckpointStore extends SqlCheckpointStore {
|
|
801
|
-
constructor(pool, logger) {
|
|
802
|
-
super(mysqlDriver(pool), logger);
|
|
799
|
+
constructor(pool, logger, opts) {
|
|
800
|
+
super(mysqlDriver(pool), logger, opts);
|
|
803
801
|
}
|
|
804
802
|
}
|
|
805
803
|
export class PgCheckpointStore extends SqlCheckpointStore {
|
|
806
|
-
constructor(pool, logger) {
|
|
807
|
-
super(pgDriver(pool), logger);
|
|
804
|
+
constructor(pool, logger, opts) {
|
|
805
|
+
super(pgDriver(pool), logger, opts);
|
|
808
806
|
}
|
|
809
807
|
}
|
|
810
808
|
//# sourceMappingURL=checkpoint-store-sql.js.map
|