@consiliency/agent-board-schema 1.45.0 → 1.50.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 (35) hide show
  1. package/fixtures/already-applied.json +24 -0
  2. package/migrations/20260926000100_agent_board_ownerless_quota_census.sql +268 -0
  3. package/migrations/20260927000100_agent_board_fleet_domain_no_downgrade.sql +393 -0
  4. package/migrations/20260928000100_agent_board_ownerless_quota_renew_convergence.sql +562 -0
  5. package/migrations/20260929000100_agent_board_advisory_revert_cap_reset.sql +371 -0
  6. package/migrations/20260930000100_agent_board_claim_policy_race.sql +922 -0
  7. package/migrations/20261001000100_agent_board_claimpolicy_lock_grant_revoke.sql +158 -0
  8. package/package.json +1 -1
  9. package/schema-manifest.json +57 -3
  10. package/src/tooling.test.mjs +52 -2
  11. package/tests/agent_board_board_claim_policy.test.sql +261 -1
  12. package/tests/agent_board_claim_subject_gate.test.sql +11 -2
  13. package/tests/agent_board_claimkey.test.sql +17 -2
  14. package/tests/agent_board_claimpolicy_race.test.sql +1374 -0
  15. package/tests/agent_board_fleet_machine_hijack.test.sql +270 -1
  16. package/tests/agent_board_fleet_machine_reclaim.test.sql +28 -2
  17. package/tests/agent_board_ownerless_quota_census.test.sql +406 -0
  18. package/tests/agent_board_ownerless_renew_quota.test.sql +580 -0
  19. package/tests/catalog/p_metadata_parameters.json +28 -0
  20. package/tests/fixtures/test-prereqs.sql +186 -0
  21. package/tests/isolation/expected/claimpolicy_acquire_revert_race.out +66 -0
  22. package/tests/isolation/expected/claimpolicy_board_scope.out +73 -0
  23. package/tests/isolation/expected/claimpolicy_claimrow_lock_order.out +80 -0
  24. package/tests/isolation/expected/claimpolicy_isolation_refusal.out +114 -0
  25. package/tests/isolation/expected/claimpolicy_renew_revert_race.out +66 -0
  26. package/tests/isolation/expected/claimpolicy_writer_keyshare.out +49 -0
  27. package/tests/isolation/expected/fleet_domain_no_downgrade_demote_race.out +447 -0
  28. package/tests/isolation/specs/claimpolicy_acquire_revert_race.spec +118 -0
  29. package/tests/isolation/specs/claimpolicy_board_scope.spec +115 -0
  30. package/tests/isolation/specs/claimpolicy_claimrow_lock_order.spec +200 -0
  31. package/tests/isolation/specs/claimpolicy_isolation_refusal.spec +162 -0
  32. package/tests/isolation/specs/claimpolicy_renew_revert_race.spec +150 -0
  33. package/tests/isolation/specs/claimpolicy_writer_keyshare.spec +107 -0
  34. package/tests/isolation/specs/fleet_domain_no_downgrade_demote_race.spec +292 -0
  35. package/tests/seeds/20261001000100_agent_board_claimpolicy_lock_grant_revoke.sql.pre.sql +99 -0
@@ -0,0 +1,447 @@
1
+ Parsed test spec with 7 sessions
2
+
3
+ starting permutation: rl_begin rl_lock rm_begin rm_move rl_demote rl_commit rm_commit chk
4
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
5
+ step rl_lock:
6
+ select id from agent_board.fleet_machines
7
+ where id = 'c3970000-0000-4000-8000-000000000001' for update;
8
+
9
+ id
10
+ ------------------------------------
11
+ c3970000-0000-4000-8000-000000000001
12
+ (1 row)
13
+
14
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
15
+ step rm_move:
16
+ select trust_domain_id
17
+ from agent_board.register_fleet_machine(
18
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000002',
19
+ 'nodowngrade-iso-machine-moved', 'sha256:nodowngrade-iso', 'portal',
20
+ jsonb_build_object('redacted', true));
21
+ <waiting ...>
22
+ step rl_demote:
23
+ update agent_board.fleet_trust_domains
24
+ set lifecycle_state = 'pending', approved_at = null, updated_at = now()
25
+ where id = 'd3970000-0000-4000-8000-000000000002';
26
+
27
+ step rl_commit: COMMIT;
28
+ step rm_move: <... completed>
29
+ ERROR: re-registration would move machine into a less approved trust domain (destination d3970000-0000-4000-8000-000000000002, current d3970000-0000-4000-8000-000000000001) — measured after the move, from one snapshot
30
+ step rm_commit: COMMIT;
31
+ step chk:
32
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
33
+ ftd.lifecycle_state as domain_state
34
+ from agent_board.fleet_machines fm
35
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
36
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
37
+
38
+ trust_domain_id |owner_agent_id |machine_state|domain_state
39
+ ------------------------------------+------------------------------------+-------------+------------
40
+ d3970000-0000-4000-8000-000000000001|a3970000-0000-4000-8000-000000000001|active |active
41
+ (1 row)
42
+
43
+
44
+ starting permutation: rm_begin rm_move rm_commit chk
45
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
46
+ step rm_move:
47
+ select trust_domain_id
48
+ from agent_board.register_fleet_machine(
49
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000002',
50
+ 'nodowngrade-iso-machine-moved', 'sha256:nodowngrade-iso', 'portal',
51
+ jsonb_build_object('redacted', true));
52
+
53
+ trust_domain_id
54
+ ------------------------------------
55
+ d3970000-0000-4000-8000-000000000002
56
+ (1 row)
57
+
58
+ step rm_commit: COMMIT;
59
+ step chk:
60
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
61
+ ftd.lifecycle_state as domain_state
62
+ from agent_board.fleet_machines fm
63
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
64
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
65
+
66
+ trust_domain_id |owner_agent_id |machine_state|domain_state
67
+ ------------------------------------+------------------------------------+-------------+------------
68
+ d3970000-0000-4000-8000-000000000002|a3970000-0000-4000-8000-000000000001|active |active
69
+ (1 row)
70
+
71
+
72
+ starting permutation: rl_begin rl_relocate_dest rm_begin rm_move_current rl_demote_current rl_commit rm_commit chk
73
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
74
+ step rl_relocate_dest:
75
+ update agent_board.fleet_machines
76
+ set trust_domain_id = 'd3970000-0000-4000-8000-000000000002', updated_at = now()
77
+ where id = 'c3970000-0000-4000-8000-000000000001';
78
+
79
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
80
+ step rm_move_current:
81
+ select trust_domain_id
82
+ from agent_board.register_fleet_machine(
83
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
84
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
85
+ jsonb_build_object('redacted', true));
86
+ <waiting ...>
87
+ step rl_demote_current:
88
+ update agent_board.fleet_trust_domains
89
+ set lifecycle_state = 'pending', approved_at = null, updated_at = now()
90
+ where id = 'd3970000-0000-4000-8000-000000000001';
91
+
92
+ step rl_commit: COMMIT;
93
+ step rm_move_current: <... completed>
94
+ ERROR: re-registration would move machine into a less approved trust domain (destination d3970000-0000-4000-8000-000000000001, current d3970000-0000-4000-8000-000000000002) — measured after the move, from one snapshot
95
+ step rm_commit: COMMIT;
96
+ step chk:
97
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
98
+ ftd.lifecycle_state as domain_state
99
+ from agent_board.fleet_machines fm
100
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
101
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
102
+
103
+ trust_domain_id |owner_agent_id |machine_state|domain_state
104
+ ------------------------------------+------------------------------------+-------------+------------
105
+ d3970000-0000-4000-8000-000000000002|a3970000-0000-4000-8000-000000000001|active |active
106
+ (1 row)
107
+
108
+
109
+ starting permutation: rl_begin rl_relocate_dest rm_begin rm_move_current rl_commit rm_commit chk
110
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
111
+ step rl_relocate_dest:
112
+ update agent_board.fleet_machines
113
+ set trust_domain_id = 'd3970000-0000-4000-8000-000000000002', updated_at = now()
114
+ where id = 'c3970000-0000-4000-8000-000000000001';
115
+
116
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
117
+ step rm_move_current:
118
+ select trust_domain_id
119
+ from agent_board.register_fleet_machine(
120
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
121
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
122
+ jsonb_build_object('redacted', true));
123
+ <waiting ...>
124
+ step rl_commit: COMMIT;
125
+ step rm_move_current: <... completed>
126
+ trust_domain_id
127
+ ------------------------------------
128
+ d3970000-0000-4000-8000-000000000001
129
+ (1 row)
130
+
131
+ step rm_commit: COMMIT;
132
+ step chk:
133
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
134
+ ftd.lifecycle_state as domain_state
135
+ from agent_board.fleet_machines fm
136
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
137
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
138
+
139
+ trust_domain_id |owner_agent_id |machine_state|domain_state
140
+ ------------------------------------+------------------------------------+-------------+------------
141
+ d3970000-0000-4000-8000-000000000001|a3970000-0000-4000-8000-000000000001|active |active
142
+ (1 row)
143
+
144
+
145
+ starting permutation: rl_begin rl_lock rm_begin rm_move_current rl_relocate_x rl_demote_current rl_commit rm_commit chk
146
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
147
+ step rl_lock:
148
+ select id from agent_board.fleet_machines
149
+ where id = 'c3970000-0000-4000-8000-000000000001' for update;
150
+
151
+ id
152
+ ------------------------------------
153
+ c3970000-0000-4000-8000-000000000001
154
+ (1 row)
155
+
156
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
157
+ step rm_move_current:
158
+ select trust_domain_id
159
+ from agent_board.register_fleet_machine(
160
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
161
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
162
+ jsonb_build_object('redacted', true));
163
+ <waiting ...>
164
+ step rl_relocate_x:
165
+ update agent_board.fleet_machines
166
+ set trust_domain_id = 'd3970000-0000-4000-8000-000000000003', updated_at = now()
167
+ where id = 'c3970000-0000-4000-8000-000000000001';
168
+
169
+ step rl_demote_current:
170
+ update agent_board.fleet_trust_domains
171
+ set lifecycle_state = 'pending', approved_at = null, updated_at = now()
172
+ where id = 'd3970000-0000-4000-8000-000000000001';
173
+
174
+ step rl_commit: COMMIT;
175
+ step rm_move_current: <... completed>
176
+ ERROR: re-registration would move machine into a less approved trust domain (destination d3970000-0000-4000-8000-000000000001, current d3970000-0000-4000-8000-000000000003) — measured after the move, from one snapshot
177
+ step rm_commit: COMMIT;
178
+ step chk:
179
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
180
+ ftd.lifecycle_state as domain_state
181
+ from agent_board.fleet_machines fm
182
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
183
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
184
+
185
+ trust_domain_id |owner_agent_id |machine_state|domain_state
186
+ ------------------------------------+------------------------------------+-------------+------------
187
+ d3970000-0000-4000-8000-000000000003|a3970000-0000-4000-8000-000000000001|active |active
188
+ (1 row)
189
+
190
+
191
+ starting permutation: rl_begin rl_lock rm_begin rm_move_current rl_relocate_x rl_commit rm_commit chk
192
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
193
+ step rl_lock:
194
+ select id from agent_board.fleet_machines
195
+ where id = 'c3970000-0000-4000-8000-000000000001' for update;
196
+
197
+ id
198
+ ------------------------------------
199
+ c3970000-0000-4000-8000-000000000001
200
+ (1 row)
201
+
202
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
203
+ step rm_move_current:
204
+ select trust_domain_id
205
+ from agent_board.register_fleet_machine(
206
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
207
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
208
+ jsonb_build_object('redacted', true));
209
+ <waiting ...>
210
+ step rl_relocate_x:
211
+ update agent_board.fleet_machines
212
+ set trust_domain_id = 'd3970000-0000-4000-8000-000000000003', updated_at = now()
213
+ where id = 'c3970000-0000-4000-8000-000000000001';
214
+
215
+ step rl_commit: COMMIT;
216
+ step rm_move_current: <... completed>
217
+ trust_domain_id
218
+ ------------------------------------
219
+ d3970000-0000-4000-8000-000000000001
220
+ (1 row)
221
+
222
+ step rm_commit: COMMIT;
223
+ step chk:
224
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
225
+ ftd.lifecycle_state as domain_state
226
+ from agent_board.fleet_machines fm
227
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
228
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
229
+
230
+ trust_domain_id |owner_agent_id |machine_state|domain_state
231
+ ------------------------------------+------------------------------------+-------------+------------
232
+ d3970000-0000-4000-8000-000000000001|a3970000-0000-4000-8000-000000000001|active |active
233
+ (1 row)
234
+
235
+
236
+ starting permutation: rc_begin rc_reclaim rm_begin rm_move_current rc_commit rm_commit chk
237
+ step rc_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
238
+ step rc_reclaim:
239
+ select owner_agent_id, trust_domain_id
240
+ from agent_board.reclaim_fleet_machine(
241
+ 'c3970000-0000-4000-8000-000000000001', 'a3970000-0000-4000-8000-000000000003',
242
+ 'a3970000-0000-4000-8000-000000000002', 'iso reclaim vs register',
243
+ 'd3970000-0000-4000-8000-000000000004');
244
+
245
+ owner_agent_id |trust_domain_id
246
+ ------------------------------------+------------------------------------
247
+ a3970000-0000-4000-8000-000000000003|d3970000-0000-4000-8000-000000000004
248
+ (1 row)
249
+
250
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
251
+ step rm_move_current:
252
+ select trust_domain_id
253
+ from agent_board.register_fleet_machine(
254
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
255
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
256
+ jsonb_build_object('redacted', true));
257
+ <waiting ...>
258
+ step rc_commit: COMMIT;
259
+ step rm_move_current: <... completed>
260
+ ERROR: machine fingerprint is registered to another owner
261
+ step rm_commit: COMMIT;
262
+ step chk:
263
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
264
+ ftd.lifecycle_state as domain_state
265
+ from agent_board.fleet_machines fm
266
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
267
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
268
+
269
+ trust_domain_id |owner_agent_id |machine_state|domain_state
270
+ ------------------------------------+------------------------------------+-------------+------------
271
+ d3970000-0000-4000-8000-000000000004|a3970000-0000-4000-8000-000000000003|active |active
272
+ (1 row)
273
+
274
+
275
+ starting permutation: rm_begin rm_move_current rc_begin rc_reclaim rm_commit rc_commit chk
276
+ step rm_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
277
+ step rm_move_current:
278
+ select trust_domain_id
279
+ from agent_board.register_fleet_machine(
280
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000001',
281
+ 'nodowngrade-iso-machine-relabelled', 'sha256:nodowngrade-iso', 'portal',
282
+ jsonb_build_object('redacted', true));
283
+
284
+ trust_domain_id
285
+ ------------------------------------
286
+ d3970000-0000-4000-8000-000000000001
287
+ (1 row)
288
+
289
+ step rc_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
290
+ step rc_reclaim:
291
+ select owner_agent_id, trust_domain_id
292
+ from agent_board.reclaim_fleet_machine(
293
+ 'c3970000-0000-4000-8000-000000000001', 'a3970000-0000-4000-8000-000000000003',
294
+ 'a3970000-0000-4000-8000-000000000002', 'iso reclaim vs register',
295
+ 'd3970000-0000-4000-8000-000000000004');
296
+ <waiting ...>
297
+ step rm_commit: COMMIT;
298
+ step rc_reclaim: <... completed>
299
+ owner_agent_id |trust_domain_id
300
+ ------------------------------------+------------------------------------
301
+ a3970000-0000-4000-8000-000000000003|d3970000-0000-4000-8000-000000000004
302
+ (1 row)
303
+
304
+ step rc_commit: COMMIT;
305
+ step chk:
306
+ select fm.trust_domain_id, fm.owner_agent_id, fm.lifecycle_state as machine_state,
307
+ ftd.lifecycle_state as domain_state
308
+ from agent_board.fleet_machines fm
309
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
310
+ where fm.id = 'c3970000-0000-4000-8000-000000000001';
311
+
312
+ trust_domain_id |owner_agent_id |machine_state|domain_state
313
+ ------------------------------------+------------------------------------+-------------+------------
314
+ d3970000-0000-4000-8000-000000000004|a3970000-0000-4000-8000-000000000003|active |active
315
+ (1 row)
316
+
317
+
318
+ starting permutation: rf_begin rf_register rm2_begin rm2_register rl_begin rl_demote_race_dest rl_commit rf_commit rm2_commit chkf
319
+ step rf_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
320
+ step rf_register:
321
+ select trust_domain_id
322
+ from agent_board.register_fleet_machine(
323
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000005',
324
+ 'nodowngrade-iso-fresh-winner', 'sha256:nodowngrade-iso-fresh', 'portal',
325
+ jsonb_build_object('redacted', true));
326
+
327
+ trust_domain_id
328
+ ------------------------------------
329
+ d3970000-0000-4000-8000-000000000005
330
+ (1 row)
331
+
332
+ step rm2_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
333
+ step rm2_register:
334
+ select trust_domain_id
335
+ from agent_board.register_fleet_machine(
336
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000006',
337
+ 'nodowngrade-iso-fresh-loser', 'sha256:nodowngrade-iso-fresh', 'portal',
338
+ jsonb_build_object('redacted', true));
339
+ <waiting ...>
340
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
341
+ step rl_demote_race_dest:
342
+ update agent_board.fleet_trust_domains
343
+ set lifecycle_state = 'quarantined', approved_at = null, updated_at = now()
344
+ where id = 'd3970000-0000-4000-8000-000000000006';
345
+
346
+ step rl_commit: COMMIT;
347
+ step rf_commit: COMMIT;
348
+ step rm2_register: <... completed>
349
+ ERROR: concurrent registration of machine fingerprint sha256:nodowngrade-iso-fresh — retry
350
+ step rm2_commit: COMMIT;
351
+ step chkf:
352
+ select fm.trust_domain_id, fm.lifecycle_state as machine_state, ftd.lifecycle_state as domain_state
353
+ from agent_board.fleet_machines fm
354
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
355
+ where fm.machine_fingerprint = 'sha256:nodowngrade-iso-fresh';
356
+
357
+ trust_domain_id |machine_state|domain_state
358
+ ------------------------------------+-------------+------------
359
+ d3970000-0000-4000-8000-000000000005|active |pending
360
+ (1 row)
361
+
362
+
363
+ starting permutation: rf_begin rf_register rm2_begin rm2_register rl_begin rl_promote_race_src rl_commit rf_commit rm2_commit chkf
364
+ step rf_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
365
+ step rf_register:
366
+ select trust_domain_id
367
+ from agent_board.register_fleet_machine(
368
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000005',
369
+ 'nodowngrade-iso-fresh-winner', 'sha256:nodowngrade-iso-fresh', 'portal',
370
+ jsonb_build_object('redacted', true));
371
+
372
+ trust_domain_id
373
+ ------------------------------------
374
+ d3970000-0000-4000-8000-000000000005
375
+ (1 row)
376
+
377
+ step rm2_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
378
+ step rm2_register:
379
+ select trust_domain_id
380
+ from agent_board.register_fleet_machine(
381
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000006',
382
+ 'nodowngrade-iso-fresh-loser', 'sha256:nodowngrade-iso-fresh', 'portal',
383
+ jsonb_build_object('redacted', true));
384
+ <waiting ...>
385
+ step rl_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
386
+ step rl_promote_race_src:
387
+ update agent_board.fleet_trust_domains
388
+ set lifecycle_state = 'active', approved_at = now(), updated_at = now()
389
+ where id = 'd3970000-0000-4000-8000-000000000005';
390
+
391
+ step rl_commit: COMMIT;
392
+ step rf_commit: COMMIT;
393
+ step rm2_register: <... completed>
394
+ ERROR: concurrent registration of machine fingerprint sha256:nodowngrade-iso-fresh — retry
395
+ step rm2_commit: COMMIT;
396
+ step chkf:
397
+ select fm.trust_domain_id, fm.lifecycle_state as machine_state, ftd.lifecycle_state as domain_state
398
+ from agent_board.fleet_machines fm
399
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
400
+ where fm.machine_fingerprint = 'sha256:nodowngrade-iso-fresh';
401
+
402
+ trust_domain_id |machine_state|domain_state
403
+ ------------------------------------+-------------+------------
404
+ d3970000-0000-4000-8000-000000000005|active |active
405
+ (1 row)
406
+
407
+
408
+ starting permutation: rf_begin rf_register rf_commit rm2_begin rm2_register rm2_commit chkf
409
+ step rf_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
410
+ step rf_register:
411
+ select trust_domain_id
412
+ from agent_board.register_fleet_machine(
413
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000005',
414
+ 'nodowngrade-iso-fresh-winner', 'sha256:nodowngrade-iso-fresh', 'portal',
415
+ jsonb_build_object('redacted', true));
416
+
417
+ trust_domain_id
418
+ ------------------------------------
419
+ d3970000-0000-4000-8000-000000000005
420
+ (1 row)
421
+
422
+ step rf_commit: COMMIT;
423
+ step rm2_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
424
+ step rm2_register:
425
+ select trust_domain_id
426
+ from agent_board.register_fleet_machine(
427
+ 'a3970000-0000-4000-8000-000000000001', 'd3970000-0000-4000-8000-000000000006',
428
+ 'nodowngrade-iso-fresh-loser', 'sha256:nodowngrade-iso-fresh', 'portal',
429
+ jsonb_build_object('redacted', true));
430
+
431
+ trust_domain_id
432
+ ------------------------------------
433
+ d3970000-0000-4000-8000-000000000006
434
+ (1 row)
435
+
436
+ step rm2_commit: COMMIT;
437
+ step chkf:
438
+ select fm.trust_domain_id, fm.lifecycle_state as machine_state, ftd.lifecycle_state as domain_state
439
+ from agent_board.fleet_machines fm
440
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
441
+ where fm.machine_fingerprint = 'sha256:nodowngrade-iso-fresh';
442
+
443
+ trust_domain_id |machine_state|domain_state
444
+ ------------------------------------+-------------+------------
445
+ d3970000-0000-4000-8000-000000000006|active |pending
446
+ (1 row)
447
+
@@ -0,0 +1,118 @@
1
+ # Consiliency/message-board#405 — an acquire whose snapshot predates a committed
2
+ # advisory -> inherit revert must NOT bank a full-horizon ownerless lease.
3
+ #
4
+ # WHY ACQUIRE IS THE WORSE HALF OF THIS FAMILY. #406's cap reset clamps the
5
+ # board's EXISTING ownerless claims on a revert. On this path there is no claim
6
+ # yet: the acquire inserts AFTER the revert committed, so there is nothing for
7
+ # the reset to reach even in principle. Whatever horizon a stale 'advisory' read
8
+ # lets through is banked outright.
9
+ #
10
+ # AND IT IS THE PATH THE FIRST DESIGN MISSED. That design said the board lock
11
+ # goes "before the agent-scoped lock". acquire_claim's agent-scoped quota lock
12
+ # lives INSIDE the branch that a stale 'advisory' read SKIPS ENTIRELY, so on the
13
+ # dangerous path it is never reached and ordering against it means nothing. This
14
+ # spec drives exactly that branch: the acquirer reads 'advisory' unless it is
15
+ # made to wait, and if it reads 'advisory' it takes no lock at all.
16
+ #
17
+ # THE INTERLEAVE. w (the board owner) opens a transaction and reverts the board
18
+ # to 'inherit', holding the board-scoped advisory lock until commit. a then asks
19
+ # for a 400-day 'file' lease. Under READ COMMITTED a's snapshot at that moment
20
+ # still shows 'advisory'.
21
+ #
22
+ # WHAT THE FIX PRODUCES (this golden): a's acquire prints `<waiting ...>` on w's
23
+ # lock; after w commits, a RE-READS the policy in a fresh statement, sees
24
+ # 'inherit', and the ownerless TTL cap rejects the 400-day horizon with
25
+ # `ERROR: ownerless claim lease horizon exceeds cap`. The checker sees ZERO
26
+ # claims.
27
+ #
28
+ # MUTATION SIGNAL (verified in the PR): delete the `perform
29
+ # agent_board._claimgate_lock_board_policy(v_board_id)` line from acquire_claim
30
+ # -> a never waits, resolves the stale 'advisory', skips the whole ownerless
31
+ # block and INSERTS. The golden diverges on the missing `<waiting ...>`, on the
32
+ # missing error, and on the checker (1 claim, over-cap lease = t).
33
+ #
34
+ # THE TWIN IS NOT OPTIONAL. A guard that simply over-serialises — or one that
35
+ # resolved every board to 'inherit' — would pass the race permutation and break
36
+ # the feature. The second permutation runs the SAME acquire with no writer at
37
+ # all: the board is still 'advisory', so the 400-day lease must be GRANTED, with
38
+ # no wait anywhere in the trace.
39
+ #
40
+ # Sessions run as `authenticated` (service_role is exempt from these guards
41
+ # entirely, so a service_role probe would prove nothing).
42
+
43
+ setup
44
+ {
45
+ insert into agent_board.claimgate_enforcement_flags(scope_key, enabled) values ('ownerless_guards', true)
46
+ on conflict (scope_key) do update set enabled = true;
47
+ insert into auth.users (id) values ('40500000-0000-4000-8000-0000000000a1');
48
+ insert into agent_board.agents(id, agent_type, kind, handle, display_name, status, auth_user_id, owner_user_id)
49
+ values ('40500000-0000-4000-8000-000000000001', 'agent', 'agent',
50
+ 'cpr-acq-owner', 'CPR Acquire Owner', 'active',
51
+ '40500000-0000-4000-8000-0000000000a1', '40500000-0000-4000-8000-0000000000a1');
52
+ select count(*) from agent_board.create_board(
53
+ '40500000-0000-4000-8000-000000000001',
54
+ 'cpr-acq-board', 'CPR Acquire Board',
55
+ 'message-board#405 acquire stale-policy probe', jsonb_build_object(), 'private');
56
+ insert into agent_board.threads(id, thread_type, created_by_agent_id, subject, board_id)
57
+ values ('40500000-0000-4000-8000-000000000010', 'coordination',
58
+ '40500000-0000-4000-8000-000000000001', 'CPR acquire thread',
59
+ (select id from agent_board.boards where slug = 'cpr-acq-board'));
60
+ -- The board starts OPTED OUT. Written directly rather than through the RPC so the setup does not
61
+ -- depend on the very gate this spec exercises; the RPC's own transitions are BCP's job.
62
+ update agent_board.boards set claim_policy = 'advisory' where slug = 'cpr-acq-board';
63
+ }
64
+
65
+ teardown
66
+ {
67
+ delete from agent_board.claims where agent_id = '40500000-0000-4000-8000-000000000001';
68
+ delete from agent_board.threads where id = '40500000-0000-4000-8000-000000000010';
69
+ delete from agent_board.board_membership_events where board_id in (
70
+ select id from agent_board.boards where slug = 'cpr-acq-board');
71
+ delete from agent_board.board_memberships where board_id in (
72
+ select id from agent_board.boards where slug = 'cpr-acq-board');
73
+ delete from agent_board.boards where slug = 'cpr-acq-board';
74
+ delete from agent_board.agents where id = '40500000-0000-4000-8000-000000000001';
75
+ delete from auth.users where id = '40500000-0000-4000-8000-0000000000a1';
76
+ delete from agent_board.claimgate_enforcement_flags where scope_key = 'ownerless_guards';
77
+ }
78
+
79
+ # w: the board owner reverting the opt-out. Holds the board policy lock until commit.
80
+ session "w"
81
+ step "w_begin" { BEGIN; SET LOCAL ROLE authenticated; SET LOCAL "request.jwt.claim.role" = 'authenticated'; SET LOCAL "request.jwt.claim.sub" = '40500000-0000-4000-8000-0000000000a1'; }
82
+ step "w_flip" {
83
+ select claim_policy
84
+ from agent_board.set_board_claim_policy(
85
+ (select id from agent_board.boards where slug = 'cpr-acq-board'), 'inherit');
86
+ }
87
+ step "w_commit" { COMMIT; }
88
+
89
+ # a: the in-flight acquire. 400 days is far past the 30-day ownerless TTL cap, so the horizon it
90
+ # gets is a direct readout of which policy it resolved.
91
+ session "a"
92
+ step "a_begin" { BEGIN; SET LOCAL ROLE authenticated; SET LOCAL "request.jwt.claim.role" = 'authenticated'; SET LOCAL "request.jwt.claim.sub" = '40500000-0000-4000-8000-0000000000a1'; }
93
+ step "a_acq" {
94
+ select resource_key
95
+ from agent_board.acquire_claim(null, 'file', 'cpr-acq-key', now() + interval '400 days',
96
+ null, '40500000-0000-4000-8000-000000000010');
97
+ }
98
+ step "a_commit" { COMMIT; }
99
+
100
+ # checker: a count and a boolean, never a timestamp — a golden with a clock in it is not a golden.
101
+ session "chk"
102
+ step "chk" {
103
+ select count(*)::int as active_claims,
104
+ coalesce(bool_or(lease_expires_at > now() + interval '31 days'), false) as over_cap_lease
105
+ from agent_board.claims
106
+ where agent_id = '40500000-0000-4000-8000-000000000001'
107
+ and resource_kind = 'file'
108
+ and status = 'active'
109
+ and released_at is null;
110
+ }
111
+
112
+ # THE RACE: the acquire is issued while the revert is uncommitted.
113
+ permutation "w_begin" "w_flip" "a_begin" "a_acq" "w_commit" "a_commit" "chk"
114
+
115
+ # THE TWIN: no revert at all. The board is advisory, so the opt-out must still WORK — the 400-day
116
+ # lease is granted and nothing waits. A guard that over-serialises, or one that resolved every
117
+ # board to 'inherit', fails here and passes the permutation above.
118
+ permutation "a_begin" "a_acq" "a_commit" "chk"