@consiliency/agent-board-schema 1.64.0 → 1.74.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 (171) hide show
  1. package/README.md +19 -0
  2. package/fixtures/already-applied.json +44 -4
  3. package/migrations/20261015000100_agent_board_session_provenance.sql +367 -0
  4. package/migrations/20261015000200_agent_board_request_preserve_removed.sql +87 -0
  5. package/migrations/20261015000300_agent_board_rls_correlation.sql +132 -0
  6. package/migrations/20261015000400_agent_board_resolution_authority.sql +146 -0
  7. package/migrations/20261026000100_agent_board_thread_association.sql +1287 -0
  8. package/migrations/20261101000100_agent_board_session_measured_mint.sql +145 -0
  9. package/migrations/20261104065658_agent_board_reply_delivery.sql +659 -0
  10. package/migrations/20261104170000_agent_board_tasking_replay_scope.sql +320 -0
  11. package/migrations/20261104180000_agent_board_delivery_writer_execute.sql +51 -0
  12. package/migrations/20261104190000_agent_board_message_replay_scope.sql +373 -0
  13. package/package.json +1 -1
  14. package/schema-manifest.json +93 -3
  15. package/src/deployment-drift-main.test.mjs +156 -0
  16. package/src/deployment-drift-script.test.mjs +14 -1
  17. package/src/policy-comment.test.mjs +17 -0
  18. package/src/tooling.test.mjs +12 -2
  19. package/tests/agent_board_661_reply_delivery.test.sql +185 -0
  20. package/tests/agent_board_667_boundary.test.sql +162 -0
  21. package/tests/agent_board_667_conversion_branches.test.sql +91 -0
  22. package/tests/agent_board_667_conversion_profile.test.sql +112 -0
  23. package/tests/agent_board_667_history_class.test.sql +785 -0
  24. package/tests/agent_board_667_native_cast_effect.test.sql +88 -0
  25. package/tests/agent_board_667_realtime_apply_behavior.test.sql +117 -0
  26. package/tests/agent_board_667_realtime_apply_controls.test.sql +143 -0
  27. package/tests/agent_board_667_realtime_apply_profile.test.sql +61 -0
  28. package/tests/agent_board_667_retention.test.sql +201 -0
  29. package/tests/agent_board_667_routing.test.sql +294 -0
  30. package/tests/agent_board_667_sender_effects.test.sql +100 -0
  31. package/tests/agent_board_667_sender_profile_controls.test.sql +29 -0
  32. package/tests/agent_board_667_storage_delimiter_behavior.test.sql +84 -0
  33. package/tests/agent_board_667_storage_delimiter_controls.test.sql +23 -0
  34. package/tests/agent_board_667_storage_delimiter_profile.test.sql +61 -0
  35. package/tests/agent_board_667_storage_search_behavior.test.sql +93 -0
  36. package/tests/agent_board_667_storage_search_controls.test.sql +22 -0
  37. package/tests/agent_board_667_storage_search_profile.test.sql +60 -0
  38. package/tests/agent_board_667_storage_timestamp_behavior.test.sql +58 -0
  39. package/tests/agent_board_667_storage_timestamp_controls.test.sql +22 -0
  40. package/tests/agent_board_667_storage_timestamp_profile.test.sql +54 -0
  41. package/tests/agent_board_667_writers.test.sql +281 -0
  42. package/tests/agent_board_717_message_replay_scope.test.sql +828 -0
  43. package/tests/agent_board_717_tasking_replay_scope.test.sql +661 -0
  44. package/tests/agent_board_addressing.test.sql +8 -5
  45. package/tests/agent_board_claim_subject_gate.test.sql +7 -3
  46. package/tests/agent_board_claimpolicy_race.test.sql +39 -11
  47. package/tests/agent_board_consent_gating.test.sql +4 -4
  48. package/tests/agent_board_delegate_role_class.test.sql +33 -15
  49. package/tests/agent_board_delivery_writer_execute.test.sql +371 -0
  50. package/tests/agent_board_fk_lock_edges.test.sql +3 -0
  51. package/tests/agent_board_gatenull_membstate.test.sql +7 -4
  52. package/tests/agent_board_hosted_delegates.test.sql +5 -2
  53. package/tests/agent_board_inbox_rpcs.test.sql +5 -3
  54. package/tests/agent_board_obsgate.test.sql +8 -4
  55. package/tests/agent_board_obsgate4.test.sql +2 -2
  56. package/tests/agent_board_outbox_wake_ordering.test.sql +25 -2
  57. package/tests/agent_board_own_post_not_delivered.test.sql +11 -9
  58. package/tests/agent_board_policy_correlation.test.sql +189 -0
  59. package/tests/agent_board_request_removed.test.sql +96 -0
  60. package/tests/agent_board_resolution_authority.test.sql +190 -0
  61. package/tests/agent_board_session_identity_behavior_classes.test.sql +2 -2
  62. package/tests/agent_board_session_identity_limits.test.sql +1 -1
  63. package/tests/agent_board_session_identity_measured_mint.test.sql +342 -0
  64. package/tests/agent_board_session_identity_predicate_isolation.test.sql +146 -0
  65. package/tests/agent_board_session_provenance.test.sql +106 -0
  66. package/tests/agent_board_sidserver_authority.test.sql +69 -0
  67. package/tests/agent_board_sidserver_catalog.test.sql +47 -0
  68. package/tests/agent_board_signed_write_gateway.test.sql +4 -2
  69. package/tests/agent_board_task_thread_lock_order.test.sql +67 -42
  70. package/tests/agent_board_v2_invariants.test.sql +5 -2
  71. package/tests/agent_board_write_enforcement_class.test.sql +3 -3
  72. package/tests/catalog/function_execute_privileges.json +43 -7
  73. package/tests/catalog/p_metadata_parameters.json +16 -0
  74. package/tests/fixtures/agent_board_667_apply_rls_guard.sql +195 -0
  75. package/tests/fixtures/agent_board_667_apply_rls_provenance.md +125 -0
  76. package/tests/fixtures/agent_board_667_apply_rls_reference.sql +1903 -0
  77. package/tests/fixtures/agent_board_667_conversion_guard.sql +162 -0
  78. package/tests/fixtures/agent_board_667_conversion_reference.md +23 -0
  79. package/tests/fixtures/agent_board_667_conversion_reference.sql +5325 -0
  80. package/tests/fixtures/agent_board_667_delimiter_guard.sql +92 -0
  81. package/tests/fixtures/agent_board_667_delimiter_provenance.md +116 -0
  82. package/tests/fixtures/agent_board_667_delimiter_reference.sql +10150 -0
  83. package/tests/fixtures/agent_board_667_search_guard.sql +92 -0
  84. package/tests/fixtures/agent_board_667_search_provenance.md +141 -0
  85. package/tests/fixtures/agent_board_667_search_reference.sql +4779 -0
  86. package/tests/fixtures/agent_board_667_sender_guard.sql +102 -0
  87. package/tests/fixtures/agent_board_667_sender_reference.md +20 -0
  88. package/tests/fixtures/agent_board_667_sender_reference.sql +875 -0
  89. package/tests/fixtures/agent_board_667_timestamp_graph.sql +84 -0
  90. package/tests/fixtures/agent_board_667_timestamp_guard.sql +94 -0
  91. package/tests/fixtures/agent_board_667_timestamp_provenance.md +99 -0
  92. package/tests/fixtures/agent_board_667_timestamp_reference.sql +2938 -0
  93. package/tests/isolation/expected/association_artifact_anchor_order.out +108 -0
  94. package/tests/isolation/expected/association_board_vs_board.out +71 -0
  95. package/tests/isolation/expected/association_post_wait_authority.out +77 -0
  96. package/tests/isolation/expected/association_strong_history_writers.out +203 -0
  97. package/tests/isolation/expected/association_strong_isolation.out +185 -0
  98. package/tests/isolation/expected/association_vs_artifact_claim_escalation.out +199 -0
  99. package/tests/isolation/expected/association_vs_heartbeat.out +78 -0
  100. package/tests/isolation/expected/association_vs_multi_anchor_artifact.out +67 -0
  101. package/tests/isolation/expected/association_vs_private_message.out +67 -0
  102. package/tests/isolation/expected/association_vs_task_and_conflict.out +133 -0
  103. package/tests/isolation/expected/association_vs_taskful_cross_thread.out +133 -0
  104. package/tests/isolation/expected/consent_approval_lock.out +1 -1
  105. package/tests/isolation/expected/message_replay_scope.out +209 -0
  106. package/tests/isolation/expected/tasking_replay_scope.out +125 -0
  107. package/tests/isolation/specs/association_artifact_anchor_order.spec +46 -0
  108. package/tests/isolation/specs/association_board_vs_board.spec +37 -0
  109. package/tests/isolation/specs/association_post_wait_authority.spec +48 -0
  110. package/tests/isolation/specs/association_strong_history_writers.spec +61 -0
  111. package/tests/isolation/specs/association_strong_isolation.spec +50 -0
  112. package/tests/isolation/specs/association_vs_artifact_claim_escalation.spec +41 -0
  113. package/tests/isolation/specs/association_vs_heartbeat.spec +47 -0
  114. package/tests/isolation/specs/association_vs_multi_anchor_artifact.spec +38 -0
  115. package/tests/isolation/specs/association_vs_private_message.spec +33 -0
  116. package/tests/isolation/specs/association_vs_task_and_conflict.spec +38 -0
  117. package/tests/isolation/specs/association_vs_taskful_cross_thread.spec +42 -0
  118. package/tests/isolation/specs/consent_approval_lock.spec +13 -7
  119. package/tests/isolation/specs/message_replay_scope.spec +77 -0
  120. package/tests/isolation/specs/tasking_replay_scope.spec +72 -0
  121. package/tests/mutations/717-f1/M0_prefix_main_acl_and_comments.sql +11 -0
  122. package/tests/mutations/717-f1/M10_wrapper_stops_delegating.sql +7 -0
  123. package/tests/mutations/717-f1/M11_transitive_recipient_content.sql +8 -0
  124. package/tests/mutations/717-f1/M12_transitive_recipient_visibility.sql +8 -0
  125. package/tests/mutations/717-f1/M13_transitive_worker_content.sql +15 -0
  126. package/tests/mutations/717-f1/M1a_regrant_upsert_delivery_recipient.sql +1 -0
  127. package/tests/mutations/717-f1/M1b_regrant_upsert_inbox_item.sql +1 -0
  128. package/tests/mutations/717-f1/M1c_regrant_queue_inbox_callbacks.sql +1 -0
  129. package/tests/mutations/717-f1/M1d_regrant_queue_board_post_callbacks.sql +1 -0
  130. package/tests/mutations/717-f1/M1e_regrant_next_thread_message_sequence.sql +1 -0
  131. package/tests/mutations/717-f1/M2_blanket_schema_grant.sql +1 -0
  132. package/tests/mutations/717-f1/M3_new_overload_of_sink.sql +10 -0
  133. package/tests/mutations/717-f1/M4_new_route_calling_sink.sql +7 -0
  134. package/tests/mutations/717-f1/M5_actor_trusts_supplied_id.sql +5 -0
  135. package/tests/mutations/717-f1/M6_signed_route_granted_to_authenticated.sql +1 -0
  136. package/tests/mutations/717-f1/M7_worker_granted_to_authenticated.sql +1 -0
  137. package/tests/mutations/717-f1/M8_recipient_state_rewrites_visibility.sql +5 -0
  138. package/tests/mutations/717-f1/M9_public_route_revoked_from_service_role.sql +1 -0
  139. package/tests/mutations/717-f1/outbox_wake_ordering/W1_regrant_queue_inbox_callbacks.sql +1 -0
  140. package/tests/mutations/717-f1/outbox_wake_ordering/W2_revoke_worker_from_service_role.sql +1 -0
  141. package/tests/mutations/717-f1/outbox_wake_ordering/W3_invoker_caller_of_sink.sql +1 -0
  142. package/tests/mutations/717-f1/outbox_wake_ordering/W4_public_regrant_board_post_sink.sql +1 -0
  143. package/tests/mutations/717-f1/run.sh +17 -0
  144. package/tests/mutations/717-f2b/C1_new_delivery_route.sql +4 -0
  145. package/tests/mutations/717-f2b/C2_new_replay_lookup.sql +3 -0
  146. package/tests/mutations/717-f2b/C3_internal_regranted.sql +2 -0
  147. package/tests/mutations/717-f2b/C4_wrapper_writes_delivery.sql +9 -0
  148. package/tests/mutations/717-f2b/C5_class_member_dynamic_sql.sql +9 -0
  149. package/tests/mutations/717-f2b/C6_drop_board_scope_constraint.sql +2 -0
  150. package/tests/mutations/717-f2b/C7_state_private_helper_content.sql +14 -0
  151. package/tests/mutations/717-f2b/L1_dm_lock_split_by_recipient.sql +8 -0
  152. package/tests/mutations/717-f2b/L2_dm_lock_removed.sql +12 -0
  153. package/tests/mutations/717-f2b/L3_mc_lock_split_by_recipients.sql +8 -0
  154. package/tests/mutations/717-f2b/L4_mc_lock_removed.sql +12 -0
  155. package/tests/mutations/717-f2b/M0_prefix_definitions.sql +17 -0
  156. package/tests/mutations/717-f2b/M10_mc_lookup_any_author.sql +15 -0
  157. package/tests/mutations/717-f2b/M11_dm_swallow_refusal.sql +8 -0
  158. package/tests/mutations/717-f2b/M12_mc_swallow_refusal.sql +8 -0
  159. package/tests/mutations/717-f2b/M13_signed_dm_swallows_refusal.sql +32 -0
  160. package/tests/mutations/717-f2b/M14_signed_mc_swallows_refusal.sql +20 -0
  161. package/tests/mutations/717-f2b/M15_mc_any_source.sql +7 -0
  162. package/tests/mutations/717-f2b/M1_dm_drop_recipient_proof.sql +16 -0
  163. package/tests/mutations/717-f2b/M2_mc_drop_recipient_proof.sql +16 -0
  164. package/tests/mutations/717-f2b/M3_dm_metadata_as_proof.sql +12 -0
  165. package/tests/mutations/717-f2b/M4_mc_metadata_as_proof.sql +16 -0
  166. package/tests/mutations/717-f2b/M5_dm_any_mode.sql +11 -0
  167. package/tests/mutations/717-f2b/M6_dm_board_delivery_counts.sql +11 -0
  168. package/tests/mutations/717-f2b/M7_mc_any_mode.sql +11 -0
  169. package/tests/mutations/717-f2b/M8_dm_thread_stamp_as_proof.sql +12 -0
  170. package/tests/mutations/717-f2b/M9_dm_lookup_any_author.sql +15 -0
  171. package/tests/mutations/717-f2b/run.sh +82 -0
@@ -1,7 +1,7 @@
1
1
  Parsed test spec with 3 sessions
2
2
 
3
3
  starting permutation: a_begin a_resolve w_begin w_leave a_commit w_commit chk
4
- step a_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
4
+ step a_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'authenticated'; SET LOCAL "request.jwt.claim.sub" = '115d0000-0000-4000-8000-000000000001';
5
5
  step a_resolve:
6
6
  select membership_state
7
7
  from agent_board.resolve_board_request(
@@ -0,0 +1,209 @@
1
+ Parsed test spec with 4 sessions
2
+
3
+ starting permutation: p_begin p_dm_c w_begin w_dm_x p_end w_end check
4
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
5
+ set_config|set_config|set_config
6
+ ----------+----------+--------------------------------------------------------------------------
7
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
8
+ (1 row)
9
+
10
+ step p_dm_c: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000003','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object());
11
+ callback_outbox_count
12
+ ---------------------
13
+ 1
14
+ (1 row)
15
+
16
+ step w_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
17
+ set_config|set_config|set_config
18
+ ----------+----------+--------------------------------------------------------------------------
19
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
20
+ (1 row)
21
+
22
+ step w_dm_x: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000005','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object()); <waiting ...>
23
+ step p_end: end;
24
+ step w_dm_x: <... completed>
25
+ ERROR: message replay cannot widen delivery scope
26
+ step w_end: end;
27
+ step check:
28
+ select count(*) as messages,
29
+ (select string_agg(a.handle || ':' || dr.delivery_mode, ',' order by a.handle, dr.delivery_mode)
30
+ from agent_board.delivery_recipients dr join agent_board.messages m on m.id = dr.source_message_id
31
+ join agent_board.agents a on a.id = dr.recipient_agent_id
32
+ where m.thread_id = '717b4000-0000-4000-8000-000000000010') as deliveries,
33
+ (select count(*) from agent_board.inbox_items ii join agent_board.messages m on m.id = ii.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as inbox,
34
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.messages m on m.id = co.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as callbacks
35
+ from agent_board.messages where thread_id = '717b4000-0000-4000-8000-000000000010';
36
+
37
+ messages|deliveries |inbox|callbacks
38
+ --------+-------------------+-----+---------
39
+ 1|f2b717-iso-c:direct| 1| 1
40
+ (1 row)
41
+
42
+
43
+ starting permutation: w_begin w_dm_x p_begin p_dm_c w_end p_end check
44
+ step w_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
45
+ set_config|set_config|set_config
46
+ ----------+----------+--------------------------------------------------------------------------
47
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
48
+ (1 row)
49
+
50
+ step w_dm_x: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000005','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object());
51
+ callback_outbox_count
52
+ ---------------------
53
+ 1
54
+ (1 row)
55
+
56
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
57
+ set_config|set_config|set_config
58
+ ----------+----------+--------------------------------------------------------------------------
59
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
60
+ (1 row)
61
+
62
+ step p_dm_c: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000003','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object()); <waiting ...>
63
+ step w_end: end;
64
+ step p_dm_c: <... completed>
65
+ ERROR: message replay cannot widen delivery scope
66
+ step p_end: end;
67
+ step check:
68
+ select count(*) as messages,
69
+ (select string_agg(a.handle || ':' || dr.delivery_mode, ',' order by a.handle, dr.delivery_mode)
70
+ from agent_board.delivery_recipients dr join agent_board.messages m on m.id = dr.source_message_id
71
+ join agent_board.agents a on a.id = dr.recipient_agent_id
72
+ where m.thread_id = '717b4000-0000-4000-8000-000000000010') as deliveries,
73
+ (select count(*) from agent_board.inbox_items ii join agent_board.messages m on m.id = ii.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as inbox,
74
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.messages m on m.id = co.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as callbacks
75
+ from agent_board.messages where thread_id = '717b4000-0000-4000-8000-000000000010';
76
+
77
+ messages|deliveries |inbox|callbacks
78
+ --------+-------------------+-----+---------
79
+ 1|f2b717-iso-x:direct| 1| 1
80
+ (1 row)
81
+
82
+
83
+ starting permutation: p_begin p_dm_c r_begin r_dm_c p_end r_end check
84
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
85
+ set_config|set_config|set_config
86
+ ----------+----------+--------------------------------------------------------------------------
87
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
88
+ (1 row)
89
+
90
+ step p_dm_c: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000003','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object());
91
+ callback_outbox_count
92
+ ---------------------
93
+ 1
94
+ (1 row)
95
+
96
+ step r_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
97
+ set_config|set_config|set_config
98
+ ----------+----------+--------------------------------------------------------------------------
99
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
100
+ (1 row)
101
+
102
+ step r_dm_c: select callback_outbox_count from agent_board.send_direct_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001','717b4000-0000-4000-8000-000000000003','iso','iso dm','comment','medium','f2b717-kd',jsonb_build_object()); <waiting ...>
103
+ step p_end: end;
104
+ step r_dm_c: <... completed>
105
+ callback_outbox_count
106
+ ---------------------
107
+ 0
108
+ (1 row)
109
+
110
+ step r_end: end;
111
+ step check:
112
+ select count(*) as messages,
113
+ (select string_agg(a.handle || ':' || dr.delivery_mode, ',' order by a.handle, dr.delivery_mode)
114
+ from agent_board.delivery_recipients dr join agent_board.messages m on m.id = dr.source_message_id
115
+ join agent_board.agents a on a.id = dr.recipient_agent_id
116
+ where m.thread_id = '717b4000-0000-4000-8000-000000000010') as deliveries,
117
+ (select count(*) from agent_board.inbox_items ii join agent_board.messages m on m.id = ii.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as inbox,
118
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.messages m on m.id = co.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as callbacks
119
+ from agent_board.messages where thread_id = '717b4000-0000-4000-8000-000000000010';
120
+
121
+ messages|deliveries |inbox|callbacks
122
+ --------+-------------------+-----+---------
123
+ 1|f2b717-iso-c:direct| 1| 1
124
+ (1 row)
125
+
126
+
127
+ starting permutation: p_begin p_mc_cc2 w_begin w_mc_cx p_end w_end check
128
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
129
+ set_config|set_config|set_config
130
+ ----------+----------+--------------------------------------------------------------------------
131
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
132
+ (1 row)
133
+
134
+ step p_mc_cc2: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.send_multicast_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001',array['717b4000-0000-4000-8000-000000000003','717b4000-0000-4000-8000-000000000004']::uuid[],'iso','iso mc','comment','medium','f2b717-km',jsonb_build_object());
135
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
136
+ -------------------------+----------------+---------------------
137
+ 2| 2| 2
138
+ (1 row)
139
+
140
+ step w_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
141
+ set_config|set_config|set_config
142
+ ----------+----------+--------------------------------------------------------------------------
143
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
144
+ (1 row)
145
+
146
+ step w_mc_cx: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.send_multicast_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001',array['717b4000-0000-4000-8000-000000000003','717b4000-0000-4000-8000-000000000005']::uuid[],'iso','iso mc','comment','medium','f2b717-km',jsonb_build_object()); <waiting ...>
147
+ step p_end: end;
148
+ step w_mc_cx: <... completed>
149
+ ERROR: message replay cannot widen delivery scope
150
+ step w_end: end;
151
+ step check:
152
+ select count(*) as messages,
153
+ (select string_agg(a.handle || ':' || dr.delivery_mode, ',' order by a.handle, dr.delivery_mode)
154
+ from agent_board.delivery_recipients dr join agent_board.messages m on m.id = dr.source_message_id
155
+ join agent_board.agents a on a.id = dr.recipient_agent_id
156
+ where m.thread_id = '717b4000-0000-4000-8000-000000000010') as deliveries,
157
+ (select count(*) from agent_board.inbox_items ii join agent_board.messages m on m.id = ii.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as inbox,
158
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.messages m on m.id = co.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as callbacks
159
+ from agent_board.messages where thread_id = '717b4000-0000-4000-8000-000000000010';
160
+
161
+ messages|deliveries |inbox|callbacks
162
+ --------+----------------------------------------------+-----+---------
163
+ 1|f2b717-iso-c:multicast,f2b717-iso-c2:multicast| 2| 2
164
+ (1 row)
165
+
166
+
167
+ starting permutation: p_begin p_mc_cc2 r_begin r_mc_c2c p_end r_end check
168
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
169
+ set_config|set_config|set_config
170
+ ----------+----------+--------------------------------------------------------------------------
171
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
172
+ (1 row)
173
+
174
+ step p_mc_cc2: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.send_multicast_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001',array['717b4000-0000-4000-8000-000000000003','717b4000-0000-4000-8000-000000000004']::uuid[],'iso','iso mc','comment','medium','f2b717-km',jsonb_build_object());
175
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
176
+ -------------------------+----------------+---------------------
177
+ 2| 2| 2
178
+ (1 row)
179
+
180
+ step r_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','717b4000-0000-4000-8000-0000000000a1')::text,true);
181
+ set_config|set_config|set_config
182
+ ----------+----------+--------------------------------------------------------------------------
183
+ | |{"role" : "authenticated", "sub" : "717b4000-0000-4000-8000-0000000000a1"}
184
+ (1 row)
185
+
186
+ step r_mc_c2c: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.send_multicast_message('717b4000-0000-4000-8000-000000000010','717b4000-0000-4000-8000-000000000001',array['717b4000-0000-4000-8000-000000000004','717b4000-0000-4000-8000-000000000003','717b4000-0000-4000-8000-000000000004']::uuid[],'iso','iso mc','comment','medium','f2b717-km',jsonb_build_object()); <waiting ...>
187
+ step p_end: end;
188
+ step r_mc_c2c: <... completed>
189
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
190
+ -------------------------+----------------+---------------------
191
+ 2| 2| 0
192
+ (1 row)
193
+
194
+ step r_end: end;
195
+ step check:
196
+ select count(*) as messages,
197
+ (select string_agg(a.handle || ':' || dr.delivery_mode, ',' order by a.handle, dr.delivery_mode)
198
+ from agent_board.delivery_recipients dr join agent_board.messages m on m.id = dr.source_message_id
199
+ join agent_board.agents a on a.id = dr.recipient_agent_id
200
+ where m.thread_id = '717b4000-0000-4000-8000-000000000010') as deliveries,
201
+ (select count(*) from agent_board.inbox_items ii join agent_board.messages m on m.id = ii.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as inbox,
202
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.messages m on m.id = co.source_message_id where m.thread_id = '717b4000-0000-4000-8000-000000000010') as callbacks
203
+ from agent_board.messages where thread_id = '717b4000-0000-4000-8000-000000000010';
204
+
205
+ messages|deliveries |inbox|callbacks
206
+ --------+----------------------------------------------+-----+---------
207
+ 1|f2b717-iso-c:multicast,f2b717-iso-c2:multicast| 2| 2
208
+ (1 row)
209
+
@@ -0,0 +1,125 @@
1
+ Parsed test spec with 4 sessions
2
+
3
+ starting permutation: p_begin p_private b_begin b_board p_end b_end check
4
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
5
+ set_config|set_config|set_config
6
+ ----------+----------+--------------------------------------------------------------------------
7
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
8
+ (1 row)
9
+
10
+ step p_private: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso private',null,array['71740000-0000-4000-8000-000000000003']::uuid[],null,'medium','distributed','f2717-kc',jsonb_build_object());
11
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
12
+ -------------------------+----------------+---------------------
13
+ 1| 1| 1
14
+ (1 row)
15
+
16
+ step b_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
17
+ set_config|set_config|set_config
18
+ ----------+----------+--------------------------------------------------------------------------
19
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
20
+ (1 row)
21
+
22
+ step b_board: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso board',null,null,'71740000-0000-4000-8000-000000000020','medium','distributed','f2717-kc',jsonb_build_object()); <waiting ...>
23
+ step p_end: end;
24
+ step b_board: <... completed>
25
+ ERROR: tasking replay cannot widen delivery scope
26
+ step b_end: end;
27
+ step check:
28
+ select count(*) as tasks,
29
+ (select count(*) from agent_board.task_events te join agent_board.tasks t on t.id = te.task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as events,
30
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is null) as private_deliveries,
31
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is not null) as board_deliveries,
32
+ (select count(*) from agent_board.inbox_items ii join agent_board.tasks t on t.id = ii.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as inbox,
33
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.tasks t on t.id = co.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as callbacks,
34
+ string_agg(title, ',' order by title) as titles
35
+ from agent_board.tasks where thread_id = '71740000-0000-4000-8000-000000000010';
36
+
37
+ tasks|events|private_deliveries|board_deliveries|inbox|callbacks|titles
38
+ -----+------+------------------+----------------+-----+---------+-----------
39
+ 1| 1| 1| 0| 1| 1|iso private
40
+ (1 row)
41
+
42
+
43
+ starting permutation: b_begin b_board p_begin p_private b_end p_end check
44
+ step b_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
45
+ set_config|set_config|set_config
46
+ ----------+----------+--------------------------------------------------------------------------
47
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
48
+ (1 row)
49
+
50
+ step b_board: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso board',null,null,'71740000-0000-4000-8000-000000000020','medium','distributed','f2717-kc',jsonb_build_object());
51
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
52
+ -------------------------+----------------+---------------------
53
+ 0| 0| 0
54
+ (1 row)
55
+
56
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
57
+ set_config|set_config|set_config
58
+ ----------+----------+--------------------------------------------------------------------------
59
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
60
+ (1 row)
61
+
62
+ step p_private: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso private',null,array['71740000-0000-4000-8000-000000000003']::uuid[],null,'medium','distributed','f2717-kc',jsonb_build_object()); <waiting ...>
63
+ step b_end: end;
64
+ step p_private: <... completed>
65
+ ERROR: tasking replay cannot widen delivery scope
66
+ step p_end: end;
67
+ step check:
68
+ select count(*) as tasks,
69
+ (select count(*) from agent_board.task_events te join agent_board.tasks t on t.id = te.task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as events,
70
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is null) as private_deliveries,
71
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is not null) as board_deliveries,
72
+ (select count(*) from agent_board.inbox_items ii join agent_board.tasks t on t.id = ii.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as inbox,
73
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.tasks t on t.id = co.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as callbacks,
74
+ string_agg(title, ',' order by title) as titles
75
+ from agent_board.tasks where thread_id = '71740000-0000-4000-8000-000000000010';
76
+
77
+ tasks|events|private_deliveries|board_deliveries|inbox|callbacks|titles
78
+ -----+------+------------------+----------------+-----+---------+---------
79
+ 1| 1| 0| 1| 1| 0|iso board
80
+ (1 row)
81
+
82
+
83
+ starting permutation: p_begin p_private r_begin r_private p_end r_end check
84
+ step p_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
85
+ set_config|set_config|set_config
86
+ ----------+----------+--------------------------------------------------------------------------
87
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
88
+ (1 row)
89
+
90
+ step p_private: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso private',null,array['71740000-0000-4000-8000-000000000003']::uuid[],null,'medium','distributed','f2717-kc',jsonb_build_object());
91
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
92
+ -------------------------+----------------+---------------------
93
+ 1| 1| 1
94
+ (1 row)
95
+
96
+ step r_begin: begin; set local role authenticated; select set_config('request.jwt.claim.role','',true), set_config('request.jwt.claim.sub','',true), set_config('request.jwt.claims',json_build_object('role','authenticated','sub','71740000-0000-4000-8000-0000000000a1')::text,true);
97
+ set_config|set_config|set_config
98
+ ----------+----------+--------------------------------------------------------------------------
99
+ | |{"role" : "authenticated", "sub" : "71740000-0000-4000-8000-0000000000a1"}
100
+ (1 row)
101
+
102
+ step r_private: select delivered_recipient_count, inbox_item_count, callback_outbox_count from agent_board.create_tasking_delivery('71740000-0000-4000-8000-000000000010','71740000-0000-4000-8000-000000000001','iso private',null,array['71740000-0000-4000-8000-000000000003']::uuid[],null,'medium','distributed','f2717-kc',jsonb_build_object()); <waiting ...>
103
+ step p_end: end;
104
+ step r_private: <... completed>
105
+ delivered_recipient_count|inbox_item_count|callback_outbox_count
106
+ -------------------------+----------------+---------------------
107
+ 1| 1| 0
108
+ (1 row)
109
+
110
+ step r_end: end;
111
+ step check:
112
+ select count(*) as tasks,
113
+ (select count(*) from agent_board.task_events te join agent_board.tasks t on t.id = te.task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as events,
114
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is null) as private_deliveries,
115
+ (select count(*) from agent_board.delivery_recipients dr join agent_board.tasks t on t.id = dr.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010' and dr.board_id is not null) as board_deliveries,
116
+ (select count(*) from agent_board.inbox_items ii join agent_board.tasks t on t.id = ii.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as inbox,
117
+ (select count(*) from agent_board.callback_outbox_events co join agent_board.tasks t on t.id = co.source_task_id where t.thread_id = '71740000-0000-4000-8000-000000000010') as callbacks,
118
+ string_agg(title, ',' order by title) as titles
119
+ from agent_board.tasks where thread_id = '71740000-0000-4000-8000-000000000010';
120
+
121
+ tasks|events|private_deliveries|board_deliveries|inbox|callbacks|titles
122
+ -----+------+------------------+----------------+-----+---------+-----------
123
+ 1| 1| 1| 0| 1| 1|iso private
124
+ (1 row)
125
+
@@ -0,0 +1,46 @@
1
+ # #667: an artifact may name an empty explicit thread and a task on another
2
+ # thread. The explicit thread must serialize with first association even when a
3
+ # different canonical anchor is also present.
4
+ setup
5
+ {
6
+ insert into agent_board.agents(id,agent_type,handle,display_name,status)
7
+ values ('66780000-0000-4000-8000-000000000001','agent','xb-anchor-order','XB multi anchor','active');
8
+ insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
9
+ values ('66780000-0000-4000-8000-000000000020','xb-anchor-order-board','XB multi anchor board',
10
+ '66780000-0000-4000-8000-000000000001','private','active');
11
+ insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
12
+ values ('66780000-0000-4000-8000-000000000010','coordination','66780000-0000-4000-8000-000000000001','explicit empty'),
13
+ ('66780000-0000-4000-8000-000000000011','coordination','66780000-0000-4000-8000-000000000001','task parent');
14
+ insert into agent_board.tasks(id,thread_id,created_by_agent_id,title)
15
+ values ('66780000-0000-4000-8000-000000000030','66780000-0000-4000-8000-000000000011','66780000-0000-4000-8000-000000000001','parent one'),
16
+ ('66780000-0000-4000-8000-000000000031','66780000-0000-4000-8000-000000000010','66780000-0000-4000-8000-000000000001','parent two');
17
+ }
18
+ teardown
19
+ {
20
+ delete from agent_board.artifacts where thread_id in ('66780000-0000-4000-8000-000000000010','66780000-0000-4000-8000-000000000011');
21
+ delete from agent_board.task_events where task_id in ('66780000-0000-4000-8000-000000000030','66780000-0000-4000-8000-000000000031');
22
+ delete from agent_board.tasks where id in ('66780000-0000-4000-8000-000000000030','66780000-0000-4000-8000-000000000031');
23
+ delete from agent_board.messages where thread_id='66780000-0000-4000-8000-000000000010';
24
+ delete from agent_board.threads where id in ('66780000-0000-4000-8000-000000000010','66780000-0000-4000-8000-000000000011');
25
+ delete from agent_board.boards where id='66780000-0000-4000-8000-000000000020';
26
+ delete from agent_board.agents where id='66780000-0000-4000-8000-000000000001';
27
+ }
28
+ session "a"
29
+ step "a_begin" { begin; set local statement_timeout='2s'; select set_config('request.jwt.claim.role','service_role',true); }
30
+ step "a_artifact" { select count(*) from agent_board.add_artifact('66780000-0000-4000-8000-000000000001','https://example.test/first',p_thread_id=>'66780000-0000-4000-8000-000000000010',p_task_id=>'66780000-0000-4000-8000-000000000030'); }
31
+ step "a_commit" { commit; }
32
+ session "b"
33
+ step "b_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
34
+ step "b_artifact" { select count(*) from agent_board.add_artifact('66780000-0000-4000-8000-000000000001','https://example.test/second',p_thread_id=>'66780000-0000-4000-8000-000000000011',p_task_id=>'66780000-0000-4000-8000-000000000031'); }
35
+ step "b_commit" { commit; }
36
+ session "hold"
37
+ step "hold_high" { begin; select id from agent_board.threads where id='66780000-0000-4000-8000-000000000011' for no key update; }
38
+ step "release_high" { commit; }
39
+ session "probe"
40
+ step "probe_low" { begin; select id from agent_board.threads where id='66780000-0000-4000-8000-000000000010' for no key update; }
41
+ step "probe_commit" { commit; }
42
+ session "check"
43
+ step "check" { select count(*) as artifacts, count(distinct thread_id) as explicit_threads, count(distinct task_id) as task_anchors from agent_board.artifacts where thread_id in ('66780000-0000-4000-8000-000000000010','66780000-0000-4000-8000-000000000011'); }
44
+ permutation "a_begin" "a_artifact" "b_begin" "b_artifact" "a_commit" "b_commit" "check"
45
+ permutation "b_begin" "b_artifact" "a_begin" "a_artifact" "b_commit" "a_commit" "check"
46
+ permutation "hold_high" "a_begin" "a_artifact" "probe_low" "release_high" "a_commit" "probe_commit" "check"
@@ -0,0 +1,37 @@
1
+ # Two first-association senders choose different boards. The loser must re-read
2
+ # the winning stamp after its wait and leave neither its message nor delivery.
3
+ setup
4
+ {
5
+ insert into agent_board.agents(id,agent_type,handle,display_name,status)
6
+ values ('66790000-0000-4000-8000-000000000001','agent','xb-board-race','XB board race','active');
7
+ insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
8
+ values ('66790000-0000-4000-8000-000000000020','xb-race-one','XB race one','66790000-0000-4000-8000-000000000001','private','active'),
9
+ ('66790000-0000-4000-8000-000000000021','xb-race-two','XB race two','66790000-0000-4000-8000-000000000001','private','active');
10
+ insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
11
+ values ('66790000-0000-4000-8000-000000000010','coordination','66790000-0000-4000-8000-000000000001','board race');
12
+ create function agent_board_test.xb_667_board_race(p_board uuid,p_text text) returns text language plpgsql as $$
13
+ begin
14
+ perform agent_board.post_board_message('66790000-0000-4000-8000-000000000010','66790000-0000-4000-8000-000000000001',p_board,'subject',p_text);
15
+ return 'allowed';
16
+ exception when others then return sqlstate || ':' || sqlerrm; end $$;
17
+ }
18
+ teardown
19
+ {
20
+ drop function agent_board_test.xb_667_board_race(uuid,text);
21
+ delete from agent_board.messages where thread_id='66790000-0000-4000-8000-000000000010';
22
+ delete from agent_board.threads where id='66790000-0000-4000-8000-000000000010';
23
+ delete from agent_board.boards where id in ('66790000-0000-4000-8000-000000000020','66790000-0000-4000-8000-000000000021');
24
+ delete from agent_board.agents where id='66790000-0000-4000-8000-000000000001';
25
+ }
26
+ session "a"
27
+ step "a_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
28
+ step "a_post" { select agent_board_test.xb_667_board_race('66790000-0000-4000-8000-000000000020','first') as outcome; }
29
+ step "a_commit" { commit; }
30
+ session "b"
31
+ step "b_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
32
+ step "b_post" { select agent_board_test.xb_667_board_race('66790000-0000-4000-8000-000000000021','second') as outcome; }
33
+ step "b_commit" { commit; }
34
+ session "check"
35
+ step "check" { select t.board_id, (select count(*) from agent_board.messages m where m.thread_id=t.id) as messages, (select count(*) from agent_board.messages m where m.thread_id=t.id and m.body='first') as first_messages, (select count(*) from agent_board.messages m where m.thread_id=t.id and m.body='second') as second_messages, (select count(*) from agent_board.delivery_recipients d join agent_board.messages m on m.id=d.source_message_id where m.thread_id=t.id) as deliveries from agent_board.threads t where t.id='66790000-0000-4000-8000-000000000010'; }
36
+ permutation "a_begin" "a_post" "b_begin" "b_post" "a_commit" "b_commit" "check"
37
+ permutation "b_begin" "b_post" "a_begin" "a_post" "b_commit" "a_commit" "check"
@@ -0,0 +1,48 @@
1
+ # #667: sequence UPDATE waits for association. The posting gate must be read
2
+ # after that wait. A nonmember thread creator is denied; a board member succeeds.
3
+ setup
4
+ {
5
+ insert into auth.users(id) values ('66750000-0000-4000-8000-0000000000b1'),('66750000-0000-4000-8000-0000000000c1');
6
+ insert into agent_board.agents(id,agent_type,handle,display_name,status,auth_user_id,owner_user_id)
7
+ values ('66750000-0000-4000-8000-000000000001','agent','xb-post-owner','XB owner','active',null,null),
8
+ ('66750000-0000-4000-8000-000000000002','agent','xb-post-denied','XB denied','active','66750000-0000-4000-8000-0000000000b1','66750000-0000-4000-8000-0000000000b1'),
9
+ ('66750000-0000-4000-8000-000000000003','agent','xb-post-member','XB member','active','66750000-0000-4000-8000-0000000000c1','66750000-0000-4000-8000-0000000000c1');
10
+ insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
11
+ values ('66750000-0000-4000-8000-000000000020','xb-post-board','XB post board','66750000-0000-4000-8000-000000000001','private','active');
12
+ select set_config('request.jwt.claim.role','service_role',false);
13
+ insert into agent_board.board_memberships(board_id,agent_id,membership_state,created_by_agent_id,role)
14
+ values ('66750000-0000-4000-8000-000000000020','66750000-0000-4000-8000-000000000003','joined','66750000-0000-4000-8000-000000000001','member');
15
+ insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
16
+ values ('66750000-0000-4000-8000-000000000010','coordination','66750000-0000-4000-8000-000000000002','denied thread'),
17
+ ('66750000-0000-4000-8000-000000000011','coordination','66750000-0000-4000-8000-000000000003','member thread');
18
+ }
19
+ teardown
20
+ {
21
+ delete from agent_board.inbox_items where board_id='66750000-0000-4000-8000-000000000020';
22
+ delete from agent_board.delivery_recipients where board_id='66750000-0000-4000-8000-000000000020';
23
+ delete from agent_board.messages where thread_id in ('66750000-0000-4000-8000-000000000010','66750000-0000-4000-8000-000000000011');
24
+ delete from agent_board.threads where id in ('66750000-0000-4000-8000-000000000010','66750000-0000-4000-8000-000000000011');
25
+ delete from agent_board.board_membership_events where board_id='66750000-0000-4000-8000-000000000020';
26
+ delete from agent_board.board_memberships where board_id='66750000-0000-4000-8000-000000000020';
27
+ delete from agent_board.boards where id='66750000-0000-4000-8000-000000000020';
28
+ delete from agent_board.agents where id in ('66750000-0000-4000-8000-000000000001','66750000-0000-4000-8000-000000000002','66750000-0000-4000-8000-000000000003');
29
+ delete from auth.users where id in ('66750000-0000-4000-8000-0000000000b1','66750000-0000-4000-8000-0000000000c1');
30
+ }
31
+ session "a"
32
+ step "a_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
33
+ step "a_post_denied" { select count(*) from agent_board.post_board_message('66750000-0000-4000-8000-000000000010','66750000-0000-4000-8000-000000000001','66750000-0000-4000-8000-000000000020','s','b'); }
34
+ step "a_post_member" { select count(*) from agent_board.post_board_message('66750000-0000-4000-8000-000000000011','66750000-0000-4000-8000-000000000001','66750000-0000-4000-8000-000000000020','s','b'); }
35
+ step "a_commit" { commit; }
36
+ session "b"
37
+ step "b_begin" { begin; set local role authenticated; select set_config('request.jwt.claim.role','authenticated',true); select set_config('request.jwt.claim.sub','66750000-0000-4000-8000-0000000000b1',true); }
38
+ step "b_post" { select count(*) from agent_board.post_message('66750000-0000-4000-8000-000000000010','66750000-0000-4000-8000-000000000002','private after wait'); }
39
+ step "b_end" { end; }
40
+ session "c"
41
+ step "c_begin" { begin; set local role authenticated; select set_config('request.jwt.claim.role','authenticated',true); select set_config('request.jwt.claim.sub','66750000-0000-4000-8000-0000000000c1',true); }
42
+ step "c_post" { select count(*) from agent_board.post_message('66750000-0000-4000-8000-000000000011','66750000-0000-4000-8000-000000000003','member after wait'); }
43
+ step "c_end" { end; }
44
+ session "check"
45
+ step "check_denied" { select count(*) as messages, max(message_sequence) as max_sequence from agent_board.messages where thread_id='66750000-0000-4000-8000-000000000010'; }
46
+ step "check_member" { select count(*) as messages, max(message_sequence) as max_sequence from agent_board.messages where thread_id='66750000-0000-4000-8000-000000000011'; }
47
+ permutation "a_begin" "a_post_denied" "b_begin" "b_post" "a_commit" "b_end" "check_denied"
48
+ permutation "a_begin" "a_post_member" "c_begin" "c_post" "a_commit" "c_end" "check_member"
@@ -0,0 +1,61 @@
1
+ # #667: fixed-snapshot first association refuses before stamping, even after a
2
+ # writer commits; already-associated board tasks remain allowed at stronger isolation.
3
+ setup
4
+ {
5
+ insert into agent_board.agents(id,agent_type,handle,display_name,status)
6
+ values ('66770000-0000-4000-8000-000000000001','agent','xb-strong-history','XB strong isolation','active');
7
+ insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
8
+ values ('66770000-0000-4000-8000-000000000020','xb-strong-history-board','XB strong board',
9
+ '66770000-0000-4000-8000-000000000001','private','active');
10
+ insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
11
+ values ('66770000-0000-4000-8000-000000000010','coordination',
12
+ '66770000-0000-4000-8000-000000000001','strong isolation');
13
+ create function agent_board_test.xb_667_try_stale_artifact() returns text language plpgsql as $$
14
+ begin
15
+ perform agent_board.add_artifact('66770000-0000-4000-8000-000000000001','https://example.test/stale',p_thread_id=>'66770000-0000-4000-8000-000000000010');
16
+ return 'allowed';
17
+ exception when others then return sqlstate || ':' || sqlerrm; end $$;
18
+ create function agent_board_test.xb_667_try_history_association() returns text language plpgsql as $$
19
+ begin
20
+ perform agent_board.post_board_message('66770000-0000-4000-8000-000000000010','66770000-0000-4000-8000-000000000001','66770000-0000-4000-8000-000000000020','s','b');
21
+ return 'allowed';
22
+ exception when others then return sqlstate || ':' || sqlerrm; end $$;
23
+ }
24
+ teardown
25
+ {
26
+ drop function agent_board_test.xb_667_try_history_association();
27
+ drop function agent_board_test.xb_667_try_stale_artifact();
28
+ delete from agent_board.artifacts where thread_id='66770000-0000-4000-8000-000000000010';
29
+ delete from agent_board.conflicts where thread_id='66770000-0000-4000-8000-000000000010';
30
+ delete from agent_board.task_events where thread_id='66770000-0000-4000-8000-000000000010';
31
+ delete from agent_board.tasks where thread_id='66770000-0000-4000-8000-000000000010';
32
+ delete from agent_board.messages where thread_id='66770000-0000-4000-8000-000000000010';
33
+ delete from agent_board.threads where id='66770000-0000-4000-8000-000000000010';
34
+ delete from agent_board.boards where id='66770000-0000-4000-8000-000000000020';
35
+ delete from agent_board.agents where id='66770000-0000-4000-8000-000000000001';
36
+ }
37
+ session "w"
38
+ step "w_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
39
+ step "w_artifact" { select count(*) from agent_board.add_artifact('66770000-0000-4000-8000-000000000001','https://example.test/strong',p_thread_id=>'66770000-0000-4000-8000-000000000010'); }
40
+ step "w_stale_artifact" { select agent_board_test.xb_667_try_stale_artifact() as outcome; }
41
+ step "w_conflict" { select count(*) from agent_board.raise_conflict('66770000-0000-4000-8000-000000000010','66770000-0000-4000-8000-000000000001','private conflict'); }
42
+ step "w_rr" { begin isolation level repeatable read; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66770000-0000-4000-8000-000000000010'; }
43
+ step "w_commit" { commit; }
44
+ session "a"
45
+ step "a_ru" { begin isolation level read uncommitted; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66770000-0000-4000-8000-000000000010'; }
46
+ step "a_rr" { begin isolation level repeatable read; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66770000-0000-4000-8000-000000000010'; }
47
+ step "a_ser" { begin isolation level serializable; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66770000-0000-4000-8000-000000000010'; }
48
+ step "a_post" { select agent_board_test.xb_667_try_history_association() as outcome; }
49
+ step "a_task" { select count(*) from agent_board.create_task('66770000-0000-4000-8000-000000000010','66770000-0000-4000-8000-000000000001','board task'); }
50
+ step "a_end" { end; }
51
+ session "p"
52
+ step "p_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
53
+ step "p_post" { select count(*) from agent_board.post_board_message('66770000-0000-4000-8000-000000000010','66770000-0000-4000-8000-000000000001','66770000-0000-4000-8000-000000000020','s','b'); }
54
+ step "p_commit" { commit; }
55
+ session "check"
56
+ step "check" { select (t.board_id is not null) as stamped, (select count(*) from agent_board.artifacts where thread_id=t.id) as artifacts, (select count(*) from agent_board.conflicts where thread_id=t.id) as conflicts, (select count(*) from agent_board.messages where thread_id=t.id) as messages from agent_board.threads t where t.id='66770000-0000-4000-8000-000000000010'; }
57
+ permutation "a_rr" "w_begin" "w_artifact" "a_post" "w_commit" "a_end" "check"
58
+ permutation "a_ser" "w_begin" "w_artifact" "a_post" "w_commit" "a_end" "check"
59
+ permutation "a_rr" "w_begin" "w_conflict" "a_post" "w_commit" "a_end" "check"
60
+ permutation "a_ser" "w_begin" "w_conflict" "a_post" "w_commit" "a_end" "check"
61
+ permutation "w_rr" "p_begin" "p_post" "w_stale_artifact" "p_commit" "w_commit" "check"
@@ -0,0 +1,50 @@
1
+ # #667: fixed-snapshot first association refuses before stamping, even after a
2
+ # writer commits; already-associated board tasks remain allowed at stronger isolation.
3
+ setup
4
+ {
5
+ insert into agent_board.agents(id,agent_type,handle,display_name,status)
6
+ values ('66740000-0000-4000-8000-000000000001','agent','xb-strong','XB strong isolation','active');
7
+ insert into agent_board.boards(id,slug,name,created_by_agent_id,visibility,status)
8
+ values ('66740000-0000-4000-8000-000000000020','xb-strong-board','XB strong board',
9
+ '66740000-0000-4000-8000-000000000001','private','active');
10
+ insert into agent_board.threads(id,thread_type,created_by_agent_id,subject)
11
+ values ('66740000-0000-4000-8000-000000000010','coordination',
12
+ '66740000-0000-4000-8000-000000000001','strong isolation');
13
+ create function agent_board_test.xb_667_try_association() returns text language plpgsql as $$
14
+ begin
15
+ perform agent_board.post_board_message('66740000-0000-4000-8000-000000000010','66740000-0000-4000-8000-000000000001','66740000-0000-4000-8000-000000000020','s','b');
16
+ return 'allowed';
17
+ exception when others then return sqlstate || ':' || sqlerrm; end $$;
18
+ }
19
+ teardown
20
+ {
21
+ drop function agent_board_test.xb_667_try_association();
22
+ delete from agent_board.task_events where thread_id='66740000-0000-4000-8000-000000000010';
23
+ delete from agent_board.tasks where thread_id='66740000-0000-4000-8000-000000000010';
24
+ delete from agent_board.messages where thread_id='66740000-0000-4000-8000-000000000010';
25
+ delete from agent_board.threads where id='66740000-0000-4000-8000-000000000010';
26
+ delete from agent_board.boards where id='66740000-0000-4000-8000-000000000020';
27
+ delete from agent_board.agents where id='66740000-0000-4000-8000-000000000001';
28
+ }
29
+ session "w"
30
+ step "w_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
31
+ step "w_task" { select count(*) from agent_board.create_task('66740000-0000-4000-8000-000000000010','66740000-0000-4000-8000-000000000001','private task'); }
32
+ step "w_commit" { commit; }
33
+ session "a"
34
+ step "a_ru" { begin isolation level read uncommitted; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66740000-0000-4000-8000-000000000010'; }
35
+ step "a_rr" { begin isolation level repeatable read; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66740000-0000-4000-8000-000000000010'; }
36
+ step "a_ser" { begin isolation level serializable; select set_config('request.jwt.claim.role','service_role',true); select count(*) from agent_board.threads where id='66740000-0000-4000-8000-000000000010'; }
37
+ step "a_post" { select agent_board_test.xb_667_try_association() as outcome; }
38
+ step "a_task" { select count(*) from agent_board.create_task('66740000-0000-4000-8000-000000000010','66740000-0000-4000-8000-000000000001','board task'); }
39
+ step "a_end" { end; }
40
+ session "p"
41
+ step "p_begin" { begin; select set_config('request.jwt.claim.role','service_role',true); }
42
+ step "p_post" { select count(*) from agent_board.post_board_message('66740000-0000-4000-8000-000000000010','66740000-0000-4000-8000-000000000001','66740000-0000-4000-8000-000000000020','s','b'); }
43
+ step "p_commit" { commit; }
44
+ session "check"
45
+ step "check" { select (t.board_id is not null) as stamped, (select count(*) from agent_board.tasks where thread_id=t.id) as tasks, (select count(*) from agent_board.messages where thread_id=t.id) as messages from agent_board.threads t where t.id='66740000-0000-4000-8000-000000000010'; }
46
+ permutation "a_ru" "a_post" "a_end" "check"
47
+ permutation "a_rr" "w_begin" "w_task" "a_post" "w_commit" "a_end" "check"
48
+ permutation "a_ser" "w_begin" "w_task" "a_post" "w_commit" "a_end" "check"
49
+ permutation "p_begin" "p_post" "p_commit" "a_rr" "a_task" "a_end" "check"
50
+ permutation "p_begin" "p_post" "p_commit" "a_ser" "a_task" "a_end" "check"