@consiliency/agent-board-schema 1.51.0 → 1.53.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 (44) hide show
  1. package/fixtures/already-applied.json +4 -0
  2. package/migrations/20261003000100_agent_board_room_roster.sql +115 -0
  3. package/package.json +1 -1
  4. package/schema-manifest.json +12 -3
  5. package/src/tooling.test.mjs +4 -2
  6. package/tests/agent_board_agent_liveness.test.sql +3 -1
  7. package/tests/agent_board_atomic_fleet_onboarding.test.sql +33 -36
  8. package/tests/agent_board_authbound_boundary.test.sql +4 -3
  9. package/tests/agent_board_board_claim_policy.test.sql +17 -6
  10. package/tests/agent_board_claim_subject_gate.test.sql +7 -8
  11. package/tests/agent_board_claimkey.test.sql +9 -6
  12. package/tests/agent_board_claimpolicy_race.test.sql +1466 -342
  13. package/tests/agent_board_consent_emission.test.sql +5 -4
  14. package/tests/agent_board_consent_gating.test.sql +20 -9
  15. package/tests/agent_board_enroll_resumption.test.sql +1 -1
  16. package/tests/agent_board_enrollment_audit_content.test.sql +5 -4
  17. package/tests/agent_board_federated_identity_injective_slug.test.sql +3 -1
  18. package/tests/agent_board_federated_lock_order_class.test.sql +69 -52
  19. package/tests/agent_board_fedsession.test.sql +3 -1
  20. package/tests/agent_board_fedsession_provider_absence_gate.test.sql +9 -4
  21. package/tests/agent_board_fedsession_stored_identity_gate.test.sql +18 -6
  22. package/tests/agent_board_fk_lock_edges.test.sql +64 -5
  23. package/tests/agent_board_fleet_domain_reclaim.test.sql +2 -4
  24. package/tests/agent_board_fleet_machine_hijack.test.sql +2 -4
  25. package/tests/agent_board_fleet_machine_reactivation.test.sql +5 -1
  26. package/tests/agent_board_fleet_machine_reclaim.test.sql +2 -4
  27. package/tests/agent_board_invite_no_downgrade.test.sql +24 -18
  28. package/tests/agent_board_ledger_authority.test.sql +29 -21
  29. package/tests/agent_board_mint_harden.test.sql +5 -5
  30. package/tests/agent_board_outbox_wake_ordering.test.sql +4 -3
  31. package/tests/agent_board_ownerless_renew_quota.test.sql +7 -2
  32. package/tests/agent_board_portal_offline_invariant.test.sql +5 -4
  33. package/tests/agent_board_receipt_subject_gate.test.sql +7 -8
  34. package/tests/agent_board_rolereset.test.sql +5 -3
  35. package/tests/agent_board_room_roster.test.sql +466 -0
  36. package/tests/agent_board_rowid.test.sql +39 -19
  37. package/tests/agent_board_signer_lifecycle.test.sql +24 -13
  38. package/tests/agent_board_source_strip_helper.test.sql +2 -1
  39. package/tests/agent_board_task_event_origin_posture.test.sql +21 -9
  40. package/tests/agent_board_wake_recovery.test.sql +53 -26
  41. package/tests/agent_board_write_enforcement_class.test.sql +130 -12
  42. package/tests/catalog/function_execute_privileges.json +1932 -0
  43. package/tests/catalog/p_metadata_parameters.json +4 -0
  44. package/tests/fixtures/test-prereqs.sql +644 -237
@@ -232,7 +232,7 @@ select is(
232
232
  from pg_proc p join pg_namespace n on n.oid = p.pronamespace
233
233
  where n.nspname = 'agent_board' and p.prokind = 'f'
234
234
  and p.prolang <> (select oid from pg_language where lanname = 'internal')
235
- and agent_board_test.stripped_body(p.oid) ~* '(insert into|update)[[:space:]]+agent_board\.board_memberships'
235
+ and agent_board_test.stripped_body(p.oid) ~ agent_board_test.stmt_re('insert into|update', 'board_memberships')
236
236
  and agent_board_test.stripped_body(p.oid) !~* 'perform agent_board\._emit_membership_event'
237
237
  and p.proname <> 'grant_board_role'),
238
238
  '',
@@ -263,7 +263,8 @@ select is(
263
263
 
264
264
  -- ...and the one exemption is genuinely state-blind: membership_state never appears in a SET.
265
265
  select ok(
266
- (select agent_board_test.stripped_body(p.oid) !~* 'set[^;]*membership_state[[:space:]]*='
266
+ (select agent_board_test.stripped_body(p.oid, true)
267
+ !~ agent_board_test.re(agent_board_test.col_assign_frag('board_memberships', 'membership_state', agent_board_test.bare_ok(p.oid)))
267
268
  from pg_proc p join pg_namespace n on n.oid = p.pronamespace
268
269
  where n.nspname = 'agent_board' and p.proname = 'grant_board_role'),
269
270
  'COMPLETENESS: the exemption holds -- grant_board_role never SETs membership_state');
@@ -274,7 +275,7 @@ select is(
274
275
  from pg_proc p join pg_namespace n on n.oid = p.pronamespace
275
276
  where n.nspname = 'agent_board' and p.prokind = 'f'
276
277
  and p.proname <> '_emit_membership_event'
277
- and pg_get_functiondef(p.oid) ~* 'insert into[[:space:]]+agent_board\.board_membership_events'),
278
+ and agent_board_test.stripped_body(p.oid, true) ~ agent_board_test.stmt_re('insert into', 'board_membership_events')),
278
279
  0,
279
280
  'COMPLETENESS: only _emit_membership_event writes the ledger -- the derivation cannot drift');
280
281
 
@@ -578,7 +579,7 @@ select is(
578
579
  where n.nspname = 'agent_board' and p.prokind = 'f'
579
580
  and p.prolang <> (select oid from pg_language where lanname = 'internal')
580
581
  and has_function_privilege('authenticated', p.oid, 'EXECUTE')
581
- and pg_get_functiondef(p.oid) ~ '_membership_consent_present'),
582
+ and agent_board_test.stripped_body(p.oid) ~ agent_board_test.call_re('_membership_consent_present')),
582
583
  'resolve_board_request, update_board_membership',
583
584
  'scope: exactly TWO authenticated routes read the predicate');
584
585
 
@@ -309,7 +309,10 @@ select is(
309
309
  -- filter that is the fail-OPEN direction: the offender simply leaves the
310
310
  -- class and the expected-empty assertion stays green. (Same mechanism
311
311
  -- agent_board_wake_recovery.test.sql records for its own WR-7 filter.)
312
- ~* '(_upsert_board_membership_state|_redeem_invite_for_agent|update_board_membership|insert into agent_board\.board_memberships)'
312
+ ~ agent_board_test.re(agent_board_test.call_frag('_upsert_board_membership_state')
313
+ || '|' || agent_board_test.call_frag('_redeem_invite_for_agent')
314
+ || '|' || agent_board_test.call_frag('update_board_membership')
315
+ || '|' || agent_board_test.stmt_frag('insert into', 'board_memberships'))
313
316
  -- gated: consults the predicate, or refuses a non-subject actor structurally.
314
317
  --
315
318
  -- SPLIT IN TWO, by what kind of thing each marker IS. The single `!~` over a
@@ -326,16 +329,20 @@ select is(
326
329
  -- gate genuinely removed. It does not any more.
327
330
  -- anchored to the CALL shape, for the same reason the message half below is
328
331
  -- anchored to the raise shape: a bare substring is satisfied by a NAME.
329
- -- SCHEMA-QUALIFIED, because a bare-name anchor proves call SYNTAX, not callee
330
- -- IDENTITY: `\m_membership_consent_present\s*\(` also matches
331
- -- `zz_other._membership_consent_present(...)` (measured true). Every live call
332
- -- site in agent_board is `agent_board.`-qualified, so requiring the
332
+ -- SCHEMA-QUALIFIED (`bare_ok => false`), because a bare-name anchor proves call
333
+ -- SYNTAX, not callee IDENTITY: the old `\m_membership_consent_present\s*\(` also
334
+ -- matched `zz_other._membership_consent_present(...)` (measured true). Every live
335
+ -- call site in agent_board is `agent_board.`-qualified, so requiring the
333
336
  -- qualification costs nothing today and is fail-CLOSED if someone later writes
334
337
  -- an unqualified call (it reads as NOT calling). Overload count is pinned
335
338
  -- separately, so schema + name is the identity.
336
- and agent_board_test.stripped_body(p.oid) !~* '\magent_board\._membership_consent_present\s*\('
339
+ and agent_board_test.stripped_body(p.oid) !~ agent_board_test.call_re('_membership_consent_present', false)
340
+ -- The raise shape through the matcher family: `raise exception` case-folded with any
341
+ -- whitespace (the hand-rolled form was case-SENSITIVE, so `RAISE EXCEPTION` passed this
342
+ -- absence silently), then the message inside a literal of the same statement.
337
343
  and agent_board_test.stripped_body(p.oid, true)
338
- !~ 'raise[[:space:]]+exception[^;]{0,250}(actor mismatch|requires an act by that agent)'
344
+ !~ agent_board_test.re('\m' || agent_board_test.ci_re('raise exception') || '\M' || agent_board_test.same_stmt()
345
+ || '''(?:[^'']|'''')*?(?:actor mismatch|requires an act by that agent)')
339
346
  -- stated exemptions, each with a reason recorded in the migration header
340
347
  and p.proname not in (
341
348
  'create_board', -- the actor IS the subject: it seeds the creator's own seat
@@ -362,7 +369,9 @@ select is(
362
369
  -- LITERALS KEPT: the marker is the ARGUMENT ''joined''/''subscribed'' passed
363
370
  -- to the sink -- a string literal in the code being matched.
364
371
  agent_board_test.stripped_body(p.oid, true),
365
- '(?:_upsert_board_membership_state|update_board_membership)\s*\([^;]*?''(joined|subscribed)''',
372
+ agent_board_test.re('(?:' || agent_board_test.call_frag('_upsert_board_membership_state')
373
+ || '|' || agent_board_test.call_frag('update_board_membership') || ')'
374
+ || '[^;]*?''(joined|subscribed)'''),
366
375
  'g') m
367
376
  where n.nspname = 'agent_board'
368
377
  and p.proname in ('invite_board_member','request_join_board','leave_board')),
@@ -377,7 +386,9 @@ select is(
377
386
  cross join lateral regexp_matches(
378
387
  -- LITERALS KEPT: same shape as above -- the state being written is a literal.
379
388
  agent_board_test.stripped_body(p.oid, true),
380
- '(?:_upsert_board_membership_state|update_board_membership)\s*\([^;]*?''(invited|requested|left)''',
389
+ agent_board_test.re('(?:' || agent_board_test.call_frag('_upsert_board_membership_state')
390
+ || '|' || agent_board_test.call_frag('update_board_membership') || ')'
391
+ || '[^;]*?''(invited|requested|left)'''),
381
392
  'g') m
382
393
  where n.nspname = 'agent_board'
383
394
  and p.proname in ('invite_board_member','request_join_board','leave_board')),
@@ -200,7 +200,7 @@ select is(
200
200
  -- while a third signing-key creator was live (message-board#293). This site was
201
201
  -- invisible to the #196 lint because that lint only inspects POSITIONAL and
202
202
  -- NEGATIVE assertions, and this is a PRESENCE match -- see the note on the lint.
203
- and agent_board_test.stripped_body(p.oid) ~* 'insert into agent_board\.agent_signing_keys'),
203
+ and agent_board_test.stripped_body(p.oid) ~ agent_board_test.stmt_re('insert into', 'agent_signing_keys')),
204
204
  '_enroll_federated_identity_once, mint_delegated_child',
205
205
  'EC-2: only the enroll creator and delegated-child mint insert signing keys (strip_sql-derived)');
206
206
 
@@ -69,7 +69,8 @@ select has_column('agent_board', 'enrollment_federation_audit', 'enrolled_at', '
69
69
  -- writes it and total human revocation reads stable principal evidence from it. ----
70
70
  select is(
71
71
  (select count(*)::int from (
72
- select pg_get_functiondef(p.oid) as def, p.proname
72
+ -- literals KEPT: a dynamic-SQL reference is still a reference, and this is an absence claim
73
+ select agent_board_test.stripped_body(p.oid, true) as def, p.proname
73
74
  from pg_proc p join pg_namespace n on n.oid = p.pronamespace
74
75
  where n.nspname = 'agent_board'
75
76
  -- pg_get_functiondef() RAISES on aggregate ('a') / window ('w') procs
@@ -85,11 +86,11 @@ select is(
85
86
  'revoke_human_subtree'
86
87
  )
87
88
  ) d
88
- where lower(d.def) like '%enrollment_federation_audit%'),
89
+ where d.def ~ agent_board_test.qname_re('enrollment_federation_audit')),
89
90
  0, 'no agent_board RPC other than federation enrollment and total human revocation references enrollment_federation_audit');
90
91
  select is(
91
92
  (select count(*)::int from (
92
- select pg_get_functiondef(p.oid) as def
93
+ select agent_board_test.stripped_body(p.oid, true) as def
93
94
  from pg_proc p join pg_namespace n on n.oid = p.pronamespace
94
95
  where n.nspname = 'agent_board'
95
96
  and p.prokind in ('f', 'p') -- pg_get_functiondef raises on aggregate/window procs
@@ -97,7 +98,7 @@ select is(
97
98
  'mint_fleet_agent_session', 'post_board_message', 'send_direct_message',
98
99
  'send_multicast_message', 'create_tasking_delivery', 'revoke_agent')
99
100
  ) d
100
- where lower(d.def) like '%enrollment_federation_audit%'),
101
+ where d.def ~ agent_board_test.qname_re('enrollment_federation_audit')),
101
102
  0, 'no send/session/revoke write-path RPC reads the enrollment audit table');
102
103
 
103
104
  -- #6 fix: the authenticated SELECT policy is scoped to the owning principal
@@ -332,7 +332,9 @@ select is(
332
332
  (select coalesce(string_agg(p.oid::regprocedure::text, ', ' order by p.oid::regprocedure::text), '(none)')
333
333
  from pg_proc p
334
334
  where p.pronamespace = 'agent_board'::regnamespace
335
- and agent_board_test.stripped_body(p.oid, true) ~ 'p_issuer\s*\|\|\s*''\|''\s*\|\|\s*p_subject'),
335
+ -- col_frag is the bare-identifier form (guards on both sides): a parameter, here
336
+ and agent_board_test.stripped_body(p.oid, true)
337
+ ~ agent_board_test.re(agent_board_test.col_frag('p_issuer') || '\s*\|\|\s*''\|''\s*\|\|\s*' || agent_board_test.col_frag('p_subject'))),
336
338
  '(none)',
337
339
  'CLS-2: no agent_board function still concatenates p_issuer || ''|'' || p_subject (offenders are named)');
338
340
 
@@ -29,13 +29,22 @@
29
29
  -- them, and it re-synced only because that count is even -- working by luck).
30
30
  -- Both shapes are now mutation-pinned by name;
31
31
  -- * table and function names matched BOTH qualified and BARE, with each
32
- -- function's own search_path (pg_proc.proconfig) deciding whether bare names
33
- -- resolve into agent_board -- a route written `insert into board_memberships`
34
- -- is visible, and so is `perform _redeem_invite_for_agent(...)`;
32
+ -- function's own search_path (pg_proc.proconfig, via agent_board_test.bare_ok)
33
+ -- deciding whether bare names resolve into agent_board -- a route written
34
+ -- `insert into board_memberships` is visible, and so is
35
+ -- `perform _redeem_invite_for_agent(...)`. The patterns are the shared matcher
36
+ -- family in fixtures/test-prereqs.sql (stmt_frag / col_assign_frag / qname_frag
37
+ -- / row_lock_frag / call_re), not regexes written here, so a boundary defect
38
+ -- is fixed once and CPR-0 pins the family's behaviour (#416/#417/#424);
35
39
  -- * three acquisition shapes: INSERT into a direct FK child, an UPDATE that
36
- -- re-points the FK column, and an explicit row lock in any statement shape
37
- -- (including `from boards b join ... for update of b`, which an earlier
38
- -- `where`-anchored pattern could not see);
40
+ -- re-points the FK column (POSITIONALLY, in the SET list -- the hand regex this
41
+ -- replaced took `board_id` anywhere after SET and credited grant_board_role,
42
+ -- whose UPDATE only FILTERS by board_id, with a boards acquisition; measured
43
+ -- on migration: that route and signed_grant_board_role, which reaches it, are
44
+ -- the only two rows that changed, and neither is in EC-2's class), and an
45
+ -- explicit row lock of any strength in any statement shape (including
46
+ -- `from boards b join ... for update of b`, which an earlier `where`-anchored
47
+ -- pattern could not see);
39
48
  -- * a function pinning search_path WITHOUT agent_board (e.g.
40
49
  -- _ensure_agent_auth_user's search_path='') is not credited with bare matches;
41
50
  -- no proconfig at all is treated as bare-resolving, over-approximating
@@ -100,16 +109,7 @@ fns as (
100
109
  -- with no search_path setting at all is treated as if bare names DO resolve, which
101
110
  -- over-approximates membership rather than under-approximating it.
102
111
  sp as (
103
- select f.oid,
104
- case
105
- when not exists (select 1 from unnest(coalesce(f.proconfig, '{}')) c
106
- where c like 'search\_path=%') then true
107
- else exists (select 1 from unnest(f.proconfig) c
108
- where c like 'search\_path=%'
109
- and ',' || replace(replace(split_part(c, '=', 2), ' ', ''), '"', '') || ','
110
- like '%,agent\_board,%')
111
- end as bare_ok
112
- from fns f
112
+ select f.oid, agent_board_test.bare_ok(f.oid) as bare_ok from fns f
113
113
  ),
114
114
  -- DIRECT FK children only: inserting into a grandchild locks the child row, not
115
115
  -- the grandparent, so transitive FK depth would manufacture false positives.
@@ -125,41 +125,60 @@ kids as (
125
125
  and c.confrelid in ('agent_board.boards'::regclass, 'auth.users'::regclass)
126
126
  and ns.nspname = 'agent_board'
127
127
  ),
128
- alt as (
129
- select (select string_agg(distinct tbl, '|') from kids
130
- where parent_oid = 'agent_board.boards'::regclass) as board_kids,
131
- (select string_agg(distinct tbl, '|') from kids
132
- where parent_oid = 'auth.users'::regclass) as owner_kids
133
- ),
128
+ -- The three acquisition shapes, composed from the shared matcher family
129
+ -- (test-prereqs) and wrapped ONCE in re() per subject. Per function, because the
130
+ -- bare-name arm depends on that function's search_path.
131
+ -- (i) INSERT into a direct FK child takes FOR KEY SHARE on the parent row
132
+ -- -- stmt_frag('insert into', kid, bare_ok);
133
+ -- (ii) an UPDATE that RE-POINTS the FK column re-checks it and locks the new
134
+ -- parent -- col_assign_frag(kid, fkcol, bare_ok), which is POSITIONAL:
135
+ -- the column must sit in the SET list. The hand form this replaced
136
+ -- accepted `board_id` anywhere after SET, including the WHERE clause, so
137
+ -- an UPDATE that merely FILTERS by board_id was counted as an acquisition;
138
+ -- (iii) an explicit row lock in ANY statement shape, deliberately not anchored
139
+ -- on `where`: `from boards b join ... for update of b` is a real
140
+ -- acquisition and the anchored form could not see it -- qname_frag ||
141
+ -- same_stmt() || row_lock_frag(), every lock strength (the hand owner arm
142
+ -- accepted only `for update`; a `for no key update` on auth.users is the
143
+ -- same acquisition and now counts).
134
144
  pat as (
135
- select f.oid, s.bare_ok,
136
- case when s.bare_ok then '(?:agent_board\.)?' else 'agent_board\.' end as q
137
- from fns f join sp s on s.oid = f.oid
145
+ select s.oid,
146
+ agent_board_test.re(
147
+ (select string_agg(agent_board_test.stmt_frag('insert into', k.tbl, s.bare_ok), '|')
148
+ from kids k where k.parent_oid = 'agent_board.boards'::regclass)
149
+ || '|' || (select string_agg(agent_board_test.col_assign_frag(k.tbl, 'board_id', s.bare_ok), '|')
150
+ from kids k where k.parent_oid = 'agent_board.boards'::regclass)
151
+ || '|' || agent_board_test.qname_frag('boards', s.bare_ok) || agent_board_test.same_stmt()
152
+ || agent_board_test.row_lock_frag()
153
+ ) as board_re,
154
+ agent_board_test.re(
155
+ (select string_agg(agent_board_test.stmt_frag('insert into', k.tbl, s.bare_ok), '|')
156
+ from kids k where k.parent_oid = 'auth.users'::regclass)
157
+ || '|' || (select string_agg(agent_board_test.col_assign_frag(k.tbl, 'owner_user_id', s.bare_ok)
158
+ || '|' || agent_board_test.col_assign_frag(k.tbl, 'auth_user_id', s.bare_ok), '|')
159
+ from kids k where k.parent_oid = 'auth.users'::regclass)
160
+ || '|' || agent_board_test.qname_frag('auth.users', false) || agent_board_test.same_stmt()
161
+ || agent_board_test.row_lock_frag()
162
+ ) as owner_re
163
+ from sp s
138
164
  ),
165
+ -- The hit is the matched TEXT (an acquisition is present); its position is the
166
+ -- match's own offset (regexp_instr), not the first occurrence of that text.
139
167
  own as (
140
- select f.oid, f.proname, f.sig, f.body, p.bare_ok, p.q,
141
- substring(f.body from
142
- -- (i) INSERT into a direct FK child takes FOR KEY SHARE on the parent row
143
- '(?:insert\s+into\s+(?:only\s+)?' || p.q || '\m(?:' || a.board_kids || ')\M)'
144
- -- (ii) UPDATE that re-points the FK column re-checks it and locks the new parent
145
- || '|(?:update\s+(?:only\s+)?' || p.q || '\m(?:' || a.board_kids || ')\M[^;]{0,250}?\mset\M[^;]{0,250}?\mboard_id\M\s*=)'
146
- -- (iii) an explicit row lock in ANY statement shape. Deliberately not
147
- -- anchored on `where`: `from boards b join ... for update of b` is a real
148
- -- acquisition and the anchored form could not see it.
149
- || '|(?:' || p.q || '\mboards\M[^;]{0,250}?for\s+(?:update|no\s+key\s+update|share|key\s+share))'
150
- ) as board_hit,
151
- substring(f.body from
152
- '(?:insert\s+into\s+(?:only\s+)?' || p.q || '\m(?:' || a.owner_kids || ')\M)'
153
- || '|(?:update\s+(?:only\s+)?' || p.q || '\m(?:' || a.owner_kids || ')\M[^;]{0,250}?\mset\M[^;]{0,250}?\m(?:owner_user_id|auth_user_id)\M\s*=)'
154
- || '|(?:auth\.users\M[^;]{0,250}?for\s+update)'
155
- ) as owner_hit
156
- from fns f join pat p on p.oid = f.oid cross join alt a
168
+ select f.oid, f.proname, f.sig, f.body, s.bare_ok,
169
+ substring(f.body from p.board_re) as board_hit,
170
+ substring(f.body from p.owner_re) as owner_hit,
171
+ nullif(regexp_instr(f.body, p.board_re), 0) as board_at,
172
+ nullif(regexp_instr(f.body, p.owner_re), 0) as owner_at
173
+ from fns f join sp s on s.oid = f.oid join pat p on p.oid = f.oid
157
174
  ),
175
+ -- A call edge is the callee's name in CALL position, schema-resolved the way the
176
+ -- caller's search_path resolves it (call_re: a `other.callee(` is NOT an edge).
158
177
  edges as (
159
178
  select c.oid as caller, e.oid as callee
160
179
  from own c
161
180
  join fns e on e.oid <> c.oid
162
- where c.body ~ (c.q || '\m' || e.proname || '\M\s*\(')
181
+ where c.body ~ agent_board_test.call_re(e.proname, c.bare_ok)
163
182
  ),
164
183
  acq_board(oid) as (
165
184
  select oid from own where board_hit is not null
@@ -176,22 +195,20 @@ select o.sig,
176
195
  (o.oid in (select oid from acq_owner)) as reaches_owner,
177
196
  (o.board_hit is not null) as own_board_lock,
178
197
  (o.owner_hit is not null) as own_owner_lock,
179
- (o.body ~* '\mexecute\M') as uses_dynamic_sql,
198
+ (o.body ~ agent_board_test.re('\m' || agent_board_test.ci_re('execute') || '\M')) as uses_dynamic_sql,
180
199
  least(
181
- case when o.board_hit is null then 2147483647 else strpos(o.body, o.board_hit) end,
182
- coalesce((select min(strpos(o.body, substring(o.body from o.q || '\m' || f2.proname || '\M\s*\(')))
200
+ coalesce(o.board_at, 2147483647),
201
+ coalesce((select min(nullif(regexp_instr(o.body, agent_board_test.call_re(f2.proname, o.bare_ok)), 0))
183
202
  from fns f2
184
203
  where f2.oid <> o.oid
185
- and f2.oid in (select oid from acq_board)
186
- and o.body ~ (o.q || '\m' || f2.proname || '\M\s*\(')), 2147483647)
204
+ and f2.oid in (select oid from acq_board)), 2147483647)
187
205
  ) as board_pos,
188
206
  least(
189
- case when o.owner_hit is null then 2147483647 else strpos(o.body, o.owner_hit) end,
190
- coalesce((select min(strpos(o.body, substring(o.body from o.q || '\m' || f2.proname || '\M\s*\(')))
207
+ coalesce(o.owner_at, 2147483647),
208
+ coalesce((select min(nullif(regexp_instr(o.body, agent_board_test.call_re(f2.proname, o.bare_ok)), 0))
191
209
  from fns f2
192
210
  where f2.oid <> o.oid
193
- and f2.oid in (select oid from acq_owner)
194
- and o.body ~ (o.q || '\m' || f2.proname || '\M\s*\(')), 2147483647)
211
+ and f2.oid in (select oid from acq_owner)), 2147483647)
195
212
  ) as owner_pos
196
213
  from own o;
197
214
 
@@ -352,7 +352,9 @@ begin
352
352
  end $$;
353
353
  -- 36
354
354
  select ok(
355
- pg_get_functiondef('agent_board.enroll_federated_human(text,text,text,jsonb,text)'::regprocedure)
355
+ -- literals kept: none of the pinned fragments is a string, but a raise message between two
356
+ -- of them is part of the ORDER this pins, and the strip must not splice around it
357
+ agent_board_test.stripped_body('agent_board.enroll_federated_human(text,text,text,jsonb,text)'::regprocedure, true)
356
358
  like '%from agent_board.boards b%for update%from agent_board.identity_providers ip%for update%_ensure_agent_auth_user(v_handle)%from auth.users u where u.id = v_uid for update%fleet_human_revocations r%r.issuer = p_issuer%r.subject = p_subject%_enroll_federated_human_after_revocation_gate%',
357
359
  '/portal-session locks default board then provider then owner and checks the durable marker before delegation');
358
360
  -- 37
@@ -66,10 +66,15 @@ select is(
66
66
  else 'gate-after-owner'
67
67
  end
68
68
  from (
69
- select coalesce(strpos(d, substring(d from
70
- $g$raise\s+exception\s+'issuer/audience not in the identity-provider allowlist \(rejected before any owner or board lock\)'$g$)), 0) as p_gate,
71
- strpos(d, '_ensure_agent_auth_user') as p_ensure,
72
- strpos(d, substring(d from 'from\s+auth\.users[^;]{0,250}?for\s+update')) as p_lock
69
+ -- Positions are the match's own offset (regexp_instr: 0 when absent), not the
70
+ -- first occurrence of the matched text.
71
+ select regexp_instr(d,
72
+ agent_board_test.re('\m' || agent_board_test.ci_re('raise exception')
73
+ || '\s+''issuer/audience not in the identity-provider allowlist \(rejected before any owner or board lock\)''')) as p_gate,
74
+ regexp_instr(d, agent_board_test.call_re('_ensure_agent_auth_user')) as p_ensure,
75
+ -- the auth.users read and any row lock (FOR UPDATE / NO KEY UPDATE / SHARE / KEY
76
+ -- SHARE) in the same statement; the old hand form knew only `for update`
77
+ nullif(regexp_instr(d, agent_board_test.re(agent_board_test.stmt_frag('from', 'auth.users', false) || agent_board_test.same_stmt() || agent_board_test.row_lock_frag())), 0) as p_lock
73
78
  -- LITERALS KEPT (the `true`): the gate marker G-2 locates IS the raise
74
79
  -- message, so stripping literals would delete it and the positional claim
75
80
  -- would read 'gate-missing' forever. Comments -- including the NESTED
@@ -78,7 +78,11 @@ select p.oid, p.proname, agent_board_test.stripped_body(p.oid, true) as body
78
78
  where n.nspname = 'agent_board'
79
79
  and p.prokind in ('f', 'p')
80
80
  and agent_board_test.stripped_body(p.oid, true) like '%\_federated\_identity\_slug(%'
81
- and agent_board_test.stripped_body(p.oid, true) ~ 'agent_board\.agents[^;]*auth_user_id\s*=';
81
+ -- a read of agents on auth_user_id, in one statement: the relation (qualified as the
82
+ -- function's search_path allows) then the column, qualified or bare, then `=`
83
+ and agent_board_test.stripped_body(p.oid, true)
84
+ ~ agent_board_test.re(agent_board_test.qname_frag('agents', agent_board_test.bare_ok(p.oid)) || agent_board_test.same_stmt()
85
+ || agent_board_test.col_ref_frag('auth_user_id') || '\s*=');
82
86
 
83
87
  -- 1 -- the class is NOT EMPTY. A class scan that finds nothing passes every
84
88
  -- "every member has X" assertion vacuously; this is the assertion that stops that.
@@ -113,9 +117,9 @@ select is((select string_agg(proname, ',' order by proname) from _c246),
113
117
  -- `have:` line instead of killing the run.
114
118
  create temp view _c246parts as
115
119
  select proname,
116
- (regexp_split_to_array(body, 'exception\s+when\s+unique_violation'))[1] as pre_handler,
117
- (regexp_split_to_array(body, 'exception\s+when\s+unique_violation'))[2] as in_handler,
118
- array_length(regexp_split_to_array(body, 'exception\s+when\s+unique_violation'), 1) as parts
120
+ (regexp_split_to_array(body, agent_board_test.re('\m' || agent_board_test.ci_re('exception when unique_violation') || '\M')))[1] as pre_handler,
121
+ (regexp_split_to_array(body, agent_board_test.re('\m' || agent_board_test.ci_re('exception when unique_violation') || '\M')))[2] as in_handler,
122
+ array_length(regexp_split_to_array(body, agent_board_test.re('\m' || agent_board_test.ci_re('exception when unique_violation') || '\M')), 1) as parts
119
123
  from _c246;
120
124
 
121
125
  -- 3 -- the split boundary is UNAMBIGUOUS for every member. With a second `exception
@@ -129,7 +133,11 @@ select is(
129
133
  -- 4 -- SITE (7a): the idempotent branch, everything before the handler.
130
134
  select is(
131
135
  (select string_agg(proname, ',' order by proname) from _c246parts
132
- where pre_handler ~ 'coalesce\(\s*v_existing\.metadata\s*#>>\s*''\{federation,issuer\}''\s*=\s*p_issuer\s+and\s+v_existing\.metadata\s*#>>\s*''\{federation,subject\}''\s*=\s*p_subject\s*,\s*false\s*\)'),
136
+ where pre_handler ~ agent_board_test.re(agent_board_test.call_frag('pg_catalog.coalesce', true) || '\s*'
137
+ || agent_board_test.ident_re('v_existing') || '\s*\.\s*' || agent_board_test.ident_re('metadata') || '\s*#>>\s*''\{federation,issuer\}''\s*=\s*' || agent_board_test.ident_re('p_issuer')
138
+ || '\s+' || agent_board_test.ci_re('and') || '\s+'
139
+ || agent_board_test.ident_re('v_existing') || '\s*\.\s*' || agent_board_test.ident_re('metadata') || '\s*#>>\s*''\{federation,subject\}''\s*=\s*' || agent_board_test.ident_re('p_subject')
140
+ || '\s*,\s*' || agent_board_test.ci_re('false') || '\s*\)')),
133
141
  (select string_agg(proname, ',' order by proname) from _c246),
134
142
  'every class member carries the gate at return site (7a) -- the idempotent branch, BEFORE the unique_violation handler');
135
143
 
@@ -138,7 +146,11 @@ select is(
138
146
  -- so this assertion is the ONLY thing standing between it and being ungated.
139
147
  select is(
140
148
  (select string_agg(proname, ',' order by proname) from _c246parts
141
- where in_handler ~ 'coalesce\(\s*v_existing\.metadata\s*#>>\s*''\{federation,issuer\}''\s*=\s*p_issuer\s+and\s+v_existing\.metadata\s*#>>\s*''\{federation,subject\}''\s*=\s*p_subject\s*,\s*false\s*\)'),
149
+ where in_handler ~ agent_board_test.re(agent_board_test.call_frag('pg_catalog.coalesce', true) || '\s*'
150
+ || agent_board_test.ident_re('v_existing') || '\s*\.\s*' || agent_board_test.ident_re('metadata') || '\s*#>>\s*''\{federation,issuer\}''\s*=\s*' || agent_board_test.ident_re('p_issuer')
151
+ || '\s+' || agent_board_test.ci_re('and') || '\s+'
152
+ || agent_board_test.ident_re('v_existing') || '\s*\.\s*' || agent_board_test.ident_re('metadata') || '\s*#>>\s*''\{federation,subject\}''\s*=\s*' || agent_board_test.ident_re('p_subject')
153
+ || '\s*,\s*' || agent_board_test.ci_re('false') || '\s*\)')),
142
154
  (select string_agg(proname, ',' order by proname) from _c246),
143
155
  'every class member carries the gate at return site (8a) -- INSIDE the unique_violation race handler');
144
156
 
@@ -40,7 +40,7 @@ set search_path = extensions, public, agent_board;
40
40
 
41
41
  begin;
42
42
 
43
- select plan(16);
43
+ select plan(18);
44
44
 
45
45
  -- ---------------------------------------------------------------------------
46
46
  -- The derivation, materialized once. `first_path` is the position PATH of the
@@ -176,7 +176,7 @@ select is(
176
176
  select is(
177
177
  (select coalesce(string_agg(distinct e.fn_name, ', ' order by e.fn_name), '')
178
178
  from _le e join pg_proc p on p.oid = e.fn_oid
179
- where agent_board_test.stripped_body(p.oid) ~* '\mexecute\M'),
179
+ where agent_board_test.stripped_body(p.oid) ~ agent_board_test.re('\m' || agent_board_test.ci_re('execute') || '\M')),
180
180
  '',
181
181
  'FKL-7: no function with a lock edge uses dynamic SQL, which the position analysis cannot read');
182
182
 
@@ -200,6 +200,16 @@ select is(
200
200
  -- and disagree with each other about the order. #281 stops here deliberately:
201
201
  -- the ordering fix is a separate decision. Do not "green" this by editing the
202
202
  -- expectation -- a changed member means the lock graph changed.
203
+ --
204
+ -- ONE MEMBER HAS BEEN REMOVED since, and the lock graph did not change -- the detector
205
+ -- did (#416/#417/#424 PR 1). `unsubscribe_callback_endpoint` was listed on the strength
206
+ -- of three `fk-update` edges the old shape-(v) regex fabricated: its only UPDATE is
207
+ -- `update callback_subscriptions cs set subscription_status = ... where cs.endpoint_id =`,
208
+ -- and the old `set[^;]{0,250}?<col>\s*=` crossed from SET into WHERE and read the
209
+ -- predicate as an FK re-point. lock_edges() now bounds the assignment scan at
210
+ -- WHERE/FROM/RETURNING (col_assign_frag), so the function has no agents edge at all.
211
+ -- Read the function before believing this comment: the WHERE is on line 15 of its
212
+ -- stripped body.
203
213
  -- ===========================================================================
204
214
  select is(
205
215
  (select array_agg(m order by m) from (
@@ -239,7 +249,6 @@ select is(
239
249
  'signed_send_direct_message: agents(key share) then memberships(key share) [unserialised]',
240
250
  'signed_send_multicast_message: agents(key share) then memberships(key share) [unserialised]',
241
251
  'subscribe_callback_endpoint: memberships(key share) then agents(key share) [unserialised]',
242
- 'unsubscribe_callback_endpoint: memberships(key share) then agents(key share) [unserialised]',
243
252
  'update_board_membership: memberships(update) then agents(key share) [unserialised]'
244
253
  ]::text[],
245
254
  'FKL-9: the agents+board_memberships lock class, FK edges included (section 9''s text scan sees 3 of these)');
@@ -278,6 +287,19 @@ select is(
278
287
  -- * tests/isolation/specs/challenge_supersede_lock_order.spec proves the absence of
279
288
  -- the wait across two real sessions -- removing the clause turns its golden from a
280
289
  -- clean completion into `<waiting ...>` and then a deadlock.
290
+ --
291
+ -- ONE PAIR HAS BEEN REMOVED BY A DETECTOR FIX, not by an ordering change (#416/#417/#424
292
+ -- PR 1). `agents <-> delegation_grants` rested on `fk-update` edges fabricated from
293
+ -- `update delegation_grants set ... where child_agent_id = ...` in renew_delegated_grant
294
+ -- and _revoke_agent_principal: the old shape-(v) regex ran on from SET into WHERE and took
295
+ -- the predicate for an assignment. Neither function re-points the FK, so neither locks the
296
+ -- agents row through it, and the pair never existed. The same fix, plus an unbounded
297
+ -- statement span, MOVED but did not add a pair on the callback tables:
298
+ -- claim_callback_outbox_events' `for update of coe skip locked` now locks
299
+ -- callback_outbox_events (real; previously beyond the old 250-char window) and no longer
300
+ -- callback_subscriptions (fabricated; `OF coe` does not name it -- lock_edges() now reads
301
+ -- the OF list). `callback_endpoints <-> callback_outbox_events` is still reported after
302
+ -- the fix; this comment does not claim to know which routes carry it.
281
303
  -- ===========================================================================
282
304
  select is(
283
305
  (select array_agg(p order by p) from (
@@ -293,7 +315,6 @@ select is(
293
315
  'agent_board.agents <-> agent_board.board_invite_tokens',
294
316
  'agent_board.agents <-> agent_board.board_memberships',
295
317
  'agent_board.agents <-> agent_board.boards',
296
- 'agent_board.agents <-> agent_board.delegation_grants',
297
318
  'agent_board.agents <-> agent_board.fleet_machine_agents',
298
319
  'agent_board.agents <-> agent_board.fleet_machines',
299
320
  'agent_board.agents <-> agent_board.fleet_trust_domains',
@@ -334,7 +355,7 @@ select is(
334
355
  'FKL-11: the #281 ABBA is present and unserialised -- reported, NOT fixed here');
335
356
 
336
357
  -- ===========================================================================
337
- -- THE PROBES. From here on, agent_board gains four functions that exist only to
358
+ -- THE PROBES. From here on, agent_board gains six functions that exist only to
338
359
  -- exercise one acquisition shape each. They are never CALLED -- the detector
339
360
  -- reads bodies -- and the transaction is rolled back. Every exact-set assertion
340
361
  -- above has already run.
@@ -384,6 +405,30 @@ begin
384
405
  end;
385
406
  $probe$;
386
407
 
408
+ -- Shape (v)'s boundary (#416/#417/#424 PR 1): the FK column appears ONLY in the WHERE. The
409
+ -- detector that listed `unsubscribe_callback_endpoint` in FKL-9 read exactly this shape as an
410
+ -- FK re-point. The SET here names no FK column, so the probe must carry the write-update
411
+ -- edge and NOTHING through an FK.
412
+ create function agent_board._probe416_fk_where(p_agent uuid)
413
+ returns void language plpgsql as $probe$
414
+ begin
415
+ update agent_board.board_memberships set role = 'member'
416
+ where agent_id = p_agent and board_id = p_agent;
417
+ end;
418
+ $probe$;
419
+
420
+ -- Shape (i)'s OF list: `FOR UPDATE OF a` locks the aliased relation only. `boards` is named in
421
+ -- the same statement and must NOT be credited; the second statement covers the no-alias
422
+ -- spelling, where the OF list names the relation itself.
423
+ create function agent_board._probe416_lock_of(p_id uuid)
424
+ returns void language plpgsql as $probe$
425
+ begin
426
+ perform 1 from agent_board.agents a join agent_board.boards b on b.id = a.id
427
+ where a.id = p_id for update of a;
428
+ perform 1 from agent_board.identity_providers where id = p_id for update of identity_providers;
429
+ end;
430
+ $probe$;
431
+
387
432
  -- The derivation, re-evaluated ONCE now that the probes exist. (Re-evaluating it
388
433
  -- per assertion is correct but costs a full re-scan of every body each time.)
389
434
  create temp table _lep on commit drop as select * from agent_board_test.lock_edges();
@@ -437,6 +482,20 @@ select is(
437
482
  'agent_board.agents share via textual',
438
483
  'FKL-16: an explicit row lock is reported with its MODE, not as a boolean');
439
484
 
485
+ select is(
486
+ (select string_agg(distinct e.rel_name || ' ' || e.lock_mode || ' via ' || e.via, ' | '
487
+ order by e.rel_name || ' ' || e.lock_mode || ' via ' || e.via)
488
+ from _lep e where e.fn_name = '_probe416_fk_where'),
489
+ 'agent_board.board_memberships update via write-update',
490
+ 'FKL-17: an FK column in the WHERE is a predicate, not a re-point -- no fk-update edge');
491
+
492
+ select is(
493
+ (select string_agg(distinct e.rel_name || ' ' || e.lock_mode || ' via ' || e.via, ' | '
494
+ order by e.rel_name || ' ' || e.lock_mode || ' via ' || e.via)
495
+ from _lep e where e.fn_name = '_probe416_lock_of'),
496
+ 'agent_board.agents update via textual | agent_board.identity_providers update via textual',
497
+ 'FKL-18: FOR UPDATE OF locks the listed relations only -- boards, named in the same statement, gets no edge');
498
+
440
499
  select * from finish();
441
500
 
442
501
  rollback;
@@ -404,10 +404,8 @@ select is(
404
404
  join pg_namespace n on n.oid = p.pronamespace
405
405
  where n.nspname = 'agent_board'
406
406
  and p.prokind = 'f'
407
- and (
408
- pg_get_functiondef(p.oid) ~ 'insert into agent_board\.fleet_trust_domains\s*\([^)]*owner_agent_id'
409
- or pg_get_functiondef(p.oid) ~ 'update agent_board\.fleet_trust_domains[^;]*owner_agent_id\s*='
410
- )
407
+ and agent_board_test.stripped_body(p.oid, true)
408
+ ~ agent_board_test.col_write_re('fleet_trust_domains', 'owner_agent_id')
411
409
  ) writers
412
410
  ),
413
411
  'reclaim_fleet_trust_domain',
@@ -409,10 +409,8 @@ select is(
409
409
  join pg_namespace n on n.oid = p.pronamespace
410
410
  where n.nspname = 'agent_board'
411
411
  and p.prokind = 'f'
412
- and (
413
- agent_board_test.stripped_body(p.oid) ~ 'insert into agent_board\.fleet_machines\s*\([^)]*trust_domain_id'
414
- or agent_board_test.stripped_body(p.oid) ~ 'update agent_board\.fleet_machines[^;]*trust_domain_id\s*='
415
- )
412
+ and agent_board_test.stripped_body(p.oid, true)
413
+ ~ agent_board_test.col_write_re('fleet_machines', 'trust_domain_id')
416
414
  ) writers
417
415
  ),
418
416
  'reclaim_fleet_machine, register_fleet_machine',
@@ -462,7 +462,11 @@ select is(
462
462
  -- not a state reader — its exemption claim is that it advances the ledger's effective_at.
463
463
  select ok(
464
464
  (
465
- select pg_get_functiondef(p.oid) ~ 'effective_at = now\(\)'
465
+ -- the UPDATE ... SET effective_at = now() of fleet_revocation_events, as an assignment
466
+ -- to that relation's column rather than as the six characters `effective_at = now()`
467
+ select agent_board_test.stripped_body(p.oid)
468
+ ~ agent_board_test.re(agent_board_test.col_assign_frag('fleet_revocation_events', 'effective_at', agent_board_test.bare_ok(p.oid))
469
+ || '\s*' || agent_board_test.call_frag('pg_catalog.now', true) || '\s*\)')
466
470
  from pg_proc p
467
471
  join pg_namespace n on n.oid = p.pronamespace
468
472
  where n.nspname = 'agent_board'
@@ -426,10 +426,8 @@ select is(
426
426
  join pg_namespace n on n.oid = p.pronamespace
427
427
  where n.nspname = 'agent_board'
428
428
  and p.prokind = 'f'
429
- and (
430
- pg_get_functiondef(p.oid) ~ 'insert into agent_board\.fleet_machines\s*\([^)]*owner_agent_id'
431
- or pg_get_functiondef(p.oid) ~ 'update agent_board\.fleet_machines[^;]*owner_agent_id\s*='
432
- )
429
+ and agent_board_test.stripped_body(p.oid, true)
430
+ ~ agent_board_test.col_write_re('fleet_machines', 'owner_agent_id')
433
431
  ) writers
434
432
  ),
435
433
  'reclaim_fleet_machine, register_fleet_machine',