@sema-agent/server 7.134.0 → 7.136.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 +197 -1
- package/USAGE.md +147 -42
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
- package/deploy/sema-up/chart/values.yaml +1 -1
- package/dist/adoption/plan.d.ts +1 -1
- package/dist/approval-ask-audit-store.d.ts +24 -24
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +122 -154
- package/dist/approval-card.js +50 -51
- package/dist/approval-content-kind.d.ts +23 -5
- package/dist/approval-content-kind.js +8 -1
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +22 -3
- package/dist/approval-gate-currency.js +44 -18
- package/dist/approval-hmac.d.ts +7 -7
- package/dist/approval-policy-settlement.d.ts +2 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval.d.ts +8 -8
- package/dist/approval.js +4 -2
- package/dist/auth-bridge.d.ts +35 -6
- package/dist/auth-bridge.js +20 -3
- package/dist/auto-mode-face.d.ts +4 -4
- package/dist/background-session-reap.d.ts +2 -2
- package/dist/bake-runner/main.d.ts +2 -2
- package/dist/bake-runner/runner.d.ts +4 -4
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/run-firm.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -2
- package/dist/boot/budget-tracing.js +2 -2
- package/dist/boot/coordinators.d.ts +2 -2
- package/dist/boot/coordinators.js +2 -2
- package/dist/boot/deferred-sandbox-path-env.d.ts +0 -6
- package/dist/boot/deferred-sandbox-path-env.js +0 -5
- package/dist/boot/engine-lease.d.ts +5 -5
- package/dist/boot/execution-env.d.ts +16 -15
- package/dist/boot/execution-env.js +19 -21
- package/dist/boot/fatal-exit.d.ts +2 -2
- package/dist/boot/late-binds.d.ts +1 -1
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +15 -15
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/parked-revive-gate.js +3 -2
- package/dist/boot/reapers.d.ts +4 -4
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +36 -29
- package/dist/boot/runner-deps.d.ts +11 -11
- package/dist/boot/runner-deps.js +7 -4
- package/dist/boot/session-faces.d.ts +3 -3
- package/dist/boot/session-faces.js +11 -30
- package/dist/boot/shutdown.d.ts +5 -5
- package/dist/boot/side-query-lane.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.js +4 -4
- package/dist/boot/stage-06-runners.d.ts +1 -1
- package/dist/boot/stage-06-runners.js +0 -2
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stores.js +4 -4
- package/dist/boot/web-admin.d.ts +17 -17
- package/dist/boot/web-admin.js +15 -27
- package/dist/boot/workflow-orchestration.js +2 -9
- package/dist/brain.d.ts +11 -11
- package/dist/brain.js +12 -3
- package/dist/budget.d.ts +7 -7
- package/dist/budget.js +4 -0
- package/dist/capabilities/approvals-push.d.ts +4 -4
- package/dist/capabilities/builtin-tools.d.ts +5 -5
- package/dist/capabilities/center-plugins.d.ts +5 -5
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +1 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/execution-lane.d.ts +5 -5
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +5 -5
- package/dist/capabilities/mcp-probe.d.ts +11 -7
- package/dist/capabilities/sandbox-file-send.d.ts +1 -18
- package/dist/capabilities/sandbox-file-send.js +0 -7
- package/dist/capabilities/scenarios.d.ts +28 -10
- package/dist/capabilities/scenarios.js +15 -5
- package/dist/capabilities/send-user-file-tool.d.ts +1 -1
- package/dist/capabilities/skills.d.ts +31 -12
- package/dist/capabilities/skills.js +23 -17
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +29 -32
- package/dist/capability-facts.js +17 -21
- package/dist/center-config-tier.d.ts +1 -1
- package/dist/center-credential.d.ts +22 -8
- package/dist/center-credential.js +18 -3
- package/dist/checkpoint-identity.d.ts +5 -0
- package/dist/checkpoint-identity.js +14 -0
- package/dist/config-catalog.d.ts +12 -12
- package/dist/config-catalog.js +12 -10
- package/dist/config-d-migration.js +1 -1
- package/dist/config-invariants.d.ts +5 -5
- package/dist/config-invariants.js +11 -2
- package/dist/config-lkg.d.ts +1 -39
- package/dist/config-lkg.js +1 -83
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +2 -1
- package/dist/config-types.d.ts +95 -87
- package/dist/config.d.ts +26 -24
- package/dist/config.js +38 -18
- package/dist/cross-session-settings.d.ts +1 -1
- package/dist/delegated-session-owner.d.ts +16 -13
- package/dist/delegated-session-owner.js +9 -10
- package/dist/deployment-governance.d.ts +16 -16
- package/dist/deployment-shape.d.ts +127 -0
- package/dist/deployment-shape.js +72 -0
- package/dist/device-store.d.ts +1 -1
- package/dist/device-ws-hub.d.ts +1 -1
- package/dist/egress-redirect.d.ts +1 -1
- package/dist/elicitation.d.ts +8 -7
- package/dist/elicitation.js +9 -8
- package/dist/entry-mode-clamp-notice.d.ts +2 -2
- package/dist/env-facts.d.ts +10 -9
- package/dist/env-facts.js +1 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -5
- package/dist/exec-bounds.d.ts +2 -2
- package/dist/execution-lane-caps.d.ts +31 -43
- package/dist/execution-lane-caps.js +0 -13
- package/dist/file-history-capture.d.ts +9 -9
- package/dist/file-history-disclosure.d.ts +25 -11
- package/dist/file-history-disclosure.js +25 -14
- package/dist/fleet/drain-entry.d.ts +2 -2
- package/dist/fleet/fleet-bus.d.ts +22 -14
- package/dist/fleet/fleet-bus.js +5 -5
- package/dist/fleet/fleet-reconciler.d.ts +9 -9
- package/dist/fleet/subagent-tail-bus.d.ts +4 -4
- package/dist/fleet-client.d.ts +45 -14
- package/dist/fleet-client.js +24 -4
- package/dist/fleet-lease.d.ts +23 -19
- package/dist/fleet-lease.js +31 -23
- package/dist/governance-http-status.d.ts +2 -2
- package/dist/hooks/hook-llm.d.ts +7 -7
- package/dist/hooks/hook-llm.js +14 -8
- package/dist/hooks/hook-runner.d.ts +58 -31
- package/dist/hooks/hook-runner.js +37 -19
- package/dist/host-decision.d.ts +5 -5
- package/dist/host-lsp-manager.d.ts +5 -5
- package/dist/hosted-posture.d.ts +23 -13
- package/dist/hosted-posture.js +4 -9
- package/dist/http/admission.d.ts +2 -2
- package/dist/http/admission.js +20 -5
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +2 -1
- package/dist/http/checkpoint-ctx.d.ts +62 -17
- package/dist/http/checkpoint-ctx.js +78 -35
- package/dist/http/dispatch.d.ts +3 -3
- package/dist/http/dispatch.js +9 -9
- package/dist/http/durable-run-leg.js +4 -3
- package/dist/http/idempotency.d.ts +2 -2
- package/dist/http/mcp-dial-deadline.d.ts +7 -5
- package/dist/http/memory-compliance-failure-reply.d.ts +4 -4
- package/dist/http/owner-access.d.ts +4 -6
- package/dist/http/owner-access.js +1 -1
- package/dist/http/principal-gate.d.ts +7 -7
- package/dist/http/principal-gate.js +3 -2
- package/dist/http/readiness.d.ts +1 -1
- package/dist/http/request-guards.d.ts +4 -4
- package/dist/http/request-guards.js +2 -1
- package/dist/http/resume-ctx-read.d.ts +9 -23
- package/dist/http/resume-ctx-read.js +2 -3
- package/dist/http/resume-legs.d.ts +3 -3
- package/dist/http/resume-legs.js +11 -8
- package/dist/http/route-ctx.d.ts +29 -29
- package/dist/http/route-table.d.ts +9 -9
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.d.ts +5 -7
- package/dist/http/routes/approvals-assistant.js +101 -26
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/background.js +2 -2
- package/dist/http/routes/capabilities.d.ts +1 -1
- package/dist/http/routes/capabilities.js +16 -8
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/devices.d.ts +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/fleet.d.ts +1 -1
- package/dist/http/routes/fleet.js +2 -1
- package/dist/http/routes/mcp-reconnect.d.ts +4 -4
- package/dist/http/routes/mcp-reconnect.js +3 -3
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/notify-wake.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -2
- package/dist/http/routes/rules.d.ts +1 -1
- package/dist/http/routes/runs.js +23 -11
- package/dist/http/routes/session-sync.d.ts +1 -1
- package/dist/http/routes/session-sync.js +97 -46
- package/dist/http/routes/sessions-list.js +1 -1
- package/dist/http/routes/sessions.js +43 -53
- package/dist/http/routes/tasks.d.ts +1 -1
- package/dist/http/routes/trace-usage.d.ts +1 -1
- package/dist/http/routes/workflows.d.ts +3 -0
- package/dist/http/routes/workflows.js +31 -28
- package/dist/http/send.d.ts +5 -5
- package/dist/http/server.d.ts +34 -34
- package/dist/http/session-inherit-env.d.ts +3 -3
- package/dist/http/sse-lifecycle.d.ts +1 -1
- package/dist/http/sse-log.d.ts +2 -2
- package/dist/http/submit-ctx.js +1 -1
- package/dist/http/sync-submit-body.d.ts +1 -1
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +33 -24
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/instruction-source-notice.d.ts +2 -2
- package/dist/key-resolver.d.ts +3 -3
- package/dist/lane-home-probe.d.ts +1 -1
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/leader/diffup.d.ts +2 -2
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/fanout.d.ts +1 -1
- package/dist/leader/leader.d.ts +4 -4
- package/dist/leader/merge.d.ts +3 -3
- package/dist/leader/repair-wire.d.ts +1 -1
- package/dist/leader/wire.d.ts +6 -6
- package/dist/list-entry-display.d.ts +1 -1
- package/dist/lsp-evict.d.ts +1 -1
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/memory-layer-legacy-lock.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +1 -1
- package/dist/memory-posture.js +4 -2
- package/dist/memory-project-layer.d.ts +1 -1
- package/dist/memory-scope.d.ts +19 -19
- package/dist/memory-store-refusal.d.ts +4 -4
- package/dist/model-entry-headers.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +17 -17
- package/dist/model-provider.d.ts +10 -10
- package/dist/model-reach-scope.d.ts +1 -1
- package/dist/model-route-endpoint.d.ts +6 -6
- package/dist/model-route-gap.d.ts +49 -4
- package/dist/model-route-gap.js +34 -1
- package/dist/model-route-url.d.ts +5 -5
- package/dist/model-select.d.ts +15 -6
- package/dist/model-select.js +5 -0
- package/dist/model-unreachable-notice.d.ts +3 -3
- package/dist/namespaced-rule-name.d.ts +15 -5
- package/dist/namespaced-rule-name.js +3 -2
- package/dist/object-store-buckets.d.ts +13 -0
- package/dist/object-store-buckets.js +3 -0
- package/dist/observability/corrupt-read-seat.d.ts +9 -9
- package/dist/observability/cost-taxonomy.d.ts +1 -1
- package/dist/observability/err-text.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +17 -13
- package/dist/observability/fail-open.js +17 -13
- package/dist/observability/metrics.d.ts +3 -3
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/principal-context.d.ts +4 -1
- package/dist/observability/principal-context.js +6 -1
- package/dist/observability/run-terminal.d.ts +36 -36
- package/dist/observability/secret-env-scrub.d.ts +3 -3
- package/dist/observability/tool-trace.d.ts +1 -1
- package/dist/operator-ask.d.ts +4 -4
- package/dist/orchestration/workflow-agent-session-index.d.ts +3 -3
- package/dist/orchestration/workflow-completion-inbox.d.ts +20 -5
- package/dist/orchestration/workflow-completion-inbox.js +29 -7
- package/dist/orchestration/workflow-notify-journal.d.ts +43 -19
- package/dist/orchestration/workflow-notify-journal.js +17 -0
- package/dist/outbound-dispatcher.d.ts +4 -4
- package/dist/parent-watch.d.ts +4 -4
- package/dist/parked-decide.d.ts +20 -18
- package/dist/parked-decide.js +31 -11
- package/dist/parked-revive-surface.d.ts +7 -7
- package/dist/parked-revive-surface.js +2 -3
- package/dist/peer-directory.d.ts +5 -4
- package/dist/peer-directory.js +6 -6
- package/dist/permission-rule-list.d.ts +10 -1
- package/dist/permission-rule-list.js +7 -5
- package/dist/permission-rule-vocab.d.ts +2 -2
- package/dist/plugins/adoption-log-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +8 -1
- package/dist/plugins/approval-ask-store-file.js +6 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +11 -7
- package/dist/plugins/approval-ask-store-memory.js +11 -7
- package/dist/plugins/approval-ask-store-sql.d.ts +42 -15
- package/dist/plugins/approval-ask-store-sql.js +21 -5
- package/dist/plugins/approval-exemption-store.d.ts +3 -3
- package/dist/plugins/approval-nonce-store.d.ts +3 -3
- package/dist/plugins/background-agent-store-sql.d.ts +1 -1
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +1 -1
- package/dist/plugins/blob-backend.js +2 -1
- package/dist/plugins/caching-session-store.d.ts +23 -32
- package/dist/plugins/caching-session-store.js +5 -17
- package/dist/plugins/checkpoint-index-columns.d.ts +130 -0
- package/dist/plugins/checkpoint-index-columns.js +90 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +71 -69
- package/dist/plugins/checkpoint-store-sql.js +109 -127
- package/dist/plugins/device-store-sql.d.ts +7 -6
- package/dist/plugins/e2b-orphan-reclaim.d.ts +1 -1
- package/dist/plugins/ensure-schema-lock-policy.d.ts +1 -1
- package/dist/plugins/file-history-store-sql.d.ts +15 -7
- package/dist/plugins/file-history-store-sql.js +55 -36
- package/dist/plugins/file-run-store.d.ts +8 -8
- package/dist/plugins/fork-routing-session-store.d.ts +2 -2
- package/dist/plugins/fork-routing-session-store.js +1 -1
- package/dist/plugins/host-platform.d.ts +10 -10
- package/dist/plugins/image-bake-store-sql.d.ts +1 -1
- package/dist/plugins/image-index-sql.d.ts +1 -1
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.d.ts +10 -10
- package/dist/plugins/local-checkpoint-store.js +7 -7
- package/dist/plugins/local-session-store.d.ts +34 -38
- package/dist/plugins/local-session-store.js +20 -39
- package/dist/plugins/local-session-window.d.ts +1 -1
- package/dist/plugins/mailbox-store-sql.d.ts +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +1 -1
- package/dist/plugins/memory-run-store.d.ts +4 -4
- package/dist/plugins/memory-sync-store-pg.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +73 -54
- package/dist/plugins/one-time-migrations.js +131 -134
- package/dist/plugins/outcome-ledger-sql.d.ts +1 -1
- package/dist/plugins/park-commit-watch.d.ts +3 -3
- package/dist/plugins/permission-rule-store-file.d.ts +5 -5
- package/dist/plugins/permission-rule-store-file.js +12 -19
- package/dist/plugins/permission-rule-store-sql.d.ts +38 -4
- package/dist/plugins/permission-rule-store-sql.js +67 -24
- package/dist/plugins/pg-cost-quota.d.ts +1 -1
- package/dist/plugins/pg-pool.d.ts +2 -2
- package/dist/plugins/pg-pool.js +5 -2
- package/dist/plugins/pg-rate-limiter.d.ts +1 -1
- package/dist/plugins/pg-session-storage.d.ts +8 -20
- package/dist/plugins/pg-session-storage.js +14 -27
- package/dist/plugins/remote-env-adb.d.ts +10 -10
- package/dist/plugins/remote-env-device.d.ts +10 -9
- package/dist/plugins/remote-env-device.js +6 -2
- package/dist/plugins/remote-env-e2b.d.ts +3 -3
- package/dist/plugins/remote-env-host.d.ts +16 -16
- package/dist/plugins/remote-env-k8s.d.ts +26 -13
- package/dist/plugins/remote-env-k8s.js +24 -7
- package/dist/plugins/remote-env-local-docker.d.ts +2 -2
- package/dist/plugins/remote-env-ssh.d.ts +4 -4
- package/dist/plugins/remote-scratchpad.d.ts +2 -3
- package/dist/plugins/remote-scratchpad.js +0 -4
- package/dist/plugins/remote-shell.d.ts +6 -6
- package/dist/plugins/retention-lane-store-sql.d.ts +4 -4
- package/dist/plugins/retention-store-sql.d.ts +4 -4
- package/dist/plugins/roster-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +8 -8
- package/dist/plugins/s3-answer.d.ts +15 -0
- package/dist/plugins/s3-answer.js +5 -0
- package/dist/plugins/schema-consistency.d.ts +2 -2
- package/dist/plugins/schema-ensure-legs.d.ts +3 -3
- package/dist/plugins/schema-indexes.d.ts +1 -1
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-event-payload.d.ts +4 -4
- package/dist/plugins/session-fork.d.ts +34 -0
- package/dist/plugins/session-fork.js +29 -0
- package/dist/plugins/session-ownership.js +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/session-policy-store-sql.d.ts +12 -12
- package/dist/plugins/session-store.d.ts +2 -2
- package/dist/plugins/session-store.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +2 -2
- package/dist/plugins/snapshot-bucket-presence.d.ts +39 -4
- package/dist/plugins/snapshot-bucket-presence.js +35 -7
- package/dist/plugins/sql-driver.d.ts +8 -8
- package/dist/plugins/sql-errors.d.ts +40 -1
- package/dist/plugins/sql-errors.js +49 -1
- package/dist/plugins/sql-json-column.d.ts +21 -21
- package/dist/plugins/sql-row-helpers.d.ts +2 -2
- package/dist/plugins/store-backend.d.ts +17 -16
- package/dist/plugins/store-backend.js +3 -3
- package/dist/plugins/store-contracts.d.ts +21 -21
- package/dist/plugins/store-fault.d.ts +4 -0
- package/dist/plugins/store-fault.js +8 -0
- package/dist/plugins/task-attachment-store.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.d.ts +2 -2
- package/dist/plugins/tidb-pool.js +10 -3
- package/dist/plugins/tidb-session-store.d.ts +16 -26
- package/dist/plugins/tidb-session-store.js +15 -27
- package/dist/plugins/tool-result-store-sql.d.ts +1 -1
- package/dist/plugins/usage-window-store-sql.d.ts +3 -3
- package/dist/plugins/user-input-ledger-file.d.ts +1 -1
- package/dist/plugins/user-input-ledger-sql.d.ts +3 -3
- package/dist/plugins/web-search.d.ts +19 -5
- package/dist/plugins/web-search.js +20 -5
- package/dist/{orchestration/workflow-journal-entry.d.ts → plugins/workflow-journal-payload.d.ts} +23 -32
- package/dist/plugins/workflow-journal-payload.js +32 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +28 -14
- package/dist/plugins/workflow-journal-store-sql.js +34 -15
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -4
- package/dist/posture-source.d.ts +11 -11
- package/dist/principal-jwt.d.ts +6 -6
- package/dist/project-identity.d.ts +3 -3
- package/dist/project-memory.d.ts +4 -4
- package/dist/read-face-posture.d.ts +7 -7
- package/dist/request-declaration-refusal.d.ts +94 -0
- package/dist/request-declaration-refusal.js +78 -0
- package/dist/request-image-urls.d.ts +6 -0
- package/dist/request-image-urls.js +27 -0
- package/dist/request-key-closure.d.ts +6 -1
- package/dist/request-key-closure.js +5 -2
- package/dist/request-value-closure.d.ts +15 -8
- package/dist/request-value-closure.js +2 -0
- package/dist/router/route-orchestration.d.ts +11 -16
- package/dist/router/route-orchestration.js +2 -12
- package/dist/rule-entry-list.d.ts +8 -7
- package/dist/rule-entry-list.js +2 -9
- package/dist/rules-consent.d.ts +6 -6
- package/dist/rules-consent.js +2 -0
- package/dist/run-cancel-context.d.ts +5 -5
- package/dist/run-local.d.ts +10 -10
- package/dist/runs.d.ts +13 -11
- package/dist/runs.js +15 -1
- package/dist/runtime-caps-resolver.d.ts +6 -6
- package/dist/runtime-caps-resolver.js +1 -1
- package/dist/runtime-governance.d.ts +9 -9
- package/dist/sandbox-pkg-source.d.ts +17 -12
- package/dist/sandbox-pkg-source.js +14 -9
- package/dist/sealed-key.d.ts +22 -3
- package/dist/sealed-key.js +47 -4
- package/dist/security.d.ts +23 -26
- package/dist/security.js +12 -9
- package/dist/server-secret-env.d.ts +10 -10
- package/dist/session-children-retire.d.ts +1 -1
- package/dist/session-error-wire.d.ts +7 -7
- package/dist/session-incarnation.d.ts +65 -37
- package/dist/session-incarnation.js +30 -12
- package/dist/session-policy-wire.d.ts +27 -5
- package/dist/session-policy-wire.js +15 -1
- package/dist/session-records-skipped-notice.d.ts +1 -1
- package/dist/session-row.d.ts +3 -17
- package/dist/session-row.js +4 -0
- package/dist/session-sync-kernel.d.ts +4 -4
- package/dist/session-sync.d.ts +61 -6
- package/dist/session-sync.js +55 -10
- package/dist/session-titler.d.ts +7 -6
- package/dist/session-titler.js +8 -13
- package/dist/session-watch.d.ts +3 -3
- package/dist/session-watch.js +4 -4
- package/dist/sighup-idle.d.ts +2 -2
- package/dist/spec-fields.d.ts +4 -4
- package/dist/sql-engine-posture.d.ts +3 -3
- package/dist/store-posture.d.ts +2 -2
- package/dist/stored-request-tool-axes-m19.d.ts +1 -1
- package/dist/task-a2a.d.ts +52 -79
- package/dist/task-a2a.js +224 -62
- package/dist/task-cwd.d.ts +7 -88
- package/dist/task-cwd.js +2 -15
- package/dist/task-mcp.d.ts +13 -17
- package/dist/task-mcp.js +29 -49
- package/dist/task-settings.d.ts +30 -18
- package/dist/task-settings.js +33 -3
- package/dist/task-workflow.d.ts +0 -24
- package/dist/task-workflow.js +2 -1
- package/dist/terminal.d.ts +5 -5
- package/dist/tighten-only-seats.d.ts +7 -6
- package/dist/tighten-only-seats.js +1 -1
- package/dist/tool-approval.d.ts +166 -207
- package/dist/tool-approval.js +61 -61
- package/dist/tool-rule-names.d.ts +2 -2
- package/dist/trace/core-keyset-guard.d.ts +13 -8
- package/dist/trace/engine-notice-wire.d.ts +5 -5
- package/dist/trace/engine-notice-wire.js +1 -0
- package/dist/trace/exit-seat.d.ts +31 -4
- package/dist/trace/exit-seat.js +69 -67
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/ledger-sink.d.ts +1 -1
- package/dist/trace/model-segment.d.ts +3 -3
- package/dist/trace/project.d.ts +47 -45
- package/dist/trace/project.js +33 -1
- package/dist/trace/redact.d.ts +61 -31
- package/dist/trace/redact.js +394 -153
- package/dist/trace/self-minted-wire.d.ts +302 -14
- package/dist/trace/self-minted-wire.js +87 -0
- package/dist/trace/sema-provenance.d.ts +1 -1
- package/dist/trace/task-notification-facets.d.ts +4 -4
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/unattended-permission-mode.d.ts +5 -5
- package/dist/url-credential-refusal.d.ts +52 -0
- package/dist/url-credential-refusal.js +14 -0
- package/dist/url-refusal.d.ts +16 -3
- package/dist/url-refusal.js +15 -2
- package/dist/usage-analytics.d.ts +2 -2
- package/dist/user-input-ledger.d.ts +23 -23
- package/dist/web-admin-client/apply-effective.d.ts +5 -5
- package/dist/web-admin-client/apply-effective.js +2 -1
- package/dist/web-admin-client/apply-ledger.d.ts +2 -2
- package/dist/web-admin-client/center-request.d.ts +2 -2
- package/dist/web-admin-client/facade.d.ts +5 -5
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/hot-keys-registry.d.ts +2 -2
- package/dist/web-admin-client/http-client.d.ts +4 -4
- package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
- package/dist/web-admin-client/pull-state.d.ts +1 -1
- package/dist/web-admin-client/read-face.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +5 -5
- package/dist/web-admin-client/restart-signal.d.ts +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +28 -3
- package/dist/web-admin-client/skills-mcp.js +29 -1
- package/dist/web-admin-client/types.d.ts +16 -9
- package/dist/workspace-space.d.ts +32 -3
- package/dist/workspace-space.js +26 -0
- package/dist/write-protection.d.ts +2 -2
- package/package.json +5 -3
- package/scripts/drain-check-local.mjs +4 -2
- package/scripts/drain-check.mysql.sql +6 -2
- package/scripts/drain-check.pg.sql +6 -2
- package/skills/loop.md +1 -1
- package/skills/schedule.md +1 -1
- package/wire-changes/server@7.104.0.json +134 -0
- package/wire-changes/server@7.105.0.json +53 -0
- package/wire-changes/server@7.106.0.json +475 -0
- package/wire-changes/server@7.107.0.json +64 -0
- package/wire-changes/server@7.108.0.json +153 -0
- package/wire-changes/server@7.109.0.json +46 -0
- package/wire-changes/server@7.110.0.json +90 -0
- package/wire-changes/server@7.111.0.json +86 -0
- package/wire-changes/server@7.112.0.json +60 -0
- package/wire-changes/server@7.113.0.json +26 -0
- package/wire-changes/server@7.114.0.json +26 -0
- package/wire-changes/server@7.115.0.json +97 -0
- package/wire-changes/server@7.116.0.json +218 -0
- package/wire-changes/server@7.116.1.json +26 -0
- package/wire-changes/server@7.117.0.json +65 -0
- package/wire-changes/server@7.118.0.json +129 -0
- package/wire-changes/server@7.119.0.json +65 -0
- package/wire-changes/server@7.120.0.json +89 -0
- package/wire-changes/server@7.121.0.json +219 -0
- package/wire-changes/server@7.122.0.json +54 -0
- package/wire-changes/server@7.123.0.json +26 -0
- package/wire-changes/server@7.124.0.json +336 -0
- package/wire-changes/server@7.124.1.json +26 -0
- package/wire-changes/server@7.125.0.json +111 -0
- package/wire-changes/server@7.126.0.json +285 -0
- package/wire-changes/server@7.127.0.json +77 -0
- package/wire-changes/server@7.127.1.json +26 -0
- package/wire-changes/server@7.127.2.json +53 -0
- package/wire-changes/server@7.128.0.json +26 -0
- package/wire-changes/server@7.129.0.json +106 -0
- package/wire-changes/server@7.129.1.json +26 -0
- package/wire-changes/server@7.130.0.json +26 -0
- package/wire-changes/server@7.131.0.json +118 -0
- package/wire-changes/server@7.132.0.json +226 -0
- package/wire-changes/server@7.133.0.json +1155 -0
- package/wire-changes/server@7.134.0.json +107 -0
- package/wire-changes/server@7.135.0.json +174 -0
- package/wire-changes/server@7.136.0.json +448 -0
- package/dist/http/run-declared-families.d.ts +0 -16
- package/dist/http/run-declared-families.js +0 -12
- package/dist/orchestration/workflow-journal-entry.js +0 -27
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
|
|
2
2
|
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
3
|
-
import { askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./approval-ask-store-sql.js";
|
|
3
|
+
import { askRowCarriesOwner, askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth, projectDecideReading } from "./approval-ask-store-sql.js";
|
|
4
4
|
function applyPatch(row, patch) {
|
|
5
5
|
if (patch.decision !== undefined)
|
|
6
6
|
row.decision = patch.decision;
|
|
@@ -41,6 +41,10 @@ export class InMemoryApprovalAskStore {
|
|
|
41
41
|
exportRows() {
|
|
42
42
|
return { asks: [...this.asks.values()].map((r) => ({ ...r })), batches: [...this.batches.values()].map((b) => ({ ...b })) };
|
|
43
43
|
}
|
|
44
|
+
peekAsk(askId) {
|
|
45
|
+
const row = this.asks.get(askId);
|
|
46
|
+
return row ? { ...row } : null;
|
|
47
|
+
}
|
|
44
48
|
importRows(snapshot) {
|
|
45
49
|
for (const r of snapshot.asks ?? [])
|
|
46
50
|
this.asks.set(r.askId, { ...r, settledBy: r.settledBy ?? null });
|
|
@@ -112,19 +116,18 @@ export class InMemoryApprovalAskStore {
|
|
|
112
116
|
row.updatedAtMs = patch.updatedAtMs;
|
|
113
117
|
return true;
|
|
114
118
|
}
|
|
115
|
-
async decideAsk(askId, batchId, decision) {
|
|
119
|
+
async decideAsk(askId, batchId, owner, decision) {
|
|
116
120
|
if (decision.idempotencyKey != null)
|
|
117
121
|
assertIdempotencyKeyShape(decision.idempotencyKey);
|
|
118
122
|
assertDecideSettledBy(decision);
|
|
119
|
-
const
|
|
123
|
+
const reading = (row) => projectDecideReading(row ? { ...row } : null, owner);
|
|
120
124
|
const batch = this.batches.get(batchId);
|
|
121
125
|
if (!batch || batch.state !== "OPEN") {
|
|
122
|
-
|
|
123
|
-
return { ok: false, reason: "batch_closed", row: row ? { ...row } : null };
|
|
126
|
+
return { ok: false, reason: "batch_closed", row: reading(this.asks.get(askId)) };
|
|
124
127
|
}
|
|
125
128
|
const ask = this.asks.get(askId);
|
|
126
|
-
if (!ask || ask.state !== "STREAM_PENDING" || ask.batchId !== batchId) {
|
|
127
|
-
return { ok: false, reason: "ask_not_pending", row: ask
|
|
129
|
+
if (!ask || ask.state !== "STREAM_PENDING" || ask.batchId !== batchId || !askRowCarriesOwner(ask, owner)) {
|
|
130
|
+
return { ok: false, reason: "ask_not_pending", row: reading(ask) };
|
|
128
131
|
}
|
|
129
132
|
if (decision.idempotencyKey != null) {
|
|
130
133
|
for (const [id, r] of this.asks) {
|
|
@@ -136,6 +139,7 @@ export class InMemoryApprovalAskStore {
|
|
|
136
139
|
let encodedUpdatedInput;
|
|
137
140
|
if (decision.updatedInput !== undefined)
|
|
138
141
|
encodedUpdatedInput = encodeDecideUpdatedInput(decision.updatedInput);
|
|
142
|
+
const now = this.now();
|
|
139
143
|
batch.rev += 1;
|
|
140
144
|
batch.updatedAtMs = now;
|
|
141
145
|
ask.state = "DECIDED";
|
|
@@ -82,8 +82,8 @@ export interface AskRow {
|
|
|
82
82
|
decisionActor: unknown | null;
|
|
83
83
|
decisionNote: string | null;
|
|
84
84
|
/**
|
|
85
|
-
* 🔴
|
|
86
|
-
* 不带这一格的 outcome 逐字按 `"human"` 读),非 null = 宿主自报的那个词(
|
|
85
|
+
* 🔴 [ref]([ref] 的持久半场)—— 这条决议的**结算来源**:`null` = 一个人答的(= 缺席律,core 对
|
|
86
|
+
* 不带这一格的 outcome 逐字按 `"human"` 读),非 null = 宿主自报的那个词([ref] 起写进来的只有决定体出处位
|
|
87
87
|
* `decidedBy:"policy"` 经 `liveSettledBy` 映射来的 `"policy"`,allow 与 deny 两向都写;词表属主恒是 core —— 见 {@link HostSettledBy})。
|
|
88
88
|
*
|
|
89
89
|
* **为什么必须是行上的一格**(病灶,7.93.3 合并树 codex ① 验真):`settledBy` 此前只到达**当次**回决的
|
|
@@ -92,7 +92,7 @@ export interface AskRow {
|
|
|
92
92
|
* 在一条根本没有人的 run 里。不变量:**一条决议的来源在所有读回路径上是同一个事实**;唯一读回铸点 =
|
|
93
93
|
* `tool-approval.ts` 的 `outcomeOfDecidedRow`。
|
|
94
94
|
*
|
|
95
|
-
* 🔴 **为什么是自己一列,不是塞进 `decision_actor` 那只袋**(
|
|
95
|
+
* 🔴 **为什么是自己一列,不是塞进 `decision_actor` 那只袋**([ref] 取舍,亲读后定):
|
|
96
96
|
* · 那只袋是**自由载荷**——型是 `unknown`(见上一格),读回不过任何 schema(`parseJsonColumn` 返回
|
|
97
97
|
* `unknown`),schema 属主在别处([ref] ActorAssertion),`adoption/plan.ts` 的裁定 D2 把它连同
|
|
98
98
|
* `decision_note` 一起定为**史实字段,永不改写**。往一只没有属主、没有类型化读回的袋里塞一个
|
|
@@ -228,11 +228,11 @@ export interface DecideAskInput {
|
|
|
228
228
|
/** 车4 §12-E:回决幂等键,赢 CAS 时随决议一起落列(见 `AskRow.idempotencyKey`)。缺席 ⇒ 列保持 NULL。 */
|
|
229
229
|
idempotencyKey?: string | null;
|
|
230
230
|
/**
|
|
231
|
-
* 🔴
|
|
231
|
+
* 🔴 [ref]:本次回决的**结算来源**,与决议同一条 UPDATE 落列 `settled_by`(语义/两态读法/为什么是
|
|
232
232
|
* 自己一列,全在 {@link AskRow.settledBy})。缺席 ⇒ 列 NULL ⇒ 读回是「一个人答的」。
|
|
233
233
|
*
|
|
234
234
|
* 店**不判词**(词表属主是 core):写什么存什么。店只判**形** —— `assertDecideSettledBy` 的那一条
|
|
235
|
-
* (长度 ≤ 列宽;
|
|
235
|
+
* (长度 ≤ 列宽;[ref] 起 approve 行也可以带来源位),理由见那只门的顶注;三 twin 同判。
|
|
236
236
|
*/
|
|
237
237
|
settledBy?: HostSettledBy;
|
|
238
238
|
/** [ref]:ctrl+g 编辑实参,与决议同一条 UPDATE 落列(语义三态见 {@link AskRow.updatedInput})。
|
|
@@ -244,7 +244,8 @@ export interface DecideAskInput {
|
|
|
244
244
|
* `idempotency_conflict`(车4 §12-E):同一 (task_id, idempotency_key) 已被**另一条** ask 的回决占用。
|
|
245
245
|
* 🔴 方言错误的判别**收在店内**(TiDB `ER_DUP_ENTRY`/errno 1062 与 PG SQLSTATE 23505),端点只认这个
|
|
246
246
|
* typed 臂 —— 否则每个消费层都得自己认两套驱动的错误对象形状,方言就漏出了持久层。
|
|
247
|
-
* `row` = 判定时刻读到的本 ask
|
|
247
|
+
* `row` = 判定时刻读到的本 ask 行,经这次决议的属主维投影({@link projectDecideReading}):行不在(并发删)**或行已不带着
|
|
248
|
+
* 门判过的那位属主**(出域,[ref])⇒ `null` —— 两者同读,出域的输者拿不到别人的行。
|
|
248
249
|
*/
|
|
249
250
|
export type DecideResult = {
|
|
250
251
|
ok: true;
|
|
@@ -274,17 +275,17 @@ export declare function assertIdempotencyKeyShape(key: string): void;
|
|
|
274
275
|
/** `settled_by` 列宽 = 这一格的唯一尺(两方言 DDL 与下面的形门读同一个常量,不手抄第二份)。 */
|
|
275
276
|
export declare const MAX_SETTLED_BY_CHARS = 16;
|
|
276
277
|
/** `settled_by` 这一列装得下这个词吗(1..{@link MAX_SETTLED_BY_CHARS})—— 店门口形门({@link assertDecideSettledBy})的**谓词本身**。
|
|
277
|
-
*
|
|
278
|
+
* [ref] 起决定口不再读它:wire 上的出处位是闭集(`host-decision.ts` 的 `APPROVAL_DECIDED_BY`),映射到这一列的词恒在尺内。 */
|
|
278
279
|
export declare function settledByFitsColumn(v: string): boolean;
|
|
279
280
|
/**
|
|
280
|
-
*
|
|
281
|
+
* [ref] 的**入店卫生门**(三 twin 同判,与 {@link assertIdempotencyKeyShape} / {@link assertIntegralEpochMs} 同族)。
|
|
281
282
|
* 判的是**形**,不是**词** —— 词表属主恒是 core,本层一个词都不认识。一条:
|
|
282
283
|
*
|
|
283
284
|
* **长度 ≤ 列宽**。`settled_by` 是 `VARCHAR(16)` 的闭集词列。不拦的话:MySQL 协议侧非严格模式**静默截断**、PG 侧直接
|
|
284
285
|
* 报错 —— 同一份调用方代码在两个后端拿到两种答案(`assertIdempotencyKeyShape` 的 PAD SPACE 论证逐字同源),而**被截断过的
|
|
285
286
|
* 词与原词是两个词**:一条决议的来源在库里变成了另一件事。空串同拒(core 那边它不是词,存进去只会读成一个假的「非人」)。
|
|
286
287
|
*
|
|
287
|
-
* 🔴
|
|
288
|
+
* 🔴 [ref]:此前的第二条「只与 `deny` 同行」**删了** —— 它的前提(「只有人能批准一个要执行的动作,core 对 `{allow:true,settledBy}`
|
|
288
289
|
* 一律 fail-closed 拒」)自 core 7.39.0 起不成立:策略的放行铸 `policy_allowed`,决定体的出处位 `decidedBy:"policy"` 在 allow 与 deny
|
|
289
290
|
* 上都落这一列,approve 行带来源位是一条合法的行(读回铸点 `outcomeOfDecidedRow` 两向都读它)。今天写这一列的只有两条路:决定口经
|
|
290
291
|
* `liveSettledBy` 映射来的 `"policy"`,与 `claimTerminal(refuse)` 的 {@link POLICY_REFUSAL_DECISION} —— 都是 core 在两向上都收的词。
|
|
@@ -362,7 +363,7 @@ export type AskTerminalClaimCurrent = {
|
|
|
362
363
|
decision: AskDecision | null;
|
|
363
364
|
/** [ref] 三态读法照 {@link AskRow.updatedInput}:键缺席 = 没带编辑;`null` 是编辑成 null 的值。 */
|
|
364
365
|
updatedInput?: unknown;
|
|
365
|
-
/**
|
|
366
|
+
/** [ref]:赢家决议的**结算来源**(语义与两态读法见 {@link AskRow.settledBy})。**必填**(不是可选)——
|
|
366
367
|
* 可选会让投影漏挑这一列时静默编译过,而漏挑的后果恰是本批要修的病:CAS 输家把赢家的策略拒读成人拒。 */
|
|
367
368
|
settledBy: HostSettledBy | null;
|
|
368
369
|
/** 行上记着的成因,经问账行成因的唯一读口 `causeOfAskRow` 读出(`kind` 说它在这一行上的意思:VOID / DENIED = 终态成因,PARKING / PARKED = 转 park 的触发成因);
|
|
@@ -427,11 +428,37 @@ export interface BatchRow {
|
|
|
427
428
|
export type AskCallCoordinate = Pick<AskRow, "taskId" | "legKey" | "toolCallId" | "sourceTaskId">;
|
|
428
429
|
/** 「这一行在这次调用上」的唯一判据(四列逐字相等):InMemory twin 的筛子与 SQL twin 的出口对齐读同一只。 */
|
|
429
430
|
export declare function askRowOnCall(row: AskRow, call: AskCallCoordinate): boolean;
|
|
431
|
+
/**
|
|
432
|
+
* 🔴 [ref] —— **一只问的属主判据**(全仓唯一;两扇决议口 —— live 应答口 `POST /v1/tool-approvals/:id/respond`、耐久决断口
|
|
433
|
+
* `POST /v1/tasks/:taskId/asks/:askId/decision` —— 与按问读口都调它):调用方是不是这只问的属主。`owner` 只有一条来源律:有行的问读行上
|
|
434
|
+
* **当下的** `owner` 列(铸行写定,只有 `/v1/adoption` 改写它;进程内任何快照 —— 包括登记在铸卡那一刻记下的那一格 —— 都改不动);
|
|
435
|
+
* 没有行的问(问账没上场 / 旧族腿)只有登记记下的那一位可读。`null` = auth-off 单用户行,恒过。
|
|
436
|
+
* 门判过的那位属主再交给决议 CAS 的作用域({@link askRowCarriesOwner},[ref])。耐久决断口的 operator 越域臂不在这里 —— 那是那扇口自己的授权门。
|
|
437
|
+
*/
|
|
438
|
+
export declare function askOwnerAdmits(owner: string | null, principal: string | undefined): boolean;
|
|
439
|
+
/**
|
|
440
|
+
* 🔴 [ref] —— **决议作用域的属主维**:这一行此刻带着的属主,是不是这次决议的门判过的那一位(逐字相等;`null` 只等于 `null`)。
|
|
441
|
+
*
|
|
442
|
+
* 律(一条):一次决议请求的作用域 = (ask, 批, **门判过的那位属主**)。属主的唯一来源是行上的 `owner` 列(铸行写定,只有 `/v1/adoption` 改写它);
|
|
443
|
+
* 门(耐久回决口 `owner ∨ operator`、live 应答口 `owner`)照旧在门里判授权,本谓词**不复判授权**,只绑「门判的那一份属主事实」——
|
|
444
|
+
* 门读行与 CAS 之间属主被改写,门的判断就不再是关于这一行的判断。于是这次请求拿到的**每一份**行读数(CAS 本身、CAS 输者的读数、
|
|
445
|
+
* 提交歧义的确认读、幂等回放的命中)都过这一只:出域 = 缺席,门按缺席答(与行不在同体同码)。
|
|
446
|
+
* InMemory twin 的判定、SQL twin 输者读数的投影、两扇门的确认读读同一只;SQL twin 的 UPDATE 谓词是它的方言镜像({@link decideOwnerWhere})。
|
|
447
|
+
*/
|
|
448
|
+
export declare function askRowCarriesOwner(row: AskRow | null, owner: string | null): row is AskRow;
|
|
449
|
+
/** [ref]:决议输者读数的投影(三 twin 共用一份):行出了这次决议的属主域 ⇒ 读作缺席,不交出别人的行。 */
|
|
450
|
+
export declare function projectDecideReading(row: AskRow | null, owner: string | null): AskRow | null;
|
|
430
451
|
export interface ApprovalAskStore {
|
|
431
452
|
/** 幂等 upsert。返回**行 + 本次是否真插入**(判别位语义见 {@link EnsureAskResult})。 */
|
|
432
453
|
ensureAsk(row: NewAskRow): Promise<EnsureAskResult>;
|
|
433
454
|
transitionAsk(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
|
|
434
|
-
|
|
455
|
+
/**
|
|
456
|
+
* 人答臂的单赢者 CAS。🔴 [ref]:`owner` = 这次决议的门**判过的**那位属主(门读到的行上 `owner` 列;活登记 = 铸卡时记下的那一份),
|
|
457
|
+
* **不是**调用方的主体 —— 运维代决别人的问,传的是那个别人。它是作用域的第三维(与 ask_id / batch_id 并列,判据 {@link askRowCarriesOwner}):
|
|
458
|
+
* 行此刻不带这位属主(门读之后被 `/v1/adoption` 改写)⇒ CAS 输、零写,`row` 读作 `null`(与行不在同读)。**必填**,不是可选:
|
|
459
|
+
* 缺省等于不绑属主,安全轴上那是静默放行。
|
|
460
|
+
*/
|
|
461
|
+
decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
|
|
435
462
|
/**
|
|
436
463
|
* [ref]:原子终局 claim —— 把「争终局」与「读真相」并成**一次**店往返(胜负判定与败方 `current` 读数
|
|
437
464
|
* 在同一原子单元内,语义见 {@link AskTerminalClaimOutcome})。[ref]-R1 的病根「CAS 与读真相是两次店
|
|
@@ -482,12 +509,12 @@ export interface ApprovalAskStore {
|
|
|
482
509
|
* 后续件。 */
|
|
483
510
|
listPendingBySession(sessionId: string, owner: string | null, signal?: AbortSignal): Promise<AskRow[]>;
|
|
484
511
|
/**
|
|
485
|
-
* 🔴
|
|
512
|
+
* 🔴 [ref] / SN-C1:**这次调用在这条腿上的全部行** —— 任意状态、任意 ask 身份(同一调用不同类集 = 不同 askId 的几只问、升级前按旧派生
|
|
486
513
|
* 写的行,都在其中)。坐标 = {@link AskCallCoordinate} 四列**精确**匹配;序 = `created_at_ms ASC, ask_id ASC`(确定性)。
|
|
487
514
|
*
|
|
488
515
|
* 唯一消费者 = 会话授权短路的争议判据(`tool-approval.ts` `sessionGrantUncontestedByRow`):「这次调用在腿内有行 ⇒ 一揽子放行不得代答」。
|
|
489
516
|
* 为什么按调用而不是按 askId 点读:争议的真源是**调用**(人对这次调用说过什么 / 这次调用还有一张卡挂着),ask 身份只是其中一问的主键;
|
|
490
|
-
* 身份可以加轴(
|
|
517
|
+
* 身份可以加轴([ref] 加了类集),争议判据不得依赖身份 —— 按身份点读在身份加轴的那一刻就把同调用的别的问、旧派生的行读成「不存在」。
|
|
491
518
|
*
|
|
492
519
|
* 三 twin 同答:SQL twin 读后按四列逐字再滤一遍 —— MySQL 协议的 VARCHAR 等值带 PAD SPACE(`'tc'` = `'tc '`),PG(`COLLATE "C"`)与
|
|
493
520
|
* InMemory 严格比较;不在入口拒(调用 id 是引擎铸的原值,首尾空白不归本店判),在出口对齐。索引:走 `idx_ask_task_state`
|
|
@@ -585,7 +612,7 @@ export declare const TIDB_APPROVAL_ASK_STATEMENTS: readonly string[];
|
|
|
585
612
|
/** {@link TIDB_APPROVAL_ASK_STATEMENTS} 的遍历壳——生产路径走 `tidb-pool.ts` 的中央 `ensureSchema`
|
|
586
613
|
* (那里展开了同一份数组),本函数留给只需要这两张表的集成测试。 */
|
|
587
614
|
export declare function ensureTiDBApprovalAskSchema(pool: MySqlPool): Promise<void>;
|
|
588
|
-
/**
|
|
615
|
+
/** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgApprovalAskSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
589
616
|
export declare const APPROVAL_ASK_INDEXES: readonly IndexSpec[];
|
|
590
617
|
export declare function ensurePgApprovalAskSchema(q: PgQueryFn): Promise<void>;
|
|
591
618
|
/**
|
|
@@ -638,7 +665,7 @@ export declare class SqlApprovalAskStore implements ApprovalAskStore {
|
|
|
638
665
|
private getBatchOn;
|
|
639
666
|
ensureAsk(row: NewAskRow): Promise<EnsureAskResult>;
|
|
640
667
|
transitionAsk(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
|
|
641
|
-
decideAsk(askId: string, batchId: string, decision: DecideAskInput): Promise<DecideResult>;
|
|
668
|
+
decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
|
|
642
669
|
/**
|
|
643
670
|
* [ref] 原子终局 claim(接口契约见 {@link ApprovalAskStore.claimTerminal};类型语义见
|
|
644
671
|
* {@link AskTerminalClaimOutcome})。expire 意图 = 既有 `expireAsk` 事务**原体**(步⓪-③ 逐字保留,
|
|
@@ -89,6 +89,15 @@ export function projectAskTerminalClaimTruth(row) {
|
|
|
89
89
|
export function askRowOnCall(row, call) {
|
|
90
90
|
return row.taskId === call.taskId && row.legKey === call.legKey && row.toolCallId === call.toolCallId && row.sourceTaskId === call.sourceTaskId;
|
|
91
91
|
}
|
|
92
|
+
export function askOwnerAdmits(owner, principal) {
|
|
93
|
+
return owner === null || owner === principal;
|
|
94
|
+
}
|
|
95
|
+
export function askRowCarriesOwner(row, owner) {
|
|
96
|
+
return row !== null && row.owner === owner;
|
|
97
|
+
}
|
|
98
|
+
export function projectDecideReading(row, owner) {
|
|
99
|
+
return askRowCarriesOwner(row, owner) ? row : null;
|
|
100
|
+
}
|
|
92
101
|
export const APPROVAL_ASK_TABLE = "approval_ask";
|
|
93
102
|
export const APPROVAL_BATCH_TABLE = "approval_batch";
|
|
94
103
|
export const TIDB_APPROVAL_ASK_STATEMENTS = [
|
|
@@ -365,6 +374,11 @@ function ph(dialect, n) {
|
|
|
365
374
|
function pendingClaimWhere(dialect, firstParam) {
|
|
366
375
|
return `ask_id = ${ph(dialect, firstParam)} AND batch_id = ${ph(dialect, firstParam + 1)} AND state = 'STREAM_PENDING'`;
|
|
367
376
|
}
|
|
377
|
+
function decideOwnerWhere(dialect, owner, param) {
|
|
378
|
+
if (owner === null)
|
|
379
|
+
return { sql: "owner IS NULL", params: [] };
|
|
380
|
+
return dialect === "tidb" ? { sql: "CAST(owner AS BINARY) = CAST(? AS BINARY)", params: [owner] } : { sql: `owner = ${ph(dialect, param)}`, params: [owner] };
|
|
381
|
+
}
|
|
368
382
|
export class SqlApprovalAskStore {
|
|
369
383
|
db;
|
|
370
384
|
constructor(db) {
|
|
@@ -451,23 +465,24 @@ export class SqlApprovalAskStore {
|
|
|
451
465
|
const res = await this.db.query(`UPDATE ${APPROVAL_ASK_TABLE} SET ${setSql}, rev = rev + 1 WHERE ask_id = ${askIdPh} AND state = ${fromPh}`, [...vals, askId, from]);
|
|
452
466
|
return res.affected === 1;
|
|
453
467
|
}
|
|
454
|
-
async decideAsk(askId, batchId, decision) {
|
|
468
|
+
async decideAsk(askId, batchId, owner, decision) {
|
|
455
469
|
if (decision.idempotencyKey != null)
|
|
456
470
|
assertIdempotencyKeyShape(decision.idempotencyKey);
|
|
457
471
|
assertDecideSettledBy(decision);
|
|
458
472
|
const now = Date.now();
|
|
459
473
|
const dialect = this.db.dialect;
|
|
474
|
+
const ownerWhere = decideOwnerWhere(dialect, owner, 11);
|
|
460
475
|
const conn = await this.db.connect();
|
|
461
476
|
try {
|
|
462
477
|
await conn.begin();
|
|
463
478
|
const batchRes = await conn.query(this.q(`UPDATE ${APPROVAL_BATCH_TABLE} SET rev = rev + 1, updated_at_ms = ? WHERE batch_id = ? AND state = 'OPEN'`, `UPDATE ${APPROVAL_BATCH_TABLE} SET rev = rev + 1, updated_at_ms = $1 WHERE batch_id = $2 AND state = 'OPEN'`), [now, batchId]);
|
|
464
479
|
if (batchRes.affected !== 1) {
|
|
465
480
|
await conn.rollback();
|
|
466
|
-
return { ok: false, reason: "batch_closed", row: await this.getAskOn(conn, askId) };
|
|
481
|
+
return { ok: false, reason: "batch_closed", row: projectDecideReading(await this.getAskOn(conn, askId), owner) };
|
|
467
482
|
}
|
|
468
483
|
let askRes;
|
|
469
484
|
try {
|
|
470
|
-
askRes = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='DECIDED', decision=${ph(dialect, 1)}, decision_actor=${ph(dialect, 2)}, decision_note=${ph(dialect, 3)}, settled_by=${ph(dialect, 4)}, updated_input=${ph(dialect, 5)}, decided_at_ms=${ph(dialect, 6)}, idempotency_key=${ph(dialect, 7)}, rev=rev+1, updated_at_ms=${ph(dialect, 8)} WHERE ${pendingClaimWhere(dialect, 9)}`, [
|
|
485
|
+
askRes = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='DECIDED', decision=${ph(dialect, 1)}, decision_actor=${ph(dialect, 2)}, decision_note=${ph(dialect, 3)}, settled_by=${ph(dialect, 4)}, updated_input=${ph(dialect, 5)}, decided_at_ms=${ph(dialect, 6)}, idempotency_key=${ph(dialect, 7)}, rev=rev+1, updated_at_ms=${ph(dialect, 8)} WHERE ${pendingClaimWhere(dialect, 9)} AND ${ownerWhere.sql}`, [
|
|
471
486
|
decision.decision,
|
|
472
487
|
decision.decisionActor == null ? null : this.json(decision.decisionActor),
|
|
473
488
|
decision.decisionNote ?? null,
|
|
@@ -478,18 +493,19 @@ export class SqlApprovalAskStore {
|
|
|
478
493
|
now,
|
|
479
494
|
askId,
|
|
480
495
|
batchId,
|
|
496
|
+
...ownerWhere.params,
|
|
481
497
|
]);
|
|
482
498
|
}
|
|
483
499
|
catch (err) {
|
|
484
500
|
if (this.isDupKey(err)) {
|
|
485
501
|
await conn.rollback();
|
|
486
|
-
return { ok: false, reason: "idempotency_conflict", row: await this.getAskOn(conn, askId) };
|
|
502
|
+
return { ok: false, reason: "idempotency_conflict", row: projectDecideReading(await this.getAskOn(conn, askId), owner) };
|
|
487
503
|
}
|
|
488
504
|
throw err;
|
|
489
505
|
}
|
|
490
506
|
if (askRes.affected !== 1) {
|
|
491
507
|
await conn.rollback();
|
|
492
|
-
return { ok: false, reason: "ask_not_pending", row: await this.getAskOn(conn, askId) };
|
|
508
|
+
return { ok: false, reason: "ask_not_pending", row: projectDecideReading(await this.getAskOn(conn, askId), owner) };
|
|
493
509
|
}
|
|
494
510
|
await conn.commit();
|
|
495
511
|
}
|
|
@@ -49,7 +49,7 @@ export declare class MemoryApprovalExemptionStore implements ApprovalExemptionSt
|
|
|
49
49
|
deleteBySession(sessionId: string): Promise<number>;
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
* 🔴
|
|
52
|
+
* 🔴 [ref] —— **fail-closed per session file.** A record in the MIDDLE of a session's log that cannot be read (bit rot,
|
|
53
53
|
* a hand edit, a line `42`, an object missing `toolName`) used to be skipped silently. When that line was a REVOKE
|
|
54
54
|
* tombstone, the grant before it survived the replay: a "don't ask again" the operator had revoked came back and the
|
|
55
55
|
* tool ran WITHOUT asking — the fail-open direction on the approval axis. We cannot tell which fact the line held, so
|
|
@@ -63,14 +63,14 @@ export declare class FileApprovalExemptionStore implements ApprovalExemptionStor
|
|
|
63
63
|
private readonly dir;
|
|
64
64
|
private readonly bySession;
|
|
65
65
|
private readonly logs;
|
|
66
|
-
/**
|
|
66
|
+
/** [ref]: sanitized session key → that session log's gate (only files that replayed a bad record are listed). */
|
|
67
67
|
private readonly corruptGates;
|
|
68
68
|
private readonly warn;
|
|
69
69
|
/** @param opts.warn corrupt-read disclosure seat (`LocalBackend` wires `discloseWarn`; absent ⇒ the owner falls back to `console.warn`, never to silence). */
|
|
70
70
|
constructor(root: string, opts?: {
|
|
71
71
|
warn?: Logger["warn"];
|
|
72
72
|
});
|
|
73
|
-
/**
|
|
73
|
+
/** [ref]: first line of every judging / appending method (see the class note). */
|
|
74
74
|
private assertUsable;
|
|
75
75
|
private pathFor;
|
|
76
76
|
/** Replay every session log (torn-tail-safe; last-wins with revoke tombstones). Index keyed by the SANITIZED id. */
|
|
@@ -74,9 +74,9 @@ export declare class MemoryApprovalNonceStore implements ApprovalNonceStore {
|
|
|
74
74
|
* 的既有暴露同级,且 SQL 车道不受此影响);**绝不**能出现的是反向 —— 记录还在却被读成不在,那要靠
|
|
75
75
|
* core JSONL 读法的断尾安全(半行丢弃)兜住。
|
|
76
76
|
*
|
|
77
|
-
* 🔴 **
|
|
77
|
+
* 🔴 **[ref]:中间一行读不出 ⇒ 整本拒用(fail-closed)**。撕尾是崩溃的正常形(core 丢弃且不报);而**中间**
|
|
78
78
|
* 那一行读不出(位腐 / 手改 / 一行 `42` / 缺键的对象)时,我们不知道它是哪一只 nonce —— 修前静默跳过它,等于
|
|
79
|
-
* 让那只已消费的证明再被受理一次(
|
|
79
|
+
* 让那只已消费的证明再被受理一次([ref] 要关的重放洞换了个入口)。现在由属主披露(`approval_nonce_corrupt_read`)
|
|
80
80
|
* 并合上 {@link gate}:`consume` / `reapExpired` 第一行即带码拒(`JsonlStoreCorruptError`,外层答 500);`nowMs` 不读账、
|
|
81
81
|
* 不经闸。清扫同样要拒:压实会把幸存者原样写回、把坏行连同证据一起抹掉,下一次重启读到的就是一本「干净」的账 ——
|
|
82
82
|
* 闸自己打开,而那只 nonce 仍然没被记住。出路在拒绝句里(移开文件的代价与安全时机)。
|
|
@@ -89,7 +89,7 @@ export declare class FileApprovalNonceStore implements ApprovalNonceStore {
|
|
|
89
89
|
* 从复合键里**解析**出来是一条没必要的反向铸形 —— 记录留着就不必解析。 */
|
|
90
90
|
private readonly rows;
|
|
91
91
|
private log;
|
|
92
|
-
/**
|
|
92
|
+
/** [ref]:本账的损坏闸(见类注)。 */
|
|
93
93
|
private readonly gate;
|
|
94
94
|
/** @param opts.warn 腐读披露座(`LocalBackend` 接 `discloseWarn`;缺席 ⇒ 属主退回 `console.warn`,不退回沉默)。 */
|
|
95
95
|
constructor(root: string, opts?: {
|
|
@@ -44,7 +44,7 @@ type ListOpts = {
|
|
|
44
44
|
limit?: number;
|
|
45
45
|
};
|
|
46
46
|
export declare function ensureTiDBBackgroundAgentSchema(pool: Pool): Promise<void>;
|
|
47
|
-
/**
|
|
47
|
+
/** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgBackgroundAgentSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
48
48
|
export declare const BACKGROUND_AGENT_INDEXES: readonly IndexSpec[];
|
|
49
49
|
export declare function ensurePgBackgroundAgentSchema(q: PgQueryFn): Promise<void>;
|
|
50
50
|
export declare class TiDBBackgroundAgentStore implements BackgroundAgentStore {
|
|
@@ -106,7 +106,7 @@ export interface BackgroundShellDriver<S> {
|
|
|
106
106
|
/** Best-effort cleanup of ONE shell's transport resources (kill + remove temp dirs/handles). Should not throw. */
|
|
107
107
|
disposeOne(state: S): Promise<void>;
|
|
108
108
|
/**
|
|
109
|
-
*
|
|
109
|
+
* [ref](core 7.32.0 [ref])—— **可选**的同步硬收一枪(`BackgroundShellCapability.killBackgroundNow` 的 driver 半场)。
|
|
110
110
|
* 只有**本机有进程组可发**的 driver 实现它(今天只有 host 车道);远端 / 沙箱车道留空 ⇒ 座位根本不挂出来,core 对那些行
|
|
111
111
|
* 答 `no_pgid` 并派普通 kill。契约(core `docs/background-process-lifetime.md`):同步(无 TERM、无定时器、无 await)、
|
|
112
112
|
* 幂等、永不抛、只对**证明得了还是自己的** pid 发信号(观察到退出 ⇒ `already_gone`,一枪都不发)。
|
|
@@ -162,7 +162,7 @@ export declare class BackgroundShellManager<S> {
|
|
|
162
162
|
poll(shellId: BackgroundShellId): Promise<Result<BackgroundPoll, BackgroundShellError>>;
|
|
163
163
|
kill(shellId: BackgroundShellId): Promise<Result<void, BackgroundShellError>>;
|
|
164
164
|
/**
|
|
165
|
-
*
|
|
165
|
+
* [ref] —— 座位 `killBackgroundNow(shellId)` 的 manager 半场:**同步**、永不抛。
|
|
166
166
|
* · 不是本 env 的 shell(未知 / 伪造 / 已被驱逐的终态行)⇒ `already_gone`(core 契约「or not its shell」);
|
|
167
167
|
* · driver 不实现 {@link BackgroundShellDriver.killNow} ⇒ `no_pgid`(没有同步硬收可落;实现座位的 env 才会走到这里);
|
|
168
168
|
* · driver 答出三词之外 ⇒ `no_pgid`(没有落地,可重试)。driver 的座位按契约**永不抛**(host 的那只由构造保证:只读子进程句柄
|
|
@@ -121,7 +121,7 @@ export declare class SqlBlobBackend implements BlobBackend {
|
|
|
121
121
|
* (a): an over-cap blob is REJECTED (typed {@link BlobTooLargeError}) BEFORE the driver ever sees the bytes —
|
|
122
122
|
* the alternative is an inscrutable packet-limit error deep in the driver, and on the HTTP face a 502 that
|
|
123
123
|
* invites the peer to retry a blob that can never land.
|
|
124
|
-
* 🔴 The cap is judged ON THE CONNECTION THAT WRITES (
|
|
124
|
+
* 🔴 The cap is judged ON THE CONNECTION THAT WRITES ([ref]): `max_allowed_packet` is a session value, fixed per
|
|
125
125
|
* connection, so the write borrows one connection through {@link connectJudged}, which reads ITS walls, judges, and — when
|
|
126
126
|
* the refusal is that connection's packet wall and the server's global wall is higher — replaces the stale connection and
|
|
127
127
|
* judges once more; the INSERT runs on the connection that passed. Never a pool-level reading, never a bare `pool.query`. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { presignS3Url, presignS3ListUrl } from "./s3-presign.js";
|
|
3
|
+
import { isNoSuchBucketAnswer } from "./s3-answer.js";
|
|
3
4
|
import { connectJudged, mysqlDriver, packetWallStatementBytes, pgDriver, rowWallPayloadBytes, sqlWallsOf } from "./sql-driver.js";
|
|
4
5
|
import { createLogger } from "../observability/logger.js";
|
|
5
6
|
const BLOB_GC_GRACE_MS = 3_600_000;
|
|
@@ -328,7 +329,7 @@ export class MinioBlobBackend {
|
|
|
328
329
|
if (res.ok)
|
|
329
330
|
return { state: "present" };
|
|
330
331
|
const body = await res.text().catch(() => "");
|
|
331
|
-
if (res.status
|
|
332
|
+
if (isNoSuchBucketAnswer(res.status, body))
|
|
332
333
|
return { state: "missing" };
|
|
333
334
|
return { state: "unknown", detail: `HTTP ${res.status}` };
|
|
334
335
|
}
|
|
@@ -3,33 +3,34 @@ import type { OwnerAwareSessionStore, SessionListItem } from "../security.js";
|
|
|
3
3
|
import type { StagingHandle } from "../session-sync-kernel.js";
|
|
4
4
|
import { type PlacementAcquireOpts } from "./session-placement.js";
|
|
5
5
|
import type { InstructionSourceStore } from "../instruction-source-notice.js";
|
|
6
|
-
import type { SessionFaceReader } from "../session-incarnation.js";
|
|
7
6
|
import type { OwnerlessClaim } from "../delegated-session-owner.js";
|
|
8
7
|
export interface CachingOptions {
|
|
9
8
|
/** Idle seconds a woken session is kept warm. 0 disables caching (pure passthrough). */
|
|
10
9
|
ttlSec: number;
|
|
11
10
|
sweepIntervalMs?: number;
|
|
12
|
-
/** Called once per warm hit that turned out stale (the store's head no longer names the cached leaf, or the
|
|
13
|
-
* gone): the entry was dropped and the session woken from the store again. Not an error — the operator signal for
|
|
11
|
+
/** Called once per warm hit that turned out stale (the store's head no longer names the cached occupant and leaf, or the
|
|
12
|
+
* session is gone): the entry was dropped and the session woken from the store again. Not an error — the operator signal for
|
|
14
13
|
* "requests for one session alternate between replicas within the TTL" (the hit rate affinity would buy back). */
|
|
15
14
|
onStaleHit?: (sessionId: string) => void;
|
|
16
15
|
}
|
|
17
|
-
/** The store's current head for one session — the one read every warm hit is checked
|
|
18
|
-
*
|
|
19
|
-
export type SessionHeadReader = Required<Pick<
|
|
16
|
+
/** The store's current head for one session — core `SessionStore.headOf`, the one by-id read of the row every warm hit is checked
|
|
17
|
+
* against (`undefined` = no such session). This cache requires its inner store to have it. */
|
|
18
|
+
export type SessionHeadReader = Required<Pick<SessionStore, "headOf">>;
|
|
20
19
|
/**
|
|
21
20
|
* Warm cache in front of a durable {@link SessionStore}.
|
|
22
21
|
*
|
|
23
22
|
* Keeps a woken session in memory and **reuses the same storage instance across turns**, so an active session is not
|
|
24
23
|
* woken from the store (meta row + event log) on every short turn. Idle sessions expire after `ttlSec`; `release` evicts.
|
|
25
24
|
*
|
|
26
|
-
* **One rule: a warm entry is served only while the store's head for that session still names the
|
|
27
|
-
* holds.** Every hit reads the head first (`
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
25
|
+
* **One rule: a warm entry is served only while the store's head for that session still names the occupant and the leaf
|
|
26
|
+
* the entry holds.** Every hit reads the head first (`headOf` — one primary-key row read on the SQL twins); head gone, another
|
|
27
|
+
* occupant (core `compareOccupants` — anything but `same`, `unknown` included), or leaf moved ⇒ the entry is dropped and the
|
|
28
|
+
* session is woken from the store again ({@link CachingOptions.onStaleHit}). The leaf is half the token because it is exactly
|
|
29
|
+
* what the stores' conditional writes compare (`expectedLeafId`): a handle this cache hands out is never behind the store's
|
|
30
|
+
* leaf, so those writes fail only on a genuinely concurrent write — two runs writing one session at the same time. The
|
|
31
|
+
* occupant is the other half: a row another replica deleted and created again under the same id can stand at the leaf the
|
|
32
|
+
* entry holds (both empty — `null`), and serving the old view would hand a run the previous occupant's token. Any number of
|
|
33
|
+
* replicas may share one store under any routing; session affinity only raises the hit rate.
|
|
33
34
|
*
|
|
34
35
|
* Open item (the same before this rule): a write that rewrites history while leaving the final leaf id where it was —
|
|
35
36
|
* a session-sync replace / `overwrite-dst` staged commit on ANOTHER replica that changes entry payloads under the same
|
|
@@ -50,17 +51,12 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
50
51
|
private readonly ttlMs;
|
|
51
52
|
private readonly timer?;
|
|
52
53
|
private readonly onStaleHit?;
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* 与记忆座在默认部署上读不到化身。 */
|
|
58
|
-
readonly sessionFaceOf?: SessionFaceReader;
|
|
59
|
-
/** core `SessionStore.incarnationOf`(按 id 读住客)—— 同一条纯转发、同一条理由:答的是行上那一格,绝不从暖缓存里那只会话的元数据答
|
|
60
|
-
* (缓存的会话活得比「另一只店删掉又重建了这一行」长)。🔴 必须转发:k8s 工作区空间的每 run 读与起服门读的就是本类。 */
|
|
61
|
-
readonly incarnationOf?: SessionStore["incarnationOf"];
|
|
54
|
+
/** core `SessionStore.headOf` —— 按 id 读一行(属主 / 住客 / 叶子)的唯一读口,**纯转发、不经暖缓存**(答的是行,绝不从暖缓存里那只会话的元数据答 ——
|
|
55
|
+
* 缓存的会话活得比「另一只店删掉又重建了这一行」长)。内层店必有(本类的暖命中按它核新鲜)。🔴 必须转发:生产默认把真店包进本类,授权口 / 属主门 /
|
|
56
|
+
* parked 两读 / k8s 工作区空间 / SSE 探针 / resume-at 读的都是本类。 */
|
|
57
|
+
readonly headOf: SessionHeadReader["headOf"];
|
|
62
58
|
readonly register?: (sessionId: string, owner: string | null) => Promise<void>;
|
|
63
|
-
/**
|
|
59
|
+
/** [ref] 委派继承律的认领口,纯转发(写的是行上的属主那一格 —— 只 CAS 子行自己,不碰暖缓存里的会话;停驻挂点在默认部署上读的就是本类 —— 与 `placementOf` 同转发同缺:内店记录委派树 ⇒ 两只都在)。 */
|
|
64
60
|
readonly claimOwnerless?: OwnerlessClaim;
|
|
65
61
|
/** Delegated SessionRepo seam (§0.5) — list/fork/delete operate on the DURABLE tables directly (they bypass the
|
|
66
62
|
* warm cache by design; a fork/delete must read/write durable state, not a possibly-stale cached view). */
|
|
@@ -84,16 +80,11 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
84
80
|
/** The auto-titler's NULL-only title write (SQL twins + local sidecar carry it; pure pass-through). */
|
|
85
81
|
readonly setTitleIfNull?: (sessionId: string, title: string) => Promise<boolean>;
|
|
86
82
|
readonly probeTitle?: (sessionId: string) => Promise<"none" | "untitled" | "titled">;
|
|
87
|
-
/**
|
|
83
|
+
/** [ref] —— 换源通告的基线面(`session_meta.instruction_source` / local sidecar),纯转发、不经暖缓存。
|
|
88
84
|
* 🔴 必须转发(与 retention / placements 同一条教训):默认 `SESSION_CACHE_TTL_SEC=300` 把真店包进本类,
|
|
89
85
|
* 而装配点按「店上两个方法都在」判席 —— 不转发 = 默认部署上换源通告**静默不发**,且没有任何一处报错。 */
|
|
90
86
|
readonly readInstructionSource?: InstructionSourceStore["readInstructionSource"];
|
|
91
87
|
readonly recordInstructionSource?: InstructionSourceStore["recordInstructionSource"];
|
|
92
|
-
/** E18 — delegate the leaf read straight to inner (a cache-bypassing single SELECT; the resume-at turn-capture
|
|
93
|
-
* reads the DURABLE leaf, not a possibly-stale cached view — same discipline as the §0.5 repo ops above). */
|
|
94
|
-
readonly getLeafId?: (sessionId: string) => Promise<string | null>;
|
|
95
|
-
/** [ref] 六轮复审:owner+leafId 原子快照透传(cache-bypassing,getLeafId 同姿势)。内层店必有(本类的暖命中按它核新鲜)。 */
|
|
96
|
-
readonly getHead: SessionHeadReader["getHead"];
|
|
97
88
|
/** 2c session-sync — delegated export/import seam, DURABLE (bypasses the warm cache exactly like
|
|
98
89
|
* list/fork: an export reads the full durable log, an import writes durable state). */
|
|
99
90
|
readonly exportEntries?: (sessionId: string) => Promise<SessionTreeEntry[] | null>;
|
|
@@ -154,9 +145,9 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
154
145
|
touch(sessionId: string): Promise<void>;
|
|
155
146
|
release(sessionId: string): Promise<void>;
|
|
156
147
|
/**
|
|
157
|
-
* The cache's one rule: the warm entry for `sessionId`, if the store's head still names the leaf it holds;
|
|
158
|
-
* the entry is dropped (counted once via `onStaleHit`) and `undefined` sends the caller to the store. The head is
|
|
159
|
-
* first, the cached
|
|
148
|
+
* The cache's one rule: the warm entry for `sessionId`, if the store's head still names the occupant and the leaf it holds;
|
|
149
|
+
* otherwise the entry is dropped (counted once via `onStaleHit`) and `undefined` sends the caller to the store. The head is
|
|
150
|
+
* read first, the cached view second: a write this replica commits in between can only turn a fresh verdict into a stale
|
|
160
151
|
* one (an extra wake), never the reverse.
|
|
161
152
|
*/
|
|
162
153
|
private freshHit;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { admitSessionPlacement } from "@sema-agent/core";
|
|
1
|
+
import { admitSessionPlacement, compareOccupants } from "@sema-agent/core";
|
|
2
2
|
import { placementCapabilityOf } from "./session-placement.js";
|
|
3
3
|
export class CachingSessionStore {
|
|
4
4
|
inner;
|
|
@@ -7,9 +7,7 @@ export class CachingSessionStore {
|
|
|
7
7
|
ttlMs;
|
|
8
8
|
timer;
|
|
9
9
|
onStaleHit;
|
|
10
|
-
|
|
11
|
-
sessionFaceOf;
|
|
12
|
-
incarnationOf;
|
|
10
|
+
headOf;
|
|
13
11
|
register;
|
|
14
12
|
claimOwnerless;
|
|
15
13
|
listSessions;
|
|
@@ -21,8 +19,6 @@ export class CachingSessionStore {
|
|
|
21
19
|
probeTitle;
|
|
22
20
|
readInstructionSource;
|
|
23
21
|
recordInstructionSource;
|
|
24
|
-
getLeafId;
|
|
25
|
-
getHead;
|
|
26
22
|
exportEntries;
|
|
27
23
|
listEntryIds;
|
|
28
24
|
exportEntriesStream;
|
|
@@ -39,7 +35,7 @@ export class CachingSessionStore {
|
|
|
39
35
|
this.inner = inner;
|
|
40
36
|
this.ttlMs = Math.max(0, opts.ttlSec) * 1000;
|
|
41
37
|
this.onStaleHit = opts.onStaleHit;
|
|
42
|
-
this.
|
|
38
|
+
this.headOf = inner.headOf.bind(inner);
|
|
43
39
|
const declared = inner.retention;
|
|
44
40
|
if (declared !== undefined)
|
|
45
41
|
this.retention = declared;
|
|
@@ -51,12 +47,6 @@ export class CachingSessionStore {
|
|
|
51
47
|
if (typeof innerPlacementOf === "function")
|
|
52
48
|
this.placementOf = (id) => innerPlacementOf.call(inner, id);
|
|
53
49
|
const ownerAware = inner;
|
|
54
|
-
if (ownerAware.ownerOf)
|
|
55
|
-
this.ownerOf = ownerAware.ownerOf.bind(inner);
|
|
56
|
-
if (ownerAware.sessionFaceOf)
|
|
57
|
-
this.sessionFaceOf = ownerAware.sessionFaceOf.bind(inner);
|
|
58
|
-
if (typeof inner.incarnationOf === "function")
|
|
59
|
-
this.incarnationOf = inner.incarnationOf.bind(inner);
|
|
60
50
|
if (ownerAware.register)
|
|
61
51
|
this.register = ownerAware.register.bind(inner);
|
|
62
52
|
if (ownerAware.claimOwnerless)
|
|
@@ -77,8 +67,6 @@ export class CachingSessionStore {
|
|
|
77
67
|
this.recordInstructionSource = ownerAware.recordInstructionSource.bind(inner);
|
|
78
68
|
if (ownerAware.fork)
|
|
79
69
|
this.fork = ownerAware.fork.bind(inner);
|
|
80
|
-
if (ownerAware.getLeafId)
|
|
81
|
-
this.getLeafId = ownerAware.getLeafId.bind(inner);
|
|
82
70
|
if (ownerAware.exportEntries)
|
|
83
71
|
this.exportEntries = ownerAware.exportEntries.bind(inner);
|
|
84
72
|
if (ownerAware.listEntryIds)
|
|
@@ -188,8 +176,8 @@ export class CachingSessionStore {
|
|
|
188
176
|
const hit = this.cache.get(sessionId);
|
|
189
177
|
if (hit === undefined)
|
|
190
178
|
return undefined;
|
|
191
|
-
const head = await this.inner.
|
|
192
|
-
if (head !== undefined && head.leafId === (await hit.acquired.session.getLeafId()))
|
|
179
|
+
const head = await this.inner.headOf(sessionId);
|
|
180
|
+
if (head !== undefined && compareOccupants(head, await hit.acquired.session.getMetadata()) === "same" && head.leafId === (await hit.acquired.session.getLeafId()))
|
|
193
181
|
return hit;
|
|
194
182
|
if (this.cache.get(sessionId) === hit)
|
|
195
183
|
this.cache.delete(sessionId);
|