@sema-agent/server 7.145.0 → 7.147.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +876 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +374 -99
- package/deploy/facts/CHANGES.json +25 -0
- package/deploy/facts/README.md +57 -0
- package/deploy/facts/lanes.json +61 -0
- package/deploy/facts/lanes.schema.json +57 -0
- package/deploy/facts/sandbox-rbac.json +113 -0
- package/deploy/facts/sandbox-rbac.schema.json +74 -0
- package/deploy/facts/sealed-key.json +9 -0
- package/deploy/facts/sealed-key.schema.json +52 -0
- package/deploy/sema-up/README.md +2 -2
- package/deploy/sema-up/chart/templates/_helpers.tpl +41 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +9 -4
- package/deploy/sema-up/chart/templates/server.yaml +9 -4
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +2 -1
- package/deploy/sema-up/lib/flagshape.sh +4 -0
- package/deploy/sema-up/lib/lanes.json +2 -5
- package/deploy/sema-up/sema-up.sh +12 -9
- package/deploy/sema-up/stack/compose.yaml +5 -4
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +34 -17
- package/dist/adoption/import-limits.d.ts +6 -0
- package/dist/adoption/import-limits.js +7 -0
- package/dist/adoption/import.d.ts +62 -0
- package/dist/adoption/import.js +107 -0
- package/dist/adoption/wire.d.ts +52 -0
- package/dist/adoption/wire.js +9 -0
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +7 -16
- package/dist/approval-card.js +0 -4
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-gate-currency.js +1 -1
- package/dist/approval-reconciler.d.ts +1 -1
- package/dist/approval.d.ts +3 -3
- package/dist/audit.js +2 -2
- package/dist/bench/s1/live-deps.js +3 -1
- package/dist/boot/crash-last.js +2 -1
- package/dist/boot/deployment-mods.d.ts +11 -1
- package/dist/boot/deployment-mods.js +15 -2
- package/dist/boot/device-lane.js +7 -5
- package/dist/boot/engine-lease.d.ts +195 -22
- package/dist/boot/engine-lease.js +146 -20
- package/dist/boot/execution-env.d.ts +5 -0
- package/dist/boot/execution-env.js +57 -33
- package/dist/boot/execution-lane.d.ts +37 -9
- package/dist/boot/execution-lane.js +74 -20
- package/dist/boot/exit-boundary.d.ts +50 -0
- package/dist/boot/exit-boundary.js +32 -0
- package/dist/boot/exit-last.d.ts +20 -4
- package/dist/boot/exit-last.js +23 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/governance-seams.js +1 -0
- package/dist/boot/leader.js +1 -1
- package/dist/boot/memory-boundary.d.ts +11 -11
- package/dist/boot/memory-boundary.js +3 -3
- package/dist/boot/memory-consolidation.d.ts +42 -41
- package/dist/boot/memory-consolidation.js +26 -28
- package/dist/boot/org-memory.js +3 -2
- package/dist/boot/parked-revive-gate.d.ts +1 -1
- package/dist/boot/parked-revive-gate.js +1 -1
- package/dist/boot/reapers.d.ts +12 -4
- package/dist/boot/reapers.js +40 -16
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +126 -123
- package/dist/boot/retention-lane.d.ts +4 -42
- package/dist/boot/runner-deps.js +1 -1
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +11 -3
- package/dist/boot/shutdown.js +27 -9
- package/dist/boot/stage-01-config.d.ts +1 -1
- package/dist/boot/stage-01-config.js +7 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
- package/dist/boot/stage-02-web-admin-pull.js +10 -8
- package/dist/boot/stage-03-store-backend.d.ts +2 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +2 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -1
- package/dist/boot/stage-05-execution-env.js +6 -6
- package/dist/boot/stage-06-runners.d.ts +5 -2
- package/dist/boot/stage-06-runners.js +12 -13
- package/dist/boot/stage-07-capability-layer.d.ts +5 -2
- package/dist/boot/stage-07-capability-layer.js +7 -7
- package/dist/boot/stage-08-reapers.d.ts +5 -2
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +6 -2
- package/dist/boot/stage-10-http-server.d.ts +6 -2
- package/dist/boot/stage-10-http-server.js +5 -3
- package/dist/boot/stores.d.ts +10 -0
- package/dist/boot/stores.js +53 -26
- package/dist/boot/web-admin.js +3 -3
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +6 -2
- package/dist/capabilities/composite-members.d.ts +4 -1
- package/dist/capabilities/composite-members.js +4 -1
- package/dist/capabilities/execution-lane.d.ts +7 -7
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +1 -1
- package/dist/capabilities/scenarios.d.ts +34 -20
- package/dist/capabilities/scenarios.js +13 -9
- package/dist/capabilities/settings-contract.d.ts +29 -0
- package/dist/capabilities/settings-contract.js +14 -0
- package/dist/capabilities/skills.d.ts +5 -5
- package/dist/capability-facts.d.ts +56 -1
- package/dist/capability-facts.js +59 -8
- package/dist/center-credential-renewer.js +3 -2
- package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
- package/dist/config-catalog.js +19 -9
- package/dist/config-invariants.d.ts +18 -3
- package/dist/config-invariants.js +36 -19
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-lkg.js +5 -6
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-provider.js +2 -0
- package/dist/config-types.d.ts +228 -185
- package/dist/config.d.ts +74 -6
- package/dist/config.js +146 -64
- package/dist/degenerate-instrument.js +1 -1
- package/dist/deleted-session-ids.d.ts +19 -0
- package/dist/deleted-session-ids.js +26 -0
- package/dist/deploy-facts.d.ts +155 -0
- package/dist/deploy-facts.js +95 -0
- package/dist/deployment-shape.d.ts +21 -12
- package/dist/deployment-shape.js +24 -6
- package/dist/device-ws-hub.d.ts +48 -3
- package/dist/device-ws-hub.js +48 -2
- package/dist/env-facts.d.ts +7 -5
- package/dist/env-facts.js +10 -6
- package/dist/error-code-family.d.ts +35 -0
- package/dist/error-code-family.js +26 -0
- package/dist/execution-config-root.d.ts +5 -5
- package/dist/execution-config-root.js +5 -5
- package/dist/execution-env-purpose.d.ts +14 -0
- package/dist/execution-env-purpose.js +29 -0
- package/dist/execution-lane-caps.d.ts +49 -86
- package/dist/execution-lane-caps.js +52 -62
- package/dist/execution-placement.d.ts +18 -2
- package/dist/execution-placement.js +19 -0
- package/dist/file-history-disclosure.d.ts +2 -2
- package/dist/fleet/drain-entry.d.ts +46 -3
- package/dist/fleet/drain-entry.js +6 -0
- package/dist/fleet/fleet-bus.d.ts +2 -1
- package/dist/fleet/serving-lease.js +3 -4
- package/dist/history-anchor.d.ts +22 -0
- package/dist/history-anchor.js +14 -0
- package/dist/hooks/branch-transcript.d.ts +1 -1
- package/dist/hooks/branch-transcript.js +1 -0
- package/dist/hooks/classic-stations.d.ts +25 -8
- package/dist/hooks/classic-stations.js +29 -3
- package/dist/hooks/command-spawn.d.ts +1 -4
- package/dist/hooks/command-spawn.js +0 -11
- package/dist/hooks/hook-runner.d.ts +85 -24
- package/dist/hooks/hook-runner.js +326 -109
- package/dist/hooks/hook-source.d.ts +14 -2
- package/dist/hooks/hook-source.js +8 -0
- package/dist/http/active-run-conflict.d.ts +1 -1
- package/dist/http/active-run-conflict.js +1 -1
- package/dist/http/admission.js +11 -1
- package/dist/http/approval-sweeps.d.ts +2 -5
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/checkpoint-ctx.d.ts +76 -71
- package/dist/http/checkpoint-ctx.js +40 -40
- package/dist/http/claim-latency.d.ts +10 -0
- package/dist/http/claim-latency.js +12 -0
- package/dist/http/dispatch.js +19 -3
- package/dist/http/durable-run-leg.d.ts +5 -0
- package/dist/http/durable-run-leg.js +3 -1
- package/dist/http/execution-context.d.ts +7 -1
- package/dist/http/execution-context.js +13 -0
- package/dist/http/health-self-report.d.ts +6 -2
- package/dist/http/health-self-report.js +3 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +5 -15
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
- package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
- package/dist/http/memory-store-refusal-reply.d.ts +3 -3
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +7 -4
- package/dist/http/principal-gate.d.ts +28 -16
- package/dist/http/principal-gate.js +10 -19
- package/dist/http/request-guards.d.ts +2 -2
- package/dist/http/request-guards.js +5 -5
- package/dist/http/resume-legs.d.ts +29 -10
- package/dist/http/resume-legs.js +94 -56
- package/dist/http/rewind-files-reply.d.ts +34 -0
- package/dist/http/rewind-files-reply.js +36 -0
- package/dist/http/route-ctx.d.ts +43 -26
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/adoption.d.ts +11 -0
- package/dist/http/routes/adoption.js +80 -6
- package/dist/http/routes/agents-roster.js +1 -0
- package/dist/http/routes/approvals-assistant.js +7 -26
- package/dist/http/routes/background.js +1 -0
- package/dist/http/routes/capabilities.js +12 -3
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +9 -14
- package/dist/http/routes/diagnostics.js +10 -20
- package/dist/http/routes/engine.d.ts +31 -0
- package/dist/http/routes/engine.js +81 -0
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-consolidation.js +3 -5
- package/dist/http/routes/memory-origin.d.ts +2 -2
- package/dist/http/routes/memory-origin.js +2 -4
- package/dist/http/routes/memory-policy.js +5 -1
- package/dist/http/routes/notify-wake.js +2 -1
- package/dist/http/routes/observability.js +3 -6
- package/dist/http/routes/projects.d.ts +70 -0
- package/dist/http/routes/projects.js +86 -0
- package/dist/http/routes/rules.js +30 -2
- package/dist/http/routes/runs.js +15 -11
- package/dist/http/routes/session-sync.js +39 -35
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +7 -1
- package/dist/http/routes/sessions.js +108 -2
- package/dist/http/routes/tasks.js +32 -8
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/run-concurrency-cap.d.ts +86 -0
- package/dist/http/run-concurrency-cap.js +54 -0
- package/dist/http/server.d.ts +31 -14
- package/dist/http/server.js +29 -3
- package/dist/http/stored-body-replay.d.ts +12 -7
- package/dist/http/stored-body-replay.js +28 -5
- package/dist/http/wire-types.d.ts +27 -13
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/instruction-source-notice.d.ts +1 -1
- package/dist/json-body-limit.d.ts +8 -0
- package/dist/json-body-limit.js +2 -0
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/local-data-root.d.ts +2 -2
- package/dist/memory-embedder-reembed.d.ts +38 -0
- package/dist/memory-embedder-reembed.js +20 -0
- package/dist/memory-incident-sink.d.ts +0 -28
- package/dist/memory-incident-sink.js +5 -0
- package/dist/memory-operator-faces.d.ts +9 -4
- package/dist/memory-scope-stores.d.ts +9 -7
- package/dist/memory-scope-stores.js +3 -14
- package/dist/memory-scope.d.ts +38 -2
- package/dist/memory-scope.js +33 -2
- package/dist/memory-store-refusal.d.ts +17 -4
- package/dist/memory-store-refusal.js +1 -1
- package/dist/memory-sync-client.d.ts +2 -0
- package/dist/memory-sync-client.js +13 -11
- package/dist/memory-sync.js +1 -1
- package/dist/model-compat.d.ts +35 -21
- package/dist/model-compat.js +49 -21
- package/dist/model-entry-refusal.d.ts +11 -1
- package/dist/model-entry-refusal.js +7 -0
- package/dist/namespaced-rule-name.d.ts +18 -1
- package/dist/namespaced-rule-name.js +12 -0
- package/dist/net-address.d.ts +53 -0
- package/dist/net-address.js +111 -0
- package/dist/observability/fail-open.d.ts +29 -17
- package/dist/observability/fail-open.js +29 -17
- package/dist/observability/metrics.d.ts +2 -0
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/secret-env-scrub.d.ts +30 -4
- package/dist/observability/secret-env-scrub.js +15 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
- package/dist/orchestration/workflow-agent-session-index.js +1 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
- package/dist/orchestration/workflow-completion-inbox.js +63 -45
- package/dist/orchestration/workflow-notify-journal.js +2 -3
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +5 -2
- package/dist/org-memory-admission.js +25 -10
- package/dist/parked-decide.d.ts +33 -26
- package/dist/parked-decide.js +36 -44
- package/dist/peer-directory.d.ts +6 -12
- package/dist/peer-directory.js +5 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +37 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
- package/dist/plugins/approval-ask-store-memory.js +11 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -1
- package/dist/plugins/blob-backend.d.ts +38 -195
- package/dist/plugins/blob-backend.js +33 -229
- package/dist/plugins/caching-session-store.d.ts +12 -5
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
- package/dist/plugins/checkpoint-index-columns.js +3 -2
- package/dist/plugins/checkpoint-store-face.d.ts +426 -0
- package/dist/plugins/checkpoint-store-face.js +152 -0
- package/dist/plugins/device-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.js +5 -10
- package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
- package/dist/plugins/execution-lane-rename-m40.js +10 -0
- package/dist/plugins/execution-placement-sql.d.ts +63 -88
- package/dist/plugins/execution-placement-sql.js +94 -54
- package/dist/plugins/file-run-store.d.ts +26 -18
- package/dist/plugins/file-run-store.js +64 -75
- package/dist/plugins/fork-routing-session-store.d.ts +6 -2
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/imported-layer-root-retirement.d.ts +22 -11
- package/dist/plugins/imported-layer-root-retirement.js +4 -8
- package/dist/plugins/inbox-payload-column.d.ts +14 -0
- package/dist/plugins/inbox-payload-column.js +13 -0
- package/dist/plugins/local-checkpoint-store.d.ts +7 -2
- package/dist/plugins/local-checkpoint-store.js +13 -8
- package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
- package/dist/plugins/local-data-dir-modes-m39.js +182 -0
- package/dist/plugins/local-engine-high-water.d.ts +11 -0
- package/dist/plugins/local-engine-high-water.js +59 -0
- package/dist/plugins/local-session-store.d.ts +119 -30
- package/dist/plugins/local-session-store.js +156 -53
- package/dist/plugins/local-task-attachment-store.d.ts +2 -0
- package/dist/plugins/local-task-attachment-store.js +10 -11
- package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
- package/dist/plugins/memory-embedder-fingerprint.js +52 -12
- package/dist/plugins/memory-embedder.d.ts +1 -1
- package/dist/plugins/memory-embedder.js +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +30 -6
- package/dist/plugins/memory-engine-pg.js +96 -214
- package/dist/plugins/memory-engine-sql-apply.d.ts +130 -0
- package/dist/plugins/memory-engine-sql-apply.js +358 -0
- package/dist/plugins/memory-engine-tidb.d.ts +38 -9
- package/dist/plugins/memory-engine-tidb.js +99 -230
- package/dist/plugins/memory-key-guards.d.ts +1 -1
- package/dist/plugins/memory-origin-law.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +169 -83
- package/dist/plugins/one-time-migrations.js +295 -235
- package/dist/plugins/owner-only-file-mode.d.ts +29 -0
- package/dist/plugins/owner-only-file-mode.js +141 -0
- package/dist/plugins/permission-rule-store-file.d.ts +17 -3
- package/dist/plugins/permission-rule-store-file.js +20 -1
- package/dist/plugins/pg-pool.d.ts +2 -1
- package/dist/plugins/pg-pool.js +12 -5
- package/dist/plugins/release-version.d.ts +20 -0
- package/dist/plugins/release-version.js +28 -0
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +39 -11
- package/dist/plugins/remote-env-e2b.d.ts +12 -3
- package/dist/plugins/remote-env-e2b.js +6 -4
- package/dist/plugins/remote-env-host.d.ts +9 -1
- package/dist/plugins/remote-env-host.js +6 -5
- package/dist/plugins/remote-env-k8s.d.ts +5 -2
- package/dist/plugins/remote-env-k8s.js +15 -4
- package/dist/plugins/remote-env-local-docker.d.ts +4 -1
- package/dist/plugins/remote-env-local-docker.js +3 -3
- package/dist/plugins/remote-env-ssh.d.ts +8 -2
- package/dist/plugins/remote-env-ssh.js +26 -24
- package/dist/plugins/remote-shell.d.ts +59 -30
- package/dist/plugins/remote-shell.js +175 -62
- package/dist/plugins/retention-declaration.d.ts +37 -0
- package/dist/plugins/retention-declaration.js +9 -0
- package/dist/plugins/retention-deployment.d.ts +126 -0
- package/dist/plugins/retention-deployment.js +88 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
- package/dist/plugins/retention-lane-store-sql.js +103 -1
- package/dist/plugins/retention-sql.d.ts +29 -0
- package/dist/plugins/retention-sql.js +8 -0
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +0 -6
- package/dist/plugins/schema-consistency.js +1 -2
- package/dist/plugins/schema-ensure-legs.d.ts +1 -1
- package/dist/plugins/schema-ensure-legs.js +13 -3
- package/dist/plugins/session-ext-table.d.ts +74 -0
- package/dist/plugins/session-ext-table.js +121 -0
- package/dist/plugins/session-fork.d.ts +31 -9
- package/dist/plugins/session-fork.js +3 -2
- package/dist/plugins/session-placement.d.ts +4 -2
- package/dist/plugins/session-row-sql.d.ts +8 -7
- package/dist/plugins/session-row-sql.js +15 -7
- package/dist/plugins/session-store-sql.d.ts +131 -0
- package/dist/plugins/session-store-sql.js +298 -0
- package/dist/plugins/session-workspace-cell.d.ts +2 -2
- package/dist/plugins/session-workspace-cell.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
- package/dist/plugins/shared-memory-store-sql.js +13 -13
- package/dist/plugins/snapshot-bucket-presence.js +1 -1
- package/dist/plugins/sql-driver.d.ts +23 -7
- package/dist/plugins/sql-driver.js +41 -8
- package/dist/plugins/sql-errors.d.ts +5 -2
- package/dist/plugins/sql-errors.js +4 -0
- package/dist/plugins/sql-json-column.d.ts +5 -1
- package/dist/plugins/store-backend.d.ts +46 -16
- package/dist/plugins/store-backend.js +192 -69
- package/dist/plugins/store-contracts.d.ts +10 -13
- package/dist/plugins/store-contracts.js +1 -9
- package/dist/plugins/store-sweep.d.ts +63 -0
- package/dist/plugins/store-sweep.js +48 -0
- package/dist/plugins/task-attachment-store.d.ts +6 -8
- package/dist/plugins/task-attachment-store.js +15 -10
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/text-column-capacity.d.ts +21 -0
- package/dist/plugins/text-column-capacity.js +5 -0
- package/dist/plugins/tidb-pool.d.ts +3 -2
- package/dist/plugins/tidb-pool.js +20 -32
- package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
- package/dist/prompt-screen.d.ts +6 -9
- package/dist/prompt-screen.js +2 -5
- package/dist/read-face-posture.d.ts +6 -6
- package/dist/read-face-posture.js +2 -2
- package/dist/request-value-closure.d.ts +5 -5
- package/dist/request-value-closure.js +1 -1
- package/dist/rules-consent.d.ts +48 -27
- package/dist/rules-consent.js +147 -23
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/run-local.js +17 -13
- package/dist/runs.d.ts +48 -30
- package/dist/runs.js +27 -17
- package/dist/runtime-caps-resolver.d.ts +15 -8
- package/dist/runtime-caps-resolver.js +14 -10
- package/dist/sandbox-egress-policy.js +6 -11
- package/dist/sandbox-rbac-rules.d.ts +88 -0
- package/dist/sandbox-rbac-rules.js +80 -0
- package/dist/sealed-key-layout.d.ts +16 -0
- package/dist/sealed-key-layout.js +3 -0
- package/dist/sealed-key.js +8 -6
- package/dist/security.d.ts +43 -9
- package/dist/security.js +9 -2
- package/dist/sema-config-dir.js +2 -2
- package/dist/server-secret-env.d.ts +2 -0
- package/dist/service-version.d.ts +2 -1
- package/dist/service-version.js +2 -2
- package/dist/session-error-wire.d.ts +1 -1
- package/dist/session-incarnation.d.ts +8 -5
- package/dist/session-notify-door.d.ts +5 -3
- package/dist/session-resident-background.d.ts +110 -0
- package/dist/session-resident-background.js +88 -0
- package/dist/session-row.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +53 -14
- package/dist/session-sync-kernel.js +70 -1
- package/dist/session-sync.d.ts +5 -3
- package/dist/session-workspace.d.ts +12 -2
- package/dist/session-workspace.js +6 -0
- package/dist/sighup-idle.d.ts +9 -7
- package/dist/sighup-idle.js +4 -5
- package/dist/spec-fields.d.ts +16 -0
- package/dist/spec-fields.js +7 -0
- package/dist/store-posture.d.ts +2 -1
- package/dist/stored-request-env-credentials-m38.d.ts +3 -0
- package/dist/stored-request-env-credentials-m38.js +8 -0
- package/dist/stored-request-hooks-m20.d.ts +3 -2
- package/dist/stored-request-hooks-m20.js +19 -14
- package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
- package/dist/stores-sql/blob-index-sql.d.ts +148 -0
- package/dist/stores-sql/blob-index-sql.js +154 -0
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +14 -428
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +43 -220
- package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
- package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
- package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
- package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +27 -67
- package/dist/{plugins → stores-sql}/pg-session-storage.js +82 -207
- package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
- package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
- package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
- package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
- package/dist/stores-sql/session-write-hooks.d.ts +59 -0
- package/dist/stores-sql/session-write-hooks.js +2 -0
- package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
- package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
- package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +35 -112
- package/dist/{plugins → stores-sql}/tidb-session-store.js +73 -169
- package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +3 -3
- package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
- package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
- package/dist/stores-sql/windowed-session-storage.js +61 -0
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
- package/dist/task-a2a.d.ts +7 -1
- package/dist/task-a2a.js +15 -14
- package/dist/task-cwd.d.ts +11 -3
- package/dist/task-cwd.js +17 -1
- package/dist/task-mcp.d.ts +10 -2
- package/dist/task-mcp.js +13 -16
- package/dist/task-settings.d.ts +68 -8
- package/dist/task-settings.js +63 -6
- package/dist/tool-approval.d.ts +23 -10
- package/dist/tool-approval.js +10 -6
- package/dist/trace/core-keyset-guard.d.ts +17 -10
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +29 -1
- package/dist/trace/exit-seat.js +4 -0
- package/dist/trace/project.d.ts +33 -16
- package/dist/trace/project.js +21 -9
- package/dist/trace/redact.d.ts +13 -2
- package/dist/trace/redact.js +347 -78
- package/dist/trace/self-minted-wire.d.ts +587 -16
- package/dist/trace/self-minted-wire.js +215 -9
- package/dist/trace/sema-provenance.d.ts +45 -41
- package/dist/trace/sema-provenance.js +81 -10
- package/dist/trace/task-notification-facets.d.ts +70 -2
- package/dist/trace/task-notification-facets.js +71 -1
- package/dist/trace/wire-projection-faces.d.ts +39 -3
- package/dist/trace/wire-projection-faces.js +27 -2
- package/dist/unread-request-members.d.ts +66 -0
- package/dist/unread-request-members.js +41 -0
- package/dist/usage-analytics.d.ts +4 -0
- package/dist/user-input-ledger.d.ts +2 -2
- package/dist/web-admin-client/apply-effective.js +22 -26
- package/dist/web-admin-client/candidate-gate.d.ts +35 -3
- package/dist/web-admin-client/candidate-gate.js +53 -5
- package/dist/web-admin-client/center-request.d.ts +4 -1
- package/dist/web-admin-client/center-request.js +2 -1
- package/dist/web-admin-client/effective-keys.js +0 -1
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/http-client.d.ts +1 -0
- package/dist/web-admin-client/http-client.js +17 -9
- package/dist/web-admin-client/restart-signal.js +5 -2
- package/dist/web-admin-client/skills-mcp.d.ts +20 -6
- package/dist/web-admin-client/skills-mcp.js +26 -21
- package/dist/web-admin-client/types.d.ts +34 -49
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
- package/package.json +22 -13
- package/scripts/drain-check-local.mjs +8 -55
- package/scripts/drain-check.mysql.sql +3 -40
- package/scripts/drain-check.pg.sql +3 -40
- package/skills/update-config.md +1 -1
- package/wire-changes/server@7.146.0.json +3221 -0
- package/wire-changes/server@7.147.0.json +813 -0
- package/dist/approval-batch-census.d.ts +0 -27
- package/dist/approval-batch-census.js +0 -27
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { PG_MEMORY_ENGINE_TABLES } from "./memory-engine-pg.js";
|
|
3
3
|
import { createZodColumnReader, decodeJsonColumn, jsonColumnText, SqlJsonColumnError } from "./sql-json-column.js";
|
|
4
4
|
import { echoCallerText } from "../caller-text-echo.js";
|
|
5
|
+
import { MEMORY_EMBEDDER_REEMBED_ENV, formatEmbedderIdentityToken, formatReembedAssignment } from "../memory-embedder-reembed.js";
|
|
5
6
|
export const PG_MEMORY_ENGINE_META_TABLE = "agent_memory_engine_meta";
|
|
6
7
|
export const EMBEDDER_IDENTITY_META_KEY = "embedder_identity";
|
|
7
8
|
export const CAS_MAX_ROUNDS = 3;
|
|
@@ -18,12 +19,12 @@ export async function ensurePgMemoryEmbedderMetaSchema(query) {
|
|
|
18
19
|
const readEmbedderIdentityColumn = createZodColumnReader(EmbedderIdentitySchema);
|
|
19
20
|
function parseStoredText(text) {
|
|
20
21
|
try {
|
|
21
|
-
return { kind: "ok", value: decodeJsonColumn(text, readEmbedderIdentityColumn, `${PG_MEMORY_ENGINE_META_TABLE}.meta_value for key ${EMBEDDER_IDENTITY_META_KEY}`) };
|
|
22
|
+
return { kind: "ok", value: decodeJsonColumn(text, readEmbedderIdentityColumn, `${PG_MEMORY_ENGINE_META_TABLE}.meta_value for key ${EMBEDDER_IDENTITY_META_KEY}`), text };
|
|
22
23
|
}
|
|
23
24
|
catch (err) {
|
|
24
25
|
if (!(err instanceof SqlJsonColumnError))
|
|
25
26
|
throw err;
|
|
26
|
-
return { kind: "unreadable", raw: `${echoCallerText(text, { maxChars: 160 })} [${err.problem}: ${echoCallerText(err.message, { maxChars: 120 })}]
|
|
27
|
+
return { kind: "unreadable", raw: `${echoCallerText(text, { maxChars: 160 })} [${err.problem}: ${echoCallerText(err.message, { maxChars: 120 })}]`, text };
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
async function readStored(query) {
|
|
@@ -32,8 +33,9 @@ async function readStored(query) {
|
|
|
32
33
|
if (row === undefined)
|
|
33
34
|
return { kind: "absent" };
|
|
34
35
|
const text = row.meta_value;
|
|
35
|
-
if (typeof text !== "string")
|
|
36
|
-
|
|
36
|
+
if (typeof text !== "string") {
|
|
37
|
+
throw new Error(`reconcileEmbedderFingerprint: ${PG_MEMORY_ENGINE_META_TABLE}.meta_value::text did not return text (${typeof text}) — the read leg is broken; refusing to start`);
|
|
38
|
+
}
|
|
37
39
|
return parseStoredText(text);
|
|
38
40
|
}
|
|
39
41
|
async function hasUnattributedVectors(query) {
|
|
@@ -45,16 +47,51 @@ async function clearEmbeddings(query) {
|
|
|
45
47
|
SELECT count(*)::int AS n FROM c`);
|
|
46
48
|
return Number(r.rows[0]?.n ?? 0);
|
|
47
49
|
}
|
|
48
|
-
async function writeIdentity(query, identity) {
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
async function writeIdentity(query, identity, judged) {
|
|
51
|
+
if (judged.kind === "absent") {
|
|
52
|
+
await query(`INSERT INTO ${PG_MEMORY_ENGINE_META_TABLE} (meta_key, meta_value) VALUES ($1, $2::jsonb)
|
|
53
|
+
ON CONFLICT (meta_key) DO NOTHING`, [EMBEDDER_IDENTITY_META_KEY, JSON.stringify(identity)]);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await query(`UPDATE ${PG_MEMORY_ENGINE_META_TABLE} SET meta_value = $2::jsonb WHERE meta_key = $1 AND meta_value::text = $3`, [
|
|
57
|
+
EMBEDDER_IDENTITY_META_KEY,
|
|
58
|
+
JSON.stringify(identity),
|
|
59
|
+
judged.text,
|
|
60
|
+
]);
|
|
51
61
|
}
|
|
52
62
|
function sameIdentity(a, b) {
|
|
53
63
|
return a.model === b.model && a.dimensions === b.dimensions;
|
|
54
64
|
}
|
|
55
65
|
const SCALE_ZERO_NOTE = "change the embedder identity with the fleet stopped (scale to 0, then start): during a ROLLING window the old replicas keep writing vectors in the OLD space after this gate cleared the column";
|
|
66
|
+
export function buildEmbedderIdentityRefusal(state, recorded, want) {
|
|
67
|
+
const configured = formatEmbedderIdentityToken(want);
|
|
68
|
+
let what;
|
|
69
|
+
switch (state) {
|
|
70
|
+
case "changed":
|
|
71
|
+
what = `${PG_MEMORY_ENGINE_META_TABLE} records the embedder identity ${recorded !== null && "model" in recorded ? formatEmbedderIdentityToken(recorded) : "(none)"} but the configured embedder is ${configured}`;
|
|
72
|
+
break;
|
|
73
|
+
case "unattributed":
|
|
74
|
+
what = `${PG_MEMORY_ENGINE_META_TABLE} records no embedder identity while ${PG_MEMORY_ENGINE_TABLES.entry}.embedding holds vectors — their origin cannot be proven to be the configured embedder ${configured}`;
|
|
75
|
+
break;
|
|
76
|
+
case "unreadable":
|
|
77
|
+
what = `the embedder identity recorded in ${PG_MEMORY_ENGINE_META_TABLE} cannot be read (${recorded !== null && "unreadable" in recorded ? recorded.unreadable : "unreadable"}), so the vectors cannot be proven to come from the configured embedder ${configured}`;
|
|
78
|
+
break;
|
|
79
|
+
default: {
|
|
80
|
+
const unknown = state;
|
|
81
|
+
throw new Error(`unknown embedder mismatch state ${JSON.stringify(unknown)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return (`memory embedder identity mismatch (state: ${state}) — refusing to start: ${what}. ` +
|
|
85
|
+
`The gate refuses on each of three states (changed: the recorded identity differs; unattributed: no recorded identity while vectors exist; unreadable: the recorded identity cannot be read) ` +
|
|
86
|
+
`and never clears the vector column on its own — clearing is irreversible (rows re-embed only when next written), refusing is not. Ways out: ` +
|
|
87
|
+
(state === "changed" ? "configure the recorded identity again (MEMORY_EMBEDDER_MODEL / MEMORY_EMBEDDER_DIM); or " : "") +
|
|
88
|
+
`confirm the re-embed — set ${formatReembedAssignment(want)} and restart with the fleet stopped (scale to 0): the column is cleared once and ${configured} recorded, after which the confirmation is inert; ` +
|
|
89
|
+
"or unset MEMORY_EMBEDDER_* to start on the lexical floor with the stored vectors left untouched.");
|
|
90
|
+
}
|
|
91
|
+
const CONFIRMED_NOTE = `re-embed confirmed by ${MEMORY_EMBEDDER_REEMBED_ENV} (inert from now on: this identity is recorded, so the next boot matches)`;
|
|
56
92
|
export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
|
|
57
93
|
const { log } = opts;
|
|
94
|
+
const confirmed = opts.reembedConfirmed === true;
|
|
58
95
|
const now = opts.now ?? Date.now;
|
|
59
96
|
const want = EmbedderIdentitySchema.parse(identity);
|
|
60
97
|
const firstStartedAt = now();
|
|
@@ -71,7 +108,7 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
|
|
|
71
108
|
reason: firstClear?.reason ?? firstChange?.reason ?? terminalState,
|
|
72
109
|
rounds,
|
|
73
110
|
elapsedMs,
|
|
74
|
-
note: `${SCALE_ZERO_NOTE}; cleared vectors are NOT backfilled — rows re-embed only as they are next written, and until then each cleared row is reachable ONLY by a query sharing a literal term with it (the lexical floor drops a row with zero term overlap, whereas a row that still has a vector is scored by cosine as long as the query embeds too) — rewrite the corpus to restore vector reach immediately`,
|
|
111
|
+
note: `${CONFIRMED_NOTE}; ${SCALE_ZERO_NOTE}; cleared vectors are NOT backfilled — rows re-embed only as they are next written, and until then each cleared row is reachable ONLY by a query sharing a literal term with it (the lexical floor drops a row with zero term overlap, whereas a row that still has a vector is scored by cosine as long as the query embeds too) — rewrite the corpus to restore vector reach immediately`,
|
|
75
112
|
});
|
|
76
113
|
return;
|
|
77
114
|
}
|
|
@@ -83,7 +120,7 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
|
|
|
83
120
|
reason: firstChange.reason,
|
|
84
121
|
rounds,
|
|
85
122
|
elapsedMs,
|
|
86
|
-
note: `${SCALE_ZERO_NOTE}; no vectors existed to clear on this boot — the identity itself changed, which is the event`,
|
|
123
|
+
note: `${CONFIRMED_NOTE}; ${SCALE_ZERO_NOTE}; no vectors existed to clear on this boot — the identity itself changed, which is the event`,
|
|
87
124
|
});
|
|
88
125
|
return;
|
|
89
126
|
}
|
|
@@ -114,15 +151,18 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
|
|
|
114
151
|
else {
|
|
115
152
|
state = (await hasUnattributedVectors(query)) ? "unattributed" : "armed";
|
|
116
153
|
}
|
|
154
|
+
const recorded = previous ?? (stored.kind === "unreadable" ? { unreadable: stored.raw } : null);
|
|
155
|
+
if (state !== "armed" && !confirmed)
|
|
156
|
+
throw new Error(buildEmbedderIdentityRefusal(state, recorded, want));
|
|
117
157
|
if (state !== "armed" && firstChange === undefined) {
|
|
118
|
-
firstChange = { reason: state, previous:
|
|
158
|
+
firstChange = { reason: state, previous: recorded };
|
|
119
159
|
}
|
|
120
160
|
const cleared = state === "armed" ? 0 : await clearEmbeddings(query);
|
|
121
161
|
if (cleared > 0 && firstClear === undefined) {
|
|
122
|
-
firstClear = { reason: state, previous:
|
|
162
|
+
firstClear = { reason: state, previous: recorded };
|
|
123
163
|
}
|
|
124
164
|
clearedTotal += cleared;
|
|
125
|
-
await writeIdentity(query, want);
|
|
165
|
+
await writeIdentity(query, want, stored);
|
|
126
166
|
const after = await readStored(query);
|
|
127
167
|
if (after.kind === "ok" && sameIdentity(after.value, want)) {
|
|
128
168
|
emitOutcome(state, round);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { MemoryEmbedderConfig } from "../config-types.js";
|
|
2
2
|
import type { PgEmbedder } from "./pg-query.js";
|
|
3
3
|
/** 工厂入参 = 配置坐标(单一属主 `config-types.ts`)+ 部署腿(观测/注入)。 */
|
|
4
|
-
export interface OpenAiCompatEmbedderOptions extends MemoryEmbedderConfig {
|
|
4
|
+
export interface OpenAiCompatEmbedderOptions extends Omit<MemoryEmbedderConfig, "reembedConfirmed"> {
|
|
5
5
|
/** 注入 fetch(测试/代理场景);缺省全局 `fetch`。 */
|
|
6
6
|
fetchImpl?: typeof fetch;
|
|
7
7
|
/**
|
|
@@ -94,9 +94,9 @@ export function createOpenAiCompatEmbedder(opts) {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
export function memoryEmbedderFor(config, deps = {}) {
|
|
97
|
-
|
|
98
|
-
if (cfg === undefined)
|
|
97
|
+
if (config.memoryEmbedder === undefined)
|
|
99
98
|
return undefined;
|
|
99
|
+
const { reembedConfirmed: _confirmation, ...cfg } = config.memoryEmbedder;
|
|
100
100
|
return createOpenAiCompatEmbedder({
|
|
101
101
|
...cfg,
|
|
102
102
|
...(deps.fetchImpl !== undefined ? { fetchImpl: deps.fetchImpl } : {}),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MemoryHistoryAppendRow } from "./memory-sync-store-pg.js";
|
|
2
2
|
import type { PgEmbedder, PgQueryFn } from "./pg-query.js";
|
|
3
|
+
import { type SqlApplyOpts } from "./memory-engine-sql-apply.js";
|
|
3
4
|
import type { MemoryBackend, MemoryEntry, MemoryEntryHeader, NotePatch, PatchReport, ScoredMemoryEntry } from "@sema-agent/core";
|
|
4
5
|
import { type IndexSpec } from "./ensure-index.js";
|
|
5
6
|
/** Table names (single source). Deliberately DISJOINT from the legacy `agent_memory*` tables —
|
|
@@ -54,6 +55,8 @@ export declare class PgMemoryEngineBackend implements MemoryBackend {
|
|
|
54
55
|
private readonly history?;
|
|
55
56
|
/** Cumulative lost-row count — audit-line breakage must itself be auditable. */
|
|
56
57
|
private historyRowsLost;
|
|
58
|
+
/** 交给共享驱动器的读口 / 写口 / history 冲刷(构造末尾铸一次)。 */
|
|
59
|
+
private readonly leg;
|
|
57
60
|
/** [ref] rung indicator — same semantics as PgMemoryStore.vectorMode. */
|
|
58
61
|
get vectorMode(): "native" | "portable" | "lexical";
|
|
59
62
|
constructor(query: PgQueryFn, opts?: PgMemoryEngineBackendOptions);
|
|
@@ -70,12 +73,33 @@ export declare class PgMemoryEngineBackend implements MemoryBackend {
|
|
|
70
73
|
limit?: number;
|
|
71
74
|
exposureBands?: boolean;
|
|
72
75
|
}): Promise<ScoredMemoryEntry[]>;
|
|
73
|
-
applyPatches(
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
*
|
|
77
|
-
|
|
78
|
-
private
|
|
76
|
+
/** core 落点问询协议的能力位:`applyPatches` 兑现 `opts.admit` / `opts.confirm`(读法见 `memory-engine-sql-apply.ts` 头注)。 */
|
|
77
|
+
readonly admitsLandings: true;
|
|
78
|
+
/** 判与驱动器只在 `memory-engine-sql-apply.ts` 一处(两只 SQL 腿共用);本腿只供读口、PG 方言写口(写语句绑定计划的投影)与 history 冲刷。
|
|
79
|
+
* `opts.anchoredRoot` 是带目录的后端的事,本腿没有目录 ⇒ 不读(core 契约原文:a backend without a directory ignores it)。 */
|
|
80
|
+
applyPatches(patches: readonly NotePatch[], opts?: SqlApplyOpts): Promise<PatchReport>;
|
|
81
|
+
private rowOf;
|
|
82
|
+
private idsAt;
|
|
83
|
+
/** 一个 patch 第一次要写之前算一次它的向量参数(撞名 / 被挪重试复用,不重调 embedder —— 改前 add 也只在后缀循环外算一次)。
|
|
84
|
+
* haystack 用调用方给的原形(add 的原名,不是撞名后缀),与改前同。 */
|
|
85
|
+
private prepareWrite;
|
|
86
|
+
/** 写不落之后的现读:这个 id 的行此刻的 rev 与投影(没了 ⇒ undefined)。 */
|
|
87
|
+
private freshRow;
|
|
88
|
+
/**
|
|
89
|
+
* add:`INSERT … ON CONFLICT (id)`,冲突靶 = 仅主键。计划时这个 id 已有行 ⇒ `DO UPDATE … WHERE` 行仍在计划的投影上(同 scope re-add 的
|
|
90
|
+
* 幂等覆盖;行被挪走就不覆盖 —— 被挪去的那个拼写没问过),add-if-absent 再绑计划读到的 rev(行被改写就不覆盖 —— 它判的是那一份内容);
|
|
91
|
+
* 计划时没有 ⇒ `DO NOTHING`(同 id 的行在判与写之间被别的副本插入就不覆盖)。两种「不覆盖」都让 `RETURNING` 交零行 ⇒ 现读确认后答
|
|
92
|
+
* `moved`(驱动器按现状重判)。剩下能撞的唯一键只有 `(scope, slug)` ⇒ `slug-taken`。
|
|
93
|
+
*/
|
|
94
|
+
private writeAdd;
|
|
95
|
+
/** update:条件 = 判过的 rev **且**判过的投影(rev 是内容哈希、不含 scope / slug)。零行 ⇒ 现读:内容未变而投影变了 = `moved`;其余 =
|
|
96
|
+
* CAS 冲突,currentRev 报现值(行没了 ⇒ 判时的值)。 */
|
|
97
|
+
private writeUpdate;
|
|
98
|
+
/** delete:条件同 update。 */
|
|
99
|
+
private writeDelete;
|
|
100
|
+
/** BEST-EFFORT history append(见 PgMemoryEngineBackendOptions.history 的如实取舍):entry 写已提交,审计行追加失败不许让报告失败 ——
|
|
101
|
+
* 吞 + warn,永不抛;appendHistory 按 (id, rev) 幂等,调用方重试安全。 */
|
|
102
|
+
private appendHistory;
|
|
79
103
|
getConsolidationCursor(scope: string): Promise<string | undefined>;
|
|
80
104
|
setConsolidationCursor(scope: string, cursor: string): Promise<void>;
|
|
81
105
|
}
|
|
@@ -2,10 +2,11 @@ import { cosineDistance, jaccardDistance, termSet } from "@sema-agent/core";
|
|
|
2
2
|
import { isUniqueViolation, readEmbeddingColumn, readFrontmatterColumn } from "./memory-engine-vector-util.js";
|
|
3
3
|
import { decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "./sql-json-column.js";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
|
-
import {
|
|
6
|
-
import { pgSafeJsonStringify
|
|
7
|
-
import { assertMemoryScopeWidth
|
|
8
|
-
import {
|
|
5
|
+
import { serializeEntryFile } from "@sema-agent/core";
|
|
6
|
+
import { pgSafeJsonStringify } from "./pg-safe-json.js";
|
|
7
|
+
import { assertMemoryScopeWidth } from "./memory-key-guards.js";
|
|
8
|
+
import { exposureBandOf, exposureCarriage, originMarkedSqlPredicate, distilledCarriage } from "./memory-origin-law.js";
|
|
9
|
+
import { applySqlPatches, } from "./memory-engine-sql-apply.js";
|
|
9
10
|
import { ensureIndexes } from "./ensure-index.js";
|
|
10
11
|
export const PG_MEMORY_ENGINE_TABLES = {
|
|
11
12
|
entry: "agent_memory_engine_entry",
|
|
@@ -72,6 +73,7 @@ export class PgMemoryEngineBackend {
|
|
|
72
73
|
clock;
|
|
73
74
|
history;
|
|
74
75
|
historyRowsLost = 0;
|
|
76
|
+
leg;
|
|
75
77
|
get vectorMode() {
|
|
76
78
|
return this.pgvectorSql ? "native" : this.embedder ? "portable" : "lexical";
|
|
77
79
|
}
|
|
@@ -83,6 +85,18 @@ export class PgMemoryEngineBackend {
|
|
|
83
85
|
this.history = opts.history;
|
|
84
86
|
if (this.pgvectorSql && !this.embedder)
|
|
85
87
|
throw new Error("PgMemoryEngineBackend: pgvectorSql requires an embedder");
|
|
88
|
+
this.leg = {
|
|
89
|
+
reads: { rowOf: (id) => this.rowOf(id), idsAt: (scope, slug) => this.idsAt(scope, slug) },
|
|
90
|
+
writes: {
|
|
91
|
+
prepare: (entry) => this.prepareWrite(entry),
|
|
92
|
+
add: (w, embedding, confirm) => this.writeAdd(w, embedding, confirm),
|
|
93
|
+
update: (w, embedding, confirm) => this.writeUpdate(w, embedding, confirm),
|
|
94
|
+
remove: (w, confirm) => this.writeDelete(w, confirm),
|
|
95
|
+
},
|
|
96
|
+
unstorableReason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)",
|
|
97
|
+
now: () => this.clock(),
|
|
98
|
+
...(this.history !== undefined ? { appendHistory: (rows) => this.appendHistory(rows) } : {}),
|
|
99
|
+
};
|
|
86
100
|
}
|
|
87
101
|
haystackOf(slug, fm, body) {
|
|
88
102
|
return `${fm.name ?? slug} ${fm.description ?? ""} ${body}`;
|
|
@@ -181,224 +195,92 @@ export class PgMemoryEngineBackend {
|
|
|
181
195
|
scored.sort(contractOrder);
|
|
182
196
|
return scored.slice(0, limit);
|
|
183
197
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
catch (err) {
|
|
202
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (this.history && historyRows.length > 0) {
|
|
206
|
-
try {
|
|
207
|
-
await this.history.appendHistory(historyRows);
|
|
208
|
-
}
|
|
209
|
-
catch (err) {
|
|
210
|
-
this.historyRowsLost += historyRows.length;
|
|
211
|
-
console.warn(`PgMemoryEngineBackend: best-effort history append failed (${historyRows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return report;
|
|
198
|
+
admitsLandings = true;
|
|
199
|
+
async applyPatches(patches, opts) {
|
|
200
|
+
return applySqlPatches(patches, opts, this.leg);
|
|
201
|
+
}
|
|
202
|
+
async rowOf(id) {
|
|
203
|
+
const res = await this.query(`SELECT slug, rev, scope, ${jsonColumnText("pg", "frontmatter")} FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
|
|
204
|
+
const r = res.rows[0];
|
|
205
|
+
if (r === undefined)
|
|
206
|
+
return undefined;
|
|
207
|
+
return { scope: String(r.scope), slug: String(r.slug), rev: String(r.rev), frontmatter: readFrontmatter(r.frontmatter, id) };
|
|
208
|
+
}
|
|
209
|
+
async idsAt(scope, slug) {
|
|
210
|
+
const res = await this.query(`SELECT id FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE scope = $1 AND slug = $2`, [scope, slug]);
|
|
211
|
+
return res.rows.map((r) => String(r.id));
|
|
212
|
+
}
|
|
213
|
+
prepareWrite(entry) {
|
|
214
|
+
return this.embeddingParam(this.haystackOf(entry.slug, entry.frontmatter, entry.body));
|
|
215
215
|
}
|
|
216
|
-
async
|
|
216
|
+
async freshRow(id) {
|
|
217
|
+
const res = await this.query(`SELECT rev, scope, slug FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
|
|
218
|
+
const r = res.rows[0];
|
|
219
|
+
return r === undefined ? undefined : { rev: String(r.rev), scope: String(r.scope), slug: String(r.slug) };
|
|
220
|
+
}
|
|
221
|
+
async writeAdd({ stored, rev, prior }, embedding, confirm) {
|
|
217
222
|
const T = PG_MEMORY_ENGINE_TABLES.entry;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
const params = [stored.id, stored.scope, stored.slug, pgSafeJsonStringify(stored.frontmatter), stored.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(stored), "utf8"), embedding];
|
|
224
|
+
const onConflict = prior !== undefined
|
|
225
|
+
? `ON CONFLICT (id) DO UPDATE SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9 WHERE ${T}.scope = $10 AND ${T}.slug = $11${prior.rev !== undefined ? ` AND ${T}.rev = $12` : ""}`
|
|
226
|
+
: "ON CONFLICT (id) DO NOTHING";
|
|
227
|
+
if (prior !== undefined)
|
|
228
|
+
params.push(prior.scope, prior.slug, ...(prior.rev !== undefined ? [prior.rev] : []));
|
|
229
|
+
confirm();
|
|
230
|
+
let landed;
|
|
231
|
+
try {
|
|
232
|
+
const res = await this.query(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding)
|
|
233
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
234
|
+
${onConflict}
|
|
235
|
+
RETURNING id`, params);
|
|
236
|
+
landed = res.rows.length > 0;
|
|
224
237
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
238
|
+
catch (err) {
|
|
239
|
+
if (isUniqueViolation(err))
|
|
240
|
+
return { kind: "slug-taken" };
|
|
241
|
+
throw err;
|
|
228
242
|
}
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (patch.op === "add") {
|
|
244
|
-
const rawEntry = patch.entry;
|
|
245
|
-
if (!rawEntry) {
|
|
246
|
-
report.conflicts.push({ op: "add", id: patch.id, reason: "add patch without an entry" });
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (pgHasUnstorable(rawEntry.frontmatter) || pgHasUnstorable(rawEntry.body) || pgHasUnstorable(rawEntry.slug)) {
|
|
250
|
-
report.conflicts.push({ op: "add", id: rawEntry.id, reason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)" });
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
const entry = rawEntry;
|
|
254
|
-
const prior = await this.query(`SELECT scope, slug, rev, ${jsonColumnText("pg", "frontmatter")} FROM ${T} WHERE id = $1`, [entry.id]);
|
|
255
|
-
const priorRow = prior.rows.length > 0 ? prior.rows[0] : undefined;
|
|
256
|
-
{
|
|
257
|
-
const committedBaseFm = rememberBatchCommitted(originBaseline, entry.id, priorRow !== undefined ? readFrontmatter(priorRow.frontmatter, entry.id) : undefined);
|
|
258
|
-
const refusal = originWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
|
|
259
|
-
if (refusal !== undefined) {
|
|
260
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: refusal });
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const dRefusal = distilledWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
|
|
264
|
-
if (dRefusal !== undefined) {
|
|
265
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: dRefusal });
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if (patch.guard === "absent" && priorRow) {
|
|
270
|
-
const currentRev = String(priorRow.rev);
|
|
271
|
-
if (currentRev !== computeEntryRev(entry)) {
|
|
272
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev });
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
if (String(priorRow.scope) !== entry.scope || String(priorRow.slug) !== entry.slug) {
|
|
276
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${String(priorRow.scope)}/${String(priorRow.slug)}`)}; add-if-absent refuses to duplicate)`, currentRev });
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (priorRow) {
|
|
281
|
-
const held = String(priorRow.scope);
|
|
282
|
-
if (held !== entry.scope) {
|
|
283
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `id already exists in scope ${JSON.stringify(held)} (cross-scope add refused)` });
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
const cEntry = entry;
|
|
288
|
-
const embedding = await this.embeddingParam(this.haystackOf(cEntry.slug, cEntry.frontmatter, cEntry.body));
|
|
289
|
-
let slug = cEntry.slug;
|
|
290
|
-
for (let n = 2;; n++) {
|
|
291
|
-
const derivedRefusal = memoryEntryKeyWidthRefusal(entry.scope, slug);
|
|
292
|
-
if (derivedRefusal !== undefined) {
|
|
293
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `${derivedRefusal} (slug collision suffix "-${n - 1}" no longer fits the column — shorten the entry name)` });
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const key = `${entry.scope}|${slug}`;
|
|
297
|
-
if (!plannedSlugs.has(key)) {
|
|
298
|
-
const taken = await this.query(`SELECT id FROM ${T} WHERE scope = $1 AND slug = $2`, [entry.scope, slug]);
|
|
299
|
-
const otherId = taken.rows.find((r) => String(r.id) !== entry.id);
|
|
300
|
-
if (!otherId) {
|
|
301
|
-
const stored = { ...cEntry, slug };
|
|
302
|
-
const rev = computeEntryRev(stored);
|
|
303
|
-
try {
|
|
304
|
-
await this.query(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding)
|
|
305
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
306
|
-
ON CONFLICT (id) DO UPDATE SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9`, [stored.id, stored.scope, stored.slug, pgSafeJsonStringify(stored.frontmatter), stored.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(stored), "utf8"), embedding]);
|
|
307
|
-
}
|
|
308
|
-
catch (err) {
|
|
309
|
-
if (isUniqueViolation(err)) {
|
|
310
|
-
slug = `${entry.slug}-${n}`;
|
|
311
|
-
continue;
|
|
312
|
-
}
|
|
313
|
-
throw err;
|
|
314
|
-
}
|
|
315
|
-
plannedSlugs.add(key);
|
|
316
|
-
report.applied.push({ op: "add", id: stored.id, slug: stored.slug });
|
|
317
|
-
if (this.history)
|
|
318
|
-
historyRows.push({ id: stored.id, rev, op: "add", scope: stored.scope, snapshot: { ...stored, rev }, writtenAtMs: this.clock() });
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
slug = `${entry.slug}-${n}`;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
const cur = await this.query(`SELECT slug, rev, scope, ${jsonColumnText("pg", "frontmatter")} FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [patch.id]);
|
|
326
|
-
if (cur.rows.length === 0) {
|
|
327
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const currentRev = String(cur.rows[0].rev);
|
|
331
|
-
const currentSlug = String(cur.rows[0].slug);
|
|
332
|
-
const currentScope = String(cur.rows[0].scope);
|
|
333
|
-
const committedFm = readFrontmatter(cur.rows[0].frontmatter, patch.id);
|
|
334
|
-
const committedBaseFm = rememberBatchCommitted(originBaseline, patch.id, committedFm);
|
|
335
|
-
if (patch.op === "update" && patch.entry !== undefined) {
|
|
336
|
-
if (committedFm.provenance?.kind === "repo_file") {
|
|
337
|
-
const next = patch.entry.frontmatter;
|
|
338
|
-
const stripsProvenance = next.provenance === undefined;
|
|
339
|
-
const stripsTrust = committedFm.trust !== undefined && next.trust === undefined;
|
|
340
|
-
if (stripsProvenance || stripsTrust) {
|
|
341
|
-
report.conflicts.push({
|
|
342
|
-
op: "update",
|
|
343
|
-
id: patch.id,
|
|
344
|
-
reason: `repo_file provenance whitewash refused: update drops ${stripsProvenance ? "provenance" : "trust"} from a repo-ingested entry (malformed patch refused)`,
|
|
345
|
-
});
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
const refusal = originWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
|
|
350
|
-
if (refusal !== undefined) {
|
|
351
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: refusal });
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
const dRefusal = distilledWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
|
|
355
|
-
if (dRefusal !== undefined) {
|
|
356
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: dRefusal });
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
|
|
361
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev });
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
if (patch.op === "delete") {
|
|
365
|
-
const res = await this.query(`DELETE FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1 AND rev = $2 RETURNING id`, [patch.id, currentRev]);
|
|
366
|
-
if (res.rows.length === 0) {
|
|
367
|
-
report.conflicts.push({ op: "delete", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: await this.freshRev(patch.id, currentRev) });
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
report.applied.push({ op: "delete", id: patch.id, slug: currentSlug });
|
|
371
|
-
if (this.history)
|
|
372
|
-
historyRows.push({ id: patch.id, rev: `tombstone:${currentRev}`, prevRev: currentRev, op: "delete", scope: currentScope, writtenAtMs: this.clock() });
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
const entry = patch.entry;
|
|
376
|
-
if (!entry) {
|
|
377
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: "update patch without an entry" });
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
|
|
381
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)" });
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
const cEntry = entry;
|
|
385
|
-
const rev = computeEntryRev(cEntry);
|
|
386
|
-
const embedding = await this.embeddingParam(this.haystackOf(cEntry.slug, cEntry.frontmatter, cEntry.body));
|
|
243
|
+
if (landed)
|
|
244
|
+
return { kind: "committed" };
|
|
245
|
+
const fresh = await this.freshRow(stored.id);
|
|
246
|
+
if (fresh !== undefined && (prior === undefined || fresh.scope !== prior.scope || fresh.slug !== prior.slug || (prior.rev !== undefined && fresh.rev !== prior.rev)))
|
|
247
|
+
return { kind: "moved" };
|
|
248
|
+
throw new Error(`memory-engine: the add of ${JSON.stringify(stored.id)} wrote no row, yet the row is ${fresh === undefined ? "absent" : "still where the write condition holds"} — refusing to report it either way`);
|
|
249
|
+
}
|
|
250
|
+
async writeUpdate({ entry, rev, currentRev, current, baseRev }, embedding, confirm) {
|
|
251
|
+
const params = [entry.id, entry.scope, entry.slug, pgSafeJsonStringify(entry.frontmatter), entry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(entry), "utf8"), embedding, currentRev, current.scope, current.slug];
|
|
252
|
+
confirm();
|
|
387
253
|
const res = await this.query(`UPDATE ${PG_MEMORY_ENGINE_TABLES.entry}
|
|
388
254
|
SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9
|
|
389
|
-
WHERE id = $1 AND rev = $10
|
|
390
|
-
RETURNING id`,
|
|
391
|
-
if (res.rows.length
|
|
392
|
-
|
|
255
|
+
WHERE id = $1 AND rev = $10 AND scope = $11 AND slug = $12
|
|
256
|
+
RETURNING id`, params);
|
|
257
|
+
if (res.rows.length > 0)
|
|
258
|
+
return { kind: "committed" };
|
|
259
|
+
const fresh = await this.freshRow(entry.id);
|
|
260
|
+
if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
|
|
261
|
+
return { kind: "moved" };
|
|
262
|
+
return { kind: "lost", conflict: { op: "update", id: entry.id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
|
|
263
|
+
}
|
|
264
|
+
async writeDelete({ id, currentRev, current, baseRev }, confirm) {
|
|
265
|
+
confirm();
|
|
266
|
+
const res = await this.query(`DELETE FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1 AND rev = $2 AND scope = $3 AND slug = $4 RETURNING id`, [id, currentRev, current.scope, current.slug]);
|
|
267
|
+
if (res.rows.length > 0)
|
|
268
|
+
return { kind: "committed" };
|
|
269
|
+
const fresh = await this.freshRow(id);
|
|
270
|
+
if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
|
|
271
|
+
return { kind: "moved" };
|
|
272
|
+
return { kind: "lost", conflict: { op: "delete", id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
|
|
273
|
+
}
|
|
274
|
+
async appendHistory(rows) {
|
|
275
|
+
if (!this.history)
|
|
393
276
|
return;
|
|
277
|
+
try {
|
|
278
|
+
await this.history.appendHistory(rows);
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
this.historyRowsLost += rows.length;
|
|
282
|
+
console.warn(`PgMemoryEngineBackend: best-effort history append failed (${rows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
|
|
394
283
|
}
|
|
395
|
-
report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
|
|
396
|
-
if (this.history)
|
|
397
|
-
historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
|
|
398
|
-
}
|
|
399
|
-
async freshRev(id, fallback) {
|
|
400
|
-
const res = await this.query(`SELECT rev FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
|
|
401
|
-
return res.rows.length > 0 ? String(res.rows[0].rev) : fallback;
|
|
402
284
|
}
|
|
403
285
|
async getConsolidationCursor(scope) {
|
|
404
286
|
const res = await this.query(`SELECT cursor FROM ${PG_MEMORY_ENGINE_TABLES.cursor} WHERE scope = $1`, [scope]);
|