@sema-agent/server 7.140.0 → 7.142.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 +505 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +142 -25
- package/dist/approval-ask-audit-store.d.ts +54 -38
- package/dist/approval-ask-audit-store.js +58 -39
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +39 -24
- package/dist/approval-card.js +6 -3
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +33 -1
- package/dist/approval-reconciler.js +43 -40
- 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/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +16 -0
- package/dist/boot/budget-tracing.js +10 -6
- 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.d.ts +24 -4
- package/dist/boot/execution-env.js +34 -27
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +1 -1
- package/dist/boot/memory-consolidation.js +3 -2
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +4 -3
- package/dist/boot/resolve-spec.js +18 -6
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.js +16 -13
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +8 -6
- package/dist/boot/shutdown.js +8 -2
- package/dist/boot/stage-04-stores.js +3 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.js +11 -7
- package/dist/boot/stage-06-runners.d.ts +1 -3
- package/dist/boot/stage-06-runners.js +3 -2
- package/dist/boot/stage-07-capability-layer.d.ts +1 -2
- package/dist/boot/stage-07-capability-layer.js +10 -11
- package/dist/boot/stage-08-reapers.d.ts +1 -2
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +1 -2
- package/dist/boot/stage-10-http-server.d.ts +1 -2
- package/dist/boot/stage-10-http-server.js +6 -4
- package/dist/boot/stores.js +13 -6
- package/dist/boot/web-admin.js +18 -17
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +33 -0
- package/dist/capability-facts.js +32 -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 +13 -13
- package/dist/config-provider.js +19 -33
- package/dist/config-types.d.ts +39 -10
- package/dist/config.d.ts +6 -0
- package/dist/config.js +72 -49
- package/dist/delegated-session-owner.d.ts +21 -19
- package/dist/delegated-session-owner.js +1 -1
- 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 +50 -2
- package/dist/execution-lane-caps.js +90 -13
- 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/fleet/fleet-bus.d.ts +6 -3
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +30 -1
- 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 +8 -2
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -0
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.js +42 -29
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +10 -6
- 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 +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-policy.js +27 -7
- 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/runs.js +3 -3
- package/dist/http/routes/session-memory-sync.d.ts +63 -0
- package/dist/http/routes/session-memory-sync.js +157 -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-list.d.ts +2 -1
- package/dist/http/routes/sessions.js +5 -4
- package/dist/http/routes/tasks.js +70 -71
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +10 -4
- package/dist/http/send.d.ts +6 -1
- package/dist/http/send.js +10 -3
- package/dist/http/server.d.ts +20 -7
- package/dist/http/server.js +2 -4
- 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/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +1 -1
- package/dist/memory-sync-client.d.ts +35 -23
- package/dist/memory-sync-client.js +122 -52
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +7 -1
- package/dist/memory-sync.js +6 -3
- package/dist/observability/fail-open.d.ts +57 -12
- package/dist/observability/fail-open.js +50 -9
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +93 -31
- package/dist/observability/run-terminal.js +175 -171
- 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/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +48 -7
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +9 -8
- package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
- package/dist/plugins/approval-ask-store-sql.js +49 -19
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +74 -3
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +4 -1
- package/dist/plugins/execution-placement-sql.d.ts +11 -1
- package/dist/plugins/execution-placement-sql.js +12 -1
- package/dist/plugins/file-run-store.d.ts +7 -2
- package/dist/plugins/file-run-store.js +12 -2
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- 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 +260 -39
- package/dist/plugins/local-session-store.js +582 -57
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +7 -2
- package/dist/plugins/memory-run-store.js +12 -2
- package/dist/plugins/one-time-migrations.d.ts +68 -2
- package/dist/plugins/one-time-migrations.js +120 -4
- 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-e2b.d.ts +47 -7
- package/dist/plugins/remote-env-e2b.js +242 -46
- package/dist/plugins/remote-env-k8s.d.ts +51 -6
- package/dist/plugins/remote-env-k8s.js +234 -44
- package/dist/plugins/remote-env-local-docker.d.ts +40 -14
- package/dist/plugins/remote-env-local-docker.js +127 -33
- package/dist/plugins/run-store-sql.d.ts +11 -3
- package/dist/plugins/run-store-sql.js +13 -4
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- 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-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/store-backend.d.ts +41 -7
- package/dist/plugins/store-backend.js +22 -4
- package/dist/plugins/store-contracts.d.ts +35 -3
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +221 -28
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +3 -2
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/run-local.js +2 -8
- package/dist/runs.d.ts +39 -12
- package/dist/runs.js +69 -55
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +11 -2
- package/dist/security.js +8 -0
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +46 -4
- package/dist/session-error-wire.js +23 -0
- package/dist/session-incarnation.d.ts +9 -3
- 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/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/task-a2a.d.ts +1 -1
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +62 -27
- package/dist/task-settings.js +105 -29
- package/dist/terminal.d.ts +97 -20
- package/dist/terminal.js +107 -18
- package/dist/tool-approval.d.ts +4 -3
- package/dist/tool-approval.js +12 -14
- package/dist/trace/core-keyset-guard.d.ts +196 -2
- package/dist/trace/engine-notice-wire.d.ts +8 -2
- package/dist/trace/engine-notice-wire.js +4 -2
- package/dist/trace/exit-seat.d.ts +9 -1
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +8 -4
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/project.d.ts +18 -1
- package/dist/trace/project.js +16 -0
- package/dist/trace/redact.js +323 -90
- package/dist/trace/self-minted-wire.d.ts +419 -4
- package/dist/trace/self-minted-wire.js +145 -0
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- 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 +22 -2
- package/dist/web-admin-client/candidate-gate.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/types.d.ts +4 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.141.0.json +367 -0
- package/wire-changes/server@7.142.0.json +639 -0
|
@@ -11,8 +11,8 @@ function applyPatch(row, patch) {
|
|
|
11
11
|
row.decisionNote = patch.decisionNote;
|
|
12
12
|
if (patch.decidedAtMs !== undefined)
|
|
13
13
|
row.decidedAtMs = patch.decidedAtMs;
|
|
14
|
-
if (patch.
|
|
15
|
-
row.
|
|
14
|
+
if (patch.endingCause !== undefined)
|
|
15
|
+
row.endingCause = patch.endingCause;
|
|
16
16
|
if (patch.gateToken !== undefined)
|
|
17
17
|
row.gateToken = patch.gateToken;
|
|
18
18
|
if (patch.gateBoundCallId !== undefined)
|
|
@@ -99,7 +99,8 @@ export class InMemoryApprovalAskStore {
|
|
|
99
99
|
decisionNote: null,
|
|
100
100
|
settledBy: null,
|
|
101
101
|
decidedAtMs: null,
|
|
102
|
-
|
|
102
|
+
endingCause: null,
|
|
103
|
+
parkTrigger: null,
|
|
103
104
|
gateToken: null,
|
|
104
105
|
gateBoundCallId: null,
|
|
105
106
|
gateBoundInputHash: null,
|
|
@@ -181,7 +182,7 @@ export class InMemoryApprovalAskStore {
|
|
|
181
182
|
const scoped = this.asks.get(askId);
|
|
182
183
|
if (scoped !== undefined && scoped.batchId !== batchId)
|
|
183
184
|
return { claimed: false, current: { state: "absent" } };
|
|
184
|
-
const won = await this.transitionAsk(askId, "STREAM_PENDING", "VOID", { updatedAtMs: this.now(), ...(opts?.cause !== undefined ? {
|
|
185
|
+
const won = await this.transitionAsk(askId, "STREAM_PENDING", "VOID", { updatedAtMs: this.now(), ...(opts?.cause !== undefined ? { endingCause: opts.cause } : {}) });
|
|
185
186
|
if (won)
|
|
186
187
|
return { claimed: true, voidedSiblings: [] };
|
|
187
188
|
break;
|
|
@@ -222,7 +223,7 @@ export class InMemoryApprovalAskStore {
|
|
|
222
223
|
return { won: false, voidedSiblings: [] };
|
|
223
224
|
ask.state = "PARKING";
|
|
224
225
|
if (cause !== undefined)
|
|
225
|
-
ask.
|
|
226
|
+
ask.parkTrigger = cause;
|
|
226
227
|
ask.rev += 1;
|
|
227
228
|
ask.updatedAtMs = now;
|
|
228
229
|
if (batch.state === "OPEN") {
|
|
@@ -234,7 +235,7 @@ export class InMemoryApprovalAskStore {
|
|
|
234
235
|
for (const [id, r] of this.asks) {
|
|
235
236
|
if (r.batchId === batchId && r.state === "STREAM_PENDING" && id !== askId) {
|
|
236
237
|
r.state = "VOID";
|
|
237
|
-
r.
|
|
238
|
+
r.endingCause = APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN;
|
|
238
239
|
r.rev += 1;
|
|
239
240
|
r.updatedAtMs = now;
|
|
240
241
|
voided.push(id);
|
|
@@ -267,7 +268,7 @@ export class InMemoryApprovalAskStore {
|
|
|
267
268
|
for (const [id, r] of this.asks) {
|
|
268
269
|
if (r.batchId === batchId && r.state === "PARKING" && id !== askId) {
|
|
269
270
|
r.state = "VOID";
|
|
270
|
-
r.
|
|
271
|
+
r.endingCause = APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE;
|
|
271
272
|
r.rev += 1;
|
|
272
273
|
r.updatedAtMs = now;
|
|
273
274
|
voidedSiblings.push(id);
|
|
@@ -295,7 +296,7 @@ export class InMemoryApprovalAskStore {
|
|
|
295
296
|
for (const [id, r] of this.asks) {
|
|
296
297
|
if (r.batchId === batchId && r.state === "STREAM_PENDING") {
|
|
297
298
|
r.state = "VOID";
|
|
298
|
-
r.
|
|
299
|
+
r.endingCause = APPROVAL_ENDING_CAUSES.BATCH_ABORTED;
|
|
299
300
|
r.rev += 1;
|
|
300
301
|
r.updatedAtMs = now;
|
|
301
302
|
voided.push(id);
|
|
@@ -42,7 +42,7 @@ import type { PgQueryFn } from "./pg-query.js";
|
|
|
42
42
|
import { type SqlDriver, type SqlDialect } from "./sql-driver.js";
|
|
43
43
|
import { type AskState, type BatchState } from "../approval-ask-machine.js";
|
|
44
44
|
import type { HostSettledBy } from "../host-decision.js";
|
|
45
|
-
import { type
|
|
45
|
+
import { type AskRowEndingCause, type SettleCause, type ParkTriggerCause } from "../approval-deny-reasons.js";
|
|
46
46
|
import { type IndexSpec } from "./ensure-index.js";
|
|
47
47
|
import { type ExecutionLane } from "../execution-lane-caps.js";
|
|
48
48
|
export type AskDecision = "approve" | "deny";
|
|
@@ -132,7 +132,16 @@ export interface AskRow {
|
|
|
132
132
|
*/
|
|
133
133
|
updatedInput?: unknown;
|
|
134
134
|
decidedAtMs: number | null;
|
|
135
|
-
|
|
135
|
+
/**
|
|
136
|
+
* `ending_cause` 列原值 —— **终态成因**:这一行为什么没被人答就结束了(到 `VOID` / `DENIED` 的转移带着它写:取消 claim、店内撤兄弟 / bind-once 落选 / 批中止、对账器、起服收敛;没带的转移 ⇒ 保持 `null`)。
|
|
137
|
+
* 只经 {@link askRowEndingCause} 读(词表 + 行不变式在那里);`null` = 没写归因。
|
|
138
|
+
*/
|
|
139
|
+
endingCause: string | null;
|
|
140
|
+
/**
|
|
141
|
+
* `park_trigger` 列原值 —— **转 park 的触发成因**:这一行为什么被转进投递面。**唯一写者** = 赢下 `STREAM_PENDING → PARKING` 的那一次 `claimTerminal(expire, { cause })`,
|
|
142
|
+
* 此后不再被写(行走到 `PARKED` / `DENIED` / `VOID` 之后它仍在;{@link AskTransitionPatch} 没有这一键)。只经 {@link askRowParkTrigger} 读;`null` = 没写(不带 cause 的转 park)。
|
|
143
|
+
*/
|
|
144
|
+
parkTrigger: string | null;
|
|
136
145
|
/** PARKED 坐标三件。 */
|
|
137
146
|
gateToken: string | null;
|
|
138
147
|
gateBoundCallId: string | null;
|
|
@@ -222,7 +231,9 @@ export interface AskTransitionPatch {
|
|
|
222
231
|
decisionActor?: unknown | null;
|
|
223
232
|
decisionNote?: string | null;
|
|
224
233
|
decidedAtMs?: number | null;
|
|
225
|
-
|
|
234
|
+
/** 终态成因(值域与终局 claim 的 `cause` 同一型 {@link SettleCause};读口按终态成因词表读,且只在 `VOID` / `DENIED` 上作数 —— 别的转移上写了也读成缺席)。
|
|
235
|
+
* 补丁**没有**触发成因那一键:它只由 `claimTerminal(expire, { cause })` 写一次。 */
|
|
236
|
+
endingCause?: SettleCause;
|
|
226
237
|
gateToken?: string | null;
|
|
227
238
|
gateBoundCallId?: string | null;
|
|
228
239
|
gateBoundInputHash?: string | null;
|
|
@@ -330,9 +341,10 @@ export interface ExpireResult {
|
|
|
330
341
|
*/
|
|
331
342
|
export type AskTerminalClaimIntent = "expire" | "cancel" | "refuse";
|
|
332
343
|
/**
|
|
333
|
-
* 终局 claim 的可选实参:`cause` ——
|
|
334
|
-
*
|
|
335
|
-
*
|
|
344
|
+
* 终局 claim 的可选实参:`cause` —— **赢下终局的同一步写进这一行的成因词**,列由意图定({@link claimCauseColumn}):`cancel`(VOID)写 `ending_cause` = 终态成因
|
|
345
|
+
* ({@link SettleCause} 里的 `run_cancelled` / `run_exited`;决断口 410 / 晚答 404 / 跨副本的败方读数读这一列),`expire`(PARKING)写 `park_trigger` = 转 park 的触发成因
|
|
346
|
+
* ({@link ParkTriggerCause}:`ttl_expired` / `broadcast_lost` / `stream_disconnected` / `undeliverable` / `shutdown_before_park`;跨副本的悬挂腿与败方读数读这一列)。
|
|
347
|
+
* 所以这一行自己记着「为什么」,读面不靠任何进程内的东西;缺席 ⇒ 列保持 NULL(读面缺席即缺席)。
|
|
336
348
|
* `refuse` 不读它(落的是一条决议,来源位 `policy`,不是结局成因);`expire` 撤兄弟时店自己写 `batch_sibling_withdrawn`(那是这条事务本身的事实)。
|
|
337
349
|
*/
|
|
338
350
|
export interface AskTerminalClaimOpts {
|
|
@@ -348,6 +360,11 @@ export declare const POLICY_REFUSAL_DECISION: {
|
|
|
348
360
|
readonly decision: "deny";
|
|
349
361
|
readonly settledBy: Extract<HostSettledBy, "policy">;
|
|
350
362
|
};
|
|
363
|
+
/**
|
|
364
|
+
* 带成因的终局 claim 把成因写进哪一列(穷举 switch:意图闭集加一个词 ⇒ 这里编译期先红)。一列一义:`cancel` 赢下的是终态(`ending_cause`),
|
|
365
|
+
* `expire` 赢下的是转 park(`park_trigger`);`refuse` 落的是一条决议,不带成因(不进本表)。SQL 两孪生读这一只;内存孪生的两臂各自落同一格(`transitionAsk` 的补丁 / `expireAsk`)。
|
|
366
|
+
*/
|
|
367
|
+
export declare function claimCauseColumn(intent: Exclude<AskTerminalClaimIntent, "refuse">): "ending_cause" | "park_trigger";
|
|
351
368
|
/** 终局 claim 意图 → 本次 CAS 的目标态(穷举 switch:意图闭集加一个词 ⇒ 这里编译期先红)。 */
|
|
352
369
|
export declare function claimTargetState(intent: AskTerminalClaimIntent): AskState;
|
|
353
370
|
/**
|
|
@@ -374,10 +391,11 @@ export type AskTerminalClaimCurrent = {
|
|
|
374
391
|
/** [ref]:赢家决议的**结算来源**(语义与两态读法见 {@link AskRow.settledBy})。**必填**(不是可选)——
|
|
375
392
|
* 可选会让投影漏挑这一列时静默编译过,而漏挑的后果恰是本批要修的病:CAS 输家把赢家的策略拒读成人拒。 */
|
|
376
393
|
settledBy: HostSettledBy | null;
|
|
377
|
-
/**
|
|
378
|
-
*
|
|
379
|
-
|
|
380
|
-
|
|
394
|
+
/** 行上记着的终态成因(`ending_cause` 列,经唯一读口 `askRowEndingCause` 读出)。**只在读得出时在场**(没写 / 与 state 不配 ⇒ 缺席;DECIDED 的败方读数逐字不变)。
|
|
395
|
+
* CAS 输家据它按**行上那个成因**结算(而不是把别人撤的卡读成一次拒绝);投影的唯一函数是 {@link projectAskTerminalClaimTruth},三 twin 不各自挑列,原始列值不出店层。 */
|
|
396
|
+
endingCause?: AskRowEndingCause;
|
|
397
|
+
/** 行上记着的转 park 触发成因(`park_trigger` 列,经唯一读口 `askRowParkTrigger` 读出;行走过 PARKING 才可能在场)。在场律同 {@link endingCause}。 */
|
|
398
|
+
parkTrigger?: ParkTriggerCause;
|
|
381
399
|
};
|
|
382
400
|
/**
|
|
383
401
|
* 单次原子往返的答案(语义律的唯一规范陈述点 = core `checkpoint-store.ts` `claimTerminal` 契约 JSDoc,
|
|
@@ -578,6 +596,20 @@ export declare const APPROVAL_ASK_EXECUTION_LANE_COLUMN: {
|
|
|
578
596
|
readonly mysql: "execution_lane VARCHAR(32) NOT NULL DEFAULT ''";
|
|
579
597
|
readonly pg: "execution_lane VARCHAR(32) COLLATE \"C\" NOT NULL DEFAULT ''";
|
|
580
598
|
};
|
|
599
|
+
/**
|
|
600
|
+
* 问行两列成因的列定义(两方言;唯一属主 —— 建表 DDL 内联它们,存量库的改名 / 加列只由一次性迁移做,那一步也读这里:窗口见 `plugins/one-time-migrations.ts` 登记表 M34)。
|
|
601
|
+
* 宽度 64 = 成因闭集里最长的词有余(钉在 `test/approval-reconciler.test.ts`)。语义见 {@link AskRow.endingCause} / {@link AskRow.parkTrigger}。
|
|
602
|
+
*/
|
|
603
|
+
export declare const APPROVAL_ASK_ENDING_CAUSE_COLUMN: {
|
|
604
|
+
readonly name: "ending_cause";
|
|
605
|
+
readonly mysql: "ending_cause VARCHAR(64) NULL";
|
|
606
|
+
readonly pg: "ending_cause VARCHAR(64) COLLATE \"C\"";
|
|
607
|
+
};
|
|
608
|
+
export declare const APPROVAL_ASK_PARK_TRIGGER_COLUMN: {
|
|
609
|
+
readonly name: "park_trigger";
|
|
610
|
+
readonly mysql: "park_trigger VARCHAR(64) NULL";
|
|
611
|
+
readonly pg: "park_trigger VARCHAR(64) COLLATE \"C\"";
|
|
612
|
+
};
|
|
581
613
|
export declare const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
582
614
|
/**
|
|
583
615
|
* TiDB/MySQL-protocol 侧的两条建表语句,**抽成导出数组**(车3 刀 3a):`tidb-pool.ts` 的
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mysqlDriver, pgDriver, dialectJsonEncoder } from "./sql-driver.js";
|
|
2
2
|
import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
|
|
3
|
-
import { APPROVAL_ENDING_CAUSES,
|
|
3
|
+
import { APPROVAL_ENDING_CAUSES, askRowEndingCause, askRowParkTrigger } from "../approval-deny-reasons.js";
|
|
4
4
|
import { isDupKeyError, isMissingColumnError } from "./sql-errors.js";
|
|
5
5
|
import { describeProbedTableDrift } from "./schema-drift-sentence.js";
|
|
6
6
|
import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, readTriStateJsonValueColumn } from "./sql-json-column.js";
|
|
@@ -61,6 +61,18 @@ async function withReadSignal(op, signal, where) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
export const POLICY_REFUSAL_DECISION = { decision: "deny", settledBy: "policy" };
|
|
64
|
+
export function claimCauseColumn(intent) {
|
|
65
|
+
switch (intent) {
|
|
66
|
+
case "cancel":
|
|
67
|
+
return "ending_cause";
|
|
68
|
+
case "expire":
|
|
69
|
+
return "park_trigger";
|
|
70
|
+
default: {
|
|
71
|
+
const unreachable = intent;
|
|
72
|
+
throw new Error(`approval-ask-store: no cause column for terminal claim intent ${String(unreachable)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
64
76
|
export function claimTargetState(intent) {
|
|
65
77
|
switch (intent) {
|
|
66
78
|
case "expire":
|
|
@@ -78,14 +90,16 @@ export function claimTargetState(intent) {
|
|
|
78
90
|
export function projectAskTerminalClaimTruth(row) {
|
|
79
91
|
if (row === null || row.state === "STREAM_PENDING")
|
|
80
92
|
return { state: "absent" };
|
|
81
|
-
const
|
|
93
|
+
const endingCause = askRowEndingCause(row);
|
|
94
|
+
const parkTrigger = askRowParkTrigger(row);
|
|
82
95
|
return {
|
|
83
96
|
state: row.state,
|
|
84
97
|
rev: row.rev,
|
|
85
98
|
decision: row.decision,
|
|
86
99
|
...(row.updatedInput !== undefined ? { updatedInput: row.updatedInput } : {}),
|
|
87
100
|
settledBy: row.settledBy,
|
|
88
|
-
...(
|
|
101
|
+
...(endingCause !== undefined ? { endingCause } : {}),
|
|
102
|
+
...(parkTrigger !== undefined ? { parkTrigger } : {}),
|
|
89
103
|
};
|
|
90
104
|
}
|
|
91
105
|
export function askRowOnCall(row, call) {
|
|
@@ -105,6 +119,16 @@ export const APPROVAL_ASK_EXECUTION_LANE_COLUMN = {
|
|
|
105
119
|
mysql: "execution_lane VARCHAR(32) NOT NULL DEFAULT ''",
|
|
106
120
|
pg: `execution_lane VARCHAR(32) COLLATE "C" NOT NULL DEFAULT ''`,
|
|
107
121
|
};
|
|
122
|
+
export const APPROVAL_ASK_ENDING_CAUSE_COLUMN = {
|
|
123
|
+
name: "ending_cause",
|
|
124
|
+
mysql: "ending_cause VARCHAR(64) NULL",
|
|
125
|
+
pg: `ending_cause VARCHAR(64) COLLATE "C"`,
|
|
126
|
+
};
|
|
127
|
+
export const APPROVAL_ASK_PARK_TRIGGER_COLUMN = {
|
|
128
|
+
name: "park_trigger",
|
|
129
|
+
mysql: "park_trigger VARCHAR(64) NULL",
|
|
130
|
+
pg: `park_trigger VARCHAR(64) COLLATE "C"`,
|
|
131
|
+
};
|
|
108
132
|
function executionLaneColumnOf(raw, askId) {
|
|
109
133
|
const lane = typeof raw === "string" ? raw : "";
|
|
110
134
|
if (!isExecutionLane(lane)) {
|
|
@@ -163,7 +187,10 @@ export const TIDB_APPROVAL_ASK_STATEMENTS = [
|
|
|
163
187
|
-- 编辑实参是整只工具入参,VARCHAR/TEXT 会造静默截断面。语义三态与读法见 AskRow.updatedInput 顶注。
|
|
164
188
|
updated_input LONGTEXT NULL,
|
|
165
189
|
decided_at_ms BIGINT NULL,
|
|
166
|
-
|
|
190
|
+
-- 成因两列,一列一义(语义见 AskRow.endingCause / AskRow.parkTrigger):ending_cause = 终态成因(到 VOID / DENIED 的转移写);
|
|
191
|
+
-- park_trigger = 转 park 的触发成因(只由 expire claim 写一次,终态不覆盖)。
|
|
192
|
+
${APPROVAL_ASK_ENDING_CAUSE_COLUMN.mysql},
|
|
193
|
+
${APPROVAL_ASK_PARK_TRIGGER_COLUMN.mysql},
|
|
167
194
|
gate_token VARCHAR(120) NULL,
|
|
168
195
|
gate_bound_call_id VARCHAR(255) NULL,
|
|
169
196
|
gate_bound_input_hash VARCHAR(255) NULL,
|
|
@@ -244,7 +271,9 @@ export async function ensurePgApprovalAskSchema(q) {
|
|
|
244
271
|
-- updated_input(S-26 / #304)—— MySQL 孪生逐字同形(语义/类型理由见那侧行内注;PG TEXT 无长度上限)。
|
|
245
272
|
updated_input TEXT COLLATE "C",
|
|
246
273
|
decided_at_ms BIGINT,
|
|
247
|
-
|
|
274
|
+
-- 成因两列 —— MySQL 孪生逐字同形(语义见那侧行内注)。
|
|
275
|
+
${APPROVAL_ASK_ENDING_CAUSE_COLUMN.pg},
|
|
276
|
+
${APPROVAL_ASK_PARK_TRIGGER_COLUMN.pg},
|
|
248
277
|
gate_token VARCHAR(120) COLLATE "C",
|
|
249
278
|
gate_bound_call_id VARCHAR(255) COLLATE "C",
|
|
250
279
|
gate_bound_input_hash VARCHAR(255) COLLATE "C",
|
|
@@ -290,7 +319,7 @@ function askCols(dialect) {
|
|
|
290
319
|
jsonColumnText(dialect, "decision_actor"),
|
|
291
320
|
"decision_note, settled_by",
|
|
292
321
|
jsonColumnText(dialect, "updated_input"),
|
|
293
|
-
"decided_at_ms,
|
|
322
|
+
"decided_at_ms, ending_cause, park_trigger, gate_token",
|
|
294
323
|
"gate_bound_call_id, gate_bound_input_hash, idempotency_key",
|
|
295
324
|
jsonColumnText(dialect, "card_json"),
|
|
296
325
|
"rule_command, rule_scope_root, schema_version, expires_at_ms",
|
|
@@ -338,7 +367,8 @@ function mapAskRowBody(r, askId) {
|
|
|
338
367
|
settledBy: strOrNull(r.settled_by),
|
|
339
368
|
...(r.updated_input == null ? {} : { updatedInput: decodeJsonColumn(r.updated_input, readTriStateJsonValueColumn, `${APPROVAL_ASK_TABLE}.updated_input for ask ${askId}`) }),
|
|
340
369
|
decidedAtMs: numOrNull(r.decided_at_ms),
|
|
341
|
-
|
|
370
|
+
endingCause: strOrNull(r.ending_cause),
|
|
371
|
+
parkTrigger: strOrNull(r.park_trigger),
|
|
342
372
|
gateToken: strOrNull(r.gate_token),
|
|
343
373
|
gateBoundCallId: strOrNull(r.gate_bound_call_id),
|
|
344
374
|
gateBoundInputHash: strOrNull(r.gate_bound_input_hash),
|
|
@@ -373,8 +403,8 @@ function patchColumns(patch, json) {
|
|
|
373
403
|
out.push(["decision_note", patch.decisionNote]);
|
|
374
404
|
if (patch.decidedAtMs !== undefined)
|
|
375
405
|
out.push(["decided_at_ms", patch.decidedAtMs]);
|
|
376
|
-
if (patch.
|
|
377
|
-
out.push(["
|
|
406
|
+
if (patch.endingCause !== undefined)
|
|
407
|
+
out.push(["ending_cause", patch.endingCause]);
|
|
378
408
|
if (patch.gateToken !== undefined)
|
|
379
409
|
out.push(["gate_token", patch.gateToken]);
|
|
380
410
|
if (patch.gateBoundCallId !== undefined)
|
|
@@ -427,9 +457,9 @@ export class SqlApprovalAskStore {
|
|
|
427
457
|
try {
|
|
428
458
|
await conn.begin();
|
|
429
459
|
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]);
|
|
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,
|
|
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,
|
|
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"), [
|
|
460
|
+
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, ending_cause, park_trigger, 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) ` +
|
|
461
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'STREAM_PENDING', 0, 0, NULL, 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, ending_cause, park_trigger, 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) ` +
|
|
462
|
+
"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, NULL, $12, $13, $14, $15, $16, $17, $18) ON CONFLICT (ask_id) DO NOTHING"), [
|
|
433
463
|
row.askId,
|
|
434
464
|
row.taskId,
|
|
435
465
|
row.sourceTaskId,
|
|
@@ -566,7 +596,7 @@ export class SqlApprovalAskStore {
|
|
|
566
596
|
? await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, decision = ${ph(dialect, 2)}, settled_by = ${ph(dialect, 3)}, decided_at_ms = ${ph(dialect, 4)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 5)} WHERE ${pendingClaimWhere(dialect, 6)}`, [to, POLICY_REFUSAL_DECISION.decision, POLICY_REFUSAL_DECISION.settledBy, now, now, askId, batchId])
|
|
567
597
|
: (intent === "cancel" || intent === "expire") && opts?.cause !== undefined
|
|
568
598
|
?
|
|
569
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)},
|
|
599
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, ${claimCauseColumn(intent)} = ${ph(dialect, 2)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 3)} WHERE ${pendingClaimWhere(dialect, 4)}`, [to, opts.cause, now, askId, batchId])
|
|
570
600
|
: await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 2)} WHERE ${pendingClaimWhere(dialect, 3)}`, [
|
|
571
601
|
to,
|
|
572
602
|
now,
|
|
@@ -585,7 +615,7 @@ export class SqlApprovalAskStore {
|
|
|
585
615
|
await conn.query(this.q(`UPDATE ${APPROVAL_BATCH_TABLE} SET state='ROUTING_UNBOUND', rev=rev+1, updated_at_ms=? WHERE batch_id=? AND state='OPEN'`, `UPDATE ${APPROVAL_BATCH_TABLE} SET state='ROUTING_UNBOUND', rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='OPEN'`), [now, batchId]);
|
|
586
616
|
let voidedSiblings;
|
|
587
617
|
if (this.db.dialect === "pg") {
|
|
588
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
618
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=$4, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId, APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN]);
|
|
589
619
|
voidedSiblings = res.rows.map((r) => String(r.ask_id));
|
|
590
620
|
}
|
|
591
621
|
else {
|
|
@@ -593,7 +623,7 @@ export class SqlApprovalAskStore {
|
|
|
593
623
|
voidedSiblings = sel.rows.map((r) => String(r.ask_id));
|
|
594
624
|
if (voidedSiblings.length > 0) {
|
|
595
625
|
const inList = voidedSiblings.map(() => "?").join(", ");
|
|
596
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
626
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [
|
|
597
627
|
APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN,
|
|
598
628
|
now,
|
|
599
629
|
...voidedSiblings,
|
|
@@ -639,7 +669,7 @@ export class SqlApprovalAskStore {
|
|
|
639
669
|
}
|
|
640
670
|
let voidedSiblings;
|
|
641
671
|
if (this.db.dialect === "pg") {
|
|
642
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
672
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=$4, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='PARKING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId, APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE]);
|
|
643
673
|
voidedSiblings = res.rows.map((r) => String(r.ask_id));
|
|
644
674
|
}
|
|
645
675
|
else {
|
|
@@ -647,7 +677,7 @@ export class SqlApprovalAskStore {
|
|
|
647
677
|
voidedSiblings = sel.rows.map((r) => String(r.ask_id));
|
|
648
678
|
if (voidedSiblings.length > 0) {
|
|
649
679
|
const inList = voidedSiblings.map(() => "?").join(", ");
|
|
650
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
680
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='PARKING'`, [APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE, now, ...voidedSiblings]);
|
|
651
681
|
}
|
|
652
682
|
}
|
|
653
683
|
await conn.commit();
|
|
@@ -677,7 +707,7 @@ export class SqlApprovalAskStore {
|
|
|
677
707
|
}
|
|
678
708
|
let voided;
|
|
679
709
|
if (this.db.dialect === "pg") {
|
|
680
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
710
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=$3, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' RETURNING ask_id`, [now, batchId, APPROVAL_ENDING_CAUSES.BATCH_ABORTED]);
|
|
681
711
|
voided = res.rows.map((r) => String(r.ask_id));
|
|
682
712
|
}
|
|
683
713
|
else {
|
|
@@ -685,7 +715,7 @@ export class SqlApprovalAskStore {
|
|
|
685
715
|
voided = sel.rows.map((r) => String(r.ask_id));
|
|
686
716
|
if (voided.length > 0) {
|
|
687
717
|
const inList = voided.map(() => "?").join(", ");
|
|
688
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID',
|
|
718
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', ending_cause=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [APPROVAL_ENDING_CAUSES.BATCH_ABORTED, now, ...voided]);
|
|
689
719
|
}
|
|
690
720
|
}
|
|
691
721
|
await conn.commit();
|
|
@@ -142,6 +142,12 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
142
142
|
* 只读快照而非 getter:声明是店的构造期常量(会变的声明本身就是缺陷)。
|
|
143
143
|
*/
|
|
144
144
|
readonly placements?: SessionStore["placements"];
|
|
145
|
+
/**
|
|
146
|
+
* 内层店的**会话耐久声明**(core `SessionStore.durability`,说的是未 placed 的会话)转发 —— 与 {@link retention} / {@link placements} 同一族教训:
|
|
147
|
+
* 生产默认把真店包进本类,core 的接线清单(`wiring_manifest.session.store`)与停驻自检读的就是包装层;不转发 = 一只声明了 `durable` 的店在默认部署上
|
|
148
|
+
* 读成 `process_local`(core 对缺席的 fail-closed 读法),没有任何一处报错。只读快照;缺席则不设。
|
|
149
|
+
*/
|
|
150
|
+
readonly durability?: SessionStore["durability"];
|
|
145
151
|
/** [ref]:placed 分区的两只读面(reap 分区腿 / 准入探针)——同款转发理由:reaper 与准入判据拿到的
|
|
146
152
|
* 是包装层,不转发 = 分区腿静默不可用、暖命中的 claim 关门静默失效。缺席则不设(诚实降级)。 */
|
|
147
153
|
readonly listPlaced?: (kind: "subagent", opts?: {
|
|
@@ -33,6 +33,7 @@ export class CachingSessionStore {
|
|
|
33
33
|
replaceEntries;
|
|
34
34
|
retention;
|
|
35
35
|
placements;
|
|
36
|
+
durability;
|
|
36
37
|
listPlaced;
|
|
37
38
|
placementOf;
|
|
38
39
|
constructor(inner, opts) {
|
|
@@ -43,6 +44,8 @@ export class CachingSessionStore {
|
|
|
43
44
|
const declared = inner.retention;
|
|
44
45
|
if (declared !== undefined)
|
|
45
46
|
this.retention = declared;
|
|
47
|
+
if (inner.durability !== undefined)
|
|
48
|
+
this.durability = inner.durability;
|
|
46
49
|
if (inner.placements !== undefined)
|
|
47
50
|
this.placements = inner.placements;
|
|
48
51
|
if (typeof inner.listPlaced === "function")
|
|
@@ -2,7 +2,10 @@ import type { Pool as MySqlPool } from "mysql2/promise";
|
|
|
2
2
|
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
|
+
import type { KindlessBatchRowSource, KindlessBatchScan } from "../approval-batch-census.js";
|
|
5
6
|
import { type SqlDialect, type SqlDriver } from "./sql-driver.js";
|
|
7
|
+
import type { SqlRunStore } from "./run-store-sql.js";
|
|
8
|
+
import type { FencedRun } from "./store-contracts.js";
|
|
6
9
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
7
10
|
import type { SealedCheckpointCtx } from "../http/checkpoint-ctx.js";
|
|
8
11
|
/** ctx 行改写店腿的读数(两孪生同形):扫到的可读行 · 回写成的行 · 回写成的行里改写函数报的改动数 · 读不出的行 · 改写之后一行装不下的行。 */
|
|
@@ -59,7 +62,8 @@ export declare function tokenFingerprint(token: string): string;
|
|
|
59
62
|
* 型与值都只有一个来源:`approval-card.ts` 的 {@link parkRowFacts}(两只店各读自己手里的那只寄存行 `pendingAction`,
|
|
60
63
|
* 交给它、原样展开)。继承而不是在这里逐键再写一遍:core 给这一臂再加一位同类事实时,改的只有那张 Pick 表。
|
|
61
64
|
*
|
|
62
|
-
*
|
|
65
|
+
* [ref]:授予绑定那一臂(`boundGrantDigest` / `boundGrantAbsence` 恰带其一)是 {@link ParkRowFacts} 的一部分,同样读自寄存行。
|
|
66
|
+
* 技能卡两位({@link SkillCardFacts}:`boundGrants` / `classifierNoRuling`)另有一只投影 {@link skillCardFacts},输入是 core 的检查点摘要而不是
|
|
63
67
|
* 寄存行原值(清单只在哈希等于摘要时才配上 wire,校验点单点在 core —— 见 {@link skillCardFacts} 顶注);同一张行上与收件箱行逐字同值,在场才带。 */
|
|
64
68
|
export interface PendingCheckpoint extends ParkRowFacts, SkillCardFacts {
|
|
65
69
|
sessionId: string;
|
|
@@ -271,6 +275,12 @@ export declare const CHECKPOINT_ADDED_COLUMNS: ReadonlyArray<{
|
|
|
271
275
|
export declare function assertCheckpointColumnSchema(query: (sql: string) => Promise<{
|
|
272
276
|
rows: Record<string, unknown>[];
|
|
273
277
|
}>, dialect: SqlDialect): Promise<void>;
|
|
278
|
+
/**
|
|
279
|
+
* 本店读者({@link boundedRuleOffers})**交给 core 读者的那份输入**:offer 扫描窗 {@link MAX_RULE_OFFER_SCAN} 与成员前缀帽({@link preboundBatchMembers})都扣在读之前,
|
|
280
|
+
* 不是列表的值原样透传。**唯一写法**:回读 / 铸行 / LOCAL 孪生三条腿与起服普查({@link SqlCheckpointStore.scanKindlessBatchRows} 的 `rule_suggestions` 载体)读同一份输入 ——
|
|
281
|
+
* 普查若对整只数组另判,「前 8 个成员合法、第 9 个是垃圾」的行本店读者读得出(走存量臂)而普查读不出,会把仍靠存量臂的行报成零。
|
|
282
|
+
*/
|
|
283
|
+
export declare function boundedReaderInput(raw: unknown): unknown;
|
|
274
284
|
/**
|
|
275
285
|
* `pendingAction.ruleOffers` 的**铸行侧**投影(mint 面,与 {@link boundedToolInput} 同位同待遇)。
|
|
276
286
|
*
|
|
@@ -460,8 +470,17 @@ interface SteerColumnRead {
|
|
|
460
470
|
* 列有内容却读不出 ⇒ `lossy`(两个调用点对它的处置见 {@link SteerColumnRead})。
|
|
461
471
|
*/
|
|
462
472
|
export declare function readPendingSteerQueueColumn(queueRaw: unknown): SteerColumnRead;
|
|
473
|
+
/** 认领栅栏下改写一行 ctx 的结局(闭集;SQL / local 两孪生同词):`written` 写了;`claim_released` 接下改写的那条腿此刻已不持有这条 run(认领放了 / 不在跑 / 腿判据答否)⇒ 零写;
|
|
474
|
+
* `context_absent` 持有、但会话没有 ctx 行 ⇒ 零写(不建行)。 */
|
|
475
|
+
export declare const CTX_CLAIM_REWRITES: readonly ["written", "claim_released", "context_absent"];
|
|
476
|
+
export type CtxClaimRewrite = (typeof CTX_CLAIM_REWRITES)[number];
|
|
477
|
+
/** SQL checkpoint 店的装配选项:托管留存声明 + ctx 改写的认领栅栏(同一只池上的 run 店)。 */
|
|
478
|
+
export interface SqlCheckpointStoreOptions {
|
|
479
|
+
readonly retention?: RetentionDeclaration;
|
|
480
|
+
readonly claims?: SqlRunStore;
|
|
481
|
+
}
|
|
463
482
|
/** Dual-dialect durable CheckpointStore. See the file header for the dialect-delta ledger. */
|
|
464
|
-
export declare class SqlCheckpointStore implements CheckpointStore {
|
|
483
|
+
export declare class SqlCheckpointStore implements CheckpointStore, KindlessBatchRowSource {
|
|
465
484
|
protected readonly db: SqlDriver;
|
|
466
485
|
protected readonly logger?: {
|
|
467
486
|
info?(msg: string, meta?: unknown): void;
|
|
@@ -514,11 +533,12 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
514
533
|
readonly execution: {
|
|
515
534
|
readonly outcome: true;
|
|
516
535
|
};
|
|
536
|
+
/** ctx 改写的认领栅栏({@link SqlCheckpointStore.rewriteCtxWhileClaimed}):后端装配绑**同一只池**上的 run 店(`plugins/store-backend.ts` 的 `checkpoint()`)。
|
|
537
|
+
* 缺席 ⇒ 那一口响亮抛(装配缺陷),其余口不读它。 */
|
|
538
|
+
private readonly claims;
|
|
517
539
|
constructor(db: SqlDriver, logger?: {
|
|
518
540
|
info?(msg: string, meta?: unknown): void;
|
|
519
|
-
} | undefined, opts?:
|
|
520
|
-
readonly retention?: RetentionDeclaration;
|
|
521
|
-
});
|
|
541
|
+
} | undefined, opts?: SqlCheckpointStoreOptions);
|
|
522
542
|
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
523
543
|
private q;
|
|
524
544
|
/** JSON column binding. TiDB: plain `JSON.stringify`, stored verbatim. PG: `pgProtocolJsonStringify` —
|
|
@@ -691,18 +711,19 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
691
711
|
*/
|
|
692
712
|
listPending(scope?: string): Promise<PendingCheckpoint[]>;
|
|
693
713
|
/**
|
|
694
|
-
* 🔴 [ref] ——
|
|
714
|
+
* 🔴 [ref] —— 运维队列行的**技能卡两位**({@link SkillCardFacts}:清单 / 成因词)。值与收件箱行同源:core `summarizeCheckpoint` 对同一行投的摘要,经 {@link skillCardFacts} 这一只投影。
|
|
715
|
+
* (授予绑定那一臂 —— 摘要 / 缺席词 —— 不在这里:[ref] 起由 {@link parkRowFacts} 读子树投出,本读口失败时它照在。)
|
|
695
716
|
*
|
|
696
|
-
* 为什么不像 {@link parkRowFacts} 那几位一样直接读 `pendingAction`
|
|
717
|
+
* 为什么不像 {@link parkRowFacts} 那几位一样直接读 `pendingAction` 子树原值:**清单** `boundGrants` 在寄存行上是未经哈希校验的原值,core 只在摘要里「哈希等于摘要」
|
|
697
718
|
* 才发布它(「never a list beside a digest that binds another」);校验读口与哈希函数都不在 core 的公开导出面上,本仓既算不出也不该再写一份 ——
|
|
698
719
|
* 于是要拿到校验过的清单,只有对这一行跑 core 的 `summarizeCheckpoint`,而它吃的是整只 {@link Checkpoint}(不是子树)。
|
|
699
720
|
*
|
|
700
|
-
* 读放大(如实)
|
|
701
|
-
* 主 SELECT 仍只取 `pendingAction` 子树(NP-3 不退)
|
|
702
|
-
* 🚧 清单校验读口成为 core
|
|
721
|
+
* 读放大(如实):**只对行上可能带两位之一的行**(摘要是串,或成因词键在场 —— {@link parkRowCarriesSkillCardFacts})多读该行一次整只快照;普通卡(绝大多数行)零额外读,
|
|
722
|
+
* 主 SELECT 仍只取 `pendingAction` 子树(NP-3 不退)。这是一个**只增不改的代价**:带两位之一的待决行数 × 读次数(`/stream` 每连接每 3s 一拍)。
|
|
723
|
+
* 🚧 清单校验读口成为 core 公开导出的那一版,本读口与门一并退役,两位改走 `parkRowFacts` 读原值经 core 的读口 —— 零额外读。
|
|
703
724
|
*
|
|
704
725
|
* 失败方向与 {@link readParkRowActionCell} 逐字同一条判据(展示/分诊材料、行级容忍 + 响亮、同一个 tag):整只快照在场却不是一只合法的检查点(读回的体坏了,或 core 的摘要读不动它)
|
|
705
|
-
* ⇒
|
|
726
|
+
* ⇒ 只丢**这一行**的两位(授予绑定那一臂照在);行已不在待决(两次读之间被决/过期)⇒ 两位缺席;`not-text`(读腿漏了投影)原样抛。
|
|
706
727
|
*/
|
|
707
728
|
private readParkedSkillCardFacts;
|
|
708
729
|
/**
|
|
@@ -836,6 +857,23 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
836
857
|
* reader the read leg uses — BEFORE the statement runs: refuse loudly, leave the row on disk untouched. */
|
|
837
858
|
putCtx(sessionId: string, ctx: SealedCheckpointCtx): Promise<void>;
|
|
838
859
|
getCtx<T extends object = object>(sessionId: string): Promise<T | null>;
|
|
860
|
+
/**
|
|
861
|
+
* **认领栅栏下改写既有 ctx 行** —— 在飞 run 的切档口(`http/routes/run-permission-mode.ts`)把准入的模式词写回存储体的唯一写口。
|
|
862
|
+
*
|
|
863
|
+
* 规则:只有**接下这笔改写的那条腿**此刻仍持有这条 run 时才写 —— `taskId` 持有 `sessionId` 的会话认领、这条 run 在跑、且调用方的腿判据 `legHolds`
|
|
864
|
+
* 对锁住那一行的 {@link FencedRun} 答是(认领与 `running` 只认 taskId:续跑腿让同一个 taskId 停驻之后回到 `running`、认领仍在,旧腿迟到的改写不许盖掉续跑的新腿
|
|
865
|
+
* 写下的体 —— 那是 ABA,只有腿判据分得开;今天的腿身份 = 副本 `instanceId`(续跑的 CAS 赢点改写它)∧ 调用方进程里这条 run 的活流仍是接下改写的那一只)。
|
|
866
|
+
* 写在所绑 run 店的认领栅栏事务里
|
|
867
|
+
* (`SqlRunStore.whileHoldingClaim`:先锁 run 行、再锁认领行 —— 与终局 / 收割同序 —— 刷新活性,本口的锁读 + UPDATE 在同一个事务连接上)。
|
|
868
|
+
* 于是「这条 run 终局放掉认领 → 同会话新 run 写下它自己的 ctx → 本口迟到的改写」这一序**结构上不可能**盖掉新 run 的行:终局要等本事务提交才拿得到
|
|
869
|
+
* run 行的锁,拿到之后本口再来就判出不持有、一个字节都不写。`putCtx` 的无条件 upsert 只给持有认领的那几条腿自己的写点(提交 / 续跑 CAS 赢点)用;
|
|
870
|
+
* 不在腿里的写者走这一口。
|
|
871
|
+
* 只改**既有**行(锁读零行 ⇒ `context_absent`,不建行):切档改的是这条 run 提交时写下的那一行,没有那一行就没有要改的存储体。
|
|
872
|
+
* 结局闭集 {@link CtxClaimRewrite}:`written` / `claim_released`(接下改写的那条腿已不持有这条 run —— 认领放了 / 不在跑 / 腿判据答否:零写)/ `context_absent`(持有、无行:零写)。
|
|
873
|
+
* 腿判据在栅栏里同步问一次(锁已持有、写之前);它只读、不许 await。
|
|
874
|
+
* 编码与形闸同 {@link SqlCheckpointStore.putCtx}(写之前判,坏形响亮拒、盘上不动);一行装不下 ⇒ `StoreRowTooLargeError`。
|
|
875
|
+
*/
|
|
876
|
+
rewriteCtxWhileClaimed(sessionId: string, taskId: string, ctx: SealedCheckpointCtx, legHolds: (run: FencedRun) => boolean): Promise<CtxClaimRewrite>;
|
|
839
877
|
/**
|
|
840
878
|
* 🔴 **一次性迁移的 ctx 行改写店腿**({@link CheckpointCtxRowsRewriter};用它的迁移与各自的行改写见那里,窗与删法见 `plugins/one-time-migrations.ts` 登记表;
|
|
841
879
|
* 本店不知道改写是什么,只负责扫与回写):按 `session_id` 键集分页扫 `checkpoint_ctx`
|
|
@@ -845,6 +883,20 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
845
883
|
* ⇒ 不计、不重试(新写者是本版写下的、已是新形;是旧版副本就由之后的起服再扫到)。一行装不下(如封签比明文长)⇒ 计 `tooLarge`、那一行留原样,其余照扫。
|
|
846
884
|
*/
|
|
847
885
|
rewriteCtxRows(rewrite: CtxRowRewrite): Promise<CtxRowsRewrite>;
|
|
886
|
+
/**
|
|
887
|
+
* 起服普查的读口({@link KindlessBatchRowSource};用法、范围与『为什么只数不改』见 `approval-batch-census.ts` 头注)—— 两个 SQL 方言**同一份实现**:
|
|
888
|
+
* 按 `token` 键集分页扫 `checkpoint`(所有状态的行),取两个载体,**各按它的读者判**(判官都是 core `readRuleOffers` 给读出的 batch 打的 `kindlessForm` 记号,
|
|
889
|
+
* {@link countKindlessBatchOffers};一行里任一载体带旧形成员即算一行):
|
|
890
|
+
* · `rule_suggestions` 列(审批候选的落列)—— 读者是本店的回读口,吃的是 {@link boundedReaderInput}(扫描窗 + 成员前缀帽);普查读同一份输入;
|
|
891
|
+
* · blob 里 `pendingAction.ruleOffers`(引擎铸、本店原样存、`put` 不校验)—— 读者是引擎(整只数组,没有本店的窗),普查读整只数组;在场却不是列表 ⇒ 数进 `unreadableCells`。
|
|
892
|
+
* 预筛(只为省传输,**不是判官**):`rule_suggestions` 是原样存的 TEXT(转义写法可以不同于 `JSON.stringify`),所以只问 `IS NOT NULL`,不做字符串匹配;
|
|
893
|
+
* blob 是 JSON 承载列(MySQL 协议 JSON / PG jsonb 入库即规范化),它的 `pendingAction` 子树文本里一个字符串值 `batch` 恒以 `"batch"` 字面出现 ⇒ `LIKE '%"batch"%'` 对它是完备的
|
|
894
|
+
* (空白不同无妨:MySQL 协议 `"kind": "batch"`)。
|
|
895
|
+
* 读不出形的 cell(坏 JSON / 不是列该有的形;读口是 {@link decodeNullableJsonColumn} 同一只,只容忍「体」的问题,读腿漏投影的 `not-text` 原样抛)不计入行,
|
|
896
|
+
* 数进 `unreadableCells`(到不了读者,但不静默:`rule_suggestions` 坏 cell 在队列读面有 `server.approvals.rule-suggestions-cell-unreadable`,普查另出 warn)。
|
|
897
|
+
* 行指纹 = {@link tokenFingerprint}(token 是机密,永不进遥测)。**只读**:不改任何一行;逐页读、**不是原子快照**(页间别的副本的写入可以让一行被漏数或多数一行)。
|
|
898
|
+
*/
|
|
899
|
+
scanKindlessBatchRows(): Promise<KindlessBatchScan>;
|
|
848
900
|
/**
|
|
849
901
|
* GC ctx rows whose lifecycle is over (bound to the checkpoint, don't leak):
|
|
850
902
|
* a session with NO pending checkpoint, NO active run, AND not touched since `cutoff`.
|
|
@@ -883,16 +935,12 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
883
935
|
export declare class TiDBCheckpointStore extends SqlCheckpointStore {
|
|
884
936
|
constructor(pool: MySqlPool, logger?: {
|
|
885
937
|
info?(msg: string, meta?: unknown): void;
|
|
886
|
-
}, opts?:
|
|
887
|
-
readonly retention?: RetentionDeclaration;
|
|
888
|
-
});
|
|
938
|
+
}, opts?: SqlCheckpointStoreOptions);
|
|
889
939
|
}
|
|
890
940
|
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
891
941
|
export declare class PgCheckpointStore extends SqlCheckpointStore {
|
|
892
942
|
constructor(pool: PgPool, logger?: {
|
|
893
943
|
info?(msg: string, meta?: unknown): void;
|
|
894
|
-
}, opts?:
|
|
895
|
-
readonly retention?: RetentionDeclaration;
|
|
896
|
-
});
|
|
944
|
+
}, opts?: SqlCheckpointStoreOptions);
|
|
897
945
|
}
|
|
898
946
|
//# sourceMappingURL=checkpoint-store-sql.d.ts.map
|