@sema-agent/server 7.141.0 → 7.143.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 +657 -0
- package/USAGE.md +102 -30
- package/dist/adoption/plan.js +22 -0
- package/dist/approval-ask-audit-store.d.ts +61 -43
- package/dist/approval-ask-audit-store.js +69 -44
- package/dist/approval-ask-machine.d.ts +15 -7
- package/dist/approval-ask-machine.js +10 -4
- package/dist/approval-card.d.ts +126 -27
- package/dist/approval-card.js +103 -23
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-queue-kind.d.ts +27 -0
- package/dist/approval-queue-kind.js +6 -0
- package/dist/approval-reconciler.d.ts +41 -9
- package/dist/approval-reconciler.js +45 -42
- package/dist/audit.js +4 -2
- package/dist/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +17 -1
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +26 -23
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/governance-seams.d.ts +26 -41
- package/dist/boot/governance-seams.js +61 -28
- package/dist/boot/late-binds.d.ts +7 -4
- package/dist/boot/late-binds.js +3 -1
- package/dist/boot/leader.js +2 -4
- package/dist/boot/memory-consolidation.d.ts +0 -8
- package/dist/boot/memory-consolidation.js +5 -4
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.js +9 -7
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +19 -10
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.d.ts +10 -7
- package/dist/boot/runner-deps.js +20 -29
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.d.ts +9 -0
- package/dist/boot/shutdown.js +19 -4
- package/dist/boot/stage-02-web-admin-pull.js +3 -0
- package/dist/boot/stage-03-store-backend.d.ts +4 -1
- package/dist/boot/stage-03-store-backend.js +1 -2
- package/dist/boot/stage-04-stores.d.ts +5 -2
- package/dist/boot/stage-04-stores.js +6 -7
- package/dist/boot/stage-05-execution-env.d.ts +6 -3
- package/dist/boot/stage-05-execution-env.js +8 -6
- package/dist/boot/stage-06-runners.d.ts +6 -3
- package/dist/boot/stage-06-runners.js +3 -4
- package/dist/boot/stage-07-capability-layer.d.ts +6 -3
- package/dist/boot/stage-07-capability-layer.js +7 -2
- package/dist/boot/stage-08-reapers.d.ts +6 -3
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +6 -3
- package/dist/boot/stage-10-http-server.d.ts +6 -3
- package/dist/boot/stage-10-http-server.js +14 -5
- package/dist/boot/stores.d.ts +5 -2
- package/dist/boot/stores.js +10 -9
- package/dist/boot/web-admin.d.ts +5 -1
- package/dist/boot/web-admin.js +48 -36
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/hands-lane.d.ts +9 -39
- package/dist/capabilities/hands-lane.js +8 -13
- package/dist/capabilities/mcp-probe.d.ts +3 -2
- package/dist/capabilities/scenarios.d.ts +11 -1
- package/dist/capabilities/scenarios.js +1 -0
- package/dist/capabilities/skills.d.ts +1 -17
- package/dist/capabilities/skills.js +0 -8
- package/dist/capability-facts.d.ts +31 -7
- package/dist/capability-facts.js +27 -4
- package/dist/card-void.d.ts +6 -9
- package/dist/config-catalog.js +2 -1
- package/dist/config-dir-trust.js +58 -29
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +7 -0
- package/dist/config-provider.d.ts +10 -0
- package/dist/config-provider.js +15 -4
- package/dist/config-root-migration.d.ts +13 -0
- package/dist/config-root-migration.js +99 -0
- package/dist/config-types.d.ts +19 -8
- package/dist/config.d.ts +10 -3
- package/dist/config.js +18 -4
- package/dist/delegated-session-owner.d.ts +5 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/env-model-table-gate.d.ts +53 -0
- package/dist/env-model-table-gate.js +53 -0
- package/dist/execution-lane-caps.d.ts +2 -1
- package/dist/fleet/fleet-bus.d.ts +34 -55
- package/dist/fleet/fleet-bus.js +35 -100
- package/dist/fleet/fleet-reconciler.d.ts +4 -4
- package/dist/fleet/fleet-reconciler.js +1 -1
- package/dist/fleet/subagent-tail-bus.d.ts +14 -11
- package/dist/fleet/subagent-tail-bus.js +15 -28
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +58 -8
- package/dist/host-decision.d.ts +54 -20
- package/dist/host-decision.js +42 -14
- package/dist/http/admission.d.ts +1 -1
- package/dist/http/admission.js +7 -3
- package/dist/http/approval-sweeps.js +11 -8
- package/dist/http/caller-trust.d.ts +1 -1
- package/dist/http/dispatch.js +4 -2
- package/dist/http/durable-run-leg.js +2 -2
- package/dist/http/engine-refusal.d.ts +16 -0
- package/dist/http/engine-refusal.js +17 -0
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
- package/dist/http/memory-compliance-failure-reply.js +4 -6
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +13 -0
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.d.ts +21 -7
- package/dist/http/resume-legs.js +76 -58
- package/dist/http/resume-restatement.d.ts +39 -0
- package/dist/http/resume-restatement.js +25 -0
- package/dist/http/route-ctx.d.ts +35 -10
- package/dist/http/route-ctx.js +1 -1
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.d.ts +9 -1
- package/dist/http/routes/approvals-assistant.js +142 -31
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +16 -4
- package/dist/http/routes/memory-policy.d.ts +2 -2
- package/dist/http/routes/memory-policy.js +27 -7
- package/dist/http/routes/notify-wake.js +23 -25
- package/dist/http/routes/rules.js +48 -13
- package/dist/http/routes/runs.js +12 -11
- package/dist/http/routes/session-memory-sync.d.ts +91 -0
- package/dist/http/routes/session-memory-sync.js +174 -0
- package/dist/http/routes/session-sync.js +13 -20
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/sessions.d.ts +2 -2
- package/dist/http/routes/sessions.js +22 -23
- package/dist/http/routes/tasks.js +34 -54
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +9 -3
- package/dist/http/send.d.ts +5 -0
- package/dist/http/send.js +9 -2
- package/dist/http/server.d.ts +27 -15
- package/dist/http/server.js +4 -6
- package/dist/http/stored-body-replay.js +15 -4
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/http/wire-types.d.ts +17 -7
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/leader/leader.js +5 -2
- package/dist/leader/wire.d.ts +7 -1
- package/dist/leader/wire.js +6 -5
- package/dist/leg-facts.d.ts +37 -0
- package/dist/leg-facts.js +15 -0
- package/dist/memory-bundle-engine.d.ts +1 -4
- package/dist/memory-bundle-engine.js +2 -2
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-operator-faces.d.ts +30 -66
- package/dist/memory-operator-faces.js +17 -88
- package/dist/memory-scope-stores.d.ts +38 -40
- package/dist/memory-scope-stores.js +51 -36
- package/dist/memory-scope.d.ts +0 -9
- package/dist/memory-scope.js +0 -9
- package/dist/memory-sync-client.d.ts +21 -21
- package/dist/memory-sync-client.js +62 -43
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +27 -5
- package/dist/memory-sync.js +29 -7
- package/dist/model-plane-face.d.ts +13 -7
- package/dist/model-plane-face.js +2 -1
- package/dist/observability/fail-open.d.ts +47 -14
- package/dist/observability/fail-open.js +37 -11
- package/dist/observability/run-terminal.d.ts +92 -34
- package/dist/observability/run-terminal.js +171 -162
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
- package/dist/orchestration/workflow-completion-inbox.js +0 -12
- package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
- package/dist/orchestration/workflow-park-decision.d.ts +8 -3
- package/dist/orchestration/workflow-park-decision.js +5 -3
- package/dist/org-delivery-gate.d.ts +11 -0
- package/dist/org-delivery-gate.js +19 -1
- package/dist/parked-decide.d.ts +13 -9
- package/dist/parked-decide.js +7 -7
- package/dist/parked-revive-surface.js +1 -1
- package/dist/peer-inbound-face.d.ts +127 -0
- package/dist/peer-inbound-face.js +158 -0
- package/dist/permission-rule-list.d.ts +13 -9
- package/dist/permission-rule-list.js +7 -3
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +64 -11
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +17 -14
- package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
- package/dist/plugins/approval-ask-store-sql.js +79 -30
- package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
- package/dist/plugins/checkpoint-store-sql.js +9 -7
- package/dist/plugins/file-history-store-sql.d.ts +24 -18
- package/dist/plugins/file-history-store-sql.js +24 -19
- package/dist/plugins/file-run-store.d.ts +35 -1
- package/dist/plugins/file-run-store.js +108 -9
- package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
- package/dist/plugins/imported-layer-root-retirement.js +96 -0
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +2 -2
- package/dist/plugins/local-session-store.d.ts +42 -9
- package/dist/plugins/local-session-store.js +83 -33
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
- package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
- package/dist/plugins/mailbox-store-sql.d.ts +12 -8
- package/dist/plugins/mailbox-store-sql.js +76 -7
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +6 -1
- package/dist/plugins/memory-run-store.js +11 -1
- package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
- package/dist/plugins/memory-sync-store-pg.js +21 -0
- package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
- package/dist/plugins/memory-sync-store-tidb.js +13 -1
- package/dist/plugins/one-time-migrations.d.ts +58 -2
- package/dist/plugins/one-time-migrations.js +161 -4
- package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
- package/dist/plugins/org-delivery-quota-store.js +2 -12
- package/dist/plugins/park-commit-watch.d.ts +1 -1
- package/dist/plugins/permission-rule-store-file.d.ts +10 -1
- package/dist/plugins/permission-rule-store-file.js +15 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
- package/dist/plugins/permission-rule-store-sql.js +35 -2
- package/dist/plugins/remote-env-device.d.ts +8 -11
- package/dist/plugins/remote-env-device.js +6 -3
- package/dist/plugins/remote-env-e2b.d.ts +23 -4
- package/dist/plugins/remote-env-e2b.js +111 -28
- package/dist/plugins/remote-env-k8s.d.ts +61 -22
- package/dist/plugins/remote-env-k8s.js +133 -33
- package/dist/plugins/remote-env-local-docker.d.ts +15 -3
- package/dist/plugins/remote-env-local-docker.js +40 -12
- package/dist/plugins/retention-store-sql.d.ts +2 -2
- package/dist/plugins/run-store-sql.d.ts +9 -1
- package/dist/plugins/run-store-sql.js +9 -1
- package/dist/plugins/sandbox-read-floor.d.ts +5 -7
- package/dist/plugins/sandbox-read-floor.js +2 -7
- package/dist/plugins/sql-errors.d.ts +10 -1
- package/dist/plugins/sql-errors.js +13 -0
- package/dist/plugins/store-backend.d.ts +33 -35
- package/dist/plugins/store-backend.js +10 -1
- package/dist/plugins/store-contracts.d.ts +50 -1
- package/dist/plugins/store-contracts.js +6 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +207 -29
- package/dist/plugins/tool-result-store-sql.d.ts +9 -8
- package/dist/plugins/tool-result-store-sql.js +23 -2
- package/dist/plugins/wiring-section-codec.d.ts +32 -0
- package/dist/plugins/wiring-section-codec.js +55 -0
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +5 -1
- package/dist/rules-consent.d.ts +28 -5
- package/dist/rules-consent.js +40 -28
- package/dist/run-local.js +11 -13
- package/dist/runs.d.ts +12 -8
- package/dist/runs.js +6 -8
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +9 -0
- package/dist/security.js +8 -0
- package/dist/server-secret-env.d.ts +4 -0
- package/dist/session-error-wire.d.ts +36 -0
- package/dist/session-error-wire.js +13 -0
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-notify-door.d.ts +106 -0
- package/dist/session-notify-door.js +93 -0
- package/dist/session-sync.d.ts +9 -14
- package/dist/session-sync.js +5 -5
- package/dist/session-workspace.d.ts +3 -13
- package/dist/session-workspace.js +0 -9
- package/dist/standing-answer-grant.d.ts +5 -0
- package/dist/standing-answer-grant.js +10 -0
- package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
- package/dist/stores-sql/session-policy-store-sql.js +3 -13
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +21 -10
- package/dist/task-settings.js +46 -13
- package/dist/terminal.d.ts +39 -19
- package/dist/terminal.js +65 -22
- package/dist/tool-approval.d.ts +56 -37
- package/dist/tool-approval.js +78 -71
- package/dist/trace/core-keyset-guard.d.ts +134 -14
- package/dist/trace/engine-notice-wire.d.ts +9 -3
- package/dist/trace/engine-notice-wire.js +7 -3
- package/dist/trace/exit-seat.d.ts +9 -2
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +10 -6
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/model-segment.d.ts +55 -25
- package/dist/trace/model-segment.js +101 -33
- package/dist/trace/project.d.ts +25 -5
- package/dist/trace/project.js +22 -0
- package/dist/trace/redact.d.ts +61 -9
- package/dist/trace/redact.js +1490 -468
- package/dist/trace/self-minted-wire.d.ts +745 -24
- package/dist/trace/self-minted-wire.js +239 -9
- package/dist/trace/wire-projection-faces.d.ts +2 -2
- package/dist/trace/wire-projection-faces.js +2 -2
- package/dist/verifier-pause-card.d.ts +33 -5
- package/dist/verifier-pause-card.js +15 -10
- package/dist/web-admin-client/apply-effective.d.ts +12 -16
- package/dist/web-admin-client/apply-effective.js +109 -9
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/types.d.ts +4 -0
- package/dist/workspace-space.d.ts +19 -3
- package/dist/workspace-space.js +8 -4
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
- package/package.json +3 -2
- package/wire-changes/server@7.142.0.json +639 -0
- package/wire-changes/server@7.143.0.json +1167 -0
|
@@ -45,6 +45,19 @@ export function isDeadlockError(dialect, err) {
|
|
|
45
45
|
return keyOf(err, "code") === PG_DEADLOCK_DETECTED_SQLSTATE;
|
|
46
46
|
return keyOf(err, "errno") === MYSQL_ER_LOCK_DEADLOCK_ERRNO || keyOf(err, "code") === MYSQL_ER_LOCK_DEADLOCK_CODE;
|
|
47
47
|
}
|
|
48
|
+
export const DEADLOCK_RETRY_LIMIT = 8;
|
|
49
|
+
export async function retryOnDeadlock(dialect, attempt, alsoArbitrated) {
|
|
50
|
+
for (let tries = 0;; tries++) {
|
|
51
|
+
try {
|
|
52
|
+
return await attempt();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (tries < DEADLOCK_RETRY_LIMIT && (isDeadlockError(dialect, err) || alsoArbitrated?.(err) === true))
|
|
56
|
+
continue;
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
48
61
|
export const TIDB_ER_ENTRY_TOO_LARGE_ERRNO = 8025;
|
|
49
62
|
export const MYSQL_ER_NET_PACKET_TOO_LARGE_ERRNO = 1153;
|
|
50
63
|
export const MYSQL_ER_NET_PACKET_TOO_LARGE_CODE = "ER_NET_PACKET_TOO_LARGE";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Pool as MysqlPool } from "mysql2/promise";
|
|
2
2
|
import type { Pool as PgPool } from "pg";
|
|
3
|
-
import type { SessionStore, SessionPolicyStore, FileHistoryStore, WorkflowJournalStore, ToolResultStore, SessionCaptureRecordStore, UsageWindowStore } from "@sema-agent/core";
|
|
3
|
+
import type { SessionStore, SessionPolicyStore, FileHistoryStore, FileHistoryBlobExchange, FileHistoryError, WorkflowJournalStore, ToolResultStore, SessionCaptureRecordStore, UsageWindowStore } from "@sema-agent/core";
|
|
4
4
|
import { type OutcomeSink } from "./file-outcome-sink.js";
|
|
5
5
|
import { type InboxWarn } from "./workflow-run-store-sql.js";
|
|
6
6
|
import { FileRunStore } from "./file-run-store.js";
|
|
@@ -60,37 +60,37 @@ export type ServiceSessionPolicyStore = SessionPolicyStore;
|
|
|
60
60
|
* carry (optional so the local lane's core `FileFileHistoryStore` still fits). Replaces the retired E19
|
|
61
61
|
* whole-tree `ServiceFileSnapshotStore` ([ref]: the boundary covers the TRACKED set only — files this
|
|
62
62
|
* session edited; there is no whole-tree manifest anymore). Also the 2c history-transfer store
|
|
63
|
-
* (exportHistory/importHistory + the blob
|
|
63
|
+
* (exportHistory/importHistory + the blob exchange below). */
|
|
64
64
|
/**
|
|
65
|
-
* The
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* The SQL twins' blob exchange — core's {@link FileHistoryBlobExchange} group (`put` / `get` / `has`, all three or none, read only
|
|
66
|
+
* through `blobExchangeOf` in `session-sync.ts`, which defers to core's judge) with ONE narrowing: a `put` refusal may carry
|
|
67
|
+
* `blobCap`, the SQL blob judge's refusal on the connection that would have written the blob
|
|
68
|
+
* ({@link import("./blob-backend.js").BlobTooLargeError}). Present ⟺ that refusal; `PUT /sync/blobs` answers it 413
|
|
69
|
+
* `blob_too_large_for_sql` (the judge's sentence, plus the machine-readable `wallSource` = where the cap came from). The content-address
|
|
70
|
+
* refusal is core's own (`adopt_failed`, `permanence: "terminal"`, nothing stored); every other failure is a write fault the route answers 502.
|
|
68
71
|
*/
|
|
69
|
-
export type
|
|
72
|
+
export type SqlBlobPutResult = {
|
|
73
|
+
readonly ok: true;
|
|
74
|
+
} | {
|
|
70
75
|
readonly ok: false;
|
|
71
|
-
readonly error: {
|
|
72
|
-
readonly
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
readonly error: FileHistoryError & {
|
|
77
|
+
readonly blobCap?: {
|
|
78
|
+
readonly wallSource: import("./blob-backend.js").SqlBlobCapReading["source"];
|
|
79
|
+
};
|
|
75
80
|
};
|
|
76
81
|
};
|
|
82
|
+
export interface ServiceBlobExchange extends FileHistoryBlobExchange {
|
|
83
|
+
put(hash: string, bytes: Uint8Array): Promise<SqlBlobPutResult>;
|
|
84
|
+
}
|
|
77
85
|
export type ServiceFileHistoryStore = FileHistoryStore & {
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
syncBlobFaces?: true;
|
|
86
|
+
/** The blob exchange (SQL twins only; core's local File store carries none). Narrowed per {@link ServiceBlobExchange}. */
|
|
87
|
+
readonly blobExchange?: ServiceBlobExchange;
|
|
81
88
|
/** E21 purge / overwrite-dst sync wipe: drop the WHOLE scope incl. v1 baselines + DV-14 markers
|
|
82
89
|
* (`reap(scope, [])` deliberately retains those while the scope lives — not a purge). SQL twins only. */
|
|
83
90
|
deleteBySession?(scope: string): Promise<number>;
|
|
84
91
|
/** Async byte-GC for the file_history_blob domain (orphans left by reap/purge/lost mint races; grace-window
|
|
85
92
|
* protected — never a synchronous external-store delete). Reaper-driven; SQL twins only. */
|
|
86
93
|
sweepOrphanBlobs?(): Promise<number>;
|
|
87
|
-
/** 2c blob negotiation: upload one content-addressed blob ahead of importHistory. SQL twins only. */
|
|
88
|
-
putBlob?(hash: string, bytes: Uint8Array): Promise<SyncBlobPutResult>;
|
|
89
|
-
/** 2c blob read face (scope-checked by the route against the session's history graph). SQL twins only. */
|
|
90
|
-
getBlob?(hash: string): Promise<Uint8Array | undefined>;
|
|
91
|
-
/** The subset of `hashes` already present — a cheap SQL INDEX probe (the import presence pre-check,
|
|
92
|
-
* never N full getBlob GETs). SQL twins only. */
|
|
93
|
-
hasBlobs?(hashes: string[]): Promise<Set<string>>;
|
|
94
94
|
};
|
|
95
95
|
/** SVC-2 (core CORE-7) WorkflowJournalStore — core's interface PLUS the service `deleteByRun` (GC extra). tidb/pg =
|
|
96
96
|
* durable SQL twins (cross-replica resume journal); local = the service {@link FileWorkflowJournalStore}
|
|
@@ -128,15 +128,10 @@ export type CheckpointStoreFull = TiDBCheckpointStore | PgCheckpointStore | Loca
|
|
|
128
128
|
/** The full tool-result store: core `ToolResultStore` + the service maintenance extras. The SQL twins carry
|
|
129
129
|
* both extras; the LOCAL lane returns core's `FileToolResultStore` (core 1.219 — durable across a
|
|
130
130
|
* process restart, the TOC "ReadToolResult(ref) 恒空" fix) which since core 5.28.0 carries `deleteBySession`
|
|
131
|
-
* (owner sidecar 判属主,无边车存量计 unattributable 不删)
|
|
132
|
-
* optional-call (`store.
|
|
133
|
-
* core 5.28 起半假——本类型注是消费方第一落点,与 LocalBackend 内部注必须同真。)
|
|
131
|
+
* (owner sidecar 判属主,无边车存量计 unattributable 不删)and since core 7.61.0 the age bound `reap(now, { maxAgeMs })`
|
|
132
|
+
* — both are core `ToolResultStore`'s own optional members, so consumers optional-call them (`store.reap?.(…)`).
|
|
134
133
|
* Structural (not a nominal union) so all three backends flow through one seam. */
|
|
135
|
-
export type ToolResultStoreFull = ToolResultStore & {
|
|
136
|
-
/** TTL sweep (SQL twins only): purge rows older than the cutoff. Local file store omits it (CC posture:
|
|
137
|
-
* a single user's tool-result files persist like transcripts; bounded by being text previews). */
|
|
138
|
-
reapOlderThan?(cutoffMs: number): Promise<number>;
|
|
139
|
-
};
|
|
134
|
+
export type ToolResultStoreFull = ToolResultStore & {};
|
|
140
135
|
/** Cross-replica counter twins expose the write-behind lifecycle (startRefresh/stop) main.ts drives. */
|
|
141
136
|
export type BreakerStateStore = TiDBBreakerState | PgBreakerState;
|
|
142
137
|
export type CostQuotaStore = TiDBCostQuota | PgCostQuota;
|
|
@@ -326,16 +321,19 @@ export interface StoreBackend {
|
|
|
326
321
|
info?(msg: string, meta?: unknown): void;
|
|
327
322
|
}): CheckpointStoreFull;
|
|
328
323
|
/**
|
|
329
|
-
* 待决 checkpoint 的**只读**读口(**必选**成员)——
|
|
324
|
+
* 待决 checkpoint 的**只读**读口(**必选**成员)—— 「前世 / 别的副本留下的停驻」的读法,不走 {@link checkpoint}。两个读者:
|
|
325
|
+
* · 审批账本留存律(`approval-ask-retention.ts` 的挂靠集)读「还有哪些会话停驻着」(`listPendingSessionIds`);
|
|
326
|
+
* · local 车道起服收敛(`approval-crash-convergence.ts`)对审计判为孤儿的前世 `PARKING` 问跑对账器判据 ① 的候选读口(`findCheckpointCandidatesForAsk`:
|
|
327
|
+
* 停车行其实已提交 ⇒ `PARKED`,不收 `VOID`)。
|
|
330
328
|
* 区别只有一条:这一口**不牵动任何别的店**。local 车道的 `checkpoint()` 是 durable 停驻面的装配点 —— 它给 run 店接上 [ref] 的收割探针(停驻行的收割从 no-op 变生效),
|
|
331
|
-
* 那是开了 `DURABLE_APPROVAL`
|
|
332
|
-
*
|
|
329
|
+
* 那是开了 `DURABLE_APPROVAL` 的部署才该发生的事;两个读者在没开它的部署上同样要读(前世 / 别的副本留下的停驻不因这一世的开关消失:留存腿看不见就会把还能被决的停驻的问删掉,
|
|
330
|
+
* 起服收敛看不见就会把前世已提交的停驻的问收成 `VOID`),所以读和接线必须分口。SQL 孪生本来无状态(接线靠 JOIN),两口同一只。
|
|
333
331
|
*
|
|
334
|
-
* 🔴 为什么必选而不是跟着 {@link checkpoint}
|
|
335
|
-
*
|
|
336
|
-
* (`{ listPendingSessionIds: async () => [] }` —— 没有店 ⇒ 没有停驻,这是事实不是缺省)。
|
|
332
|
+
* 🔴 为什么必选而不是跟着 {@link checkpoint} 一起可选:读不到这一口的后果都在**不可逆方向**(挂靠集里少了待决停驻 ⇒ 还能被决的停驻的问按龄被删;判据 ① 恒不命中 ⇒
|
|
333
|
+
* 已提交的停驻的问被收成终态),「有 checkpoint 店却没交读口」若只是运行期的 `undefined`,就是一次静默少保护;必选 ⇒ 漏实现是**编译红**。没有 checkpoint 店的后端
|
|
334
|
+
* (`checkpoint` 缺席)交一只恒空的读口(`{ listPendingSessionIds: async () => [], findCheckpointCandidatesForAsk: async () => [] }` —— 没有店 ⇒ 没有停驻,这是事实不是缺省)。
|
|
337
335
|
*/
|
|
338
|
-
checkpointReadView(): Pick<CheckpointStoreFull, "listPendingSessionIds">;
|
|
336
|
+
checkpointReadView(): Pick<CheckpointStoreFull, "listPendingSessionIds" | "findCheckpointCandidatesForAsk">;
|
|
339
337
|
toolResult?(): ToolResultStoreFull;
|
|
340
338
|
imageIndex?(): ImageIndex;
|
|
341
339
|
imageBake?(): ImageBake;
|
|
@@ -2,6 +2,7 @@ import { homedir } from "node:os";
|
|
|
2
2
|
import { createCorruptReadSeat, createDurableAbsenceSeat } from "../observability/corrupt-read-seat.js";
|
|
3
3
|
import { createLogger } from "../observability/logger.js";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
5
6
|
import { AdoptionError, FileStorageBackend } from "@sema-agent/core";
|
|
6
7
|
import { FileWorkflowJournalStore } from "@sema-agent/core";
|
|
7
8
|
import { fileSessionCaptureRecordStore } from "@sema-agent/core";
|
|
@@ -58,7 +59,8 @@ import { TiDBAdoptionLogStore, PgAdoptionLogStore } from "./adoption-log-sql.js"
|
|
|
58
59
|
import { TiDBRetentionStore, PgRetentionStore, sqlStoreRetention } from "./retention-store-sql.js";
|
|
59
60
|
import { TiDBRetentionLaneStore, PgRetentionLaneStore } from "./retention-lane-store-sql.js";
|
|
60
61
|
import { createSqlPermissionRuleStores } from "./permission-rule-store-sql.js";
|
|
61
|
-
import { createFilePermissionRuleStores } from "./permission-rule-store-file.js";
|
|
62
|
+
import { FILE_PERMISSION_RULE_DIR, createFilePermissionRuleStores } from "./permission-rule-store-file.js";
|
|
63
|
+
import { retireImportedLayerRootAllows } from "./imported-layer-root-retirement.js";
|
|
62
64
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
63
65
|
import { storeDegradedReasonFor } from "../store-posture.js";
|
|
64
66
|
import { openWithinWait } from "./store-open-wait.js";
|
|
@@ -298,17 +300,24 @@ class LocalBackend {
|
|
|
298
300
|
const holderDeathCodeRowsBackfilled = this.runStore.migrateLegacyHolderDeathCodes();
|
|
299
301
|
const archives = await this.sessionStore.migrateLocalArchives();
|
|
300
302
|
const placements = await backfillLocalExecutionPlacements(this.runStore.sessionIdsWithRuns(), this.sessionStore.executionPlacementBackfill, { lanes: this.executionLanes });
|
|
303
|
+
const importedLayerRoot = { importedLayerRootAllowsRetired: [], importedLayerRootBucketsSkipped: [] };
|
|
304
|
+
if (existsSync(join(this.fileBackend.root, FILE_PERMISSION_RULE_DIR))) {
|
|
305
|
+
const rules = this.permissionRule();
|
|
306
|
+
await retireImportedLayerRootAllows({ candidateOwners: () => rules.approvals.importRecordOwners(), durable: rules.durable, isWholeBucketRefusal: () => false, isVanishedBucket: () => false }, importedLayerRoot);
|
|
307
|
+
}
|
|
301
308
|
return {
|
|
302
309
|
...NO_SQL_MIGRATIONS,
|
|
303
310
|
holderDeathCodeRowsBackfilled,
|
|
304
311
|
executionPlacementsBackfilled: placements.backfilled,
|
|
305
312
|
executionPlacementSessionsUnreadable: placements.unreadable,
|
|
306
313
|
askExecutionLanesBackfilled: backfillLocalAskExecutionLanes(this.approvalAskStore, { lanes: this.executionLanes }),
|
|
314
|
+
askJournalRecordsUpgraded: this.approvalAskStore.upgradeJournalEnvelope(),
|
|
307
315
|
localArchiveRowFactsBackfilled: archives.rowFactsBackfilled,
|
|
308
316
|
localArchivesAnonymized: archives.anonymized,
|
|
309
317
|
localArchivesKeptStamped: archives.keptStamped,
|
|
310
318
|
localArchivesUnreadable: archives.unreadable,
|
|
311
319
|
localArchiveSnapshotsRecovered: archives.snapshotsRecovered,
|
|
320
|
+
...importedLayerRoot,
|
|
312
321
|
};
|
|
313
322
|
}
|
|
314
323
|
async close() {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { PeerSessionTempo, TaskResult, TaskStatus } from "@sema-agent/core";
|
|
22
22
|
import type { RunIdentity } from "../identity-source.js";
|
|
23
|
+
import type { SessionUnreadable } from "../session-error-wire.js";
|
|
23
24
|
/**
|
|
24
25
|
* **File 店族的 boot 期拒启基类**([ref];把 `RunStoreStrictHydrateError` 的那条论证升成一条族规)。
|
|
25
26
|
*
|
|
@@ -443,7 +444,7 @@ export declare function isUnsuccessfulRunStatus(status: RunRecord["status"]): bo
|
|
|
443
444
|
* 未知词的方向与 {@link isTerminalRunStatus} 同向保守:判**不是** park。理由是消费点会据此做**不可逆**
|
|
444
445
|
* 动作(cancel 的恢复把手会 CAS-expire 一张 checkpoint);对一个本进程读不懂的状态,少动一次远好过错杀。
|
|
445
446
|
*/
|
|
446
|
-
export declare function isParkedRunStatus(status: RunRecord["status"]):
|
|
447
|
+
export declare function isParkedRunStatus(status: RunRecord["status"]): status is ParkedRunStatus;
|
|
447
448
|
/**
|
|
448
449
|
* 会话的**活动词**(core `PeerSessionTempo`)——「这条会话现在在忙还是闲」的**唯一**一张表([ref])。
|
|
449
450
|
*
|
|
@@ -531,6 +532,9 @@ export interface SessionSummary {
|
|
|
531
532
|
/** 行标签(`src/session-row.ts` 的 `sessionRowTagOf`):这一位住客「PATCH 能写的每一格」的单向摘要,present-iff 这一行可被条件写(店有行格写原语 ∧ 行上有化身);
|
|
532
533
|
* 只经店的列表行映射铸(`sessionRowTagKey`)。没有会话行的 lister(legacy task_run 聚合 / 内存孪生)缺席。wire 半场见 `security.ts SessionListItem.rowTag`(同名同义)。 */
|
|
533
534
|
rowTag?: string;
|
|
535
|
+
/** 这只会话的存档读不出:present-iff 头的叶子读不出(唯一铸点 `session-error-wire.ts` 的 `sessionUnreadableOf`;码与读口同表)。叶子是行上一列的店(SQL 孪生)
|
|
536
|
+
* 与没有会话行的 lister 恒缺席。wire 半场见 `security.ts SessionListItem.unreadable`(同名同义)。 */
|
|
537
|
+
unreadable?: SessionUnreadable;
|
|
534
538
|
}
|
|
535
539
|
/**
|
|
536
540
|
* [ref] —— 会话**枚举面**读 run 账里「每会话的 run 投影」的窄读面:`runCount` / `lastStatus` / `lastRunId` / `lastTaskRunId` 四位,
|
|
@@ -572,6 +576,51 @@ export interface LatestRunRef {
|
|
|
572
576
|
owner: string | null;
|
|
573
577
|
createdAt: string;
|
|
574
578
|
}
|
|
579
|
+
/** 引擎对一条腿实际挂上的记忆读集的观测(core `TaskResult.effectiveMemoryScopes` 的值;core 包根不单独导出这只型,从结果型取)。 */
|
|
580
|
+
export type EffectiveMemoryScopes = NonNullable<PersistedTaskResult["effectiveMemoryScopes"]>;
|
|
581
|
+
/**
|
|
582
|
+
* [ref] —— **空观测**的因由(闭集;词表属主 = 本文件,唯一铸点 = {@link settledLegObservationOf})。两词都只说**那条已结腿的记录里有什么**,不猜它为什么停 ——
|
|
583
|
+
* 停因的真源是那一条 run 自己的终局(`GET /v1/runs/:id` 的 `status` / `errorCode`),这里不复述第二份:
|
|
584
|
+
* · `run_result_missing` —— 记录里**没有结果**:本服务结算它时手里没有引擎的结果(持有它的实例丢了被收割、腿在引擎答出之前抛),或收割时写空了它(停驻过期被收割 ——
|
|
585
|
+
* [ref] 律:收割把停驻结果写空,停驻时那份结果里的观测随之不在;本读口不另存一份);
|
|
586
|
+
* · `run_result_unobserved` —— 记录里**有结果、结果里没有观测**:引擎的律是「缺席 ⇔ prepare 没走完」(引擎在准备阶段拒了 / 失败了它),
|
|
587
|
+
* 另两形同答 —— 引擎答出之前就被取消、由本服务铸的取消终局,与比这一观测更早的引擎写下的结果。
|
|
588
|
+
* 自铸 wire 值登记 = `trace/self-minted-wire.ts` 的 `sessionMemoryUnobservedReason`(`satisfies Record<…>`:加 / 删一个词而登记没跟 ⇒ tsc 红)。
|
|
589
|
+
*/
|
|
590
|
+
export declare const MEMORY_OBSERVATION_ABSENT_REASONS: readonly ["run_result_missing", "run_result_unobserved"];
|
|
591
|
+
export type MemoryObservationAbsentReason = (typeof MEMORY_OBSERVATION_ABSENT_REASONS)[number];
|
|
592
|
+
/** [ref] —— 空观测记号:与引擎三态同一只字段、同一个判别位 `state`(闭集加一词 `absent`;引擎哪天自己长出同名一态 ⇒ `trace/core-keyset-guard.ts` 的跨界钉当场红)。 */
|
|
593
|
+
export interface AbsentMemoryObservation {
|
|
594
|
+
readonly state: "absent";
|
|
595
|
+
readonly reason: MemoryObservationAbsentReason;
|
|
596
|
+
}
|
|
597
|
+
/** 一条已结腿的记忆观测 —— 四态闭集:引擎铸的三态原样(`mounted` / `memoryless` / `none`)∪ 空观测({@link AbsentMemoryObservation})。消费方按 `state` 穷举分支。 */
|
|
598
|
+
export type LegMemoryObservation = EffectiveMemoryScopes | AbsentMemoryObservation;
|
|
599
|
+
/**
|
|
600
|
+
* 「这个会话**最近一条已结腿**与它的记忆观测」的窄读面(run 店的 `latestMemoryObservationForSession` 的回值)—— 会话记忆同步触发口
|
|
601
|
+
* (`POST /v1/sessions/:id/memory/sync`)的**会话读集**只读这一只:读集 = 最近一条已结腿结果里引擎铸的观测(引擎一处铸、随 run 行持久;路由不重铸 spec)。
|
|
602
|
+
*
|
|
603
|
+
* 一条规则,三只实现同答:
|
|
604
|
+
* · 已结 = {@link isTerminalRunStatus}(成功 / 非成功终局;在飞与停在门上的腿还占着会话的认领,不算;读不懂的词同向保守判「未结」)。两孪生调这只谓词;
|
|
605
|
+
* SQL 两方言按本文件的惯例写字面词集 `status IN ('completed','failed','blocked')`,与谓词的同源由 `test/source-hygiene-gate.test.ts` 的方言对 parity 门钉;
|
|
606
|
+
* 取最近一条(排序口径与 {@link LatestRunRef} 逐字同一句:`created_at DESC, task_id DESC`);
|
|
607
|
+
* · `observation` = 那一条腿的观测,**恒在场**,四态之一({@link LegMemoryObservation}):结果里有引擎的观测 ⇒ 原样;没有 ⇒ 空观测记号,因由说记录里有什么
|
|
608
|
+
* ({@link MemoryObservationAbsentReason})。**不往更早的腿找**:读集是「最近一条已结腿」的,不是「最近一条有观测的腿」的 —— 空观测是那一条的值,不是去找下一条的信号。
|
|
609
|
+
* 空观测**不落盘**:它是行上已有事实(结果列、结果里那一键的缺席)的一只纯函数,铸在读口({@link settledLegObservationOf},三店共用);落一份 = 第二真源
|
|
610
|
+
* (与引擎「缺席 ⇔ prepare 没走完」那条律并存、两份要对得上),且终局写口二十余处、收割器整行写空结果的 SQL 两方言语句与存量行都得各补一份。
|
|
611
|
+
* 结果列读不出 ⇒ 抛(与 `getRun` 同一个失败方向:不把一条结了的腿当成没有结果)。
|
|
612
|
+
*/
|
|
613
|
+
export interface SettledLegMemoryObservation {
|
|
614
|
+
readonly taskId: string;
|
|
615
|
+
readonly observation: LegMemoryObservation;
|
|
616
|
+
}
|
|
617
|
+
/** {@link SettledLegMemoryObservation} 的**唯一铸点**(三只实现共用):一条已结腿的结果 → 读口的回值(空观测记号只在这里铸)。 */
|
|
618
|
+
export declare function settledLegObservationOf(taskId: string, result: PersistedTaskResult | null): SettledLegMemoryObservation;
|
|
619
|
+
/**
|
|
620
|
+
* run 店账本的一条事件 —— 三只孪生的 `getEvents` 都交出写口收下的那一形(按 seq 升序、每读一份新拷贝)。存形是孪生的私事、读者看不见:
|
|
621
|
+
* File 孪生把 `wiring_manifest` 行的容器段按会话存成块(`<root>/run-blobs/<会话>.jsonl`,律与唯一编解码 = `wiring-section-codec.ts`),行里只留引用,
|
|
622
|
+
* 读口装回整帧;装不回的那一帧不交出(F 类留痕),绝不交出缺段的清单。SQL / Memory 孪生整帧存。
|
|
623
|
+
*/
|
|
575
624
|
export interface RunEvent {
|
|
576
625
|
seq: number;
|
|
577
626
|
type: string;
|
|
@@ -56,4 +56,10 @@ export function sessionTempoOfRunStatus(lastStatus) {
|
|
|
56
56
|
export function runProvenElsewhere(run, thisInstanceId) {
|
|
57
57
|
return typeof run.instanceId === "string" && run.instanceId.length > 0 && thisInstanceId !== undefined && run.instanceId !== thisInstanceId;
|
|
58
58
|
}
|
|
59
|
+
export const MEMORY_OBSERVATION_ABSENT_REASONS = ["run_result_missing", "run_result_unobserved"];
|
|
60
|
+
export function settledLegObservationOf(taskId, result) {
|
|
61
|
+
if (result === null)
|
|
62
|
+
return { taskId, observation: { state: "absent", reason: "run_result_missing" } };
|
|
63
|
+
return { taskId, observation: result.effectiveMemoryScopes ?? { state: "absent", reason: "run_result_unobserved" } };
|
|
64
|
+
}
|
|
59
65
|
//# sourceMappingURL=store-contracts.js.map
|
|
@@ -21,12 +21,16 @@
|
|
|
21
21
|
* - 隔离键排序规则:TiDB 表级 utf8mb4_bin / PG owner 列 COLLATE "C"(bga F2 同姿,'=' 字节等价)。
|
|
22
22
|
* owner 值恒为 server 端从凭据推导(非用户输入),PAD SPACE 近撞面不可达,VARBINARY 键列不必要。
|
|
23
23
|
* - 布尔列:无(遵 1.287.0 归一约定,若未来加,PG 用 SMALLINT 0/1)。
|
|
24
|
-
* - 绑定:`bind` 把行钉到 sessionId(
|
|
25
|
-
*
|
|
24
|
+
* - 绑定:`bind` 把行钉到 sessionId,两条律都在店里、都不是先读后写(契约见 {@link TaskAttachmentStore.bind}):
|
|
25
|
+
* **一经绑定不再改绑**(UPDATE 谓词只放行未绑的行与已绑本会话的行,行级原子;同会话重绑 —— 首交重试、续跑腿重放存量体 —— 不改 `bound_at_ms`);
|
|
26
|
+
* **一只会话一只种子**(未绑的项目包只在这只会话还没有项目包时绑上:SQL 两方言是表上的唯一键 —— 种子键 `seed_session_id`(项目包行的会话,由引擎从 `mime` 与 `session_id` 推导)上的 `uq_att_seed`,第二只项目包的绑定被引擎拒;进程内的店是一段不被打断的判与改:内存店同一段同步,local 店的变更口同排一条串行段、bind 判在副本上、落成的行才合回)。
|
|
27
|
+
* 同 session 多 task 共享自然成立(listBySession 是物化输入)。
|
|
28
|
+
* 未绑定行 = 上传后从未被任何 task 引用 ⇒ reapUnbound(TTL)。
|
|
26
29
|
*/
|
|
27
30
|
import { z } from "zod";
|
|
28
31
|
import type { Pool } from "mysql2/promise";
|
|
29
32
|
import type { PgQueryFn } from "./pg-query.js";
|
|
33
|
+
import type { Pool as PgPool } from "pg";
|
|
30
34
|
import { type IndexSpec } from "./ensure-index.js";
|
|
31
35
|
/**
|
|
32
36
|
* 一条附件 meta 的**形属主**(整仓唯一那份键集)。
|
|
@@ -55,8 +59,14 @@ export interface TaskAttachmentStore {
|
|
|
55
59
|
/** meta(不带 bytes);owner 不匹配/不存在 → null(无 oracle)。 */
|
|
56
60
|
get(owner: string, id: string): Promise<TaskAttachmentRecord | null>;
|
|
57
61
|
getContent(owner: string, id: string): Promise<Uint8Array | null>;
|
|
58
|
-
/**
|
|
59
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 把 ids(请求序)钉到 sessionId。绑定的两条律都在店里判,判与写对这只会话的其它绑定是原子的(不是先读后写):
|
|
64
|
+
* · **一经绑定不再改绑** —— 已绑别的会话的行 ⇒ `bound_elsewhere`(行不动);已绑本会话的行命中、不改 `boundAtMs`;
|
|
65
|
+
* · **一只会话一只种子** —— 一只**未绑的项目包**只在这只会话此刻没有项目包时绑上,否则 ⇒ `bundle_seed_fixed`(同一次调用里请求序靠前的那只先占);
|
|
66
|
+
* 两次并发绑定各带一只新项目包到同一会话 ⇒ 恰一只绑上。
|
|
67
|
+
* 属主门在店里(owner 不匹配 / 不存在的 id 两边都不出现,无 oracle)。`bound` 按请求序、不重复。
|
|
68
|
+
*/
|
|
69
|
+
bind(owner: string, ids: readonly string[], sessionId: string, boundAtMs: number): Promise<AttachmentStoreBindOutcome>;
|
|
60
70
|
/** 物化输入(env 建立时)——按 session 单键查(绑定时已 owner 验过;session uuid 不可枚举)。 */
|
|
61
71
|
listBySession(sessionId: string): Promise<TaskAttachmentRecord[]>;
|
|
62
72
|
delete(owner: string, id: string): Promise<boolean>;
|
|
@@ -89,22 +99,108 @@ export interface AttachmentBytesStore {
|
|
|
89
99
|
* (created_at_ms, id)分配 `attachments/<name>`;同名撞车时后者前缀 id 头 8 位。名字在上传时已
|
|
90
100
|
* 消毒为安全 basename([A-Za-z0-9._-]),拼接后仍是安全相对路径。 */
|
|
91
101
|
export declare function materializedRelPaths(atts: TaskAttachmentRecord[]): Map<string, string>;
|
|
92
|
-
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
102
|
+
/**
|
|
103
|
+
* 提交体 `attachmentIds` 绑定时的拒(闭集;码与状态的唯一映射 = {@link attachmentBindRefusalAnswer})。
|
|
104
|
+
* · `bound_elsewhere` —— 这只附件已绑在别的会话上(一经绑定不再改绑;每个会话各上传一次);
|
|
105
|
+
* · `bundle_lane_not_isolated` —— 项目包只交给 OS 隔离边界内的车道(`laneIsolated`),这条腿的车道不是;
|
|
106
|
+
* · `bundle_seed_fixed` —— 本会话的种子已定(最早绑定的那只项目包),第二只项目包不收。
|
|
107
|
+
*/
|
|
108
|
+
export type AttachmentBindRefusal = {
|
|
109
|
+
readonly kind: "bound_elsewhere";
|
|
110
|
+
readonly id: string;
|
|
111
|
+
} | {
|
|
112
|
+
readonly kind: "bundle_lane_not_isolated";
|
|
113
|
+
readonly id: string;
|
|
114
|
+
readonly lane: string;
|
|
115
|
+
} | {
|
|
116
|
+
readonly kind: "bundle_seed_fixed";
|
|
117
|
+
readonly id: string;
|
|
118
|
+
};
|
|
119
|
+
/** 店在一次绑定里答的拒(闭集的子集:车道那一只是提交侧对这条腿的判,店不判)。 */
|
|
120
|
+
export type AttachmentStoreBindRefusal = Extract<AttachmentBindRefusal, {
|
|
121
|
+
readonly kind: "bound_elsewhere" | "bundle_seed_fixed";
|
|
122
|
+
}>;
|
|
123
|
+
/** 一次 {@link TaskAttachmentStore.bind} 的答:此刻绑在这只会话上的 id(请求序)与店拒掉的 id;两边都不在的 id = 不在 / 他人的。 */
|
|
124
|
+
export interface AttachmentStoreBindOutcome {
|
|
125
|
+
readonly bound: readonly string[];
|
|
126
|
+
readonly refused: readonly AttachmentStoreBindRefusal[];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 进程内的店(local 文件店、测试内存店)的绑定律 —— {@link TaskAttachmentStore.bind} 那一条律在进程内的**唯一**写法:判与改在**同一段同步**里
|
|
130
|
+
* (本函数不 await),于是调用方只要不在本函数前后放开(内存店:整条 `bind` 就是这一段;local 店:`bind` 与店的其它变更口同排一条串行段),
|
|
131
|
+
* 同一进程里两次并发绑定不可能都读到「这只会话还没有种子」(local 契约本就是单进程,`local-task-attachment-store.ts` 头注)。
|
|
132
|
+
* 改的是传进来的 `rows` 里的行对象本身 —— 内存店传自己的索引;需要落盘的店传**副本**,只把落盘落成的那些 `claimed` 行合回自己的索引
|
|
133
|
+
* (`claimed` = 这一次新绑上的行,即副本里被改的那些行对象;索引只反映盘上已有的)。
|
|
134
|
+
*/
|
|
135
|
+
export declare function bindRowsInProcess(rows: ReadonlyMap<string, TaskAttachmentRecord>, owner: string, ids: readonly string[], sessionId: string, boundAtMs: number): {
|
|
136
|
+
readonly outcome: AttachmentStoreBindOutcome;
|
|
137
|
+
readonly claimed: readonly TaskAttachmentRecord[];
|
|
138
|
+
};
|
|
139
|
+
/** 绑定拒的码 → 状态:唯一属主表(一个码在本服务上只有一个状态;`<名>_HTTP_STATUS` 是本仓这类表的名形,码目录门按名形读它的键)。 */
|
|
140
|
+
export declare const ATTACHMENT_BIND_HTTP_STATUS: {
|
|
141
|
+
readonly "attachment.bound_elsewhere": 409;
|
|
142
|
+
readonly "attachment.bundle_lane_not_isolated": 409;
|
|
143
|
+
readonly "attachment.bundle_seed_fixed": 409;
|
|
144
|
+
};
|
|
145
|
+
export type AttachmentBindCode = keyof typeof ATTACHMENT_BIND_HTTP_STATUS;
|
|
146
|
+
/** 一只绑定拒在 wire 上的答(状态取自 {@link ATTACHMENT_BIND_HTTP_STATUS} + 码 + 句 + 体键);穷举 switch —— 闭集多一种而这里没跟 ⇒ 编译红。 */
|
|
147
|
+
export declare function attachmentBindRefusalAnswer(r: AttachmentBindRefusal): {
|
|
148
|
+
readonly status: number;
|
|
149
|
+
readonly errorCode: AttachmentBindCode;
|
|
150
|
+
readonly message: string;
|
|
151
|
+
readonly extra: Record<string, string>;
|
|
152
|
+
};
|
|
153
|
+
/** 会话里**附件**那一类的行(项目包行不在其中)—— 告知的路径分配与物化读的唯一过滤读口:过滤在路径分配之前(种子行不挤动附件的撞名前缀)。 */
|
|
154
|
+
export declare function listAttachmentsBySession(store: TaskAttachmentStore, sessionId: string): Promise<TaskAttachmentRecord[]>;
|
|
155
|
+
/**
|
|
156
|
+
* 会话种子的读口:最早绑定的项目包行 + 它的字节,字节**必核**行上的 `sha256` 与 `sizeBytes`(种子身份 = 上传那一刻的摘要;local 店读侧不核,这里核)。
|
|
157
|
+
* 三种答:没有种子 ⇒ `undefined`;种子在、字节在、摘要对 ⇒ `{ record, bytes }`;店里的定局坏了(行在、字节没了 / 摘要不符)⇒ `{ record, broken }`。
|
|
158
|
+
* 店读本身抛(连接断、超时)⇒ 原样抛:那是一时的失败,不是这只会话的定答 —— 调用方据此分「换一次恢复点重读」与「这只环境此后同一个拒」。
|
|
159
|
+
*/
|
|
160
|
+
export declare function seedOfSession(store: TaskAttachmentStore, sessionId: string): Promise<{
|
|
161
|
+
readonly record: TaskAttachmentRecord;
|
|
162
|
+
readonly bytes: Uint8Array;
|
|
163
|
+
} | {
|
|
164
|
+
readonly record: TaskAttachmentRecord;
|
|
165
|
+
readonly broken: string;
|
|
166
|
+
} | undefined>;
|
|
167
|
+
/**
|
|
168
|
+
* 半场②(提交时绑定 + objective 告知)的可测核。fresh 腿硬验证(未知/他人 id → `onMissing` throw;拒 → `onRefused` throw);
|
|
169
|
+
* resume 腿降级(warn+跳过 —— 4xx 会砖存量 task;记录不可变 ⇒ 在场行的 notice 字节恒稳)。判序:
|
|
170
|
+
* ① 行在不在(属主门);② 已绑别的会话 ⇒ `bound_elsewhere`;③ 项目包 × 车道不隔离 ⇒ `bundle_lane_not_isolated`;
|
|
171
|
+
* ④ 本次提交体里第二只新项目包 ⇒ `bundle_seed_fixed`(只看提交体本身,不读店);
|
|
172
|
+
* ⑤ 绑定 —— 「本会话已有种子」与「不改绑」两条律只在店里判({@link TaskAttachmentStore.bind},判与写原子:并发的两次提交在那里分胜负,这里不先读):
|
|
173
|
+
* 提交体那只新项目包先**单独**绑,店拒了它 ⇒ `onRefused` 在体里其余 id 绑上之前就到(新提交腿上,店拒了种子候选的提交,体里其余 id 一只都不绑;读与绑之间才被别的会话抢走的附件不在此列 —— 先绑上的不回滚,请求仍 409);其余 id 随后一次绑。
|
|
174
|
+
* notice 只罗列本次引用的**附件**(项目包是工作区本身,不进告知),路径从绑定后的全会话附件集推导(与物化共用 {@link materializedRelPaths})。
|
|
175
|
+
*/
|
|
95
176
|
export declare function bindAttachmentsForTask(opts: {
|
|
96
177
|
store: TaskAttachmentStore;
|
|
97
178
|
owner: string;
|
|
98
179
|
ids: string[];
|
|
99
180
|
sessionId: string;
|
|
181
|
+
/** 这条腿的执行车道(执行上下文那一读)与它是否在 OS 隔离边界内(`laneIsolated` 那一判,调用方判一次交进来)。 */
|
|
182
|
+
lane: {
|
|
183
|
+
readonly word: string;
|
|
184
|
+
readonly isolated: boolean;
|
|
185
|
+
};
|
|
100
186
|
leg: "fresh" | "resume";
|
|
101
187
|
nowMs: number;
|
|
102
188
|
onMissing: (id: string) => void | never;
|
|
189
|
+
onRefused: (refusal: AttachmentBindRefusal) => void | never;
|
|
103
190
|
}): Promise<{
|
|
104
191
|
notice: string | undefined;
|
|
105
192
|
}>;
|
|
106
|
-
/**
|
|
107
|
-
*
|
|
193
|
+
/** 会话绑定的附件按工作区收它们的样子:行 + 物化相对路径(与 objective 告知同一份推导 {@link materializedRelPaths})。
|
|
194
|
+
* 两只物化座(没有恢复点的车道 = 执行环境建立时 {@link materializeAttachmentsInto};隔离车道 = 恢复点的填充 `workspace-fill.ts`)读的是这一份。 */
|
|
195
|
+
export interface AttachmentPlacement {
|
|
196
|
+
readonly record: TaskAttachmentRecord;
|
|
197
|
+
readonly relPath: string;
|
|
198
|
+
}
|
|
199
|
+
export declare function attachmentPlacementsOf(store: TaskAttachmentStore, sessionId: string): Promise<AttachmentPlacement[]>;
|
|
200
|
+
/** 一只要放进工作区的附件的字节;读不到 ⇒ 抛(fail-loud:objective 已宣告它在场)。 */
|
|
201
|
+
export declare function attachmentBytesOf(store: TaskAttachmentStore, rec: TaskAttachmentRecord): Promise<Uint8Array>;
|
|
202
|
+
/** 半场③(没有恢复点的车道:env 建立时物化)的可测核。**fail-loud**:objective 已宣告文件在场,静默缺文件=模型按幻影
|
|
203
|
+
* 文件行动,比 env 建立失败更糟 ⇒ 任一写失败即 throw。幂等:重建 env / resume 重写同路径同字节。 */
|
|
108
204
|
export declare function materializeAttachmentsInto(env: {
|
|
109
205
|
createDir(path: string, options?: {
|
|
110
206
|
recursive?: boolean;
|
|
@@ -129,10 +225,10 @@ export declare function ensureTiDBTaskAttachmentSchema(pool: Pool): Promise<void
|
|
|
129
225
|
/** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgTaskAttachmentSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
130
226
|
export declare const TASK_ATTACHMENT_INDEXES: readonly IndexSpec[];
|
|
131
227
|
export declare function ensurePgTaskAttachmentSchema(q: PgQueryFn): Promise<void>;
|
|
132
|
-
/** bytes → 4 MiB 块序列(共享切块器,两方言 + 完整性校验共用)。 */
|
|
133
228
|
export declare class TiDBTaskAttachmentStore implements TaskAttachmentStore {
|
|
134
229
|
private readonly pool;
|
|
135
230
|
private readonly bytes;
|
|
231
|
+
private readonly db;
|
|
136
232
|
constructor(pool: Pool, bytes: AttachmentBytesStore);
|
|
137
233
|
put(rec: TaskAttachmentRecord & {
|
|
138
234
|
content: Uint8Array;
|
|
@@ -143,7 +239,7 @@ export declare class TiDBTaskAttachmentStore implements TaskAttachmentStore {
|
|
|
143
239
|
* 失败只吞不抛——E21 purge 不被对象存储抖动卡死(blob-backend 异步删裁定同旨);无 meta 的对象
|
|
144
240
|
* 经 API 不可达,彻底清收敛记 follow-up。 */
|
|
145
241
|
private deleteBytesIfUnreferenced;
|
|
146
|
-
bind(owner: string, ids: string[], sessionId: string, boundAtMs: number): Promise<
|
|
242
|
+
bind(owner: string, ids: readonly string[], sessionId: string, boundAtMs: number): Promise<AttachmentStoreBindOutcome>;
|
|
147
243
|
listBySession(sessionId: string): Promise<TaskAttachmentRecord[]>;
|
|
148
244
|
delete(owner: string, id: string): Promise<boolean>;
|
|
149
245
|
deleteBySession(sessionId: string): Promise<number>;
|
|
@@ -160,16 +256,18 @@ export declare class TiDBTaskAttachmentStore implements TaskAttachmentStore {
|
|
|
160
256
|
private filterStillOrphan;
|
|
161
257
|
}
|
|
162
258
|
export declare class PgTaskAttachmentStore implements TaskAttachmentStore {
|
|
163
|
-
private readonly q;
|
|
164
259
|
private readonly bytes;
|
|
165
|
-
|
|
260
|
+
private readonly db;
|
|
261
|
+
private readonly q;
|
|
262
|
+
/** 收池:绑定({@link bindOnSql})走与 TiDB 孪生同一只驱动形({@link pgDriver})。 */
|
|
263
|
+
constructor(pool: PgPool, bytes: AttachmentBytesStore);
|
|
166
264
|
put(rec: TaskAttachmentRecord & {
|
|
167
265
|
content: Uint8Array;
|
|
168
266
|
}): Promise<void>;
|
|
169
267
|
get(owner: string, id: string): Promise<TaskAttachmentRecord | null>;
|
|
170
268
|
getContent(owner: string, id: string): Promise<Uint8Array | null>;
|
|
171
269
|
private deleteBytesIfUnreferenced;
|
|
172
|
-
bind(owner: string, ids: string[], sessionId: string, boundAtMs: number): Promise<
|
|
270
|
+
bind(owner: string, ids: readonly string[], sessionId: string, boundAtMs: number): Promise<AttachmentStoreBindOutcome>;
|
|
173
271
|
listBySession(sessionId: string): Promise<TaskAttachmentRecord[]>;
|
|
174
272
|
delete(owner: string, id: string): Promise<boolean>;
|
|
175
273
|
deleteBySession(sessionId: string): Promise<number>;
|