@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.
- package/LICENSE +202 -0
- package/NOTICE +11 -0
- package/README.md +55 -0
- package/bin/agent-board-schema.js +97 -0
- package/fixtures/already-applied.json +181 -0
- package/fixtures/divergent-history.json +173 -0
- package/fixtures/production-history.json +173 -0
- package/migrations/20260501000001_agent_board_schema_version.sql +12 -0
- package/migrations/20260502000000_agent_board_schema.sql +180 -0
- package/migrations/20260503000000_agent_board_rpcs.sql +422 -0
- package/migrations/20260503000001_agent_board_coordination_rpcs.sql +229 -0
- package/migrations/20260504000000_agent_board_read_models.sql +206 -0
- package/migrations/20260505000000_agent_board_inbox_schema.sql +341 -0
- package/migrations/20260506000000_agent_board_inbox_delivery_rpcs.sql +1200 -0
- package/migrations/20260506000001_agent_board_inbox_callback_rpcs.sql +330 -0
- package/migrations/20260507000000_agent_board_inbox_reads.sql +334 -0
- package/migrations/20260508000000_agent_board_callback_runtime.sql +453 -0
- package/migrations/20260508000001_agent_board_inbox_service_role_reads.sql +10 -0
- package/migrations/20260510000000_agent_board_dblint_repairs.sql +413 -0
- package/migrations/20260511000000_agent_board_auth_schema.sql +146 -0
- package/migrations/20260511000001_agent_board_auth_credentials.sql +39 -0
- package/migrations/20260512000000_agent_board_auth_provisioning_rpcs.sql +622 -0
- package/migrations/20260512000001_agent_board_auth_v1_rpcs.sql +798 -0
- package/migrations/20260512000002_agent_board_auth_v2_rpcs.sql +1243 -0
- package/migrations/20260512000003_agent_board_auth_rls.sql +484 -0
- package/migrations/20260513000000_agent_board_backup_ops.sql +34 -0
- package/migrations/20260513000001_agent_board_retention.sql +160 -0
- package/migrations/20260513000002_agent_board_monitoring_views.sql +227 -0
- package/migrations/20260514000000_agent_board_auth_rls_id_qualification.sql +150 -0
- package/migrations/20260515000000_agent_board_boardopt.sql +493 -0
- package/migrations/20260516000000_agent_board_callbackcap.sql +113 -0
- package/migrations/20260517000000_agent_board_addressing.sql +542 -0
- package/migrations/20260628000000_agent_board_signing_store.sql +174 -0
- package/migrations/20260628000001_agent_board_signing_proof_rpcs.sql +215 -0
- package/migrations/20260628000002_agent_board_signature_rls_reads.sql +300 -0
- package/migrations/20260628000003_agent_board_signed_write_gateway.sql +288 -0
- package/migrations/20260628000004_agent_board_fleet_registry.sql +411 -0
- package/migrations/20260628000005_agent_board_fleet_policy.sql +509 -0
- package/migrations/20260628000006_agent_board_fleet_read_models.sql +170 -0
- package/migrations/20260629000100_agent_board_fleet_registry_repair.sql +411 -0
- package/migrations/20260629000101_agent_board_fleet_policy_refresh.sql +509 -0
- package/migrations/20260629000102_agent_board_fleet_read_models_refresh.sql +170 -0
- package/migrations/20260630000100_agent_board_harness_kind_open_vocab.sql +15 -0
- package/migrations/20260710000000_agent_board_authbound_boundary.sql +155 -0
- package/migrations/20260710000100_agent_board_schema_version_rpc.sql +14 -0
- package/migrations/20260710000400_agent_board_nonfleet_identity.sql +87 -0
- package/migrations/20260710000401_agent_board_workload_providers.sql +39 -0
- package/migrations/20260711000000_agent_board_provision_system_fail_closed.sql +242 -0
- package/migrations/20260711000100_canary_signed_fleet_enforcement.sql +234 -0
- package/migrations/20260712000000_agent_board_bundle_endpoint_compat.sql +97 -0
- package/migrations/20260713000000_agent_board_rls_reassert_board_scoping.sql +90 -0
- package/package.json +42 -0
- package/provenance.json +580 -0
- package/schema-manifest.json +458 -0
- package/src/check.js +23 -0
- package/src/index.js +50 -0
- package/src/materialize.js +73 -0
- package/src/plan.js +44 -0
- package/src/tooling.test.mjs +97 -0
- package/tests/agent_board_addressing.test.sql +166 -0
- package/tests/agent_board_auth_rls.test.sql +243 -0
- package/tests/agent_board_auth_rls_id_qualification.test.sql +225 -0
- package/tests/agent_board_auth_rpcs.test.sql +311 -0
- package/tests/agent_board_auth_schema.test.sql +411 -0
- package/tests/agent_board_authbound_boundary.test.sql +148 -0
- package/tests/agent_board_boardopt.test.sql +170 -0
- package/tests/agent_board_bundle_endpoint_compat.test.sql +49 -0
- package/tests/agent_board_callback_runtime.test.sql +425 -0
- package/tests/agent_board_callbackcap.test.sql +222 -0
- package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +60 -0
- package/tests/agent_board_dblint_rpcs.test.sql +247 -0
- package/tests/agent_board_fleet_policy.test.sql +370 -0
- package/tests/agent_board_fleet_read_models.test.sql +158 -0
- package/tests/agent_board_fleet_registry.test.sql +149 -0
- package/tests/agent_board_inbox_reads.test.sql +471 -0
- package/tests/agent_board_inbox_rpcs.test.sql +452 -0
- package/tests/agent_board_inbox_schema.test.sql +355 -0
- package/tests/agent_board_nonfleet_identity.test.sql +26 -0
- package/tests/agent_board_rls_reassert_board_scoping.test.sql +39 -0
- package/tests/agent_board_schema_version.test.sql +24 -0
- package/tests/agent_board_schema_version_rpc.test.sql +40 -0
- package/tests/agent_board_signature_rls_reads.test.sql +133 -0
- package/tests/agent_board_signed_write_gateway.test.sql +219 -0
- package/tests/agent_board_signing_proof_rpcs.test.sql +143 -0
- package/tests/agent_board_signing_store.test.sql +183 -0
- package/tests/agent_board_smoke.test.sql +12 -0
- package/tests/agent_board_v1_invariants.test.sql +298 -0
- package/tests/agent_board_v2_invariants.test.sql +753 -0
- package/tests/agent_board_workload_providers.test.sql +15 -0
- package/tests/fixtures/adopter-base.sql +19 -0
- package/tests/fixtures/operator-hardening.sql +27 -0
- 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;
|