@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
|
@@ -10,8 +10,9 @@ import { StoreBootRefusalError } from "./store-contracts.js";
|
|
|
10
10
|
import { decodeRunResultCellM44 } from "./run-store-sql.js";
|
|
11
11
|
import { persistedPlaneOf } from "../terminal.js";
|
|
12
12
|
import { RUN_PREVIEW_COARSE_PREFIXES_M45, normalizedRunPreviewM45 } from "./run-preview-m45.js";
|
|
13
|
-
import { SHELL_SENTINEL_OWNER_M48, SHELL_SENTINEL_OWNER_TABLES_M48 } from "./shell-sentinel-owner-m48.js";
|
|
14
|
-
import {
|
|
13
|
+
import { SHELL_SENTINEL_OWNER_M48, SHELL_SENTINEL_OWNER_TABLES_M48, shellSentinelOwnerWhereM48 } from "./shell-sentinel-owner-m48.js";
|
|
14
|
+
import { LEGACY_SKILL_EXEMPTION_PAGE } from "./approval-exemption-skill-m46.js";
|
|
15
|
+
import { SKILL_EXEMPTION_TOOL_NAME, readSqlSkillExemptionCutoff } from "./approval-exemption-skill-cutoff.js";
|
|
15
16
|
import { PERMISSION_RULE_TABLE, SqlDurableRulePartitionProvider, isSqlBucketRefusal, isSqlBucketVanished, listRuleBucketOwners } from "./permission-rule-store-sql.js";
|
|
16
17
|
import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
|
|
17
18
|
import { readJsonObjectColumn } from "./sql-json-column.js";
|
|
@@ -27,8 +28,11 @@ import { RENAMED_EXECUTION_LANE_M40, RETIRED_EXECUTION_LANE_WORD_M40, retiredExe
|
|
|
27
28
|
import { retireImportedLayerRootAllows } from "./imported-layer-root-retirement.js";
|
|
28
29
|
import { isUnusableArchive } from "../execution-placement.js";
|
|
29
30
|
import { IDENTITY_COLUMN_NAME, SCENARIO_PREFIX_LIKE, SCENARIO_PREFIX_MARKER_ID, ScenarioPrefixSwitchRefusedError } from "./scenario-prefix-switch-m42.js";
|
|
30
|
-
import { MIGRATION_MARKER_TABLE, migrationMarkerDdl } from "./one-time-migration-marker.js";
|
|
31
|
-
import { expectedTableShapes } from "./schema-consistency.js";
|
|
31
|
+
import { MIGRATION_MARKER_TABLE, SKILL_EXEMPTION_CUTOFF_ID, markIfAbsentSql, migrationMarkerDdl } from "./one-time-migration-marker.js";
|
|
32
|
+
import { describeUpgradeDriftTail, expectedTableShapes } from "./schema-consistency.js";
|
|
33
|
+
import { olderReplicaEvidenceSentence, stopThenStartAction } from "./stop-then-start-sentence.js";
|
|
34
|
+
import { buildThisReplicaRegistration, knowsCapability, readReplicaRegistrations, registerReplica } from "./replica-registration.js";
|
|
35
|
+
import { assertReplicaTablesPresent, assertServingRequirementsMet } from "./serving-requirement.js";
|
|
32
36
|
const RETIRED_SESSION_RULE_BUCKETS = ["commandAllow", "commandDeny"];
|
|
33
37
|
export function buildMigrationReceipts() {
|
|
34
38
|
return {
|
|
@@ -66,6 +70,7 @@ export function buildMigrationReceipts() {
|
|
|
66
70
|
runErrorCodeColumnRewritten: 0,
|
|
67
71
|
runObjectivePreviewRewritten: 0,
|
|
68
72
|
shellSentinelOwnersCleared: 0,
|
|
73
|
+
shellSentinelOwnerRowsRetained: [],
|
|
69
74
|
checkpointHostSessionsBackfilled: 0,
|
|
70
75
|
legacySkillExemptionsDropped: 0,
|
|
71
76
|
executionPlacementSessionsUnreadable: [],
|
|
@@ -127,6 +132,7 @@ function changedAnything(r) {
|
|
|
127
132
|
r.runErrorCodeColumnRewritten > 0 ||
|
|
128
133
|
r.runObjectivePreviewRewritten > 0 ||
|
|
129
134
|
r.shellSentinelOwnersCleared > 0 ||
|
|
135
|
+
r.shellSentinelOwnerRowsRetained.length > 0 ||
|
|
130
136
|
r.checkpointHostSessionsBackfilled > 0 ||
|
|
131
137
|
r.legacySkillExemptionsDropped > 0 ||
|
|
132
138
|
r.executionPlacementSessionsUnreadable.length > 0 ||
|
|
@@ -152,6 +158,7 @@ function readingsSnapshot(r) {
|
|
|
152
158
|
sessionRuleRowsWithUnreadableDeny: [...r.sessionRuleRowsWithUnreadableDeny],
|
|
153
159
|
parkedApprovalCardRowsUnreadable: [...r.parkedApprovalCardRowsUnreadable],
|
|
154
160
|
parkedApprovalCardRowsTooLong: [...r.parkedApprovalCardRowsTooLong],
|
|
161
|
+
shellSentinelOwnerRowsRetained: [...r.shellSentinelOwnerRowsRetained],
|
|
155
162
|
executionPlacementSessionsUnreadable: [...r.executionPlacementSessionsUnreadable],
|
|
156
163
|
localArchivesKeptStamped: [...r.localArchivesKeptStamped],
|
|
157
164
|
localArchivesUnreadable: [...r.localArchivesUnreadable],
|
|
@@ -180,21 +187,18 @@ export class OneTimeMigrationInterruptedError extends Error {
|
|
|
180
187
|
this.receipts = receipts;
|
|
181
188
|
}
|
|
182
189
|
}
|
|
190
|
+
const WORKFLOW_JOURNAL_TABLE = "workflow_journal";
|
|
191
|
+
const WORKFLOW_JOURNAL_OWNER_TABLE = "workflow_journal_owner";
|
|
192
|
+
const WORKFLOW_JOURNAL_STAGING = `${WORKFLOW_JOURNAL_TABLE}_m24`;
|
|
193
|
+
const WORKFLOW_JOURNAL_RETIRED = `${WORKFLOW_JOURNAL_TABLE}_m24_old`;
|
|
194
|
+
const WORKFLOW_JOURNAL_SUPPLIED_COLUMN = "incarnation";
|
|
195
|
+
const RETIRED_JOURNAL_SCOPE_COLUMN = "scope";
|
|
196
|
+
const SESSION_POLICY_TABLE = "session_policy";
|
|
197
|
+
const RETIRED_SESSION_RULES_COLUMN = "rules";
|
|
198
|
+
const OLD_GRAMMAR_SESSION_RULES_COLUMN = "rule_entries_old_grammar";
|
|
199
|
+
const RETIRED_ASK_CAUSE_COLUMN = "denied_reason";
|
|
200
|
+
const ASK_EXECUTION_LANE_COLUMN = "execution_lane";
|
|
183
201
|
export const ONE_TIME_MIGRATIONS = [
|
|
184
|
-
{
|
|
185
|
-
id: "M12",
|
|
186
|
-
introducedIn: "7.122.0",
|
|
187
|
-
releasedOn: "2026-10-09",
|
|
188
|
-
removableAfter: "2026-11-08",
|
|
189
|
-
removal: "删模式词读法记号的判据与拒臂:`http/stored-body-replay.ts` 的 `permissionModeReadingUnstated`;`http/checkpoint-ctx.ts` 的 `permissionModeReadingStated` / `permissionModeReadingRefusal` / `PERMISSION_MODE_READINGS`、" +
|
|
190
|
-
"`StoredBodyReplayRefusal` 的 `permission_mode_reading` 臂及其日志字段与答复臂、`buildCheckpointCtx` 与 `withPermissionModeRewritten` 两处记号写点" +
|
|
191
|
-
"(后者删后 `resume-legs.ts` `drivePlanReview` 里对它的那一处调用回到只换体的 `{ ...ctx, body }`)、`CheckpointCtx.permissionModeReading`、" +
|
|
192
|
-
"`http/stored-body-replay.ts` 里 `StoredReplayDeployment` 的 `autonomy` 位与 `storedBodyReplayRefusal` 读 `deployment.autonomy` 的那一句(这一位只服务这一问;四个问点传 `deps.config` 整份,home 位还服务 `permissions` 一问,不动);" +
|
|
193
|
-
"`test/stored-request-prompt-profile-m30.test.ts` 的 SHARED 表里 `StoredBodyReplayRefusal` 那一行(rows 含 M12;M30 的登记行组已先删时该表已不在,这一句无事可做):rows 去掉 M12、整行并入同文件的 SITES(值 = 该行的 files 数组)",
|
|
194
|
-
afterRemoval: "没有响亮臂:删码之后仍停驻、在 7.121.x 及以前写下的行(把 `APPROVAL_TERMINAL_BACKSTOP_MS` 调长的部署,或跳过了带本条的版本直接升的库)在设了 " +
|
|
195
|
-
"`AUTONOMY=plan` 的部署上按体里的原词重放(运维的 plan 不再被按段重钳)—— 升级前把这些停驻的 run 决掉 / 取消,或升级窗内设 `AUTONOMY=read-only`",
|
|
196
|
-
reportKeys: [],
|
|
197
|
-
},
|
|
198
202
|
{
|
|
199
203
|
id: "M13",
|
|
200
204
|
introducedIn: "7.123.0",
|
|
@@ -250,6 +254,7 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
250
254
|
"出路是先在一只带本条的版本上起服一次;② 行里仍带退役命令桶:SQL 店读回照旧答 `corrupt`(引擎的形读法点名那只桶,与本条在场时同一个结局),只是起服日志不再逐行点名 —— " +
|
|
251
255
|
"运维在库里把那一行改写成引擎文法或删掉它(删会话即删规则);③ 跳过本条直接升的库同样没有改名那一拍的条目判读 —— 由 ① 的拒启接住(出路同 ①)",
|
|
252
256
|
reportKeys: ["sessionRuleColumn", "sessionRuleRowsWithRetiredBuckets", "sessionRuleRowsWithOldGrammarEntries", "sessionRuleRowsWithUnreadableDeny"],
|
|
257
|
+
shapeChanges: [{ kind: "rename", table: SESSION_POLICY_TABLE, from: [RETIRED_SESSION_RULES_COLUMN, OLD_GRAMMAR_SESSION_RULES_COLUMN], to: SESSION_RULES_COLUMN.name }],
|
|
253
258
|
},
|
|
254
259
|
{
|
|
255
260
|
id: "M18",
|
|
@@ -370,6 +375,7 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
370
375
|
afterRemoval: "起服对账一族的列集探针接住(`schema-consistency.ts` 的 `assertSchemaMatchesCode`,常设):跳过了带本条的版本直接升的库,`workflow_journal` 上仍带 scope 列、没有 incarnation 列 = 库与代码列集不符 ⇒ " +
|
|
371
376
|
"响亮拒启(`config.schema_mismatch`),拒句点名两列;出路是先在带本条的版本(7.133.x)起服一次让它走完,再升",
|
|
372
377
|
reportKeys: ["workflowJournalScopeColumn", "workflowJournalOwnersBackfilled", "workflowJournalForeignScopeRowsRemoved"],
|
|
378
|
+
shapeChanges: [{ kind: "rebuild", table: WORKFLOW_JOURNAL_TABLE, whilePresent: RETIRED_JOURNAL_SCOPE_COLUMN, supplies: [WORKFLOW_JOURNAL_SUPPLIED_COLUMN] }],
|
|
373
379
|
},
|
|
374
380
|
{
|
|
375
381
|
id: "M25",
|
|
@@ -497,13 +503,15 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
497
503
|
afterRemoval: "起服对账一族的跳版库拒启臂接住:删码同版把 `device_session` / `device_session_retired` 两张表加进退役 schema 判据(`schema-consistency.ts` 的跳版库探针,先于建表)⇒ " +
|
|
498
504
|
"跳过了带本条的版本直接升的库响亮拒启,出路 = 先在带本条的版本起服一次让切换走完,再升;缺执行放置列的库由列集对账缺列拒启(`config.schema_mismatch`,拒句给 ALTER),同一出路",
|
|
499
505
|
reportKeys: ["executionPlacementColumnsAdded", "deviceBindingsMoved", "deviceBindingsOrphaned", "deviceBindingTablesDropped", "executionPlacementsBackfilled", "askExecutionLanesBackfilled", "executionPlacementSessionsUnreadable"],
|
|
506
|
+
shapeChanges: [{ kind: "add", table: APPROVAL_ASK_TABLE, column: ASK_EXECUTION_LANE_COLUMN, whilePresent: { table: "session_meta", anyOf: SESSION_EXT_MOVED_COLUMNS.map((c) => c.name) } }],
|
|
500
507
|
},
|
|
501
508
|
{
|
|
502
509
|
id: "M33",
|
|
503
510
|
introducedIn: "7.141.0",
|
|
504
511
|
releasedOn: "2026-10-30",
|
|
505
512
|
removableAfter: "2026-11-29",
|
|
506
|
-
removal: "删 `LocalSessionStore.migrateLocalArchives` 与它的私有助手 `anonymizeArchiveHeld` / `fillRowFacts`、`settleArchiveSnapshots`
|
|
513
|
+
removal: "删 `LocalSessionStore.migrateLocalArchives` 与它的私有助手 `anonymizeArchiveHeld` / `fillRowFacts`、`settleArchiveSnapshots` 整只(逐份消化的循环与 `settleArchiveSnapshot`;`LocalBackend.ensureSchema` 里那一步)—— " +
|
|
514
|
+
"常设臂 `assertNoArchiveSnapshots`(只读)搬进数据根准入 `local-data-root-admission.ts` 的 `admitLocalDataRoot`(一格,本进程第一笔写之前判)、" +
|
|
507
515
|
"`archiveSnapshotsSettled` 字段、`rowFactsFilled` / `ARCHIVE_SNAPSHOT_RECORD` / `ArchiveSnapshotRecord` / `readArchiveSnapshotRecord` / `sameLog` / " +
|
|
508
516
|
"`ArchivedRowFacts` / `archivedRowFactsOf`(M47 仍在树时留着,随 M47 删)/ " +
|
|
509
517
|
"`ArchiveRewriteStep` / `LocalArchiveMigrationReading` / `errnoOf`、" +
|
|
@@ -532,6 +540,10 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
532
540
|
"出路 = 先在带本条的版本起服一次让迁移走完,再升(列册对账见幽灵列 / 缺列同样拒启,但它的拒句给的是加列,不是这一出路 —— 所以退役判据要在删码同版加上);" +
|
|
533
541
|
"② local —— 信封号 1 的日志记录走 File 问账店「认不出的信封号」拒启(`unknown envelope version`,点名文件与出路:用写下它的那一版起服一次,或移开文件)",
|
|
534
542
|
reportKeys: ["askCauseColumnsChanged", "askParkTriggersMoved", "askJournalRecordsUpgraded"],
|
|
543
|
+
shapeChanges: [
|
|
544
|
+
{ kind: "rename", table: APPROVAL_ASK_TABLE, from: [RETIRED_ASK_CAUSE_COLUMN], to: APPROVAL_ASK_ENDING_CAUSE_COLUMN.name },
|
|
545
|
+
{ kind: "add", table: APPROVAL_ASK_TABLE, column: APPROVAL_ASK_PARK_TRIGGER_COLUMN.name },
|
|
546
|
+
],
|
|
535
547
|
},
|
|
536
548
|
{
|
|
537
549
|
id: "M35",
|
|
@@ -606,13 +618,18 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
606
618
|
introducedIn: "7.147.0",
|
|
607
619
|
releasedOn: "2026-11-07",
|
|
608
620
|
removableAfter: "2026-12-07",
|
|
609
|
-
removal: "删 `src/plugins/execution-lane-rename-m40.ts` 整只文件;本文件的 M40 步(`renameRetiredExecutionLaneWordsM40` / `refuseWhileRunsHeartbeat
|
|
610
|
-
"`EXECUTION_LANE_RENAME_REFUSED_CODE
|
|
611
|
-
"`store-backend.ts` 的 `LocalBackend.ensureSchema` 第一步与 `executionLaneWordsRenamed`
|
|
621
|
+
removal: "删 `src/plugins/execution-lane-rename-m40.ts` 整只文件;本文件的 M40 步(`renameRetiredExecutionLaneWordsM40` / `refuseWhileRunsHeartbeat`〔读证据的那一处调用;证据读法 `readOlderReplicaEvidence` 与判活窗输入归 M52 行〕/ `ExecutionLaneRenameRefusedError` / " +
|
|
622
|
+
"`EXECUTION_LANE_RENAME_REFUSED_CODE`,`migrateStepsOn` 第一步那一行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `executionLaneWordsRenamed`、头注 M40 段;" +
|
|
623
|
+
"`store-backend.ts` 的 `LocalBackend.ensureSchema` 第一步与 `executionLaneWordsRenamed` 字段;" +
|
|
624
|
+
"`local-session-store.ts` 的内核 `renameRetiredExecutionLaneWordsInCellsM40` 与数据根准入的具名读者 `readSessionMetaSidecarInWindow`(在内存里套的那一步;准入的解码点改用 `readSessionMetaSidecar`);" +
|
|
612
625
|
"`LocalSessionStore.renameRetiredExecutionLaneWordM40`、`FileApprovalAskStore.renameRetiredExecutionLaneWordM40` 与内核的 `renameExecutionLaneWord`;" +
|
|
613
626
|
"`approval-ask-store-sql.ts` / `execution-placement-sql.ts` 拒句里的 `retiredExecutionLaneHintM40(…)` 补句;`test/execution-lane-rename-m40.test.ts` 整只文件与 `test/execution-placement-switch-db-integration.test.ts` 的 M40 组",
|
|
614
627
|
afterRemoval: "既有读口的拒臂接住(响亮,不再改名):仍带旧词的行 —— 跳过了带本条的版本直接升的库、窗关之后还在写的更早版本副本 —— SQL 问行读口拒、会话执行格读口拒(`ExecutionPlacementRowError`)," +
|
|
615
628
|
"local 会话元数据边档整只严格拒启(`config.schema_mismatch`),local 问账日志由 M32 回填的词表外拒臂拒启(M32 删码之后:那只问行原样装回)。出路 = 升级时先过一次带本条的版本并起服",
|
|
629
|
+
stopThenStart: {
|
|
630
|
+
reason: "renames the retired execution-lane word \"in-process\" to \"none\" on stored approval asks and sessions; a replica of an earlier version would keep writing the old word after the rename",
|
|
631
|
+
owedOn: owesExecutionLaneRenameM40,
|
|
632
|
+
},
|
|
616
633
|
reportKeys: ["executionLaneWordsRenamed"],
|
|
617
634
|
},
|
|
618
635
|
{
|
|
@@ -623,11 +640,15 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
623
640
|
removal: "删本文件的 M41 步(`moveSessionCellsToSideTable` / `refuseSessionExtMoveWhileRunsHeartbeat` / `deploymentColumnsOnMeta` / `SessionExtMoveRefusedError` / `SESSION_EXT_MOVE_REFUSED_CODE` / " +
|
|
624
641
|
"`SessionExtMoveRefusalReason` / `sameCell` / `SESSION_EXT_MOVE_PAGE`,`migrateStepsOn` 里那两行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `sessionExtRowsMoved` / `sessionMetaColumnsDropped`、头注 M41 段;" +
|
|
625
642
|
"M32 读形里的 `cellsOnSideTable` 判(它读本条的 `deploymentColumnsOnMeta`):M32 还在时改成恒旁表形 —— 删 M32 写 `session_meta` 八列的那些臂(② ④ ④b ⑥ 与 ③ 的 `migrateDeviceBindingsStatement` 臂)," +
|
|
626
|
-
"留 ③ 的旁表臂(`migrateDeviceBindingsOntoSideTableStatements`:围栏拒句的「采旧」在任何库上仍要能落到执行格);M32 先于本条删码时这些随 M32 一并删;`
|
|
643
|
+
"留 ③ 的旁表臂(`migrateDeviceBindingsOntoSideTableStatements`:围栏拒句的「采旧」在任何库上仍要能落到执行格);M32 先于本条删码时这些随 M32 一并删;`test/session-ext-move-db-integration.test.ts` 整只文件。能力名单 `REPLICA_CAPABILITIES` 里的 `M41` 不删(只增)",
|
|
627
644
|
afterRemoval: "跳过了带本条的版本直接升上来的库:`session_meta` 上仍带部署格列 ⇒ 起服列册对账拒启(`config.schema_mismatch`,那几列是本树之外的多余列,拒句不给 ALTER —— 出路是带本条的版本);" +
|
|
628
645
|
"部署格从旁表读,旧列上的值不被任何读者读。出路 = 升级时先过一次带本条的版本并起服",
|
|
646
|
+
stopThenStart: {
|
|
647
|
+
reason: "moves the session deployment cells from session_meta to session_ext and then retires the old columns; a cell an earlier replica writes between the copy and the retirement is lost, and every cell write it makes afterwards fails",
|
|
648
|
+
owedOn: owesSessionExtMoveM41,
|
|
649
|
+
},
|
|
629
650
|
reportKeys: ["sessionExtRowsMoved", "sessionMetaColumnsDropped"],
|
|
630
|
-
|
|
651
|
+
shapeChanges: [{ kind: "drop", table: "session_meta", columns: SESSION_EXT_MOVED_COLUMNS.map((c) => c.name) }],
|
|
631
652
|
},
|
|
632
653
|
{
|
|
633
654
|
id: "M42",
|
|
@@ -635,10 +656,14 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
635
656
|
releasedOn: "2026-11-08",
|
|
636
657
|
removableAfter: "2026-12-08",
|
|
637
658
|
removal: "删 `src/plugins/scenario-prefix-switch-m42.ts` 整只文件;本文件的 M42 步(`switchScenarioPrefixM42` / `scannedIdentityColumnsM42`,`migrateStepsOn` 第一步那一行)、报告 / 收据 / 日志的 `scenarioPrefixSourcesScanned`、头注 M42 段;" +
|
|
638
|
-
"`
|
|
639
|
-
"
|
|
659
|
+
"`store-backend.ts` 的 `LocalBackend.runOneTimeMigrations` 里 M42 那一腿(`switchLocalScenarioPrefixM42`)与四只 File 店的 `scenarioPrefixOwnerRowsM42`(run / 会话 / 问 / 附件);`test/scenario-prefix-switch-m42.test.ts` 与 `test/scenario-prefix-switch-db-integration.test.ts` 两只文件。" +
|
|
660
|
+
"标记表 `one-time-migration-marker.ts` 不随删(常设:中央建表语句建它,`Skill` 豁免截点那一行的家);库里留下的 `M42` 标记行 / 数据根里的标记文件无人再读,不删",
|
|
640
661
|
afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升的库,存量里以 `_scn:` 开头的身份被恢复管线读作某个人的场景(拆不出合文法的场景与人的 ⇒ `owner.malformed_subject` 响亮)。" +
|
|
641
662
|
"出路 = 升级时先过一次带本条的版本并起服(它扫一次、命中即拒启点名)",
|
|
663
|
+
stopThenStart: {
|
|
664
|
+
reason: "scans stored identities for the reserved scenario prefix and records a marker; an earlier replica does not reserve the prefix and would keep accepting such identities after the scan",
|
|
665
|
+
owedOn: owesScenarioPrefixSwitchM42,
|
|
666
|
+
},
|
|
642
667
|
reportKeys: ["scenarioPrefixSourcesScanned"],
|
|
643
668
|
},
|
|
644
669
|
{
|
|
@@ -647,7 +672,7 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
647
672
|
releasedOn: "2026-11-08",
|
|
648
673
|
removableAfter: "2026-12-08",
|
|
649
674
|
removal: "删本文件的 M43 步(`markWithdrawEnabledM43`,`migrateStepsOn` 里那一行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `withdrawMarkWritten`、头注 M43 段;" +
|
|
650
|
-
"`plugins/session-withdraw-sql.ts` 的 `WITHDRAW_MARK_ID` 与部署判据里读标记的那一句(撤回出口无条件启用);标记表 `one-time-migration-marker.ts`
|
|
675
|
+
"`plugins/session-withdraw-sql.ts` 的 `WITHDRAW_MARK_ID` 与部署判据里读标记的那一句(撤回出口无条件启用);标记表 `one-time-migration-marker.ts` 不随删(常设)、`plugins/session-birth.ts` 的 `upgrade_pending` 词与出口计数里的同名词;" +
|
|
651
676
|
"local 会话元数据格「没有 `clientWrites` 位 ⇒ upgrade_pending」那一臂;库里留下的标记行无人再读,不删(与 M42 同一张标记表)",
|
|
652
677
|
afterRemoval: "窗 30 天之后更早版本的副本早已不在;标记行不再被任何读者读(留着无害)。跳过了带本条的版本直接升上来的库:撤回出口从第一次起服就启用 —— " +
|
|
653
678
|
"跨两版以上的混跑本就不被支持(7.147.0 起的停-迁-起)。出路 = 升级时先过一次带本条的版本并起服",
|
|
@@ -685,9 +710,16 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
685
710
|
removableAfter: "2026-12-08",
|
|
686
711
|
removal: "删 `src/plugins/approval-exemption-skill-m46.ts` 整个文件;本文件的 M46 步(`dropLegacySkillExemptionsM46`,`migrateStepsOn` 里那一行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `legacySkillExemptionsDropped`、头注 M46 段、`logReceiptRows` 里的 `legacy_skill_exemptions_dropped` 一行;" +
|
|
687
712
|
"`approval-exemption-store.ts` 的 `FileApprovalExemptionStore.dropToolRowsCreatedBeforeM46` 与 `LocalBackend.runOneTimeMigrations` 里那一格;" +
|
|
688
|
-
"`test/approval-exemption-skill-m46.test.ts` 整个文件、`test/one-time-migrations-db-integration.test.ts` 的 M46
|
|
689
|
-
|
|
690
|
-
"
|
|
713
|
+
"`test/approval-exemption-skill-m46.test.ts` 整个文件、`test/one-time-migrations-db-integration.test.ts` 的 M46 组;" +
|
|
714
|
+
"跳版拒启臂的豁免:`store-backend.ts` 的 `withRetiredSchemaProbe` 与 `local-data-root-admission.ts` 的 `admitLocalDataRoot` 各一处 `migrationCarried(SKILL_EXEMPTION_CUTOFF_ID)` 实参、" +
|
|
715
|
+
"`assertSkillExemptionCutoffHeldOnPool` / `judgeSqlSkillExemptionCutoff` / `judgeLocalSkillExemptionCutoff` 的 `carried` 参数与它那一支(臂恒判;截点读不出的拒本来就不看它)。" +
|
|
716
|
+
"**不随本条删**(常设):`approval-exemption-skill-cutoff.ts` 整只(截点、工具名、两车道的判与落)、标记表 `one-time-migration-marker.ts` 与它的 `M46` 行(截点的家)、" +
|
|
717
|
+
"数据根里的 `one-time-migration-M46.marker`、`ensureSchema()` 的截点种子行、数据根准入锁内一步的落截点、`approval-exemption-store.ts` 的 `readExemptionLog`",
|
|
718
|
+
afterRemoval: "跳版拒启臂接住(常设,起服对账一族,先于本次起服对这只库的任何写;`approval-exemption-skill-cutoff.ts`):库里有首次放行早于 `Skill` 豁免截点 T0 的 `Skill` 行" +
|
|
719
|
+
"(SQL:标记表 `M46` 行 / local:`one-time-migration-M46.marker`;T0 缺席 ⇒ 任一 `Skill` 行)⇒ 拒启 `config.schema_mismatch`,零写 —— " +
|
|
720
|
+
"SQL 在 `ensureSchema()` 建表之前(`LegacySkillExemptionsPresentError`,与退役 schema 探针同一处),local 在数据根准入(读数种别 `skipped-required-migration`)。" +
|
|
721
|
+
"出路 = 先用一个仍带本条、不低于 7.148.0(local 还要不低于拒句里已记的引擎高水位)的版本对这只库完整起一次,再升;SQL 另可手工 `DELETE FROM approval_exemption WHERE tool_name = 'Skill'`。" +
|
|
722
|
+
"T0 由常设的一步落(SQL:`ensureSchema()` 建表之后的种子行;local:准入的锁内一步):判过、缺席才落 —— 删码之后全新的库照样有 T0,不会被自己写下的合法行拒",
|
|
691
723
|
reportKeys: ["legacySkillExemptionsDropped"],
|
|
692
724
|
},
|
|
693
725
|
{
|
|
@@ -695,13 +727,13 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
695
727
|
introducedIn: "7.148.0",
|
|
696
728
|
releasedOn: "2026-11-08",
|
|
697
729
|
removableAfter: "2026-12-08",
|
|
698
|
-
removal: "删 `LocalSessionStore.adoptArchiveTokensM47`(含欠账起服的 `required` 分档、证明 `assertArchiveTokensAdoptedM47` / `adoptionScopeOf` / `skippedFromAdoption` 与它那一处销账)与 `LocalArchiveTokenAdoption
|
|
730
|
+
removal: "删 `LocalSessionStore.adoptArchiveTokensM47`(含欠账起服的 `required` 分档、证明 `assertArchiveTokensAdoptedM47` / `adoptionScopeOf` / `skippedFromAdoption` 与它那一处销账)与 `LocalArchiveTokenAdoption`;" +
|
|
699
731
|
"收令牌欠账的记账(`recordArchiveTokenAdoptionPending`);窗内长第一格的规则 `firstCellIncarnationOf` / `LocalSessionStore.firstCellIncarnationHeld`(调用点 —— 补铸、登记、执行位回填、M33 的行回填与快照恢复 —— 回到新铸);" +
|
|
700
|
-
"`
|
|
732
|
+
"`judgeArchiveTokenAdoptionDuty` 的 `adoptionCarried` 参数与 `record` 那一支(`ArchiveTokenAdoptionDutyAction` 随之少 `record`,`settleArchiveTokenAdoptionDuty` 的那一臂同删)、`local-data-root-admission.ts` 里传它的那一处 `migrationCarried(\"M47\")`(臂恒判);" +
|
|
701
733
|
"`LocalBackend.ensureSchema` 里对 `adoptArchiveTokensM47` 的调用与两只读数字段、`runOneTimeMigrations` 里报告两键那几行;报告 / 收据 / `changedAnything` / `readingFields` / `NO_SQL_MIGRATIONS` 的 `localArchiveTokensAdopted` / `localArchiveTokensMinted`、头注 M47 段;" +
|
|
702
734
|
"M33 也已删码时连同 `archivedRowFactsOf` / `ArchivedRowFacts`;`test/local-root-one-row-store.test.ts` 里标题含 `P3` / `P4` 的格。" +
|
|
703
|
-
"**不随本条删**:跳版拒启臂 `
|
|
704
|
-
afterRemoval: "跳版拒启臂接住(
|
|
735
|
+
"**不随本条删**:跳版拒启臂 `judgeArchiveTokenAdoptionDuty`(不带本条那一支:标记在而无格存档为零 ⇒ `discharge`)/ `settleArchiveTokenAdoptionDuty` / `readSessionMetaCellsSync` / `archiveTokenAdoptionPendingPresent` / `dischargeArchiveTokenAdoptionPending` / `ARCHIVE_TOKEN_ADOPTION_SINCE`、读数种别 `skipped-required-migration` 与它按高水位分支的拒句(常设)",
|
|
736
|
+
afterRemoval: "跳版拒启臂接住(常设,数据根准入的一格:只读、本进程第一笔写之前、引擎高水位抬之前):(打开之前的引擎高水位早于 7.148.0 或缺席 ∨ 数据根里的收令牌欠账标记还在 —— 带本条的版本打开过、没收完)" +
|
|
705
737
|
"∧ 根里有存档在而会话元数据格缺的会话 ⇒ 拒启 `config.schema_mismatch`(读数种别 `skipped-required-migration`,点名会话数与版本),零写、不抬高水位 —— " +
|
|
706
738
|
"出路 = 先用一个仍带本条、不低于 7.148.0 且不低于已记高水位的版本(服务或 run-local)完整起一次,再升",
|
|
707
739
|
reportKeys: ["localArchiveTokensAdopted", "localArchiveTokensMinted"],
|
|
@@ -711,14 +743,14 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
711
743
|
introducedIn: "7.148.0",
|
|
712
744
|
releasedOn: "2026-11-08",
|
|
713
745
|
removableAfter: "2026-12-08",
|
|
714
|
-
removal: "删 `src/plugins/shell-sentinel-owner-m48.ts` 整个文件;本文件的 M48 步(`clearShellSentinelOwnersM48`,`migrateStepsOn` 里那一行)、报告 / 收据 / 日志的 `shellSentinelOwnersCleared
|
|
746
|
+
removal: "删 `src/plugins/shell-sentinel-owner-m48.ts` 整个文件;本文件的 M48 步(`clearShellSentinelOwnersM48`,`migrateStepsOn` 里那一行)、报告 / 收据 / `changedAnything` / `readingFields` / `readingsSnapshot` / 日志的 `shellSentinelOwnersCleared` 与 `shellSentinelOwnerRowsRetained`(连同 `logReceiptRows` 里 `shell_sentinel_rows_retained` 那一支)、头注 M48 段;" +
|
|
715
747
|
"`SqlOneTimeMigrationInput` 里 M48 那一半(`ShellSentinelOwnerInput`)与它在两只 SQL 后端 / 测试夹具上的实参(`identityBoundary`);" +
|
|
716
|
-
"local 腿 `LocalSessionStore.clearShellSentinelOwnersM48` / `FileRunStore.clearShellSentinelOwnersM48`
|
|
748
|
+
"local 腿 `LocalSessionStore.clearShellSentinelOwnersM48` / `countShellSentinelOwnersM48` 与 `FileRunStore.clearShellSentinelOwnersM48` / `countShellSentinelOwnersM48`,以及 `LocalBackend.runOneTimeMigrations` 里那两格(改写读数与留存读数)(连同后端的 `identityBoundary` 字段);部署形表行 `identityBoundary` 不随删(dev-open 判据读它);" +
|
|
717
749
|
"`test/shell-sentinel-owner-m48.test.ts` 整个文件、`test/one-time-migrations-db-integration.test.ts` 的 M48 组",
|
|
718
750
|
afterRemoval: "没有响亮臂(如实):没有身份边界的部署跳过了带本条的版本直接升上来,哨兵属主的存量行仍记着那个字面量,属主面表已不认它 —— 不带主体的本地单用户读不到、续不上那些会话与 run(404)," +
|
|
719
751
|
"带同一个头的请求仍读得到(属主相同)。出路 = 升级时先过一次带本条的版本并起服(或运维手工 `UPDATE <表> SET owner = NULL WHERE owner = 'anon:shell-live'`,三张表见删法)。" +
|
|
720
752
|
"有身份边界的部署本条本来就零改写,删码前后同答(哨兵是一位普通的具名属主)",
|
|
721
|
-
reportKeys: ["shellSentinelOwnersCleared"],
|
|
753
|
+
reportKeys: ["shellSentinelOwnersCleared", "shellSentinelOwnerRowsRetained"],
|
|
722
754
|
},
|
|
723
755
|
{
|
|
724
756
|
id: "M49",
|
|
@@ -752,10 +784,27 @@ export const ONE_TIME_MIGRATIONS = [
|
|
|
752
784
|
removableAfter: "2026-12-08",
|
|
753
785
|
removal: "删本文件的 M51 步(`switchSessionDeletingM51` / `SessionDeletingSwitchRefusedError` / `SESSION_DELETING_SWITCH_REFUSED_CODE` / `SESSION_DELETING_MARK_ID`,`migrateStepsOn` 里那一行)、" +
|
|
754
786
|
"报告 / 收据 / `changedAnything` / `readingFields` / `NO_SQL_MIGRATIONS` 的 `sessionDeletingSwitchMarked`、头注 M51 段;`test/session-deleting-state-db-integration.test.ts` 的 M51 组;" +
|
|
755
|
-
"
|
|
787
|
+
"库里留下的 `M51` 标记行无人再读,不删。**不随本条删**:在删态本身(列、围栏、规则 L 的在删半、终刀判令牌 —— 常设)、标记表 `one-time-migration-marker.ts`(常设)",
|
|
756
788
|
afterRemoval: "没有响亮臂(也无需):窗 30 天之后更早版本的副本早已不在;跳过了带本条的版本直接升上来的库 —— 跨两版以上的混跑本就不被支持(7.147.0 起的停-迁-起)。出路 = 升级时先过一次带本条的版本并起服",
|
|
789
|
+
stopThenStart: {
|
|
790
|
+
reason: "switches session deletion to a deleting state that every replica must read; an earlier replica does not read it and would accept a submission on a session this version is deleting",
|
|
791
|
+
owedOn: owesSessionDeletingSwitchM51,
|
|
792
|
+
},
|
|
757
793
|
reportKeys: ["sessionDeletingSwitchMarked"],
|
|
758
794
|
},
|
|
795
|
+
{
|
|
796
|
+
id: "M52",
|
|
797
|
+
introducedIn: "7.150.0",
|
|
798
|
+
releasedOn: "2026-11-09",
|
|
799
|
+
removableAfter: "2026-12-09",
|
|
800
|
+
removal: "删 `readOlderReplicaEvidence` 的心跳一半(按 `instance_id` 分组读 `task_run` 心跳的那一句、减去登记为知道该迁移的持有者那一步)与它的判活窗输入:`LiveRunWindowInput`、`SqlOneTimeMigrationInput` 里的那一半、" +
|
|
801
|
+
"`store-backend.ts` 的 `buildSqlOneTimeMigrationInput` 读 `runStaleSec` 的那一半、夹具 `test/helpers/db-schema-boot.ts` 的 `liveRunWindowMs`;停-迁-起守卫若已全部删码(M40 / M41 / M42 / M43 / M51 的窗都早于本条关)," +
|
|
802
|
+
"连同 `readOlderReplicaEvidence` 与 `stop-then-start-sentence.ts` 的 `OlderReplicaEvidence` / `OlderReplicaHolder` / `olderReplicaEvidenceSentence` 一并删;" +
|
|
803
|
+
"`test/run-liveness-single-source-gate.test.ts` ② 的 `one-time-migrations.ts` 白名单行与 ③ `store-backend.ts` 理由里「一次性迁移守卫」半句;`test/older-replica-evidence-db-integration.test.ts` 的证据组;头注 M52 段。" +
|
|
804
|
+
"**不随本条删**:副本能力登记(`replica-registration.ts`,能力名单只增)与起服准入(`serving-requirement.ts`)—— 常设",
|
|
805
|
+
afterRemoval: "没有响亮臂(如实):早于副本登记的副本不登记,删码之后它们对停-迁-起守卫完全不可见,忙与闲同 —— 发布日之后的天数不证明旧进程不在;出路只有运维:起带停-迁-起迁移的版本之前停光早于本条的副本",
|
|
806
|
+
reportKeys: [],
|
|
807
|
+
},
|
|
759
808
|
];
|
|
760
809
|
export function migrationWindowOpen(window, today) {
|
|
761
810
|
return window.removableAfter === null || today <= window.removableAfter;
|
|
@@ -768,21 +817,11 @@ export function migrationWindowEnd(id) {
|
|
|
768
817
|
throw new Error(`one-time-migrations: ${id} is in the unreleased form (removableAfter: null) — there is no window end to quote yet`);
|
|
769
818
|
return row.removableAfter;
|
|
770
819
|
}
|
|
771
|
-
export function
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
for (const column of columns) {
|
|
777
|
-
const owner = owners.get(column);
|
|
778
|
-
if (owner !== undefined)
|
|
779
|
-
throw new Error(`one-time-migrations: ${table}.${column} is claimed as dropped by both ${owner} and ${row.id} — one column has one dropping migration`);
|
|
780
|
-
owners.set(column, row.id);
|
|
781
|
-
}
|
|
782
|
-
removals.set(table, owners);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
return removals;
|
|
820
|
+
export function migrationCarried(id) {
|
|
821
|
+
return ONE_TIME_MIGRATIONS.some((w) => w.id === id);
|
|
822
|
+
}
|
|
823
|
+
export function stopThenStartMigrations(registry = ONE_TIME_MIGRATIONS) {
|
|
824
|
+
return registry.flatMap((row) => (row.stopThenStart === undefined ? [] : [{ id: row.id, ...row.stopThenStart }]));
|
|
786
825
|
}
|
|
787
826
|
export const NO_SQL_MIGRATIONS = {
|
|
788
827
|
sessionRuleColumn: "file-store",
|
|
@@ -872,16 +911,27 @@ async function columnExists(db, dialect, table, column) {
|
|
|
872
911
|
export function createSqlImportedLayerRootSource(exec) {
|
|
873
912
|
return { candidateOwners: async () => ({ owners: await listRuleBucketOwners(exec), unnamedBuckets: 0 }), durable: new SqlDurableRulePartitionProvider(exec), isWholeBucketRefusal: isSqlBucketRefusal, isVanishedBucket: isSqlBucketVanished };
|
|
874
913
|
}
|
|
875
|
-
export async function runSqlOneTimeMigrations(dialect, pool, input) {
|
|
876
|
-
|
|
914
|
+
export async function runSqlOneTimeMigrations(dialect, pool, input, me = buildThisReplicaRegistration()) {
|
|
915
|
+
const head = async (db) => {
|
|
916
|
+
await assertReplicaTablesPresent(db, dialect, me);
|
|
917
|
+
await registerReplica(db, dialect, me, Date.now());
|
|
918
|
+
await assertServingRequirementsMet(db, me);
|
|
919
|
+
};
|
|
920
|
+
const locked = async (db) => {
|
|
921
|
+
await assertServingRequirementsMet(db, me);
|
|
922
|
+
return migrateOn(db, dialect, input);
|
|
923
|
+
};
|
|
924
|
+
return dialect === "mysql" ? withMysqlLock(pool, head, locked) : withPgLock(pool, head, locked);
|
|
877
925
|
}
|
|
878
|
-
async function withMysqlLock(pool, run) {
|
|
926
|
+
async function withMysqlLock(pool, head, run) {
|
|
879
927
|
const conn = await pool.getConnection();
|
|
880
928
|
let locked = false;
|
|
881
929
|
try {
|
|
930
|
+
const db = mysqlDb(conn);
|
|
931
|
+
await head(db);
|
|
882
932
|
await acquireEnsureSchemaLock(conn, "oneTimeMigrations");
|
|
883
933
|
locked = true;
|
|
884
|
-
return await run(
|
|
934
|
+
return await run(db);
|
|
885
935
|
}
|
|
886
936
|
finally {
|
|
887
937
|
if (locked)
|
|
@@ -889,13 +939,15 @@ async function withMysqlLock(pool, run) {
|
|
|
889
939
|
conn.release();
|
|
890
940
|
}
|
|
891
941
|
}
|
|
892
|
-
async function withPgLock(pool, run) {
|
|
942
|
+
async function withPgLock(pool, head, run) {
|
|
893
943
|
const client = await pool.connect();
|
|
894
944
|
let locked = false;
|
|
895
945
|
try {
|
|
946
|
+
const db = pgDb(client);
|
|
947
|
+
await head(db);
|
|
896
948
|
await acquirePgEnsureSchemaLock(client, "oneTimeMigrations");
|
|
897
949
|
locked = true;
|
|
898
|
-
return await run(
|
|
950
|
+
return await run(db);
|
|
899
951
|
}
|
|
900
952
|
finally {
|
|
901
953
|
if (locked)
|
|
@@ -1007,13 +1059,18 @@ async function rewriteRunObjectivePreviewM45(db, dialect, receipts) {
|
|
|
1007
1059
|
}
|
|
1008
1060
|
}
|
|
1009
1061
|
export async function clearShellSentinelOwnersM48(db, dialect, receipts, input) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
const sentinelOwner = dialect === "mysql" ? "CAST(owner AS BINARY) = CAST(? AS BINARY)" : "owner = $1";
|
|
1062
|
+
const rewrite = input.identityBoundary === false;
|
|
1063
|
+
const sentinelOwner = shellSentinelOwnerWhereM48(dialect);
|
|
1013
1064
|
for (const table of SHELL_SENTINEL_OWNER_TABLES_M48) {
|
|
1014
1065
|
if (!(await tableExists(db, dialect, table)))
|
|
1015
1066
|
continue;
|
|
1016
|
-
|
|
1067
|
+
if (rewrite) {
|
|
1068
|
+
receipts.shellSentinelOwnersCleared += await db.exec(`UPDATE ${table} SET owner = NULL WHERE ${sentinelOwner}`, [SHELL_SENTINEL_OWNER_M48]);
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
const rows = Number((await db.rows(`SELECT COUNT(*) AS n FROM ${table} WHERE ${sentinelOwner}`, [SHELL_SENTINEL_OWNER_M48]))[0]?.["n"] ?? 0);
|
|
1072
|
+
if (rows > 0)
|
|
1073
|
+
receipts.shellSentinelOwnerRowsRetained.push({ surface: table, rows });
|
|
1017
1074
|
}
|
|
1018
1075
|
}
|
|
1019
1076
|
const HOST_SESSION_BACKFILL_PAGE = 500;
|
|
@@ -1038,27 +1095,22 @@ export async function dropLegacySkillExemptionsM46(db, dialect, receipts) {
|
|
|
1038
1095
|
if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
|
|
1039
1096
|
await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
|
|
1040
1097
|
const ph = (i) => (dialect === "mysql" ? "?" : `$${i}`);
|
|
1041
|
-
const readMark =
|
|
1042
|
-
const [row] = await db.rows(`SELECT marked_at_ms FROM ${MIGRATION_MARKER_TABLE} WHERE migration_id = ${ph(1)}`, [LEGACY_SKILL_EXEMPTION_MARKER_ID]);
|
|
1043
|
-
return row === undefined ? undefined : Number(row["marked_at_ms"]);
|
|
1044
|
-
};
|
|
1098
|
+
const readMark = () => readSqlSkillExemptionCutoff((sql, params) => db.rows(sql, params), dialect);
|
|
1045
1099
|
let markedAtMs = await readMark();
|
|
1046
1100
|
if (markedAtMs === undefined) {
|
|
1047
|
-
await db.exec(dialect
|
|
1048
|
-
? `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES (?, ?) ON DUPLICATE KEY UPDATE migration_id = migration_id`
|
|
1049
|
-
: `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES ($1, $2) ON CONFLICT (migration_id) DO NOTHING`, [LEGACY_SKILL_EXEMPTION_MARKER_ID, Date.now()]);
|
|
1101
|
+
await db.exec(markIfAbsentSql(dialect), [SKILL_EXEMPTION_CUTOFF_ID, Date.now()]);
|
|
1050
1102
|
markedAtMs = await readMark();
|
|
1051
1103
|
}
|
|
1052
|
-
if (markedAtMs === undefined
|
|
1053
|
-
throw new Error("one-time migration M46: the marker row is missing
|
|
1104
|
+
if (markedAtMs === undefined)
|
|
1105
|
+
throw new Error("one-time migration M46: the marker row is missing right after it was written — refusing to delete rows without a recorded cutoff");
|
|
1054
1106
|
const cutoff = new Date(markedAtMs);
|
|
1055
1107
|
let after = "";
|
|
1056
1108
|
for (;;) {
|
|
1057
|
-
const page = await db.rows(`SELECT session_id FROM approval_exemption WHERE tool_name = ${ph(1)} AND created_at < ${ph(2)} AND session_id > ${ph(3)} ORDER BY session_id LIMIT ${LEGACY_SKILL_EXEMPTION_PAGE}`, [
|
|
1109
|
+
const page = await db.rows(`SELECT session_id FROM approval_exemption WHERE tool_name = ${ph(1)} AND created_at < ${ph(2)} AND session_id > ${ph(3)} ORDER BY session_id LIMIT ${LEGACY_SKILL_EXEMPTION_PAGE}`, [SKILL_EXEMPTION_TOOL_NAME, cutoff, after]);
|
|
1058
1110
|
if (page.length === 0)
|
|
1059
1111
|
return;
|
|
1060
1112
|
const sessionIds = page.map((r) => String(r["session_id"]));
|
|
1061
|
-
receipts.legacySkillExemptionsDropped += await db.exec(`DELETE FROM approval_exemption WHERE tool_name = ${ph(1)} AND created_at < ${ph(2)} AND session_id IN (${sessionIds.map((_, i) => ph(i + 3)).join(", ")})`, [
|
|
1113
|
+
receipts.legacySkillExemptionsDropped += await db.exec(`DELETE FROM approval_exemption WHERE tool_name = ${ph(1)} AND created_at < ${ph(2)} AND session_id IN (${sessionIds.map((_, i) => ph(i + 3)).join(", ")})`, [SKILL_EXEMPTION_TOOL_NAME, cutoff, ...sessionIds]);
|
|
1062
1114
|
if (page.length < LEGACY_SKILL_EXEMPTION_PAGE)
|
|
1063
1115
|
return;
|
|
1064
1116
|
after = sessionIds[sessionIds.length - 1];
|
|
@@ -1070,38 +1122,50 @@ async function markWithdrawEnabledM43(db, dialect, receipts, input) {
|
|
|
1070
1122
|
const marked = await db.rows(dialect === "mysql" ? `SELECT 1 AS present FROM ${MIGRATION_MARKER_TABLE} WHERE migration_id = ?` : `SELECT 1 AS present FROM ${MIGRATION_MARKER_TABLE} WHERE migration_id = $1`, [WITHDRAW_MARK_ID]);
|
|
1071
1123
|
if (marked.length > 0)
|
|
1072
1124
|
return;
|
|
1073
|
-
if ((await
|
|
1125
|
+
if ((await readOlderReplicaEvidence(db, dialect, input, "M43")) !== undefined)
|
|
1074
1126
|
return;
|
|
1075
|
-
receipts.withdrawMarkWritten += await db.exec(dialect
|
|
1076
|
-
|
|
1077
|
-
|
|
1127
|
+
receipts.withdrawMarkWritten += await db.exec(markIfAbsentSql(dialect), [WITHDRAW_MARK_ID, Date.now()]);
|
|
1128
|
+
}
|
|
1129
|
+
async function migrationMarked(read, dialect, id) {
|
|
1130
|
+
if (!(await tableExists({ rows: read }, dialect, MIGRATION_MARKER_TABLE)))
|
|
1131
|
+
return false;
|
|
1132
|
+
return (await read(`SELECT 1 AS present FROM ${MIGRATION_MARKER_TABLE} WHERE migration_id = '${id}'`)).length > 0;
|
|
1133
|
+
}
|
|
1134
|
+
async function owesExecutionLaneRenameM40(read, dialect) {
|
|
1135
|
+
return (await executionLaneWordRowsM40(read, dialect)).pendingRows > 0;
|
|
1136
|
+
}
|
|
1137
|
+
async function owesSessionExtMoveM41(read, dialect) {
|
|
1138
|
+
return (await deploymentColumnsOnMeta({ rows: read }, dialect)).length > 0;
|
|
1139
|
+
}
|
|
1140
|
+
async function owesScenarioPrefixSwitchM42(read, dialect) {
|
|
1141
|
+
return !(await migrationMarked(read, dialect, SCENARIO_PREFIX_MARKER_ID));
|
|
1142
|
+
}
|
|
1143
|
+
async function owesSessionDeletingSwitchM51(read, dialect) {
|
|
1144
|
+
return !(await migrationMarked(read, dialect, SESSION_DELETING_MARK_ID));
|
|
1078
1145
|
}
|
|
1079
1146
|
export const SESSION_DELETING_MARK_ID = "M51";
|
|
1080
1147
|
export const SESSION_DELETING_SWITCH_REFUSED_CODE = "config.session_deleting_switch_refused";
|
|
1081
1148
|
export class SessionDeletingSwitchRefusedError extends StoreBootRefusalError {
|
|
1082
1149
|
code = SESSION_DELETING_SWITCH_REFUSED_CODE;
|
|
1083
|
-
reason = "
|
|
1084
|
-
constructor(
|
|
1085
|
-
super(`${SESSION_DELETING_SWITCH_REFUSED_CODE} (reason:
|
|
1086
|
-
`(a submission on a session being deleted is refused), but ${
|
|
1150
|
+
reason = "older_replica";
|
|
1151
|
+
constructor(evidence, tail = "") {
|
|
1152
|
+
super(`${SESSION_DELETING_SWITCH_REFUSED_CODE} (reason: older_replica): this version deletes a session through a deleting state that every replica must read ` +
|
|
1153
|
+
`(a submission on a session being deleted is refused), but ${olderReplicaEvidenceSentence(evidence)} — ` +
|
|
1087
1154
|
"a replica of an earlier version may still be serving; it does not read that state and would accept a submission on a session this version is deleting. Nothing was changed and no marker was written. " +
|
|
1088
|
-
|
|
1089
|
-
|
|
1155
|
+
stopThenStartAction(evidence.after) +
|
|
1156
|
+
tail);
|
|
1090
1157
|
this.name = "SessionDeletingSwitchRefusedError";
|
|
1091
1158
|
}
|
|
1092
1159
|
}
|
|
1093
1160
|
async function switchSessionDeletingM51(db, dialect, receipts, input) {
|
|
1094
1161
|
if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
|
|
1095
1162
|
await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
|
|
1096
|
-
|
|
1097
|
-
if (marked.length > 0)
|
|
1163
|
+
if (!(await owesSessionDeletingSwitchM51((sql) => db.rows(sql), dialect)))
|
|
1098
1164
|
return;
|
|
1099
|
-
const
|
|
1100
|
-
if (
|
|
1101
|
-
throw new SessionDeletingSwitchRefusedError(
|
|
1102
|
-
receipts.sessionDeletingSwitchMarked += await db.exec(dialect
|
|
1103
|
-
? `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES (?, ?) ON DUPLICATE KEY UPDATE migration_id = migration_id`
|
|
1104
|
-
: `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES ($1, $2) ON CONFLICT (migration_id) DO NOTHING`, [SESSION_DELETING_MARK_ID, Date.now()]);
|
|
1165
|
+
const evidence = await readOlderReplicaEvidence(db, dialect, input, "M51");
|
|
1166
|
+
if (evidence !== undefined)
|
|
1167
|
+
throw new SessionDeletingSwitchRefusedError(evidence, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
|
|
1168
|
+
receipts.sessionDeletingSwitchMarked += await db.exec(markIfAbsentSql(dialect), [SESSION_DELETING_MARK_ID, Date.now()]);
|
|
1105
1169
|
}
|
|
1106
1170
|
export async function scannedIdentityColumnsM42(db, dialect) {
|
|
1107
1171
|
const scope = dialect === "mysql" ? "DATABASE()" : "current_schema()";
|
|
@@ -1120,8 +1184,7 @@ export async function scannedIdentityColumnsM42(db, dialect) {
|
|
|
1120
1184
|
export async function switchScenarioPrefixM42(db, dialect, receipts, input) {
|
|
1121
1185
|
if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
|
|
1122
1186
|
await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
|
|
1123
|
-
|
|
1124
|
-
if (marked.length > 0)
|
|
1187
|
+
if (!(await owesScenarioPrefixSwitchM42((sql) => db.rows(sql), dialect)))
|
|
1125
1188
|
return;
|
|
1126
1189
|
const columns = await scannedIdentityColumnsM42(db, dialect);
|
|
1127
1190
|
const hits = [];
|
|
@@ -1133,13 +1196,11 @@ export async function switchScenarioPrefixM42(db, dialect, receipts, input) {
|
|
|
1133
1196
|
}
|
|
1134
1197
|
receipts.scenarioPrefixSourcesScanned += columns.length;
|
|
1135
1198
|
if (hits.length > 0)
|
|
1136
|
-
throw new ScenarioPrefixSwitchRefusedError("stored_prefix", hits);
|
|
1137
|
-
const
|
|
1138
|
-
if (
|
|
1139
|
-
throw new ScenarioPrefixSwitchRefusedError("
|
|
1140
|
-
await db.exec(dialect
|
|
1141
|
-
? `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES (?, ?) ON DUPLICATE KEY UPDATE migration_id = migration_id`
|
|
1142
|
-
: `INSERT INTO ${MIGRATION_MARKER_TABLE} (migration_id, marked_at_ms) VALUES ($1, $2) ON CONFLICT (migration_id) DO NOTHING`, [SCENARIO_PREFIX_MARKER_ID, Date.now()]);
|
|
1199
|
+
throw new ScenarioPrefixSwitchRefusedError("stored_prefix", hits, undefined, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
|
|
1200
|
+
const evidence = await readOlderReplicaEvidence(db, dialect, input, "M42");
|
|
1201
|
+
if (evidence !== undefined)
|
|
1202
|
+
throw new ScenarioPrefixSwitchRefusedError("older_replica", [], evidence, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
|
|
1203
|
+
await db.exec(markIfAbsentSql(dialect), [SCENARIO_PREFIX_MARKER_ID, Date.now()]);
|
|
1143
1204
|
}
|
|
1144
1205
|
export const EXECUTION_LANE_RENAME_REFUSED_CODE = "config.execution_lane_rename_refused";
|
|
1145
1206
|
export class ExecutionLaneRenameRefusedError extends StoreBootRefusalError {
|
|
@@ -1171,16 +1232,20 @@ export class ExecutionLaneRenameWriteRefusedError extends StoreBootRefusalError
|
|
|
1171
1232
|
}
|
|
1172
1233
|
}
|
|
1173
1234
|
const EXECUTION_LANE_TABLES = [APPROVAL_ASK_TABLE, "session_meta", SESSION_EXT_TABLE];
|
|
1174
|
-
|
|
1235
|
+
async function executionLaneWordRowsM40(read, dialect) {
|
|
1175
1236
|
const tables = [];
|
|
1176
1237
|
for (const table of EXECUTION_LANE_TABLES)
|
|
1177
|
-
if (await columnExists(
|
|
1238
|
+
if (await columnExists({ rows: read }, dialect, table, "execution_lane"))
|
|
1178
1239
|
tables.push(table);
|
|
1179
1240
|
let pendingRows = 0;
|
|
1180
1241
|
for (const table of tables) {
|
|
1181
|
-
const [row] = await
|
|
1242
|
+
const [row] = await read(`SELECT COUNT(*) AS n FROM ${table} WHERE execution_lane = '${RETIRED_EXECUTION_LANE_WORD_M40}'`);
|
|
1182
1243
|
pendingRows += Number(row?.["n"] ?? 0);
|
|
1183
1244
|
}
|
|
1245
|
+
return { tables, pendingRows };
|
|
1246
|
+
}
|
|
1247
|
+
export async function renameRetiredExecutionLaneWordsM40(db, dialect, receipts, input) {
|
|
1248
|
+
const { tables, pendingRows } = await executionLaneWordRowsM40((sql) => db.rows(sql), dialect);
|
|
1184
1249
|
if (pendingRows === 0)
|
|
1185
1250
|
return;
|
|
1186
1251
|
await refuseWhileRunsHeartbeat(db, dialect, pendingRows, input);
|
|
@@ -1188,35 +1253,55 @@ export async function renameRetiredExecutionLaneWordsM40(db, dialect, receipts,
|
|
|
1188
1253
|
receipts.executionLaneWordsRenamed += await db.exec(dialect === "mysql" ? `UPDATE ${table} SET execution_lane = ? WHERE execution_lane = ?` : `UPDATE ${table} SET execution_lane = $1 WHERE execution_lane = $2`, [RENAMED_EXECUTION_LANE_M40, RETIRED_EXECUTION_LANE_WORD_M40]);
|
|
1189
1254
|
}
|
|
1190
1255
|
}
|
|
1191
|
-
async function
|
|
1256
|
+
export async function readOlderReplicaEvidence(db, dialect, input, migrationId) {
|
|
1192
1257
|
if (!(await tableExists(db, dialect, "task_run")))
|
|
1193
1258
|
return undefined;
|
|
1194
1259
|
const since = new Date(Date.now() - input.liveRunWindowMs);
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1260
|
+
const groups = (await db.rows(`SELECT instance_id, COUNT(*) AS n, MAX(updated_at) AS newest FROM task_run WHERE status = 'running' AND updated_at >= ${dialect === "mysql" ? "?" : "$1"} GROUP BY instance_id`, [since]))
|
|
1261
|
+
.map((r) => ({ holder: typeof r["instance_id"] === "string" ? r["instance_id"] : undefined, runs: Number(r["n"] ?? 0), newest: r["newest"] }))
|
|
1262
|
+
.filter((g) => g.runs > 0);
|
|
1263
|
+
if (groups.length === 0)
|
|
1264
|
+
return undefined;
|
|
1265
|
+
const registered = await readReplicaRegistrations({ query: async (sql, params) => ({ rows: await db.rows(sql, params), affected: 0 }) }, dialect, groups.flatMap((g) => (g.holder === undefined ? [] : [g.holder])));
|
|
1266
|
+
let unregisteredRuns = 0;
|
|
1267
|
+
let newestMs = Number.NaN;
|
|
1268
|
+
const registeredWithout = [];
|
|
1269
|
+
for (const g of groups) {
|
|
1270
|
+
const r = g.holder === undefined ? undefined : registered.get(g.holder);
|
|
1271
|
+
if (r !== undefined && knowsCapability(r.capabilities, migrationId))
|
|
1272
|
+
continue;
|
|
1273
|
+
if (r === undefined)
|
|
1274
|
+
unregisteredRuns += g.runs;
|
|
1275
|
+
else
|
|
1276
|
+
registeredWithout.push({ instanceId: r.instanceId, releaseLine: r.releaseLine, hostName: r.hostName, pid: r.pid, runs: g.runs });
|
|
1277
|
+
const cell = g.newest instanceof Date ? g.newest : new Date(String(g.newest));
|
|
1278
|
+
if (!Number.isNaN(cell.getTime()) && !(cell.getTime() <= newestMs))
|
|
1279
|
+
newestMs = cell.getTime();
|
|
1280
|
+
}
|
|
1281
|
+
const liveRuns = unregisteredRuns + registeredWithout.reduce((n, h) => n + h.runs, 0);
|
|
1197
1282
|
if (liveRuns === 0)
|
|
1198
1283
|
return undefined;
|
|
1199
|
-
const newestCell = row?.["newest"];
|
|
1200
|
-
const newest = newestCell instanceof Date ? newestCell : new Date(String(newestCell));
|
|
1201
1284
|
const now = Date.now();
|
|
1202
|
-
const restartAtMs = (Number.isNaN(
|
|
1285
|
+
const restartAtMs = (Number.isNaN(newestMs) ? now : newestMs) + input.liveRunWindowMs;
|
|
1203
1286
|
return {
|
|
1287
|
+
migration: migrationId,
|
|
1204
1288
|
liveRuns,
|
|
1205
1289
|
windowSec: Math.round(input.liveRunWindowMs / 1000),
|
|
1206
1290
|
restartAfter: new Date(restartAtMs).toISOString(),
|
|
1207
1291
|
after: `${new Date(restartAtMs).toISOString()} (${Math.max(0, Math.ceil((restartAtMs - now) / 1000))}s from now)`,
|
|
1292
|
+
unregisteredRuns,
|
|
1293
|
+
registeredWithout: registeredWithout.sort((a, b) => a.instanceId.localeCompare(b.instanceId)),
|
|
1208
1294
|
};
|
|
1209
1295
|
}
|
|
1210
1296
|
async function refuseWhileRunsHeartbeat(db, dialect, pendingRows, input) {
|
|
1211
|
-
const
|
|
1212
|
-
if (
|
|
1297
|
+
const evidence = await readOlderReplicaEvidence(db, dialect, input, "M40");
|
|
1298
|
+
if (evidence === undefined)
|
|
1213
1299
|
return;
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
`If every replica is already stopped, those are the runs they left behind: start this version again after ${after}`);
|
|
1300
|
+
throw new ExecutionLaneRenameRefusedError(pendingRows, evidence.liveRuns, evidence.restartAfter, `${pendingRows} stored rows (approval asks / sessions) carry the execution lane word "${RETIRED_EXECUTION_LANE_WORD_M40}", the name an earlier version gave the lane with no execution environment, ` +
|
|
1301
|
+
`which this version calls "${RENAMED_EXECUTION_LANE_M40}" and does not read; this boot renames them (one-time migration M40), but ${olderReplicaEvidenceSentence(evidence)} ` +
|
|
1302
|
+
`— a replica of an earlier version may still be serving, and it would keep writing the old word after the rename. No stored row was changed. ` +
|
|
1303
|
+
stopThenStartAction(evidence.after) +
|
|
1304
|
+
(await describeUpgradeDriftTail((sql) => db.rows(sql), dialect)));
|
|
1220
1305
|
}
|
|
1221
1306
|
export const SESSION_EXT_MOVE_REFUSED_CODE = "config.session_ext_move_refused";
|
|
1222
1307
|
export class SessionExtMoveRefusedError extends StoreBootRefusalError {
|
|
@@ -1246,14 +1331,14 @@ export async function refuseSessionExtMoveWhileRunsHeartbeat(db, dialect, input)
|
|
|
1246
1331
|
const columns = await deploymentColumnsOnMeta(db, dialect);
|
|
1247
1332
|
if (columns.length === 0)
|
|
1248
1333
|
return;
|
|
1249
|
-
const
|
|
1250
|
-
if (
|
|
1334
|
+
const evidence = await readOlderReplicaEvidence(db, dialect, input, "M41");
|
|
1335
|
+
if (evidence === undefined)
|
|
1251
1336
|
return;
|
|
1252
|
-
throw new SessionExtMoveRefusedError("
|
|
1253
|
-
`(one-time migration M41: copy, verify, then drop the columns), but ${
|
|
1254
|
-
"a replica of an earlier version
|
|
1255
|
-
|
|
1256
|
-
|
|
1337
|
+
throw new SessionExtMoveRefusedError("older_replica", `${columns.length} session cells (${columns.map((c) => c.name).join(", ")}) still live on session_meta; this version keeps them on the side table ${SESSION_EXT_TABLE} and moves them on this boot ` +
|
|
1338
|
+
`(one-time migration M41: copy, verify, then drop the columns), but ${olderReplicaEvidenceSentence(evidence)} — ` +
|
|
1339
|
+
"a replica of an earlier version may still be serving; a cell it writes between the copy and the drop would be lost, and every cell write it makes after the drop fails. Nothing was changed. " +
|
|
1340
|
+
stopThenStartAction(evidence.after) +
|
|
1341
|
+
(await describeUpgradeDriftTail((sql) => db.rows(sql), dialect)));
|
|
1257
1342
|
}
|
|
1258
1343
|
export async function moveSessionCellsToSideTable(db, dialect, receipts) {
|
|
1259
1344
|
const columns = await deploymentColumnsOnMeta(db, dialect);
|
|
@@ -1283,7 +1368,6 @@ export async function moveSessionCellsToSideTable(db, dialect, receipts) {
|
|
|
1283
1368
|
await execUntil(db, `ALTER TABLE session_meta ${names.map((n) => `DROP COLUMN ${n}`).join(", ")}`, async () => (await deploymentColumnsOnMeta(db, dialect)).length === 0);
|
|
1284
1369
|
receipts.sessionMetaColumnsDropped += columns.length;
|
|
1285
1370
|
}
|
|
1286
|
-
const RETIRED_ASK_CAUSE_COLUMN = "denied_reason";
|
|
1287
1371
|
function renameAskCauseColumnSql(dialect) {
|
|
1288
1372
|
return dialect === "mysql"
|
|
1289
1373
|
? `ALTER TABLE ${APPROVAL_ASK_TABLE} CHANGE COLUMN ${RETIRED_ASK_CAUSE_COLUMN} ${APPROVAL_ASK_ENDING_CAUSE_COLUMN.mysql}`
|
|
@@ -1338,7 +1422,7 @@ async function readSwitchShape(db, dialect) {
|
|
|
1338
1422
|
}
|
|
1339
1423
|
async function askTableShape(db, dialect) {
|
|
1340
1424
|
const askTable = await tableExists(db, dialect, APPROVAL_ASK_TABLE);
|
|
1341
|
-
return { askTable, askLaneColumn: askTable && (await columnExists(db, dialect, APPROVAL_ASK_TABLE,
|
|
1425
|
+
return { askTable, askLaneColumn: askTable && (await columnExists(db, dialect, APPROVAL_ASK_TABLE, ASK_EXECUTION_LANE_COLUMN)) };
|
|
1342
1426
|
}
|
|
1343
1427
|
function switchStarted(s) {
|
|
1344
1428
|
return s.placementColumns.has("execution_role") || s.parkedTable || s.cellsOnSideTable;
|
|
@@ -1644,11 +1728,6 @@ async function dropRetiredBreakerTable(db, dialect, receipts) {
|
|
|
1644
1728
|
await execUntil(db, `DROP TABLE IF EXISTS ${RETIRED_BREAKER_TABLE}`, async () => !(await tableExists(db, dialect, RETIRED_BREAKER_TABLE)));
|
|
1645
1729
|
receipts.retiredBreakerTablesDropped += 1;
|
|
1646
1730
|
}
|
|
1647
|
-
const WORKFLOW_JOURNAL_TABLE = "workflow_journal";
|
|
1648
|
-
const WORKFLOW_JOURNAL_OWNER_TABLE = "workflow_journal_owner";
|
|
1649
|
-
const WORKFLOW_JOURNAL_STAGING = `${WORKFLOW_JOURNAL_TABLE}_m24`;
|
|
1650
|
-
const WORKFLOW_JOURNAL_RETIRED = `${WORKFLOW_JOURNAL_TABLE}_m24_old`;
|
|
1651
|
-
const RETIRED_JOURNAL_SCOPE_COLUMN = "scope";
|
|
1652
1731
|
const M24_OWNER_INCARNATION = "m24-backfill";
|
|
1653
1732
|
const M24_COPY_BATCH_BYTES = 32 * 1024 * 1024;
|
|
1654
1733
|
const M24_COPY_SCAN_PAGE = 1000;
|
|
@@ -1662,7 +1741,7 @@ async function copyJournalInBatches(db, dialect) {
|
|
|
1662
1741
|
const T = WORKFLOW_JOURNAL_TABLE;
|
|
1663
1742
|
const bytes = dialect === "mysql" ? "LENGTH(result)" : "OCTET_LENGTH(result)";
|
|
1664
1743
|
const copyHead = `INSERT INTO ${WORKFLOW_JOURNAL_STAGING} (run_id, incarnation, ordinal, call_key, result, created_at_ms) ` +
|
|
1665
|
-
`SELECT ${T}.run_id, o
|
|
1744
|
+
`SELECT ${T}.run_id, o.${WORKFLOW_JOURNAL_SUPPLIED_COLUMN}, ordinal, call_key, ${jsonColumnText(dialect, "result")}, created_at_ms FROM ${T} ` +
|
|
1666
1745
|
`JOIN ${WORKFLOW_JOURNAL_OWNER_TABLE} o ON o.run_id = ${T}.run_id AND o.scope = ${T}.${RETIRED_JOURNAL_SCOPE_COLUMN} WHERE `;
|
|
1667
1746
|
let after;
|
|
1668
1747
|
for (;;) {
|
|
@@ -1724,9 +1803,6 @@ export async function moveWorkflowJournalScope(db, dialect, receipts) {
|
|
|
1724
1803
|
}
|
|
1725
1804
|
receipts.workflowJournalScopeColumn = "moved";
|
|
1726
1805
|
}
|
|
1727
|
-
const SESSION_POLICY_TABLE = "session_policy";
|
|
1728
|
-
const RETIRED_SESSION_RULES_COLUMN = "rules";
|
|
1729
|
-
const OLD_GRAMMAR_SESSION_RULES_COLUMN = "rule_entries_old_grammar";
|
|
1730
1806
|
const SESSION_RULES_SCAN_PAGE = 500;
|
|
1731
1807
|
export function retiredSessionRuleBucketsOf(body) {
|
|
1732
1808
|
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
@@ -2141,6 +2217,7 @@ function readingFields(r) {
|
|
|
2141
2217
|
runErrorCodeColumnRewritten: r.runErrorCodeColumnRewritten,
|
|
2142
2218
|
runObjectivePreviewRewritten: r.runObjectivePreviewRewritten,
|
|
2143
2219
|
shellSentinelOwnersCleared: r.shellSentinelOwnersCleared,
|
|
2220
|
+
shellSentinelOwnerRowsRetained: r.shellSentinelOwnerRowsRetained.reduce((n, surface) => n + surface.rows, 0),
|
|
2144
2221
|
checkpointHostSessionsBackfilled: r.checkpointHostSessionsBackfilled,
|
|
2145
2222
|
legacySkillExemptionsDropped: r.legacySkillExemptionsDropped,
|
|
2146
2223
|
executionPlacementSessionsUnreadable: r.executionPlacementSessionsUnreadable.length,
|
|
@@ -2242,6 +2319,17 @@ function logReceiptRows(log, backend, r) {
|
|
|
2242
2319
|
"(the next boot then migrates it) or the session is deleted. Named on every boot until then",
|
|
2243
2320
|
});
|
|
2244
2321
|
}
|
|
2322
|
+
if (r.shellSentinelOwnerRowsRetained.length > 0) {
|
|
2323
|
+
log.warn("shell_sentinel_rows_retained", {
|
|
2324
|
+
backend,
|
|
2325
|
+
rows: r.shellSentinelOwnerRowsRetained.reduce((n, surface) => n + surface.rows, 0),
|
|
2326
|
+
surfaces: Object.fromEntries(r.shellSentinelOwnerRowsRetained.map((surface) => [surface.surface, surface.rows])),
|
|
2327
|
+
note: "this deployment has an identity boundary, so the one-time migration that clears the old cli shell sentinel owner (`anon:shell-live`) to no owner did not touch these rows: they keep that owner, and only a caller whose principal is exactly that value reads them as its own " +
|
|
2328
|
+
"(on the local backend session_meta = the session-metadata cells and task_run = the run rows). The reading comes from the configuration of THE ONE PROCESS that starts the migration, and the rewrite lands on the whole database / data root and cannot be undone: " +
|
|
2329
|
+
"every process that opens this same database or data root (run-local, an embedding host's boot, a one-off tool process) must carry at least one identity key (service credential, auth bridge, REQUIRE_PRINCIPAL, direct door, read-only trace credential — any one is enough; the rewrite runs only when the starting process has none of them); " +
|
|
2330
|
+
"a process started with no identity key at all first would clear these rows to no owner on the boundary deployment's behalf. To clear them deliberately, run the manual step in MIGRATION.md entry 86 of the 7.148.0 section. Counted on every start until then",
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2245
2333
|
if (r.legacySkillExemptionsDropped > 0) {
|
|
2246
2334
|
log.warn("legacy_skill_exemptions_dropped", {
|
|
2247
2335
|
backend,
|