@consiliency/agent-board-schema 1.60.0 → 1.64.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 (100) hide show
  1. package/README.md +86 -0
  2. package/fixtures/already-applied.json +16 -0
  3. package/migrations/20261011000100_agent_board_session_identities.sql +1964 -0
  4. package/migrations/20261012000100_agent_board_sidowner.sql +209 -0
  5. package/migrations/20261014000100_agent_board_grant_target_role.sql +218 -0
  6. package/migrations/20261014000200_agent_board_last_owner.sql +239 -0
  7. package/package.json +1 -1
  8. package/schema-manifest.json +39 -3
  9. package/src/tooling.test.mjs +10 -2
  10. package/tests/agent_board_atomic_fleet_onboarding.test.sql +15 -4
  11. package/tests/agent_board_atomic_fleet_onboarding_runtime.test.sql +7 -0
  12. package/tests/agent_board_consent_emission.test.sql +30 -11
  13. package/tests/agent_board_consent_gating.test.sql +16 -2
  14. package/tests/agent_board_delegate_role_class.test.sql +1 -1
  15. package/tests/agent_board_delegation_cap_ceiling.test.sql +26 -15
  16. package/tests/agent_board_delegation_enforcement.test.sql +1 -1
  17. package/tests/agent_board_enroll_resumption.test.sql +22 -4
  18. package/tests/agent_board_enroll_token_single_use.test.sql +18 -3
  19. package/tests/agent_board_federated_lock_order_class.test.sql +2 -2
  20. package/tests/agent_board_fk_lock_edges.test.sql +77 -16
  21. package/tests/agent_board_grant_target_role.test.sql +1118 -0
  22. package/tests/agent_board_hosted_delegates.test.sql +5 -3
  23. package/tests/agent_board_invite_no_downgrade.test.sql +15 -11
  24. package/tests/agent_board_ledger_authority.test.sql +77 -12
  25. package/tests/agent_board_membership_current_row_class.test.sql +9 -1
  26. package/tests/agent_board_mint_fleet_agent_session.test.sql +2 -2
  27. package/tests/agent_board_mint_harden.test.sql +38 -27
  28. package/tests/agent_board_role_guard.test.sql +319 -0
  29. package/tests/agent_board_rolereset.test.sql +25 -29
  30. package/tests/agent_board_roomdeleg.test.sql +8 -0
  31. package/tests/agent_board_roomdeleg_lane_b.test.sql +6 -6
  32. package/tests/agent_board_roomown.test.sql +3 -1
  33. package/tests/agent_board_rowid.test.sql +7 -2
  34. package/tests/agent_board_session_identity_approval_revocation.test.sql +334 -0
  35. package/tests/agent_board_session_identity_backfill.test.sql +82 -0
  36. package/tests/agent_board_session_identity_backfill_refusal.test.sql +14 -0
  37. package/tests/agent_board_session_identity_behavior_classes.test.sql +176 -0
  38. package/tests/agent_board_session_identity_class.test.sql +118 -0
  39. package/tests/agent_board_session_identity_fingerprint.test.sql +271 -0
  40. package/tests/agent_board_session_identity_labels_limits.test.sql +205 -0
  41. package/tests/agent_board_session_identity_lease.test.sql +235 -0
  42. package/tests/agent_board_session_identity_lifetime.test.sql +230 -0
  43. package/tests/agent_board_session_identity_limits.test.sql +208 -0
  44. package/tests/agent_board_session_identity_lineage.test.sql +64 -0
  45. package/tests/agent_board_session_identity_link.test.sql +201 -0
  46. package/tests/agent_board_session_identity_mint.test.sql +233 -0
  47. package/tests/agent_board_session_identity_panel_r1.test.sql +194 -0
  48. package/tests/agent_board_session_identity_panel_r2.test.sql +174 -0
  49. package/tests/agent_board_session_identity_protected_actions.test.sql +156 -0
  50. package/tests/agent_board_session_identity_revoke_closure.test.sql +131 -0
  51. package/tests/agent_board_sidowner_leases.test.sql +107 -0
  52. package/tests/agent_board_sidowner_owner_required.test.sql +97 -0
  53. package/tests/agent_board_sidowner_read_class.test.sql +171 -0
  54. package/tests/agent_board_sidowner_reads.test.sql +136 -0
  55. package/tests/agent_board_signer_lifecycle.test.sql +26 -4
  56. package/tests/agent_board_signing_challenge_pending_cap.test.sql +1 -1
  57. package/tests/agent_board_write_enforcement_class.test.sql +74 -15
  58. package/tests/catalog/function_execute_privileges.json +227 -2
  59. package/tests/catalog/p_metadata_parameters.json +102 -2
  60. package/tests/isolation/expected/grant_target_role_race.out +348 -0
  61. package/tests/isolation/expected/last_owner_departure.out +562 -0
  62. package/tests/isolation/expected/session_identity_limits.out +165 -0
  63. package/tests/isolation/expected/session_identity_links.out +235 -0
  64. package/tests/isolation/expected/session_identity_reclaim.out +253 -0
  65. package/tests/isolation/expected/session_identity_renew_revoke.out +115 -0
  66. package/tests/isolation/expected/session_identity_renew_revoke_key_gate.out +138 -0
  67. package/tests/isolation/expected/session_identity_tombstone_onboarding.out +247 -0
  68. package/tests/isolation/specs/atomic_fleet_authority_races.spec +8 -3
  69. package/tests/isolation/specs/atomic_fleet_binding_revoke.spec +0 -3
  70. package/tests/isolation/specs/atomic_fleet_board_archive.spec +0 -3
  71. package/tests/isolation/specs/atomic_fleet_human_fresh_revoke.spec +0 -3
  72. package/tests/isolation/specs/atomic_fleet_identity_disposition.spec +0 -3
  73. package/tests/isolation/specs/atomic_fleet_lifecycle_races.spec +0 -3
  74. package/tests/isolation/specs/atomic_fleet_subtree_lock_order.spec +0 -3
  75. package/tests/isolation/specs/ceiling_setter_lock_before_upsert.spec +0 -3
  76. package/tests/isolation/specs/claimpolicy_acquire_revert_race.spec +0 -2
  77. package/tests/isolation/specs/claimpolicy_board_scope.spec +0 -2
  78. package/tests/isolation/specs/claimpolicy_claimrow_lock_order.spec +0 -2
  79. package/tests/isolation/specs/claimpolicy_isolation_refusal.spec +0 -2
  80. package/tests/isolation/specs/claimpolicy_renew_revert_race.spec +0 -2
  81. package/tests/isolation/specs/claimpolicy_writer_keyshare.spec +0 -2
  82. package/tests/isolation/specs/consent_approval_lock.spec +0 -1
  83. package/tests/isolation/specs/consent_emit_actual_state.spec +0 -1
  84. package/tests/isolation/specs/grant_target_role_race.spec +206 -0
  85. package/tests/isolation/specs/hosted_delegate_add_tombstone_race.spec +0 -1
  86. package/tests/isolation/specs/hosted_delegate_tombstone_revoke_race.spec +0 -1
  87. package/tests/isolation/specs/hosted_delegate_withdraw_evict_race.spec +0 -1
  88. package/tests/isolation/specs/last_owner_departure.spec +137 -0
  89. package/tests/isolation/specs/ledger_authority_revoke.spec +0 -3
  90. package/tests/isolation/specs/onboarding_ceiling_lock_order.spec +0 -3
  91. package/tests/isolation/specs/outbox_wake_ordering.spec +0 -1
  92. package/tests/isolation/specs/session_identity_limits.spec +81 -0
  93. package/tests/isolation/specs/session_identity_links.spec +82 -0
  94. package/tests/isolation/specs/session_identity_reclaim.spec +125 -0
  95. package/tests/isolation/specs/session_identity_renew_revoke.spec +84 -0
  96. package/tests/isolation/specs/session_identity_renew_revoke_key_gate.spec +94 -0
  97. package/tests/isolation/specs/session_identity_tombstone_onboarding.spec +107 -0
  98. package/tests/isolation/specs/signed_grant_onboarding_deadlock.spec +0 -1
  99. package/tests/isolation/specs/signer_lifecycle_revoke.spec +0 -1
  100. package/tests/seeds/20261011000100_agent_board_session_identities.sql.pre.sql +47 -0
@@ -56,8 +56,6 @@ teardown
56
56
  delete from agent_board.threads where id = '40500000-0000-4000-8000-000000000060';
57
57
  delete from agent_board.board_membership_events where board_id in (
58
58
  select id from agent_board.boards where slug = 'cpr-ks-board');
59
- delete from agent_board.board_memberships where board_id in (
60
- select id from agent_board.boards where slug = 'cpr-ks-board');
61
59
  delete from agent_board.boards where slug = 'cpr-ks-board';
62
60
  delete from agent_board.agents where id = '40500000-0000-4000-8000-000000000005';
63
61
  delete from auth.users where id = '40500000-0000-4000-8000-0000000000e1';
@@ -53,7 +53,6 @@ setup
53
53
  teardown
54
54
  {
55
55
  delete from agent_board.board_membership_events where board_id = '115b0000-0000-4000-8000-000000000001';
56
- delete from agent_board.board_memberships where board_id = '115b0000-0000-4000-8000-000000000001';
57
56
  delete from agent_board.boards where id = '115b0000-0000-4000-8000-000000000001';
58
57
  delete from agent_board.agents where id in ('115a0000-0000-4000-8000-000000000001','115a0000-0000-4000-8000-000000000002');
59
58
  }
@@ -37,7 +37,6 @@ setup
37
37
  teardown
38
38
  {
39
39
  delete from agent_board.board_membership_events where board_id = '105b0000-0000-4000-8000-000000000001';
40
- delete from agent_board.board_memberships where board_id = '105b0000-0000-4000-8000-000000000001';
41
40
  delete from agent_board.boards where id = '105b0000-0000-4000-8000-000000000001';
42
41
  delete from agent_board.agents where id = '105a0000-0000-4000-8000-000000000001';
43
42
  }
@@ -0,0 +1,206 @@
1
+ # #674 (plans/plan-674-grant-target-role.md §5.4): grant_board_role reads the target's
2
+ # CURRENT role in ONE step-6 statement that locks the target's active row
3
+ # FOR NO KEY UPDATE OF t and LEFT JOINs the grantor's active row unlocked. Every session
4
+ # uses explicit BEGIN/COMMIT (or ROLLBACK); claims are transaction-local, so they are set
5
+ # in the begin step. Authenticated grants pass no p_grantor_agent_id (the host shape).
6
+ #
7
+ # Board B (created by O). Roles at setup:
8
+ # O owner, A1 admin, M member, V observer, G member.
9
+ # One admin-preset invite link on B, minted by O through create_invite_link (max_uses 5).
10
+ #
11
+ # I-1 M redeems the admin link (rank-max lifts M to admin, row held) while A1 grants
12
+ # M -> observer. A1 BLOCKS at step 6; after M commits, the locked read sees admin,
13
+ # and C-B refuses (D6b). M stays admin. (pins M7)
14
+ # I-2 O removes M (update_board_membership, held) while A1 grants M -> observer. A1
15
+ # blocks; after O commits, A1 gets P0002 (no all-null row).
16
+ # I-3 O demotes A1 to member (held) while A1 grants M -> observer. A1 blocks on the
17
+ # board advisory lock; after O commits, step 6 sees A1 as member and C-A refuses
18
+ # (D6a). Reverse order: both succeed.
19
+ # I-4 O posts on B (post_board_message fan-out inserts delivery_recipients naming M's
20
+ # membership: FOR KEY SHARE on M's row, held) while O's second session grants
21
+ # M -> observer. The grant completes WITHOUT blocking. (pins M7b)
22
+ # I-5 G redeems the admin link (G's own row raised to admin, held) while G's second
23
+ # session grants V -> member. It does NOT block (g is unlocked), reads G's committed
24
+ # role member, and C-A refuses (D6a). After G commits, a retry succeeds.
25
+
26
+ setup
27
+ {
28
+ insert into auth.users(id) values
29
+ ('67410000-0000-4000-8000-000000000001'),
30
+ ('67410000-0000-4000-8000-000000000002'),
31
+ ('67410000-0000-4000-8000-000000000003'),
32
+ ('67410000-0000-4000-8000-000000000004'),
33
+ ('67410000-0000-4000-8000-000000000005');
34
+ insert into agent_board.agents(id, agent_type, handle, display_name, status, auth_user_id) values
35
+ ('67420000-0000-4000-8000-000000000001', 'agent', 'g674-iso-o', 'G674 O', 'active', '67410000-0000-4000-8000-000000000001'),
36
+ ('67420000-0000-4000-8000-000000000002', 'agent', 'g674-iso-a1', 'G674 A1', 'active', '67410000-0000-4000-8000-000000000002'),
37
+ ('67420000-0000-4000-8000-000000000003', 'agent', 'g674-iso-m', 'G674 M', 'active', '67410000-0000-4000-8000-000000000003'),
38
+ ('67420000-0000-4000-8000-000000000004', 'agent', 'g674-iso-v', 'G674 V', 'active', '67410000-0000-4000-8000-000000000004'),
39
+ ('67420000-0000-4000-8000-000000000005', 'agent', 'g674-iso-g', 'G674 G', 'active', '67410000-0000-4000-8000-000000000005');
40
+ insert into agent_board.boards(id, slug, name, created_by_agent_id, visibility)
41
+ values ('67430000-0000-4000-8000-000000000001', 'g674-iso-board', 'G674 isolation board',
42
+ '67420000-0000-4000-8000-000000000001', 'private');
43
+ insert into agent_board.board_memberships(board_id, agent_id, membership_state, role, created_by_agent_id) values
44
+ ('67430000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000001', 'joined', 'owner', '67420000-0000-4000-8000-000000000001'),
45
+ ('67430000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000002', 'joined', 'admin', '67420000-0000-4000-8000-000000000001'),
46
+ ('67430000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000003', 'joined', 'member', '67420000-0000-4000-8000-000000000001'),
47
+ ('67430000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000004', 'joined', 'observer', '67420000-0000-4000-8000-000000000001'),
48
+ ('67430000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000005', 'joined', 'member', '67420000-0000-4000-8000-000000000001');
49
+ insert into agent_board.threads(id, created_by_agent_id, subject, board_id)
50
+ values ('67440000-0000-4000-8000-000000000001', '67420000-0000-4000-8000-000000000001', 'g674 iso thread',
51
+ '67430000-0000-4000-8000-000000000001');
52
+ -- The admin-preset link, minted by O through the real RPC (service path, O supplied).
53
+ select count(*) from agent_board.create_invite_link('67430000-0000-4000-8000-000000000001', 'admin', 'joined', 5,
54
+ null, '67420000-0000-4000-8000-000000000001', jsonb_build_object());
55
+ }
56
+
57
+ teardown
58
+ {
59
+ delete from agent_board.board_invite_redemptions where invite_id in
60
+ (select id from agent_board.board_invite_tokens where board_id = '67430000-0000-4000-8000-000000000001');
61
+ delete from agent_board.board_invite_tokens where board_id = '67430000-0000-4000-8000-000000000001';
62
+ delete from agent_board.delivery_recipients where board_id = '67430000-0000-4000-8000-000000000001';
63
+ delete from agent_board.inbox_items where board_id = '67430000-0000-4000-8000-000000000001';
64
+ delete from agent_board.callback_outbox_events where board_id = '67430000-0000-4000-8000-000000000001';
65
+ delete from agent_board.messages where thread_id = '67440000-0000-4000-8000-000000000001';
66
+ delete from agent_board.threads where id = '67440000-0000-4000-8000-000000000001';
67
+ delete from agent_board.board_membership_events where board_id = '67430000-0000-4000-8000-000000000001';
68
+ delete from agent_board.boards where id = '67430000-0000-4000-8000-000000000001';
69
+ delete from agent_board.agents where id::text like '67420000-0000-4000-8000-00000000000_';
70
+ delete from auth.users where id::text like '67410000-0000-4000-8000-00000000000_';
71
+ }
72
+
73
+ # M, redeeming the admin link (I-1).
74
+ session "m"
75
+ step "m_begin" {
76
+ BEGIN;
77
+ select set_config('g674.code', (select code from agent_board.board_invite_tokens
78
+ where board_id = '67430000-0000-4000-8000-000000000001' and preset_role = 'admin'), true) is not null as have_code;
79
+ SET LOCAL ROLE authenticated;
80
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
81
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000003';
82
+ }
83
+ step "m_redeem" { select role, membership_state from agent_board.redeem_invite_link(current_setting('g674.code')); }
84
+ step "m_commit" { COMMIT; }
85
+
86
+ # A1, the admin grantor (I-1, I-2, I-3).
87
+ session "a"
88
+ step "a_begin" {
89
+ BEGIN;
90
+ SET LOCAL ROLE authenticated;
91
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
92
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000002';
93
+ }
94
+ step "a_grant_m_observer" {
95
+ select role from agent_board.grant_board_role('67430000-0000-4000-8000-000000000001',
96
+ '67420000-0000-4000-8000-000000000003', 'observer');
97
+ }
98
+ step "a_commit" { COMMIT; }
99
+ step "a_rollback" { ROLLBACK; }
100
+
101
+ # O, the owner (I-2 eviction, I-3 demotion of A1, I-4 grantor).
102
+ session "o"
103
+ step "o_begin" {
104
+ BEGIN;
105
+ SET LOCAL ROLE authenticated;
106
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
107
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000001';
108
+ }
109
+ step "o_remove_m" {
110
+ select membership_state from agent_board.update_board_membership('67430000-0000-4000-8000-000000000001',
111
+ '67420000-0000-4000-8000-000000000003', 'removed');
112
+ }
113
+ step "o_demote_a" {
114
+ select role from agent_board.grant_board_role('67430000-0000-4000-8000-000000000001',
115
+ '67420000-0000-4000-8000-000000000002', 'member');
116
+ }
117
+ step "o_grant_m_observer" {
118
+ select role from agent_board.grant_board_role('67430000-0000-4000-8000-000000000001',
119
+ '67420000-0000-4000-8000-000000000003', 'observer');
120
+ }
121
+ step "o_commit" { COMMIT; }
122
+
123
+ # O's second session, posting on B (I-4): the fan-out FK-inserts delivery_recipients rows
124
+ # naming each recipient's membership, which takes FOR KEY SHARE on M's row.
125
+ session "p"
126
+ step "p_begin" {
127
+ BEGIN;
128
+ SET LOCAL ROLE authenticated;
129
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
130
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000001';
131
+ }
132
+ step "p_post" {
133
+ select count(*) > 0 as posted from agent_board.post_board_message('67440000-0000-4000-8000-000000000001',
134
+ '67420000-0000-4000-8000-000000000001', '67430000-0000-4000-8000-000000000001', 'g674 iso', 'fan-out to M');
135
+ }
136
+ # RESET ROLE (still inside the open transaction, which keeps every lock it took) so this
137
+ # count reads M's uncommitted delivery row past the recipient-scoped RLS O is under.
138
+ step "p_holds_m_fk" {
139
+ RESET ROLE;
140
+ select count(*) as m_delivery_rows from agent_board.delivery_recipients dr
141
+ join agent_board.board_memberships bm on bm.id = dr.board_membership_id
142
+ where bm.board_id = '67430000-0000-4000-8000-000000000001' and bm.agent_id = '67420000-0000-4000-8000-000000000003';
143
+ }
144
+ step "p_commit" { COMMIT; }
145
+
146
+ # G, redeeming the admin link for its OWN row (I-5).
147
+ session "g"
148
+ step "g_begin" {
149
+ BEGIN;
150
+ select set_config('g674.code', (select code from agent_board.board_invite_tokens
151
+ where board_id = '67430000-0000-4000-8000-000000000001' and preset_role = 'admin'), true) is not null as have_code;
152
+ SET LOCAL ROLE authenticated;
153
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
154
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000005';
155
+ }
156
+ step "g_redeem" { select role, membership_state from agent_board.redeem_invite_link(current_setting('g674.code')); }
157
+ step "g_commit" { COMMIT; }
158
+
159
+ # G's second session, the grantor in I-5.
160
+ session "g2"
161
+ step "g2_begin" {
162
+ BEGIN;
163
+ SET LOCAL ROLE authenticated;
164
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
165
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000005';
166
+ }
167
+ step "g2_grant_v_member" {
168
+ select role from agent_board.grant_board_role('67430000-0000-4000-8000-000000000001',
169
+ '67420000-0000-4000-8000-000000000004', 'member');
170
+ }
171
+ step "g2_rollback" { ROLLBACK; }
172
+ step "g2_retry_begin" {
173
+ BEGIN;
174
+ SET LOCAL ROLE authenticated;
175
+ SET LOCAL "request.jwt.claim.role" = 'authenticated';
176
+ SET LOCAL "request.jwt.claim.sub" = '67410000-0000-4000-8000-000000000005';
177
+ }
178
+ step "g2_retry_grant_v_member" {
179
+ select role from agent_board.grant_board_role('67430000-0000-4000-8000-000000000001',
180
+ '67420000-0000-4000-8000-000000000004', 'member');
181
+ }
182
+ step "g2_commit" { COMMIT; }
183
+
184
+ session "check"
185
+ step "check" {
186
+ select a.handle, bm.role, bm.membership_state
187
+ from agent_board.board_memberships bm join agent_board.agents a on a.id = bm.agent_id
188
+ where bm.board_id = '67430000-0000-4000-8000-000000000001'
189
+ order by a.handle, bm.membership_state;
190
+ }
191
+
192
+ # I-1: the target is promoted through the product while it is being demoted.
193
+ permutation "m_begin" "m_redeem" "a_begin" "a_grant_m_observer" "m_commit" "a_rollback" "check"
194
+ # I-2: eviction during a grant.
195
+ permutation "o_begin" "o_remove_m" "a_begin" "a_grant_m_observer" "o_commit" "a_rollback" "check"
196
+ # I-3: two grants on one board, advisory-serialised. Demotion first: the grantor's role is
197
+ # read AFTER the advisory wait (C-A refuses). Grant first: both succeed.
198
+ permutation "o_begin" "o_demote_a" "a_begin" "a_grant_m_observer" "o_commit" "a_rollback" "check"
199
+ permutation "a_begin" "a_grant_m_observer" "o_begin" "o_demote_a" "a_commit" "o_commit" "check"
200
+ # I-4: FK-share non-interference -- the grant completes without blocking. The poster commits
201
+ # BEFORE the grantor so that a grant which DID block (M7b, FOR UPDATE) is released and the
202
+ # golden diff shows `<waiting ...>`/`<... completed>` instead of a truncated run.
203
+ permutation "p_begin" "p_post" "p_holds_m_fk" "o_begin" "o_grant_m_observer" "p_commit" "o_commit" "check"
204
+ # I-5: a concurrent raise of the grantor is seen as the older, lower rank (refusal), never
205
+ # a wrongful allow; the retry after commit succeeds.
206
+ permutation "g_begin" "g_redeem" "g2_begin" "g2_grant_v_member" "g2_rollback" "g_commit" "g2_retry_begin" "g2_retry_grant_v_member" "g2_commit" "check"
@@ -48,7 +48,6 @@ setup
48
48
  teardown
49
49
  {
50
50
  delete from agent_board.board_membership_events where board_id = '16591300-0000-4000-8000-000000000001';
51
- delete from agent_board.board_memberships where board_id = '16591300-0000-4000-8000-000000000001';
52
51
  delete from agent_board.boards where id = '16591300-0000-4000-8000-000000000001';
53
52
  delete from agent_board.agent_credentials
54
53
  where agent_id in (select agent_id from agent_board.delegate_instances where instance_id like 'iso\_at\_%');
@@ -74,7 +74,6 @@ teardown
74
74
  delete from agent_board.fleet_revocation_events where revoked_by_agent_id = '16591000-0000-4000-8000-000000000001';
75
75
  delete from agent_board.fleet_human_revocations where issuer = 'https://iso-tr.test';
76
76
  delete from agent_board.board_membership_events where board_id = '16591200-0000-4000-8000-000000000001';
77
- delete from agent_board.board_memberships where board_id = '16591200-0000-4000-8000-000000000001';
78
77
  delete from agent_board.boards where id = '16591200-0000-4000-8000-000000000001';
79
78
  delete from agent_board.agent_credentials
80
79
  where agent_id in (select agent_id from agent_board.delegate_instances where instance_id like 'iso\_tr\_%');
@@ -60,7 +60,6 @@ setup
60
60
  teardown
61
61
  {
62
62
  delete from agent_board.board_membership_events where board_id = '16322000-0000-4000-8000-000000000001';
63
- delete from agent_board.board_memberships where board_id = '16322000-0000-4000-8000-000000000001';
64
63
  delete from agent_board.boards where id = '16322000-0000-4000-8000-000000000001';
65
64
  delete from agent_board.agent_credentials
66
65
  where agent_id in (select agent_id from agent_board.delegate_instances where instance_id like 'iso\_wd\_%');
@@ -0,0 +1,137 @@
1
+ # Consiliency/message-board#675: two active owners independently leave/demote.
2
+ # The second RPC waits on the FIRST lock (board authority advisory), then reads
3
+ # the committed owner's exit and refuses. No timing sleeps; each permutation
4
+ # finishes with exactly one owner. The same spec on schema 1.63.0 ends at zero.
5
+ setup
6
+ {
7
+ create function public.roleguard_isolation_refusal(p_statement text)
8
+ returns text language plpgsql as $probe$
9
+ begin
10
+ execute p_statement;
11
+ return 'UNEXPECTED_SUCCESS';
12
+ exception when others then
13
+ return sqlstate;
14
+ end;
15
+ $probe$;
16
+ insert into auth.users(id,instance_id,aud,role,email)
17
+ select ('67500000-0000-0000-0000-'||lpad(n::text,12,'0'))::uuid,
18
+ '00000000-0000-0000-0000-000000000000','authenticated','authenticated',
19
+ 'last-owner-'||n||'@test.invalid' from generate_series(1,2) n;
20
+ insert into agent_board.agents(id,agent_type,kind,handle,display_name,status,auth_user_id)
21
+ select ('67510000-0000-4000-8000-'||lpad(n::text,12,'0'))::uuid,
22
+ 'agent','agent','last-owner-'||n,'Last Owner '||n,'active',
23
+ ('67500000-0000-0000-0000-'||lpad(n::text,12,'0'))::uuid from generate_series(1,2) n;
24
+ insert into agent_board.boards(id,slug,name,created_by_agent_id)
25
+ values ('67520000-0000-4000-8000-000000000099','last-owner-race','Last Owner Race',
26
+ '67510000-0000-4000-8000-000000000001');
27
+ insert into agent_board.board_memberships(board_id,agent_id,role,membership_state,created_by_agent_id)
28
+ select '67520000-0000-4000-8000-000000000099',id,'owner','joined',
29
+ '67510000-0000-4000-8000-000000000001' from agent_board.agents where handle like 'last-owner-%';
30
+ }
31
+
32
+ teardown
33
+ {
34
+ drop function public.roleguard_isolation_refusal(text);
35
+ delete from agent_board.board_membership_events
36
+ where board_id='67520000-0000-4000-8000-000000000099';
37
+ delete from agent_board.boards where id='67520000-0000-4000-8000-000000000099';
38
+ delete from agent_board.agents where handle like 'last-owner-%';
39
+ delete from auth.users where email like 'last-owner-%@test.invalid';
40
+ }
41
+
42
+ session "a"
43
+ step "a_begin" {
44
+ begin;
45
+ set local role authenticated;
46
+ select set_config('request.jwt.claims', json_build_object('role','authenticated','sub','67500000-0000-0000-0000-000000000001')::text,true) is not null as authenticated;
47
+ }
48
+ step "a_leave" {
49
+ select membership_state from agent_board.leave_board(
50
+ '67520000-0000-4000-8000-000000000099','67510000-0000-4000-8000-000000000001');
51
+ }
52
+ step "a_demote" {
53
+ select role from agent_board.grant_board_role(
54
+ '67520000-0000-4000-8000-000000000099','67510000-0000-4000-8000-000000000001','member');
55
+ }
56
+ step "a_commit" { commit; }
57
+ step "a_repeatable" {
58
+ begin isolation level repeatable read;
59
+ set local role authenticated;
60
+ select set_config('request.jwt.claims', json_build_object('role','authenticated','sub','67500000-0000-0000-0000-000000000001')::text,true) is not null as authenticated;
61
+ }
62
+ step "a_snapshot" {
63
+ select count(*) as snapshot_owners from agent_board.board_memberships where board_id='67520000-0000-4000-8000-000000000099' and role='owner' and membership_state in ('joined','subscribed');
64
+ }
65
+ step "a_leave_code" {
66
+ select public.roleguard_isolation_refusal($probe$
67
+ select agent_board.leave_board(
68
+ '67520000-0000-4000-8000-000000000099','67510000-0000-4000-8000-000000000001')
69
+ $probe$) as error_code;
70
+ }
71
+ step "a_raw" {
72
+ reset role;
73
+ select agent_board._lock_board_authority_ceiling('67520000-0000-4000-8000-000000000099');
74
+ update agent_board.board_memberships set membership_state='left',left_at=now()
75
+ where board_id='67520000-0000-4000-8000-000000000099'
76
+ and agent_id='67510000-0000-4000-8000-000000000001';
77
+ }
78
+ step "a_session_begin" {
79
+ begin;
80
+ select pg_advisory_lock(hashtextextended(
81
+ 'agent_board.board_authority_ceilings:67520000-0000-4000-8000-000000000099',0));
82
+ }
83
+ step "a_session_leave" {
84
+ update agent_board.board_memberships set membership_state='left',left_at=now()
85
+ where board_id='67520000-0000-4000-8000-000000000099'
86
+ and agent_id='67510000-0000-4000-8000-000000000001';
87
+ }
88
+ step "a_session_unlock" {
89
+ select pg_advisory_unlock(hashtextextended(
90
+ 'agent_board.board_authority_ceilings:67520000-0000-4000-8000-000000000099',0));
91
+ }
92
+
93
+ session "b"
94
+ step "b_begin" {
95
+ begin;
96
+ set local role authenticated;
97
+ select set_config('request.jwt.claims', json_build_object('role','authenticated','sub','67500000-0000-0000-0000-000000000002')::text,true) is not null as authenticated;
98
+ }
99
+ step "b_leave" {
100
+ select membership_state from agent_board.leave_board(
101
+ '67520000-0000-4000-8000-000000000099','67510000-0000-4000-8000-000000000002');
102
+ }
103
+ step "b_demote" {
104
+ select role from agent_board.grant_board_role(
105
+ '67520000-0000-4000-8000-000000000099','67510000-0000-4000-8000-000000000002','member');
106
+ }
107
+ step "b_commit" { commit; }
108
+ step "b_raw" {
109
+ reset role;
110
+ delete from agent_board.board_memberships
111
+ where board_id='67520000-0000-4000-8000-000000000099'
112
+ and agent_id='67510000-0000-4000-8000-000000000002';
113
+ }
114
+ step "b_lock" {
115
+ reset role;
116
+ select agent_board._lock_board_authority_ceiling('67520000-0000-4000-8000-000000000099');
117
+ }
118
+
119
+ session "check"
120
+ step "owners" {
121
+ select count(*) as active_owners from agent_board.board_memberships
122
+ where board_id='67520000-0000-4000-8000-000000000099'
123
+ and role='owner' and membership_state in ('joined','subscribed');
124
+ }
125
+
126
+ permutation "a_begin" "a_leave" "b_begin" "b_leave" "a_commit" "b_commit" "owners"
127
+ permutation "b_begin" "b_leave" "a_begin" "a_leave" "b_commit" "a_commit" "owners"
128
+ permutation "a_begin" "a_demote" "b_begin" "b_demote" "a_commit" "b_commit" "owners"
129
+ permutation "b_begin" "b_demote" "a_begin" "a_demote" "b_commit" "a_commit" "owners"
130
+ permutation "a_begin" "a_leave" "b_begin" "b_demote" "a_commit" "b_commit" "owners"
131
+ permutation "b_begin" "b_demote" "a_begin" "a_leave" "b_commit" "a_commit" "owners"
132
+ permutation "a_begin" "a_raw" "b_begin" "b_raw" "a_commit" "b_commit" "owners"
133
+ permutation "b_begin" "b_lock" "b_raw" "a_begin" "a_raw" "b_commit" "a_commit" "owners"
134
+ permutation "a_repeatable" "a_leave_code" "a_commit" "owners"
135
+ permutation "a_session_begin" "a_session_leave" "a_session_unlock" "b_begin" "b_leave" "a_commit" "b_commit" "owners"
136
+
137
+ permutation "a_repeatable" "a_snapshot" "b_begin" "b_leave" "a_leave_code" "b_commit" "a_commit" "owners"
@@ -112,8 +112,6 @@ teardown
112
112
  where board_id = '27720000-0000-4000-8000-000000000001';
113
113
  delete from agent_board.board_membership_events
114
114
  where board_id in (select id from agent_board.boards where slug like 'k280-iso-%');
115
- delete from agent_board.board_memberships
116
- where board_id in (select id from agent_board.boards where slug like 'k280-iso-%');
117
115
  delete from agent_board.boards where slug like 'k280-iso-%';
118
116
  delete from agent_board.board_membership_events
119
117
  where board_id = '27720000-0000-4000-8000-000000000001';
@@ -127,7 +125,6 @@ teardown
127
125
  delete from agent_board.agent_signing_keys
128
126
  where agent_id in (select id from agent_board.agents where handle like 'k276iso-%');
129
127
  delete from agent_board.board_authority_ceilings where board_id='27720000-0000-4000-8000-000000000001';
130
- delete from agent_board.board_memberships where board_id='27720000-0000-4000-8000-000000000001';
131
128
  delete from agent_board.boards where id='27720000-0000-4000-8000-000000000001';
132
129
  delete from agent_board.agents where handle like 'k276iso-%';
133
130
  delete from auth.users where id in (
@@ -103,9 +103,6 @@ teardown
103
103
  delete from agent_board.board_authority_ceilings where board_id in (
104
104
  select id from agent_board.boards where slug='onboard-ceiling-board'
105
105
  );
106
- delete from agent_board.board_memberships where board_id in (
107
- select id from agent_board.boards where slug='onboard-ceiling-board'
108
- );
109
106
  delete from agent_board.enrollment_federation_audit where agent_id in (
110
107
  select id from agent_board.agents where handle='onboard-ceiling-agent'
111
108
  );
@@ -114,7 +114,6 @@ teardown
114
114
  delete from agent_board.callback_outbox_events where board_id in ('18701000-0000-4000-8000-00000000000a', '18701000-0000-4000-8000-00000000000b');
115
115
  delete from agent_board.callback_subscriptions where board_id in ('18701000-0000-4000-8000-00000000000a', '18701000-0000-4000-8000-00000000000b');
116
116
  delete from agent_board.callback_endpoints where endpoint_url like 'https://example.test/iso187/%';
117
- delete from agent_board.board_memberships where board_id in ('18701000-0000-4000-8000-00000000000a', '18701000-0000-4000-8000-00000000000b');
118
117
  delete from agent_board.messages where thread_id in ('18702000-0000-4000-8000-00000000000a', '18702000-0000-4000-8000-00000000000b');
119
118
  delete from agent_board.threads where id in ('18702000-0000-4000-8000-00000000000a', '18702000-0000-4000-8000-00000000000b');
120
119
  delete from agent_board.boards where id in ('18701000-0000-4000-8000-00000000000a', '18701000-0000-4000-8000-00000000000b');
@@ -0,0 +1,81 @@
1
+ # Concurrent mints from a 59-row mixed rolling-hour census share the true root
2
+ # lock. Expired legacy grants and revoked session mints still consume the hour.
3
+ setup
4
+ {
5
+ grant usage on schema extensions to service_role;
6
+ insert into auth.users(id) values ('77000000-0000-4000-8000-000000000001');
7
+ insert into agent_board.agents(id, agent_type, handle, display_name, status, owner_user_id)
8
+ values ('78000000-0000-4000-8000-000000000001', 'agent', 'sid-limits-root', 'SID limits root', 'active',
9
+ '77000000-0000-4000-8000-000000000001');
10
+ insert into agent_board.session_identities(agent_id, root_agent_id, depth)
11
+ values ('78000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001', 0);
12
+ insert into agent_board.delegation_policies(id, root_agent_id, mode, max_active_children, allowed_scopes, child_ttl_ceiling)
13
+ values ('79000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001', 'root_minted', 200, '[]', interval '8 hours');
14
+ do $$ declare n integer; child uuid; begin
15
+ for n in 1..59 loop
16
+ child := gen_random_uuid();
17
+ insert into agent_board.agents(id, agent_type, handle, display_name, status, owner_user_id, parent_agent_id, root_agent_id)
18
+ values (child, 'agent', 'sid-limits-history-' || n, 'SID limits history', case when n <= 30 then 'active' else 'revoked' end,
19
+ '77000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001');
20
+ insert into agent_board.session_identities(agent_id, parent_agent_id, root_agent_id, depth, identity_kind, harness, tombstoned_at, tombstone_reason)
21
+ values (child, '78000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001', 1,
22
+ case when n <= 30 then 'legacy' else 'session' end, case when n <= 30 then null else 'codex' end,
23
+ case when n <= 30 then null else now() end, case when n <= 30 then null else 'revoked' end);
24
+ insert into agent_board.delegation_grants(child_agent_id, root_agent_id, parent_agent_id, delegation_policy_id, granted_scopes, grant_expires_at, revoked_at)
25
+ values (child, '78000000-0000-4000-8000-000000000001', '78000000-0000-4000-8000-000000000001',
26
+ '79000000-0000-4000-8000-000000000001', '[]', now() - interval '1 hour', case when n <= 30 then null else now() end);
27
+ end loop;
28
+ end $$;
29
+ }
30
+
31
+ teardown
32
+ {
33
+ do $$ declare v_auth_ids uuid[]; begin
34
+ select array_agg(auth_user_id) into v_auth_ids from agent_board.agents
35
+ where root_agent_id = '78000000-0000-4000-8000-000000000001' and auth_user_id is not null;
36
+ delete from agent_board.session_id_aliases where root_agent_id = '78000000-0000-4000-8000-000000000001';
37
+ delete from agent_board.session_identities where root_agent_id = '78000000-0000-4000-8000-000000000001';
38
+ delete from agent_board.agents where root_agent_id = '78000000-0000-4000-8000-000000000001';
39
+ delete from agent_board.agents where id = '78000000-0000-4000-8000-000000000001';
40
+ delete from auth.users where id = any(v_auth_ids) or id = '77000000-0000-4000-8000-000000000001';
41
+ end $$;
42
+ }
43
+
44
+ session "a"
45
+ step "a_begin" { BEGIN; SET LOCAL ROLE service_role; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
46
+ step "a_mint" {
47
+ do $$ begin
48
+ perform * from agent_board.mint_delegated_child('78000000-0000-4000-8000-000000000001', 'sid-limit-a', '[]',
49
+ public.test_pubkey('sid-limit-a'), interval '1 hour', false, 'codex', 'limit-a');
50
+ end $$;
51
+ }
52
+ step "a_commit" { COMMIT; }
53
+
54
+ session "b"
55
+ step "b_begin" { BEGIN; SET LOCAL ROLE service_role; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
56
+ step "b_mint" {
57
+ do $$ begin
58
+ perform * from agent_board.mint_delegated_child('78000000-0000-4000-8000-000000000001', 'sid-limit-b', '[]',
59
+ public.test_pubkey('sid-limit-b'), interval '1 hour', false, 'codex', 'limit-b');
60
+ end $$;
61
+ }
62
+ step "b_duplicate" {
63
+ do $$ begin
64
+ perform * from agent_board.mint_delegated_child('78000000-0000-4000-8000-000000000001', 'sid-limit-b', '[]',
65
+ public.test_pubkey('sid-limit-b'), interval '1 hour', false, 'codex', 'limit-a');
66
+ end $$;
67
+ }
68
+ step "b_commit" { COMMIT; }
69
+
70
+ session "check"
71
+ step "check" {
72
+ select count(*) as mixed_hourly, count(*) filter (where revoked_at is not null) as tombstoned_hourly
73
+ from agent_board.delegation_grants where root_agent_id = '78000000-0000-4000-8000-000000000001';
74
+ select count(*) as new_principals from agent_board.agents where handle in ('sid-limit-a', 'sid-limit-b');
75
+ select count(*) as aliases from agent_board.session_id_aliases where root_agent_id = '78000000-0000-4000-8000-000000000001';
76
+ }
77
+
78
+ permutation "a_begin" "a_mint" "b_begin" "b_mint" "a_commit" "b_commit" "check"
79
+ permutation "b_begin" "b_mint" "a_begin" "a_mint" "b_commit" "a_commit" "check"
80
+ permutation "a_begin" "a_mint" "b_begin" "b_duplicate" "a_commit" "b_commit" "check"
81
+ permutation "b_begin" "b_duplicate" "a_begin" "a_mint" "b_commit" "a_commit" "check"
@@ -0,0 +1,82 @@
1
+ # Two verified service-role links serialize on one live Claude identity. Both
2
+ # commit orders and idempotent/different aliases are observable without sleeps.
3
+ setup
4
+ {
5
+ insert into auth.users(id) values ('71000000-0000-4000-8000-000000000001');
6
+ insert into agent_board.agents(id, agent_type, handle, display_name, status, auth_user_id, parent_agent_id, root_agent_id)
7
+ values
8
+ ('72000000-0000-4000-8000-000000000001', 'agent', 'sid-links-root', 'SID links root', 'active', null, null, null),
9
+ ('72000000-0000-4000-8000-000000000003', 'agent', 'sid-links-coowner', 'SID links coowner', 'active', null, null, null),
10
+ ('72000000-0000-4000-8000-000000000002', 'agent', 'sid-links-child', 'SID links child', 'active', '71000000-0000-4000-8000-000000000001',
11
+ '72000000-0000-4000-8000-000000000001', '72000000-0000-4000-8000-000000000001');
12
+ insert into agent_board.session_identities(agent_id, parent_agent_id, root_agent_id, depth, identity_kind, harness,
13
+ approved_risky_digest, current_risky_digest, holder_secret_hash, last_heartbeat)
14
+ values
15
+ ('72000000-0000-4000-8000-000000000001', null, '72000000-0000-4000-8000-000000000001', 0, 'legacy', null, 'approved', 'approved', null, null),
16
+ ('72000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000001', '72000000-0000-4000-8000-000000000001', 1, 'session', 'claude',
17
+ 'approved', 'approved', extensions.digest('isolation-holder', 'sha256'), now());
18
+ insert into agent_board.session_id_aliases(id, identity_agent_id, root_agent_id, harness, session_id)
19
+ values ('73000000-0000-4000-8000-000000000001', '72000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000001', 'claude', 'original');
20
+ update agent_board.session_identities set lease_alias_id = '73000000-0000-4000-8000-000000000001'
21
+ where agent_id = '72000000-0000-4000-8000-000000000002';
22
+ insert into agent_board.delegation_policies(id, root_agent_id, mode, allowed_scopes)
23
+ values ('74000000-0000-4000-8000-000000000001', '72000000-0000-4000-8000-000000000001', 'root_minted', '["read","write"]');
24
+ insert into agent_board.delegation_grants(child_agent_id, root_agent_id, parent_agent_id, delegation_policy_id, granted_scopes, grant_expires_at)
25
+ values ('72000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000001',
26
+ '72000000-0000-4000-8000-000000000001', '74000000-0000-4000-8000-000000000001', '["read","write"]', now() + interval '8 hours');
27
+ insert into agent_board.boards(id, slug, name, created_by_agent_id)
28
+ values ('74000000-0000-4000-8000-000000000002', 'sid-links-room', 'SID links room', '72000000-0000-4000-8000-000000000001');
29
+ insert into agent_board.board_memberships(board_id, agent_id, membership_state, role) values
30
+ ('74000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000001', 'joined', 'owner'),
31
+ ('74000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000003', 'joined', 'owner'),
32
+ ('74000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000002', 'joined', 'admin');
33
+ }
34
+
35
+ teardown
36
+ {
37
+ delete from agent_board.board_membership_events where board_id = '74000000-0000-4000-8000-000000000002';
38
+ delete from agent_board.boards where id = '74000000-0000-4000-8000-000000000002';
39
+ delete from agent_board.delegation_grants where root_agent_id = '72000000-0000-4000-8000-000000000001';
40
+ delete from agent_board.delegation_policies where root_agent_id = '72000000-0000-4000-8000-000000000001';
41
+ update agent_board.session_identities set lease_alias_id = null where root_agent_id = '72000000-0000-4000-8000-000000000001';
42
+ delete from agent_board.session_id_aliases where root_agent_id = '72000000-0000-4000-8000-000000000001';
43
+ delete from agent_board.session_identities where root_agent_id = '72000000-0000-4000-8000-000000000001';
44
+ delete from agent_board.agents where id = '72000000-0000-4000-8000-000000000002';
45
+ delete from agent_board.agents where id = '72000000-0000-4000-8000-000000000001';
46
+ delete from agent_board.agents where id = '72000000-0000-4000-8000-000000000003';
47
+ delete from auth.users where id = '71000000-0000-4000-8000-000000000001';
48
+ }
49
+
50
+ session "a"
51
+ step "a_begin" { BEGIN; SET LOCAL ROLE service_role; SET LOCAL "request.jwt.claim.role" = 'service_role'; SET LOCAL "request.jwt.claim.sub" = '71000000-0000-4000-8000-000000000001'; }
52
+ step "a_link" { select agent_board.link_session_alias('72000000-0000-4000-8000-000000000002', '0', 'continued-a'); }
53
+ step "a_commit" { COMMIT; }
54
+ step "a_rebegin" { BEGIN; SET LOCAL ROLE service_role; SET LOCAL "request.jwt.claim.role" = 'service_role'; SET LOCAL "request.jwt.claim.sub" = '71000000-0000-4000-8000-000000000001'; }
55
+ step "a_relink" { select agent_board.link_session_alias('72000000-0000-4000-8000-000000000002', '0', 'continued-a'); }
56
+ step "a_recommit" { COMMIT; }
57
+
58
+ session "b"
59
+ step "b_begin" { BEGIN; SET LOCAL ROLE service_role; SET LOCAL "request.jwt.claim.role" = 'service_role'; SET LOCAL "request.jwt.claim.sub" = '71000000-0000-4000-8000-000000000001'; }
60
+ step "b_same" { select agent_board.link_session_alias('72000000-0000-4000-8000-000000000002', '0', 'continued-a'); }
61
+ step "b_other" { select agent_board.link_session_alias('72000000-0000-4000-8000-000000000002', '0', 'continued-b'); }
62
+ step "b_narrow" {
63
+ select role from agent_board.grant_board_role('74000000-0000-4000-8000-000000000002', '72000000-0000-4000-8000-000000000001', 'observer', '72000000-0000-4000-8000-000000000001');
64
+ select allowed_scopes from agent_board.upsert_delegation_policy('72000000-0000-4000-8000-000000000001', 'root_minted', '["read"]', 200, interval '8 hours', true);
65
+ }
66
+ step "b_commit" { COMMIT; }
67
+
68
+ session "check"
69
+ step "check" {
70
+ select count(*) as aliases, count(distinct identity_agent_id) as identities
71
+ from agent_board.session_id_aliases where root_agent_id = '72000000-0000-4000-8000-000000000001';
72
+ select credential_epoch, holder_secret_hash = extensions.digest('isolation-holder', 'sha256') as unchanged_holder
73
+ from agent_board.session_identities where agent_id = '72000000-0000-4000-8000-000000000002';
74
+ select granted_scopes, role from agent_board.delegation_grants g join agent_board.board_memberships bm on bm.agent_id = g.child_agent_id
75
+ where g.child_agent_id = '72000000-0000-4000-8000-000000000002' and bm.board_id = '74000000-0000-4000-8000-000000000002';
76
+ }
77
+
78
+ permutation "a_begin" "a_link" "b_begin" "b_same" "a_commit" "b_commit" "check"
79
+ permutation "b_begin" "b_same" "a_begin" "a_link" "b_commit" "a_commit" "check"
80
+ permutation "a_begin" "a_link" "b_begin" "b_other" "a_commit" "b_commit" "check"
81
+ permutation "a_begin" "a_link" "b_begin" "b_narrow" "a_commit" "b_commit" "a_rebegin" "a_relink" "a_recommit" "check"
82
+ permutation "b_begin" "b_narrow" "a_begin" "a_link" "b_commit" "a_commit" "check"