@consiliency/agent-board-schema 1.28.0 → 1.35.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 -0
- package/migrations/20260910000100_agent_board_ceiling_lock_comment_truth.sql +89 -0
- package/migrations/20260911000100_agent_board_ledger_revoked_board_creation.sql +330 -0
- package/migrations/20260912000100_agent_board_receipt_subject_gate.sql +348 -0
- package/migrations/20260913000100_agent_board_task_thread_lock_order.sql +292 -0
- package/migrations/20260914000100_agent_board_claim_subject_gate.sql +500 -0
- package/migrations/20260915000100_agent_board_fedsession_stored_identity_gate.sql +353 -0
- package/migrations/20260916000100_agent_board_federated_identity_injective_slug.sql +1646 -0
- package/package.json +1 -1
- package/schema-manifest.json +66 -3
- package/src/tooling.test.mjs +47 -2
- package/tests/agent_board_atomic_fleet_onboarding.test.sql +144 -29
- package/tests/agent_board_claim_subject_gate.test.sql +1025 -0
- package/tests/agent_board_enroll_resumption.test.sql +7 -1
- package/tests/agent_board_federated_identity_injective_slug.test.sql +388 -0
- package/tests/agent_board_fedsession.test.sql +17 -2
- package/tests/agent_board_fedsession_stored_identity_gate.test.sql +606 -0
- package/tests/agent_board_fk_lock_edges.test.sql +422 -0
- package/tests/agent_board_ledger_authority.test.sql +142 -71
- package/tests/agent_board_receipt_subject_gate.test.sql +624 -0
- package/tests/agent_board_signer_lifecycle.test.sql +23 -6
- package/tests/agent_board_source_strip_helper.test.sql +157 -1
- package/tests/agent_board_task_thread_lock_order.test.sql +337 -0
- package/tests/catalog/p_metadata_parameters.json +12 -0
- package/tests/fixtures/test-prereqs.sql +420 -11
- package/tests/isolation/expected/ledger_authority_revoke.out +219 -1
- package/tests/isolation/expected/task_thread_lock_order.out +203 -0
- package/tests/isolation/specs/enroll_identity_board_owner_lock_order.spec +5 -4
- package/tests/isolation/specs/fedsession_provider_absent_owner_lock.spec +4 -4
- package/tests/isolation/specs/ledger_authority_revoke.spec +115 -0
- package/tests/isolation/specs/task_thread_lock_order.spec +197 -0
- package/tests/seeds/20260916000100_agent_board_federated_identity_injective_slug.sql.pre.sql +196 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Parsed test spec with
|
|
1
|
+
Parsed test spec with 10 sessions
|
|
2
2
|
|
|
3
3
|
starting permutation: ugrant_begin ugrant_grant revoke_begin revoke_agent ugrant_commit revoke_commit check
|
|
4
4
|
step ugrant_begin:
|
|
@@ -481,3 +481,221 @@ grantee_role|owner_status|agent_ledger_rows|active_bindings|minted_tokens|outsta
|
|
|
481
481
|
admin |active | 1| 0| 0| 1
|
|
482
482
|
(1 row)
|
|
483
483
|
|
|
484
|
+
|
|
485
|
+
starting permutation: cboard_begin cboard_create revoke_begin revoke_agent cboard_commit revoke_commit cbcheck
|
|
486
|
+
step cboard_begin:
|
|
487
|
+
BEGIN;
|
|
488
|
+
SET LOCAL ROLE authenticated;
|
|
489
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
490
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
491
|
+
|
|
492
|
+
step cboard_create:
|
|
493
|
+
select c.slug
|
|
494
|
+
from agent_board.create_board(
|
|
495
|
+
'27710000-0000-4000-8000-000000000001', 'k280-iso-fresh', 'K280 ISO Fresh') c;
|
|
496
|
+
|
|
497
|
+
slug
|
|
498
|
+
--------------
|
|
499
|
+
k280-iso-fresh
|
|
500
|
+
(1 row)
|
|
501
|
+
|
|
502
|
+
step revoke_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
503
|
+
step revoke_agent:
|
|
504
|
+
select subject_kind
|
|
505
|
+
from agent_board.revoke_fleet_subject(
|
|
506
|
+
'agent',
|
|
507
|
+
'27710000-0000-4000-8000-000000000001',
|
|
508
|
+
'27710000-0000-4000-8000-000000000003',
|
|
509
|
+
'k276 iso fleet revocation');
|
|
510
|
+
<waiting ...>
|
|
511
|
+
step cboard_commit: COMMIT;
|
|
512
|
+
step revoke_agent: <... completed>
|
|
513
|
+
subject_kind
|
|
514
|
+
------------
|
|
515
|
+
agent
|
|
516
|
+
(1 row)
|
|
517
|
+
|
|
518
|
+
step revoke_commit: COMMIT;
|
|
519
|
+
step cbcheck:
|
|
520
|
+
select
|
|
521
|
+
(select count(*) from agent_board.boards where slug = 'k280-iso-fresh') as fresh_boards,
|
|
522
|
+
(select count(*) from agent_board.board_memberships bm
|
|
523
|
+
join agent_board.boards b on b.id = bm.board_id
|
|
524
|
+
where b.slug = 'k280-iso-fresh') as fresh_seats,
|
|
525
|
+
(select name from agent_board.boards
|
|
526
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_name,
|
|
527
|
+
(select visibility from agent_board.boards
|
|
528
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_visibility,
|
|
529
|
+
(select status from agent_board.agents
|
|
530
|
+
where id = '27710000-0000-4000-8000-000000000001') as owner_status,
|
|
531
|
+
(select count(*) from agent_board.fleet_revocation_events
|
|
532
|
+
where subject_kind = 'agent'
|
|
533
|
+
and subject_id = '27710000-0000-4000-8000-000000000001') as agent_ledger_rows;
|
|
534
|
+
|
|
535
|
+
fresh_boards|fresh_seats|existing_board_name|existing_board_visibility|owner_status|agent_ledger_rows
|
|
536
|
+
------------+-----------+-------------------+-------------------------+------------+-----------------
|
|
537
|
+
1| 1|K276 ISO Board |private |active | 1
|
|
538
|
+
(1 row)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
starting permutation: revoke_begin revoke_agent cboard_begin cboard_create revoke_commit cboard_commit cbcheck
|
|
542
|
+
step revoke_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
543
|
+
step revoke_agent:
|
|
544
|
+
select subject_kind
|
|
545
|
+
from agent_board.revoke_fleet_subject(
|
|
546
|
+
'agent',
|
|
547
|
+
'27710000-0000-4000-8000-000000000001',
|
|
548
|
+
'27710000-0000-4000-8000-000000000003',
|
|
549
|
+
'k276 iso fleet revocation');
|
|
550
|
+
|
|
551
|
+
subject_kind
|
|
552
|
+
------------
|
|
553
|
+
agent
|
|
554
|
+
(1 row)
|
|
555
|
+
|
|
556
|
+
step cboard_begin:
|
|
557
|
+
BEGIN;
|
|
558
|
+
SET LOCAL ROLE authenticated;
|
|
559
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
560
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
561
|
+
|
|
562
|
+
step cboard_create:
|
|
563
|
+
select c.slug
|
|
564
|
+
from agent_board.create_board(
|
|
565
|
+
'27710000-0000-4000-8000-000000000001', 'k280-iso-fresh', 'K280 ISO Fresh') c;
|
|
566
|
+
<waiting ...>
|
|
567
|
+
step revoke_commit: COMMIT;
|
|
568
|
+
step cboard_create: <... completed>
|
|
569
|
+
ERROR: fleet_revoked: create_board is not permitted for a fleet-revoked agent
|
|
570
|
+
step cboard_commit: COMMIT;
|
|
571
|
+
step cbcheck:
|
|
572
|
+
select
|
|
573
|
+
(select count(*) from agent_board.boards where slug = 'k280-iso-fresh') as fresh_boards,
|
|
574
|
+
(select count(*) from agent_board.board_memberships bm
|
|
575
|
+
join agent_board.boards b on b.id = bm.board_id
|
|
576
|
+
where b.slug = 'k280-iso-fresh') as fresh_seats,
|
|
577
|
+
(select name from agent_board.boards
|
|
578
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_name,
|
|
579
|
+
(select visibility from agent_board.boards
|
|
580
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_visibility,
|
|
581
|
+
(select status from agent_board.agents
|
|
582
|
+
where id = '27710000-0000-4000-8000-000000000001') as owner_status,
|
|
583
|
+
(select count(*) from agent_board.fleet_revocation_events
|
|
584
|
+
where subject_kind = 'agent'
|
|
585
|
+
and subject_id = '27710000-0000-4000-8000-000000000001') as agent_ledger_rows;
|
|
586
|
+
|
|
587
|
+
fresh_boards|fresh_seats|existing_board_name|existing_board_visibility|owner_status|agent_ledger_rows
|
|
588
|
+
------------+-----------+-------------------+-------------------------+------------+-----------------
|
|
589
|
+
0| 0|K276 ISO Board |private |active | 1
|
|
590
|
+
(1 row)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
starting permutation: revoke_begin revoke_agent creopen_begin creopen_call revoke_commit creopen_commit cbcheck
|
|
594
|
+
step revoke_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
595
|
+
step revoke_agent:
|
|
596
|
+
select subject_kind
|
|
597
|
+
from agent_board.revoke_fleet_subject(
|
|
598
|
+
'agent',
|
|
599
|
+
'27710000-0000-4000-8000-000000000001',
|
|
600
|
+
'27710000-0000-4000-8000-000000000003',
|
|
601
|
+
'k276 iso fleet revocation');
|
|
602
|
+
|
|
603
|
+
subject_kind
|
|
604
|
+
------------
|
|
605
|
+
agent
|
|
606
|
+
(1 row)
|
|
607
|
+
|
|
608
|
+
step creopen_begin:
|
|
609
|
+
BEGIN;
|
|
610
|
+
SET LOCAL ROLE authenticated;
|
|
611
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
612
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
613
|
+
|
|
614
|
+
step creopen_call:
|
|
615
|
+
select c.name, c.visibility
|
|
616
|
+
from agent_board.create_board(
|
|
617
|
+
'27710000-0000-4000-8000-000000000001', 'k276-iso-board', 'K280 ISO REOPENED',
|
|
618
|
+
null, null, 'open') c;
|
|
619
|
+
<waiting ...>
|
|
620
|
+
step revoke_commit: COMMIT;
|
|
621
|
+
step creopen_call: <... completed>
|
|
622
|
+
ERROR: fleet_revoked: create_board is not permitted for a fleet-revoked agent
|
|
623
|
+
step creopen_commit: COMMIT;
|
|
624
|
+
step cbcheck:
|
|
625
|
+
select
|
|
626
|
+
(select count(*) from agent_board.boards where slug = 'k280-iso-fresh') as fresh_boards,
|
|
627
|
+
(select count(*) from agent_board.board_memberships bm
|
|
628
|
+
join agent_board.boards b on b.id = bm.board_id
|
|
629
|
+
where b.slug = 'k280-iso-fresh') as fresh_seats,
|
|
630
|
+
(select name from agent_board.boards
|
|
631
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_name,
|
|
632
|
+
(select visibility from agent_board.boards
|
|
633
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_visibility,
|
|
634
|
+
(select status from agent_board.agents
|
|
635
|
+
where id = '27710000-0000-4000-8000-000000000001') as owner_status,
|
|
636
|
+
(select count(*) from agent_board.fleet_revocation_events
|
|
637
|
+
where subject_kind = 'agent'
|
|
638
|
+
and subject_id = '27710000-0000-4000-8000-000000000001') as agent_ledger_rows;
|
|
639
|
+
|
|
640
|
+
fresh_boards|fresh_seats|existing_board_name|existing_board_visibility|owner_status|agent_ledger_rows
|
|
641
|
+
------------+-----------+-------------------+-------------------------+------------+-----------------
|
|
642
|
+
0| 0|K276 ISO Board |private |active | 1
|
|
643
|
+
(1 row)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
starting permutation: creopen_begin creopen_call revoke_begin revoke_agent creopen_commit revoke_commit cbcheck
|
|
647
|
+
step creopen_begin:
|
|
648
|
+
BEGIN;
|
|
649
|
+
SET LOCAL ROLE authenticated;
|
|
650
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
651
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
652
|
+
|
|
653
|
+
step creopen_call:
|
|
654
|
+
select c.name, c.visibility
|
|
655
|
+
from agent_board.create_board(
|
|
656
|
+
'27710000-0000-4000-8000-000000000001', 'k276-iso-board', 'K280 ISO REOPENED',
|
|
657
|
+
null, null, 'open') c;
|
|
658
|
+
|
|
659
|
+
name |visibility
|
|
660
|
+
-----------------+----------
|
|
661
|
+
K280 ISO REOPENED|open
|
|
662
|
+
(1 row)
|
|
663
|
+
|
|
664
|
+
step revoke_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
665
|
+
step revoke_agent:
|
|
666
|
+
select subject_kind
|
|
667
|
+
from agent_board.revoke_fleet_subject(
|
|
668
|
+
'agent',
|
|
669
|
+
'27710000-0000-4000-8000-000000000001',
|
|
670
|
+
'27710000-0000-4000-8000-000000000003',
|
|
671
|
+
'k276 iso fleet revocation');
|
|
672
|
+
<waiting ...>
|
|
673
|
+
step creopen_commit: COMMIT;
|
|
674
|
+
step revoke_agent: <... completed>
|
|
675
|
+
subject_kind
|
|
676
|
+
------------
|
|
677
|
+
agent
|
|
678
|
+
(1 row)
|
|
679
|
+
|
|
680
|
+
step revoke_commit: COMMIT;
|
|
681
|
+
step cbcheck:
|
|
682
|
+
select
|
|
683
|
+
(select count(*) from agent_board.boards where slug = 'k280-iso-fresh') as fresh_boards,
|
|
684
|
+
(select count(*) from agent_board.board_memberships bm
|
|
685
|
+
join agent_board.boards b on b.id = bm.board_id
|
|
686
|
+
where b.slug = 'k280-iso-fresh') as fresh_seats,
|
|
687
|
+
(select name from agent_board.boards
|
|
688
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_name,
|
|
689
|
+
(select visibility from agent_board.boards
|
|
690
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_visibility,
|
|
691
|
+
(select status from agent_board.agents
|
|
692
|
+
where id = '27710000-0000-4000-8000-000000000001') as owner_status,
|
|
693
|
+
(select count(*) from agent_board.fleet_revocation_events
|
|
694
|
+
where subject_kind = 'agent'
|
|
695
|
+
and subject_id = '27710000-0000-4000-8000-000000000001') as agent_ledger_rows;
|
|
696
|
+
|
|
697
|
+
fresh_boards|fresh_seats|existing_board_name|existing_board_visibility|owner_status|agent_ledger_rows
|
|
698
|
+
------------+-----------+-------------------+-------------------------+------------+-----------------
|
|
699
|
+
0| 0|K280 ISO REOPENED |open |active | 1
|
|
700
|
+
(1 row)
|
|
701
|
+
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Parsed test spec with 5 sessions
|
|
2
|
+
|
|
3
|
+
starting permutation: probe_begin probe_threads append_begin append_run probe_tasks probe_commit append_commit check
|
|
4
|
+
step probe_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
5
|
+
step probe_threads:
|
|
6
|
+
select count(*)::int as locked_threads from (
|
|
7
|
+
select 1 from agent_board.threads t
|
|
8
|
+
where t.id = '7a820000-0000-4000-8000-000000000001' for update) s;
|
|
9
|
+
|
|
10
|
+
locked_threads
|
|
11
|
+
--------------
|
|
12
|
+
1
|
|
13
|
+
(1 row)
|
|
14
|
+
|
|
15
|
+
step append_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
16
|
+
step append_run:
|
|
17
|
+
select e.event_sequence,
|
|
18
|
+
(e.thread_id = '7a820000-0000-4000-8000-000000000001') as thread_is_task_thread
|
|
19
|
+
from agent_board.append_task_event(
|
|
20
|
+
'7a830000-0000-4000-8000-000000000001',
|
|
21
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
22
|
+
'commented') e;
|
|
23
|
+
<waiting ...>
|
|
24
|
+
step probe_tasks:
|
|
25
|
+
select count(*)::int as locked_tasks from (
|
|
26
|
+
select 1 from agent_board.tasks tk
|
|
27
|
+
where tk.id = '7a830000-0000-4000-8000-000000000001' for update) s;
|
|
28
|
+
|
|
29
|
+
locked_tasks
|
|
30
|
+
------------
|
|
31
|
+
1
|
|
32
|
+
(1 row)
|
|
33
|
+
|
|
34
|
+
step probe_commit: COMMIT;
|
|
35
|
+
step append_run: <... completed>
|
|
36
|
+
event_sequence|thread_is_task_thread
|
|
37
|
+
--------------+---------------------
|
|
38
|
+
1|t
|
|
39
|
+
(1 row)
|
|
40
|
+
|
|
41
|
+
step append_commit: COMMIT;
|
|
42
|
+
step check:
|
|
43
|
+
select (select array_agg(te.event_sequence order by te.event_sequence)
|
|
44
|
+
from agent_board.task_events te
|
|
45
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001') as event_sequences,
|
|
46
|
+
(select count(*)::int from agent_board.messages
|
|
47
|
+
where thread_id = '7a820000-0000-4000-8000-000000000001') as messages,
|
|
48
|
+
(select count(*)::int from agent_board.task_events te
|
|
49
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001'
|
|
50
|
+
and te.thread_id <> '7a820000-0000-4000-8000-000000000001') as events_on_wrong_thread;
|
|
51
|
+
|
|
52
|
+
event_sequences|messages|events_on_wrong_thread
|
|
53
|
+
---------------+--------+----------------------
|
|
54
|
+
{1} | 0| 0
|
|
55
|
+
(1 row)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
starting permutation: append_begin append_run post_begin post_run append_commit post_commit check
|
|
59
|
+
step append_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
60
|
+
step append_run:
|
|
61
|
+
select e.event_sequence,
|
|
62
|
+
(e.thread_id = '7a820000-0000-4000-8000-000000000001') as thread_is_task_thread
|
|
63
|
+
from agent_board.append_task_event(
|
|
64
|
+
'7a830000-0000-4000-8000-000000000001',
|
|
65
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
66
|
+
'commented') e;
|
|
67
|
+
|
|
68
|
+
event_sequence|thread_is_task_thread
|
|
69
|
+
--------------+---------------------
|
|
70
|
+
1|t
|
|
71
|
+
(1 row)
|
|
72
|
+
|
|
73
|
+
step post_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
74
|
+
step post_run:
|
|
75
|
+
select m.message_sequence,
|
|
76
|
+
(m.task_id = '7a830000-0000-4000-8000-000000000001') as task_attached
|
|
77
|
+
from agent_board.post_message(
|
|
78
|
+
'7a820000-0000-4000-8000-000000000001',
|
|
79
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
80
|
+
'r1 iso body',
|
|
81
|
+
'comment',
|
|
82
|
+
'7a830000-0000-4000-8000-000000000001') m;
|
|
83
|
+
<waiting ...>
|
|
84
|
+
step append_commit: COMMIT;
|
|
85
|
+
step post_run: <... completed>
|
|
86
|
+
message_sequence|task_attached
|
|
87
|
+
----------------+-------------
|
|
88
|
+
1|t
|
|
89
|
+
(1 row)
|
|
90
|
+
|
|
91
|
+
step post_commit: COMMIT;
|
|
92
|
+
step check:
|
|
93
|
+
select (select array_agg(te.event_sequence order by te.event_sequence)
|
|
94
|
+
from agent_board.task_events te
|
|
95
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001') as event_sequences,
|
|
96
|
+
(select count(*)::int from agent_board.messages
|
|
97
|
+
where thread_id = '7a820000-0000-4000-8000-000000000001') as messages,
|
|
98
|
+
(select count(*)::int from agent_board.task_events te
|
|
99
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001'
|
|
100
|
+
and te.thread_id <> '7a820000-0000-4000-8000-000000000001') as events_on_wrong_thread;
|
|
101
|
+
|
|
102
|
+
event_sequences|messages|events_on_wrong_thread
|
|
103
|
+
---------------+--------+----------------------
|
|
104
|
+
{1} | 1| 0
|
|
105
|
+
(1 row)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
starting permutation: post_begin post_run append_begin append_run post_commit append_commit check
|
|
109
|
+
step post_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
110
|
+
step post_run:
|
|
111
|
+
select m.message_sequence,
|
|
112
|
+
(m.task_id = '7a830000-0000-4000-8000-000000000001') as task_attached
|
|
113
|
+
from agent_board.post_message(
|
|
114
|
+
'7a820000-0000-4000-8000-000000000001',
|
|
115
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
116
|
+
'r1 iso body',
|
|
117
|
+
'comment',
|
|
118
|
+
'7a830000-0000-4000-8000-000000000001') m;
|
|
119
|
+
|
|
120
|
+
message_sequence|task_attached
|
|
121
|
+
----------------+-------------
|
|
122
|
+
1|t
|
|
123
|
+
(1 row)
|
|
124
|
+
|
|
125
|
+
step append_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
126
|
+
step append_run:
|
|
127
|
+
select e.event_sequence,
|
|
128
|
+
(e.thread_id = '7a820000-0000-4000-8000-000000000001') as thread_is_task_thread
|
|
129
|
+
from agent_board.append_task_event(
|
|
130
|
+
'7a830000-0000-4000-8000-000000000001',
|
|
131
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
132
|
+
'commented') e;
|
|
133
|
+
<waiting ...>
|
|
134
|
+
step post_commit: COMMIT;
|
|
135
|
+
step append_run: <... completed>
|
|
136
|
+
event_sequence|thread_is_task_thread
|
|
137
|
+
--------------+---------------------
|
|
138
|
+
1|t
|
|
139
|
+
(1 row)
|
|
140
|
+
|
|
141
|
+
step append_commit: COMMIT;
|
|
142
|
+
step check:
|
|
143
|
+
select (select array_agg(te.event_sequence order by te.event_sequence)
|
|
144
|
+
from agent_board.task_events te
|
|
145
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001') as event_sequences,
|
|
146
|
+
(select count(*)::int from agent_board.messages
|
|
147
|
+
where thread_id = '7a820000-0000-4000-8000-000000000001') as messages,
|
|
148
|
+
(select count(*)::int from agent_board.task_events te
|
|
149
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001'
|
|
150
|
+
and te.thread_id <> '7a820000-0000-4000-8000-000000000001') as events_on_wrong_thread;
|
|
151
|
+
|
|
152
|
+
event_sequences|messages|events_on_wrong_thread
|
|
153
|
+
---------------+--------+----------------------
|
|
154
|
+
{1} | 1| 0
|
|
155
|
+
(1 row)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
starting permutation: append_begin append_run append2_begin append2_run append_commit append2_commit check
|
|
159
|
+
step append_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
160
|
+
step append_run:
|
|
161
|
+
select e.event_sequence,
|
|
162
|
+
(e.thread_id = '7a820000-0000-4000-8000-000000000001') as thread_is_task_thread
|
|
163
|
+
from agent_board.append_task_event(
|
|
164
|
+
'7a830000-0000-4000-8000-000000000001',
|
|
165
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
166
|
+
'commented') e;
|
|
167
|
+
|
|
168
|
+
event_sequence|thread_is_task_thread
|
|
169
|
+
--------------+---------------------
|
|
170
|
+
1|t
|
|
171
|
+
(1 row)
|
|
172
|
+
|
|
173
|
+
step append2_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
174
|
+
step append2_run:
|
|
175
|
+
select e.event_sequence
|
|
176
|
+
from agent_board.append_task_event(
|
|
177
|
+
'7a830000-0000-4000-8000-000000000001',
|
|
178
|
+
'7a810000-0000-4000-8000-000000000001',
|
|
179
|
+
'status_changed') e;
|
|
180
|
+
<waiting ...>
|
|
181
|
+
step append_commit: COMMIT;
|
|
182
|
+
step append2_run: <... completed>
|
|
183
|
+
event_sequence
|
|
184
|
+
--------------
|
|
185
|
+
2
|
|
186
|
+
(1 row)
|
|
187
|
+
|
|
188
|
+
step append2_commit: COMMIT;
|
|
189
|
+
step check:
|
|
190
|
+
select (select array_agg(te.event_sequence order by te.event_sequence)
|
|
191
|
+
from agent_board.task_events te
|
|
192
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001') as event_sequences,
|
|
193
|
+
(select count(*)::int from agent_board.messages
|
|
194
|
+
where thread_id = '7a820000-0000-4000-8000-000000000001') as messages,
|
|
195
|
+
(select count(*)::int from agent_board.task_events te
|
|
196
|
+
where te.task_id = '7a830000-0000-4000-8000-000000000001'
|
|
197
|
+
and te.thread_id <> '7a820000-0000-4000-8000-000000000001') as events_on_wrong_thread;
|
|
198
|
+
|
|
199
|
+
event_sequences|messages|events_on_wrong_thread
|
|
200
|
+
---------------+--------+----------------------
|
|
201
|
+
{1,2} | 0| 0
|
|
202
|
+
(1 row)
|
|
203
|
+
|
|
@@ -60,12 +60,13 @@ setup
|
|
|
60
60
|
-- Materialize the owner auth.users row the enrollment will derive, so the guard
|
|
61
61
|
-- holds the SAME row (a race to INSERT it would block on the unique index, not on
|
|
62
62
|
-- the lock order under test).
|
|
63
|
+
-- #246: through the shared derivation helper, deliberately. The point of this row is
|
|
64
|
+
-- that it is the SAME row the enrollment will resolve to; a copied expression here
|
|
65
|
+
-- would silently stop matching the moment the derivation moved, and this spec would
|
|
66
|
+
-- go on "passing" while holding a lock on an unrelated row.
|
|
63
67
|
create table lo194_owner as
|
|
64
68
|
select agent_board._ensure_agent_auth_user(
|
|
65
|
-
'
|
|
66
|
-
encode(extensions.digest(
|
|
67
|
-
convert_to('https://lo194-iso.test' || '|' || 'iso-human', 'UTF8'), 'sha256'), 'hex'),
|
|
68
|
-
1, 32)) as uid;
|
|
69
|
+
agent_board._federated_identity_slug('https://lo194-iso.test', 'iso-human')) as uid;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
# Holds the human owner row, so the enrollment parks on it in either schema.
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
|
|
23
23
|
setup
|
|
24
24
|
{
|
|
25
|
+
-- #246: through the shared derivation helper, deliberately -- see the note in
|
|
26
|
+
-- enroll_identity_board_owner_lock_order.spec. The row must be the one the path under
|
|
27
|
+
-- test would resolve to, not a copy of an expression that can drift away from it.
|
|
25
28
|
create table lo193_owner as
|
|
26
29
|
select agent_board._ensure_agent_auth_user(
|
|
27
|
-
'
|
|
28
|
-
encode(extensions.digest(
|
|
29
|
-
convert_to('https://lo193-iso.test' || '|' || 'iso-orphan', 'UTF8'), 'sha256'), 'hex'),
|
|
30
|
-
1, 32)) as uid;
|
|
30
|
+
agent_board._federated_identity_slug('https://lo193-iso.test', 'iso-orphan')) as uid;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
# Holds the human owner row that the absent-provider path must never reach.
|
|
@@ -31,6 +31,20 @@
|
|
|
31
31
|
# MUTATION-VERIFIED: dropping `for share` from _assert_actor_not_fleet_revoked (leaving the
|
|
32
32
|
# ledger read unlocked) changes permutations 2 and 4 — the authority write no longer waits.
|
|
33
33
|
# Clean schema -> byte-identical across 10 runs.
|
|
34
|
+
#
|
|
35
|
+
# #280 RE-RAN THAT MUTATION and measured which of the four new permutations it moves. The result
|
|
36
|
+
# is the honest form of this migration's lock claim, so it is recorded here rather than argued:
|
|
37
|
+
# * Permutations 9 and 10 (the FRESH-BOARD branch) are BYTE-IDENTICAL with the lock removed.
|
|
38
|
+
# That is expected and is the point: the owner-seat INSERT's FK already holds KEY SHARE on
|
|
39
|
+
# the actor's agents row before the gate runs, so the FK — not the FOR SHARE — is what makes
|
|
40
|
+
# that branch wait. These two permutations pin the OUTCOME (blocks, fails closed, no board
|
|
41
|
+
# and no seat) and CANNOT pin the lock. Nothing here should be read as though they do.
|
|
42
|
+
# * Permutations 11 and 12 (the SLUG-COLLISION branch) BOTH move. With the lock removed,
|
|
43
|
+
# permutation 11 stops waiting entirely and the reopen SUCCEEDS on its pre-revocation
|
|
44
|
+
# snapshot: the check row goes from `K276 ISO Board | private` to `K280 ISO REOPENED | open`
|
|
45
|
+
# — a ledger-revoked owner reopening an existing board and making it publicly visible across
|
|
46
|
+
# a committing revocation. That is the TOCTOU the FOR SHARE closes, and permutation 11 is the
|
|
47
|
+
# only place in this spec where the lock itself is discriminated.
|
|
34
48
|
|
|
35
49
|
setup
|
|
36
50
|
{
|
|
@@ -96,6 +110,11 @@ teardown
|
|
|
96
110
|
where board_id = '27720000-0000-4000-8000-000000000001');
|
|
97
111
|
delete from agent_board.board_invite_tokens
|
|
98
112
|
where board_id = '27720000-0000-4000-8000-000000000001';
|
|
113
|
+
delete from agent_board.board_membership_events
|
|
114
|
+
where board_id in (select id from agent_board.boards where slug like 'k280-iso-%');
|
|
115
|
+
delete from agent_board.board_memberships
|
|
116
|
+
where board_id in (select id from agent_board.boards where slug like 'k280-iso-%');
|
|
117
|
+
delete from agent_board.boards where slug like 'k280-iso-%';
|
|
99
118
|
delete from agent_board.board_membership_events
|
|
100
119
|
where board_id = '27720000-0000-4000-8000-000000000001';
|
|
101
120
|
delete from agent_board.fleet_revocation_events
|
|
@@ -220,6 +239,74 @@ step "redeem2_link" {
|
|
|
220
239
|
}
|
|
221
240
|
step "redeem2_commit" { COMMIT; }
|
|
222
241
|
|
|
242
|
+
# ---------------------------------------------------------------------------------------------
|
|
243
|
+
# #280 — create_board. TWO sessions, because the function is two operations behind one name and
|
|
244
|
+
# the FOR SHARE means something different on each branch (see 20260911000100's header).
|
|
245
|
+
#
|
|
246
|
+
# cboard — the FRESH-BOARD branch. The owner seat INSERT takes FK KEY SHARE on the actor's
|
|
247
|
+
# agents row BEFORE the gate runs, so the FK — not the gate — is what makes this
|
|
248
|
+
# branch wait. Permutations 9 and 10 therefore pin the OUTCOME (blocks, then fails
|
|
249
|
+
# closed, leaving NO board and NO seat) and structurally cannot pin the lock.
|
|
250
|
+
# creopen — the SLUG-COLLISION branch, re-opening the board the actor already owns. The boards
|
|
251
|
+
# UPDATE does not touch created_by_agent_id, so no FK fires and the gate's FOR SHARE
|
|
252
|
+
# is the ONLY agents lock on that path. Permutation 11 is the genuine lock
|
|
253
|
+
# discriminator this migration has and the mint path could not provide: remove the
|
|
254
|
+
# FOR SHARE and the reopen stops waiting and SUCCEEDS on its own snapshot.
|
|
255
|
+
# ---------------------------------------------------------------------------------------------
|
|
256
|
+
session "cboard"
|
|
257
|
+
step "cboard_begin" {
|
|
258
|
+
BEGIN;
|
|
259
|
+
SET LOCAL ROLE authenticated;
|
|
260
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
261
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
262
|
+
}
|
|
263
|
+
step "cboard_create" {
|
|
264
|
+
select c.slug
|
|
265
|
+
from agent_board.create_board(
|
|
266
|
+
'27710000-0000-4000-8000-000000000001', 'k280-iso-fresh', 'K280 ISO Fresh') c;
|
|
267
|
+
}
|
|
268
|
+
step "cboard_commit" { COMMIT; }
|
|
269
|
+
|
|
270
|
+
session "creopen"
|
|
271
|
+
step "creopen_begin" {
|
|
272
|
+
BEGIN;
|
|
273
|
+
SET LOCAL ROLE authenticated;
|
|
274
|
+
SET LOCAL "request.jwt.claim.role" = 'authenticated';
|
|
275
|
+
SET LOCAL "request.jwt.claim.sub" = '27700000-0000-0000-0000-0000000000a1';
|
|
276
|
+
}
|
|
277
|
+
# p_metadata is passed as NULL below rather than as an empty-object jsonb literal, and this note
|
|
278
|
+
# lives OUTSIDE the step for the same reason: the isolationtester spec lexer matches BRACES to
|
|
279
|
+
# delimit a step body, so an empty-object literal anywhere inside the SQL closes the step early
|
|
280
|
+
# and the parse dies on the next quote. create_board coalesces a null p_metadata to that same
|
|
281
|
+
# empty object, so the call is identical. (Backticks break the lexer here too.)
|
|
282
|
+
step "creopen_call" {
|
|
283
|
+
select c.name, c.visibility
|
|
284
|
+
from agent_board.create_board(
|
|
285
|
+
'27710000-0000-4000-8000-000000000001', 'k276-iso-board', 'K280 ISO REOPENED',
|
|
286
|
+
null, null, 'open') c;
|
|
287
|
+
}
|
|
288
|
+
step "creopen_commit" { COMMIT; }
|
|
289
|
+
|
|
290
|
+
# The #280 state row. Kept separate from "check" so the existing golden rows keep their shape and
|
|
291
|
+
# a diff in permutations 1-8 can only be a real change.
|
|
292
|
+
session "cbcheck"
|
|
293
|
+
step "cbcheck" {
|
|
294
|
+
select
|
|
295
|
+
(select count(*) from agent_board.boards where slug = 'k280-iso-fresh') as fresh_boards,
|
|
296
|
+
(select count(*) from agent_board.board_memberships bm
|
|
297
|
+
join agent_board.boards b on b.id = bm.board_id
|
|
298
|
+
where b.slug = 'k280-iso-fresh') as fresh_seats,
|
|
299
|
+
(select name from agent_board.boards
|
|
300
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_name,
|
|
301
|
+
(select visibility from agent_board.boards
|
|
302
|
+
where id = '27720000-0000-4000-8000-000000000001') as existing_board_visibility,
|
|
303
|
+
(select status from agent_board.agents
|
|
304
|
+
where id = '27710000-0000-4000-8000-000000000001') as owner_status,
|
|
305
|
+
(select count(*) from agent_board.fleet_revocation_events
|
|
306
|
+
where subject_kind = 'agent'
|
|
307
|
+
and subject_id = '27710000-0000-4000-8000-000000000001') as agent_ledger_rows;
|
|
308
|
+
}
|
|
309
|
+
|
|
223
310
|
session "check"
|
|
224
311
|
step "check" {
|
|
225
312
|
select
|
|
@@ -288,3 +375,31 @@ permutation "revoke_begin" "revoke_agent" "revoke_commit" "redeem_begin" "redeem
|
|
|
288
375
|
# but a creator holding K links has K independent windows. outstanding_link_uses = 1 in the
|
|
289
376
|
# check row is the byte that says exactly one slipped.
|
|
290
377
|
permutation "revoke_begin" "revoke_agent" "redeem_begin" "redeem_link" "redeem2_begin" "redeem2_link" "revoke_commit" "redeem_commit" "redeem2_commit" "check"
|
|
378
|
+
|
|
379
|
+
# 9. #280, FRESH branch, create first. The revocation must WAIT rather than commit underneath a
|
|
380
|
+
# board creation that has already run its gate. The board stands and the revocation lands
|
|
381
|
+
# after it -- a creation that beat the revocation, the same outcome as a creation a
|
|
382
|
+
# millisecond earlier. What makes the revoker wait here is the seat INSERT's FK KEY SHARE on
|
|
383
|
+
# the actor's agents row, not the gate; recorded so nobody reads this permutation as a lock
|
|
384
|
+
# pin for the FOR SHARE.
|
|
385
|
+
permutation "cboard_begin" "cboard_create" "revoke_begin" "revoke_agent" "cboard_commit" "revoke_commit" "cbcheck"
|
|
386
|
+
|
|
387
|
+
# 10. #280's OWN interleaving, FRESH branch: the revocation is in flight when create_board runs.
|
|
388
|
+
# The creation blocks, then observes the committed revocation and fails closed -- fresh_boards
|
|
389
|
+
# and fresh_seats are both 0, so the boards INSERT, the owner seat and the owner_seed event
|
|
390
|
+
# all rolled back together. Before 20260911000100 this permutation COMPLETED the creation:
|
|
391
|
+
# create_board read no ledger at all, so there was nothing to see. This is the OUTCOME pin.
|
|
392
|
+
permutation "revoke_begin" "revoke_agent" "cboard_begin" "cboard_create" "revoke_commit" "cboard_commit" "cbcheck"
|
|
393
|
+
|
|
394
|
+
# 11. #280, SLUG-COLLISION branch, revoke in flight -- THE LOCK DISCRIMINATOR. The boards UPDATE
|
|
395
|
+
# leaves created_by_agent_id alone, so no FK takes an agents lock and the gate's FOR SHARE is
|
|
396
|
+
# the only one on this path. The reopen blocks on it, then fails closed, leaving the existing
|
|
397
|
+
# board's name and visibility untouched. Drop the FOR SHARE from
|
|
398
|
+
# _assert_actor_not_fleet_revoked and this permutation stops waiting and SUCCEEDS on its own
|
|
399
|
+
# pre-revocation snapshot -- which permutations 9 and 10 cannot show, and neither can the
|
|
400
|
+
# mint path (permutation 5), where the FK always gets there first.
|
|
401
|
+
permutation "revoke_begin" "revoke_agent" "creopen_begin" "creopen_call" "revoke_commit" "creopen_commit" "cbcheck"
|
|
402
|
+
|
|
403
|
+
# 12. ...and the collision branch write-first, for the pair: the reopen is authorized and stands,
|
|
404
|
+
# the revocation waits on the share-locked agents row and lands after it.
|
|
405
|
+
permutation "creopen_begin" "creopen_call" "revoke_begin" "revoke_agent" "creopen_commit" "revoke_commit" "cbcheck"
|