@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.
@@ -612,6 +612,14 @@
612
612
  {
613
613
  "id": "20261005000100_agent_board_enroll_token_single_use",
614
614
  "sha256": "317d7b41432b36a2e38cc64940838e173e425014e3e256a96d832202b250e82d"
615
+ },
616
+ {
617
+ "id": "20261006000100_agent_board_room_roster_active_first",
618
+ "sha256": "637480feeca07dbb2fe7a4624dc6d063d0c1f23e6ea3c3ee9a946ad43de4e34e"
619
+ },
620
+ {
621
+ "id": "20261007000100_agent_board_onboard_requests",
622
+ "sha256": "fbdbecfb1c78e2d1b16b37845a74082dcdf1241c61c0356b992e1e01baddc41c"
615
623
  }
616
624
  ]
617
625
  }
@@ -0,0 +1,118 @@
1
+ -- ROOMCONTRACT-ACTIVEFIRST (message-board#542): the owner/admin roster chooses current
2
+ -- standing ACTIVE-FIRST, as every other acting membership reader does (MBROWID 3a).
3
+ --
4
+ -- THE DEFECT. 20261003000100 chose the caller's standing (authorization) and each
5
+ -- member's inclusion (projection) from the LATEST board_memberships row alone:
6
+ -- `order by created_at desc, id desc`. The active-membership unique index is PARTIAL
7
+ -- (idx_agent_board_board_memberships_active_unique, WHERE membership_state in
8
+ -- ('joined','subscribed')), so one active row can coexist with newer non-active rows
9
+ -- (removed / left / requested / invited). MBROWID 3a (20260803000100) ruled that every
10
+ -- reader acting on "current standing" prefers the active row when one exists; join_board,
11
+ -- update_board_membership, _upsert_board_membership_state and
12
+ -- list_board_pending_memberships all do. The roster did not, so an active owner or admin
13
+ -- with a newer non-active row was refused with 42501 and omitted from every roster —
14
+ -- while the rest of MB (and Portal's self view, which reduces active-first as MBROWID
15
+ -- requires) treated them as active.
16
+ --
17
+ -- THE FIX. Both selection sites take the MBROWID 3a key, then the existing total order:
18
+ -- order by case when membership_state in ('joined','subscribed') then 0 else 1 end,
19
+ -- created_at desc, id desc
20
+ -- Everything else is unchanged: signature, projection, STABLE, SECURITY DEFINER,
21
+ -- search_path, the 42501 message, the result order, and the grants.
22
+ --
23
+ -- The class this belongs to is pinned from the catalog, not from this list:
24
+ -- tests/agent_board_membership_current_row_class.test.sql derives every statement that
25
+ -- picks ONE board_memberships row by recency and requires the active-first key, or a
26
+ -- named exemption whose filter it asserts exactly. This migration fixes the only two
27
+ -- sites that class found without the key; the exemptions are recorded there.
28
+ --
29
+ -- CREATE OR REPLACE keeps the ACL and the COMMENT, but both are restated below anyway:
30
+ -- the COMMENT's text described latest-row semantics and must change, and the grants are
31
+ -- restated so this file alone says what the function's posture is.
32
+
33
+ create or replace function agent_board.list_board_members(p_board_id uuid)
34
+ returns table(
35
+ membership_id uuid,
36
+ board_id uuid,
37
+ agent_id uuid,
38
+ handle text,
39
+ display_name text,
40
+ agent_type text,
41
+ membership_state text,
42
+ role text,
43
+ created_by_agent_id uuid,
44
+ membership_created_at timestamptz,
45
+ membership_updated_at timestamptz
46
+ )
47
+ language plpgsql
48
+ stable
49
+ security definer
50
+ set search_path = agent_board, public
51
+ as $$
52
+ declare
53
+ v_actor uuid := agent_board.current_agent_id();
54
+ begin
55
+ -- Authorization precedes disclosure. Creator identity is deliberately absent:
56
+ -- only the caller's current membership row can establish authority, and the
57
+ -- current row is the ACTIVE one when one exists (MBROWID 3a), else the latest.
58
+ if v_actor is null
59
+ or not exists (
60
+ select 1
61
+ from (
62
+ select bm.membership_state, bm.role
63
+ from agent_board.board_memberships bm
64
+ where bm.board_id = p_board_id
65
+ and bm.agent_id = v_actor
66
+ order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end,
67
+ bm.created_at desc, bm.id desc
68
+ limit 1
69
+ ) actor_standing
70
+ where actor_standing.membership_state in ('joined', 'subscribed')
71
+ and actor_standing.role in ('owner', 'admin')
72
+ ) then
73
+ raise exception 'only a board owner or admin may list board members'
74
+ using errcode = '42501';
75
+ end if;
76
+
77
+ -- Choose exactly one current row per agent (active-first, MBROWID 3a), then
78
+ -- keep only agents whose current row is active.
79
+ return query
80
+ select
81
+ latest.id,
82
+ latest.board_id,
83
+ latest.agent_id,
84
+ a.handle,
85
+ a.display_name,
86
+ a.agent_type,
87
+ latest.membership_state,
88
+ latest.role,
89
+ latest.created_by_agent_id,
90
+ latest.created_at,
91
+ latest.updated_at
92
+ from (
93
+ select distinct on (bm.agent_id) bm.*
94
+ from agent_board.board_memberships bm
95
+ where bm.board_id = p_board_id
96
+ order by bm.agent_id,
97
+ case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end,
98
+ bm.created_at desc, bm.id desc
99
+ ) latest
100
+ join agent_board.agents a on a.id = latest.agent_id
101
+ where latest.membership_state in ('joined', 'subscribed')
102
+ order by
103
+ case latest.role
104
+ when 'owner' then 0
105
+ when 'admin' then 1
106
+ when 'member' then 2
107
+ when 'observer' then 3
108
+ end,
109
+ lower(a.handle),
110
+ latest.agent_id;
111
+ end;
112
+ $$;
113
+
114
+ comment on function agent_board.list_board_members(uuid) is
115
+ 'Owner/admin-gated active board roster. Fails 42501 for a null actor (including service_role through this user-facing path), creator without current standing, or any caller whose current board membership is not active owner/admin. The current row is chosen active-first (MBROWID 3a): case when membership_state in (joined, subscribed) then 0 else 1 end, created_at desc, id desc — so an active row outranks a newer removed/left/requested/invited row. Returns each agent''s current row only when joined/subscribed, ordered owner/admin/member/observer then lower(handle), agent_id. Board-scoped and metadata-free.';
116
+
117
+ revoke all on function agent_board.list_board_members(uuid) from public, anon;
118
+ grant execute on function agent_board.list_board_members(uuid) to authenticated, service_role;
@@ -0,0 +1,139 @@
1
+ -- ONBOARD (v11) SL-2: the caller's own join requests (IF-0-ONBOARD-4) and a service-side
2
+ -- invite label lookup for the consent page (IF-0-ONBOARD-11). Additive: two new read-only
3
+ -- functions and one index. schema_version stays 8.
4
+ --
5
+ -- Sources read, each at its latest definition:
6
+ -- * agent_board.current_agent_id() -- 20260920000100 (the resolver
7
+ -- request_join_board, 20260810000100, calls);
8
+ -- * agent_board.board_membership_events -- 20260806000100 (the append-only
9
+ -- consent ledger; seq is the total order, created_at is wall-clock age);
10
+ -- * agent_board.boards.join_request_ttl_days -- 20260806000100;
11
+ -- * the emitter _emit_membership_event -- 20260807000100: a request made by the
12
+ -- subject through request_join_board is `target-authored` / `requested`;
13
+ -- * agent_board.board_invite_tokens -- 20260724000100. invite_board_for_display
14
+ -- checks only the frozen IF-0-ONBOARD-11 subset: not revoked, expires_at > now(), uses
15
+ -- remaining. The redeem core (latest 20260909000100) refuses MORE -- a suspended or
16
+ -- fleet-revoked creator, a lapsed ceiling, a removed agent, fleet-bounded invites -- so a
17
+ -- code that displays a board can still fail to redeem.
18
+
19
+ -- =============================================================================
20
+ -- 1. list_my_board_requests() -- IF-0-ONBOARD-4
21
+ -- =============================================================================
22
+ -- WHICH REQUESTS. The ledger, never the membership row. A request is a (board, caller) with
23
+ -- at least one event where agent_id is the caller, provenance = 'target-authored' and
24
+ -- result_state = 'requested'. board_memberships.created_by_agent_id is NOT a source: the
25
+ -- sink overwrites it on every later write (an approval names the approver), so it cannot say
26
+ -- who asked.
27
+ --
28
+ -- IDENTITY. From the session only, by the resolver request_join_board uses. There is no
29
+ -- parameter, and a null identity (service_role, anon, a revoked credential) returns nothing.
30
+ --
31
+ -- CURRENT STATE. The caller's membership row on that board, chosen active-first (MBROWID 3a,
32
+ -- the key every current-standing reader uses), or 'none' when no row exists. A rejected request
33
+ -- reads 'left' (REJECTSEM, #89: a refusal lands on the recoverable state).
34
+ --
35
+ -- EXPIRY. expires_at = the latest request event's created_at + the board's
36
+ -- join_request_ttl_days. expired mirrors the consent predicates exactly
37
+ -- (created_at < now() - ttl): an expired request no longer counts as consent. It is a property
38
+ -- of the REQUEST and is reported whatever the membership's current state.
39
+ create or replace function agent_board.list_my_board_requests()
40
+ returns table(
41
+ board_id uuid,
42
+ board_name text,
43
+ board_slug text,
44
+ requested_at timestamptz,
45
+ membership_state text,
46
+ expires_at timestamptz,
47
+ expired boolean
48
+ )
49
+ language plpgsql
50
+ stable
51
+ security definer
52
+ set search_path = agent_board, public
53
+ as $$
54
+ declare
55
+ v_actor uuid := agent_board.current_agent_id();
56
+ begin
57
+ if v_actor is null then
58
+ return;
59
+ end if;
60
+
61
+ return query
62
+ select
63
+ b.id,
64
+ b.name,
65
+ b.slug,
66
+ req.created_at,
67
+ coalesce(cur.membership_state, 'none'),
68
+ req.created_at + make_interval(days => b.join_request_ttl_days),
69
+ req.created_at < now() - make_interval(days => b.join_request_ttl_days)
70
+ from (
71
+ -- The latest request event per board, by seq (the ledger's total order).
72
+ select distinct on (e.board_id) e.board_id, e.created_at
73
+ from agent_board.board_membership_events e
74
+ where e.agent_id = v_actor
75
+ and e.provenance = 'target-authored'
76
+ and e.result_state = 'requested'
77
+ order by e.board_id, e.seq desc
78
+ ) req
79
+ join agent_board.boards b on b.id = req.board_id
80
+ left join lateral (
81
+ select bm.membership_state
82
+ from agent_board.board_memberships bm
83
+ where bm.board_id = req.board_id
84
+ and bm.agent_id = v_actor
85
+ order by case when bm.membership_state in ('joined', 'subscribed') then 0 else 1 end,
86
+ bm.created_at desc, bm.id desc
87
+ limit 1
88
+ ) cur on true
89
+ order by req.created_at desc, b.id desc;
90
+ end;
91
+ $$;
92
+
93
+ comment on function agent_board.list_my_board_requests() is
94
+ 'IF-0-ONBOARD-4: the caller''s own join requests as they stand now. Source is the consent ledger (board_membership_events: agent_id = caller, provenance target-authored, result_state requested), never board_memberships.created_by_agent_id, which later writers overwrite. Identity is current_agent_id() only; there is no parameter and a null identity returns nothing, so service_role (no caller identity) is refused EXECUTE. Per board: id, name, slug, the latest request event''s time, the current membership state chosen active-first (MBROWID 3a) or none, expires_at = requested_at + join_request_ttl_days, and expired (the request no longer counts as consent). Requests made before the ledger existed carry only a board-authored backfill_neutral event and are not returned. No per-row history.';
95
+
96
+ revoke all on function agent_board.list_my_board_requests() from public, anon, service_role;
97
+ grant execute on function agent_board.list_my_board_requests() to authenticated;
98
+
99
+ -- =============================================================================
100
+ -- 2. invite_board_for_display(p_code_sha256) -- IF-0-ONBOARD-11
101
+ -- =============================================================================
102
+ -- The Portal's consent page shows which board an in-chat enrollment will join, and it holds
103
+ -- only the digest (the code itself never leaves the agent). The digest is the lowercase hex
104
+ -- sha256 of the code text; the argument is compared case-insensitively.
105
+ --
106
+ -- Only a code passing the IF-0-ONBOARD-11 subset resolves: not revoked, not expired, and uses
107
+ -- remaining. This is narrower than the redeem core (see the header), so display is not a promise
108
+ -- that redeem will succeed. Anything else -- including an unknown digest -- returns no row, one uniform
109
+ -- answer. Codes are 256-bit, so the digest is not a practical oracle; EXECUTE is service_role
110
+ -- only regardless, because the Portal calls it server-side.
111
+ create index if not exists idx_agent_board_board_invite_tokens_code_sha256
112
+ on agent_board.board_invite_tokens (encode(extensions.digest(code, 'sha256'), 'hex'));
113
+
114
+ create or replace function agent_board.invite_board_for_display(p_code_sha256 text)
115
+ returns table(
116
+ board_id uuid,
117
+ board_name text,
118
+ board_slug text,
119
+ preset_role text
120
+ )
121
+ language sql
122
+ stable
123
+ security definer
124
+ set search_path = agent_board, public
125
+ as $$
126
+ select b.id, b.name, b.slug, t.preset_role
127
+ from agent_board.board_invite_tokens t
128
+ join agent_board.boards b on b.id = t.board_id
129
+ where encode(extensions.digest(t.code, 'sha256'), 'hex') = lower(p_code_sha256)
130
+ and t.revoked_at is null
131
+ and t.expires_at > now()
132
+ and (t.max_uses is null or t.uses_count < t.max_uses);
133
+ $$;
134
+
135
+ comment on function agent_board.invite_board_for_display(text) is
136
+ 'IF-0-ONBOARD-11: resolves an invite code''s digest (lowercase hex sha256 of the code, compared case-insensitively) to (board_id, board_name, board_slug, preset_role) for display on the Portal consent page. Only a usable code resolves -- not revoked, expires_at > now(), and max_uses null or uses_count < max_uses (a subset of the redeem core''s checks, so a displayed board can still fail to redeem); revoked, expired, exhausted and unknown codes return no row. Read-only. EXECUTE is service_role only: the Portal calls it server-side.';
137
+
138
+ revoke all on function agent_board.invite_board_for_display(text) from public, anon, authenticated;
139
+ grant execute on function agent_board.invite_board_for_display(text) to service_role;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@consiliency/agent-board-schema",
3
- "version": "1.55.0",
3
+ "version": "1.57.0",
4
4
  "description": "Canonical, immutable, exact-pinnable agent_board schema bundle: ordered SQL migrations, digest + compatibility manifest, and deterministic materialize/plan/check tooling for adopters.",
5
5
  "repository": "https://github.com/Consiliency/message-board.git",
6
6
  "type": "module",
@@ -2,7 +2,7 @@
2
2
  "schema": "agent_board_schema_manifest.v1",
3
3
  "interface": "IF-0-MBPLANE-BUNDLE-1",
4
4
  "package": "@consiliency/agent-board-schema",
5
- "packageVersion": "1.55.0",
5
+ "packageVersion": "1.57.0",
6
6
  "schemaVersion": 8,
7
7
  "minClientVersion": "1.1.0",
8
8
  "source": {
@@ -46,8 +46,8 @@
46
46
  "usage": "upsert (retention/monitoring defaults; on conflict do nothing)"
47
47
  }
48
48
  ],
49
- "migrationCount": 153,
50
- "aggregateSha256": "90e7cdfd7208e11b31f1699482c22b96f2ad0d797eb9490c85098491881e95dc",
49
+ "migrationCount": 155,
50
+ "aggregateSha256": "347357b36b5ee37fbde189e005993c40df1e63a2d9d247b53823761304ae127e",
51
51
  "migrations": [
52
52
  {
53
53
  "order": 0,
@@ -1425,6 +1425,24 @@
1425
1425
  "sourceRef": "message-board",
1426
1426
  "bytes": 55964,
1427
1427
  "sha256": "317d7b41432b36a2e38cc64940838e173e425014e3e256a96d832202b250e82d"
1428
+ },
1429
+ {
1430
+ "order": 153,
1431
+ "id": "20261006000100_agent_board_room_roster_active_first",
1432
+ "filename": "20261006000100_agent_board_room_roster_active_first.sql",
1433
+ "origin": "message-board-forward",
1434
+ "sourceRef": "message-board",
1435
+ "bytes": 5470,
1436
+ "sha256": "637480feeca07dbb2fe7a4624dc6d063d0c1f23e6ea3c3ee9a946ad43de4e34e"
1437
+ },
1438
+ {
1439
+ "order": 154,
1440
+ "id": "20261007000100_agent_board_onboard_requests",
1441
+ "filename": "20261007000100_agent_board_onboard_requests.sql",
1442
+ "origin": "message-board-forward",
1443
+ "sourceRef": "message-board",
1444
+ "bytes": 7655,
1445
+ "sha256": "fbdbecfb1c78e2d1b16b37845a74082dcdf1241c61c0356b992e1e01baddc41c"
1428
1446
  }
1429
1447
  ],
1430
1448
  "excludedBridge": {
@@ -38,9 +38,9 @@ describe('manifest integrity', () => {
38
38
  expect(manifest.schemaVersion).toBe(8);
39
39
  expect(manifest.minClientVersion).toMatch(/^\d+\.\d+\.\d+$/);
40
40
  });
41
- it('registers the four MBAUTHZ + four MBSENDAUTHZ + four MBSESSION + four MBDELEG + three MBFED + three MBHARDEN + two MBPORTALGATE + two MBPORTAL-PR32 + two ROOMOWN + two ROOMLINK + one ROOMDELEG + one LOCALAUTH + one ROOMUIAPI + one FEDSESSION + one FEDSESSION-AUTOJOIN + one GATENULL + one MEMBSTATE + one AGENTSDIR + one LEAVEIDEM + one ROLERESET + one MBROWID + one MBHYGIENE + one MBCONSENT-A + one MBCONSENT-B(a) + one MBCONSENT-B(i) + one MBCONSENT-B(ii) + one MBCONSENT-B(iii) + one MBHARDEN-#97 + one MBHARDEN-#118 + one INVITEPOLICY + one OBSGATE + one OBSGATE-2 + one OBSGATE-3 + one OBSGATE-4 + one FLEETMACHINERLS + one RESOLVENOOP + one ROOMDELEG-LANEB + one CLAIMKEY + two MINTHARDEN + one FLEETMACHINEHIJACK + one CLAIMGATE-SHADOW + one CLAIMGATE-ENFORCE + one FLEETMACHINEREACTIVATION + one DELEGCAPCEILING + one FLEETMACHINERECLAIM + one DELEGSOLEWRITER + one FLEETDOMAINRECLAIM + five ATOMICFLEETONBOARDING (onboarding + ceiling-lock + revocation-evidence + fedsession-gate + fedsession-lock-order) + one OUTBOXWAKE + one ENROLLLOCKORDER + one FEDPROVIDERABSENCE + one WAKERECOVERY + one CONSENTRECONCILE + one ENROLLRESUMPTION + one SIGNEDAUTHORITY + one SIGNERLIFECYCLE + one LEDGERAUTHORITY + one CEILINGLOCKCOMMENT + one LEDGERBOARDCREATE + one RECEIPTSUBJECTGATE + one TASKTHREADLOCKORDER + one CLAIMSUBJECTGATE + one FEDSESSIONIDENTITYGATE + one FEDIDENTITYSLUG + one INVITENODOWNGRADE + one SIGNEDWRITEFLAG + one SIGNEDWRITEMODEL + one RTCREDCLAIM + one ORIGINPOSTURE + one BOARDCLAIMPOLICY + one HEARTBEATPRESERVE + one LIVENESSDENOM + one OWNERLESSRENEWTTL + one OWNERLESSQUOTACENSUS + one FLEETDOMAINNODOWNGRADE + one OWNERLESSQUOTACONVERGE + one ADVISORYREVERTRESET + one CLAIMPOLICYRACE + one CLAIMPOLICYLOCKGRANT + one SESSIONCHALLENGESUPERSEDE + one ROOMCONTRACT + one CALLBACKCONSUMER + one ENROLLTOKENSINGLEUSE forward migrations (migrationCount = prior 113 + 5 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 153)', () => {
41
+ it('registers the four MBAUTHZ + four MBSENDAUTHZ + four MBSESSION + four MBDELEG + three MBFED + three MBHARDEN + two MBPORTALGATE + two MBPORTAL-PR32 + two ROOMOWN + two ROOMLINK + one ROOMDELEG + one LOCALAUTH + one ROOMUIAPI + one FEDSESSION + one FEDSESSION-AUTOJOIN + one GATENULL + one MEMBSTATE + one AGENTSDIR + one LEAVEIDEM + one ROLERESET + one MBROWID + one MBHYGIENE + one MBCONSENT-A + one MBCONSENT-B(a) + one MBCONSENT-B(i) + one MBCONSENT-B(ii) + one MBCONSENT-B(iii) + one MBHARDEN-#97 + one MBHARDEN-#118 + one INVITEPOLICY + one OBSGATE + one OBSGATE-2 + one OBSGATE-3 + one OBSGATE-4 + one FLEETMACHINERLS + one RESOLVENOOP + one ROOMDELEG-LANEB + one CLAIMKEY + two MINTHARDEN + one FLEETMACHINEHIJACK + one CLAIMGATE-SHADOW + one CLAIMGATE-ENFORCE + one FLEETMACHINEREACTIVATION + one DELEGCAPCEILING + one FLEETMACHINERECLAIM + one DELEGSOLEWRITER + one FLEETDOMAINRECLAIM + five ATOMICFLEETONBOARDING (onboarding + ceiling-lock + revocation-evidence + fedsession-gate + fedsession-lock-order) + one OUTBOXWAKE + one ENROLLLOCKORDER + one FEDPROVIDERABSENCE + one WAKERECOVERY + one CONSENTRECONCILE + one ENROLLRESUMPTION + one SIGNEDAUTHORITY + one SIGNERLIFECYCLE + one LEDGERAUTHORITY + one CEILINGLOCKCOMMENT + one LEDGERBOARDCREATE + one RECEIPTSUBJECTGATE + one TASKTHREADLOCKORDER + one CLAIMSUBJECTGATE + one FEDSESSIONIDENTITYGATE + one FEDIDENTITYSLUG + one INVITENODOWNGRADE + one SIGNEDWRITEFLAG + one SIGNEDWRITEMODEL + one RTCREDCLAIM + one ORIGINPOSTURE + one BOARDCLAIMPOLICY + one HEARTBEATPRESERVE + one LIVENESSDENOM + one OWNERLESSRENEWTTL + one OWNERLESSQUOTACENSUS + one FLEETDOMAINNODOWNGRADE + one OWNERLESSQUOTACONVERGE + one ADVISORYREVERTRESET + one CLAIMPOLICYRACE + one CLAIMPOLICYLOCKGRANT + one SESSIONCHALLENGESUPERSEDE + one ROOMCONTRACT + one CALLBACKCONSUMER + one ENROLLTOKENSINGLEUSE + one ROOMCONTRACT-ACTIVEFIRST + one ONBOARD forward migrations (migrationCount = prior 113 + 5 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 155)', () => {
42
42
  expect(manifest.migrationCount).toBe(manifest.migrations.length);
43
- expect(manifest.migrationCount).toBe(153);
43
+ expect(manifest.migrationCount).toBe(155);
44
44
  // MBSESSION switched enforcement on (scoped-send re-grant): the client-visible
45
45
  // schema version bumped to 8. MBDELEG tightens delegation and MBFED adds only
46
46
  // enrollment-only additive surface (identity_providers registry, enrollment audit,
@@ -340,6 +340,12 @@ describe('manifest integrity', () => {
340
340
  '20261004000100_agent_board_callback_consumer_intent.sql',
341
341
  // ENROLLTOKENSINGLEUSE (#521): a verified Portal token binds to at most one key.
342
342
  '20261005000100_agent_board_enroll_token_single_use.sql',
343
+ // ROOMCONTRACT-ACTIVEFIRST (#542): list_board_members chooses current standing
344
+ // active-first (MBROWID 3a) at both its authorization and projection sites.
345
+ '20261006000100_agent_board_room_roster_active_first.sql',
346
+ // ONBOARD (v11): list_my_board_requests (IF-0-ONBOARD-4) and the service-only
347
+ // invite_board_for_display digest lookup (IF-0-ONBOARD-11).
348
+ '20261007000100_agent_board_onboard_requests.sql',
343
349
  ]) {
344
350
  expect(names.has(f)).toBe(true);
345
351
  }