@sema-agent/server 7.148.0 → 7.150.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 +551 -9
- package/README.md +17 -2
- package/README.zh-CN.md +5 -1
- package/USAGE.md +126 -68
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +33 -33
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-leg-origin.d.ts +33 -0
- package/dist/approval-leg-origin.js +4 -0
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +9 -1
- package/dist/auth-bridge.js +4 -4
- package/dist/auth-keys.d.ts +10 -1
- package/dist/auth-keys.js +8 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/execution-env.js +10 -11
- package/dist/boot/execution-lane.d.ts +6 -4
- package/dist/boot/execution-lane.js +3 -1
- package/dist/boot/org-delivery.d.ts +3 -2
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +66 -28
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.js +21 -21
- package/dist/boot/stage-01-config.d.ts +1 -0
- package/dist/boot/stage-01-config.js +4 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +4 -4
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +2 -1
- package/dist/boot/stage-06-runners.js +1 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-10-http-server.d.ts +35 -2
- package/dist/boot/stage-10-http-server.js +9 -4
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +22 -19
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +70 -60
- package/dist/capability-facts.js +45 -49
- package/dist/card-settle-stored-scope.d.ts +56 -0
- package/dist/card-settle-stored-scope.js +27 -0
- package/dist/card-void.d.ts +7 -12
- package/dist/card-void.js +2 -7
- package/dist/config-catalog.d.ts +12 -0
- package/dist/config-catalog.js +37 -33
- package/dist/config-invariants.d.ts +5 -4
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +49 -16
- package/dist/config.d.ts +6 -5
- package/dist/config.js +35 -24
- package/dist/context-window-notice.d.ts +31 -0
- package/dist/context-window-notice.js +28 -0
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +20 -11
- package/dist/deployment-shape.js +1 -0
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +64 -28
- package/dist/device-ws-protocol.d.ts +20 -6
- package/dist/device-ws-protocol.js +9 -2
- package/dist/engine-identity.d.ts +7 -1
- package/dist/engine-identity.js +5 -0
- package/dist/env-name-allowlist-knobs.d.ts +6 -5
- package/dist/env-name-allowlist-knobs.js +5 -0
- package/dist/execution-lane-caps.d.ts +20 -5
- package/dist/execution-lane-caps.js +18 -4
- package/dist/field-conflict.d.ts +2 -2
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/command-spawn.d.ts +7 -2
- package/dist/hooks/command-spawn.js +13 -6
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +11 -7
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +5 -5
- package/dist/http/approval-sweeps.js +5 -3
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +18 -63
- package/dist/http/checkpoint-ctx.js +1 -24
- package/dist/http/claim-heartbeat.d.ts +6 -6
- package/dist/http/claim-heartbeat.js +6 -6
- package/dist/http/claimed-run.d.ts +16 -9
- package/dist/http/claimed-run.js +8 -0
- package/dist/http/dispatch.js +7 -5
- package/dist/http/durable-run-leg.d.ts +8 -1
- package/dist/http/durable-run-leg.js +34 -15
- package/dist/http/execution-context.d.ts +115 -14
- package/dist/http/execution-context.js +130 -40
- package/dist/http/owner-access.d.ts +246 -21
- package/dist/http/owner-access.js +186 -8
- package/dist/http/principal-gate.d.ts +18 -11
- package/dist/http/principal-gate.js +3 -1
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.d.ts +14 -3
- package/dist/http/resume-ctx-read.js +24 -3
- package/dist/http/resume-legs.d.ts +35 -3
- package/dist/http/resume-legs.js +262 -106
- package/dist/http/route-ctx.d.ts +29 -11
- package/dist/http/routes/a2a-serve.js +17 -14
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +11 -11
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -1
- package/dist/http/routes/diagnostics.js +30 -5
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/principal-inbox.d.ts +3 -1
- package/dist/http/routes/principal-inbox.js +3 -2
- package/dist/http/routes/projects.d.ts +1 -0
- package/dist/http/routes/projects.js +5 -3
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +33 -37
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +24 -5
- package/dist/http/routes/session-sync.js +45 -37
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +18 -44
- package/dist/http/routes/tasks.js +136 -101
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +12 -9
- package/dist/http/server.js +35 -6
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +2 -2
- package/dist/http/submit-ctx.js +5 -5
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/leader/endpoint.js +9 -8
- package/dist/leg-facts.d.ts +13 -2
- package/dist/leg-facts.js +2 -0
- package/dist/local-store-declaration.d.ts +54 -0
- package/dist/local-store-declaration.js +59 -0
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/mcp-assertion-header.js +1 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-project-layer.js +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.js +2 -2
- package/dist/model-context-window.d.ts +50 -11
- package/dist/model-context-window.js +20 -1
- package/dist/model-entry-refusal.d.ts +5 -4
- package/dist/model-entry-refusal.js +17 -3
- package/dist/model-reach-scope.d.ts +2 -1
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +19 -7
- package/dist/observability/fail-open.js +19 -7
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/org-delivery-gate.d.ts +31 -6
- package/dist/org-delivery-gate.js +7 -4
- package/dist/owner-faces.d.ts +30 -5
- package/dist/owner-faces.js +2 -0
- package/dist/park-row-commit.d.ts +67 -0
- package/dist/park-row-commit.js +76 -0
- package/dist/parked-decide.d.ts +9 -7
- package/dist/parked-decide.js +25 -6
- package/dist/peer-directory.d.ts +1 -1
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/plugins/adoption-log-sql.d.ts +3 -3
- package/dist/plugins/adoption-log-sql.js +19 -19
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-sql.js +3 -5
- package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
- package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
- package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
- package/dist/plugins/approval-exemption-skill-m46.js +6 -10
- package/dist/plugins/approval-exemption-store.d.ts +26 -1
- package/dist/plugins/approval-exemption-store.js +28 -19
- package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
- package/dist/plugins/ensure-schema-lock-policy.js +75 -9
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/file-run-store.d.ts +22 -9
- package/dist/plugins/file-run-store.js +51 -23
- package/dist/plugins/local-checkpoint-store.d.ts +8 -1
- package/dist/plugins/local-checkpoint-store.js +5 -1
- package/dist/plugins/local-data-root-admission.d.ts +52 -0
- package/dist/plugins/local-data-root-admission.js +100 -0
- package/dist/plugins/local-engine-high-water.d.ts +28 -7
- package/dist/plugins/local-engine-high-water.js +27 -22
- package/dist/plugins/local-session-store.d.ts +134 -49
- package/dist/plugins/local-session-store.js +149 -108
- package/dist/plugins/memory-run-store.d.ts +14 -9
- package/dist/plugins/memory-run-store.js +48 -22
- package/dist/plugins/one-time-migration-marker.d.ts +19 -3
- package/dist/plugins/one-time-migration-marker.js +7 -1
- package/dist/plugins/one-time-migrations.d.ts +110 -59
- package/dist/plugins/one-time-migrations.js +224 -136
- package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
- package/dist/plugins/org-delivery-quota-store.js +29 -14
- package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
- package/dist/plugins/permission-rule-store-sql.js +5 -9
- package/dist/plugins/pg-pool.d.ts +1 -1
- package/dist/plugins/pg-pool.js +14 -12
- package/dist/plugins/posix-shell-fs.js +4 -2
- package/dist/plugins/remote-env-adb.js +3 -2
- package/dist/plugins/remote-env-device.d.ts +3 -2
- package/dist/plugins/remote-env-device.js +8 -6
- package/dist/plugins/remote-env-e2b.d.ts +4 -8
- package/dist/plugins/remote-env-e2b.js +21 -15
- package/dist/plugins/remote-env-host.d.ts +51 -10
- package/dist/plugins/remote-env-host.js +97 -31
- package/dist/plugins/remote-env-k8s.js +7 -4
- package/dist/plugins/remote-env-local-docker.d.ts +6 -3
- package/dist/plugins/remote-env-local-docker.js +11 -25
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/remote-shell.d.ts +3 -1
- package/dist/plugins/remote-shell.js +3 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +27 -8
- package/dist/plugins/run-store-sql.js +46 -18
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +8 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +9 -6
- package/dist/plugins/schema-consistency.d.ts +91 -5
- package/dist/plugins/schema-consistency.js +189 -7
- package/dist/plugins/schema-drift-sentence.d.ts +6 -5
- package/dist/plugins/schema-drift-sentence.js +13 -5
- package/dist/plugins/serving-requirement.d.ts +49 -0
- package/dist/plugins/serving-requirement.js +53 -0
- package/dist/plugins/session-placement.d.ts +5 -4
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +55 -0
- package/dist/plugins/stop-then-start-sentence.js +51 -0
- package/dist/plugins/store-backend.d.ts +23 -9
- package/dist/plugins/store-backend.js +58 -24
- package/dist/plugins/store-contracts.d.ts +45 -5
- package/dist/plugins/store-contracts.js +19 -0
- package/dist/plugins/tidb-pool.d.ts +11 -6
- package/dist/plugins/tidb-pool.js +22 -12
- package/dist/plugins/workspace-custody.d.ts +44 -0
- package/dist/plugins/workspace-custody.js +47 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.js +70 -0
- package/dist/project-identity.d.ts +8 -7
- package/dist/project-identity.js +40 -17
- package/dist/project-layer-key.d.ts +13 -2
- package/dist/project-layer-key.js +9 -1
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/read-deny-floor-notice.d.ts +36 -0
- package/dist/read-deny-floor-notice.js +40 -0
- package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
- package/dist/request-declaration-disposition.js +39 -0
- package/dist/run-cancel-card.d.ts +28 -0
- package/dist/run-cancel-card.js +20 -0
- package/dist/run-cancel-context.d.ts +10 -0
- package/dist/run-cancel-context.js +1 -0
- package/dist/run-local.js +28 -13
- package/dist/runs.d.ts +31 -7
- package/dist/runs.js +34 -16
- package/dist/security.d.ts +3 -3
- package/dist/server-secret-env.d.ts +34 -20
- package/dist/server-secret-env.js +61 -18
- package/dist/session-agent.d.ts +4 -12
- package/dist/session-agent.js +0 -6
- package/dist/session-children-retire.d.ts +6 -3
- package/dist/session-children-retire.js +2 -5
- package/dist/session-incarnation.d.ts +18 -4
- package/dist/session-incarnation.js +4 -1
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync.js +3 -3
- package/dist/session-workspace.d.ts +3 -3
- package/dist/store-admission.d.ts +33 -0
- package/dist/store-admission.js +49 -0
- package/dist/store-posture.d.ts +5 -0
- package/dist/store-posture.js +18 -1
- package/dist/stores-sql/checkpoint-store-sql.d.ts +22 -3
- package/dist/stores-sql/checkpoint-store-sql.js +109 -23
- package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
- package/dist/stores-sql/file-history-store-sql.js +3 -5
- package/dist/stores-sql/retention-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +4 -6
- package/dist/task-a2a.d.ts +3 -8
- package/dist/task-a2a.js +25 -27
- package/dist/task-cwd.d.ts +27 -10
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +1 -1
- package/dist/task-settings.d.ts +13 -0
- package/dist/task-settings.js +14 -7
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.js +21 -6
- package/dist/tool-approval.d.ts +50 -41
- package/dist/tool-approval.js +96 -73
- package/dist/trace/engine-notice-wire.d.ts +38 -21
- package/dist/trace/engine-notice-wire.js +25 -4
- package/dist/trace/ledger-sink.d.ts +3 -1
- package/dist/trace/project.d.ts +8 -5
- package/dist/trace/project.js +11 -9
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/redact.d.ts +12 -0
- package/dist/trace/redact.js +5 -1
- package/dist/trace/self-minted-wire.d.ts +268 -56
- package/dist/trace/self-minted-wire.js +110 -40
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.js +22 -9
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
- package/docs/error-text-lexicon.json +317 -0
- package/package.json +4 -2
- package/scripts/embed-minimal.mjs +183 -0
- package/wire-changes/server@7.149.0.json +372 -0
- package/wire-changes/server@7.150.0.json +335 -0
- package/dist/plain-string-record.js +0 -70
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **卡已提交之后,停驻的唯一提交点** —— run 行的停驻写(`setSuspended` / `setNeedsReview`:对本腿持有的这条行的 CAS,保 `task_active` 认领)。
|
|
3
|
+
*
|
|
4
|
+
* 引擎交回停驻之前已把卡落进 checkpoint 店(卡已提交):这条 run 此刻在等那张卡。腿的收场只由行的这一笔写回答,规则一句 ——
|
|
5
|
+
* **店答出的拒是答案,店的故障不是**(与续跑认领之后的提交同一条律、同一对类别词:店答出 = `refused`,店没答出来 = `faulted`;
|
|
6
|
+
* 判在写口的两只出口上,结构判 —— 交回值 vs 抛 —— 不读错误文案)。
|
|
7
|
+
*
|
|
8
|
+
* 停驻写的 CAS = **行仍归本腿(持有腿 `legId`,认领交给本腿的那一只)∧ 仍在跑(或已停在本词上)∧ 没挂取消请求**(三件的属主 = 店的两只写口,
|
|
9
|
+
* `run-store-sql.ts` 的 `setSuspended` 头注;内存 / 文件孪生同判)。第一笔与每一次再提交是**同一个形**:写;店答出「不」⇒ 读行、由行答 ——
|
|
10
|
+
* · 行不在 ⇒ 兑现卡的 run 没了 ⇒ 作废卡(`card-void.ts` 的结算作废;卡的命运跟着行,行先、卡后);
|
|
11
|
+
* · 行已终局(不论哪条腿持有)⇒ run 收场了 ⇒ 作废卡(已不 pending 的卡作废是空操作);
|
|
12
|
+
* · 行归别的腿、还活着(在跑 / 停驻)⇒ 本腿先前那一笔落下了、卡被决、下一条腿接走了这条行(重开的同一张卡此刻归它)⇒ 停驻成立过,不写、卡不碰;
|
|
13
|
+
* · 行归本腿、停在本词上 ⇒ 本腿先前那一笔落下了(一笔抛了的写结局未知)⇒ 停驻成立;
|
|
14
|
+
* · 行归本腿、在跑、挂着取消请求(`POST /v1/runs/:id/cancel` 对在跑行只置旗)⇒ 取消先到:先作废卡、再落取消终局
|
|
15
|
+
* (唯一铸点 `mintCancelledResult`,码 `cancelled`)—— 不把一次已答「取消中」的 run 停成可决的停驻;
|
|
16
|
+
* · 行归本腿、在跑、没挂取消 ⇒ 店自相矛盾(CAS 说不、读说该写)= 不变量破 ⇒ 响亮记一次(`server.park.row-commit-contradicted`,带 taskId 与读到的词),
|
|
17
|
+
* 再当店故障处置(下面的再提交路)。
|
|
18
|
+
* 店故障(写 / 读 / 收场写抛:故障 / 超时 / 程序错)= `faulted` ⇒ **不收场**:不落 failed、不作废卡、认领原样留着,同一笔停驻再提交 ——
|
|
19
|
+
* 当拍一次,仍没答出 ⇒ 按心跳节拍续,直到店答出。上界 = 这台部署判活窗的两倍(`REAP_RUN_STALE_SEC`:一窗让这条不再有心跳的行落到既有的
|
|
20
|
+
* 失联判决射程里,一窗让判决落下、被下一次再提交读到 —— 读到即作废卡)。过了上界仍没答 ⇒ 停手,交既有出路:行由失联收割(`reapStale` /
|
|
21
|
+
* 观察口)按同一只判活窗收成 failed、放认领,卡由审批兜底收割按它的截止 / 绝对兜底时刻作废。不新造出路。
|
|
22
|
+
* 停驻的账本投影(停驻帧、它之前的用量差)不在这里:写口 `appendParkRow` 写不下只留痕,不改判词。
|
|
23
|
+
*/
|
|
24
|
+
import { type CardRef, type CardVoidPort } from "./card-void.js";
|
|
25
|
+
import type { RunStore } from "./plugins/store-backend.js";
|
|
26
|
+
import { type PersistedTaskResult, type RunRecord } from "./plugins/store-contracts.js";
|
|
27
|
+
import type { ParkLedgerEventType } from "./trace/ledger-events.js";
|
|
28
|
+
/**
|
|
29
|
+
* 一次停驻提交交回的读数(调用方按它收场,三形穷举):
|
|
30
|
+
* · `parked` —— 停驻成立(这一笔落下,或本腿先前那一笔已落下 —— 此后行可能已交给接手腿);
|
|
31
|
+
* · `pending` —— 店故障,再提交在续(行留 `running`、卡待决);
|
|
32
|
+
* · `ended` —— 这条 run 没有停住、已收场:`row` = 提交点读到 / 写下之后读回的那一行(终局;`undefined` = 行不在),卡已交作废。
|
|
33
|
+
* 这次收场是不是取消,读行的码(`row.errorCode === "cancelled"`,终局码的唯一读法)。
|
|
34
|
+
*/
|
|
35
|
+
export type ParkCommitOutcome = {
|
|
36
|
+
readonly kind: "parked";
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: "pending";
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: "ended";
|
|
41
|
+
readonly row: RunRecord | undefined;
|
|
42
|
+
};
|
|
43
|
+
export interface ParkRowCommit {
|
|
44
|
+
readonly runStore: Pick<RunStore, "setSuspended" | "setNeedsReview" | "getRun" | "setTerminal">;
|
|
45
|
+
readonly taskId: string;
|
|
46
|
+
/** 停在哪个词上(同一扇门的词:`plan_review` 落 `needs_review`,其余落 `suspended`)。 */
|
|
47
|
+
readonly word: ParkLedgerEventType;
|
|
48
|
+
/** 落在行上的结果(店入口再封口;`null` = 这条腿手里没有停驻结果 —— 重开 / 放回 / 兜底腿)。 */
|
|
49
|
+
readonly result: PersistedTaskResult | null;
|
|
50
|
+
/** 这次停驻在等的那张卡(凭据 + 它应归的会话 = 本 run 的会话)。店答出 run 已收场 ⇒ 作废的就是它。 */
|
|
51
|
+
readonly card: CardRef;
|
|
52
|
+
/** 读卡 / 作废的 checkpoint 店(缺席 ⇒ 作废那一步响亮留痕,见 `card-void.ts`)。 */
|
|
53
|
+
readonly cards: CardVoidPort | undefined;
|
|
54
|
+
/** 探针行上的产地(`leg=<…>`)。 */
|
|
55
|
+
readonly leg: "bg" | "resume" | "sync";
|
|
56
|
+
/** 本腿的持有腿(`RunRecord.legId`):认领交给本腿的那一只 —— 建行 `createRun` 的 `{ ok: true, legId }`、续跑认领 `markResuming` 的交回值。
|
|
57
|
+
* 停驻写只许它落下;拒后判拿它比行上的那一只。不是读来的:读到的持有腿可能已是接手腿的。 */
|
|
58
|
+
readonly legId: string;
|
|
59
|
+
/** 这台部署的判活窗(ms,`REAP_RUN_STALE_SEC` × 1000,活配置);缺席 ⇒ 缺省窗(不经装配直接调用的嵌入方 / 夹具)。 */
|
|
60
|
+
readonly staleWindowMs: number | undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 提交一次停驻(见模块头注)。不抛:第一笔抛 ⇒ 当拍再提交一次,仍抛 ⇒ 交回 `pending` 并起续提交;每一次失败、以及到上界停手,都经 F 类 tag
|
|
64
|
+
* `server.park.row-commit-deferred` 计数 + 探针行(detail `leg=<…> step=<first|again|retry|gave_up> err=<原句>`,不含凭据)。
|
|
65
|
+
*/
|
|
66
|
+
export declare function commitParkRow(c: ParkRowCommit): Promise<ParkCommitOutcome>;
|
|
67
|
+
//# sourceMappingURL=park-row-commit.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { voidPendingCard } from "./card-void.js";
|
|
2
|
+
import { LIVENESS_HEARTBEAT_MS } from "./config-invariants.js";
|
|
3
|
+
import { RUN_STALE_SEC_DEFAULT } from "./run-stale-default.js";
|
|
4
|
+
import { mintCancelledResult } from "./run-cancel-context.js";
|
|
5
|
+
import { errorText } from "./observability/err-text.js";
|
|
6
|
+
import { recordFailOpen } from "./observability/fail-open.js";
|
|
7
|
+
import { isTerminalRunStatus } from "./plugins/store-contracts.js";
|
|
8
|
+
const DEFERRED_TAG = "server.park.row-commit-deferred";
|
|
9
|
+
const CONTRADICTED_TAG = "server.park.row-commit-contradicted";
|
|
10
|
+
const VOID_TAG = "server.park.held-card-void-failed";
|
|
11
|
+
const CANCELLED_WHILE_PARKING = "cancelled before its park was committed (the pending approval was settled)";
|
|
12
|
+
const PARK_WRITE = {
|
|
13
|
+
suspended: (s, taskId, result, legId) => s.setSuspended(taskId, result, legId),
|
|
14
|
+
needs_review: (s, taskId, result, legId) => s.setNeedsReview(taskId, result, legId),
|
|
15
|
+
};
|
|
16
|
+
async function ended(c, row, at) {
|
|
17
|
+
await voidPendingCard(c.card, c.cards, VOID_TAG, `leg=${c.leg} at=${at}`);
|
|
18
|
+
return { kind: "ended", row };
|
|
19
|
+
}
|
|
20
|
+
async function settleByRow(c, row) {
|
|
21
|
+
if (row === undefined || isTerminalRunStatus(row.status))
|
|
22
|
+
return ended(c, row, "park_commit_refused");
|
|
23
|
+
if (row.legId !== c.legId)
|
|
24
|
+
return { kind: "parked" };
|
|
25
|
+
if (row.status !== "running")
|
|
26
|
+
return { kind: "parked" };
|
|
27
|
+
if (row.cancelRequested) {
|
|
28
|
+
await voidPendingCard(c.card, c.cards, VOID_TAG, `leg=${c.leg} at=park_commit_cancelled`);
|
|
29
|
+
const cancelled = mintCancelledResult({ taskId: c.taskId, sessionId: row.sessionId, startedAtMs: Date.parse(row.createdAt), message: CANCELLED_WHILE_PARKING, cause: "cancel_verb" });
|
|
30
|
+
await c.runStore.setTerminal(c.taskId, "failed", cancelled, CANCELLED_WHILE_PARKING);
|
|
31
|
+
return { kind: "ended", row: await c.runStore.getRun(c.taskId) };
|
|
32
|
+
}
|
|
33
|
+
recordFailOpen(CONTRADICTED_TAG, `leg=${c.leg} taskId=${c.taskId} word=${c.word} status=${row.status} holder=self cancel=false`);
|
|
34
|
+
throw new Error(`park commit: the store refused the ${c.word} write of run ${c.taskId} while its row reads as this leg's, running, with no cancel request`);
|
|
35
|
+
}
|
|
36
|
+
async function attempt(c) {
|
|
37
|
+
if ((await PARK_WRITE[c.word](c.runStore, c.taskId, c.result, c.legId)) !== false)
|
|
38
|
+
return { kind: "parked" };
|
|
39
|
+
return settleByRow(c, await c.runStore.getRun(c.taskId));
|
|
40
|
+
}
|
|
41
|
+
export async function commitParkRow(c) {
|
|
42
|
+
try {
|
|
43
|
+
return await attempt(c);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
recordFailOpen(DEFERRED_TAG, `leg=${c.leg} step=first err=${errorText(e)}`);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return await attempt(c);
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
recordFailOpen(DEFERRED_TAG, `leg=${c.leg} step=again err=${errorText(e)}`);
|
|
53
|
+
}
|
|
54
|
+
continueParkCommit(c);
|
|
55
|
+
return { kind: "pending" };
|
|
56
|
+
}
|
|
57
|
+
function continueParkCommit(c) {
|
|
58
|
+
const untilMs = Date.now() + 2 * (c.staleWindowMs ?? RUN_STALE_SEC_DEFAULT * 1000);
|
|
59
|
+
let inFlight = false;
|
|
60
|
+
const timer = setInterval(() => {
|
|
61
|
+
if (inFlight)
|
|
62
|
+
return;
|
|
63
|
+
inFlight = true;
|
|
64
|
+
void attempt(c).then(() => clearInterval(timer), (e) => {
|
|
65
|
+
inFlight = false;
|
|
66
|
+
if (Date.now() < untilMs) {
|
|
67
|
+
recordFailOpen(DEFERRED_TAG, `leg=${c.leg} step=retry err=${errorText(e)}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
clearInterval(timer);
|
|
71
|
+
recordFailOpen(DEFERRED_TAG, `leg=${c.leg} step=gave_up err=${errorText(e)}`);
|
|
72
|
+
});
|
|
73
|
+
}, LIVENESS_HEARTBEAT_MS);
|
|
74
|
+
timer.unref?.();
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=park-row-commit.js.map
|
package/dist/parked-decide.d.ts
CHANGED
|
@@ -16,8 +16,10 @@ import type { ParkedReviveSurfaceFactory } from "./parked-revive-surface.js";
|
|
|
16
16
|
import type { RebuiltInheritedGate } from "./boot/parked-revive-gate.js";
|
|
17
17
|
import { type WorkflowRunParkKey, type WorkflowAgentSessionIndex } from "./orchestration/workflow-agent-session-index.js";
|
|
18
18
|
import type { WorkflowParkDecisionStore, WorkflowParkOutcome } from "./orchestration/workflow-park-decision.js";
|
|
19
|
+
import { type ApprovalLegOrigin } from "./approval-leg-origin.js";
|
|
19
20
|
import type { SessionFace } from "./session-incarnation.js";
|
|
20
|
-
import { type
|
|
21
|
+
import { type CardSettlePort } from "./card-settle-stored-scope.js";
|
|
22
|
+
import { type ClaimFace, type ExecutionCommitDeps, type RootedExecutionContext } from "./http/execution-context.js";
|
|
21
23
|
import type { GateIdentity } from "./checkpoint-identity.js";
|
|
22
24
|
/**
|
|
23
25
|
* 本腿的**装配前提**(`createHttpServer` 起服拒的拒句;规则见 {@link ParkedDecideDeps} 的 `execution`):接了本腿(`parkedReviveSurface` 在场)的部署,
|
|
@@ -155,8 +157,8 @@ export declare function findParkedAgentForCheckpoint(agentStore: BackgroundAgent
|
|
|
155
157
|
}): Promise<ParkedAgentMatch | undefined>;
|
|
156
158
|
export interface ParkedDecideDeps {
|
|
157
159
|
agentStore: BackgroundAgentStore;
|
|
158
|
-
/** `expire
|
|
159
|
-
checkpointStore: Pick<CheckpointStore, "get" | "expire"
|
|
160
|
+
/** `expire` + `peekScopeByToken` + 状态读:[ref] deny 作废复活不了的卡(`expireCardUnderStoredScope`:先读状态、再按店里该卡的属主格 CAS);`get`:引擎的 claim / 对账读卡。 */
|
|
161
|
+
checkpointStore: Pick<CheckpointStore, "get" | "expire"> & CardSettlePort;
|
|
160
162
|
/** 与 reaper/scenarios 同一个 registry(claim/rollback 的 CAS 与 in-memory handle 收敛在同处;[ref] 作废之后的对账也是它)。 */
|
|
161
163
|
registry: Pick<TaskRegistry, "claimParkedAgent" | "rollbackParkedClaim" | "reconcileParkedAgents">;
|
|
162
164
|
/** [ref](core 7.32.0):按**行**解析赎回面 —— 驱动哪一只 Agent 工具(生产装配,与 spawn 同源:subRunner / bg opts /
|
|
@@ -188,19 +190,19 @@ export interface ParkedDecideDeps {
|
|
|
188
190
|
owner: string | null;
|
|
189
191
|
taskId: string;
|
|
190
192
|
sessionId: string;
|
|
191
|
-
|
|
192
|
-
}) => NonNullable<ToolExecuteContext["onAsk"]>;
|
|
193
|
+
} & ApprovalLegOrigin) => NonNullable<ToolExecuteContext["onAsk"]>;
|
|
193
194
|
/**
|
|
194
195
|
* 边界 9 的执行上下文(设计 §3.2;与提交腿 / 续跑家族同一只解析器、同一只写口)—— 本腿对根会话的住客**一读一判**:
|
|
195
196
|
* · `resolve` —— **认领之前**按行的根取上下文:解析器那一次行读(执行席:住客 + 格)就是本腿对根会话的**唯一一读**;根行不在 ⇒ `gone`
|
|
196
|
-
* (本腿答既有的 `decide.not_parked`);其余拒(mirror / 车道不再服务 / 主体的车道裁定)按续跑家族的折叠律答好交回(`answer`)
|
|
197
|
+
* (本腿答既有的 `decide.not_parked`);其余拒(mirror / 车道不再服务 / 主体的车道裁定)按续跑家族的折叠律答好交回(`answer`);店没答出来 ⇒ 本腿交来的这一面
|
|
198
|
+
* `face` 的瞬时答复(`answer`,与认领那一笔撞店故障同答)—— 不认领、不驱动。
|
|
197
199
|
* 成功形的 `occupant` **必有**:接本腿的部署必须带执行席(无席的会话店交不出这一读;`createHttpServer` 在装配时拒无席形);
|
|
198
200
|
* · `commitDeps` —— 认领之后 `commitExecutionContext` 读的部署件:唯一写口按那一读的住客定址写 / 再读(化身 ∧ 属主),这就是认领之后对根住客的
|
|
199
201
|
* **唯一一判**(拒 ⇒ 先回滚认领)。写口放行的那一位就是赎回面的根住客见证;写口之后本腿不再读根。
|
|
200
202
|
* 复活子代的审批席带这只上下文的车道(`approverSeatFor` 的 `executionLane`)。
|
|
201
203
|
*/
|
|
202
204
|
execution: {
|
|
203
|
-
resolve: (root: string) => Promise<{
|
|
205
|
+
resolve: (root: string, face: ClaimFace) => Promise<{
|
|
204
206
|
readonly ok: true;
|
|
205
207
|
readonly ctx: RootedExecutionContext & {
|
|
206
208
|
readonly occupant: SessionFace;
|
package/dist/parked-decide.js
CHANGED
|
@@ -5,10 +5,12 @@ import { recordFailOpen } from "./observability/fail-open.js";
|
|
|
5
5
|
import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
|
|
6
6
|
import { backgroundScopesForCheckpointScope, decodeCheckpointScope, ownerOfCheckpointScope } from "./security.js";
|
|
7
7
|
import { ASK_USER_QUESTION_TOOL_NAME, isEngineQuestionRow } from "./approval-content-kind.js";
|
|
8
|
+
import { approvalLegOriginOf } from "./approval-leg-origin.js";
|
|
8
9
|
import { refusalBody, resumeRefusalFacts } from "./http/refusal-body.js";
|
|
9
10
|
import { backgroundAgentNameOf } from "./background-agent-name.js";
|
|
10
11
|
import { buildSettlementEvidence, NO_SETTLEMENT_EVIDENCE } from "./gate-settlement.js";
|
|
11
|
-
import {
|
|
12
|
+
import { CARD_EXPIRE_OUTCOME, expireCardUnderStoredScope } from "./card-settle-stored-scope.js";
|
|
13
|
+
import { cardWaitingRefusalAnswer, commitExecutionContext, faultedAnswerOf, isRootSessionGoneRefusal } from "./http/execution-context.js";
|
|
12
14
|
import { EXECUTION_PLACEMENT_SEAT_CARRIERS } from "./execution-placement.js";
|
|
13
15
|
export const PARKED_REVIVE_EXECUTION_SEAT_REQUIRED = `the parked-agent revive leg (parkedReviveSurface) needs a session store with an execution placement seat (sessionStorage.executionPlacement) — after the claim, the root session's occupant is judged only by the write on that seat; ${EXECUTION_PLACEMENT_SEAT_CARRIERS}; refusing to start rather than revive parked agents with nobody judging the root session's occupant after the claim`;
|
|
14
16
|
export async function findParkOrigin(sources, cp) {
|
|
@@ -346,6 +348,15 @@ function sessionGone(taskId) {
|
|
|
346
348
|
}),
|
|
347
349
|
};
|
|
348
350
|
}
|
|
351
|
+
function parkedClaimFaultAnswer(taskId) {
|
|
352
|
+
return { status: 503, body: refusalBody({ errorCode: "decide.store_unreachable", message: "the stored state this decision needs could not be read or written just now (the store failed) — nothing was decided and the agent is still waiting for it; retry", facts: { taskId } }) };
|
|
353
|
+
}
|
|
354
|
+
function parkedRedeemFace(taskId) {
|
|
355
|
+
return {
|
|
356
|
+
refused: (refusal) => (isRootSessionGoneRefusal(refusal) ? sessionGone(taskId) : cardWaitingRefusalAnswer(refusal)),
|
|
357
|
+
faulted: () => parkedClaimFaultAnswer(taskId),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
349
360
|
function gateMoved(taskId) {
|
|
350
361
|
return { status: 409, body: refusalBody({ errorCode: "decide.gate_moved", message: "the approval gate moved under this decide (re-parked or already settled) — re-check the pending list", facts: { taskId } }) };
|
|
351
362
|
}
|
|
@@ -356,7 +367,7 @@ function revivabilityOf(row, taskId) {
|
|
|
356
367
|
return { kind: "revivable", root: row.rootSessionId };
|
|
357
368
|
}
|
|
358
369
|
async function voidUnrevivableCard(deps, req, match) {
|
|
359
|
-
const voided = await deps.checkpointStore
|
|
370
|
+
const voided = (await expireCardUnderStoredScope(deps.checkpointStore, req.token)) === CARD_EXPIRE_OUTCOME.expired;
|
|
360
371
|
if (!voided) {
|
|
361
372
|
return gateMoved(match.handle);
|
|
362
373
|
}
|
|
@@ -385,7 +396,8 @@ export async function decideParkedAgent(deps, req, match) {
|
|
|
385
396
|
if (revivability.kind === "unrevivable")
|
|
386
397
|
return req.decision === "deny" ? voidUnrevivableCard(deps, req, match) : revivability.approveRefusal;
|
|
387
398
|
const root = revivability.root;
|
|
388
|
-
const
|
|
399
|
+
const face = parkedRedeemFace(match.handle);
|
|
400
|
+
const resolved = await deps.execution.resolve(root, face);
|
|
389
401
|
if (!resolved.ok)
|
|
390
402
|
return resolved.gone ? sessionGone(match.handle) : resolved.answer;
|
|
391
403
|
const execution = resolved.ctx;
|
|
@@ -395,7 +407,7 @@ export async function decideParkedAgent(deps, req, match) {
|
|
|
395
407
|
if (!claim.ok) {
|
|
396
408
|
switch (claim.reason) {
|
|
397
409
|
case "store_unreachable":
|
|
398
|
-
return
|
|
410
|
+
return face.faulted();
|
|
399
411
|
case "claim_lost":
|
|
400
412
|
return { status: 409, body: refusalBody({ errorCode: "decide.claim_lost", message: "the parked agent is already claimed — either a concurrent decide won (re-check the pending list), or a stale claim is pending automatic cleanup (retry after the stale-claim window)", facts: { taskId: match.handle } }) };
|
|
401
413
|
case "binding_broken":
|
|
@@ -428,7 +440,14 @@ export async function decideParkedAgent(deps, req, match) {
|
|
|
428
440
|
await rollback("claimed_token_moved");
|
|
429
441
|
return gateMoved(match.handle);
|
|
430
442
|
}
|
|
431
|
-
|
|
443
|
+
let placementRefusal;
|
|
444
|
+
try {
|
|
445
|
+
const refusal = await commitExecutionContext(deps.execution.commitDeps, { kind: "parked", taskId: match.handle, rollback }, execution);
|
|
446
|
+
placementRefusal = refusal === null ? null : face.refused(refusal);
|
|
447
|
+
}
|
|
448
|
+
catch (e) {
|
|
449
|
+
placementRefusal = faultedAnswerOf(e, face.faulted);
|
|
450
|
+
}
|
|
432
451
|
if (placementRefusal)
|
|
433
452
|
return placementRefusal;
|
|
434
453
|
let surface;
|
|
@@ -457,7 +476,7 @@ export async function decideParkedAgent(deps, req, match) {
|
|
|
457
476
|
...(surface.mountsCallerTool !== undefined ? { mountsCallerTool: surface.mountsCallerTool } : {}),
|
|
458
477
|
...(surface.onBackgroundChildEvent !== undefined ? { onBackgroundChildEvent: surface.onBackgroundChildEvent } : {}),
|
|
459
478
|
...(deps.approverSeatFor !== undefined && seatRoot !== undefined
|
|
460
|
-
? { onAsk: deps.approverSeatFor({ owner: ownerOfCheckpointScope(req.scope), taskId: match.handle, sessionId: seatRoot,
|
|
479
|
+
? { onAsk: deps.approverSeatFor({ owner: ownerOfCheckpointScope(req.scope), taskId: match.handle, sessionId: seatRoot, ...approvalLegOriginOf(execution) }) }
|
|
461
480
|
: {}),
|
|
462
481
|
reviveClaim: {
|
|
463
482
|
row: { ...ticket.row, parkClaimId: ticket.claimId },
|
package/dist/peer-directory.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ⚠️ **共享的是谓词,不是最终集合**(codex 对抗复审 r1 ② 采纳,如实收窄 —— 稿里与本注初版都写成了
|
|
20
20
|
* 「两面集合相等」,那是**过度承诺**):两面在下面这些地方按设计给出不同的集合,逐条都不是 bug ——
|
|
21
|
-
* · **fleet-wide 调用方**:`GET /v1/sessions`
|
|
21
|
+
* · **fleet-wide 调用方**:`GET /v1/sessions` 对不报主体的 service-token / dev-open 调用方不钉 owner、还认 `?owner=`
|
|
22
22
|
* (运维视图);目录**只**按 core 递进来的那一个 scope 分区,永不跨;
|
|
23
23
|
* · **分页与搜索**:那条路由有 `?limit`/`?cursor`/`?q=`,目录是一次定量读(见 {@link PEER_DIRECTORY_CAP});
|
|
24
24
|
* · **peer 可寻址性过滤**:语法外 / 非小写规范形 / 与别条会话折到同一只箱的 id 都不入目录(下面那道
|
package/dist/peer-seat.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ export type PeerBinding = {
|
|
|
66
66
|
readonly url: string;
|
|
67
67
|
readonly cardUrl?: string;
|
|
68
68
|
};
|
|
69
|
-
/** Why the seat refused a question. Closed: a
|
|
69
|
+
/** Why the seat refused a question. Closed: a word belongs to a row of the seat's per-kind table (or to the handle row's own two refusals). */
|
|
70
70
|
export type PeerSeatRefusalReason = "handle_not_held" | "binding_mismatch" | "kind_env" | "kind_vault" | "kind_assertion" | "kind_unknown";
|
|
71
71
|
/**
|
|
72
72
|
* The desk's own failures, each loud:
|
package/dist/peer-seat.js
CHANGED
|
@@ -151,67 +151,60 @@ export function createPeerDesk(opts = {}) {
|
|
|
151
151
|
return { kind: "carry", env: entry.pieces };
|
|
152
152
|
}
|
|
153
153
|
};
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
case "handle":
|
|
157
|
-
return ref.id;
|
|
158
|
-
case "env":
|
|
159
|
-
case "vault":
|
|
160
|
-
case "assertion":
|
|
161
|
-
return undefined;
|
|
162
|
-
default: {
|
|
163
|
-
const unknownKind = ref;
|
|
164
|
-
void unknownKind;
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
154
|
+
const notMintedHold = () => {
|
|
155
|
+
throw new Error("peer desk: hold of a reference this desk did not mint — not held");
|
|
168
156
|
};
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
157
|
+
const notMintedRelease = () => {
|
|
158
|
+
throw new Error("peer desk: release of a reference this desk did not mint — nothing released");
|
|
159
|
+
};
|
|
160
|
+
const notMinted = (reason) => ({
|
|
161
|
+
answer: (_ref, question) => refuse(question.peer, reason),
|
|
162
|
+
hold: notMintedHold,
|
|
163
|
+
release: notMintedRelease,
|
|
164
|
+
});
|
|
165
|
+
const seatKinds = {
|
|
166
|
+
handle: {
|
|
167
|
+
answer: (ref, question) => {
|
|
168
|
+
const target = question.peer;
|
|
169
|
+
const entry = table.get(ref.id);
|
|
170
|
+
if (entry === undefined)
|
|
171
|
+
return refuse(target, "handle_not_held");
|
|
172
|
+
if (!sameBinding(entry.binding, bindingOf(target)))
|
|
173
|
+
return refuse(target, "binding_mismatch");
|
|
174
|
+
return carry(entry);
|
|
175
|
+
},
|
|
176
|
+
hold: (ref) => {
|
|
177
|
+
const id = ref.id;
|
|
178
|
+
if (id === undefined)
|
|
179
|
+
return notMintedHold();
|
|
180
|
+
const entry = table.get(id);
|
|
181
|
+
if (entry === undefined)
|
|
182
|
+
throw new Error("peer desk: hold of a handle whose entry is gone — not held (a hold never revives an entry)");
|
|
183
|
+
entry.engineHolds += 1;
|
|
184
|
+
},
|
|
185
|
+
release: (ref) => {
|
|
186
|
+
const id = ref.id;
|
|
187
|
+
if (id === undefined)
|
|
188
|
+
return notMintedRelease();
|
|
189
|
+
const entry = table.get(id);
|
|
190
|
+
if (entry === undefined || entry.engineHolds === 0)
|
|
191
|
+
throw new Error("peer desk: release of a handle with no counted engine hold — nothing released");
|
|
192
|
+
entry.engineHolds -= 1;
|
|
193
|
+
dropIfUnheld(id, entry);
|
|
194
|
+
},
|
|
188
195
|
},
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return carry(entry);
|
|
202
|
-
}
|
|
203
|
-
case "env":
|
|
204
|
-
return refuse(target, "kind_env");
|
|
205
|
-
case "vault":
|
|
206
|
-
return refuse(target, "kind_vault");
|
|
207
|
-
case "assertion":
|
|
208
|
-
return refuse(target, "kind_assertion");
|
|
209
|
-
default: {
|
|
210
|
-
const unknownKind = ref;
|
|
211
|
-
void unknownKind;
|
|
212
|
-
return refuse(target, "kind_unknown");
|
|
213
|
-
}
|
|
214
|
-
}
|
|
196
|
+
env: notMinted("kind_env"),
|
|
197
|
+
vault: notMinted("kind_vault"),
|
|
198
|
+
assertion: notMinted("kind_assertion"),
|
|
199
|
+
};
|
|
200
|
+
const unknownKind = notMinted("kind_unknown");
|
|
201
|
+
const rowOf = (ref) => (Object.hasOwn(seatKinds, ref.kind) ? seatKinds[ref.kind] : unknownKind);
|
|
202
|
+
const seat = Object.freeze({
|
|
203
|
+
hold: (ref) => rowOf(ref).hold(ref),
|
|
204
|
+
release: (ref) => rowOf(ref).release(ref),
|
|
205
|
+
answer: async (question, signal) => {
|
|
206
|
+
const ref = question.peer.credentials;
|
|
207
|
+
return ref === undefined ? { kind: "carry" } : rowOf(ref).answer(ref, question, signal);
|
|
215
208
|
},
|
|
216
209
|
});
|
|
217
210
|
return Object.freeze({
|
|
@@ -193,9 +193,9 @@ export declare class SqlAdoptionLogStore implements AdoptionLogStore {
|
|
|
193
193
|
/**
|
|
194
194
|
* 收编弧的 advisory 锁(183 I1 的 form b 形:「与任何活写互斥」在 SQL 侧 = 一次只有一个副本在推这条弧)。
|
|
195
195
|
*
|
|
196
|
-
* **非阻塞取 + 有界轮询**(
|
|
197
|
-
*
|
|
198
|
-
* 返回 `undefined`,调用方按「在飞」应答 —— **不假装成功,也不无限等**。
|
|
196
|
+
* **非阻塞取 + 有界轮询**(阻塞式 GET_LOCK 会把并发调用方全部 park 在 TiDB 的悲观锁行上,既耗它的重试预算又饿死应用自己的 FOR UPDATE 路)。
|
|
197
|
+
* 取锁走本仓**唯一的取锁器**(`ensure-schema-lock-policy.ts` 的 {@link acquireAdvisoryLockWithin}):探针句、答案读法、TiDB「悲观锁重试上限」
|
|
198
|
+
* 读成「别人持着」、坏连接计数全在那里,本店不自带第二只探针。取不到 ⇒ 返回 `undefined`,调用方按「在飞」应答 —— **不假装成功,也不无限等**。
|
|
199
199
|
*
|
|
200
200
|
* 🔴 入参 `name` 是**逻辑**锁名(`adoptionLockName(fromPrincipal)`);真正发给引擎的是它被
|
|
201
201
|
* {@link qualifyAdoptionLockName} 限定到本库之后的形([ref]:两方言键空间不等价)。限定发生在
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { writeLogText } from "../observability/logger.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
|
+
import { acquireAdvisoryLockWithin, releaseAdvisoryLock } from "./ensure-schema-lock-policy.js";
|
|
4
5
|
import { ensureIndexes } from "./ensure-index.js";
|
|
5
6
|
export const ADOPTION_LOG_TABLE = "adoption_log";
|
|
6
7
|
export const ADOPTION_PHASE = {
|
|
@@ -77,6 +78,18 @@ const PG_ADOPTION_LOCK_CLASS = 4907;
|
|
|
77
78
|
function pgLockObjectKey(name) {
|
|
78
79
|
return createHash("sha256").update(name).digest().readInt32BE(0);
|
|
79
80
|
}
|
|
81
|
+
function arcLockId(dialect, qualifiedName) {
|
|
82
|
+
switch (dialect) {
|
|
83
|
+
case "mysql":
|
|
84
|
+
return { dialect, name: qualifiedName };
|
|
85
|
+
case "pg":
|
|
86
|
+
return { dialect, keys: [PG_ADOPTION_LOCK_CLASS, pgLockObjectKey(qualifiedName)] };
|
|
87
|
+
default: {
|
|
88
|
+
const unreachable = dialect;
|
|
89
|
+
throw new Error(`unreachable SQL dialect: ${String(unreachable)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
80
93
|
export function adoptionLockName(fromPrincipal) {
|
|
81
94
|
return `sema_adoption:${createHash("sha256").update(fromPrincipal).digest("hex").slice(0, 32)}`;
|
|
82
95
|
}
|
|
@@ -188,30 +201,17 @@ export class SqlAdoptionLogStore {
|
|
|
188
201
|
}
|
|
189
202
|
async withLock(name, fn, attempts = 20, sleepMs = 100) {
|
|
190
203
|
const conn = await this.db.connect();
|
|
191
|
-
let held
|
|
192
|
-
let lockName = "";
|
|
204
|
+
let held;
|
|
193
205
|
try {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const res = await conn.query(this.q("SELECT GET_LOCK(?, 0) AS got", "SELECT pg_try_advisory_lock($1, $2) AS got"), this.db.dialect === "mysql" ? [lockName] : [PG_ADOPTION_LOCK_CLASS, pgLockObjectKey(lockName)]);
|
|
197
|
-
const got = res.rows[0]?.got;
|
|
198
|
-
held = got === 1 || got === true || got === "1";
|
|
199
|
-
if (!held)
|
|
200
|
-
await new Promise((r) => setTimeout(r, sleepMs));
|
|
201
|
-
}
|
|
202
|
-
if (!held)
|
|
206
|
+
const lock = arcLockId(this.db.dialect, qualifyAdoptionLockName(await this.resolveLockKeyspace(conn), name));
|
|
207
|
+
if (!(await acquireAdvisoryLockWithin(conn, lock, "adoption-log", attempts, sleepMs)))
|
|
203
208
|
return undefined;
|
|
209
|
+
held = lock;
|
|
204
210
|
return await fn(conn);
|
|
205
211
|
}
|
|
206
212
|
finally {
|
|
207
|
-
if (held)
|
|
208
|
-
|
|
209
|
-
await conn.query(this.q("SELECT RELEASE_LOCK(?) AS released", "SELECT pg_advisory_unlock($1, $2) AS released"), this.db.dialect === "mysql" ? [lockName] : [PG_ADOPTION_LOCK_CLASS, pgLockObjectKey(lockName)]);
|
|
210
|
-
}
|
|
211
|
-
catch (releaseErr) {
|
|
212
|
-
writeLogText("stderr", "[adoption-log] releasing the adoption arc lock failed (it auto-frees when the connection closes):", releaseErr);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
213
|
+
if (held !== undefined)
|
|
214
|
+
await releaseAdvisoryLock(conn, held, "adoption-log");
|
|
215
215
|
conn.release();
|
|
216
216
|
}
|
|
217
217
|
}
|
|
@@ -715,7 +715,7 @@ export declare function ensurePgApprovalAskSchema(q: PgQueryFn): Promise<void>;
|
|
|
715
715
|
*
|
|
716
716
|
* 判据 = **能力探测**(恒空的 `WHERE 1=0` 读)+ **方言的缺列错误码**(判据属主 `sql-errors.ts` 的
|
|
717
717
|
* {@link isMissingColumnError});其余错误**原样 rethrow**,一个字都不加工 —— 把一次瞬时故障诊断成「缺列」的拒因
|
|
718
|
-
* 比它要挡的缺陷更贵([ref] 那两轮收窄的结论逐字继承)。拒因的出路是**闭集三条**(与整库对账同一份,{@link
|
|
718
|
+
* 比它要挡的缺陷更贵([ref] 那两轮收窄的结论逐字继承)。拒因的出路是**闭集三条**(与整库对账同一份,{@link probedMissingColumnRefusal}),没有销毁性的一条。
|
|
719
719
|
*
|
|
720
720
|
* 🔴 位置与两条先例同款:**不在** `ensureSchema` 里(那条通道的契约是「只发 CREATE」,有运行时门看着),
|
|
721
721
|
* 放在 DDL 之后、任何路由装配之前;且**只在流内审批协议真会上场时**跑(判据 = 与协调器同一个符号
|
|
@@ -4,7 +4,7 @@ import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
|
|
|
4
4
|
import { DECIDED_VIA } from "@sema-agent/core";
|
|
5
5
|
import { APPROVAL_ENDING_CAUSES, askRowEndingCause, askRowParkTrigger } from "../approval-deny-reasons.js";
|
|
6
6
|
import { isDupKeyError, isMissingColumnError } from "./sql-errors.js";
|
|
7
|
-
import {
|
|
7
|
+
import { probedMissingColumnRefusal } from "./schema-drift-sentence.js";
|
|
8
8
|
import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, readTriStateJsonValueColumn } from "./sql-json-column.js";
|
|
9
9
|
import { ensureIndexes } from "./ensure-index.js";
|
|
10
10
|
import { isExecutionLane } from "../execution-lane-caps.js";
|
|
@@ -334,7 +334,7 @@ export async function assertApprovalAskRuleMaterialSchema(query, dialect) {
|
|
|
334
334
|
catch (err) {
|
|
335
335
|
if (!isMissingColumnError(err, dialect))
|
|
336
336
|
throw err;
|
|
337
|
-
throw
|
|
337
|
+
throw await probedMissingColumnRefusal(query, dialect, [APPROVAL_ASK_TABLE], `${APPROVAL_ASK_TABLE} is missing the #363 rule-material columns (rule_command / rule_scope_root) and/or the S-26 edited-input column (updated_input) — refusing to start. ` +
|
|
338
338
|
`A parked approval's late decision can now carry \`persistRule\` ("don't ask again"), and the row is where the ` +
|
|
339
339
|
`adjudicated command and the project root of the authorization site live; a decision's edited input (ctrl+g) is ` +
|
|
340
340
|
`persisted on the row too, so a replica that does not hold the waiting leg replays the approved bytes; every ask-row ` +
|
|
@@ -342,9 +342,7 @@ export async function assertApprovalAskRuleMaterialSchema(query, dialect) {
|
|
|
342
342
|
`is persisted, the replay list stays empty, late decisions 404) while /v1/capabilities still reports it active. ` +
|
|
343
343
|
`The table holds IN-FLIGHT approval asks (cards awaiting an answer) plus settled bookkeeping; the durable park face ` +
|
|
344
344
|
`(checkpoint rows) and the persisted rules themselves are untouched, so an in-flight card falls back to the durable gate ` +
|
|
345
|
-
`(\`POST /v1/approvals/:sessionId/decide\`) until the columns exist
|
|
346
|
-
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
|
|
347
|
-
(await describeProbedTableDrift(query, dialect, [APPROVAL_ASK_TABLE])));
|
|
345
|
+
`(\`POST /v1/approvals/:sessionId/decide\`) until the columns exist.`, err);
|
|
348
346
|
}
|
|
349
347
|
}
|
|
350
348
|
function askCols(dialect) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Logger } from "../observability/logger.js";
|
|
2
|
+
import type { RetiredSchemaProbeTarget } from "./schema-consistency.js";
|
|
3
|
+
import type { SqlDialect } from "./sql-driver.js";
|
|
4
|
+
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
5
|
+
/** 被判的行的 wire 工具名 —— 引擎 `Skill` 工具的名字,core 导出(不手抄;core 改名 ⇒ 谓词跟着走)。 */
|
|
6
|
+
export declare const SKILL_EXEMPTION_TOOL_NAME: string;
|
|
7
|
+
/** 第一只落截点、删截点之前的行的版本(一次性迁移 M46 的引入版本;登记表 M46 行在时两者逐字相同 —— `test/approval-exemption-skill-cutoff.test.ts` 钉)。拒句点名的出路版本下限。 */
|
|
8
|
+
export declare const SKILL_EXEMPTION_CUTOFF_SINCE = "7.148.0";
|
|
9
|
+
/** local 车道的截点文件(数据根顶层;文件名沿用 M46 —— 7.148.0 起的数据根里已经是它)。 */
|
|
10
|
+
export declare const LOCAL_SKILL_EXEMPTION_CUTOFF_FILE = "one-time-migration-M46.marker";
|
|
11
|
+
/** 截点之前的行写下时的意思与今天读法的差 —— SQL 拒句与 local 读数段同一句。 */
|
|
12
|
+
export declare const PRE_CUTOFF_SKILL_EXEMPTION_CONSEQUENCE: string;
|
|
13
|
+
/** 判用的读口:一句带参数的查询 ⇒ 行。 */
|
|
14
|
+
type CutoffQuery = (sql: string, params?: readonly unknown[]) => Promise<Array<Record<string, unknown>>>;
|
|
15
|
+
/**
|
|
16
|
+
* **SQL 截点的唯一读者**(常设臂与一次性迁移 M46 的删句同读;调用方先确认标记表在):行不在 ⇒ `undefined`(缺席);行在而读不出时刻 ⇒ 拒启 {@link StoreBootRefusalError}
|
|
17
|
+
* —— 不按「此刻」、也不按「没有」猜(非法时刻进比较,驱动把它写成 `NULL`,`created_at < NULL` 数出 0 = 静默放行)。拒句只带读到的数值与出路。
|
|
18
|
+
*/
|
|
19
|
+
export declare function readSqlSkillExemptionCutoff(query: CutoffQuery, dialect: SqlDialect): Promise<number | undefined>;
|
|
20
|
+
/**
|
|
21
|
+
* SQL 腿的拒启:这只库里有首次放行早于截点(或截点缺席)的 `Skill` 豁免行,而本构建已不带删它们的一次性迁移。**具名类型**(族基类 {@link StoreBootRefusalError}:
|
|
22
|
+
* 起服降级臂不吞、开库等待窗不重试);码与退役 schema / 列册对账同一个 `config.schema_mismatch`。拒句只带行数、截点与工具名(行的会话 / 放行人不进句子)。
|
|
23
|
+
*/
|
|
24
|
+
export declare class LegacySkillExemptionsPresentError extends StoreBootRefusalError {
|
|
25
|
+
/** 截点之前的 `Skill` 行数。 */
|
|
26
|
+
readonly rows: number;
|
|
27
|
+
/** 截点(ISO 时刻;`null` = 这只库没记截点:从没在落截点的版本上起过服)。 */
|
|
28
|
+
readonly cutoff: string | null;
|
|
29
|
+
/** 机读码(与退役 schema / 列册对账的拒启同一个)。 */
|
|
30
|
+
readonly code = "config.schema_mismatch";
|
|
31
|
+
constructor(
|
|
32
|
+
/** 截点之前的 `Skill` 行数。 */
|
|
33
|
+
rows: number,
|
|
34
|
+
/** 截点(ISO 时刻;`null` = 这只库没记截点:从没在落截点的版本上起过服)。 */
|
|
35
|
+
cutoff: string | null);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* SQL 腿的判(纯读,**唯一一只**;律见文件头):读截点({@link readSqlSkillExemptionCutoff};标记表不在 ⇒ 缺席,读不出 ⇒ 拒 —— `carried` 也判,建表之前)→
|
|
39
|
+
* `carried`(本构建还带 M46)或豁免表不在(新库,建表之前)⇒ 无事 → 数截点之前的 `Skill` 行(截点缺席 ⇒ 全部 `Skill` 行)→ 非零 ⇒ 拒。
|
|
40
|
+
* 谓词与 M46 的删句同一条,比较在库里做(`created_at < ?`,参数是截点的 `Date`)。读抛 ⇒ 原样上抛(判不了 ⇒ 不放行;不是确定的拒启表态)。
|
|
41
|
+
*/
|
|
42
|
+
export declare function judgeSqlSkillExemptionCutoff(query: CutoffQuery, dialect: SqlDialect, carried: boolean): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* **探针口**(SQL 腿的判唯一的读处;唯一调用点 = `store-backend.ts` 的 `withRetiredSchemaProbe`,先于第一条 CREATE):借一条连接判一次、用完即还(拒时连接也已归还);
|
|
45
|
+
* `carried`(本构建还带 M46)⇒ 只验截点读得出、不数行(存量行交给 M46 删)。不取 `ensureSchema` 那把锁:纯读。
|
|
46
|
+
*/
|
|
47
|
+
export declare function assertSkillExemptionCutoffHeldOnPool(target: RetiredSchemaProbeTarget, carried: boolean): Promise<void>;
|
|
48
|
+
/** local 截点文件正文 ⇒ T0(epoch 毫秒);读不出时刻 ⇒ `undefined`(调用方决定拒形:准入点名文件拒、M46 的腿拒并给「删掉再起」)。 */
|
|
49
|
+
export declare function skillExemptionCutoffOfText(text: string): number | undefined;
|
|
50
|
+
/** 写截点文件(原子、`required`:目录项没证落盘也算没写成 ⇒ 抛)。本车道截点文件唯一的写口:准入的锁内一步与 M46 的腿同调。 */
|
|
51
|
+
export declare function writeLocalSkillExemptionCutoff(path: string, cutoffMs: number): void;
|
|
52
|
+
/**
|
|
53
|
+
* 截点之前的 `Skill` 行所在的会话数(`cutoffMs` 缺席 ⇒ 任一 `Skill` 行都算):逐只日志经店的唯一读者 {@link readExemptionLog} 重放(同一套撤销 / 首次放行读法);
|
|
54
|
+
* 闸合上的日志不算(店对那只会话拒读、照问)。坏行的披露走 `warn`(缺席 ⇒ 日志接缝;同一次起服里店的 hydrate 会再披露一次)。
|
|
55
|
+
*/
|
|
56
|
+
export declare function localSkillExemptionSessionsBefore(root: string, cutoffMs: number | undefined, warn?: Logger["warn"]): number;
|
|
57
|
+
/** 豁免日志目录的指纹(文件名 · 字节数 · 修改时刻;按名排序)—— 准入与锁内「没动」核对比同一只(锁内不再重放日志)。 */
|
|
58
|
+
export declare function exemptionLogFingerprints(root: string): string[];
|
|
59
|
+
/** 截点在 local 上的动作(准入判、锁内做):`lay` = 截点缺席,落「此刻」;`none` = 不写。 */
|
|
60
|
+
export type SkillExemptionCutoffAction = "none" | "lay";
|
|
61
|
+
/** **落截点**(锁内;准入的读数核过之后、抬引擎版本高水位之前;唯一调用点 = 数据根准入的锁内一步)。写不进 ⇒ 抛(抬之前拒)。 */
|
|
62
|
+
export declare function settleLocalSkillExemptionCutoff(physicalRoot: string, action: SkillExemptionCutoffAction, now?: () => number): void;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=approval-exemption-skill-cutoff.d.ts.map
|