@sema-agent/server 7.145.0 → 7.147.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 +876 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +374 -99
- package/deploy/facts/CHANGES.json +25 -0
- package/deploy/facts/README.md +57 -0
- package/deploy/facts/lanes.json +61 -0
- package/deploy/facts/lanes.schema.json +57 -0
- package/deploy/facts/sandbox-rbac.json +113 -0
- package/deploy/facts/sandbox-rbac.schema.json +74 -0
- package/deploy/facts/sealed-key.json +9 -0
- package/deploy/facts/sealed-key.schema.json +52 -0
- package/deploy/sema-up/README.md +2 -2
- package/deploy/sema-up/chart/templates/_helpers.tpl +41 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +9 -4
- package/deploy/sema-up/chart/templates/server.yaml +9 -4
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +2 -1
- package/deploy/sema-up/lib/flagshape.sh +4 -0
- package/deploy/sema-up/lib/lanes.json +2 -5
- package/deploy/sema-up/sema-up.sh +12 -9
- package/deploy/sema-up/stack/compose.yaml +5 -4
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +34 -17
- package/dist/adoption/import-limits.d.ts +6 -0
- package/dist/adoption/import-limits.js +7 -0
- package/dist/adoption/import.d.ts +62 -0
- package/dist/adoption/import.js +107 -0
- package/dist/adoption/wire.d.ts +52 -0
- package/dist/adoption/wire.js +9 -0
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +7 -16
- package/dist/approval-card.js +0 -4
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-gate-currency.js +1 -1
- package/dist/approval-reconciler.d.ts +1 -1
- package/dist/approval.d.ts +3 -3
- package/dist/audit.js +2 -2
- package/dist/bench/s1/live-deps.js +3 -1
- package/dist/boot/crash-last.js +2 -1
- package/dist/boot/deployment-mods.d.ts +11 -1
- package/dist/boot/deployment-mods.js +15 -2
- package/dist/boot/device-lane.js +7 -5
- package/dist/boot/engine-lease.d.ts +195 -22
- package/dist/boot/engine-lease.js +146 -20
- package/dist/boot/execution-env.d.ts +5 -0
- package/dist/boot/execution-env.js +57 -33
- package/dist/boot/execution-lane.d.ts +37 -9
- package/dist/boot/execution-lane.js +74 -20
- package/dist/boot/exit-boundary.d.ts +50 -0
- package/dist/boot/exit-boundary.js +32 -0
- package/dist/boot/exit-last.d.ts +20 -4
- package/dist/boot/exit-last.js +23 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/governance-seams.js +1 -0
- package/dist/boot/leader.js +1 -1
- package/dist/boot/memory-boundary.d.ts +11 -11
- package/dist/boot/memory-boundary.js +3 -3
- package/dist/boot/memory-consolidation.d.ts +42 -41
- package/dist/boot/memory-consolidation.js +26 -28
- package/dist/boot/org-memory.js +3 -2
- package/dist/boot/parked-revive-gate.d.ts +1 -1
- package/dist/boot/parked-revive-gate.js +1 -1
- package/dist/boot/reapers.d.ts +12 -4
- package/dist/boot/reapers.js +40 -16
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +126 -123
- package/dist/boot/retention-lane.d.ts +4 -42
- package/dist/boot/runner-deps.js +1 -1
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +11 -3
- package/dist/boot/shutdown.js +27 -9
- package/dist/boot/stage-01-config.d.ts +1 -1
- package/dist/boot/stage-01-config.js +7 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
- package/dist/boot/stage-02-web-admin-pull.js +10 -8
- package/dist/boot/stage-03-store-backend.d.ts +2 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +2 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -1
- package/dist/boot/stage-05-execution-env.js +6 -6
- package/dist/boot/stage-06-runners.d.ts +5 -2
- package/dist/boot/stage-06-runners.js +12 -13
- package/dist/boot/stage-07-capability-layer.d.ts +5 -2
- package/dist/boot/stage-07-capability-layer.js +7 -7
- package/dist/boot/stage-08-reapers.d.ts +5 -2
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +6 -2
- package/dist/boot/stage-10-http-server.d.ts +6 -2
- package/dist/boot/stage-10-http-server.js +5 -3
- package/dist/boot/stores.d.ts +10 -0
- package/dist/boot/stores.js +53 -26
- package/dist/boot/web-admin.js +3 -3
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +6 -2
- package/dist/capabilities/composite-members.d.ts +4 -1
- package/dist/capabilities/composite-members.js +4 -1
- package/dist/capabilities/execution-lane.d.ts +7 -7
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +1 -1
- package/dist/capabilities/scenarios.d.ts +34 -20
- package/dist/capabilities/scenarios.js +13 -9
- package/dist/capabilities/settings-contract.d.ts +29 -0
- package/dist/capabilities/settings-contract.js +14 -0
- package/dist/capabilities/skills.d.ts +5 -5
- package/dist/capability-facts.d.ts +56 -1
- package/dist/capability-facts.js +59 -8
- package/dist/center-credential-renewer.js +3 -2
- package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
- package/dist/config-catalog.js +19 -9
- package/dist/config-invariants.d.ts +18 -3
- package/dist/config-invariants.js +36 -19
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-lkg.js +5 -6
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-provider.js +2 -0
- package/dist/config-types.d.ts +228 -185
- package/dist/config.d.ts +74 -6
- package/dist/config.js +146 -64
- package/dist/degenerate-instrument.js +1 -1
- package/dist/deleted-session-ids.d.ts +19 -0
- package/dist/deleted-session-ids.js +26 -0
- package/dist/deploy-facts.d.ts +155 -0
- package/dist/deploy-facts.js +95 -0
- package/dist/deployment-shape.d.ts +21 -12
- package/dist/deployment-shape.js +24 -6
- package/dist/device-ws-hub.d.ts +48 -3
- package/dist/device-ws-hub.js +48 -2
- package/dist/env-facts.d.ts +7 -5
- package/dist/env-facts.js +10 -6
- package/dist/error-code-family.d.ts +35 -0
- package/dist/error-code-family.js +26 -0
- package/dist/execution-config-root.d.ts +5 -5
- package/dist/execution-config-root.js +5 -5
- package/dist/execution-env-purpose.d.ts +14 -0
- package/dist/execution-env-purpose.js +29 -0
- package/dist/execution-lane-caps.d.ts +49 -86
- package/dist/execution-lane-caps.js +52 -62
- package/dist/execution-placement.d.ts +18 -2
- package/dist/execution-placement.js +19 -0
- package/dist/file-history-disclosure.d.ts +2 -2
- package/dist/fleet/drain-entry.d.ts +46 -3
- package/dist/fleet/drain-entry.js +6 -0
- package/dist/fleet/fleet-bus.d.ts +2 -1
- package/dist/fleet/serving-lease.js +3 -4
- package/dist/history-anchor.d.ts +22 -0
- package/dist/history-anchor.js +14 -0
- package/dist/hooks/branch-transcript.d.ts +1 -1
- package/dist/hooks/branch-transcript.js +1 -0
- package/dist/hooks/classic-stations.d.ts +25 -8
- package/dist/hooks/classic-stations.js +29 -3
- package/dist/hooks/command-spawn.d.ts +1 -4
- package/dist/hooks/command-spawn.js +0 -11
- package/dist/hooks/hook-runner.d.ts +85 -24
- package/dist/hooks/hook-runner.js +326 -109
- package/dist/hooks/hook-source.d.ts +14 -2
- package/dist/hooks/hook-source.js +8 -0
- package/dist/http/active-run-conflict.d.ts +1 -1
- package/dist/http/active-run-conflict.js +1 -1
- package/dist/http/admission.js +11 -1
- package/dist/http/approval-sweeps.d.ts +2 -5
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/checkpoint-ctx.d.ts +76 -71
- package/dist/http/checkpoint-ctx.js +40 -40
- package/dist/http/claim-latency.d.ts +10 -0
- package/dist/http/claim-latency.js +12 -0
- package/dist/http/dispatch.js +19 -3
- package/dist/http/durable-run-leg.d.ts +5 -0
- package/dist/http/durable-run-leg.js +3 -1
- package/dist/http/execution-context.d.ts +7 -1
- package/dist/http/execution-context.js +13 -0
- package/dist/http/health-self-report.d.ts +6 -2
- package/dist/http/health-self-report.js +3 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +5 -15
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
- package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
- package/dist/http/memory-store-refusal-reply.d.ts +3 -3
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +7 -4
- package/dist/http/principal-gate.d.ts +28 -16
- package/dist/http/principal-gate.js +10 -19
- package/dist/http/request-guards.d.ts +2 -2
- package/dist/http/request-guards.js +5 -5
- package/dist/http/resume-legs.d.ts +29 -10
- package/dist/http/resume-legs.js +94 -56
- package/dist/http/rewind-files-reply.d.ts +34 -0
- package/dist/http/rewind-files-reply.js +36 -0
- package/dist/http/route-ctx.d.ts +43 -26
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/adoption.d.ts +11 -0
- package/dist/http/routes/adoption.js +80 -6
- package/dist/http/routes/agents-roster.js +1 -0
- package/dist/http/routes/approvals-assistant.js +7 -26
- package/dist/http/routes/background.js +1 -0
- package/dist/http/routes/capabilities.js +12 -3
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +9 -14
- package/dist/http/routes/diagnostics.js +10 -20
- package/dist/http/routes/engine.d.ts +31 -0
- package/dist/http/routes/engine.js +81 -0
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-consolidation.js +3 -5
- package/dist/http/routes/memory-origin.d.ts +2 -2
- package/dist/http/routes/memory-origin.js +2 -4
- package/dist/http/routes/memory-policy.js +5 -1
- package/dist/http/routes/notify-wake.js +2 -1
- package/dist/http/routes/observability.js +3 -6
- package/dist/http/routes/projects.d.ts +70 -0
- package/dist/http/routes/projects.js +86 -0
- package/dist/http/routes/rules.js +30 -2
- package/dist/http/routes/runs.js +15 -11
- package/dist/http/routes/session-sync.js +39 -35
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +7 -1
- package/dist/http/routes/sessions.js +108 -2
- package/dist/http/routes/tasks.js +32 -8
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/run-concurrency-cap.d.ts +86 -0
- package/dist/http/run-concurrency-cap.js +54 -0
- package/dist/http/server.d.ts +31 -14
- package/dist/http/server.js +29 -3
- package/dist/http/stored-body-replay.d.ts +12 -7
- package/dist/http/stored-body-replay.js +28 -5
- package/dist/http/wire-types.d.ts +27 -13
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/instruction-source-notice.d.ts +1 -1
- package/dist/json-body-limit.d.ts +8 -0
- package/dist/json-body-limit.js +2 -0
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/local-data-root.d.ts +2 -2
- package/dist/memory-embedder-reembed.d.ts +38 -0
- package/dist/memory-embedder-reembed.js +20 -0
- package/dist/memory-incident-sink.d.ts +0 -28
- package/dist/memory-incident-sink.js +5 -0
- package/dist/memory-operator-faces.d.ts +9 -4
- package/dist/memory-scope-stores.d.ts +9 -7
- package/dist/memory-scope-stores.js +3 -14
- package/dist/memory-scope.d.ts +38 -2
- package/dist/memory-scope.js +33 -2
- package/dist/memory-store-refusal.d.ts +17 -4
- package/dist/memory-store-refusal.js +1 -1
- package/dist/memory-sync-client.d.ts +2 -0
- package/dist/memory-sync-client.js +13 -11
- package/dist/memory-sync.js +1 -1
- package/dist/model-compat.d.ts +35 -21
- package/dist/model-compat.js +49 -21
- package/dist/model-entry-refusal.d.ts +11 -1
- package/dist/model-entry-refusal.js +7 -0
- package/dist/namespaced-rule-name.d.ts +18 -1
- package/dist/namespaced-rule-name.js +12 -0
- package/dist/net-address.d.ts +53 -0
- package/dist/net-address.js +111 -0
- package/dist/observability/fail-open.d.ts +29 -17
- package/dist/observability/fail-open.js +29 -17
- package/dist/observability/metrics.d.ts +2 -0
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/secret-env-scrub.d.ts +30 -4
- package/dist/observability/secret-env-scrub.js +15 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
- package/dist/orchestration/workflow-agent-session-index.js +1 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
- package/dist/orchestration/workflow-completion-inbox.js +63 -45
- package/dist/orchestration/workflow-notify-journal.js +2 -3
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +5 -2
- package/dist/org-memory-admission.js +25 -10
- package/dist/parked-decide.d.ts +33 -26
- package/dist/parked-decide.js +36 -44
- package/dist/peer-directory.d.ts +6 -12
- package/dist/peer-directory.js +5 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +37 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
- package/dist/plugins/approval-ask-store-memory.js +11 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -1
- package/dist/plugins/blob-backend.d.ts +38 -195
- package/dist/plugins/blob-backend.js +33 -229
- package/dist/plugins/caching-session-store.d.ts +12 -5
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
- package/dist/plugins/checkpoint-index-columns.js +3 -2
- package/dist/plugins/checkpoint-store-face.d.ts +426 -0
- package/dist/plugins/checkpoint-store-face.js +152 -0
- package/dist/plugins/device-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.js +5 -10
- package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
- package/dist/plugins/execution-lane-rename-m40.js +10 -0
- package/dist/plugins/execution-placement-sql.d.ts +63 -88
- package/dist/plugins/execution-placement-sql.js +94 -54
- package/dist/plugins/file-run-store.d.ts +26 -18
- package/dist/plugins/file-run-store.js +64 -75
- package/dist/plugins/fork-routing-session-store.d.ts +6 -2
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/imported-layer-root-retirement.d.ts +22 -11
- package/dist/plugins/imported-layer-root-retirement.js +4 -8
- package/dist/plugins/inbox-payload-column.d.ts +14 -0
- package/dist/plugins/inbox-payload-column.js +13 -0
- package/dist/plugins/local-checkpoint-store.d.ts +7 -2
- package/dist/plugins/local-checkpoint-store.js +13 -8
- package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
- package/dist/plugins/local-data-dir-modes-m39.js +182 -0
- package/dist/plugins/local-engine-high-water.d.ts +11 -0
- package/dist/plugins/local-engine-high-water.js +59 -0
- package/dist/plugins/local-session-store.d.ts +119 -30
- package/dist/plugins/local-session-store.js +156 -53
- package/dist/plugins/local-task-attachment-store.d.ts +2 -0
- package/dist/plugins/local-task-attachment-store.js +10 -11
- package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
- package/dist/plugins/memory-embedder-fingerprint.js +52 -12
- package/dist/plugins/memory-embedder.d.ts +1 -1
- package/dist/plugins/memory-embedder.js +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +30 -6
- package/dist/plugins/memory-engine-pg.js +96 -214
- package/dist/plugins/memory-engine-sql-apply.d.ts +130 -0
- package/dist/plugins/memory-engine-sql-apply.js +358 -0
- package/dist/plugins/memory-engine-tidb.d.ts +38 -9
- package/dist/plugins/memory-engine-tidb.js +99 -230
- package/dist/plugins/memory-key-guards.d.ts +1 -1
- package/dist/plugins/memory-origin-law.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +169 -83
- package/dist/plugins/one-time-migrations.js +295 -235
- package/dist/plugins/owner-only-file-mode.d.ts +29 -0
- package/dist/plugins/owner-only-file-mode.js +141 -0
- package/dist/plugins/permission-rule-store-file.d.ts +17 -3
- package/dist/plugins/permission-rule-store-file.js +20 -1
- package/dist/plugins/pg-pool.d.ts +2 -1
- package/dist/plugins/pg-pool.js +12 -5
- package/dist/plugins/release-version.d.ts +20 -0
- package/dist/plugins/release-version.js +28 -0
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +39 -11
- package/dist/plugins/remote-env-e2b.d.ts +12 -3
- package/dist/plugins/remote-env-e2b.js +6 -4
- package/dist/plugins/remote-env-host.d.ts +9 -1
- package/dist/plugins/remote-env-host.js +6 -5
- package/dist/plugins/remote-env-k8s.d.ts +5 -2
- package/dist/plugins/remote-env-k8s.js +15 -4
- package/dist/plugins/remote-env-local-docker.d.ts +4 -1
- package/dist/plugins/remote-env-local-docker.js +3 -3
- package/dist/plugins/remote-env-ssh.d.ts +8 -2
- package/dist/plugins/remote-env-ssh.js +26 -24
- package/dist/plugins/remote-shell.d.ts +59 -30
- package/dist/plugins/remote-shell.js +175 -62
- package/dist/plugins/retention-declaration.d.ts +37 -0
- package/dist/plugins/retention-declaration.js +9 -0
- package/dist/plugins/retention-deployment.d.ts +126 -0
- package/dist/plugins/retention-deployment.js +88 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
- package/dist/plugins/retention-lane-store-sql.js +103 -1
- package/dist/plugins/retention-sql.d.ts +29 -0
- package/dist/plugins/retention-sql.js +8 -0
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +0 -6
- package/dist/plugins/schema-consistency.js +1 -2
- package/dist/plugins/schema-ensure-legs.d.ts +1 -1
- package/dist/plugins/schema-ensure-legs.js +13 -3
- package/dist/plugins/session-ext-table.d.ts +74 -0
- package/dist/plugins/session-ext-table.js +121 -0
- package/dist/plugins/session-fork.d.ts +31 -9
- package/dist/plugins/session-fork.js +3 -2
- package/dist/plugins/session-placement.d.ts +4 -2
- package/dist/plugins/session-row-sql.d.ts +8 -7
- package/dist/plugins/session-row-sql.js +15 -7
- package/dist/plugins/session-store-sql.d.ts +131 -0
- package/dist/plugins/session-store-sql.js +298 -0
- package/dist/plugins/session-workspace-cell.d.ts +2 -2
- package/dist/plugins/session-workspace-cell.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
- package/dist/plugins/shared-memory-store-sql.js +13 -13
- package/dist/plugins/snapshot-bucket-presence.js +1 -1
- package/dist/plugins/sql-driver.d.ts +23 -7
- package/dist/plugins/sql-driver.js +41 -8
- package/dist/plugins/sql-errors.d.ts +5 -2
- package/dist/plugins/sql-errors.js +4 -0
- package/dist/plugins/sql-json-column.d.ts +5 -1
- package/dist/plugins/store-backend.d.ts +46 -16
- package/dist/plugins/store-backend.js +192 -69
- package/dist/plugins/store-contracts.d.ts +10 -13
- package/dist/plugins/store-contracts.js +1 -9
- package/dist/plugins/store-sweep.d.ts +63 -0
- package/dist/plugins/store-sweep.js +48 -0
- package/dist/plugins/task-attachment-store.d.ts +6 -8
- package/dist/plugins/task-attachment-store.js +15 -10
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/text-column-capacity.d.ts +21 -0
- package/dist/plugins/text-column-capacity.js +5 -0
- package/dist/plugins/tidb-pool.d.ts +3 -2
- package/dist/plugins/tidb-pool.js +20 -32
- package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
- package/dist/prompt-screen.d.ts +6 -9
- package/dist/prompt-screen.js +2 -5
- package/dist/read-face-posture.d.ts +6 -6
- package/dist/read-face-posture.js +2 -2
- package/dist/request-value-closure.d.ts +5 -5
- package/dist/request-value-closure.js +1 -1
- package/dist/rules-consent.d.ts +48 -27
- package/dist/rules-consent.js +147 -23
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/run-local.js +17 -13
- package/dist/runs.d.ts +48 -30
- package/dist/runs.js +27 -17
- package/dist/runtime-caps-resolver.d.ts +15 -8
- package/dist/runtime-caps-resolver.js +14 -10
- package/dist/sandbox-egress-policy.js +6 -11
- package/dist/sandbox-rbac-rules.d.ts +88 -0
- package/dist/sandbox-rbac-rules.js +80 -0
- package/dist/sealed-key-layout.d.ts +16 -0
- package/dist/sealed-key-layout.js +3 -0
- package/dist/sealed-key.js +8 -6
- package/dist/security.d.ts +43 -9
- package/dist/security.js +9 -2
- package/dist/sema-config-dir.js +2 -2
- package/dist/server-secret-env.d.ts +2 -0
- package/dist/service-version.d.ts +2 -1
- package/dist/service-version.js +2 -2
- package/dist/session-error-wire.d.ts +1 -1
- package/dist/session-incarnation.d.ts +8 -5
- package/dist/session-notify-door.d.ts +5 -3
- package/dist/session-resident-background.d.ts +110 -0
- package/dist/session-resident-background.js +88 -0
- package/dist/session-row.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +53 -14
- package/dist/session-sync-kernel.js +70 -1
- package/dist/session-sync.d.ts +5 -3
- package/dist/session-workspace.d.ts +12 -2
- package/dist/session-workspace.js +6 -0
- package/dist/sighup-idle.d.ts +9 -7
- package/dist/sighup-idle.js +4 -5
- package/dist/spec-fields.d.ts +16 -0
- package/dist/spec-fields.js +7 -0
- package/dist/store-posture.d.ts +2 -1
- package/dist/stored-request-env-credentials-m38.d.ts +3 -0
- package/dist/stored-request-env-credentials-m38.js +8 -0
- package/dist/stored-request-hooks-m20.d.ts +3 -2
- package/dist/stored-request-hooks-m20.js +19 -14
- package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
- package/dist/stores-sql/blob-index-sql.d.ts +148 -0
- package/dist/stores-sql/blob-index-sql.js +154 -0
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +14 -428
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +43 -220
- package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
- package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
- package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
- package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +27 -67
- package/dist/{plugins → stores-sql}/pg-session-storage.js +82 -207
- package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
- package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
- package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
- package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
- package/dist/stores-sql/session-write-hooks.d.ts +59 -0
- package/dist/stores-sql/session-write-hooks.js +2 -0
- package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
- package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
- package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +35 -112
- package/dist/{plugins → stores-sql}/tidb-session-store.js +73 -169
- package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +3 -3
- package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
- package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
- package/dist/stores-sql/windowed-session-storage.js +61 -0
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
- package/dist/task-a2a.d.ts +7 -1
- package/dist/task-a2a.js +15 -14
- package/dist/task-cwd.d.ts +11 -3
- package/dist/task-cwd.js +17 -1
- package/dist/task-mcp.d.ts +10 -2
- package/dist/task-mcp.js +13 -16
- package/dist/task-settings.d.ts +68 -8
- package/dist/task-settings.js +63 -6
- package/dist/tool-approval.d.ts +23 -10
- package/dist/tool-approval.js +10 -6
- package/dist/trace/core-keyset-guard.d.ts +17 -10
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +29 -1
- package/dist/trace/exit-seat.js +4 -0
- package/dist/trace/project.d.ts +33 -16
- package/dist/trace/project.js +21 -9
- package/dist/trace/redact.d.ts +13 -2
- package/dist/trace/redact.js +347 -78
- package/dist/trace/self-minted-wire.d.ts +587 -16
- package/dist/trace/self-minted-wire.js +215 -9
- package/dist/trace/sema-provenance.d.ts +45 -41
- package/dist/trace/sema-provenance.js +81 -10
- package/dist/trace/task-notification-facets.d.ts +70 -2
- package/dist/trace/task-notification-facets.js +71 -1
- package/dist/trace/wire-projection-faces.d.ts +39 -3
- package/dist/trace/wire-projection-faces.js +27 -2
- package/dist/unread-request-members.d.ts +66 -0
- package/dist/unread-request-members.js +41 -0
- package/dist/usage-analytics.d.ts +4 -0
- package/dist/user-input-ledger.d.ts +2 -2
- package/dist/web-admin-client/apply-effective.js +22 -26
- package/dist/web-admin-client/candidate-gate.d.ts +35 -3
- package/dist/web-admin-client/candidate-gate.js +53 -5
- package/dist/web-admin-client/center-request.d.ts +4 -1
- package/dist/web-admin-client/center-request.js +2 -1
- package/dist/web-admin-client/effective-keys.js +0 -1
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/http-client.d.ts +1 -0
- package/dist/web-admin-client/http-client.js +17 -9
- package/dist/web-admin-client/restart-signal.js +5 -2
- package/dist/web-admin-client/skills-mcp.d.ts +20 -6
- package/dist/web-admin-client/skills-mcp.js +26 -21
- package/dist/web-admin-client/types.d.ts +34 -49
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
- package/package.json +22 -13
- package/scripts/drain-check-local.mjs +8 -55
- package/scripts/drain-check.mysql.sql +3 -40
- package/scripts/drain-check.pg.sql +3 -40
- package/skills/update-config.md +1 -1
- package/wire-changes/server@7.146.0.json +3221 -0
- package/wire-changes/server@7.147.0.json +813 -0
- package/dist/approval-batch-census.d.ts +0 -27
- package/dist/approval-batch-census.js +0 -27
|
@@ -23,14 +23,84 @@
|
|
|
23
23
|
* 自增判据在**应用层**算,因为它同时要产出返回给调用方的 token);
|
|
24
24
|
* - 事务动词:只有 `begin()` 一个;读语义的判据在 {@link SqlTxConn.begin} 的 `@contract txn.read-semantics`
|
|
25
25
|
* (本店唯一的读是 `acquire` 的租约行 `FOR UPDATE` —— 锁读在两引擎都是当前读)。
|
|
26
|
-
* - schema
|
|
27
|
-
* `
|
|
26
|
+
* - schema 属主:**审计 / hold / 租约三张表由本文件建**(`TIDB_RETENTION_LANE_STATEMENTS` / `PG_RETENTION_LANE_SCHEMA`,
|
|
27
|
+
* 中央 ensure 组合);墓碑表是执行器的(`stores-sql/retention-store-sql.ts`)。「一张表恰好一个 DDL 属主」(db-gate.ts 顶注
|
|
28
28
|
* 的实测结论:第二个属主的 `IF NOT EXISTS` 会静默吞掉列/索引差异)。
|
|
29
|
+
* - 执行器破坏性事务里的两句也写在这里(`lockHoldSentinel` 首句 / `appendDestructiveAuditRow` 末句):hold / 审计是**调度方语义**,
|
|
30
|
+
* 经执行器的事务内钩(K4)参与,不住在执行器里。
|
|
29
31
|
*/
|
|
30
32
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
31
33
|
import type { Pool as PgPool } from "pg";
|
|
32
|
-
import { type SqlDriver, type SqlExec } from "./sql-driver.js";
|
|
33
|
-
import {
|
|
34
|
+
import { type SqlDialect, type SqlDriver, type SqlExec } from "./sql-driver.js";
|
|
35
|
+
import type { IndexSpec } from "./ensure-index.js";
|
|
36
|
+
import type { RetentionMode } from "../config-types.js";
|
|
37
|
+
/** 追加式审计表(设计稿 §6)。 */
|
|
38
|
+
export declare const RETENTION_AUDIT_TABLE = "retention_audit";
|
|
39
|
+
/** per-domain 法务保留标记(设计稿 §5)——**行在 = 该域整体冻结**。 */
|
|
40
|
+
export declare const RETENTION_HOLD_TABLE = "retention_hold";
|
|
41
|
+
/** sweep 互斥的单行租约表(设计稿 §3)。表建在车1(schema 一次齐),抢/续租的逻辑归车2。 */
|
|
42
|
+
export declare const RETENTION_LEASE_TABLE = "retention_lease";
|
|
43
|
+
/**
|
|
44
|
+
* 审计行的 `action` 闭集(设计稿 §6 逐字)。**破坏性三词**在执行器的删除事务里由 audit 钩写({@link appendDestructiveAuditRow});其余五词
|
|
45
|
+
* (`audit_only` / `skipped_legal_hold` / `failed` / `hold_placed` / `hold_released`)属主是 lane/路由(车2)
|
|
46
|
+
* —— 它们没有「删了没记」的窗口。词表与审计表同住本文件:一份真源。
|
|
47
|
+
*/
|
|
48
|
+
export type RetentionAuditAction = "expired_checkpoints" | "deleted_sessions" | "deleted_tool_results" | "audit_only" | "skipped_legal_hold" | "failed" | "hold_placed" | "hold_released";
|
|
49
|
+
/** MySQL 协议方言的建表语句(本模块是这三张表的唯一 DDL 属主;由 `tidb-pool.ts` 展开进中央 `SCHEMA_STATEMENTS`,紧挨执行器的墓碑表那一句、次序不变)。 */
|
|
50
|
+
export declare const TIDB_RETENTION_LANE_STATEMENTS: readonly string[];
|
|
51
|
+
/** PG 方言的建表语句(MySQL 孪生的逐条翻译:AUTO_INCREMENT→BIGSERIAL,逐列 `COLLATE "C"`,内联 KEY→独立
|
|
52
|
+
* CREATE INDEX)。语义逐字见 MySQL 孪生的行内注,此处不复述(两份注释迟早分叉)。由 `pg-pool.ts` 的中央 `ensurePgSchema` 组合(紧挨墓碑表那一句)。 */
|
|
53
|
+
export declare const PG_RETENTION_LANE_SCHEMA: readonly string[];
|
|
54
|
+
/** [ref]:三张表的索引**声明**(两方言共用一份)。PG 侧由 `pg-pool.ts` 的中央 ensure 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
55
|
+
export declare const RETENTION_LANE_INDEXES: readonly IndexSpec[];
|
|
56
|
+
/**
|
|
57
|
+
* 一次破坏性留存调用的**审计上下文**——判定时点的三格,由调用方(lane)随每次破坏性调用交给组合座(`plugins/store-backend.ts`
|
|
58
|
+
* `createSqlRetentionExecutor`),组合座把它绑进**这一次**调用的 audit 钩(执行器入参只有 core 的 `{domain, cutoffMs}`,不认识它)。
|
|
59
|
+
*
|
|
60
|
+
* 🔴 为什么必须由调用方传、而不是店自己去读配置:`mode`/`policyDays` 是**判定时点**的事实(策略是部署
|
|
61
|
+
* env、模式是灰度旋钮,两者都会在两次 sweep 之间被改),`fencingToken` 更是本轮租约的身份。店去现读
|
|
62
|
+
* 配置 = 审计行记的是「写这行的那一刻的配置」,而不是「按哪档删的」,那正好把审计的意义抹掉。
|
|
63
|
+
*/
|
|
64
|
+
export interface RetentionAuditContext {
|
|
65
|
+
/** 判定时点的灰度档。词表闭集(与 §4 同一张表);`audit-only` 档下 lane 不该调破坏性方法,但如果调了,
|
|
66
|
+
* 审计行会如实记下这个矛盾(而不是被悄悄改写成 enforce)。 */
|
|
67
|
+
mode: RetentionMode;
|
|
68
|
+
/** 判定时点的策略值(天)。 */
|
|
69
|
+
policyDays: number;
|
|
70
|
+
/** 本轮 sweep lease 的 fencing token(§3)。`null` = 调用方没有租约面(单机/测试);破坏性行仍会落
|
|
71
|
+
* 审计,只是这一位为空 —— 「没有轮次身份」本身也是审计要记的事实。 */
|
|
72
|
+
fencingToken: number | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 破坏性事务的**首句**(K4 `holdLock`):拿本域的互斥行锁,并读出「这个域是不是冻结中」(§5 F2 承重)。持有到提交,无复核。
|
|
76
|
+
*
|
|
77
|
+
* 两步,缺一不可:
|
|
78
|
+
* ① 幂等建一条 `held = 0` 的**哨兵行**(形 A,[ref]:MySQL `ON DUPLICATE KEY UPDATE domain = domain` /
|
|
79
|
+
* PG `ON CONFLICT DO NOTHING`)—— 它永远不会改写一条既存的 hold(两方言的这两个动词都只在缺行时
|
|
80
|
+
* 写),只保证**接下来那把行锁有东西可锁**;重复键取的是 **X** 锁,与 ② 的 `FOR UPDATE` 同锁模式
|
|
81
|
+
* (`INSERT IGNORE` 在这里取 S 再升 X = InnoDB 上两个并发 sweep 互等的死锁形,[ref]);
|
|
82
|
+
* ② `SELECT held … FOR UPDATE` —— 现在这行必定存在,于是锁真的拿到了。
|
|
83
|
+
*
|
|
84
|
+
* 🔴 为什么必须先造行(codex 交叉复审 R1-[high],验真后改):`FOR UPDATE` 锁不住缺席行(TiDB 无 gap
|
|
85
|
+
* lock;PG READ COMMITTED 同样)。presence 形(「行在 = 冻结」)下,operator 的 PUT 与本事务可以**同时**
|
|
86
|
+
* 都读到「没有 hold」,PUT 提交返回成功之后本事务照删不误 —— 设计稿 §5 声称由行锁给出的串行化在那一形
|
|
87
|
+
* 上根本不存在。哨兵行把 hold 的写点与删除的读点压到**同一把行锁**上,那句承诺才成立。
|
|
88
|
+
* ⚠️ PUT/DELETE hold 必须走**同一 PK 的 upsert 改 `held` 列**(本模块 `setHoldOn`,不是 INSERT/DELETE 行),
|
|
89
|
+
* 否则这把锁又会退回缺席形。
|
|
90
|
+
*/
|
|
91
|
+
export declare function lockHoldSentinel(txn: SqlExec, dialect: SqlDialect, domain: string): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* 破坏性审计行的**唯一**写点 —— 执行器事务里提交前的**末句**(K4 `audit`;§6 F5:与删除同一个事务,先删后补记 = 崩在中间会留下无证删除)。
|
|
94
|
+
* 三个数字 = 这一次调用的回执(执行器交给 audit 钩的那一份),判定时点三格 = 这一次调用的 {@link RetentionAuditContext}。
|
|
95
|
+
*/
|
|
96
|
+
export declare function appendDestructiveAuditRow(txn: SqlExec, dialect: SqlDialect, row: {
|
|
97
|
+
domain: string;
|
|
98
|
+
action: Extract<RetentionAuditAction, "expired_checkpoints" | "deleted_sessions" | "deleted_tool_results">;
|
|
99
|
+
audit: RetentionAuditContext;
|
|
100
|
+
deleted: number;
|
|
101
|
+
skipped: number;
|
|
102
|
+
tombstones: number;
|
|
103
|
+
}): Promise<void>;
|
|
34
104
|
/** 审计读面的单页上界(与 roster 名册窗同姿势:读面要有界)。 */
|
|
35
105
|
export declare const RETENTION_AUDIT_MAX_LIMIT = 200;
|
|
36
106
|
/** 审计读面的缺省页大小。 */
|
|
@@ -1,5 +1,107 @@
|
|
|
1
1
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
2
|
-
|
|
2
|
+
export const RETENTION_AUDIT_TABLE = "retention_audit";
|
|
3
|
+
export const RETENTION_HOLD_TABLE = "retention_hold";
|
|
4
|
+
export const RETENTION_LEASE_TABLE = "retention_lease";
|
|
5
|
+
export const TIDB_RETENTION_LANE_STATEMENTS = [
|
|
6
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_AUDIT_TABLE} (
|
|
7
|
+
id BIGINT NOT NULL AUTO_INCREMENT,
|
|
8
|
+
domain VARCHAR(190) NOT NULL,
|
|
9
|
+
-- action:闭集词表见 RetentionAuditAction。前三词 = 破坏性行(本店写),其余 = lane/路由写。
|
|
10
|
+
action VARCHAR(32) NOT NULL,
|
|
11
|
+
-- mode:判定时点的灰度档(audit-only | enforce)——「按哪档跑的」必须与计数同行,否则事后无法解释
|
|
12
|
+
-- 一行 deleted=0 是"没有候选"还是"当时是 audit-only"。
|
|
13
|
+
mode VARCHAR(16) NOT NULL,
|
|
14
|
+
-- policy_days:判定时点的策略值(按哪版策略删的)。策略是部署 env,会被改;计数离开它就没有意义。
|
|
15
|
+
policy_days INT NOT NULL,
|
|
16
|
+
-- fencing_token:本轮 sweep lease 的 fencing token(§3;**破坏性行必填**,非破坏行可空)。丢租后
|
|
17
|
+
-- 在飞的旧轮仍可能提交一条审计行,靠这一位判别新旧轮。
|
|
18
|
+
fencing_token BIGINT NULL,
|
|
19
|
+
-- 三数字 = RetentionReceipt(audit_only 行 = previewRetention 的三候选数)。
|
|
20
|
+
deleted INT NOT NULL DEFAULT 0,
|
|
21
|
+
skipped INT NOT NULL DEFAULT 0,
|
|
22
|
+
tombstones INT NOT NULL DEFAULT 0,
|
|
23
|
+
executed_at_ms BIGINT NOT NULL,
|
|
24
|
+
error TEXT NULL,
|
|
25
|
+
PRIMARY KEY (id),
|
|
26
|
+
KEY idx_retention_audit_domain (domain, id),
|
|
27
|
+
KEY idx_retention_audit_executed (executed_at_ms)
|
|
28
|
+
) COLLATE utf8mb4_bin`,
|
|
29
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_HOLD_TABLE} (
|
|
30
|
+
domain VARCHAR(190) NOT NULL,
|
|
31
|
+
-- held:**1 = 冻结中,0 = 只是一把锁**。
|
|
32
|
+
-- 🔴 为什么冻结不能用「行在/行不在」表达(codex 对抗复审 R1-[high],验真后改的**承重**形):
|
|
33
|
+
-- 设计稿 §5 声称「PUT hold 的 commit 一旦完成,其后任何删除事务都必然看见它,串行化由行锁给出」——
|
|
34
|
+
-- 而 SELECT … FOR UPDATE **锁不住一条不存在的行**(TiDB 无 gap lock;PG 的 READ COMMITTED 同样
|
|
35
|
+
-- 不锁缺席行)。presence 形下两边都读到「没有 hold」是完全可能的,于是 operator 拿到成功回执之后
|
|
36
|
+
-- 数据仍被删 —— 那正是 F2 要消灭的那件事,只是换了个位置复发。
|
|
37
|
+
-- ⇒ 行**恒存在**(破坏性事务首步幂等建一条 held=0 的哨兵),冻结与否写在这一列上。
|
|
38
|
+
-- 于是 hold 的放置(同一 PK 的 upsert)与三只破坏性事务抢的是**同一把行锁**,串行化由引擎给出:
|
|
39
|
+
-- PUT 提交完成 ⇒ 其后每一个破坏性事务的首读必见 held=1。放置/解除都必须走这一列(车2 交接件)。
|
|
40
|
+
held TINYINT(1) NOT NULL DEFAULT 0,
|
|
41
|
+
placed_by VARCHAR(190) NULL,
|
|
42
|
+
placed_at_ms BIGINT NULL,
|
|
43
|
+
note TEXT NULL,
|
|
44
|
+
PRIMARY KEY (domain)
|
|
45
|
+
) COLLATE utf8mb4_bin`,
|
|
46
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_LEASE_TABLE} (
|
|
47
|
+
-- singleton:恒 'x' 的单行键(全局唯一一只 sweep 租约)。用定值列而不是 id=1,是为了让"这张表只能有
|
|
48
|
+
-- 一行"写在**主键**上而不是写在注释里。
|
|
49
|
+
singleton CHAR(1) NOT NULL DEFAULT 'x',
|
|
50
|
+
holder VARCHAR(190) NOT NULL,
|
|
51
|
+
-- fencing_token:每次**抢租**(而非续租)自增;随本轮全部审计行走,旧轮的写因此可判别。
|
|
52
|
+
fencing_token BIGINT NOT NULL DEFAULT 0,
|
|
53
|
+
expires_at_ms BIGINT NOT NULL,
|
|
54
|
+
PRIMARY KEY (singleton)
|
|
55
|
+
) COLLATE utf8mb4_bin`,
|
|
56
|
+
];
|
|
57
|
+
export const PG_RETENTION_LANE_SCHEMA = [
|
|
58
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_AUDIT_TABLE} (
|
|
59
|
+
id BIGSERIAL,
|
|
60
|
+
domain VARCHAR(190) COLLATE "C" NOT NULL,
|
|
61
|
+
action VARCHAR(32) COLLATE "C" NOT NULL,
|
|
62
|
+
mode VARCHAR(16) COLLATE "C" NOT NULL,
|
|
63
|
+
policy_days INT NOT NULL,
|
|
64
|
+
fencing_token BIGINT NULL,
|
|
65
|
+
deleted INT NOT NULL DEFAULT 0,
|
|
66
|
+
skipped INT NOT NULL DEFAULT 0,
|
|
67
|
+
tombstones INT NOT NULL DEFAULT 0,
|
|
68
|
+
executed_at_ms BIGINT NOT NULL,
|
|
69
|
+
error TEXT COLLATE "C" NULL,
|
|
70
|
+
PRIMARY KEY (id)
|
|
71
|
+
)`,
|
|
72
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_HOLD_TABLE} (
|
|
73
|
+
domain VARCHAR(190) COLLATE "C" NOT NULL,
|
|
74
|
+
-- held:1 = 冻结中,0 = 只是那把域级互斥行锁的哨兵。完整判据(为什么 presence 形不成立)见 MySQL 孪生。
|
|
75
|
+
held SMALLINT NOT NULL DEFAULT 0,
|
|
76
|
+
placed_by VARCHAR(190) COLLATE "C" NULL,
|
|
77
|
+
placed_at_ms BIGINT NULL,
|
|
78
|
+
note TEXT COLLATE "C" NULL,
|
|
79
|
+
PRIMARY KEY (domain)
|
|
80
|
+
)`,
|
|
81
|
+
`CREATE TABLE IF NOT EXISTS ${RETENTION_LEASE_TABLE} (
|
|
82
|
+
singleton CHAR(1) COLLATE "C" NOT NULL DEFAULT 'x',
|
|
83
|
+
holder VARCHAR(190) COLLATE "C" NOT NULL,
|
|
84
|
+
fencing_token BIGINT NOT NULL DEFAULT 0,
|
|
85
|
+
expires_at_ms BIGINT NOT NULL,
|
|
86
|
+
PRIMARY KEY (singleton)
|
|
87
|
+
)`,
|
|
88
|
+
];
|
|
89
|
+
export const RETENTION_LANE_INDEXES = [
|
|
90
|
+
{ table: `${RETENTION_AUDIT_TABLE}`, name: "idx_retention_audit_domain", columns: ["domain", "id"] },
|
|
91
|
+
{ table: `${RETENTION_AUDIT_TABLE}`, name: "idx_retention_audit_executed", columns: ["executed_at_ms"] },
|
|
92
|
+
];
|
|
93
|
+
export async function lockHoldSentinel(txn, dialect, domain) {
|
|
94
|
+
const key = domain;
|
|
95
|
+
const q = (mysql, pg) => (dialect === "mysql" ? mysql : pg);
|
|
96
|
+
await txn.query(q(`INSERT INTO ${RETENTION_HOLD_TABLE} (domain, held, placed_by, placed_at_ms, note) VALUES (?,0,NULL,NULL,NULL) ON DUPLICATE KEY UPDATE domain = domain`, `INSERT INTO ${RETENTION_HOLD_TABLE} (domain, held, placed_by, placed_at_ms, note) VALUES ($1,0,NULL,NULL,NULL) ON CONFLICT (domain) DO NOTHING`), [key]);
|
|
97
|
+
const { rows } = await txn.query(q(`SELECT held FROM ${RETENTION_HOLD_TABLE} WHERE domain = ? FOR UPDATE`, `SELECT held FROM ${RETENTION_HOLD_TABLE} WHERE domain = $1 FOR UPDATE`), [key]);
|
|
98
|
+
return Number(rows[0]?.held ?? 0) === 1;
|
|
99
|
+
}
|
|
100
|
+
export async function appendDestructiveAuditRow(txn, dialect, row) {
|
|
101
|
+
await txn.query(dialect === "mysql"
|
|
102
|
+
? `INSERT INTO ${RETENTION_AUDIT_TABLE} (domain, action, mode, policy_days, fencing_token, deleted, skipped, tombstones, executed_at_ms) VALUES (?,?,?,?,?,?,?,?,?)`
|
|
103
|
+
: `INSERT INTO ${RETENTION_AUDIT_TABLE} (domain, action, mode, policy_days, fencing_token, deleted, skipped, tombstones, executed_at_ms) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`, [row.domain, row.action, row.audit.mode, row.audit.policyDays, row.audit.fencingToken, row.deleted, row.skipped, row.tombstones, Date.now()]);
|
|
104
|
+
}
|
|
3
105
|
export const RETENTION_AUDIT_MAX_LIMIT = 200;
|
|
4
106
|
export const RETENTION_AUDIT_DEFAULT_LIMIT = 50;
|
|
5
107
|
export class SqlRetentionLaneStore {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 托管留存的两只 SQL 谓词 —— 执行器(`stores-sql/retention-store-sql.ts`,引擎座表那一半)与部署的事务内钩(`plugins/retention-deployment.ts`,
|
|
3
|
+
* 部署表那一半)对**同一条域律**发谓词,只从这里取:一条律一个读法,两半不各写一份(分家的方向是多删或漏删)。
|
|
4
|
+
*
|
|
5
|
+
* 域 = 租户键:`COALESCE(session_meta.owner, '')` / `checkpoint.scope` 原样;**空串 `''` = 无主(anonymous/dev)桶**,谓词写成
|
|
6
|
+
* `(owner IS NULL OR owner = '')` —— 合并只发生在无主侧,永远伸不进一个真租户;拆成两个桶才会漏(NULL 那半永不被枚举)。
|
|
7
|
+
*/
|
|
8
|
+
import type { SqlDialect } from "./sql-driver.js";
|
|
9
|
+
/**
|
|
10
|
+
* 域谓词。**四种写法逐条写出来**(方言 × 有主/无主):
|
|
11
|
+
* · 有主:`col = ?` / `col = $n`;
|
|
12
|
+
* · 无主(域键 `""`):`(col IS NULL OR col = ?)` / `(col IS NULL OR col = $n)`。
|
|
13
|
+
* 🔴 两支的**占位符数量刻意相同**(无主支也绑一个 `""`):arity 一变,PG 的 `$n` 编号就会在同一条 SQL 的
|
|
14
|
+
* 后续参数上错位——那是一类只在某个域值上才复现的 bug,不许存在。
|
|
15
|
+
*/
|
|
16
|
+
export declare function retentionDomainWhere(dialect: SqlDialect, col: string, domain: string, pgIndex: number): {
|
|
17
|
+
sql: string;
|
|
18
|
+
params: unknown[];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* 多值集合谓词 —— **真方言分叉**(不是 SQL 文本差):MySQL 展开 N 个 `?`,PG 用**一枚**数组参数
|
|
22
|
+
* `= ANY($n::text[])`。占位符数量因此不同(N vs 1),这是先例(workflow-run-store-sql 的 reap)也是
|
|
23
|
+
* 必然:把 500 个 id 展开成 500 个 `$n` 会让语句文本随批量变形,PG 的预编译缓存跟着退化。
|
|
24
|
+
*/
|
|
25
|
+
export declare function retentionIdSet(dialect: SqlDialect, col: string, ids: readonly string[], pgIndex: number): {
|
|
26
|
+
sql: string;
|
|
27
|
+
params: unknown[];
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=retention-sql.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function retentionDomainWhere(dialect, col, domain, pgIndex) {
|
|
2
|
+
const ph = dialect === "mysql" ? "?" : `$${pgIndex}`;
|
|
3
|
+
return domain === "" ? { sql: `(${col} IS NULL OR ${col} = ${ph})`, params: [""] } : { sql: `${col} = ${ph}`, params: [domain] };
|
|
4
|
+
}
|
|
5
|
+
export function retentionIdSet(dialect, col, ids, pgIndex) {
|
|
6
|
+
return dialect === "mysql" ? { sql: `${col} IN (${ids.map(() => "?").join(",")})`, params: [...ids] } : { sql: `${col} = ANY($${pgIndex}::text[])`, params: [ids] };
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=retention-sql.js.map
|
|
@@ -6,7 +6,7 @@ import { pgSanitizeText } from "./pg-safe-json.js";
|
|
|
6
6
|
import { toIso as iso } from "./sql-row-helpers.js";
|
|
7
7
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
8
8
|
import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, readJsonObjectColumn, readNonNullJsonValueColumn } from "./sql-json-column.js";
|
|
9
|
-
import { RUN_HOLDER_DEATH_CODES, RUN_STALLED_ERROR,
|
|
9
|
+
import { RUN_HOLDER_DEATH_CODES, RUN_STALLED_ERROR, settledLegObservationOf } from "./store-contracts.js";
|
|
10
10
|
import { notifyRunTerminal, runTerminalLogLevel } from "../observability/run-terminal.js";
|
|
11
11
|
import { mysqlDriver, pgDriver, dialectJsonEncoder, SQL_DB_NOW_MS, sqlDbNowMs } from "./sql-driver.js";
|
|
12
12
|
import { isDupKeyError } from "./sql-errors.js";
|
|
@@ -310,7 +310,7 @@ export class SqlRunStore {
|
|
|
310
310
|
status: r.status,
|
|
311
311
|
result: refusing("serve a finished run as if it had produced nothing", () => decodeResultColumn(r.result, String(r.task_id))) ?? null,
|
|
312
312
|
error: r.error ?? null,
|
|
313
|
-
errorCode:
|
|
313
|
+
errorCode: r.error_code ?? null,
|
|
314
314
|
jobId: r.job_id ?? null,
|
|
315
315
|
source: r.source ?? null,
|
|
316
316
|
identity: readRunIdentityCells(r.identity_source, r.identity_scope, r.identity_principal_inc),
|
|
@@ -73,12 +73,6 @@ export interface ParsedTable {
|
|
|
73
73
|
export declare function parseCreateTable(stmt: string): ParsedTable | undefined;
|
|
74
74
|
/** 启动时真会建出来的**全部**表形(录制 → 解析)。同名表二次出现以**先到**为准(`IF NOT EXISTS` 的真语义)。 */
|
|
75
75
|
export declare function expectedTableShapes(dialect: SqlDialect): Promise<Map<string, ParsedTable>>;
|
|
76
|
-
/**
|
|
77
|
-
* 拒启码(机读)。附录 A / 拒启码表的登记名。含义 = 「本构建读不出的持久形,开始服务之前判」,一个码三只臂:本文件的列册对账与退役 schema 两道(SQL),
|
|
78
|
-
* 以及 local 数据根的严格边档对账(`local-session-store.ts` 的 `LocalDataRootSchemaMismatchError`,`LocalBackend.ensureSchema()` 调;拒句同形:
|
|
79
|
-
* 码开头的表头 · 逐坐标一段 · 「NEWER than this build」方向句 · 闭集出路)。
|
|
80
|
-
*/
|
|
81
|
-
export declare const SCHEMA_MISMATCH_ERROR_CODE = "config.schema_mismatch";
|
|
82
76
|
/** 一张表的对账结论。 */
|
|
83
77
|
export interface TableMismatch {
|
|
84
78
|
readonly table: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { recordEnsureStatements } from "./schema-ensure-legs.js";
|
|
2
2
|
import { readLiveColumns } from "./schema-live-columns.js";
|
|
3
3
|
import { SCHEMA_MISMATCH_WAYS_OUT } from "./schema-drift-sentence.js";
|
|
4
|
-
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
4
|
+
import { SCHEMA_MISMATCH_ERROR_CODE, StoreBootRefusalError } from "./store-contracts.js";
|
|
5
5
|
const QUOTES = new Set(["'", '"', "`"]);
|
|
6
6
|
function stripLineComments(sql) {
|
|
7
7
|
let out = "";
|
|
@@ -106,7 +106,6 @@ export async function expectedTableShapes(dialect) {
|
|
|
106
106
|
}
|
|
107
107
|
return shapes;
|
|
108
108
|
}
|
|
109
|
-
export const SCHEMA_MISMATCH_ERROR_CODE = "config.schema_mismatch";
|
|
110
109
|
export function diffSchema(expected, live) {
|
|
111
110
|
const out = [];
|
|
112
111
|
for (const [table, shape] of expected) {
|
|
@@ -6,7 +6,7 @@ export declare const LOCK_RE: RegExp;
|
|
|
6
6
|
* **「一个新库对 ensure 探针怎么答」的唯一属主**(合并复审 车HB 后收口:此前生成器录制器、`test/ensure-schema.test.ts`
|
|
7
7
|
* 的假池、`test/schema-baseline-generated.test.ts` ③c 的假驱动各抄一份,[ref] 加了索引探针 + PG 锁改 `got === true`
|
|
8
8
|
* 之后三份各漂一处 —— 假池答零行诱发 68 条 ALTER、③c 答 `got: 1` 让 PG 锁永远拿不到)。
|
|
9
|
-
* 返回 `undefined` = 不是探针,由调用方录制 /
|
|
9
|
+
* 返回 `undefined` = 不是探针,由调用方录制 / 执行;四条例外的理由见上面三条正则与 {@link newDatabaseSessionMetaKeyCollation} 的注。
|
|
10
10
|
*/
|
|
11
11
|
export declare function answerEnsureProbe(text: string): {
|
|
12
12
|
rows: Record<string, unknown>[];
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { ensureSchema } from "./tidb-pool.js";
|
|
1
|
+
import { SCHEMA_STATEMENTS, ensureSchema } from "./tidb-pool.js";
|
|
2
|
+
import { SESSION_META_KEY_COLLATION_PROBE } from "./session-ext-table.js";
|
|
2
3
|
import { ensurePgSchema } from "./pg-pool.js";
|
|
3
4
|
import { ensureTiDBMemoryEngineSchema } from "./memory-engine-tidb.js";
|
|
4
5
|
import { ensurePgMemoryEngineSchema } from "./memory-engine-pg.js";
|
|
5
6
|
import { ensurePgMemoryEmbedderMetaSchema } from "./memory-embedder-fingerprint.js";
|
|
6
7
|
import { ensureTiDBMemorySyncSchema, ensureTiDBMemoryHistorySchema } from "./memory-sync-store-tidb.js";
|
|
7
8
|
import { ensurePgMemorySyncSchema, ensurePgMemoryHistorySchema } from "./memory-sync-store-pg.js";
|
|
8
|
-
import { ensureTiDBRosterSchema, ensurePgRosterSchema } from "
|
|
9
|
+
import { ensureTiDBRosterSchema, ensurePgRosterSchema } from "../stores-sql/roster-store-sql.js";
|
|
9
10
|
import { ensureTiDBBackgroundAgentSchema, ensurePgBackgroundAgentSchema } from "../stores-sql/background-agent-store-sql.js";
|
|
10
|
-
import { ensureTiDBMailboxSchema, ensurePgMailboxSchema } from "
|
|
11
|
+
import { ensureTiDBMailboxSchema, ensurePgMailboxSchema } from "../stores-sql/mailbox-store-sql.js";
|
|
11
12
|
import { ensureTiDBTaskAttachmentSchema, ensurePgTaskAttachmentSchema } from "./task-attachment-store.js";
|
|
12
13
|
import { ensureTiDBUsageWindowSchema, ensurePgUsageWindowSchema } from "../stores-sql/usage-window-store-sql.js";
|
|
13
14
|
import { ensureTiDBTaskListSchema, ensurePgTaskListSchema } from "./task-list-store-sql.js";
|
|
@@ -15,6 +16,13 @@ import { ensureTiDBDeviceSchema, ensurePgDeviceSchema } from "./device-store-sql
|
|
|
15
16
|
export const LOCK_RE = /GET_LOCK|RELEASE_LOCK|pg_(try_)?advisory/i;
|
|
16
17
|
const INDEX_PROBE_RE = /FROM information_schema\.statistics\b/i;
|
|
17
18
|
const PG_INDEX_VALID_RE = /FROM pg_index i WHERE i\.indexrelid = to_regclass/i;
|
|
19
|
+
function newDatabaseSessionMetaKeyCollation() {
|
|
20
|
+
const stmt = SCHEMA_STATEMENTS.find((s) => s.includes("CREATE TABLE IF NOT EXISTS session_meta ("));
|
|
21
|
+
const m = stmt === undefined ? null : /\)\s*COLLATE\s+([A-Za-z0-9_]+)\s*$/.exec(stmt);
|
|
22
|
+
if (m === null)
|
|
23
|
+
throw new Error("schema-ensure-legs: the central session_meta statement carries no table-level COLLATE — cannot answer the session_ext key-collation probe for a new database");
|
|
24
|
+
return { cs: m[1].split("_")[0], coll: m[1] };
|
|
25
|
+
}
|
|
18
26
|
export function answerEnsureProbe(text) {
|
|
19
27
|
if (LOCK_RE.test(text))
|
|
20
28
|
return { rows: [{ got: true }] };
|
|
@@ -22,6 +30,8 @@ export function answerEnsureProbe(text) {
|
|
|
22
30
|
return { rows: [{ present: 1 }] };
|
|
23
31
|
if (PG_INDEX_VALID_RE.test(text))
|
|
24
32
|
return { rows: [{ indisvalid: true }] };
|
|
33
|
+
if (text === SESSION_META_KEY_COLLATION_PROBE)
|
|
34
|
+
return { rows: [newDatabaseSessionMetaKeyCollation()] };
|
|
25
35
|
return undefined;
|
|
26
36
|
}
|
|
27
37
|
function recorder() {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
2
|
+
import type { SqlDialect, SqlDriver } from "./sql-driver.js";
|
|
3
|
+
/** 表名(建表句、语句模块、迁移同读)。 */
|
|
4
|
+
export declare const SESSION_EXT_TABLE = "session_ext";
|
|
5
|
+
/** 一列:名字 + 两方言定义。 */
|
|
6
|
+
export interface SessionExtColumn {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly mysql: string;
|
|
9
|
+
readonly pg: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 执行放置七列 + `fork_key` —— 宽度:车道词 ≤ 32、设备 id 与 `device` 表同宽 64、属主两列与设备店同宽 190、fork 键 255(服务端拼的不透明串)。
|
|
13
|
+
* 全部可空:NULL = absent / 非键控 fork。一次性迁移 M32(7.139–7.146 形:这八列在 `session_meta` 上)读同一份定义。
|
|
14
|
+
*/
|
|
15
|
+
export declare const EXECUTION_PLACEMENT_COLUMNS: readonly SessionExtColumn[];
|
|
16
|
+
/** 本表的全部格(主键之外),按建表句的列序。一次性迁移 M41 逐列从 `session_meta` 搬进来的就是这一组。 */
|
|
17
|
+
export declare const SESSION_EXT_COLUMNS: readonly SessionExtColumn[];
|
|
18
|
+
/** 外键约束名(两方言同名;起服探针与迁移的后置条件按名读)。 */
|
|
19
|
+
export declare const SESSION_EXT_FOREIGN_KEY = "fk_session_ext_session";
|
|
20
|
+
/** 被引列 `session_meta.session_id` 的字符集与排序规则(MySQL 协议方言;外键列逐字带上,见顶注「外键列的字符集与排序规则取自被引列」)。 */
|
|
21
|
+
export interface ReferencedKeyCollation {
|
|
22
|
+
readonly characterSet: string;
|
|
23
|
+
readonly collation: string;
|
|
24
|
+
}
|
|
25
|
+
/** 读被引列字符集 / 排序规则的那一句(只读;当前库、表 `session_meta`、列 `session_id`)。录制驱动按这一串认它、答新库的真相(`schema-ensure-legs.ts`)。 */
|
|
26
|
+
export declare const SESSION_META_KEY_COLLATION_PROBE = "SELECT CHARACTER_SET_NAME AS cs, COLLATION_NAME AS coll FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'session_meta' AND COLUMN_NAME = 'session_id'";
|
|
27
|
+
/** 探针读数 → 被引列的字符集与排序规则;恰一行、两格都是合形的名字才算读出,否则 `undefined`(调用方拒启,不猜)。 */
|
|
28
|
+
export declare function readReferencedKeyCollation(rows: readonly unknown[]): ReferencedKeyCollation | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* 建表句(两方言;中央 `ensureSchema` 在 `session_meta` 之后发)。MySQL 协议方言必须给被引列的字符集与排序规则(外键列逐字带上它们);PostgreSQL 一形不收它。
|
|
31
|
+
*/
|
|
32
|
+
export declare function sessionExtDdl(dialect: "pg"): string;
|
|
33
|
+
export declare function sessionExtDdl(dialect: "mysql", referenced: ReferencedKeyCollation): string;
|
|
34
|
+
/** 旁表建不出 —— 起服拒(确定的拒启表态,起服对账一族同一个码 `config.schema_mismatch`):点名表名、外键列按被引列写下的字符集 / 排序规则(读得出时)与库的原句。 */
|
|
35
|
+
export declare class SessionExtTableRefusedError extends StoreBootRefusalError {
|
|
36
|
+
readonly code = "config.schema_mismatch";
|
|
37
|
+
constructor(detail: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* MySQL 协议方言建旁表(中央 `ensureSchema` 在 `session_meta` 建好之后调):读被引列的字符集 / 排序规则 → 按它铸建表句 → 建。`query` = 那条 DDL 连接上的一次查询(交回行)。
|
|
41
|
+
* 读不出被引列 ⇒ {@link SessionExtTableRefusedError};「库确定拒了这条建表句」只按本仓唯一判官的闭集认(`sql-errors.ts` 的 `isDeploymentFaultError`:外键两侧不相容 / 加不上外键 /
|
|
42
|
+
* 被引列缺索引 / 建表被存储引擎拒 / 表级权限拒 …)⇒ 同一只拒,原句随拒句;认不出的错(连接类故障、TiDB 的瞬时错、锁等待超时 …,带不带 SQL 状态码都一样)原样上抛 —— 开库等待窗重试它。
|
|
43
|
+
* 本模块不自带分类:判官加一码,这里随之。
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureSessionExtTableMysql(query: (sql: string) => Promise<readonly unknown[]>): Promise<void>;
|
|
46
|
+
/** 一条语句:文本 + 按序的参数。 */
|
|
47
|
+
export interface SessionExtStatement {
|
|
48
|
+
readonly text: string;
|
|
49
|
+
readonly values: readonly unknown[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 补行(行在 ⇒ 不动):旁表写者在锁住根 `session_meta` 行之后、写格之前发。MySQL 协议方言的重复键臂改一只非键列成它自己(不碰主键 —— 子表主键即外键列,
|
|
53
|
+
* 改它会让引擎做一次外键检查);PG `ON CONFLICT DO NOTHING`。外键:根行必须在(调用方锁着它)。
|
|
54
|
+
*/
|
|
55
|
+
export declare function ensureSessionExtRowStatement(dialect: SqlDialect, sessionId: string): SessionExtStatement;
|
|
56
|
+
/**
|
|
57
|
+
* 补行的**一批**形:按一句 SELECT(交回一列 `session_id`)补旁表行,行已在 ⇒ 不动任何格 —— 与 {@link ensureSessionExtRowStatement} 同一只冲突子句。
|
|
58
|
+
* SELECT 包成派生表 `picked`(只露 `session_id`)⇒ 冲突子句里的列名只可能指本表。只给一次性迁移用(运行期的写者一律按单行补,在锁住根行之后)。
|
|
59
|
+
*/
|
|
60
|
+
export declare function ensureSessionExtRowsStatement(dialect: SqlDialect, selectSessionIds: string): SessionExtStatement;
|
|
61
|
+
/** 旁表的外键级联在这只库上不生效 —— 起服拒的机读码(确定的拒启表态,与 `config.schema_mismatch` 同一族)。 */
|
|
62
|
+
export declare const SESSION_EXT_CASCADE_REFUSED_CODE = "config.session_ext_cascade_absent";
|
|
63
|
+
/** 起服拒:旁表行没有随根行删掉。继承 {@link StoreBootRefusalError}(确定的拒启表态:再等也等不来另一个答案)。 */
|
|
64
|
+
export declare class SessionExtCascadeAbsentError extends StoreBootRefusalError {
|
|
65
|
+
readonly dialect: SqlDialect;
|
|
66
|
+
readonly code = "config.session_ext_cascade_absent";
|
|
67
|
+
constructor(dialect: SqlDialect);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 起服能力探针(fail-closed):一只事务里插一行根会话 + 一行旁表、删根行、读旁表行,**回滚**(库零写)。旁表行还在 ⇒ {@link SessionExtCascadeAbsentError}。
|
|
71
|
+
* 读不到 / 写不进 ⇒ 原样上抛(证不出级联 ≠ 通过)。调用点:起服序列在建表之后、一次性迁移之前(`boot/stores.ts`)。
|
|
72
|
+
*/
|
|
73
|
+
export declare function assertSessionExtCascadeOn(db: Pick<SqlDriver, "dialect" | "connect">): Promise<void>;
|
|
74
|
+
//# sourceMappingURL=session-ext-table.d.ts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { SESSION_TITLE_MAX_CHARS } from "../session-row.js";
|
|
2
|
+
import { SESSION_WORKSPACE_COLUMN } from "./session-workspace-cell.js";
|
|
3
|
+
import { SCHEMA_MISMATCH_ERROR_CODE, StoreBootRefusalError } from "./store-contracts.js";
|
|
4
|
+
import { isDeploymentFaultError } from "./sql-errors.js";
|
|
5
|
+
export const SESSION_EXT_TABLE = "session_ext";
|
|
6
|
+
export const EXECUTION_PLACEMENT_COLUMNS = [
|
|
7
|
+
{ name: "execution_role", mysql: "execution_role VARCHAR(16) NULL", pg: `execution_role VARCHAR(16) COLLATE "C"` },
|
|
8
|
+
{ name: "execution_lane", mysql: "execution_lane VARCHAR(32) NULL", pg: `execution_lane VARCHAR(32) COLLATE "C"` },
|
|
9
|
+
{ name: "execution_device_id", mysql: "execution_device_id VARCHAR(64) NULL", pg: `execution_device_id VARCHAR(64) COLLATE "C"` },
|
|
10
|
+
{ name: "execution_device_owner_tenant", mysql: "execution_device_owner_tenant VARCHAR(190) NULL", pg: `execution_device_owner_tenant VARCHAR(190) COLLATE "C"` },
|
|
11
|
+
{ name: "execution_device_owner_subject", mysql: "execution_device_owner_subject VARCHAR(190) NULL", pg: `execution_device_owner_subject VARCHAR(190) COLLATE "C"` },
|
|
12
|
+
{ name: "execution_placed_at", mysql: "execution_placed_at DATETIME(3) NULL", pg: "execution_placed_at TIMESTAMPTZ(3)" },
|
|
13
|
+
{ name: "execution_rev", mysql: "execution_rev BIGINT NULL", pg: "execution_rev BIGINT" },
|
|
14
|
+
{ name: "fork_key", mysql: "fork_key VARCHAR(255) NULL", pg: `fork_key VARCHAR(255) COLLATE "C"` },
|
|
15
|
+
];
|
|
16
|
+
const PRODUCT_COLUMNS = [
|
|
17
|
+
{ name: "title", mysql: `title VARCHAR(${SESSION_TITLE_MAX_CHARS}) NULL`, pg: `title VARCHAR(${SESSION_TITLE_MAX_CHARS}) COLLATE "C"` },
|
|
18
|
+
{ name: "pinned", mysql: "pinned BOOLEAN NOT NULL DEFAULT FALSE", pg: "pinned BOOLEAN NOT NULL DEFAULT FALSE" },
|
|
19
|
+
{ name: "instruction_source", mysql: "instruction_source VARCHAR(64) NULL", pg: `instruction_source VARCHAR(64) COLLATE "C"` },
|
|
20
|
+
SESSION_WORKSPACE_COLUMN,
|
|
21
|
+
];
|
|
22
|
+
export const SESSION_EXT_COLUMNS = [...PRODUCT_COLUMNS, ...EXECUTION_PLACEMENT_COLUMNS];
|
|
23
|
+
export const SESSION_EXT_FOREIGN_KEY = "fk_session_ext_session";
|
|
24
|
+
export const SESSION_META_KEY_COLLATION_PROBE = "SELECT CHARACTER_SET_NAME AS cs, COLLATION_NAME AS coll FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'session_meta' AND COLUMN_NAME = 'session_id'";
|
|
25
|
+
const COLLATION_NAME_RE = /^[A-Za-z0-9_]{1,64}$/;
|
|
26
|
+
export function readReferencedKeyCollation(rows) {
|
|
27
|
+
if (rows.length !== 1)
|
|
28
|
+
return undefined;
|
|
29
|
+
const row = rows[0];
|
|
30
|
+
const cs = row?.cs;
|
|
31
|
+
const coll = row?.coll;
|
|
32
|
+
return typeof cs === "string" && typeof coll === "string" && COLLATION_NAME_RE.test(cs) && COLLATION_NAME_RE.test(coll) ? { characterSet: cs, collation: coll } : undefined;
|
|
33
|
+
}
|
|
34
|
+
export function sessionExtDdl(dialect, referenced) {
|
|
35
|
+
if (dialect === "mysql" && referenced === undefined)
|
|
36
|
+
throw new Error("sessionExtDdl(mysql): the referenced column's character set and collation are required (the foreign key column copies them)");
|
|
37
|
+
const key = dialect === "pg" ? `session_id VARCHAR(64) COLLATE "C" NOT NULL` : `session_id VARCHAR(64) CHARACTER SET ${referenced.characterSet} COLLATE ${referenced.collation} NOT NULL`;
|
|
38
|
+
return (`CREATE TABLE IF NOT EXISTS ${SESSION_EXT_TABLE} (\n` +
|
|
39
|
+
` ${key},\n` +
|
|
40
|
+
SESSION_EXT_COLUMNS.map((c) => ` ${c[dialect]},\n`).join("") +
|
|
41
|
+
" PRIMARY KEY (session_id),\n" +
|
|
42
|
+
` CONSTRAINT ${SESSION_EXT_FOREIGN_KEY} FOREIGN KEY (session_id) REFERENCES session_meta (session_id) ON DELETE CASCADE\n` +
|
|
43
|
+
(dialect === "pg" ? " )" : " ) COLLATE utf8mb4_bin"));
|
|
44
|
+
}
|
|
45
|
+
export class SessionExtTableRefusedError extends StoreBootRefusalError {
|
|
46
|
+
code = SCHEMA_MISMATCH_ERROR_CODE;
|
|
47
|
+
constructor(detail) {
|
|
48
|
+
super(`${SCHEMA_MISMATCH_ERROR_CODE}: this MySQL-protocol database cannot create table ${SESSION_EXT_TABLE} — refusing to start. ${detail} ` +
|
|
49
|
+
`The table's foreign key ${SESSION_EXT_FOREIGN_KEY} references session_meta (session_id) with ON DELETE CASCADE; its key column copies the character set and collation of session_meta.session_id. ` +
|
|
50
|
+
"Check that session_meta is an InnoDB table on MySQL (foreign keys need InnoDB on both sides), that the database supports foreign keys (TiDB from v6.6.0), " +
|
|
51
|
+
"and that session_meta.session_id is a character column. This check changed nothing in the database.");
|
|
52
|
+
this.name = "SessionExtTableRefusedError";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function ensureSessionExtTableMysql(query) {
|
|
56
|
+
const rows = await query(SESSION_META_KEY_COLLATION_PROBE);
|
|
57
|
+
const referenced = readReferencedKeyCollation(rows);
|
|
58
|
+
if (referenced === undefined) {
|
|
59
|
+
throw new SessionExtTableRefusedError(`Reading the character set and collation of session_meta.session_id from information_schema.COLUMNS gave ${rows.length} row(s) without two readable names, so the foreign key column cannot be declared to match it.`);
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
await query(sessionExtDdl("mysql", referenced));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (!isDeploymentFaultError(err))
|
|
66
|
+
throw err;
|
|
67
|
+
const { sqlState, sqlMessage: said } = err;
|
|
68
|
+
const sentence = typeof said === "string" ? said : err instanceof Error ? err.message : String(err);
|
|
69
|
+
throw new SessionExtTableRefusedError(`The foreign key column was declared CHARACTER SET ${referenced.characterSet} COLLATE ${referenced.collation} (read from session_meta.session_id); the database answered: ${sentence.split(/\r?\n/, 1)[0] ?? ""}${typeof sqlState === "string" ? ` (SQLSTATE ${sqlState})` : ""}.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function ensureSessionExtRowStatement(dialect, sessionId) {
|
|
73
|
+
return { text: `INSERT INTO ${SESSION_EXT_TABLE} (session_id) VALUES (${dialect === "pg" ? "$1" : "?"}) ${ensureConflictClause(dialect)}`, values: [sessionId] };
|
|
74
|
+
}
|
|
75
|
+
export function ensureSessionExtRowsStatement(dialect, selectSessionIds) {
|
|
76
|
+
return { text: `INSERT INTO ${SESSION_EXT_TABLE} (session_id) SELECT picked.session_id FROM (${selectSessionIds}) picked ${ensureConflictClause(dialect)}`, values: [] };
|
|
77
|
+
}
|
|
78
|
+
function ensureConflictClause(dialect) {
|
|
79
|
+
return dialect === "pg" ? "ON CONFLICT (session_id) DO NOTHING" : "ON DUPLICATE KEY UPDATE pinned = pinned";
|
|
80
|
+
}
|
|
81
|
+
export const SESSION_EXT_CASCADE_REFUSED_CODE = "config.session_ext_cascade_absent";
|
|
82
|
+
export class SessionExtCascadeAbsentError extends StoreBootRefusalError {
|
|
83
|
+
dialect;
|
|
84
|
+
code = SESSION_EXT_CASCADE_REFUSED_CODE;
|
|
85
|
+
constructor(dialect) {
|
|
86
|
+
super(`${SESSION_EXT_CASCADE_REFUSED_CODE}: on this ${dialect === "pg" ? "PostgreSQL" : "MySQL-protocol"} database, deleting a session row did not delete its ${SESSION_EXT_TABLE} row ` +
|
|
87
|
+
`(the foreign key ${SESSION_EXT_FOREIGN_KEY} … ON DELETE CASCADE is not enforced) — refusing to start: a session id registered again would inherit the previous occupant's ` +
|
|
88
|
+
"title, pin, instruction baseline and execution placement. " +
|
|
89
|
+
(dialect === "pg"
|
|
90
|
+
? "Check that the constraint exists on the table (it is created with the table) and that no session_replication_role / trigger setting disables it."
|
|
91
|
+
: "On TiDB, foreign keys are enforced from v6.6.0 with the session variable foreign_key_checks=ON (the default; a DSN or global setting may turn it OFF); " +
|
|
92
|
+
`on MySQL, the table must be InnoDB. If the table was created while foreign keys were not enforced, drop the (empty) ${SESSION_EXT_TABLE} table and start again.`));
|
|
93
|
+
this.dialect = dialect;
|
|
94
|
+
this.name = "SessionExtCascadeAbsentError";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const CASCADE_PROBE_ID = "~session-ext-cascade-probe";
|
|
98
|
+
export async function assertSessionExtCascadeOn(db) {
|
|
99
|
+
const conn = await db.connect();
|
|
100
|
+
try {
|
|
101
|
+
await conn.begin();
|
|
102
|
+
const p = db.dialect === "pg" ? (n) => `$${n}` : () => "?";
|
|
103
|
+
const now = new Date();
|
|
104
|
+
await conn.query(`INSERT INTO session_meta (session_id, created_at, updated_at) VALUES (${p(1)}, ${p(2)}, ${p(3)})`, [CASCADE_PROBE_ID, now, now]);
|
|
105
|
+
const ensure = ensureSessionExtRowStatement(db.dialect, CASCADE_PROBE_ID);
|
|
106
|
+
await conn.query(ensure.text, [...ensure.values]);
|
|
107
|
+
await conn.query(`DELETE FROM session_meta WHERE session_id = ${p(1)}`, [CASCADE_PROBE_ID]);
|
|
108
|
+
const left = await conn.query(`SELECT session_id FROM ${SESSION_EXT_TABLE} WHERE session_id = ${p(1)}`, [CASCADE_PROBE_ID]);
|
|
109
|
+
await conn.rollback();
|
|
110
|
+
if (left.rows.length !== 0)
|
|
111
|
+
throw new SessionExtCascadeAbsentError(db.dialect);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
await conn.rollback().catch(() => undefined);
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
conn.release();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=session-ext-table.js.map
|
|
@@ -13,10 +13,15 @@
|
|
|
13
13
|
* 吃一只 `Session`):唤醒出来的会话 `getEntry` 在地板之下会回读持久日志,所以判官在压缩过的会话上也看得见整条叶链。
|
|
14
14
|
*
|
|
15
15
|
* ## fork 续写的店契约(本文件下半)
|
|
16
|
-
* 三店同一只私有体 `forkTo(sourceId, owner,
|
|
17
|
-
* local 崩溃中间态 `forking` 只许同键重试补齐 · fork 键此后每个写携带(
|
|
16
|
+
* 三店同一只私有体 `forkTo(sourceId, owner, target)`:目标行原子新建(唯一创建点)· 撞已在按属主与 fork 键分类({@link classifyForkTarget})·
|
|
17
|
+
* local 崩溃中间态 `forking` 只许同键重试补齐 · fork 键此后每个写携带(整段换装:local 经 `carriedRowCells`,SQL 就地改写、旁表行不动)。core 契约 `fork(sourceId, owner?, opts?)` = {@link forkByFreshId}。
|
|
18
|
+
*
|
|
19
|
+
* ## fork 进委派分区(core `SessionStore.fork` 的 `opts.placement`)
|
|
20
|
+
* fork 的创建那一笔就是一次建行:带元组的 fork 与带 placement 的 acquire 落**同一组**元组(六列 / 存档行头,first-write 不可变,`placedAt` 由店铸),
|
|
21
|
+
* 此后这一行欠 placed 行的每一条义务(不上宿主列表 · claim 形 acquire 拒 · 进分区枚举 · release = 真删除)。元组不带属主:行的属主仍是 fork 的属主参数
|
|
22
|
+
* 按 `forkOwnerOf` 的那一读(core 句:元组没有属主)。没声明分区的店照常 fork、不落元组(core 句:忽略合法,拒 fork 不合法)。
|
|
18
23
|
*/
|
|
19
|
-
import { type ForkPoint, type ForkRowShape, type SessionStorage } from "@sema-agent/core";
|
|
24
|
+
import { type ForkPoint, type ForkRowShape, type SessionStorage, type SessionStore } from "@sema-agent/core";
|
|
20
25
|
/** 问引擎:这只(已唤醒的)源会话从哪里拷。SQL 孪生用它;local 店手里就是引擎的 `Session`,直接调 `settledForkOptions`。 */
|
|
21
26
|
export declare function forkPointOf(storage: SessionStorage): Promise<ForkPoint>;
|
|
22
27
|
/** 两只 SQL 孪生整份日志里的一行(两孪生选同一组列):父链两键交引擎挑行,其余三列原样搬进新会话、不读内容。 */
|
|
@@ -33,13 +38,27 @@ export interface ForkLogRow {
|
|
|
33
38
|
*/
|
|
34
39
|
export declare const FORK_LOG_ROW_SHAPE: ForkRowShape<ForkLogRow>;
|
|
35
40
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
41
|
+
* fork 进委派分区时落的元组 —— core `SessionStore.fork` 第三参 `opts.placement` 的那一形,**直接取 core 的型、不复述**(core 当前写作 `SessionPlacement` 去掉属主:行的属主是
|
|
42
|
+
* fork 的属主参数的那一读)。本仓里这个元组型只有这一处定义:三店(local · pg · tidb)、路由店、`forkByFreshId`、引擎面声明的 fork 形参,以及建行绑定值
|
|
43
|
+
* `placementInsertValues`(`session-placement.ts`)都读它 —— core 再改 `fork` 的第三参,型面在这里一处跟着动(`SessionStore.fork` 是可选成员,所以取参数前先 `NonNullable`)。
|
|
44
|
+
*/
|
|
45
|
+
export type ForkPlacement = NonNullable<NonNullable<Parameters<NonNullable<SessionStore["fork"]>>[2]>["placement"]>;
|
|
46
|
+
/**
|
|
47
|
+
* `forkTo` 的目标:调用方给的新会话 id,外加两者之一(或都没有):
|
|
48
|
+
* · `key` —— 服务端拼的不透明串(路由按「源 + 调用方 nonce」派生),存进新行那一格 `fork_key`(SQL)/ `forkKey`(local):一个事实 = 「建这一行的那次 fork 请求的键」;
|
|
49
|
+
* · `placement` —— 新行落进委派分区的元组(见文件头「fork 进委派分区」)。
|
|
50
|
+
* 两者互斥由型面说:带键的是客户端经路由的 fork(一位用户续一只会话,永不 placed —— placement 只走引擎的可信内部链),placed 的是引擎的 fork(后台 fork 子代的转录,
|
|
51
|
+
* 现铸 id、永不带键)⇒ {@link classifyForkTarget} 的重放判(键相等)永远碰不到 placed 目标。都缺 = 非键控、普通的 fork(core 契约的现铸形)。
|
|
38
52
|
*/
|
|
39
|
-
export
|
|
53
|
+
export type ForkTarget = {
|
|
40
54
|
readonly id: string;
|
|
41
55
|
readonly key?: string;
|
|
42
|
-
|
|
56
|
+
readonly placement?: undefined;
|
|
57
|
+
} | {
|
|
58
|
+
readonly id: string;
|
|
59
|
+
readonly placement: ForkPlacement;
|
|
60
|
+
readonly key?: undefined;
|
|
61
|
+
};
|
|
43
62
|
/**
|
|
44
63
|
* fork 键的**唯一**拼法(路由带键 ⇒ `forkTo(…, { id: forkId, key: forkKeyOf(源, forkNonce) })`):服务端拼的不透明串 —— 源 id 与调用方 nonce 的摘要,
|
|
45
64
|
* 定长(远短于 `fork_key` 的 255),源进摘要 ⇒ 「异源同 nonce」拼出不同的键(撞同一只目标即 409,不当重放)。调用方不读它,只靠同键重试同答。
|
|
@@ -78,8 +97,11 @@ export declare class ForkTargetUnsettledError extends Error {
|
|
|
78
97
|
/** 三店的 `forkTo` 形(私有体,经店面 `forkTo` 交出)。 */
|
|
79
98
|
export type ForkToFn = (sourceId: string, owner: string | null, target: ForkTarget) => Promise<ForkToOutcome | null>;
|
|
80
99
|
/**
|
|
81
|
-
* core 契约 `fork(sourceId, owner?) → string | null` = `forkTo(…, { id: uuidv7() })` 的投影(三店同一只):`created` ⇒ 新 id;源不在 ⇒ `null`。
|
|
100
|
+
* core 契约 `fork(sourceId, owner?, opts?) → string | null` = `forkTo(…, { id: uuidv7(), placement? })` 的投影(三店同一只):`created` ⇒ 新 id;源不在 ⇒ `null`。
|
|
101
|
+
* `opts.placement` 原样进目标(落不落由店判:声明了分区的店落,没声明的忽略 —— 各店 `forkTo` 一处)。
|
|
82
102
|
* 新铸的 uuidv7 撞上已在的行(`occupied` / `replayed`)不是一个答案,是不变量破 ⇒ 响亮抛 —— 无键请求永不答 `replayed`。
|
|
83
103
|
*/
|
|
84
|
-
export declare function forkByFreshId(forkTo: ForkToFn, sourceId: string, owner: string | null | undefined
|
|
104
|
+
export declare function forkByFreshId(forkTo: ForkToFn, sourceId: string, owner: string | null | undefined, opts?: {
|
|
105
|
+
placement?: ForkPlacement;
|
|
106
|
+
}): Promise<string | null>;
|
|
85
107
|
//# sourceMappingURL=session-fork.d.ts.map
|
|
@@ -26,9 +26,10 @@ export class ForkTargetUnsettledError extends Error {
|
|
|
26
26
|
this.name = "ForkTargetUnsettledError";
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
export async function forkByFreshId(forkTo, sourceId, owner) {
|
|
29
|
+
export async function forkByFreshId(forkTo, sourceId, owner, opts) {
|
|
30
30
|
const id = uuidv7();
|
|
31
|
-
const
|
|
31
|
+
const placement = opts?.placement;
|
|
32
|
+
const out = await forkTo(sourceId, owner ?? null, placement !== undefined ? { id, placement } : { id });
|
|
32
33
|
if (out === null)
|
|
33
34
|
return null;
|
|
34
35
|
switch (out.outcome) {
|