@consiliency/agent-board-schema 1.2.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.
Files changed (92) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +11 -0
  3. package/README.md +55 -0
  4. package/bin/agent-board-schema.js +97 -0
  5. package/fixtures/already-applied.json +181 -0
  6. package/fixtures/divergent-history.json +173 -0
  7. package/fixtures/production-history.json +173 -0
  8. package/migrations/20260501000001_agent_board_schema_version.sql +12 -0
  9. package/migrations/20260502000000_agent_board_schema.sql +180 -0
  10. package/migrations/20260503000000_agent_board_rpcs.sql +422 -0
  11. package/migrations/20260503000001_agent_board_coordination_rpcs.sql +229 -0
  12. package/migrations/20260504000000_agent_board_read_models.sql +206 -0
  13. package/migrations/20260505000000_agent_board_inbox_schema.sql +341 -0
  14. package/migrations/20260506000000_agent_board_inbox_delivery_rpcs.sql +1200 -0
  15. package/migrations/20260506000001_agent_board_inbox_callback_rpcs.sql +330 -0
  16. package/migrations/20260507000000_agent_board_inbox_reads.sql +334 -0
  17. package/migrations/20260508000000_agent_board_callback_runtime.sql +453 -0
  18. package/migrations/20260508000001_agent_board_inbox_service_role_reads.sql +10 -0
  19. package/migrations/20260510000000_agent_board_dblint_repairs.sql +413 -0
  20. package/migrations/20260511000000_agent_board_auth_schema.sql +146 -0
  21. package/migrations/20260511000001_agent_board_auth_credentials.sql +39 -0
  22. package/migrations/20260512000000_agent_board_auth_provisioning_rpcs.sql +622 -0
  23. package/migrations/20260512000001_agent_board_auth_v1_rpcs.sql +798 -0
  24. package/migrations/20260512000002_agent_board_auth_v2_rpcs.sql +1243 -0
  25. package/migrations/20260512000003_agent_board_auth_rls.sql +484 -0
  26. package/migrations/20260513000000_agent_board_backup_ops.sql +34 -0
  27. package/migrations/20260513000001_agent_board_retention.sql +160 -0
  28. package/migrations/20260513000002_agent_board_monitoring_views.sql +227 -0
  29. package/migrations/20260514000000_agent_board_auth_rls_id_qualification.sql +150 -0
  30. package/migrations/20260515000000_agent_board_boardopt.sql +493 -0
  31. package/migrations/20260516000000_agent_board_callbackcap.sql +113 -0
  32. package/migrations/20260517000000_agent_board_addressing.sql +542 -0
  33. package/migrations/20260628000000_agent_board_signing_store.sql +174 -0
  34. package/migrations/20260628000001_agent_board_signing_proof_rpcs.sql +215 -0
  35. package/migrations/20260628000002_agent_board_signature_rls_reads.sql +300 -0
  36. package/migrations/20260628000003_agent_board_signed_write_gateway.sql +288 -0
  37. package/migrations/20260628000004_agent_board_fleet_registry.sql +411 -0
  38. package/migrations/20260628000005_agent_board_fleet_policy.sql +509 -0
  39. package/migrations/20260628000006_agent_board_fleet_read_models.sql +170 -0
  40. package/migrations/20260629000100_agent_board_fleet_registry_repair.sql +411 -0
  41. package/migrations/20260629000101_agent_board_fleet_policy_refresh.sql +509 -0
  42. package/migrations/20260629000102_agent_board_fleet_read_models_refresh.sql +170 -0
  43. package/migrations/20260630000100_agent_board_harness_kind_open_vocab.sql +15 -0
  44. package/migrations/20260710000000_agent_board_authbound_boundary.sql +155 -0
  45. package/migrations/20260710000100_agent_board_schema_version_rpc.sql +14 -0
  46. package/migrations/20260710000400_agent_board_nonfleet_identity.sql +87 -0
  47. package/migrations/20260710000401_agent_board_workload_providers.sql +39 -0
  48. package/migrations/20260711000000_agent_board_provision_system_fail_closed.sql +242 -0
  49. package/migrations/20260711000100_canary_signed_fleet_enforcement.sql +234 -0
  50. package/migrations/20260712000000_agent_board_bundle_endpoint_compat.sql +97 -0
  51. package/migrations/20260713000000_agent_board_rls_reassert_board_scoping.sql +90 -0
  52. package/package.json +42 -0
  53. package/provenance.json +580 -0
  54. package/schema-manifest.json +458 -0
  55. package/src/check.js +23 -0
  56. package/src/index.js +50 -0
  57. package/src/materialize.js +73 -0
  58. package/src/plan.js +44 -0
  59. package/src/tooling.test.mjs +97 -0
  60. package/tests/agent_board_addressing.test.sql +166 -0
  61. package/tests/agent_board_auth_rls.test.sql +243 -0
  62. package/tests/agent_board_auth_rls_id_qualification.test.sql +225 -0
  63. package/tests/agent_board_auth_rpcs.test.sql +311 -0
  64. package/tests/agent_board_auth_schema.test.sql +411 -0
  65. package/tests/agent_board_authbound_boundary.test.sql +148 -0
  66. package/tests/agent_board_boardopt.test.sql +170 -0
  67. package/tests/agent_board_bundle_endpoint_compat.test.sql +49 -0
  68. package/tests/agent_board_callback_runtime.test.sql +425 -0
  69. package/tests/agent_board_callbackcap.test.sql +222 -0
  70. package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +60 -0
  71. package/tests/agent_board_dblint_rpcs.test.sql +247 -0
  72. package/tests/agent_board_fleet_policy.test.sql +370 -0
  73. package/tests/agent_board_fleet_read_models.test.sql +158 -0
  74. package/tests/agent_board_fleet_registry.test.sql +149 -0
  75. package/tests/agent_board_inbox_reads.test.sql +471 -0
  76. package/tests/agent_board_inbox_rpcs.test.sql +452 -0
  77. package/tests/agent_board_inbox_schema.test.sql +355 -0
  78. package/tests/agent_board_nonfleet_identity.test.sql +26 -0
  79. package/tests/agent_board_rls_reassert_board_scoping.test.sql +39 -0
  80. package/tests/agent_board_schema_version.test.sql +24 -0
  81. package/tests/agent_board_schema_version_rpc.test.sql +40 -0
  82. package/tests/agent_board_signature_rls_reads.test.sql +133 -0
  83. package/tests/agent_board_signed_write_gateway.test.sql +219 -0
  84. package/tests/agent_board_signing_proof_rpcs.test.sql +143 -0
  85. package/tests/agent_board_signing_store.test.sql +183 -0
  86. package/tests/agent_board_smoke.test.sql +12 -0
  87. package/tests/agent_board_v1_invariants.test.sql +298 -0
  88. package/tests/agent_board_v2_invariants.test.sql +753 -0
  89. package/tests/agent_board_workload_providers.test.sql +15 -0
  90. package/tests/fixtures/adopter-base.sql +19 -0
  91. package/tests/fixtures/operator-hardening.sql +27 -0
  92. package/tests/fixtures/test-prereqs.sql +84 -0
@@ -0,0 +1,170 @@
1
+ create extension if not exists pgtap with schema extensions;
2
+ set search_path = extensions, public, agent_board;
3
+
4
+ begin;
5
+
6
+ select plan(9);
7
+
8
+ create temp table _boardopt_fixture (
9
+ user_reader uuid,
10
+ agent_owner uuid,
11
+ agent_reader uuid,
12
+ board_open uuid,
13
+ board_invite uuid,
14
+ board_private uuid,
15
+ board_hidden uuid,
16
+ thread_id uuid
17
+ ) on commit drop;
18
+ grant all on table _boardopt_fixture to authenticated, service_role;
19
+
20
+ do $$
21
+ declare
22
+ v_suffix text := replace(substr(gen_random_uuid()::text, 1, 8), '-', '');
23
+ v_user_owner uuid;
24
+ v_user_reader uuid;
25
+ v_agent_owner uuid := gen_random_uuid();
26
+ v_agent_reader uuid := gen_random_uuid();
27
+ v_thread uuid := gen_random_uuid();
28
+ v_open uuid;
29
+ v_invite uuid;
30
+ v_private uuid;
31
+ v_hidden uuid;
32
+ begin
33
+ v_user_owner := public.ensure_github_user(
34
+ 'boardopt-owner-' || v_suffix,
35
+ 'boardopt-owner-' || v_suffix || '@example.test',
36
+ 'boardopt-owner-' || v_suffix,
37
+ 'BOARDOPT Owner ' || v_suffix
38
+ );
39
+ v_user_reader := public.ensure_github_user(
40
+ 'boardopt-reader-' || v_suffix,
41
+ 'boardopt-reader-' || v_suffix || '@example.test',
42
+ 'boardopt-reader-' || v_suffix,
43
+ 'BOARDOPT Reader ' || v_suffix
44
+ );
45
+
46
+ insert into agent_board.agents(id, agent_type, kind, handle, display_name, status, auth_user_id, owner_user_id)
47
+ values
48
+ (v_agent_owner, 'agent', 'agent', 'boardopt-owner-' || v_suffix, 'BOARDOPT Owner', 'active', v_user_owner, v_user_owner),
49
+ (v_agent_reader, 'agent', 'agent', 'boardopt-reader-' || v_suffix, 'BOARDOPT Reader', 'active', v_user_reader, v_user_reader);
50
+
51
+ insert into agent_board.threads(id, thread_type, created_by_agent_id, subject)
52
+ values (v_thread, 'coordination', v_agent_owner, 'BOARDOPT thread');
53
+
54
+ select board_id into v_open
55
+ from agent_board.create_board(v_agent_owner, 'boardopt-open-' || v_suffix, 'BOARDOPT Open', 'open directory board', '{}'::jsonb, 'open');
56
+ select board_id into v_invite
57
+ from agent_board.create_board(v_agent_owner, 'boardopt-invite-' || v_suffix, 'BOARDOPT Invite', 'invite board', '{}'::jsonb, 'invite_only');
58
+ select board_id into v_private
59
+ from agent_board.create_board(v_agent_owner, 'boardopt-private-' || v_suffix, 'BOARDOPT Private', 'private board', '{}'::jsonb, 'private');
60
+ select board_id into v_hidden
61
+ from agent_board.create_board(v_agent_owner, 'boardopt-hidden-' || v_suffix, 'BOARDOPT Hidden', 'hidden board', '{}'::jsonb, 'directory_hidden');
62
+
63
+ perform agent_board.join_board(v_open, v_agent_owner, 'joined', v_agent_owner, '{}'::jsonb);
64
+ perform agent_board.invite_board_member(v_invite, v_agent_reader, v_agent_owner, '{}'::jsonb);
65
+
66
+ perform agent_board.post_board_message(
67
+ v_thread,
68
+ v_agent_owner,
69
+ v_open,
70
+ 'BOARDOPT pre-join post',
71
+ 'visible only after active membership',
72
+ 'comment',
73
+ 'medium',
74
+ 'boardopt-prejoin-' || v_suffix,
75
+ '{}'::jsonb
76
+ );
77
+
78
+ insert into _boardopt_fixture(user_reader, agent_owner, agent_reader, board_open, board_invite, board_private, board_hidden, thread_id)
79
+ values (v_user_reader, v_agent_owner, v_agent_reader, v_open, v_invite, v_private, v_hidden, v_thread);
80
+ end
81
+ $$;
82
+
83
+ select has_column('agent_board', 'boards', 'visibility', 'boards expose BOARDOPT visibility');
84
+ select col_has_check('agent_board', 'boards', 'visibility', 'boards visibility is check-constrained');
85
+ select col_has_check('agent_board', 'board_memberships', 'membership_state', 'board membership state includes BOARDOPT workflow values');
86
+
87
+ set local role authenticated;
88
+ select set_config('request.jwt.claim.role', 'authenticated', true);
89
+
90
+ do $$
91
+ declare
92
+ v_fixture record;
93
+ v_directory_count bigint;
94
+ v_feed_before bigint;
95
+ v_open_state text;
96
+ v_invite_state text;
97
+ v_feed_after bigint;
98
+ begin
99
+ select * into v_fixture from _boardopt_fixture;
100
+ perform set_config('request.jwt.claim.sub', v_fixture.user_reader::text, true);
101
+
102
+ select count(*) into v_directory_count
103
+ from agent_board.v_board_directory
104
+ where board_id in (
105
+ v_fixture.board_open,
106
+ v_fixture.board_invite,
107
+ v_fixture.board_private,
108
+ v_fixture.board_hidden
109
+ );
110
+ if v_directory_count <> 2 then
111
+ raise exception 'reader should discover open plus invited board only, saw %', v_directory_count;
112
+ end if;
113
+
114
+ select count(*) into v_feed_before
115
+ from agent_board.v_board_feed
116
+ where board_id = v_fixture.board_open;
117
+ if v_feed_before <> 0 then
118
+ raise exception 'open-board discovery exposed feed before active membership';
119
+ end if;
120
+
121
+ perform agent_board.request_join_board(v_fixture.board_open, v_fixture.agent_reader, '{}'::jsonb);
122
+ select membership_state into v_open_state
123
+ from agent_board.v_board_memberships
124
+ where board_id = v_fixture.board_open
125
+ and agent_id = v_fixture.agent_reader
126
+ limit 1;
127
+ if v_open_state <> 'requested' then
128
+ raise exception 'request-to-join should create requested state, got %', v_open_state;
129
+ end if;
130
+
131
+ perform agent_board.join_board(v_fixture.board_open, v_fixture.agent_reader, 'subscribed', v_fixture.agent_reader, '{}'::jsonb);
132
+ select membership_state into v_open_state
133
+ from agent_board.v_board_memberships
134
+ where board_id = v_fixture.board_open
135
+ and agent_id = v_fixture.agent_reader
136
+ limit 1;
137
+ if v_open_state <> 'subscribed' then
138
+ raise exception 'open-board join should activate subscribed state, got %', v_open_state;
139
+ end if;
140
+
141
+ perform agent_board.join_board(v_fixture.board_invite, v_fixture.agent_reader, 'joined', v_fixture.agent_reader, '{}'::jsonb);
142
+ select membership_state into v_invite_state
143
+ from agent_board.v_board_memberships
144
+ where board_id = v_fixture.board_invite
145
+ and agent_id = v_fixture.agent_reader
146
+ limit 1;
147
+ if v_invite_state <> 'joined' then
148
+ raise exception 'invite-only join should activate invited reader, got %', v_invite_state;
149
+ end if;
150
+
151
+ select count(*) into v_feed_after
152
+ from agent_board.v_board_feed
153
+ where board_id = v_fixture.board_open
154
+ and subject = 'BOARDOPT pre-join post';
155
+ if v_feed_after <> 1 then
156
+ raise exception 'active membership should expose board feed history, saw %', v_feed_after;
157
+ end if;
158
+ end
159
+ $$;
160
+
161
+ select pass('Directory discovery is limited to open and invited boards for user-scoped agents');
162
+ select pass('Discoverability does not expose board feed before active membership');
163
+ select pass('Request-to-join creates a pending requested row only');
164
+ select pass('Open-board self-join activates membership');
165
+ select pass('Invite-only join activates only after an invited row exists');
166
+ select pass('Active membership exposes board feed history');
167
+
168
+ select finish();
169
+
170
+ rollback;
@@ -0,0 +1,49 @@
1
+ begin;
2
+ select plan(12);
3
+
4
+ -- objects exist
5
+ select has_table('agent_board', 'bundle_installation', 'bundle_installation table exists');
6
+ select has_function('agent_board', 'get_bundle_compatibility', 'get_bundle_compatibility exists');
7
+ select has_function('agent_board', 'record_bundle_installation',
8
+ ARRAY['text','text','integer','text','text'], 'record_bundle_installation exists');
9
+
10
+ -- grants: compat health is authenticated + service_role; not anon
11
+ select ok(has_function_privilege('authenticated', 'agent_board.get_bundle_compatibility()', 'EXECUTE'),
12
+ 'authenticated can execute get_bundle_compatibility');
13
+ select ok(not has_function_privilege('anon', 'agent_board.get_bundle_compatibility()', 'EXECUTE'),
14
+ 'anon cannot execute get_bundle_compatibility');
15
+ select ok(not has_function_privilege('authenticated',
16
+ 'agent_board.record_bundle_installation(text,text,integer,text,text)', 'EXECUTE'),
17
+ 'authenticated cannot record installs (service_role only)');
18
+ select ok(has_function_privilege('service_role',
19
+ 'agent_board.record_bundle_installation(text,text,integer,text,text)', 'EXECUTE'),
20
+ 'service_role can record installs');
21
+
22
+ -- before any install: not ready, schema version still reported
23
+ select is((agent_board.get_bundle_compatibility() ->> 'ready'), 'false',
24
+ 'not ready before materializer records an install');
25
+ select is((agent_board.get_bundle_compatibility() ->> 'schema_version'), '7',
26
+ 'compatibility reports schema version 7');
27
+
28
+ -- signed-write enforcement posture is active (canary revoked direct writes)
29
+ select is((agent_board.get_bundle_compatibility() ->> 'signed_write_enforced'), 'true',
30
+ 'signed-write enforcement is reported active');
31
+
32
+ -- probe covers ALL four gated RPCs: re-granting EXECUTE on one of the OTHER
33
+ -- three (not send_direct_message) must flip enforcement to false.
34
+ grant execute on function agent_board.send_multicast_message(uuid, uuid, uuid[], text, text, text, text, text, jsonb) to authenticated;
35
+ select is((agent_board.get_bundle_compatibility() ->> 'signed_write_enforced'), 'false',
36
+ 'enforcement flips to false when any gated write RPC is re-granted to authenticated');
37
+
38
+ -- after the materializer records an install: ready + bundle identity present,
39
+ -- and no credential/row content leaks (only whitelisted keys)
40
+ select agent_board.record_bundle_installation('1.1.0', 'deadbeef', 7, 'abc123', 'receipt-1');
41
+ select is(
42
+ (agent_board.get_bundle_compatibility() ->> 'ready') || ':' ||
43
+ (agent_board.get_bundle_compatibility() ->> 'installed_bundle_version') || ':' ||
44
+ (agent_board.get_bundle_compatibility() ->> 'installed_bundle_digest'),
45
+ 'true:1.1.0:deadbeef',
46
+ 'ready + bundle identity reported after install record');
47
+
48
+ select * from finish();
49
+ rollback;
@@ -0,0 +1,425 @@
1
+ begin;
2
+
3
+ select plan(24);
4
+
5
+ select has_function(
6
+ 'agent_board',
7
+ 'claim_callback_outbox_events',
8
+ array['integer'],
9
+ 'claim_callback_outbox_events helper exists'
10
+ );
11
+ select has_function(
12
+ 'agent_board',
13
+ 'record_callback_delivery_success',
14
+ array['uuid', 'uuid', 'integer', 'jsonb'],
15
+ 'record_callback_delivery_success helper exists'
16
+ );
17
+ select has_function(
18
+ 'agent_board',
19
+ 'record_callback_delivery_retry',
20
+ array['uuid', 'uuid', 'integer', 'text', 'timestamp with time zone', 'jsonb'],
21
+ 'record_callback_delivery_retry helper exists'
22
+ );
23
+ select has_function(
24
+ 'agent_board',
25
+ 'record_callback_delivery_terminal_failure',
26
+ array['uuid', 'uuid', 'integer', 'text', 'jsonb'],
27
+ 'record_callback_delivery_terminal_failure helper exists'
28
+ );
29
+ select has_function(
30
+ 'agent_board',
31
+ 'disable_callback_delivery_endpoint',
32
+ array['uuid', 'uuid', 'text', 'text', 'jsonb'],
33
+ 'disable_callback_delivery_endpoint helper exists'
34
+ );
35
+
36
+ select ok(
37
+ (
38
+ select count(distinct routine_name) = 5
39
+ from information_schema.routine_privileges
40
+ where specific_schema = 'agent_board'
41
+ and routine_name in (
42
+ 'claim_callback_outbox_events',
43
+ 'record_callback_delivery_success',
44
+ 'record_callback_delivery_retry',
45
+ 'record_callback_delivery_terminal_failure',
46
+ 'disable_callback_delivery_endpoint'
47
+ )
48
+ and grantee = 'service_role'
49
+ and privilege_type = 'EXECUTE'
50
+ ),
51
+ 'service_role can execute the callback runtime helper surface'
52
+ );
53
+
54
+ create temporary table callback_runtime_claim_results (
55
+ outbox_event_id uuid not null,
56
+ attempt_number integer not null
57
+ ) on commit drop;
58
+
59
+ -- claim_callback_outbox_events polls the global ready queue. Neutralize
60
+ -- preexisting ready rows so this fixture controls the first claim on reused
61
+ -- local databases; the surrounding transaction rolls the isolation update back.
62
+ update agent_board.callback_outbox_events
63
+ set outbox_status = 'delivered',
64
+ delivered_at = coalesce(delivered_at, now()),
65
+ updated_at = now()
66
+ where outbox_status in ('pending', 'retryable')
67
+ and available_at <= now();
68
+
69
+ do $$
70
+ declare
71
+ v_sender uuid := gen_random_uuid();
72
+ v_recipient uuid := gen_random_uuid();
73
+ v_thread uuid := gen_random_uuid();
74
+ v_message uuid := gen_random_uuid();
75
+ v_delivery_recipient uuid;
76
+ v_inbox_item uuid;
77
+ v_endpoint uuid;
78
+ v_subscription uuid;
79
+ v_terminal_endpoint uuid;
80
+ v_terminal_subscription uuid;
81
+ v_disable_endpoint uuid;
82
+ v_disable_subscription uuid;
83
+ v_pending_outbox uuid;
84
+ v_success_outbox uuid;
85
+ v_retry_outbox uuid;
86
+ v_terminal_outbox uuid;
87
+ v_disable_outbox uuid;
88
+ v_claim record;
89
+ v_now timestamptz := now();
90
+ begin
91
+ insert into agent_board.agents(id, agent_type, handle, display_name)
92
+ values
93
+ (v_sender, 'agent', 'test_callback_runtime_sender', 'Callback Runtime Sender'),
94
+ (v_recipient, 'agent', 'test_callback_runtime_recipient', 'Callback Runtime Recipient');
95
+
96
+ insert into agent_board.threads(id, thread_type, created_by_agent_id, subject)
97
+ values (v_thread, 'coordination', v_sender, 'Callback runtime test thread');
98
+
99
+ insert into agent_board.messages(id, thread_id, author_agent_id, message_sequence, message_type, body)
100
+ values (v_message, v_thread, v_sender, 1, 'comment', 'callback runtime body');
101
+
102
+ insert into agent_board.delivery_recipients(delivery_mode, recipient_agent_id, source_kind, source_message_id)
103
+ values ('direct', v_recipient, 'message', v_message)
104
+ returning id into v_delivery_recipient;
105
+
106
+ insert into agent_board.inbox_items(
107
+ id,
108
+ delivery_recipient_id,
109
+ recipient_agent_id,
110
+ delivery_mode,
111
+ source_kind,
112
+ source_message_id,
113
+ subject,
114
+ preview,
115
+ priority,
116
+ action_state,
117
+ visible_in_inbox,
118
+ visible_in_board_feed,
119
+ fetch_descriptor
120
+ )
121
+ values (
122
+ gen_random_uuid(),
123
+ v_delivery_recipient,
124
+ v_recipient,
125
+ 'direct',
126
+ 'message',
127
+ v_message,
128
+ 'Callback runtime subject',
129
+ 'Callback runtime preview',
130
+ 'high',
131
+ 'new',
132
+ true,
133
+ false,
134
+ jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime')
135
+ )
136
+ returning id into v_inbox_item;
137
+
138
+ insert into agent_board.callback_endpoints(
139
+ id,
140
+ owner_agent_id,
141
+ endpoint_url,
142
+ endpoint_status,
143
+ verification_requested_at,
144
+ verified_at
145
+ )
146
+ values (
147
+ gen_random_uuid(),
148
+ v_recipient,
149
+ 'https://example.test/callback-runtime',
150
+ 'verified',
151
+ v_now,
152
+ v_now
153
+ )
154
+ returning id into v_endpoint;
155
+
156
+ insert into agent_board.callback_subscriptions(
157
+ id,
158
+ endpoint_id,
159
+ agent_id,
160
+ subscription_scope,
161
+ event_category,
162
+ subscription_status
163
+ )
164
+ values (
165
+ gen_random_uuid(),
166
+ v_endpoint,
167
+ v_recipient,
168
+ 'own_inbox',
169
+ 'inbox.item.delivered',
170
+ 'active'
171
+ )
172
+ returning id into v_subscription;
173
+
174
+ insert into agent_board.callback_endpoints(
175
+ id,
176
+ owner_agent_id,
177
+ endpoint_url,
178
+ endpoint_status,
179
+ verification_requested_at,
180
+ verified_at
181
+ )
182
+ values (
183
+ gen_random_uuid(),
184
+ v_recipient,
185
+ 'https://example.test/callback-runtime-disabled',
186
+ 'verified',
187
+ v_now,
188
+ v_now
189
+ )
190
+ returning id into v_disable_endpoint;
191
+
192
+ insert into agent_board.callback_endpoints(
193
+ id,
194
+ owner_agent_id,
195
+ endpoint_url,
196
+ endpoint_status,
197
+ verification_requested_at,
198
+ verified_at
199
+ )
200
+ values (
201
+ gen_random_uuid(),
202
+ v_recipient,
203
+ 'https://example.test/callback-runtime-terminal',
204
+ 'verified',
205
+ v_now,
206
+ v_now
207
+ )
208
+ returning id into v_terminal_endpoint;
209
+
210
+ insert into agent_board.callback_subscriptions(
211
+ id,
212
+ endpoint_id,
213
+ agent_id,
214
+ subscription_scope,
215
+ event_category,
216
+ subscription_status
217
+ )
218
+ values (
219
+ gen_random_uuid(),
220
+ v_disable_endpoint,
221
+ v_recipient,
222
+ 'own_inbox',
223
+ 'inbox.item.delivered',
224
+ 'active'
225
+ )
226
+ returning id into v_disable_subscription;
227
+
228
+ insert into agent_board.callback_subscriptions(
229
+ id,
230
+ endpoint_id,
231
+ agent_id,
232
+ subscription_scope,
233
+ event_category,
234
+ subscription_status
235
+ )
236
+ values (
237
+ gen_random_uuid(),
238
+ v_terminal_endpoint,
239
+ v_recipient,
240
+ 'own_inbox',
241
+ 'inbox.item.delivered',
242
+ 'active'
243
+ )
244
+ returning id into v_terminal_subscription;
245
+
246
+ insert into agent_board.callback_outbox_events(
247
+ id,
248
+ endpoint_id,
249
+ subscription_id,
250
+ recipient_agent_id,
251
+ inbox_item_id,
252
+ event_category,
253
+ delivery_mode,
254
+ source_kind,
255
+ source_message_id,
256
+ idempotency_key,
257
+ subject,
258
+ preview,
259
+ priority,
260
+ fetch_descriptor,
261
+ outbox_status,
262
+ available_at
263
+ )
264
+ values
265
+ (gen_random_uuid(), v_endpoint, v_subscription, v_recipient, v_inbox_item, 'inbox.item.delivered', 'direct', 'message', v_message, 'callback-runtime-pending', 'Callback runtime subject', 'Callback runtime preview', 'high', jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime'), 'pending', v_now - interval '5 minutes'),
266
+ (gen_random_uuid(), v_endpoint, v_subscription, v_recipient, v_inbox_item, 'inbox.item.delivered', 'direct', 'message', v_message, 'callback-runtime-success', 'Callback runtime subject', 'Callback runtime preview', 'high', jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime'), 'pending', v_now - interval '1 minute'),
267
+ (gen_random_uuid(), v_endpoint, v_subscription, v_recipient, v_inbox_item, 'inbox.item.delivered', 'direct', 'message', v_message, 'callback-runtime-retry', 'Callback runtime subject', 'Callback runtime preview', 'high', jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime'), 'pending', v_now - interval '1 minute'),
268
+ (gen_random_uuid(), v_terminal_endpoint, v_terminal_subscription, v_recipient, v_inbox_item, 'inbox.item.delivered', 'direct', 'message', v_message, 'callback-runtime-terminal', 'Callback runtime subject', 'Callback runtime preview', 'high', jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime'), 'pending', v_now - interval '1 minute'),
269
+ (gen_random_uuid(), v_disable_endpoint, v_disable_subscription, v_recipient, v_inbox_item, 'inbox.item.delivered', 'direct', 'message', v_message, 'callback-runtime-disable', 'Callback runtime subject', 'Callback runtime preview', 'high', jsonb_build_object('surface', 'thread', 'targetId', v_thread::text, 'view', 'agent_board.v_thread_feed', 'filters', jsonb_build_object(), 'reason', 'callback runtime'), 'pending', v_now - interval '1 minute');
270
+
271
+ select id into v_pending_outbox from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-pending';
272
+ select id into v_success_outbox from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-success';
273
+ select id into v_retry_outbox from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-retry';
274
+ select id into v_terminal_outbox from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-terminal';
275
+ select id into v_disable_outbox from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-disable';
276
+
277
+ select * into v_claim
278
+ from agent_board.claim_callback_outbox_events(1);
279
+
280
+ insert into callback_runtime_claim_results(outbox_event_id, attempt_number)
281
+ values (v_claim.outbox_event_id, v_claim.attempt_number);
282
+
283
+ perform agent_board.record_callback_delivery_success(v_success_outbox, v_endpoint, 202, jsonb_build_object('result', 'delivered'));
284
+ perform agent_board.record_callback_delivery_retry(
285
+ v_retry_outbox,
286
+ v_endpoint,
287
+ 503,
288
+ 'temporary upstream failure',
289
+ v_now + interval '5 minutes',
290
+ jsonb_build_object('retry', true)
291
+ );
292
+ perform agent_board.record_callback_delivery_terminal_failure(
293
+ v_terminal_outbox,
294
+ v_terminal_endpoint,
295
+ 404,
296
+ 'receiver rejected payload',
297
+ jsonb_build_object('terminal', true)
298
+ );
299
+ perform agent_board.disable_callback_delivery_endpoint(
300
+ v_disable_endpoint,
301
+ v_disable_outbox,
302
+ 'disablement threshold reached',
303
+ 'callback endpoint disabled after repeated terminal failures',
304
+ jsonb_build_object('disabledBy', 'runtime')
305
+ );
306
+ end;
307
+ $$;
308
+
309
+ select is(
310
+ (select outbox_event_id::text from callback_runtime_claim_results limit 1),
311
+ (select id::text from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-pending'),
312
+ 'claim_callback_outbox_events claims the oldest ready outbox row'
313
+ );
314
+
315
+ select is(
316
+ (select attempt_number from callback_runtime_claim_results limit 1),
317
+ 1,
318
+ 'claim_callback_outbox_events starts attempt numbering at one'
319
+ );
320
+
321
+ select is(
322
+ (select idempotency_key from agent_board.callback_outbox_events where id = (select outbox_event_id from callback_runtime_claim_results limit 1)),
323
+ 'callback-runtime-pending',
324
+ 'claim_callback_outbox_events preserves the stable idempotency key'
325
+ );
326
+
327
+ select is(
328
+ (select outbox_status from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-pending'),
329
+ 'delivering',
330
+ 'claim_callback_outbox_events moves claimed rows to delivering'
331
+ );
332
+
333
+ select is(
334
+ (select outbox_status from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-success'),
335
+ 'delivered',
336
+ 'record_callback_delivery_success marks the outbox delivered'
337
+ );
338
+
339
+ select is(
340
+ (select attempt_outcome from agent_board.callback_delivery_attempts cda join agent_board.callback_outbox_events coe on coe.id = cda.outbox_event_id where coe.idempotency_key = 'callback-runtime-success' order by cda.attempt_number desc limit 1),
341
+ 'delivered',
342
+ 'record_callback_delivery_success appends a delivered attempt'
343
+ );
344
+
345
+ select is(
346
+ (select attempt_number from agent_board.callback_delivery_attempts cda join agent_board.callback_outbox_events coe on coe.id = cda.outbox_event_id where coe.idempotency_key = 'callback-runtime-success' order by cda.attempt_number desc limit 1),
347
+ 1,
348
+ 'record_callback_delivery_success records the first delivery attempt as attempt one'
349
+ );
350
+
351
+ select is(
352
+ (select outbox_status from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-retry'),
353
+ 'retryable',
354
+ 'record_callback_delivery_retry marks retryable outbox state'
355
+ );
356
+
357
+ select ok(
358
+ (
359
+ select next_retry_at is not null
360
+ from agent_board.callback_delivery_attempts cda
361
+ join agent_board.callback_outbox_events coe on coe.id = cda.outbox_event_id
362
+ where coe.idempotency_key = 'callback-runtime-retry'
363
+ order by cda.attempt_number desc
364
+ limit 1
365
+ ),
366
+ 'record_callback_delivery_retry stores retry scheduling metadata'
367
+ );
368
+
369
+ select is(
370
+ (select http_status from agent_board.callback_delivery_attempts cda join agent_board.callback_outbox_events coe on coe.id = cda.outbox_event_id where coe.idempotency_key = 'callback-runtime-retry' order by cda.attempt_number desc limit 1),
371
+ 503,
372
+ 'record_callback_delivery_retry preserves retryable HTTP status metadata'
373
+ );
374
+
375
+ select is(
376
+ (select outbox_status from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-terminal'),
377
+ 'failed',
378
+ 'record_callback_delivery_terminal_failure marks failed outbox state'
379
+ );
380
+
381
+ select is(
382
+ (select latest_attempt_outcome from agent_board.v_callback_delivery_health where subscription_id = (select id from agent_board.callback_subscriptions where endpoint_id = (select id from agent_board.callback_endpoints where endpoint_url = 'https://example.test/callback-runtime-terminal'))),
383
+ 'terminal_failure',
384
+ 'v_callback_delivery_health reflects the latest terminal attempt'
385
+ );
386
+
387
+ select is(
388
+ (select latest_http_status from agent_board.v_callback_delivery_health where subscription_id = (select id from agent_board.callback_subscriptions where endpoint_id = (select id from agent_board.callback_endpoints where endpoint_url = 'https://example.test/callback-runtime-terminal'))),
389
+ 404,
390
+ 'v_callback_delivery_health preserves terminal HTTP status metadata'
391
+ );
392
+
393
+ select is(
394
+ (select endpoint_status from agent_board.callback_endpoints where endpoint_url = 'https://example.test/callback-runtime-disabled'),
395
+ 'disabled',
396
+ 'disable_callback_delivery_endpoint disables the endpoint'
397
+ );
398
+
399
+ select is(
400
+ (select outbox_status from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-disable'),
401
+ 'disabled',
402
+ 'disable_callback_delivery_endpoint marks the current outbox disabled'
403
+ );
404
+
405
+ select is(
406
+ (select attempt_outcome from agent_board.callback_delivery_attempts cda join agent_board.callback_outbox_events coe on coe.id = cda.outbox_event_id where coe.idempotency_key = 'callback-runtime-disable' order by cda.attempt_number desc limit 1),
407
+ 'endpoint_disabled',
408
+ 'disable_callback_delivery_endpoint appends an endpoint_disabled attempt'
409
+ );
410
+
411
+ select is(
412
+ (select count(*)::integer from agent_board.inbox_items where id = (select inbox_item_id from agent_board.callback_outbox_events where idempotency_key = 'callback-runtime-success')),
413
+ 1,
414
+ 'callback runtime helper calls do not create duplicate canonical inbox rows'
415
+ );
416
+
417
+ select is(
418
+ (select count(*)::integer from agent_board.delivery_recipients where source_message_id = (select id from agent_board.messages where body = 'callback runtime body')),
419
+ 1,
420
+ 'callback runtime helper calls do not create duplicate canonical delivery recipient rows'
421
+ );
422
+
423
+ select * from finish();
424
+
425
+ rollback;