@byok-sdk/cloud-dataplane 0.8.0 → 0.9.0-rc.1

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.
@@ -0,0 +1,134 @@
1
+ -- 0014_agent_memory_projection.sql — bounded hosted Agent-memory projection.
2
+ --
3
+ -- The head is one redacted, bounded snapshot per (tenant, agent). It is not a
4
+ -- transcript, audit log, or raw-source store: replacing it discards the prior
5
+ -- bytes in the same transaction that records the accepted metering receipt.
6
+ -- The receipt deliberately has no body column, so durable metering cannot
7
+ -- become a second content authority.
8
+
9
+ CREATE TABLE agent_memory_projection_head (
10
+ tenant_id text NOT NULL,
11
+ agent_id text NOT NULL,
12
+ writer_epoch integer NOT NULL,
13
+ source_seq integer NOT NULL,
14
+ mutation_id uuid NOT NULL,
15
+ device_id text NOT NULL,
16
+ task_id text NOT NULL,
17
+ agent_profile_revision text NOT NULL,
18
+ session_ref text NOT NULL,
19
+ runtime_id text NOT NULL,
20
+ grant_ref text NOT NULL,
21
+ policy_revision text NOT NULL,
22
+ redacted_hash text NOT NULL,
23
+ redacted_snapshot bytea NOT NULL,
24
+ redacted_byte_count integer NOT NULL,
25
+ committed_at timestamptz NOT NULL,
26
+ PRIMARY KEY (tenant_id, agent_id),
27
+ CONSTRAINT agent_memory_projection_head_epoch_positive
28
+ CHECK (writer_epoch > 0),
29
+ CONSTRAINT agent_memory_projection_head_seq_positive
30
+ CHECK (source_seq > 0),
31
+ CONSTRAINT agent_memory_projection_head_snapshot_bounded
32
+ CHECK (
33
+ redacted_byte_count >= 0
34
+ AND redacted_byte_count <= 524288
35
+ AND octet_length(redacted_snapshot) = redacted_byte_count
36
+ ),
37
+ CONSTRAINT agent_memory_projection_head_hash_shape
38
+ CHECK (redacted_hash ~ '^sha256:[a-f0-9]{64}$'),
39
+ CONSTRAINT agent_memory_projection_head_agent_bounded
40
+ CHECK (
41
+ octet_length(agent_id) BETWEEN 1 AND 160
42
+ AND agent_id !~ '[[:cntrl:]]'
43
+ AND octet_length(agent_profile_revision) BETWEEN 1 AND 160
44
+ AND agent_profile_revision !~ '[[:cntrl:]]'
45
+ ),
46
+ CONSTRAINT agent_memory_projection_head_binding_bounded
47
+ CHECK (
48
+ octet_length(device_id) BETWEEN 1 AND 160
49
+ AND device_id !~ '[[:cntrl:]]'
50
+ AND octet_length(task_id) BETWEEN 1 AND 2048
51
+ AND octet_length(session_ref) BETWEEN 1 AND 512
52
+ AND session_ref !~ '[[:cntrl:]]'
53
+ AND octet_length(runtime_id) BETWEEN 1 AND 160
54
+ AND runtime_id !~ '[[:cntrl:]]'
55
+ AND octet_length(grant_ref) BETWEEN 1 AND 512
56
+ AND grant_ref !~ '[[:cntrl:]]'
57
+ AND octet_length(policy_revision) BETWEEN 1 AND 160
58
+ AND policy_revision !~ '[[:cntrl:]]'
59
+ )
60
+ );
61
+
62
+ -- Metering retains immutable acceptance facts but no body. A sequence key is
63
+ -- unique within one writer epoch; mutation_id is independently unique there so
64
+ -- a reused mutation cannot silently account for two sequence positions.
65
+ CREATE TABLE agent_memory_projection_metering_receipt (
66
+ tenant_id text NOT NULL,
67
+ agent_id text NOT NULL,
68
+ writer_epoch integer NOT NULL,
69
+ source_seq integer NOT NULL,
70
+ mutation_id uuid NOT NULL,
71
+ device_id text NOT NULL,
72
+ task_id text NOT NULL,
73
+ agent_profile_revision text NOT NULL,
74
+ session_ref text NOT NULL,
75
+ runtime_id text NOT NULL,
76
+ grant_ref text NOT NULL,
77
+ policy_revision text NOT NULL,
78
+ redacted_hash text NOT NULL,
79
+ redacted_byte_count integer NOT NULL,
80
+ metering_receipt_id uuid NOT NULL,
81
+ recorded_at timestamptz NOT NULL,
82
+ PRIMARY KEY (tenant_id, agent_id, writer_epoch, source_seq),
83
+ UNIQUE (tenant_id, agent_id, writer_epoch, mutation_id),
84
+ CONSTRAINT agent_memory_projection_metering_epoch_positive
85
+ CHECK (writer_epoch > 0),
86
+ CONSTRAINT agent_memory_projection_metering_seq_positive
87
+ CHECK (source_seq > 0),
88
+ CONSTRAINT agent_memory_projection_metering_bytes_bounded
89
+ CHECK (redacted_byte_count >= 0 AND redacted_byte_count <= 524288),
90
+ CONSTRAINT agent_memory_projection_metering_hash_shape
91
+ CHECK (redacted_hash ~ '^sha256:[a-f0-9]{64}$'),
92
+ CONSTRAINT agent_memory_projection_metering_agent_bounded
93
+ CHECK (
94
+ octet_length(agent_id) BETWEEN 1 AND 160
95
+ AND agent_id !~ '[[:cntrl:]]'
96
+ AND octet_length(agent_profile_revision) BETWEEN 1 AND 160
97
+ AND agent_profile_revision !~ '[[:cntrl:]]'
98
+ ),
99
+ CONSTRAINT agent_memory_projection_metering_binding_bounded
100
+ CHECK (
101
+ octet_length(device_id) BETWEEN 1 AND 160
102
+ AND device_id !~ '[[:cntrl:]]'
103
+ AND octet_length(task_id) BETWEEN 1 AND 2048
104
+ AND octet_length(session_ref) BETWEEN 1 AND 512
105
+ AND session_ref !~ '[[:cntrl:]]'
106
+ AND octet_length(runtime_id) BETWEEN 1 AND 160
107
+ AND runtime_id !~ '[[:cntrl:]]'
108
+ AND octet_length(grant_ref) BETWEEN 1 AND 512
109
+ AND grant_ref !~ '[[:cntrl:]]'
110
+ AND octet_length(policy_revision) BETWEEN 1 AND 160
111
+ AND policy_revision !~ '[[:cntrl:]]'
112
+ )
113
+ );
114
+
115
+ CREATE INDEX agent_memory_projection_metering_receipt_readback
116
+ ON agent_memory_projection_metering_receipt (tenant_id, agent_id, writer_epoch, source_seq);
117
+
118
+ -- Server-side erase deletes the only body and all immutable receipts, but it
119
+ -- must leave one body-free epoch fence. A stale local outbox cannot re-enter
120
+ -- after deletion and make an empty head accept an old writer's later sequence.
121
+ CREATE TABLE agent_memory_projection_erase_fence (
122
+ tenant_id text NOT NULL,
123
+ agent_id text NOT NULL,
124
+ next_writer_epoch integer NOT NULL,
125
+ erased_at timestamptz NOT NULL,
126
+ PRIMARY KEY (tenant_id, agent_id),
127
+ CONSTRAINT agent_memory_projection_erase_fence_epoch_positive
128
+ CHECK (next_writer_epoch > 0),
129
+ CONSTRAINT agent_memory_projection_erase_fence_agent_bounded
130
+ CHECK (
131
+ octet_length(agent_id) BETWEEN 1 AND 160
132
+ AND agent_id !~ '[[:cntrl:]]'
133
+ )
134
+ );
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Postgres authority for the optional, one-way hosted Agent-memory projection.
3
+ *
4
+ * The only stored body is the latest accepted redacted snapshot. Immutable
5
+ * receipt rows retain the complete non-body replay binding and byte metering so
6
+ * an old exact retry is still provable after the head advances or an epoch is
7
+ * superseded. Neither table has a raw-source hash, cwd, path, or audit body.
8
+ */
9
+ import { type AgentMemoryProjectionCommitInput, type AgentMemoryProjectionEraseResult, type AgentMemoryProjectionReceipt, type AgentMemoryProjectionStore, type CloudCrypto } from '@byok-sdk/cloud';
10
+ import type { Clock, TenantId } from '@byok-sdk/core';
11
+ import type { Pool } from 'pg';
12
+ export interface PostgresAgentMemoryProjectionStoreOptions {
13
+ readonly pool: Pool;
14
+ readonly clock: Clock;
15
+ /** The same Worker-safe crypto authority used by the hosting cloud composition. */
16
+ readonly crypto: Pick<CloudCrypto, 'randomUuid' | 'sha256'>;
17
+ }
18
+ /**
19
+ * A transaction-scoped Postgres projection store. The per-source advisory lock
20
+ * closes the empty-head race without creating a separate lock row or making a
21
+ * tenant-wide writer bottleneck; erase takes the identical lock.
22
+ */
23
+ export declare class PostgresAgentMemoryProjectionStore implements AgentMemoryProjectionStore {
24
+ #private;
25
+ constructor(options: PostgresAgentMemoryProjectionStoreOptions);
26
+ commit(input: AgentMemoryProjectionCommitInput): Promise<AgentMemoryProjectionReceipt>;
27
+ /** Delete body/receipts but retain a body-free epoch fence under one source lock. */
28
+ erase(input: {
29
+ readonly tenantId: TenantId;
30
+ readonly agentId: string;
31
+ }): Promise<AgentMemoryProjectionEraseResult>;
32
+ }
33
+ /** Build the runtime-safe Postgres implementation of the optional cloud port. */
34
+ export declare function createPostgresAgentMemoryProjectionStore(options: PostgresAgentMemoryProjectionStoreOptions): AgentMemoryProjectionStore;
@@ -35,6 +35,8 @@ export { PostgresTaskCancellationStore } from './task-cancellations';
35
35
  export { PostgresActivityStore } from './activity';
36
36
  export { PostgresApprovalTimelineStore } from './approval-timeline';
37
37
  export { PostgresAgentEgressStore } from './agent-egress';
38
+ export { PostgresAgentMemoryProjectionStore, createPostgresAgentMemoryProjectionStore, } from './agent-memory-projection';
39
+ export type { PostgresAgentMemoryProjectionStoreOptions } from './agent-memory-projection';
38
40
  export { PostgresDeviceAssertionReplayAuthority } from './device-assertion-replay';
39
41
  export { DEFAULT_MAX_ATTEMPTS, DEFAULT_PRESIGN_TTL_SECONDS, DEFAULT_RETRY_DELAY_MS, MAX_PRESIGN_TTL_SECONDS, MIN_PRESIGN_TTL_SECONDS, ObjectStoreRequestError, R2_BLOB_ERROR_CODES, R2BlobStoreError, R2CloudBlobStore, R2ObjectMaintenanceStore, } from './r2-blobs';
40
42
  export type { ObjectStoreFetch, R2BlobErrorCode, R2BlobStoreOptions } from './r2-blobs';
@@ -1,8 +1,8 @@
1
1
  import { type Clock, type TenantId } from '@byok-sdk/core';
2
2
  import type { Pool } from 'pg';
3
3
  import { type R2BlobStoreOptions, type R2ObjectMaintenance } from './stores/r2-blobs';
4
- /** Every tenant-owned table as of 0013, in child-before-parent deletion order. */
5
- export declare const TENANT_ERASURE_TABLES: readonly ['object_reference', 'object_manifest', 'storage_reservation', 'storage_usage', 'storage_entitlement', 'gc_cursor', 'cleanup_job', 'tenant_retention_policy', 'skill_pack_file', 'skill_pack', 'approval_timeline_tail', 'activity_tail', 'attested_record', 'board_item', 'tenant_stream', 'outbox', 'agent_egress_event', 'device_request_receipts', 'proof_request_receipt', 'task', 'device_presence', 'device_assertion_replay', 'device_stream', 'inbound_dedup', 'auth_nonce', 'pairing_code', 'device'];
4
+ /** Every tenant-owned table as of 0014, in child-before-parent deletion order. */
5
+ export declare const TENANT_ERASURE_TABLES: readonly ['object_reference', 'object_manifest', 'storage_reservation', 'storage_usage', 'storage_entitlement', 'gc_cursor', 'cleanup_job', 'tenant_retention_policy', 'skill_pack_file', 'skill_pack', 'approval_timeline_tail', 'activity_tail', 'attested_record', 'board_item', 'tenant_stream', 'outbox', 'agent_memory_projection_metering_receipt', 'agent_memory_projection_head', 'agent_memory_projection_erase_fence', 'agent_egress_event', 'device_request_receipts', 'proof_request_receipt', 'task', 'device_presence', 'device_assertion_replay', 'device_stream', 'inbound_dedup', 'auth_nonce', 'pairing_code', 'device'];
6
6
  export declare const TENANT_ERASURE_ERROR_CODES: {
7
7
  readonly tenant_erasure_invalid_input: 'tenant_erasure_invalid_input';
8
8
  readonly tenant_erasure_schema_drift: 'tenant_erasure_schema_drift';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byok-sdk/cloud-dataplane",
3
- "version": "0.8.0",
3
+ "version": "0.9.0-rc.1",
4
4
  "description": "BYOK SDK hosted data plane: canonical Postgres + R2 stores, migrations, truth transactions, and maintenance",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -49,9 +49,9 @@
49
49
  "clean": "rm -rf dist"
50
50
  },
51
51
  "dependencies": {
52
- "@byok-sdk/cloud": "0.8.0",
53
- "@byok-sdk/core": "0.8.0",
54
- "@byok-sdk/protocol": "0.8.0",
52
+ "@byok-sdk/cloud": "0.9.0-rc.1",
53
+ "@byok-sdk/core": "0.9.0-rc.1",
54
+ "@byok-sdk/protocol": "0.9.0-rc.1",
55
55
  "aws4fetch": "1.0.20",
56
56
  "fast-xml-parser": "^5.10.1",
57
57
  "pg": "^8.22.0"