Cross-backend parity suite for role-gated participation conferral — the
success paths. The imperative escape hatch beneath the declarative
conformance_participation_cases.ts: the multi-step flows that need a real
recipient account (so a static conformance row can't express them) — an
admin assigns the participant app-role, and an admin offers it through the
consent flow and the recipient accepts.
Proves the two conferral *write* paths agree on both spines (TS spine binary
+ Rust testing_spine_stub):
- immediate assign —
role_grant_assign of the admin-grantable
participant role lands a grant and returns {ok, role_grant_id};
re-assigning the active grant is idempotent (same id). - consent flow —
role_grant_offer_create of participant (admin-only)
→ the recipient role_grant_offer_accepts → a role_grant lands.
The single-request gate/denial matrix (grantability refusal, admin-only
conferral, dispatcher admin gate, auth) lives in the declarative table
(conformance_participation_cases.ts) — keep new single-request assertions
there; this suite is only for flows the table cannot carry.
The participant role is registered admin-grantable on both spines
(spine_roles / the Rust stub's RoleRegistry), so the suite is ungated;
every spine mounts the standard RPC surface it drives.
$lib-free by contract (relative specifiers only), like the sibling
cross-backend suites.