@consiliency/agent-board-schema 1.68.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.
- package/fixtures/already-applied.json +28 -4
- package/migrations/20261026000100_agent_board_thread_association.sql +1287 -0
- package/migrations/20261101000100_agent_board_session_measured_mint.sql +145 -0
- package/migrations/20261104065658_agent_board_reply_delivery.sql +659 -0
- package/migrations/20261104170000_agent_board_tasking_replay_scope.sql +320 -0
- package/migrations/20261104180000_agent_board_delivery_writer_execute.sql +51 -0
- package/migrations/20261104190000_agent_board_message_replay_scope.sql +373 -0
- package/package.json +1 -1
- package/schema-manifest.json +57 -3
- package/src/tooling.test.mjs +8 -2
- package/tests/agent_board_661_reply_delivery.test.sql +185 -0
- package/tests/agent_board_667_boundary.test.sql +162 -0
- package/tests/agent_board_667_conversion_branches.test.sql +91 -0
- package/tests/agent_board_667_conversion_profile.test.sql +112 -0
- package/tests/agent_board_667_history_class.test.sql +785 -0
- package/tests/agent_board_667_native_cast_effect.test.sql +88 -0
- package/tests/agent_board_667_realtime_apply_behavior.test.sql +117 -0
- package/tests/agent_board_667_realtime_apply_controls.test.sql +143 -0
- package/tests/agent_board_667_realtime_apply_profile.test.sql +61 -0
- package/tests/agent_board_667_retention.test.sql +201 -0
- package/tests/agent_board_667_routing.test.sql +294 -0
- package/tests/agent_board_667_sender_effects.test.sql +100 -0
- package/tests/agent_board_667_sender_profile_controls.test.sql +29 -0
- package/tests/agent_board_667_storage_delimiter_behavior.test.sql +84 -0
- package/tests/agent_board_667_storage_delimiter_controls.test.sql +23 -0
- package/tests/agent_board_667_storage_delimiter_profile.test.sql +61 -0
- package/tests/agent_board_667_storage_search_behavior.test.sql +93 -0
- package/tests/agent_board_667_storage_search_controls.test.sql +22 -0
- package/tests/agent_board_667_storage_search_profile.test.sql +60 -0
- package/tests/agent_board_667_storage_timestamp_behavior.test.sql +58 -0
- package/tests/agent_board_667_storage_timestamp_controls.test.sql +22 -0
- package/tests/agent_board_667_storage_timestamp_profile.test.sql +54 -0
- package/tests/agent_board_667_writers.test.sql +281 -0
- package/tests/agent_board_717_message_replay_scope.test.sql +828 -0
- package/tests/agent_board_717_tasking_replay_scope.test.sql +661 -0
- package/tests/agent_board_addressing.test.sql +8 -5
- package/tests/agent_board_claim_subject_gate.test.sql +7 -3
- package/tests/agent_board_claimpolicy_race.test.sql +39 -11
- package/tests/agent_board_delegate_role_class.test.sql +33 -15
- package/tests/agent_board_delivery_writer_execute.test.sql +371 -0
- package/tests/agent_board_fk_lock_edges.test.sql +3 -0
- package/tests/agent_board_hosted_delegates.test.sql +5 -2
- package/tests/agent_board_inbox_rpcs.test.sql +5 -3
- package/tests/agent_board_obsgate.test.sql +8 -4
- package/tests/agent_board_obsgate4.test.sql +2 -2
- package/tests/agent_board_outbox_wake_ordering.test.sql +25 -2
- package/tests/agent_board_own_post_not_delivered.test.sql +11 -9
- package/tests/agent_board_session_identity_behavior_classes.test.sql +2 -2
- package/tests/agent_board_session_identity_limits.test.sql +1 -1
- package/tests/agent_board_session_identity_measured_mint.test.sql +342 -0
- package/tests/agent_board_session_identity_predicate_isolation.test.sql +146 -0
- package/tests/agent_board_sidserver_authority.test.sql +69 -0
- package/tests/agent_board_sidserver_catalog.test.sql +47 -0
- package/tests/agent_board_signed_write_gateway.test.sql +4 -2
- package/tests/agent_board_task_thread_lock_order.test.sql +67 -42
- package/tests/agent_board_v2_invariants.test.sql +5 -2
- package/tests/agent_board_write_enforcement_class.test.sql +3 -3
- package/tests/catalog/function_execute_privileges.json +41 -5
- package/tests/catalog/p_metadata_parameters.json +16 -0
- package/tests/fixtures/agent_board_667_apply_rls_guard.sql +195 -0
- package/tests/fixtures/agent_board_667_apply_rls_provenance.md +125 -0
- package/tests/fixtures/agent_board_667_apply_rls_reference.sql +1903 -0
- package/tests/fixtures/agent_board_667_conversion_guard.sql +162 -0
- package/tests/fixtures/agent_board_667_conversion_reference.md +23 -0
- package/tests/fixtures/agent_board_667_conversion_reference.sql +5325 -0
- package/tests/fixtures/agent_board_667_delimiter_guard.sql +92 -0
- package/tests/fixtures/agent_board_667_delimiter_provenance.md +116 -0
- package/tests/fixtures/agent_board_667_delimiter_reference.sql +10150 -0
- package/tests/fixtures/agent_board_667_search_guard.sql +92 -0
- package/tests/fixtures/agent_board_667_search_provenance.md +141 -0
- package/tests/fixtures/agent_board_667_search_reference.sql +4779 -0
- package/tests/fixtures/agent_board_667_sender_guard.sql +102 -0
- package/tests/fixtures/agent_board_667_sender_reference.md +20 -0
- package/tests/fixtures/agent_board_667_sender_reference.sql +875 -0
- package/tests/fixtures/agent_board_667_timestamp_graph.sql +84 -0
- package/tests/fixtures/agent_board_667_timestamp_guard.sql +94 -0
- package/tests/fixtures/agent_board_667_timestamp_provenance.md +99 -0
- package/tests/fixtures/agent_board_667_timestamp_reference.sql +2938 -0
- package/tests/isolation/expected/association_artifact_anchor_order.out +108 -0
- package/tests/isolation/expected/association_board_vs_board.out +71 -0
- package/tests/isolation/expected/association_post_wait_authority.out +77 -0
- package/tests/isolation/expected/association_strong_history_writers.out +203 -0
- package/tests/isolation/expected/association_strong_isolation.out +185 -0
- package/tests/isolation/expected/association_vs_artifact_claim_escalation.out +199 -0
- package/tests/isolation/expected/association_vs_heartbeat.out +78 -0
- package/tests/isolation/expected/association_vs_multi_anchor_artifact.out +67 -0
- package/tests/isolation/expected/association_vs_private_message.out +67 -0
- package/tests/isolation/expected/association_vs_task_and_conflict.out +133 -0
- package/tests/isolation/expected/association_vs_taskful_cross_thread.out +133 -0
- package/tests/isolation/expected/message_replay_scope.out +209 -0
- package/tests/isolation/expected/tasking_replay_scope.out +125 -0
- package/tests/isolation/specs/association_artifact_anchor_order.spec +46 -0
- package/tests/isolation/specs/association_board_vs_board.spec +37 -0
- package/tests/isolation/specs/association_post_wait_authority.spec +48 -0
- package/tests/isolation/specs/association_strong_history_writers.spec +61 -0
- package/tests/isolation/specs/association_strong_isolation.spec +50 -0
- package/tests/isolation/specs/association_vs_artifact_claim_escalation.spec +41 -0
- package/tests/isolation/specs/association_vs_heartbeat.spec +47 -0
- package/tests/isolation/specs/association_vs_multi_anchor_artifact.spec +38 -0
- package/tests/isolation/specs/association_vs_private_message.spec +33 -0
- package/tests/isolation/specs/association_vs_task_and_conflict.spec +38 -0
- package/tests/isolation/specs/association_vs_taskful_cross_thread.spec +42 -0
- package/tests/isolation/specs/message_replay_scope.spec +77 -0
- package/tests/isolation/specs/tasking_replay_scope.spec +72 -0
- package/tests/mutations/717-f1/M0_prefix_main_acl_and_comments.sql +11 -0
- package/tests/mutations/717-f1/M10_wrapper_stops_delegating.sql +7 -0
- package/tests/mutations/717-f1/M11_transitive_recipient_content.sql +8 -0
- package/tests/mutations/717-f1/M12_transitive_recipient_visibility.sql +8 -0
- package/tests/mutations/717-f1/M13_transitive_worker_content.sql +15 -0
- package/tests/mutations/717-f1/M1a_regrant_upsert_delivery_recipient.sql +1 -0
- package/tests/mutations/717-f1/M1b_regrant_upsert_inbox_item.sql +1 -0
- package/tests/mutations/717-f1/M1c_regrant_queue_inbox_callbacks.sql +1 -0
- package/tests/mutations/717-f1/M1d_regrant_queue_board_post_callbacks.sql +1 -0
- package/tests/mutations/717-f1/M1e_regrant_next_thread_message_sequence.sql +1 -0
- package/tests/mutations/717-f1/M2_blanket_schema_grant.sql +1 -0
- package/tests/mutations/717-f1/M3_new_overload_of_sink.sql +10 -0
- package/tests/mutations/717-f1/M4_new_route_calling_sink.sql +7 -0
- package/tests/mutations/717-f1/M5_actor_trusts_supplied_id.sql +5 -0
- package/tests/mutations/717-f1/M6_signed_route_granted_to_authenticated.sql +1 -0
- package/tests/mutations/717-f1/M7_worker_granted_to_authenticated.sql +1 -0
- package/tests/mutations/717-f1/M8_recipient_state_rewrites_visibility.sql +5 -0
- package/tests/mutations/717-f1/M9_public_route_revoked_from_service_role.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W1_regrant_queue_inbox_callbacks.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W2_revoke_worker_from_service_role.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W3_invoker_caller_of_sink.sql +1 -0
- package/tests/mutations/717-f1/outbox_wake_ordering/W4_public_regrant_board_post_sink.sql +1 -0
- package/tests/mutations/717-f1/run.sh +17 -0
- package/tests/mutations/717-f2b/C1_new_delivery_route.sql +4 -0
- package/tests/mutations/717-f2b/C2_new_replay_lookup.sql +3 -0
- package/tests/mutations/717-f2b/C3_internal_regranted.sql +2 -0
- package/tests/mutations/717-f2b/C4_wrapper_writes_delivery.sql +9 -0
- package/tests/mutations/717-f2b/C5_class_member_dynamic_sql.sql +9 -0
- package/tests/mutations/717-f2b/C6_drop_board_scope_constraint.sql +2 -0
- package/tests/mutations/717-f2b/C7_state_private_helper_content.sql +14 -0
- package/tests/mutations/717-f2b/L1_dm_lock_split_by_recipient.sql +8 -0
- package/tests/mutations/717-f2b/L2_dm_lock_removed.sql +12 -0
- package/tests/mutations/717-f2b/L3_mc_lock_split_by_recipients.sql +8 -0
- package/tests/mutations/717-f2b/L4_mc_lock_removed.sql +12 -0
- package/tests/mutations/717-f2b/M0_prefix_definitions.sql +17 -0
- package/tests/mutations/717-f2b/M10_mc_lookup_any_author.sql +15 -0
- package/tests/mutations/717-f2b/M11_dm_swallow_refusal.sql +8 -0
- package/tests/mutations/717-f2b/M12_mc_swallow_refusal.sql +8 -0
- package/tests/mutations/717-f2b/M13_signed_dm_swallows_refusal.sql +32 -0
- package/tests/mutations/717-f2b/M14_signed_mc_swallows_refusal.sql +20 -0
- package/tests/mutations/717-f2b/M15_mc_any_source.sql +7 -0
- package/tests/mutations/717-f2b/M1_dm_drop_recipient_proof.sql +16 -0
- package/tests/mutations/717-f2b/M2_mc_drop_recipient_proof.sql +16 -0
- package/tests/mutations/717-f2b/M3_dm_metadata_as_proof.sql +12 -0
- package/tests/mutations/717-f2b/M4_mc_metadata_as_proof.sql +16 -0
- package/tests/mutations/717-f2b/M5_dm_any_mode.sql +11 -0
- package/tests/mutations/717-f2b/M6_dm_board_delivery_counts.sql +11 -0
- package/tests/mutations/717-f2b/M7_mc_any_mode.sql +11 -0
- package/tests/mutations/717-f2b/M8_dm_thread_stamp_as_proof.sql +12 -0
- package/tests/mutations/717-f2b/M9_dm_lookup_any_author.sql +15 -0
- package/tests/mutations/717-f2b/run.sh +82 -0
|
@@ -11,7 +11,8 @@ create temp table _addressing_fixture (
|
|
|
11
11
|
reviewer uuid,
|
|
12
12
|
human uuid,
|
|
13
13
|
board_id uuid,
|
|
14
|
-
thread_id uuid
|
|
14
|
+
thread_id uuid,
|
|
15
|
+
board_thread_id uuid
|
|
15
16
|
) on commit drop;
|
|
16
17
|
grant all on table _addressing_fixture to authenticated, service_role;
|
|
17
18
|
|
|
@@ -23,6 +24,7 @@ declare
|
|
|
23
24
|
v_reviewer uuid := gen_random_uuid();
|
|
24
25
|
v_human uuid := gen_random_uuid();
|
|
25
26
|
v_thread uuid := gen_random_uuid();
|
|
27
|
+
v_board_thread uuid := gen_random_uuid();
|
|
26
28
|
v_board uuid;
|
|
27
29
|
begin
|
|
28
30
|
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status, metadata)
|
|
@@ -35,15 +37,16 @@ begin
|
|
|
35
37
|
(v_human, 'human', 'human', 'addressing-human-' || v_suffix, 'ADDRESSING Human', 'active', '{}'::jsonb);
|
|
36
38
|
|
|
37
39
|
insert into agent_board.threads(id, thread_type, created_by_agent_id, subject)
|
|
38
|
-
values (v_thread, 'coordination', v_actor, 'ADDRESSING thread')
|
|
40
|
+
values (v_thread, 'coordination', v_actor, 'ADDRESSING thread'),
|
|
41
|
+
(v_board_thread, 'coordination', v_actor, 'ADDRESSING empty board thread');
|
|
39
42
|
|
|
40
43
|
select board_id into v_board
|
|
41
44
|
from agent_board.create_board(v_actor, 'addressing-board-' || v_suffix, 'ADDRESSING Board', 'addressing test board', '{}'::jsonb, 'open');
|
|
42
45
|
perform agent_board.join_board(v_board, v_actor, 'joined', v_actor, '{}'::jsonb);
|
|
43
46
|
perform agent_board.join_board(v_board, v_worker, 'subscribed', v_actor, '{}'::jsonb);
|
|
44
47
|
|
|
45
|
-
insert into _addressing_fixture(actor, worker, reviewer, human, board_id, thread_id)
|
|
46
|
-
values (v_actor, v_worker, v_reviewer, v_human, v_board, v_thread);
|
|
48
|
+
insert into _addressing_fixture(actor, worker, reviewer, human, board_id, thread_id, board_thread_id)
|
|
49
|
+
values (v_actor, v_worker, v_reviewer, v_human, v_board, v_thread, v_board_thread);
|
|
47
50
|
end
|
|
48
51
|
$$;
|
|
49
52
|
|
|
@@ -128,7 +131,7 @@ select lives_ok(
|
|
|
128
131
|
$$
|
|
129
132
|
select *
|
|
130
133
|
from agent_board.post_board_message(
|
|
131
|
-
(select
|
|
134
|
+
(select board_thread_id from _addressing_fixture),
|
|
132
135
|
(select actor from _addressing_fixture),
|
|
133
136
|
(select slug from agent_board.boards where id = (select board_id from _addressing_fixture)),
|
|
134
137
|
'addressing_v1',
|
|
@@ -661,13 +661,17 @@ select lives_ok(
|
|
|
661
661
|
select set_config('request.jwt.claim.role', 'service_role', true);
|
|
662
662
|
select set_config('request.jwt.claim.sub', '', true);
|
|
663
663
|
|
|
664
|
+
-- #661 adds a read in post_message to preserve restricted-thread privacy. Pin
|
|
665
|
+
-- both reviewed read-only bodies, not just their names: allowing the wrapper's
|
|
666
|
+
-- name alone would admit a future access_mode write inside that volatile RPC.
|
|
667
|
+
-- The reply suite separately executes inherit/restricted preservation cases.
|
|
664
668
|
select is(
|
|
665
|
-
(select coalesce(string_agg(p.proname, ',' order by p.proname), '(none)')
|
|
669
|
+
(select coalesce(string_agg(p.proname || ':' || md5(agent_board_test.stripped_body(p.oid, true)), ',' order by p.proname), '(none)')
|
|
666
670
|
from pg_proc p
|
|
667
671
|
where p.pronamespace = 'agent_board'::regnamespace
|
|
668
672
|
and lower(agent_board_test.stripped_body(p.oid, true)) ~ 'access_mode'),
|
|
669
|
-
'_agent_can_access_thread',
|
|
670
|
-
'catalog:
|
|
673
|
+
'_agent_can_access_thread:84a666a661c89a8338225155add8660f,post_message:0fa30de305331417b7bed464b7b89df4',
|
|
674
|
+
'catalog: every access_mode site matches its reviewed read-only definition; new sites and changed bodies name themselves');
|
|
671
675
|
|
|
672
676
|
select is(
|
|
673
677
|
(select coalesce(string_agg(distinct coalesce(g.rolname, 'PUBLIC') || ':' || a.privilege_type,
|
|
@@ -83,7 +83,7 @@ set search_path = extensions, public, agent_board;
|
|
|
83
83
|
|
|
84
84
|
begin;
|
|
85
85
|
|
|
86
|
-
select plan(
|
|
86
|
+
select plan(47);
|
|
87
87
|
|
|
88
88
|
-- ---------------------------------------------------------------------------
|
|
89
89
|
-- Fixture: one board, one thread on it, one thread with NO board (the constitutive-'inherit'
|
|
@@ -1570,8 +1570,9 @@ select is(
|
|
|
1570
1570
|
'acquire_claim=lock-first, renew_claim=lock-first, set_board_claim_policy=lock-first',
|
|
1571
1571
|
'CPR-3 ORDER: in each decider the board lock precedes the policy decision in source order — the population is a restatement of CPR-2''s catalog-derived set with a per-function decision marker, so a FOURTH decider fails CPR-2 before this list can go stale; the behavioural half is claimpolicy_acquire_revert_race.spec');
|
|
1572
1572
|
|
|
1573
|
-
-- CPR-4. acquire_claim takes
|
|
1574
|
-
--
|
|
1573
|
+
-- CPR-4. acquire_claim takes the board and quota advisory locks in that order. The
|
|
1574
|
+
-- broader two-hashtext census also includes unrelated actor-scoped namespaces,
|
|
1575
|
+
-- including heartbeat; its namespace and closure are checked positively below.
|
|
1575
1576
|
-- CPR-4 REMOVED (#405 completeness review). It read acquire_claim alone; CPR-4a derives the same
|
|
1576
1577
|
-- ordering over every function taking the actor-scoped quota lock and so strictly contains it.
|
|
1577
1578
|
-- Confirmed by mutation before removal: inverting acquire_claim's two locks trips CPR-4a (it tripped
|
|
@@ -1612,9 +1613,26 @@ select is(
|
|
|
1612
1613
|
when board_pos < quota_pos then 'board-then-agent'
|
|
1613
1614
|
else 'AGENT-THEN-BOARD' end), ', ' order by proname), '<none>')
|
|
1614
1615
|
from q),
|
|
1615
|
-
'acquire_claim=board-then-agent, upsert_delegation_policy=no-board-lock',
|
|
1616
|
+
'acquire_claim=board-then-agent, heartbeat=no-board-lock, upsert_delegation_policy=no-board-lock',
|
|
1616
1617
|
'CPR-4a ORDER (schema-wide): every function taking the actor-scoped quota lock either never takes the board lock or takes the board lock FIRST — the universal half of CPR-4, derived from the catalog rather than asserted about one function');
|
|
1617
1618
|
|
|
1619
|
+
-- The two-argument advisory census includes heartbeat's independent actor namespace.
|
|
1620
|
+
-- Check the literal namespace and call closure rather than filtering it out by name.
|
|
1621
|
+
select ok(
|
|
1622
|
+
(select position('agent_board.heartbeat_thread' in agent_board_test.stripped_body(p.oid, true))>0
|
|
1623
|
+
and position('claimgate_ownerless_quota' in agent_board_test.stripped_body(p.oid, true))=0
|
|
1624
|
+
and agent_board_test.stripped_body(p.oid) ~ agent_board_test.write_re('presence')
|
|
1625
|
+
and not (agent_board_test.stripped_body(p.oid) ~ agent_board_test.write_re('claims'))
|
|
1626
|
+
from pg_proc p where p.oid='agent_board.heartbeat(uuid,uuid,text,text,interval,jsonb)'::regprocedure),
|
|
1627
|
+
'CPR-4b heartbeat uses its own actor namespace and writes presence rather than claims');
|
|
1628
|
+
select is(
|
|
1629
|
+
(select string_agg(c.reached_oid::regprocedure::text, ', ' order by c.reached_oid::regprocedure::text)
|
|
1630
|
+
from agent_board_test.fn_call_closure() c
|
|
1631
|
+
where c.root_oid='agent_board.heartbeat(uuid,uuid,text,text,interval,jsonb)'::regprocedure
|
|
1632
|
+
and c.reached_oid in ('agent_board._claimgate_lock_board_policy(uuid)'::regprocedure,
|
|
1633
|
+
'agent_board.acquire_claim(uuid,text,text,timestamptz,uuid,uuid,jsonb)'::regprocedure)),
|
|
1634
|
+
null::text, 'CPR-4c heartbeat closure does not reach board-policy lock or claim acquisition');
|
|
1635
|
+
|
|
1618
1636
|
-- CPR-5. THE EXEMPTION, ASSERTED POSITIVELY. `v_ownerless_claim_quota` resolves board policy at
|
|
1619
1637
|
-- query time (#393's OQ-29) and is deliberately NOT serialised. The claim that makes that safe is
|
|
1620
1638
|
-- "it cannot produce a lease", and this asserts exactly that rather than asserting it is absent
|
|
@@ -1725,7 +1743,7 @@ select is(
|
|
|
1725
1743
|
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
|
1726
1744
|
where n.nspname = 'agent_board'
|
|
1727
1745
|
and agent_board_test.stripped_body(p.oid, true) ~ agent_board_test.stmt_re('update', 'threads')),
|
|
1728
|
-
'
|
|
1746
|
+
'_associate_empty_thread, _next_thread_message_sequence',
|
|
1729
1747
|
'CPR-11 BOARD IMMUTABILITY: these are the functions that UPDATE agent_board.threads, qualified or not — a third has to be decided against this premise rather than inheriting it');
|
|
1730
1748
|
|
|
1731
1749
|
-- CPR-12. THE POPULATION IS A STATEMENT TEST, NOT A SPELLING LIST. It matched `board_id =` after an
|
|
@@ -1750,7 +1768,9 @@ select is(
|
|
|
1750
1768
|
(case when agent_board_test.stripped_body(p.oid, true)
|
|
1751
1769
|
~ agent_board_test.re(agent_board_test.col_assign_frag('threads', 'board_id', agent_board_test.bare_ok(p.oid))
|
|
1752
1770
|
|| '\s*' || agent_board_test.ident_re('p_board_id') || agent_board_test.same_stmt()
|
|
1753
|
-
|| '\m' || agent_board_test.ci_re('where') || '\s+' || agent_board_test.col_ref_frag('
|
|
1771
|
+
|| '\m' || agent_board_test.ci_re('where') || '\s+' || agent_board_test.col_ref_frag('id')
|
|
1772
|
+
|| '\s*=\s*' || agent_board_test.ident_re('p_thread_id')
|
|
1773
|
+
|| '\s+' || agent_board_test.ci_re('and') || '\s+' || agent_board_test.col_ref_frag('board_id')
|
|
1754
1774
|
|| '\s+' || agent_board_test.ci_re('is null') || '\M')
|
|
1755
1775
|
then 'first-board-wins' else 'UNGUARDED' end) || ']', ', ' order by p.proname), '<none>')
|
|
1756
1776
|
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
|
|
@@ -1758,7 +1778,7 @@ select is(
|
|
|
1758
1778
|
and n.nspname !~ '^pg_'
|
|
1759
1779
|
and p.prolang <> (select oid from pg_language where lanname = 'internal')
|
|
1760
1780
|
and agent_board_test.stripped_body(p.oid, true) ~ agent_board_test.col_write_re('threads', 'board_id')),
|
|
1761
|
-
'
|
|
1781
|
+
'_associate_empty_thread[first-board-wins]',
|
|
1762
1782
|
'CPR-12 BOARD IMMUTABILITY: the sole writer of threads.board_id stamps only where it is null (OBSGATE first-board-wins), so a board can be gained but never moved');
|
|
1763
1783
|
|
|
1764
1784
|
-- CPR-13. And no session can do it directly.
|
|
@@ -1979,17 +1999,25 @@ select is(
|
|
|
1979
1999
|
or body ~ agent_board_test.row_lock_re('claims')
|
|
1980
2000
|
), class_rels as (
|
|
1981
2001
|
-- every relation in agent_board, from pg_class: a write to ANY of them is the verb.
|
|
1982
|
-
select array_agg(c.relname order by c.relname) as rels
|
|
2002
|
+
select array_agg(c.relname order by c.relname) as rels,
|
|
2003
|
+
array_agg(c.relname order by c.relname) filter (where c.relname <> 'threads') as other_rels
|
|
1983
2004
|
from pg_class c join pg_namespace n on n.oid = c.relnamespace
|
|
1984
2005
|
where n.nspname = 'agent_board' and c.relkind in ('r', 'p', 'v', 'm', 'f')
|
|
1985
2006
|
)
|
|
1986
2007
|
select coalesce(string_agg(m.oid::regprocedure::text || '[' ||
|
|
1987
|
-
(case when m.
|
|
2008
|
+
(case when m.oid = 'agent_board._associate_empty_thread(uuid,uuid)'::regprocedure
|
|
2009
|
+
and m.body ~ agent_board_test.stmt_re('update','threads')
|
|
2010
|
+
and not (m.body ~ agent_board_test.writes_any_re((select other_rels from class_rels)))
|
|
2011
|
+
and not (m.body ~ agent_board_test.write_re('claims'))
|
|
2012
|
+
and not (m.body ~ agent_board_test.row_lock_re('claims'))
|
|
2013
|
+
and not (m.body ~ agent_board_test.re('\mexecute\M'))
|
|
2014
|
+
then 'claims-reader-thread-stamp'
|
|
2015
|
+
when m.body ~ agent_board_test.writes_any_re((select rels from class_rels))
|
|
1988
2016
|
then 'HAS-WRITE-VERB' else 'no-write-verb' end) || ']', ', ' order by m.oid::regprocedure::text), '<none>')
|
|
1989
2017
|
from mentioners m
|
|
1990
2018
|
where m.oid not in (select oid from censused)),
|
|
1991
|
-
'_agent_can_access_thread(uuid,uuid)[no-write-verb], _claimgate_active_ownerless_claims(uuid)[no-write-verb], _claimgate_promotion_blockers(text)[no-write-verb]',
|
|
1992
|
-
'CPR-14b LOCK ORDER (census complement):
|
|
2019
|
+
'_agent_can_access_thread(uuid,uuid)[no-write-verb], _associate_empty_thread(uuid,uuid)[claims-reader-thread-stamp], _claimgate_active_ownerless_claims(uuid)[no-write-verb], _claimgate_promotion_blockers(text)[no-write-verb]',
|
|
2020
|
+
'CPR-14b LOCK ORDER (census complement): claims mentioners outside the writer census are readers, except the OID-bounded history reader that writes threads only');
|
|
1993
2021
|
|
|
1994
2022
|
-- ---------------------------------------------------------------------------
|
|
1995
2023
|
-- CPR-3a/3b/3c. THE PREMISE EVERYTHING ELSE RESTS ON, WHICH NOTHING PINNED.
|
|
@@ -16,7 +16,7 @@ set search_path = extensions, public, agent_board;
|
|
|
16
16
|
|
|
17
17
|
begin;
|
|
18
18
|
|
|
19
|
-
select plan(
|
|
19
|
+
select plan(49);
|
|
20
20
|
|
|
21
21
|
-- ===========================================================================
|
|
22
22
|
-- 1. The role itself
|
|
@@ -381,12 +381,12 @@ select is(
|
|
|
381
381
|
and p.prosrc ~* '(operator-designated|target-authored|board-authored)')),
|
|
382
382
|
'_board_membership_events_provenance_guard:guards it, _emit_membership_event:derives it, _membership_consent_kind:reads it in case and filter, _membership_consent_present:reads it in case and filter, _redeem_unbounded_invite_for_agent:never a delegate target, _upsert_board_membership_state:emits only through the emitter, bootstrap_board_owner_memberships:never a delegate target, create_board:never a delegate target, list_my_board_requests:not callable by a delegate, resolve_board_request:admits only through the sink (D15)',
|
|
383
383
|
'every reader of the provenance vocabulary has a positive disposition for principal-authored');
|
|
384
|
-
-- 31 --
|
|
384
|
+
-- 31 -- _insert_thread_message is the only function that inserts into messages (the attribution mark is complete)
|
|
385
385
|
select is(
|
|
386
386
|
(select string_agg(f.name, ',' order by f.name) from _fn f
|
|
387
387
|
where agent_board_test.stripped_body(f.oid) ~ agent_board_test.stmt_re('insert into', 'messages')),
|
|
388
|
-
'
|
|
389
|
-
'
|
|
388
|
+
'_insert_thread_message',
|
|
389
|
+
'_insert_thread_message is the only writer of messages, so its delegate mark covers every message');
|
|
390
390
|
-- 32 -- the delegate fact is written only by the exchange's first-use insert
|
|
391
391
|
select is(
|
|
392
392
|
(select string_agg(f.name, ',' order by f.name) from _fn f
|
|
@@ -627,33 +627,52 @@ select is(
|
|
|
627
627
|
'0/0/0/0',
|
|
628
628
|
'D14: a boardless message it AUTHORED, a boardless delivery and inbox item ADDRESSED to it, and its own presence: invisible');
|
|
629
629
|
|
|
630
|
-
--
|
|
630
|
+
-- The BA thread cannot be reused for BN. A distinct empty thread carries the
|
|
631
|
+
-- intended BN-only visibility witness without promoting the BA thread's history.
|
|
631
632
|
select pg_temp.authn(pg_temp.u('K.auth'));
|
|
632
|
-
select
|
|
633
|
+
select throws_ok($$select * from agent_board.post_board_message(pg_temp.u('TA'), pg_temp.u('K'), pg_temp.u('BN'), 's', 'cross-board to BN')$$,
|
|
634
|
+
'42501', 'thread belongs to a different board', 'D14 cross-board mismatch refuses at the boundary');
|
|
635
|
+
with created as (
|
|
636
|
+
insert into agent_board.threads(thread_type, created_by_agent_id, subject)
|
|
637
|
+
values ('coordination', pg_temp.u('K'), 'empty BN thread') returning id
|
|
638
|
+
) select pg_temp.put('TBN', id::text) from created;
|
|
639
|
+
select lives_ok($$select pg_temp.put('XB', (select message_id::text from agent_board.post_board_message(pg_temp.u('TBN'), pg_temp.u('K'), pg_temp.u('BN'), 's', 'board BN')))$$,
|
|
640
|
+
'D14 separate empty BN thread accepts a board post');
|
|
641
|
+
select ok(pg_temp.v('XB') is not null and exists (select 1 from agent_board.messages where id=pg_temp.u('XB')),
|
|
642
|
+
'D14 BN post result identifies a stored message');
|
|
633
643
|
select is(
|
|
634
644
|
(select board_id::text from agent_board.threads where id = pg_temp.u('TA')) || ' ' ||
|
|
635
645
|
pg_temp.as_d_val(format($$ select count(*) from agent_board.messages where id = %L $$, pg_temp.v('XB'))),
|
|
636
646
|
pg_temp.v('BA') || ' 0',
|
|
637
|
-
'D14
|
|
647
|
+
'D14 BN post: BA remains stamped and a BN message is invisible to a delegate on BA');
|
|
638
648
|
select is(
|
|
639
649
|
pg_temp.as_d_val(format($$ select count(*) from agent_board.messages where id = %L $$, pg_temp.v('MA'))),
|
|
640
650
|
'1',
|
|
641
651
|
'D14 cross-board post, paired: the BA post in the same thread is visible');
|
|
642
652
|
|
|
643
|
-
--
|
|
653
|
+
-- A private DM cannot be promoted to a board; the paired board visibility
|
|
654
|
+
-- control uses a separate empty thread and leaves the original DM intact.
|
|
644
655
|
do $$
|
|
645
|
-
declare v_thread uuid;
|
|
656
|
+
declare v_thread uuid; v_board_thread uuid;
|
|
646
657
|
begin
|
|
647
658
|
perform pg_temp.authn(pg_temp.u('K.auth'));
|
|
648
659
|
select thread_id into v_thread from agent_board.create_or_find_thread(pg_temp.u('K'), 'dm then board', 'zrows-dm');
|
|
649
660
|
perform agent_board.send_direct_message(v_thread, pg_temp.u('K'), pg_temp.u('K2'), 's', 'the dm before');
|
|
650
661
|
perform pg_temp.put('DMT', v_thread::text);
|
|
651
|
-
|
|
662
|
+
insert into agent_board.threads(thread_type, created_by_agent_id, subject)
|
|
663
|
+
values ('coordination', pg_temp.u('K'), 'empty BA thread') returning id into v_board_thread;
|
|
664
|
+
perform pg_temp.put('BPT', v_board_thread::text);
|
|
652
665
|
end $$;
|
|
653
|
-
select
|
|
654
|
-
|
|
666
|
+
select throws_ok($$select * from agent_board.post_board_message(pg_temp.u('DMT'), pg_temp.u('K'), pg_temp.u('BA'), 's', 'the board post after')$$,
|
|
667
|
+
'42501', 'thread has private history', 'D14 private DM cannot be promoted to a board');
|
|
668
|
+
select is((select board_id from agent_board.threads where id=pg_temp.u('DMT')), null::uuid,
|
|
669
|
+
'D14 refused private DM remains unstamped');
|
|
670
|
+
select lives_ok($$select * from agent_board.post_board_message(pg_temp.u('BPT'), pg_temp.u('K'), pg_temp.u('BA'), 's', 'the board post after')$$,
|
|
671
|
+
'D14 separate empty BA thread accepts its board post');
|
|
672
|
+
select is(
|
|
673
|
+
pg_temp.as_d_val(format($$ select string_agg(body, ',' order by body) from agent_board.messages where thread_id = %L $$, pg_temp.v('BPT'))),
|
|
655
674
|
'the board post after',
|
|
656
|
-
'D14
|
|
675
|
+
'D14 board post on separate BA thread is visible');
|
|
657
676
|
|
|
658
677
|
-- 41 -- A CO-MEMBER'S INBOX: K2's per-recipient item on BA is invisible; v_agent_inbox shows
|
|
659
678
|
-- only the delegate's own rows or feed-visible ones, and shows some
|
|
@@ -674,8 +693,7 @@ select is(
|
|
|
674
693
|
-- ids the delegate SEES with the row ids the contract's predicates ADMIT, computed here as
|
|
675
694
|
-- the table owner from the rule itself. The fixture above holds every case the contract
|
|
676
695
|
-- names: active, never-member, removed and left boards; boardless rows addressed to and
|
|
677
|
-
-- authored by the delegate; a task assigned to it off-board; a cross-board post; a DM
|
|
678
|
-
-- later stamped by a board post; and a co-member's non-feed inbox row. A relation with no
|
|
696
|
+
-- authored by the delegate; a task assigned to it off-board; a refused cross-board post; a private DM and separate board post; and a co-member's non-feed inbox row. A relation with no
|
|
679
697
|
-- reference rule here is reported UNMAPPED and fails.
|
|
680
698
|
create function pg_temp.oracle(p_rel text, p_d uuid) returns text language plpgsql as $$
|
|
681
699
|
declare q text; v text;
|