@byok-sdk/cloud-dataplane 0.6.0 → 0.6.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,41 @@
1
+ -- 0012_agent_home_contract.sql — durable Agent capability and attempt identity.
2
+ --
3
+ -- Additive only. Existing legacy device/task rows remain valid with NULL
4
+ -- Agent fields and therefore cannot accidentally acquire Agent semantics.
5
+ -- The hosted gate treats a NULL capability snapshot as unknown and refuses an
6
+ -- Agent offer before either a mailbox row or a task attempt is created.
7
+
8
+ ALTER TABLE device
9
+ ADD COLUMN capabilities jsonb;
10
+
11
+ ALTER TABLE device
12
+ ADD CONSTRAINT device_capabilities_shape
13
+ CHECK (capabilities IS NULL OR jsonb_typeof(capabilities) = 'array');
14
+
15
+ ALTER TABLE task
16
+ ADD COLUMN agent_id text,
17
+ ADD COLUMN agent_profile_revision text,
18
+ ADD COLUMN terminal_cause text;
19
+
20
+ ALTER TABLE task
21
+ ADD CONSTRAINT task_agent_ref_pair
22
+ CHECK ((agent_id IS NULL) = (agent_profile_revision IS NULL));
23
+
24
+ ALTER TABLE task
25
+ ADD CONSTRAINT task_agent_ref_bounded
26
+ CHECK (
27
+ agent_id IS NULL
28
+ OR (
29
+ octet_length(agent_id) BETWEEN 1 AND 160
30
+ AND octet_length(agent_profile_revision) BETWEEN 1 AND 160
31
+ AND position('/' IN agent_id) = 0
32
+ AND position(E'\\' IN agent_id) = 0
33
+ AND position(':' IN agent_id) = 0
34
+ AND agent_id !~ '[<>"|?*]'
35
+ AND agent_id NOT IN ('.', '..')
36
+ AND agent_id !~ '[. ]$'
37
+ AND lower(split_part(agent_id, '.', 1)) !~ '^(con|prn|aux|nul|com[1-9]|lpt[1-9])$'
38
+ AND agent_id !~ '[[:cntrl:]]'
39
+ AND agent_profile_revision !~ '[[:cntrl:]]'
40
+ )
41
+ );
@@ -0,0 +1,47 @@
1
+ -- 0013_agent_egress_contract.sql — first-write-wins reliable Agent egress facts.
2
+ --
3
+ -- The typed policy never authorizes raw workspace/transcript/artifact bytes to
4
+ -- this table. `payload_json` is the daemon's sanitized JSON projection; exact
5
+ -- AgentRef, session, cursor, content hash, and cloud receipt identity remain
6
+ -- independently addressable so a readback never has to reinterpret an opaque
7
+ -- envelope body.
8
+
9
+ CREATE TABLE agent_egress_event (
10
+ tenant_id text NOT NULL,
11
+ device_id text NOT NULL,
12
+ event_id uuid NOT NULL,
13
+ agent_id text NOT NULL,
14
+ agent_profile_revision text NOT NULL,
15
+ session_ref text NOT NULL,
16
+ policy_revision text NOT NULL,
17
+ cursor bigint NOT NULL,
18
+ payload_json jsonb NOT NULL,
19
+ content_hash text NOT NULL,
20
+ byte_count integer NOT NULL,
21
+ receipt_id uuid NOT NULL,
22
+ recorded_at timestamptz NOT NULL,
23
+ PRIMARY KEY (tenant_id, device_id, event_id),
24
+ CONSTRAINT agent_egress_event_cursor_positive CHECK (cursor > 0 AND cursor <= 2147483647),
25
+ CONSTRAINT agent_egress_event_byte_count CHECK (byte_count >= 0 AND byte_count <= 262144),
26
+ CONSTRAINT agent_egress_event_hash_shape CHECK (content_hash ~ '^sha256:[a-f0-9]{64}$'),
27
+ CONSTRAINT agent_egress_event_agent_ref_bounded CHECK (
28
+ octet_length(agent_id) BETWEEN 1 AND 160
29
+ AND octet_length(agent_profile_revision) BETWEEN 1 AND 160
30
+ AND agent_id !~ '[[:cntrl:]]'
31
+ AND agent_profile_revision !~ '[[:cntrl:]]'
32
+ ),
33
+ CONSTRAINT agent_egress_event_session_bounded CHECK (
34
+ octet_length(session_ref) BETWEEN 1 AND 512
35
+ AND session_ref !~ '[[:cntrl:]]'
36
+ ),
37
+ CONSTRAINT agent_egress_event_policy_bounded CHECK (
38
+ octet_length(policy_revision) BETWEEN 1 AND 160
39
+ AND policy_revision !~ '[[:cntrl:]]'
40
+ )
41
+ );
42
+
43
+ -- Readback and operational inspection preserve the same tenant/device/session
44
+ -- partition as the wire cursor. This is intentionally not unique: event id is
45
+ -- the reliable idempotency authority, and cursor is an exact observation.
46
+ CREATE INDEX agent_egress_event_cursor_idx
47
+ ON agent_egress_event (tenant_id, device_id, agent_id, agent_profile_revision, session_ref, cursor);
@@ -0,0 +1,14 @@
1
+ import type { AgentEgressRecord, AgentEgressStore } from '@byok-sdk/cloud';
2
+ import type { Clock, TenantId } from '@byok-sdk/core';
3
+ import type { Pool } from 'pg';
4
+ /** Postgres implementation of the immutable reliable Agent egress receipt fact. */
5
+ export declare class PostgresAgentEgressStore implements AgentEgressStore {
6
+ private readonly pool;
7
+ private readonly clock;
8
+ constructor(pool: Pool, clock: Clock);
9
+ record(tenant: TenantId, input: Omit<AgentEgressRecord, 'tenantId' | 'recordedAt'>): Promise<{
10
+ readonly record: AgentEgressRecord;
11
+ readonly created: boolean;
12
+ }>;
13
+ get(tenant: TenantId, deviceId: string, eventId: string): Promise<AgentEgressRecord | undefined>;
14
+ }
@@ -18,6 +18,10 @@ export declare class PostgresDeviceDirectory implements DeviceDirectory {
18
18
  register(tenant: TenantId, input: DeviceRegistration): Promise<DeviceRecord>;
19
19
  get(tenant: TenantId, deviceId: string): Promise<DeviceRecord | undefined>;
20
20
  revoke(tenant: TenantId, deviceId: string): Promise<void>;
21
+ recordCapabilities(tenant: TenantId, input: {
22
+ readonly deviceId: string;
23
+ readonly capabilities: readonly string[];
24
+ }): Promise<DeviceRecord | undefined>;
21
25
  list(tenant: TenantId): Promise<readonly DeviceRecord[]>;
22
26
  readiness(tenant: TenantId, _presence: PresenceStore): Promise<TenantReadiness>;
23
27
  resolveByDeviceId(deviceId: string): Promise<DeviceRecord | undefined>;
@@ -34,11 +34,12 @@ export { PostgresTaskAttemptStore } from './task-attempts';
34
34
  export { PostgresTaskCancellationStore } from './task-cancellations';
35
35
  export { PostgresActivityStore } from './activity';
36
36
  export { PostgresApprovalTimelineStore } from './approval-timeline';
37
+ export { PostgresAgentEgressStore } from './agent-egress';
37
38
  export { PostgresDeviceAssertionReplayAuthority } from './device-assertion-replay';
38
39
  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';
39
40
  export type { ObjectStoreFetch, R2BlobErrorCode, R2BlobStoreOptions } from './r2-blobs';
40
41
  export type { R2DeleteResult, R2ListedObject, R2ObjectMaintenance, R2ObjectMaintenanceOptions, R2ObjectPage, } from './r2-blobs';
41
- /** Every cloud-local port. All eleven, or it is not a composition. */
42
+ /** Every cloud-local port. All twelve, or it is not a composition. */
42
43
  export type PostgresCloudStores = CloudStores;
43
44
  /** Everything the blob store needs that is not already a composition-wide input. */
44
45
  export type PostgresObjectStorageOptions = Omit<R2BlobStoreOptions, 'objects'>;
@@ -14,21 +14,24 @@
14
14
  * `claim` and `recordStatus` on a task this tenant never offered write nothing
15
15
  * and return `undefined`.
16
16
  */
17
- import type { TaskAttempt, TaskAttemptStatus, TaskAttemptStore } from '@byok-sdk/cloud';
17
+ import type { AgentRef, TaskAttempt, TaskAttemptStatus, TaskAttemptStore } from '@byok-sdk/cloud';
18
18
  import type { Clock, TenantId } from '@byok-sdk/core';
19
19
  import type { Pool } from 'pg';
20
20
  export interface TaskRow {
21
21
  readonly tenant_id: string;
22
22
  readonly task_id: string;
23
23
  readonly device_id: string;
24
+ readonly agent_id: string | null;
25
+ readonly agent_profile_revision: string | null;
24
26
  readonly owner_device_id: string | null;
25
27
  readonly status: string;
28
+ readonly terminal_cause: string | null;
26
29
  readonly cancel_requested_at: Date | null;
27
30
  readonly cancel_reason: string | null;
28
31
  readonly cancel_message_id: string | null;
29
32
  readonly updated_at: Date;
30
33
  }
31
- export declare const TASK_SELECT_COLUMNS = "tenant_id, task_id, device_id, owner_device_id, status, cancel_requested_at, cancel_reason, cancel_message_id, updated_at";
34
+ export declare const TASK_SELECT_COLUMNS = "tenant_id, task_id, device_id, agent_id, agent_profile_revision, owner_device_id, status, terminal_cause, cancel_requested_at, cancel_reason, cancel_message_id, updated_at";
32
35
  export declare function taskRowToAttempt(row: TaskRow): TaskAttempt;
33
36
  export declare class PostgresTaskAttemptStore implements TaskAttemptStore {
34
37
  #private;
@@ -36,7 +39,16 @@ export declare class PostgresTaskAttemptStore implements TaskAttemptStore {
36
39
  open(tenant: TenantId, input: {
37
40
  readonly taskId: string;
38
41
  readonly deviceId: string;
42
+ readonly agentRef?: AgentRef;
39
43
  }): Promise<TaskAttempt>;
44
+ reserveAgentOffer(tenant: TenantId, input: {
45
+ readonly taskId: string;
46
+ readonly deviceId: string;
47
+ readonly agentRef: AgentRef;
48
+ }): Promise<{
49
+ readonly attempt: TaskAttempt;
50
+ readonly created: boolean;
51
+ }>;
40
52
  get(tenant: TenantId, taskId: string): Promise<TaskAttempt | undefined>;
41
53
  getMany(tenant: TenantId, taskIds: readonly string[]): Promise<readonly TaskAttempt[]>;
42
54
  claim(tenant: TenantId, input: {
@@ -46,5 +58,7 @@ export declare class PostgresTaskAttemptStore implements TaskAttemptStore {
46
58
  recordStatus(tenant: TenantId, input: {
47
59
  readonly taskId: string;
48
60
  readonly status: TaskAttemptStatus;
61
+ readonly agentRef?: AgentRef;
62
+ readonly terminalCause?: string;
49
63
  }): Promise<TaskAttempt | undefined>;
50
64
  }
@@ -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 0010, 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', '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 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'];
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.6.0",
3
+ "version": "0.6.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.6.0",
53
- "@byok-sdk/core": "0.6.0",
54
- "@byok-sdk/protocol": "0.6.0",
52
+ "@byok-sdk/cloud": "0.6.1",
53
+ "@byok-sdk/core": "0.6.1",
54
+ "@byok-sdk/protocol": "0.6.1",
55
55
  "aws4fetch": "1.0.20",
56
56
  "fast-xml-parser": "^5.10.1",
57
57
  "pg": "^8.22.0"