@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
|
@@ -8,7 +8,7 @@ import { IS_WIN32 } from "./host-platform.js";
|
|
|
8
8
|
import { atomicWriteFileAsync, atomicWriteFileSync, proveDurableSync } from "./owner-only-file-mode.js";
|
|
9
9
|
import { assertFirstOwnerWritable, forkOwnerOf, importerOwnerOf, placedSessionOwnerOf } from "./session-ownership.js";
|
|
10
10
|
import { SessionOwnerUnreadableError, StampedSessionArchiveError, sessionUnreadableOf } from "../session-error-wire.js";
|
|
11
|
-
import {
|
|
11
|
+
import { isShellSentinelOwnerM48 } from "./shell-sentinel-owner-m48.js";
|
|
12
12
|
import { FileSessionRepo, SessionError, StoredSession, admitSessionPlacement, atomicWriteFile, ensureDir, forkRowCells, sessionLogMarkOf, settledForkOptions, uuidv7, validateEntriesForImport } from "@sema-agent/core";
|
|
13
13
|
import { placementCapabilityOf } from "./session-placement.js";
|
|
14
14
|
import { z } from "zod";
|
|
@@ -19,8 +19,9 @@ import { judgeSessionRowWrite, sessionRowTagKey, settleSessionRowWrite, } from "
|
|
|
19
19
|
import { quarantineUnreadableSidecar } from "./local-sidecar-quarantine.js";
|
|
20
20
|
import { createZodColumnReader, decodeJsonColumn, isJsonColumnBodyProblem, isJsonObject, readJsonObjectColumn, readStringRecordColumn, SqlJsonColumnError } from "./sql-json-column.js";
|
|
21
21
|
import { RENAMED_EXECUTION_LANE_M40, RETIRED_EXECUTION_LANE_WORD_M40 } from "./execution-lane-rename-m40.js";
|
|
22
|
-
import { ExecutionLaneRenameWriteRefusedError,
|
|
22
|
+
import { ExecutionLaneRenameWriteRefusedError, migrationCarried } from "./one-time-migrations.js";
|
|
23
23
|
import { compareReleaseTriples, releaseText, releaseTriple } from "./release-version.js";
|
|
24
|
+
import { PRE_CUTOFF_SKILL_EXEMPTION_CONSEQUENCE, SKILL_EXEMPTION_TOOL_NAME } from "./approval-exemption-skill-cutoff.js";
|
|
24
25
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
25
26
|
import { createLogger, writeLogText } from "../observability/logger.js";
|
|
26
27
|
import { UNMANAGED_RETENTION } from "./retention-declaration.js";
|
|
@@ -78,6 +79,15 @@ function readSessionMetaCell(cell) {
|
|
|
78
79
|
? { incarnation: cell, owner: undefined, execution: undefined, forkKey: undefined, createdAt: undefined, forkedFrom: undefined, forkedFromIncarnation: undefined, dropping: false, deleting: undefined, clientWrites: undefined }
|
|
79
80
|
: { incarnation: cell.incarnation, owner: cell.owner, execution: cell.execution, forkKey: cell.forkKey, createdAt: cell.createdAt, forkedFrom: cell.forkedFrom, forkedFromIncarnation: cell.forkedFromIncarnation, dropping: cell.dropping === true, deleting: cell.deleting, clientWrites: cell.clientWrites };
|
|
80
81
|
}
|
|
82
|
+
function shellSentinelCellIdsM48(cells) {
|
|
83
|
+
const ids = [];
|
|
84
|
+
for (const [sessionId, cell] of cells) {
|
|
85
|
+
if (typeof cell === "string" || !isShellSentinelOwnerM48(cell.owner) || readSessionMetaCell(cell).dropping)
|
|
86
|
+
continue;
|
|
87
|
+
ids.push(sessionId);
|
|
88
|
+
}
|
|
89
|
+
return ids;
|
|
90
|
+
}
|
|
81
91
|
const ownerRecorded = (cell) => cell !== undefined && readSessionMetaCell(cell).owner !== undefined;
|
|
82
92
|
const cellObjectOf = (cell) => (typeof cell === "string" ? { incarnation: cell } : cell);
|
|
83
93
|
function cellWith(before, bits) {
|
|
@@ -162,6 +172,27 @@ export const SESSION_META_CELL_OBJECT = z
|
|
|
162
172
|
.strict();
|
|
163
173
|
const SESSION_META_SIDECAR = z.record(z.string(), z.union([z.string(), SESSION_META_CELL_OBJECT]));
|
|
164
174
|
const readSessionMetaSidecar = createZodColumnReader(SESSION_META_SIDECAR);
|
|
175
|
+
function renameRetiredExecutionLaneWordsInCellsM40(entries) {
|
|
176
|
+
if (!isJsonObject(entries))
|
|
177
|
+
return 0;
|
|
178
|
+
let renamed = 0;
|
|
179
|
+
for (const cell of Object.values(entries)) {
|
|
180
|
+
if (!isJsonObject(cell))
|
|
181
|
+
continue;
|
|
182
|
+
const execution = cell["execution"];
|
|
183
|
+
if (!isJsonObject(execution) || execution["role"] !== "writer" || execution["lane"] !== RETIRED_EXECUTION_LANE_WORD_M40)
|
|
184
|
+
continue;
|
|
185
|
+
execution["lane"] = RENAMED_EXECUTION_LANE_M40;
|
|
186
|
+
renamed += 1;
|
|
187
|
+
}
|
|
188
|
+
return renamed;
|
|
189
|
+
}
|
|
190
|
+
const STRICT_SIDECARS = [{ file: SESSION_META_SIDECAR_FILE, which: "session-meta" }];
|
|
191
|
+
const readSessionMetaSidecarInWindow = (body) => {
|
|
192
|
+
renameRetiredExecutionLaneWordsInCellsM40(body);
|
|
193
|
+
return readSessionMetaSidecar(body);
|
|
194
|
+
};
|
|
195
|
+
const STRICT_SIDECAR_FILES = new Set(STRICT_SIDECARS.map((s) => s.file));
|
|
165
196
|
const SIDECAR_MAP_STATE_BY_PATH = new Map();
|
|
166
197
|
const SESSION_WRITE_LOCKS_BY_ROOT = new Map();
|
|
167
198
|
const quotedFieldNames = (names) => `${names.slice(0, 8).map((name) => JSON.stringify(name.slice(0, 64))).join(", ")}${names.length > 8 ? `, … (${names.length} in all)` : ""}`;
|
|
@@ -174,24 +205,40 @@ function describeDataRootFinding(f) {
|
|
|
174
205
|
if (f.problem === "newer-engine") {
|
|
175
206
|
return ` ${f.label} at ${f.path}: engine high-water ${f.engineHighWater.highWater} — the data root has been opened by server ${f.engineHighWater.highWater}, NEWER than this build (${f.engineHighWater.engine}).`;
|
|
176
207
|
}
|
|
177
|
-
if (f.problem === "skipped-required-migration")
|
|
178
|
-
|
|
179
|
-
const consequence = "This build no longer carries that migration: opening the root would give those sessions a new occupant token, and memory records kept under the old one (capture opt-outs, pollution marks) would stop applying to them.";
|
|
180
|
-
if (highWater !== null && releaseAtOrAbove(highWater, requiredSince)) {
|
|
181
|
-
return (` ${f.label} at ${f.path}: ${sessions} session archive(s) have no session-meta cell, and the data root was last opened by server ${highWater}, which carries the one-time migration ` +
|
|
182
|
-
`(introduced in ${requiredSince}) that gives such an archive its row cell under the occupant token the archive already carries — but that start did not finish it ` +
|
|
183
|
-
`(${ARCHIVE_TOKEN_ADOPTION_PENDING_FILE} is still in the data root). ${consequence} ` +
|
|
184
|
-
`Start the root once with a release at or above ${highWater} that still carries that migration (server or run-local) and let that start finish, then start this build.`);
|
|
185
|
-
}
|
|
186
|
-
const lastOpened = highWater === null ? "no engine that records a high-water (run-local before 7.148.0, or a server before 7.144.0)" : `server ${highWater}`;
|
|
187
|
-
return (` ${f.label} at ${f.path}: ${sessions} session archive(s) have no session-meta cell, and the data root was last opened by ${lastOpened} — older than ${requiredSince}, ` +
|
|
188
|
-
`whose one-time migration gives such an archive its row cell under the occupant token the archive already carries. ${consequence} ` +
|
|
189
|
-
`Start the root once with a release at or above ${requiredSince} that still carries that migration (server or run-local) and let that start finish, then start this build.`);
|
|
190
|
-
}
|
|
208
|
+
if (f.problem === "skipped-required-migration")
|
|
209
|
+
return describeSkippedMigration(f);
|
|
191
210
|
return f.unknownFields.length > 0
|
|
192
211
|
? ` ${f.label} at ${f.path}: UNKNOWN field(s) ${quotedFieldNames(f.unknownFields)} — the data root is NEWER than this build (a newer server engine wrote it).`
|
|
193
212
|
: ` ${f.label} at ${f.path}: unreadable (${f.problem}) — this build cannot read it, and an unreadable file is treated as a mismatch, not as empty.`;
|
|
194
213
|
}
|
|
214
|
+
function describeSkippedMigration(f) {
|
|
215
|
+
const m = f.skippedMigration;
|
|
216
|
+
switch (m.residue) {
|
|
217
|
+
case "archives-without-cell":
|
|
218
|
+
return describeArchivesWithoutCell(f, m);
|
|
219
|
+
case "pre-cutoff-skill-exemptions": {
|
|
220
|
+
const atLeast = m.highWater !== null && releaseAtOrAbove(m.highWater, m.requiredSince) ? m.highWater : m.requiredSince;
|
|
221
|
+
const cutoff = m.cutoff === null ? "no cutoff is recorded in the data root (no release that records it has fully started on this root)" : `the data root's cutoff is ${m.cutoff}`;
|
|
222
|
+
return (` ${f.label} at ${f.path}: ${m.sessions} session(s) hold a \`${SKILL_EXEMPTION_TOOL_NAME}\` session approval exemption first granted before the Skill exemption cutoff (${cutoff}). ` +
|
|
223
|
+
`${PRE_CUTOFF_SKILL_EXEMPTION_CONSEQUENCE} This build no longer carries the one-time migration (introduced in ${m.requiredSince}) that removes such rows. ` +
|
|
224
|
+
`Start the root once with a release at or above ${atLeast} that still carries that migration (server or run-local) and let that start finish, then start this build.`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function describeArchivesWithoutCell(f, m) {
|
|
229
|
+
const { highWater, requiredSince, sessions } = m;
|
|
230
|
+
const consequence = "This build no longer carries that migration: opening the root would give those sessions a new occupant token, and memory records kept under the old one (capture opt-outs, pollution marks) would stop applying to them.";
|
|
231
|
+
if (highWater !== null && releaseAtOrAbove(highWater, requiredSince)) {
|
|
232
|
+
return (` ${f.label} at ${f.path}: ${sessions} session archive(s) have no session-meta cell, and the data root was last opened by server ${highWater}, which carries the one-time migration ` +
|
|
233
|
+
`(introduced in ${requiredSince}) that gives such an archive its row cell under the occupant token the archive already carries — but that start did not finish it ` +
|
|
234
|
+
`(${ARCHIVE_TOKEN_ADOPTION_PENDING_FILE} is still in the data root). ${consequence} ` +
|
|
235
|
+
`Start the root once with a release at or above ${highWater} that still carries that migration (server or run-local) and let that start finish, then start this build.`);
|
|
236
|
+
}
|
|
237
|
+
const lastOpened = highWater === null ? "no engine that records a high-water (run-local before 7.148.0, or a server before 7.144.0)" : `server ${highWater}`;
|
|
238
|
+
return (` ${f.label} at ${f.path}: ${sessions} session archive(s) have no session-meta cell, and the data root was last opened by ${lastOpened} — older than ${requiredSince}, ` +
|
|
239
|
+
`whose one-time migration gives such an archive its row cell under the occupant token the archive already carries. ${consequence} ` +
|
|
240
|
+
`Start the root once with a release at or above ${requiredSince} that still carries that migration (server or run-local) and let that start finish, then start this build.`);
|
|
241
|
+
}
|
|
195
242
|
function describeLocalDataRootMismatch(findings, when) {
|
|
196
243
|
const lines = [
|
|
197
244
|
when === "boot"
|
|
@@ -200,7 +247,9 @@ function describeLocalDataRootMismatch(findings, when) {
|
|
|
200
247
|
];
|
|
201
248
|
for (const f of findings)
|
|
202
249
|
lines.push(describeDataRootFinding(f));
|
|
203
|
-
lines.push("This build never reads such a file as empty and never writes over it: either would silently change what the file records.", "", " Ways out (these four and no others):", " (1) the data root is NEWER than this build (unknown fields, or an engine high-water above this build): deploy the build that wrote it (for a high-water: server at or above it) — to run an older build on this machine, give it its own data root (LOCAL_DATA_ROOT);", " (2) roll back: restore the data-root backup taken before the upgrade, then start this build — also the way out when the file's bytes are damaged (not-json / malformed);", " (3) the file could not be read at all (an I/O error such as EACCES): repair access to it (permissions, mount, disk) and restart — nothing in the file needs changing;", " (4) the data root skipped a required one-time migration, or a release carrying it opened the root and did not finish it (the finding names the release to start with): start the root once with a release at or above that one that still carries the migration (server or run-local), let that start finish, then start this build.",
|
|
250
|
+
lines.push("This build never reads such a file as empty and never writes over it: either would silently change what the file records.", "", " Ways out (these four and no others):", " (1) the data root is NEWER than this build (unknown fields, or an engine high-water above this build): deploy the build that wrote it (for a high-water: server at or above it) — to run an older build on this machine, give it its own data root (LOCAL_DATA_ROOT);", " (2) roll back: restore the data-root backup taken before the upgrade, then start this build — also the way out when the file's bytes are damaged (not-json / malformed);", " (3) the file could not be read at all (an I/O error such as EACCES): repair access to it (permissions, mount, disk) and restart — nothing in the file needs changing;", " (4) the data root skipped a required one-time migration, or a release carrying it opened the root and did not finish it (the finding names the release to start with): start the root once with a release at or above that one that still carries the migration (server or run-local), let that start finish, then start this build.", when === "boot"
|
|
251
|
+
? "This refusal comes from the data-root admission, which only reads and runs before this start writes anything to the data root: the data root is exactly as it was — no file, directory, key or lock was created, changed or removed."
|
|
252
|
+
: "The check behind this refusal only reads: the file(s) named above were left in place, unchanged.");
|
|
204
253
|
return lines.join("\n");
|
|
205
254
|
}
|
|
206
255
|
export class LocalDataRootSchemaMismatchError extends StoreBootRefusalError {
|
|
@@ -215,14 +264,11 @@ export class LocalDataRootSchemaMismatchError extends StoreBootRefusalError {
|
|
|
215
264
|
}
|
|
216
265
|
}
|
|
217
266
|
export const ARCHIVE_TOKEN_ADOPTION_SINCE = "7.148.0";
|
|
218
|
-
export function archiveTokenAdoptionCarried() {
|
|
219
|
-
return ONE_TIME_MIGRATIONS.some((w) => w.id === "M47");
|
|
220
|
-
}
|
|
221
267
|
const ARCHIVE_DIR = "sessions";
|
|
222
268
|
const ARCHIVE_SUFFIX = ".jsonl";
|
|
223
269
|
const ARCHIVE_TOKEN_ADOPTION_PENDING_FILE = "archive-token-adoption.pending";
|
|
224
270
|
const archiveTokenAdoptionPendingPath = (root) => resolve(join(root, ARCHIVE_TOKEN_ADOPTION_PENDING_FILE));
|
|
225
|
-
function archiveTokenAdoptionPendingPresent(root) {
|
|
271
|
+
export function archiveTokenAdoptionPendingPresent(root) {
|
|
226
272
|
try {
|
|
227
273
|
lstatSync(archiveTokenAdoptionPendingPath(root));
|
|
228
274
|
return true;
|
|
@@ -258,7 +304,7 @@ function dischargeArchiveTokenAdoptionPending(root) {
|
|
|
258
304
|
if (!IS_WIN32)
|
|
259
305
|
fsyncPaths(dirname(path));
|
|
260
306
|
}
|
|
261
|
-
function archiveIdsInSync(root) {
|
|
307
|
+
export function archiveIdsInSync(root) {
|
|
262
308
|
let names;
|
|
263
309
|
try {
|
|
264
310
|
names = readdirSync(join(root, ARCHIVE_DIR));
|
|
@@ -270,54 +316,78 @@ function archiveIdsInSync(root) {
|
|
|
270
316
|
}
|
|
271
317
|
return names.filter((name) => name.endsWith(ARCHIVE_SUFFIX)).map((name) => name.slice(0, -ARCHIVE_SUFFIX.length));
|
|
272
318
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
319
|
+
function strictSidecarSite(root, entry) {
|
|
320
|
+
return { path: resolve(join(root, entry.file)), label: `${entry.file} (the local ${entry.which} sidecar)` };
|
|
321
|
+
}
|
|
322
|
+
export function readStrictSidecarTextsSync(root) {
|
|
323
|
+
return STRICT_SIDECARS.map((entry) => readDataRootFileTextSync(strictSidecarSite(root, entry).path));
|
|
324
|
+
}
|
|
325
|
+
function decodeStrictSidecar(root, entry, raw) {
|
|
326
|
+
const { path, label } = strictSidecarSite(root, entry);
|
|
327
|
+
if (raw.state === "absent")
|
|
328
|
+
return raw;
|
|
277
329
|
if (raw.state === "unreadable")
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
try {
|
|
282
|
-
cells = decodeJsonColumn(raw.text, readSessionMetaSidecar, label);
|
|
283
|
-
}
|
|
284
|
-
catch (e) {
|
|
285
|
-
throw new LocalDataRootSchemaMismatchError([dataRootMismatchOf(sidecarPath, label, e)], "boot");
|
|
286
|
-
}
|
|
330
|
+
return { state: "unreadable", finding: dataRootMismatchOf(path, label, raw.fault) };
|
|
331
|
+
try {
|
|
332
|
+
return { state: "read", entries: decodeJsonColumn(raw.text, readSessionMetaSidecarInWindow, label) };
|
|
287
333
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
334
|
+
catch (e) {
|
|
335
|
+
return { state: "unreadable", finding: dataRootMismatchOf(path, label, e) };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
export function readSessionMetaCellsSync(root) {
|
|
339
|
+
return decodeStrictSidecar(root, STRICT_SIDECARS[0], readDataRootFileTextSync(strictSidecarSite(root, STRICT_SIDECARS[0]).path));
|
|
291
340
|
}
|
|
292
|
-
export function
|
|
341
|
+
export function judgeStrictSidecars(root, texts) {
|
|
342
|
+
const findings = [];
|
|
343
|
+
let sessionMeta = {};
|
|
344
|
+
STRICT_SIDECARS.forEach((entry, i) => {
|
|
345
|
+
const reading = decodeStrictSidecar(root, entry, texts[i] ?? { state: "absent" });
|
|
346
|
+
if (reading.state === "unreadable")
|
|
347
|
+
findings.push(reading.finding);
|
|
348
|
+
else if (reading.state === "read")
|
|
349
|
+
sessionMeta = reading.entries;
|
|
350
|
+
});
|
|
351
|
+
if (findings.length > 0)
|
|
352
|
+
throw new LocalDataRootSchemaMismatchError(findings, "boot");
|
|
353
|
+
return sessionMeta;
|
|
354
|
+
}
|
|
355
|
+
function cellLessArchiveIds(archiveIds, cells) {
|
|
356
|
+
return archiveIds.filter((id) => !Object.hasOwn(cells, id)).sort();
|
|
357
|
+
}
|
|
358
|
+
export function judgeArchiveTokenAdoptionDuty(root, priorHighWater, adoptionCarried, observed) {
|
|
293
359
|
const since = releaseTriple(ARCHIVE_TOKEN_ADOPTION_SINCE);
|
|
294
360
|
const neverOpenedByAdoptingRelease = priorHighWater === undefined || compareReleaseTriples(priorHighWater, since) < 0;
|
|
295
|
-
if (adoptionCarried)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
const owed = archiveTokenAdoptionPendingPresent(root);
|
|
361
|
+
if (adoptionCarried)
|
|
362
|
+
return neverOpenedByAdoptingRelease && observed.archiveIds.length > 0 ? "record" : "none";
|
|
363
|
+
const owed = observed.adoptionPending;
|
|
301
364
|
if (!neverOpenedByAdoptingRelease && !owed)
|
|
302
|
-
return;
|
|
303
|
-
const cellLess =
|
|
304
|
-
if (cellLess.length === 0)
|
|
305
|
-
|
|
306
|
-
dischargeArchiveTokenAdoptionPending(root);
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
365
|
+
return "none";
|
|
366
|
+
const cellLess = cellLessArchiveIds(observed.archiveIds, observed.cells);
|
|
367
|
+
if (cellLess.length === 0)
|
|
368
|
+
return owed ? "discharge" : "none";
|
|
309
369
|
throw new LocalDataRootSchemaMismatchError([
|
|
310
370
|
{
|
|
311
371
|
path: resolve(join(root, ARCHIVE_DIR)),
|
|
312
372
|
label: `${ARCHIVE_DIR} (the local session archives)`,
|
|
313
373
|
problem: "skipped-required-migration",
|
|
314
374
|
unknownFields: [],
|
|
315
|
-
skippedMigration: { highWater: priorHighWater === undefined ? null : releaseText(priorHighWater), requiredSince: ARCHIVE_TOKEN_ADOPTION_SINCE, sessions: cellLess.length },
|
|
375
|
+
skippedMigration: { residue: "archives-without-cell", highWater: priorHighWater === undefined ? null : releaseText(priorHighWater), requiredSince: ARCHIVE_TOKEN_ADOPTION_SINCE, sessions: cellLess.length },
|
|
316
376
|
},
|
|
317
377
|
], "boot");
|
|
318
378
|
}
|
|
379
|
+
export function settleArchiveTokenAdoptionDuty(physicalRoot, priorHighWater, action) {
|
|
380
|
+
switch (action) {
|
|
381
|
+
case "none":
|
|
382
|
+
return;
|
|
383
|
+
case "record":
|
|
384
|
+
return recordArchiveTokenAdoptionPending(physicalRoot, priorHighWater);
|
|
385
|
+
case "discharge":
|
|
386
|
+
return dischargeArchiveTokenAdoptionPending(physicalRoot);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
319
389
|
function firstCellIncarnationOf(sessionId, archiveToken) {
|
|
320
|
-
const token =
|
|
390
|
+
const token = migrationCarried("M47") ? incarnationFromCell(sessionId, archiveToken, "absent") : undefined;
|
|
321
391
|
return token !== undefined ? { incarnation: token, adopted: true } : { incarnation: mintSessionIncarnation(), adopted: false };
|
|
322
392
|
}
|
|
323
393
|
function cellChangedUnderLock(sessionId) {
|
|
@@ -423,20 +493,6 @@ class SidecarMap {
|
|
|
423
493
|
}
|
|
424
494
|
return st.loaded;
|
|
425
495
|
}
|
|
426
|
-
async reconcile() {
|
|
427
|
-
const path = this.path;
|
|
428
|
-
if (!path)
|
|
429
|
-
return;
|
|
430
|
-
const st = this.state;
|
|
431
|
-
if (st.refused !== undefined)
|
|
432
|
-
throw st.refused;
|
|
433
|
-
if (!st.loaded)
|
|
434
|
-
return this.ensureLoaded();
|
|
435
|
-
await st.loaded;
|
|
436
|
-
const disk = await this.readDisk(path);
|
|
437
|
-
if (disk.state === "unreadable")
|
|
438
|
-
throw this.refuse(path, disk);
|
|
439
|
-
}
|
|
440
496
|
async landed(path, changed, draft) {
|
|
441
497
|
const disk = await this.readDisk(path);
|
|
442
498
|
switch (disk.state) {
|
|
@@ -656,7 +712,6 @@ export class LocalSessionStore {
|
|
|
656
712
|
instructionSources;
|
|
657
713
|
workspaces;
|
|
658
714
|
meta;
|
|
659
|
-
strictSidecars = [];
|
|
660
715
|
log;
|
|
661
716
|
sessionWriteLocks;
|
|
662
717
|
executionPlacement;
|
|
@@ -698,17 +753,15 @@ export class LocalSessionStore {
|
|
|
698
753
|
}
|
|
699
754
|
this.durability = opts.durability;
|
|
700
755
|
}
|
|
701
|
-
const sidecar = (file, which, read
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
this.strictSidecars.push(map);
|
|
705
|
-
return map;
|
|
756
|
+
const sidecar = (file, which, read) => {
|
|
757
|
+
const strict = STRICT_SIDECAR_FILES.has(file);
|
|
758
|
+
return new SidecarMap(dataDir ? resolve(join(dataDir, file)) : undefined, `${file} (the local ${which} sidecar)`, read, (path, e) => this.refuseSidecar(path, `LocalSessionStore ${which} sidecar`, e, which), (e) => this.warnSidecar("write", e, which), strict);
|
|
706
759
|
};
|
|
707
760
|
this.titles = sidecar("session-titles.json", "title", readStringRecordColumn);
|
|
708
761
|
this.pinned = sidecar("session-pinned.json", "pinned", readPinnedSidecar);
|
|
709
762
|
this.instructionSources = sidecar("session-instruction-sources.json", "instruction-source", readStringRecordColumn);
|
|
710
763
|
this.workspaces = sidecar("session-workspaces.json", "workspace", readStringRecordColumn);
|
|
711
|
-
this.meta = sidecar(SESSION_META_SIDECAR_FILE, "session-meta", readSessionMetaSidecar
|
|
764
|
+
this.meta = sidecar(SESSION_META_SIDECAR_FILE, "session-meta", readSessionMetaSidecar);
|
|
712
765
|
const root = dataDir ? resolve(dataDir) : undefined;
|
|
713
766
|
this.dataRoot = root;
|
|
714
767
|
if (root !== undefined && !SESSION_WRITE_LOCKS_BY_ROOT.has(root))
|
|
@@ -738,16 +791,7 @@ export class LocalSessionStore {
|
|
|
738
791
|
const disk = await readSessionMetaForM40(path);
|
|
739
792
|
if (disk.state !== "read")
|
|
740
793
|
return 0;
|
|
741
|
-
|
|
742
|
-
for (const cell of Object.values(disk.entries)) {
|
|
743
|
-
if (!isJsonObject(cell))
|
|
744
|
-
continue;
|
|
745
|
-
const execution = cell["execution"];
|
|
746
|
-
if (!isJsonObject(execution) || execution["role"] !== "writer" || execution["lane"] !== RETIRED_EXECUTION_LANE_WORD_M40)
|
|
747
|
-
continue;
|
|
748
|
-
execution["lane"] = RENAMED_EXECUTION_LANE_M40;
|
|
749
|
-
renamed += 1;
|
|
750
|
-
}
|
|
794
|
+
const renamed = renameRetiredExecutionLaneWordsInCellsM40(disk.entries);
|
|
751
795
|
if (renamed === 0)
|
|
752
796
|
return 0;
|
|
753
797
|
try {
|
|
@@ -758,19 +802,6 @@ export class LocalSessionStore {
|
|
|
758
802
|
}
|
|
759
803
|
return renamed;
|
|
760
804
|
}
|
|
761
|
-
async assertStrictSidecarsReadable() {
|
|
762
|
-
const loads = await Promise.allSettled(this.strictSidecars.map((map) => map.reconcile()));
|
|
763
|
-
const findings = [];
|
|
764
|
-
for (const load of loads) {
|
|
765
|
-
if (load.status === "fulfilled")
|
|
766
|
-
continue;
|
|
767
|
-
if (!(load.reason instanceof LocalDataRootSchemaMismatchError))
|
|
768
|
-
throw load.reason;
|
|
769
|
-
findings.push(...load.reason.findings);
|
|
770
|
-
}
|
|
771
|
-
if (findings.length > 0)
|
|
772
|
-
throw new LocalDataRootSchemaMismatchError(findings, "boot");
|
|
773
|
-
}
|
|
774
805
|
async forkingOf(sessionId, meta) {
|
|
775
806
|
if (!isForkCreatedCell(meta))
|
|
776
807
|
return false;
|
|
@@ -1027,7 +1058,7 @@ export class LocalSessionStore {
|
|
|
1027
1058
|
return meta;
|
|
1028
1059
|
}
|
|
1029
1060
|
async firstCellIncarnationHeld(sessionId) {
|
|
1030
|
-
const head =
|
|
1061
|
+
const head = migrationCarried("M47") ? await this.archiveHeadOf(sessionId) : undefined;
|
|
1031
1062
|
return firstCellIncarnationOf(sessionId, head?.incarnation).incarnation;
|
|
1032
1063
|
}
|
|
1033
1064
|
async headOf(sessionId) {
|
|
@@ -2040,20 +2071,25 @@ export class LocalSessionStore {
|
|
|
2040
2071
|
await this.meta.ensureLoaded();
|
|
2041
2072
|
let cleared = 0;
|
|
2042
2073
|
const committed = await this.meta.commit((draft) => {
|
|
2043
|
-
|
|
2044
|
-
for (const sessionId of
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
continue;
|
|
2048
|
-
draft.set(sessionId, { ...cell, owner: null });
|
|
2049
|
-
cleared += 1;
|
|
2050
|
-
}
|
|
2074
|
+
const hits = shellSentinelCellIdsM48(draft);
|
|
2075
|
+
for (const sessionId of hits)
|
|
2076
|
+
draft.set(sessionId, { ...cellObjectOf(draft.get(sessionId)), owner: null });
|
|
2077
|
+
cleared = hits.length;
|
|
2051
2078
|
return cleared > 0;
|
|
2052
2079
|
}, "best-effort");
|
|
2053
2080
|
if (!committed)
|
|
2054
2081
|
throw new SessionError("storage", "LocalSessionStore: the one-time migration M48 could not write the session-meta cells it cleared of the shell sentinel owner durably — nothing was changed");
|
|
2055
2082
|
return cleared;
|
|
2056
2083
|
}
|
|
2084
|
+
async countShellSentinelOwnersM48() {
|
|
2085
|
+
await this.meta.ensureLoaded();
|
|
2086
|
+
let count = 0;
|
|
2087
|
+
await this.meta.commit((draft) => {
|
|
2088
|
+
count = shellSentinelCellIdsM48(draft).length;
|
|
2089
|
+
return false;
|
|
2090
|
+
}, "best-effort");
|
|
2091
|
+
return count;
|
|
2092
|
+
}
|
|
2057
2093
|
async adoptArchiveTokensM47() {
|
|
2058
2094
|
const root = this.dataRoot;
|
|
2059
2095
|
if (root === undefined)
|
|
@@ -2087,8 +2123,13 @@ export class LocalSessionStore {
|
|
|
2087
2123
|
return { adopted, minted };
|
|
2088
2124
|
}
|
|
2089
2125
|
async assertArchiveTokensAdoptedM47(root) {
|
|
2126
|
+
const reading = readSessionMetaCellsSync(root);
|
|
2127
|
+
if (reading.state === "unreadable") {
|
|
2128
|
+
throw new SessionError("storage", `LocalSessionStore: the one-time migration M47 cannot re-read ${reading.finding.label} to prove the adoption finished (${reading.finding.problem}) — refusing to start. ` +
|
|
2129
|
+
`${ARCHIVE_TOKEN_ADOPTION_PENDING_FILE} stays in the data root; the next start of a release carrying this migration tries again.`);
|
|
2130
|
+
}
|
|
2090
2131
|
let left = 0;
|
|
2091
|
-
for (const sessionId of
|
|
2132
|
+
for (const sessionId of cellLessArchiveIds(archiveIdsInSync(root), reading.state === "read" ? reading.entries : {}))
|
|
2092
2133
|
if ((await this.adoptionScopeOf(sessionId)) === "in")
|
|
2093
2134
|
left += 1;
|
|
2094
2135
|
if (left > 0) {
|
|
@@ -66,11 +66,15 @@ export declare class MemoryRunStore implements InProcessClaimFence {
|
|
|
66
66
|
withdrawRunsOf(sessionId: string, ownTaskId: string | undefined): "proceed" | {
|
|
67
67
|
readonly keep: "runs";
|
|
68
68
|
};
|
|
69
|
+
/** 撤回本请求铸的这一条 run(SQL / 文件孪生同判,律见 SQL 孪生头注):行上的持有腿不是 `legId` ⇒ 不是本腿的行,一个字节不动;是 ⇒ 行仍在跑 ⇒ 删事件、幂等键、行,放本行持有的认领;已终局 ⇒ 行零删、只放它上面的提交幂等键;停驻 ⇒ 一个字节不动。交回删没删。 */
|
|
70
|
+
withdrawMintedRun(taskId: string, legId: string): Promise<boolean>;
|
|
69
71
|
/** Undo THIS submission's binding (key + body fingerprint → null) — called only where the submit surface refuses the submission
|
|
70
72
|
* before any work and terminalizes the row it just claimed (the sync leg's zero-work refusal, an execution-placement reject):
|
|
71
73
|
* the error answer invites a retry, and a retry with the same key must run, not replay the refusal. The row stays (it
|
|
72
74
|
* is the refusal's record); only the binding is freed. */
|
|
73
75
|
releaseIdemKey(taskId: string): Promise<void>;
|
|
76
|
+
/** 放一条行上的提交幂等键绑定(`releaseIdemKey` 与 `withdrawMintedRun` 的非在跑臂同读)。 */
|
|
77
|
+
private dropIdemBinding;
|
|
74
78
|
/** The body fingerprint this row's binding of `idem.key` holds — binding `idem.bodyFingerprint` first when it holds none (first
|
|
75
79
|
* arrival binds, everyone after reads; the twin of the SQL conditional UPDATE). `null` = no such row, or the row is not bound to
|
|
76
80
|
* this key (never written). */
|
|
@@ -95,15 +99,16 @@ export declare class MemoryRunStore implements InProcessClaimFence {
|
|
|
95
99
|
/** The terminal write's one synchronous section (SQL twin: one transaction): the k8s space's pending commit row (when
|
|
96
100
|
* offered) → the terminal row → the active-run slot release. Returns whether the pending row is now this run's. */
|
|
97
101
|
private writeTerminal;
|
|
98
|
-
/** Durable F4: park NON-terminal `suspended`, KEEP the task_active claim. CAS
|
|
99
|
-
* [ref]:同时落 `result` —— 封口脱敏后的投影(`sealRunRowResult`,凭据不落;`null` = 没观察到 park 结果),SQL 孪生同注。
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
/** Durable F4: park NON-terminal `suspended`, KEEP the task_active claim. CAS = 行仍归 `legId` ∧ running / suspended ∧ 没挂取消请求(三件的理由见 SQL 孪生)。
|
|
103
|
+
* [ref]:同时落 `result` —— 封口脱敏后的投影(`sealRunRowResult`,凭据不落;`null` = 没观察到 park 结果),SQL 孪生同注。
|
|
104
|
+
* 交回 CAS 的答:`true` ⇔ 这一写之后行停在这个词上;`false` ⇔ 三件有一件不成立(或行不在)—— 写不动它。判与写同一个同步段。 */
|
|
105
|
+
setSuspended(taskId: string, result: PersistedTaskResult | null, legId: string): Promise<boolean>;
|
|
106
|
+
/** [ref] D-B: park NON-terminal `needs_review`, KEEP the claim. CAS = {@link setSuspended} 的三件(词换成 needs_review)。
|
|
107
|
+
* [ref]:同 {@link setSuspended} 落封口脱敏后的 `result`;CAS 的答同 {@link setSuspended}。 */
|
|
108
|
+
setNeedsReview(taskId: string, result: PersistedTaskResult | null, legId: string): Promise<boolean>;
|
|
109
|
+
/** Durable F4 resume: flip suspended/needs_review → running (CAS);认领 = 换持有腿(铸新的 `legId` 交回)+ 两面请求旗随旧腿清零(SQL 孪生同注)。
|
|
110
|
+
* [ref](codex R1 [medium]):认领 = 接管 `instanceId`(= 当前持有副本;SQL 孪生同注)。CAS 输不改、交回 `undefined`。 */
|
|
111
|
+
markResuming(taskId: string, instanceId: string): Promise<string | undefined>;
|
|
107
112
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
108
113
|
/** 认领当写栅栏用(契约 = `store-contracts.ts` 的 `InProcessClaimFence`):判、刷新活性与 `write` 是同一个同步段。 */
|
|
109
114
|
whileHoldingClaim(sessionId: string, taskId: string, write: (run: FencedRun) => FenceLanded): boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { redactErrorMessage, redactLedgerEventData, runRowErrorCodeOf, sealRunRowResult } from "../observability/run-terminal.js";
|
|
2
2
|
import { outwardPlane } from "../terminal.js";
|
|
3
3
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
4
|
-
import { RUN_HOLDER_DEATH_CODES, RUN_STALLED_ERROR, RUN_STALL_DEFAULT_WIRING, isTerminalRunStatus, runLivenessOf, settledLegObservationOf } from "./store-contracts.js";
|
|
4
|
+
import { RUN_HOLDER_DEATH_CODES, RUN_STALLED_ERROR, RUN_STALL_DEFAULT_WIRING, isTerminalRunStatus, mintRunLegId, runLivenessOf, settledLegObservationOf } from "./store-contracts.js";
|
|
5
5
|
import { buildSessionRunRollups } from "./session-run-rollup.js";
|
|
6
6
|
import { notifyRunTerminal } from "../observability/run-terminal.js";
|
|
7
7
|
import { createInProcessSpaceCommitTable, fenceSpaceCommitAtTerminal } from "../workspace-space-commit.js";
|
|
@@ -52,6 +52,7 @@ export class MemoryRunStore {
|
|
|
52
52
|
source: r.source,
|
|
53
53
|
identity: r.identity,
|
|
54
54
|
instanceId: r.instanceId,
|
|
55
|
+
legId: r.legId,
|
|
55
56
|
cancelRequested: r.cancelRequested,
|
|
56
57
|
objectivePreview: r.objectivePreview,
|
|
57
58
|
createdAt: r.createdAt.toISOString(),
|
|
@@ -74,6 +75,7 @@ export class MemoryRunStore {
|
|
|
74
75
|
if (claimed !== undefined && !this.settleDueHolder(claimed))
|
|
75
76
|
return { ok: false, activeTaskId: claimed };
|
|
76
77
|
const now = new Date();
|
|
78
|
+
const legId = mintRunLegId();
|
|
77
79
|
this.active.set(sessionId, taskId);
|
|
78
80
|
this.runs.set(taskId, {
|
|
79
81
|
taskId,
|
|
@@ -86,6 +88,7 @@ export class MemoryRunStore {
|
|
|
86
88
|
jobId: meta.jobId ?? null,
|
|
87
89
|
source: meta.source ?? null,
|
|
88
90
|
instanceId,
|
|
91
|
+
legId,
|
|
89
92
|
objectivePreview: meta.objectivePreview ?? null,
|
|
90
93
|
idemKey,
|
|
91
94
|
idemBodyFingerprint: meta.idem?.bodyFingerprint ?? null,
|
|
@@ -97,7 +100,7 @@ export class MemoryRunStore {
|
|
|
97
100
|
});
|
|
98
101
|
if (idemKey !== null)
|
|
99
102
|
this.byIdem.set(idemKey, taskId);
|
|
100
|
-
return { ok: true };
|
|
103
|
+
return { ok: true, legId };
|
|
101
104
|
}
|
|
102
105
|
withdrawRunsOf(sessionId, ownTaskId) {
|
|
103
106
|
for (const r of this.runs.values())
|
|
@@ -114,14 +117,33 @@ export class MemoryRunStore {
|
|
|
114
117
|
this.runs.delete(own.taskId);
|
|
115
118
|
return "proceed";
|
|
116
119
|
}
|
|
120
|
+
async withdrawMintedRun(taskId, legId) {
|
|
121
|
+
const r = this.runs.get(taskId);
|
|
122
|
+
if (r === undefined || r.legId !== legId)
|
|
123
|
+
return false;
|
|
124
|
+
if (r.status !== "running") {
|
|
125
|
+
if (isTerminalRunStatus(r.status))
|
|
126
|
+
this.dropIdemBinding(r);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
this.events.delete(taskId);
|
|
130
|
+
if (r.idemKey !== null && this.byIdem.get(r.idemKey) === taskId)
|
|
131
|
+
this.byIdem.delete(r.idemKey);
|
|
132
|
+
this.runs.delete(taskId);
|
|
133
|
+
if (this.active.get(r.sessionId) === taskId)
|
|
134
|
+
this.active.delete(r.sessionId);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
117
137
|
async releaseIdemKey(taskId) {
|
|
118
138
|
const r = this.runs.get(taskId);
|
|
119
|
-
if (
|
|
120
|
-
|
|
139
|
+
if (r)
|
|
140
|
+
this.dropIdemBinding(r);
|
|
141
|
+
}
|
|
142
|
+
dropIdemBinding(r) {
|
|
121
143
|
r.idemBodyFingerprint = null;
|
|
122
144
|
if (r.idemKey === null)
|
|
123
145
|
return;
|
|
124
|
-
if (this.byIdem.get(r.idemKey) === taskId)
|
|
146
|
+
if (this.byIdem.get(r.idemKey) === r.taskId)
|
|
125
147
|
this.byIdem.delete(r.idemKey);
|
|
126
148
|
r.idemKey = null;
|
|
127
149
|
}
|
|
@@ -235,38 +257,42 @@ export class MemoryRunStore {
|
|
|
235
257
|
notifyRunTerminal(pending);
|
|
236
258
|
return fenced;
|
|
237
259
|
}
|
|
238
|
-
async setSuspended(taskId, result) {
|
|
260
|
+
async setSuspended(taskId, result, legId) {
|
|
239
261
|
const sealed = sealRunRowResult(result);
|
|
240
262
|
const r = this.runs.get(taskId);
|
|
241
|
-
if (r
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
263
|
+
if (!r || r.legId !== legId || (r.status !== "running" && r.status !== "suspended") || r.cancelRequested)
|
|
264
|
+
return false;
|
|
265
|
+
r.status = "suspended";
|
|
266
|
+
r.result = sealed;
|
|
267
|
+
r.errorCode = runRowErrorCodeOf(sealed);
|
|
268
|
+
r.updatedAt = new Date();
|
|
269
|
+
return true;
|
|
247
270
|
}
|
|
248
|
-
async setNeedsReview(taskId, result) {
|
|
271
|
+
async setNeedsReview(taskId, result, legId) {
|
|
249
272
|
const sealed = sealRunRowResult(result);
|
|
250
273
|
const r = this.runs.get(taskId);
|
|
251
|
-
if (r
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
274
|
+
if (!r || r.legId !== legId || (r.status !== "running" && r.status !== "needs_review") || r.cancelRequested)
|
|
275
|
+
return false;
|
|
276
|
+
r.status = "needs_review";
|
|
277
|
+
r.result = sealed;
|
|
278
|
+
r.errorCode = runRowErrorCodeOf(sealed);
|
|
279
|
+
r.updatedAt = new Date();
|
|
280
|
+
return true;
|
|
257
281
|
}
|
|
258
282
|
async markResuming(taskId, instanceId) {
|
|
259
283
|
const r = this.runs.get(taskId);
|
|
260
284
|
if (!r || (r.status !== "suspended" && r.status !== "needs_review"))
|
|
261
|
-
return
|
|
285
|
+
return undefined;
|
|
286
|
+
const legId = mintRunLegId();
|
|
262
287
|
r.status = "running";
|
|
263
288
|
r.result = null;
|
|
264
289
|
r.errorCode = null;
|
|
265
290
|
r.instanceId = instanceId;
|
|
291
|
+
r.legId = legId;
|
|
266
292
|
r.cancelRequested = false;
|
|
267
293
|
r.preemptRequested = false;
|
|
268
294
|
r.updatedAt = new Date();
|
|
269
|
-
return
|
|
295
|
+
return legId;
|
|
270
296
|
}
|
|
271
297
|
async getActiveTaskId(sessionId) {
|
|
272
298
|
return this.active.get(sessionId);
|
|
@@ -276,7 +302,7 @@ export class MemoryRunStore {
|
|
|
276
302
|
if (this.active.get(sessionId) !== taskId || r === undefined || r.status !== "running")
|
|
277
303
|
return false;
|
|
278
304
|
r.updatedAt = new Date();
|
|
279
|
-
write({ instanceId: r.instanceId });
|
|
305
|
+
write({ instanceId: r.instanceId, legId: r.legId });
|
|
280
306
|
return true;
|
|
281
307
|
}
|
|
282
308
|
async getRun(taskId) {
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* **标记表**(SQL 两方言)—— 一库一行一事实,键 = 落它的那一条一次性迁移的名(`plugins/one-time-migrations.ts` 登记表)。两类行:
|
|
3
|
+
* · **一次性的标记**:需要「这一库上这一条已经判过 / 落过」的迁移各记一行(M42 / M43 / M51),随那一条删码后无人再读(行留着无害);
|
|
4
|
+
* · **常设的一行 —— `Skill` 豁免截点**({@link SKILL_EXEMPTION_CUTOFF_ID}):T0 = 一只按今天的意思读会话豁免行的构建第一次接管这只库的时刻。
|
|
5
|
+
* 首次放行早于它的引擎家 `Skill` 豁免行是更早的意思写下的(批准 = 激活某技能),读者 = 跳版拒启臂 `approval-exemption-skill-cutoff.ts`(无窗)与一次性迁移 M46(窗内删那些行)。
|
|
6
|
+
* 表是常设的:中央建表语句建它(`tidb-pool.ts` / `pg-pool.ts`),`ensureSchema()` 在建表之后落截点那一行(只在缺席时落 —— 「此刻这只库由知道今天读法的构建接管」)。
|
|
4
7
|
*/
|
|
5
8
|
import type { SqlDialect } from "./sql-driver.js";
|
|
6
9
|
/** 标记表名。 */
|
|
7
10
|
export declare const MIGRATION_MARKER_TABLE = "one_time_migration_marker";
|
|
8
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* 常设的那一行的键:`Skill` 豁免截点 T0(`marked_at_ms` = T0 的 epoch 毫秒)。键沿用第一个落它的一次性迁移 M46 的名 —— 7.148.0 起的库里已经是这一行,
|
|
13
|
+
* 改名就要再迁一次;M46 删码之后这一行照旧是截点的家。
|
|
14
|
+
*/
|
|
15
|
+
export declare const SKILL_EXEMPTION_CUTOFF_ID = "M46";
|
|
16
|
+
/**
|
|
17
|
+
* 标记表的建表句(两方言;幂等)。中央建表语句与一次性迁移的步骤读同一只。键列与中央各表同形钉二进制排序(MySQL 协议表级 `COLLATE utf8mb4_bin`、PG 列级 `"C"`),
|
|
18
|
+
* 不继承库的缺省排序;7.148.0 由迁移建下的那一张(MySQL 协议上没钉表级排序)`IF NOT EXISTS` 不动它 —— 键是固定的 ASCII 迁移名,列册对账不看排序规则。
|
|
19
|
+
*/
|
|
9
20
|
export declare function migrationMarkerDdl(dialect: SqlDialect): string;
|
|
21
|
+
/**
|
|
22
|
+
* 落一行标记、只在缺席时落(两方言;参数 `[键, 毫秒]`;已在 ⇒ 零改动,先落的那一只赢 —— 并发起服收敛到同一个值)。本表唯一的写句:
|
|
23
|
+
* `ensureSchema()` 的截点种子行与一次性迁移的各步同读这一只。
|
|
24
|
+
*/
|
|
25
|
+
export declare function markIfAbsentSql(dialect: SqlDialect): string;
|
|
10
26
|
//# sourceMappingURL=one-time-migration-marker.d.ts.map
|