@consiliency/agent-board-schema 1.55.0 → 1.57.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.
@@ -0,0 +1,462 @@
1
+ -- MBROWID 3a as a CLASS (message-board#542): every statement that picks ONE
2
+ -- board_memberships row must prefer the active row first.
3
+ --
4
+ -- WHY THIS FILE EXISTS. MBROWID (20260803000100) ruled that a reader acting on
5
+ -- "current standing" orders
6
+ -- case when membership_state in ('joined','subscribed') then 0 else 1 end,
7
+ -- created_at desc, id desc
8
+ -- and enumerated the readers of its day in a comment. ROOMCONTRACT
9
+ -- (20261003000100) then shipped list_board_members with bare
10
+ -- `created_at desc, id desc` at BOTH its selection sites, and nothing noticed:
11
+ -- the rule lived in a comment, and agent_board_rowid.test.sql pins the id DESC
12
+ -- tiebreak, not the active-first key. This file makes the key a class property,
13
+ -- so the next reader that forgets it fails here and NAMES itself.
14
+ --
15
+ -- THE CLASS, derived from the catalog (every agent_board function body, read
16
+ -- through agent_board_test.stripped_body so a comment cannot supply or hide a
17
+ -- site). A SITE is a query that picks ONE row from a SOURCE:
18
+ -- * SOURCE `direct`: agent_board.board_memberships or the unfiltered view
19
+ -- agent_board.v_board_memberships, at the query's own parenthesis level;
20
+ -- * SOURCE `outer` (form shown as `limit(outer)` etc.): a parenthesised group
21
+ -- -- a derived table or a CTE body -- that reads either one directly or one
22
+ -- group down, with the choosing ORDER BY outside the group;
23
+ -- and the ONE-ROW forms, each followed at the same level:
24
+ -- * `limit` : ORDER BY <list> LIMIT|FETCH;
25
+ -- * `distinct`: DISTINCT ON (...) ... ORDER BY <list>;
26
+ -- * `into` : a plpgsql SELECT ... INTO with an ORDER BY and no LIMIT, which
27
+ -- silently keeps the first row.
28
+ -- The ORDER BY operands are NOT inspected: a recency order spelled through an
29
+ -- output alias or a column ordinal is in the class the same as `created_at desc`,
30
+ -- and so is a non-recency order (see _grant_within_ceiling below).
31
+ -- A site is:
32
+ -- * `active-first` when the MBROWID 3a key is the FIRST ordering item (for
33
+ -- DISTINCT ON, the first after exactly the DISTINCT ON expressions) AND a
34
+ -- COMPLETE ascending item: `case when membership_state in ('joined',
35
+ -- 'subscribed') then 0 else 1 end`, then only [ASC] [NULLS FIRST|LAST], then
36
+ -- `,` or the end of the list (see the key pattern for why);
37
+ -- * `filtered:<set>` when the key is absent but the query's own WHERE pins
38
+ -- membership_state to an explicit literal set AT ITS OWN LEVEL (a
39
+ -- `membership_state in (...)` inside a nested subquery, on any table, is
40
+ -- consumed with that subquery and never read as this query's filter). The
41
+ -- row is then chosen among rows of that set only, and the set is asserted
42
+ -- EXACTLY per exemption below;
43
+ -- * `latest-row` otherwise -- the defect.
44
+ --
45
+ -- WHAT IS ASSERTED.
46
+ -- CRC-1 the exact site population (function / form / verdict). A new site --
47
+ -- compliant or not -- changes it and appears in the diff by name, so
48
+ -- reverse membership holds, and a site that silently leaves the class
49
+ -- (a matcher that stops matching) fails too.
50
+ -- CRC-2 no site is `latest-row`; the failure lists every offender by name.
51
+ -- CRC-3 each exemption, positively: the exact function and the exact state set
52
+ -- its WHERE pins. Widening one (resolve_board_request's pending read
53
+ -- admitting 'joined', say) fails here even though the site stays
54
+ -- "filtered".
55
+ -- CRC-4 the active-first members, exactly.
56
+ -- CRC-5.. behaviour rows: the SAME pattern objects over fixture text, with the
57
+ -- REJECT rows (key after another ordering item, a key naming the wrong
58
+ -- states, a key only in a comment, a `)` inside a literal) that every
59
+ -- defective matcher passes.
60
+ --
61
+ -- WHAT THIS CANNOT SEE, stated so the green is not over-read:
62
+ -- * views as SITES. v_board_directory's current_membership lateral is
63
+ -- active-first and is pinned BEHAVIOURALLY by agent_board_rowid.test.sql; a
64
+ -- deparsed viewdef spells the key `CASE WHEN (... = ANY (ARRAY[...]))`, which
65
+ -- this matcher does not read. (A function reading v_board_memberships IS a
66
+ -- site, above.)
67
+ -- * any other view or set-returning function that exposes membership rows,
68
+ -- read by a function: only the two relation names above are sources.
69
+ -- * an `outer` source nested more than two groups deep, and nesting deeper than
70
+ -- three parenthesis levels inside one ORDER BY or WHERE.
71
+ -- * dynamic SQL (EXECUTE of an assembled string), and a choice made by
72
+ -- max()/min() or a window function instead of ORDER BY.
73
+ -- * a filter widened by an OR elsewhere in the same WHERE level: the filter
74
+ -- check reads the first `membership_state in (...)` conjunct at that level,
75
+ -- not the boolean structure around it. An `outer` site's filter is read from
76
+ -- the span AFTER the group, so a filter inside the derived table does not
77
+ -- exempt it (fails closed).
78
+ -- * the key's SEMANTICS beyond its spelling. The matcher accepts one exact
79
+ -- spelling (arms 0/1, the literal pair in that order, ascending) and rejects
80
+ -- every other; an equivalent spelling (`in ('subscribed','joined')`,
81
+ -- `then 0 else 2`, a helper function returning the rank) is reported
82
+ -- `latest-row` and fails closed rather than being judged.
83
+ -- * a key spelled inside a DOLLAR-quoted string constant within the ORDER BY
84
+ -- list. Literals are kept (see _crc_bodies), so such a constant's text would
85
+ -- satisfy the key match. A single-quoted constant cannot: its doubled quotes
86
+ -- (`(''joined''`) break the `\(\s*'joined'` match. Ordering by a string
87
+ -- constant is not a shape any reader has a reason to write; it is named here
88
+ -- because the fixture rows cover the comment arm and not this one.
89
+ -- The shapes the second review round named (a derived table or CTE with the
90
+ -- ORDER BY ... LIMIT outside it, a read through v_board_memberships, an ORDER BY
91
+ -- alias or ordinal, a filter inside a nested subquery) are detected, and pinned
92
+ -- by CRC-15..CRC-19.
93
+ --
94
+ -- HAND-COUNTED plan: CRC-1..CRC-4 + 20 behaviour rows = 24.
95
+ create extension if not exists pgtap with schema extensions;
96
+ set search_path = extensions, public, agent_board;
97
+
98
+ begin;
99
+
100
+ select plan(24);
101
+
102
+ -- The composed patterns, built ONCE from the shared matcher family and read by
103
+ -- both the catalog scan and the behaviour rows, so the rows exercise the same
104
+ -- objects the scan compiles.
105
+ -- lit : a plain string literal, consumed whole ('' escapes), so a `)` or `;`
106
+ -- inside one cannot end a span;
107
+ -- bal : a parenthesised group, literal-aware, three levels deep;
108
+ -- item : one token of the SAME parenthesis level (a group is ONE token);
109
+ -- qn : a reference to agent_board.board_memberships OR to the unfiltered
110
+ -- view agent_board.v_board_memberships (bare admitted: every
111
+ -- agent_board function that could read either bare pins agent_board
112
+ -- on its search_path, and over-admitting only ADDS sites, which fails
113
+ -- closed);
114
+ -- grp : a parenthesised group (derived table, CTE body) that references qn
115
+ -- directly or one group down -- the `outer` source, whose ORDER BY
116
+ -- sits OUTSIDE the group that reads memberships.
117
+ create temp view _crc_frag as
118
+ with base as (
119
+ select
120
+ $l$'(?:[^']|'')*'$l$ as lit,
121
+ '\m' || agent_board_test.ci_re('order by') || '\M' as orderby,
122
+ '\m(?:' || agent_board_test.ci_re('limit') || '|' || agent_board_test.ci_re('fetch') || ')\M' as limitkw,
123
+ '(?:' || agent_board_test.qname_frag('board_memberships', true)
124
+ || '|' || agent_board_test.qname_frag('v_board_memberships', true) || ')' as qn
125
+ ),
126
+ bal as (
127
+ select b.*,
128
+ '\((?:[^()'']|' || b.lit || '|\((?:[^()'']|' || b.lit
129
+ || '|\((?:[^()'']|' || b.lit || ')*\))*\))*\)' as bal
130
+ from base b
131
+ ),
132
+ it as (
133
+ select b.*, '(?:[^;()'']|' || b.lit || '|' || b.bal || ')' as item,
134
+ '(?:[^()'']|' || b.lit || '|' || b.bal || ')' as gitem
135
+ from bal b
136
+ ),
137
+ g1 as (
138
+ select i.*, '\(' || i.gitem || '*?' || i.qn || i.gitem || '*\)' as grp1
139
+ from it i
140
+ )
141
+ select
142
+ g.*,
143
+ '(?:' || g.grp1 || '|\(' || g.gitem || '*?' || g.grp1 || g.gitem || '*\))' as grp,
144
+ -- the MBROWID 3a key, literals included: its operands ARE the claim.
145
+ -- It must be a COMPLETE ASCENDING ORDER BY item, so the pattern pins three
146
+ -- things, not just the CASE text:
147
+ -- * the arms: exactly `then 0 else 1` -- `then 1 else 0` is the reversal
148
+ -- and does not match (`\s+0\s+` also refuses `0.5`, `00`, `0::int`);
149
+ -- * the CONTINUATION after END: only an optional ASC, then an optional
150
+ -- NULLS FIRST|LAST, then `,` or the END of the ORDER BY list. DESC (the
151
+ -- reversal), arithmetic (`* 0` erases the preference), a cast, COLLATE,
152
+ -- or anything else leaves the item unmatched, and the site falls through
153
+ -- to `latest-row` (fails closed). NULLS FIRST/LAST are admitted because
154
+ -- they are inert here: this CASE has an ELSE and literal arms, so it is
155
+ -- never NULL and a NULLS clause cannot reorder it;
156
+ -- * the START is checked by the classifier, not here: nothing but the
157
+ -- DISTINCT ON expressions may precede the key in the list.
158
+ agent_board_test.ci_re('case') || '\s+' || agent_board_test.ci_re('when') || '\s+'
159
+ || agent_board_test.col_ref_frag('membership_state') || '\s+' || agent_board_test.ci_re('in')
160
+ || $k$\s*\(\s*'joined'\s*,\s*'subscribed'\s*\)\s*$k$
161
+ || agent_board_test.ci_re('then') || '\s+0\s+' || agent_board_test.ci_re('else') || '\s+1\s+'
162
+ || agent_board_test.ci_re('end') || agent_board_test.trail_guard()
163
+ || '(?:\s+' || agent_board_test.ci_re('asc') || agent_board_test.trail_guard() || ')?'
164
+ || '(?:\s+' || agent_board_test.ci_re('nulls') || '\s+(?:' || agent_board_test.ci_re('first')
165
+ || '|' || agent_board_test.ci_re('last') || ')' || agent_board_test.trail_guard() || ')?'
166
+ || '\s*(?:,|$)' as key,
167
+ -- a `membership_state in ('<a>', '<b>', ...)` conjunct AT THE WHERE-SPAN'S OWN
168
+ -- LEVEL: every group before it is consumed whole, so a filter inside a nested
169
+ -- subquery (on any table) is never read as this query's filter.
170
+ '^(?:(?!' || agent_board_test.col_ref_frag('membership_state') || '\s+' || agent_board_test.ci_re('in') || '\s*\()'
171
+ || g.item || ')*' || agent_board_test.col_ref_frag('membership_state') || '\s+' || agent_board_test.ci_re('in')
172
+ || '\s*\(((?:\s*' || g.lit || '\s*,?)+)\)' as filter
173
+ from g1 g;
174
+
175
+ -- Six extraction patterns: three single-row FORMS x two SOURCES. The sources run
176
+ -- as SEPARATE patterns because a 'g' scan never returns overlapping matches: a
177
+ -- derived table with its own LIMIT inside and another outside would otherwise
178
+ -- lose one of the two sites.
179
+ -- form `limit` : <source> <where-span> ORDER BY <list> LIMIT|FETCH
180
+ -- form `distinct`: DISTINCT ON (<exprs>) ... <source> <where-span> ORDER BY <list> <end of level>
181
+ -- form `into` : SELECT ... INTO <var> ... <source> <where-span> ORDER BY <list>, no LIMIT
182
+ -- (`into` directly followed by the relation is an INSERT target)
183
+ -- Every pattern captures (1) the where-span, (2) the ORDER BY list; `distinct`
184
+ -- captures (3) the DISTINCT ON group.
185
+ create temp table _crc_re on commit drop as
186
+ with src(source, s, guard) as (
187
+ -- An OUTER match's where-span may not itself name the relation at its own
188
+ -- level: `exists (select … from memberships …) then … from memberships … order
189
+ -- by … limit 1` is the DIRECT site after the group, not a second, outer one.
190
+ select 'direct', f.qn, '' from _crc_frag f
191
+ union all
192
+ select 'outer', f.grp, '(?!' || f.qn || ')' from _crc_frag f
193
+ )
194
+ select
195
+ x.source,
196
+ agent_board_test.re(
197
+ x.s || '((?:(?!' || f.orderby || ')' || x.guard || f.item || ')*)' || f.orderby
198
+ || '((?:(?!' || f.limitkw || ')' || f.item || ')*)(?=' || f.limitkw || ')'
199
+ ) as limit_re,
200
+ agent_board_test.re(
201
+ '\m' || agent_board_test.ci_re('distinct on') || '\s*(' || f.bal || ')'
202
+ || '(?:(?!' || f.orderby || ')' || f.item || ')*?' || x.s
203
+ || '((?:(?!' || f.orderby || ')' || x.guard || f.item || ')*)' || f.orderby
204
+ || '((?:(?!' || f.limitkw || ')' || f.item || ')*)(?=\s*(?:\)|;|$))'
205
+ ) as distinct_re,
206
+ agent_board_test.re(
207
+ '\m' || agent_board_test.ci_re('into') || '\M(?!\s*' || f.qn || ')'
208
+ || '(?:(?!' || f.orderby || ')' || f.item || ')*?' || x.s
209
+ || '((?:(?!' || f.orderby || ')' || x.guard || f.item || ')*)' || f.orderby
210
+ || '((?:(?!' || f.limitkw || ')' || f.item || ')*)(?=\s*(?:\)|;|$|\m'
211
+ || agent_board_test.ci_re('for') || '\M|\m' || agent_board_test.ci_re('loop') || '\M))'
212
+ ) as into_re,
213
+ agent_board_test.re(f.key) as key_re,
214
+ agent_board_test.re(f.filter) as filter_re,
215
+ agent_board_test.re(f.lit) as lit_re
216
+ from src x cross join _crc_frag f;
217
+
218
+ -- Bodies: every live agent_board function, plus the behaviour-row fixtures, in
219
+ -- ONE relation so both go through the same extraction.
220
+ -- stripped_body(..., true) KEEPS LITERALS on purpose: the key's operands
221
+ -- 'joined'/'subscribed' and the exemption filter sets ARE the claim, and a
222
+ -- literal-stripped body would make every key and every filter read identically.
223
+ -- Comments are still removed, so prose cannot supply a key.
224
+ create temp table _crc_fixture (label text primary key, src text not null) on commit drop;
225
+ insert into _crc_fixture(label, src) values
226
+ ('latest', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by bm.created_at desc, bm.id desc limit 1$f$),
227
+ ('keyed', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end, bm.created_at desc, bm.id desc limit 1$f$),
228
+ ('key-after', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by bm.created_at desc, case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end limit 1$f$),
229
+ ('key-wrong-set', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'removed') then 0 else 1 end, bm.created_at desc limit 1$f$),
230
+ ('key-in-comment',$f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by /* case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end, */ bm.created_at desc limit 1$f$),
231
+ ('paren-literal', $f$select bm.id into v from agent_board.board_memberships bm where bm.note <> ')' and bm.board_id = p order by bm.created_at desc limit 1$f$),
232
+ ('distinct', $f$return query select * from (select distinct on (bm.agent_id) bm.* from agent_board.board_memberships bm where bm.board_id = p order by bm.agent_id, bm.created_at desc) x order by x.agent_id$f$),
233
+ ('into-nolimit', $f$select bm.role into v from agent_board.board_memberships bm where bm.board_id = p order by bm.updated_at desc$f$),
234
+ ('end-desc', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end desc, bm.created_at desc limit 1$f$),
235
+ ('end-times-zero',$f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end * 0, bm.created_at desc limit 1$f$),
236
+ ('then1-else0', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 1 else 0 end, bm.created_at desc limit 1$f$),
237
+ ('end-cast', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end::text, bm.created_at desc limit 1$f$),
238
+ ('end-asc', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end ASC nulls last, bm.created_at desc limit 1$f$),
239
+ ('filtered', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p and bm.membership_state in ('joined','subscribed') order by bm.created_at desc limit 1$f$),
240
+ ('outer-derived', $f$select x.id into v from (select bm.id, bm.created_at from agent_board.board_memberships bm where bm.board_id = p) x order by x.created_at desc limit 1$f$),
241
+ ('outer-cte', $f$return query with h as (select bm.* from agent_board.board_memberships bm where bm.board_id = p) select h.id from h order by h.created_at desc limit 1$f$),
242
+ ('view', $f$select m.board_membership_id into v from agent_board.v_board_memberships m where m.board_id = p order by m.created_at desc limit 1$f$),
243
+ ('ordinal', $f$select bm.id, bm.created_at into v, t from agent_board.board_memberships bm where bm.board_id = p order by 2 desc limit 1$f$),
244
+ ('nested-filter', $f$select bm.id into v from agent_board.board_memberships bm where bm.board_id = p and exists (select 1 from agent_board.agents o where o.id = bm.agent_id and o.membership_state in ('joined','subscribed')) order by bm.created_at desc limit 1$f$),
245
+ ('not-a-site', $f$perform 1 from agent_board.board_memberships bm where bm.board_id = p order by bm.id for update; for r in select bm.id from agent_board.board_memberships bm where bm.membership_state in ('joined', 'subscribed') order by bm.created_at loop null; end loop$f$);
246
+
247
+ create temp view _crc_bodies as
248
+ select 'catalog'::text as kind,
249
+ p.proname::text as proname,
250
+ agent_board_test.stripped_body(p.oid, true) as body
251
+ from pg_proc p
252
+ join pg_namespace n on n.oid = p.pronamespace
253
+ where n.nspname = 'agent_board'
254
+ and p.prokind = 'f'
255
+ union all
256
+ select 'fixture', x.label, agent_board_test.strip_sql(x.src, true)
257
+ from _crc_fixture x;
258
+
259
+ create temp view _crc_sites as
260
+ with raw as (
261
+ select b.kind, b.proname, 'limit'::text as form, r.source, m[1] as where_span, m[2] as order_list, null::text as don
262
+ from _crc_bodies b cross join _crc_re as r cross join lateral regexp_matches(b.body, r.limit_re, 'g') as m
263
+ union all
264
+ select b.kind, b.proname, 'distinct', r.source, m[2], m[3], m[1]
265
+ from _crc_bodies b cross join _crc_re as r cross join lateral regexp_matches(b.body, r.distinct_re, 'g') as m
266
+ union all
267
+ select b.kind, b.proname, 'into', r.source, m[1], m[2], null
268
+ from _crc_bodies b cross join _crc_re as r cross join lateral regexp_matches(b.body, r.into_re, 'g') as m
269
+ ),
270
+ cls as (
271
+ select raw.*,
272
+ nullif(regexp_instr(raw.order_list, k.key_re), 0) as key_at,
273
+ (select array_to_string(array_agg(l[1] order by ord), ',')
274
+ from regexp_matches(substring(raw.where_span from k.filter_re), k.lit_re, 'g')
275
+ with ordinality as fl(l, ord)) as filter_set
276
+ from raw join _crc_re as k on k.source = 'direct'
277
+ )
278
+ -- ACTIVE-FIRST means the key is the FIRST ordering item: nothing may precede it
279
+ -- except, for DISTINCT ON, exactly the DISTINCT ON expressions (which partition
280
+ -- and do not choose). The ordering operands are NOT inspected, so a recency order
281
+ -- spelled through an output alias or a column ordinal is judged the same way as
282
+ -- `created_at desc` -- and so is a non-recency order (a rank): any single-row
283
+ -- choice over memberships is in the class.
284
+ select kind, proname,
285
+ form || case when source = 'outer' then '(outer)' else '' end as form,
286
+ case
287
+ when key_at is not null
288
+ and (translate(substr(order_list, 1, key_at - 1), E' \t\r\n', '') = ''
289
+ or (form = 'distinct'
290
+ and translate(substr(order_list, 1, key_at - 1), E' \t\r\n', '')
291
+ = translate(substr(don, 2, length(don) - 2), E' \t\r\n', '') || ','))
292
+ then 'active-first'
293
+ when filter_set is not null then 'filtered:' || filter_set
294
+ else 'latest-row'
295
+ end as verdict
296
+ from cls;
297
+
298
+ -- ---------------------------------------------------------------------------
299
+ -- CRC-1: the exact population, derived from the catalog.
300
+ -- ---------------------------------------------------------------------------
301
+ select is(
302
+ (select array_agg(proname || '/' || form || '/' || verdict order by proname, form, verdict)
303
+ from _crc_sites where kind = 'catalog'),
304
+ array[
305
+ '_active_board_membership_id/limit/filtered:''joined'',''subscribed''',
306
+ '_grant_within_ceiling/limit/filtered:''joined'',''subscribed''',
307
+ '_upsert_board_membership_state/limit/active-first',
308
+ 'join_board/limit/active-first',
309
+ 'list_board_members/distinct/active-first',
310
+ 'list_board_members/limit/active-first',
311
+ 'list_board_pending_memberships/distinct/active-first',
312
+ 'list_my_board_requests/limit/active-first',
313
+ 'request_join_board/limit/filtered:''joined'',''subscribed''',
314
+ 'resolve_board_request/limit/filtered:''joined'',''subscribed''',
315
+ 'resolve_board_request/limit/filtered:''requested'',''invited''',
316
+ 'update_board_membership/limit/active-first',
317
+ 'update_board_membership/limit/active-first'
318
+ ]::text[],
319
+ 'CRC-1: every catalog statement choosing ONE board_memberships row is exactly this set');
320
+
321
+ -- ---------------------------------------------------------------------------
322
+ -- CRC-2: no site chooses the bare latest row.
323
+ -- ---------------------------------------------------------------------------
324
+ select is(
325
+ (select coalesce(array_agg(proname || '/' || form order by proname, form), '{}'::text[])
326
+ from _crc_sites where kind = 'catalog' and verdict = 'latest-row'),
327
+ '{}'::text[],
328
+ 'CRC-2: no function chooses one board membership row without the MBROWID 3a key or an exact filter');
329
+
330
+ -- ---------------------------------------------------------------------------
331
+ -- CRC-3: each exemption's claim, positively -- the function and the EXACT set
332
+ -- its WHERE pins. Why each is legitimately not active-first:
333
+ -- _active_board_membership_id -- returns the ACTIVE row's id; the WHERE already
334
+ -- restricts to joined/subscribed, and the partial unique index allows at most
335
+ -- one such row, so there is nothing for the key to prefer (MBROWID 3c).
336
+ -- request_join_board -- the same: its idempotent return reads the
337
+ -- caller's existing ACTIVE row only.
338
+ -- resolve_board_request (active) -- the approval path's "already active" probe.
339
+ -- _grant_within_ceiling -- orders by ROLE RANK, not recency: it takes the
340
+ -- grantor's highest active role, among active rows only. With one active row
341
+ -- per (board, agent) the order is moot; it is in the class because the class
342
+ -- no longer requires a recency operand (an alias or ordinal would hide one).
343
+ -- resolve_board_request (pending) -- MBROWID 3c: the approval gate must see the
344
+ -- newest requested/invited marker, NOT prefer a coexisting active row; the
345
+ -- active case is handled by the probe above.
346
+ -- ---------------------------------------------------------------------------
347
+ select is(
348
+ (select array_agg(proname || '=' || substr(verdict, length('filtered:') + 1) order by proname, verdict)
349
+ from _crc_sites where kind = 'catalog' and verdict like 'filtered:%'),
350
+ array[
351
+ '_active_board_membership_id=''joined'',''subscribed''',
352
+ '_grant_within_ceiling=''joined'',''subscribed''',
353
+ 'request_join_board=''joined'',''subscribed''',
354
+ 'resolve_board_request=''joined'',''subscribed''',
355
+ 'resolve_board_request=''requested'',''invited'''
356
+ ]::text[],
357
+ 'CRC-3: the five filtered exemptions pin exactly these membership_state sets');
358
+
359
+ -- ---------------------------------------------------------------------------
360
+ -- CRC-4: the active-first members, exactly.
361
+ -- ---------------------------------------------------------------------------
362
+ select is(
363
+ (select array_agg(proname || '/' || form order by proname, form)
364
+ from _crc_sites where kind = 'catalog' and verdict = 'active-first'),
365
+ array[
366
+ '_upsert_board_membership_state/limit',
367
+ 'join_board/limit',
368
+ 'list_board_members/distinct',
369
+ 'list_board_members/limit',
370
+ 'list_board_pending_memberships/distinct',
371
+ 'list_my_board_requests/limit',
372
+ 'update_board_membership/limit',
373
+ 'update_board_membership/limit'
374
+ ]::text[],
375
+ 'CRC-4: these eight sites carry the MBROWID 3a active-first key');
376
+
377
+ -- ---------------------------------------------------------------------------
378
+ -- CRC-5..14: behaviour rows over fixture text, through the same objects.
379
+ -- ---------------------------------------------------------------------------
380
+ select is(
381
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'latest'),
382
+ array['limit/latest-row']::text[],
383
+ 'CRC-5 REJECT: bare created_at desc, id desc + LIMIT is latest-row');
384
+ select is(
385
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'keyed'),
386
+ array['limit/active-first']::text[],
387
+ 'CRC-6 ACCEPT: the MBROWID 3a key before the recency operands is active-first');
388
+ select is(
389
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'key-after'),
390
+ array['limit/latest-row']::text[],
391
+ 'CRC-7 REJECT: the key AFTER a recency operand does not make the choice active-first');
392
+ select is(
393
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'key-wrong-set'),
394
+ array['limit/latest-row']::text[],
395
+ 'CRC-8 REJECT: a key preferring (joined, removed) is not the active-first key');
396
+ select is(
397
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'key-in-comment'),
398
+ array['limit/latest-row']::text[],
399
+ 'CRC-9 REJECT: a key written only in a comment is stripped and does not count');
400
+ select is(
401
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'paren-literal'),
402
+ array['limit/latest-row']::text[],
403
+ 'CRC-10 REJECT: a `)` inside a string literal in the WHERE does not hide the site');
404
+ select is(
405
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'distinct'),
406
+ array['distinct/latest-row']::text[],
407
+ 'CRC-11 REJECT: a DISTINCT ON per-agent choice by bare recency is latest-row (and the outer order is not a site)');
408
+ select is(
409
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'into-nolimit'),
410
+ array['into/latest-row']::text[],
411
+ 'CRC-12 REJECT: SELECT ... INTO ordered by updated_at desc with no LIMIT keeps the first row, and is a site');
412
+ select is(
413
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'filtered'),
414
+ array['limit/filtered:''joined'',''subscribed''']::text[],
415
+ 'CRC-13 ACCEPT-AS-EXEMPTION: a WHERE pinning membership_state reports its exact set');
416
+ select is(
417
+ (select count(*)::int from _crc_sites where kind = 'fixture' and proname = 'not-a-site'),
418
+ 0,
419
+ 'CRC-14: a lock-ordering PERFORM and an unbounded ascending iteration choose no row and are not sites');
420
+ select is(
421
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'outer-derived'),
422
+ array['limit(outer)/latest-row']::text[],
423
+ 'CRC-15 REJECT: a derived table read by an OUTER order by recency + LIMIT is a site');
424
+ select is(
425
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'outer-cte'),
426
+ array['limit(outer)/latest-row']::text[],
427
+ 'CRC-16 REJECT: a CTE over memberships chosen by the outer ORDER BY ... LIMIT is a site');
428
+ select is(
429
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'view'),
430
+ array['limit/latest-row']::text[],
431
+ 'CRC-17 REJECT: a latest-row read through the unfiltered view v_board_memberships is a site');
432
+ select is(
433
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'ordinal'),
434
+ array['limit/latest-row']::text[],
435
+ 'CRC-18 REJECT: ORDER BY a column ordinal (or an alias) is a site; the operand is not inspected');
436
+ select is(
437
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'nested-filter'),
438
+ array['limit/latest-row']::text[],
439
+ 'CRC-19 REJECT: a membership_state filter inside a nested subquery is not this query''s filter');
440
+ select is(
441
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'end-desc'),
442
+ array['limit/latest-row']::text[],
443
+ 'CRC-20 REJECT: `... END DESC` is inactive-first -- the exact reversal -- not the key');
444
+ select is(
445
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'end-times-zero'),
446
+ array['limit/latest-row']::text[],
447
+ 'CRC-21 REJECT: `... END * 0` erases the preference and is not the key');
448
+ select is(
449
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'then1-else0'),
450
+ array['limit/latest-row']::text[],
451
+ 'CRC-22 REJECT: `THEN 1 ELSE 0` is the reversal and is not the key');
452
+ select is(
453
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'end-cast'),
454
+ array['limit/latest-row']::text[],
455
+ 'CRC-23 REJECT: `... END::text` (a cast continuation) is not the key');
456
+ select is(
457
+ (select array_agg(form || '/' || verdict) from _crc_sites where kind = 'fixture' and proname = 'end-asc'),
458
+ array['limit/active-first']::text[],
459
+ 'CRC-24 ACCEPT: `... END ASC NULLS LAST` is the key (ASC is the default; NULLS is inert on a non-null CASE)');
460
+
461
+ select * from finish();
462
+ rollback;