Responsible gaming
What the RG layer does, the hooks your platform can drive, and the invariant underneath all of it: every operator-facing control can make the feed stricter — none can make it looser.
The built-in baseline (non-configurable)
- Breather at 3 consecutive losses, global across games. The round finishes normally; the breather is the next card. Its continue button is gated for the full 8 seconds — no skip path. Session net (win or loss) is shown plainly.
- 2 non-bet cards guaranteed after every breather — betting-capable cards are hard-filtered from the candidate pool, not down-weighted.
- Loss-streak damping: at 2 consecutive losses the playable-card weight drops ×0.15 for the pick.
- RG modifications only ever subtract betting opportunity from the baseline mix, never add.
The one RG config field — clamped tighten-only
| field | clamp | meaning |
|---|---|---|
rg.breatherAt | ≤ 3 (floor 1) | fire the breather sooner; a value above the default is ignored |
rg.postBreatherNonBet | ≥ 2 | guarantee more non-bet cards; a smaller value is ignored |
rg.requirePlayerCheck | — | fail-closed: bets start disabled until your player_check_result allows them |
rg.maxSessionSec | any positive value | foreground-active session limit → forced breather (background time never counts) |
The clamp is unit-tested precisely on the weaken-attempt cases: a hostile or mistaken value can only tighten or be ignored.
Hook 1 · Pre-session player check
With wallet: 'operator', the feed posts fidra:v1:player_check on init. You answer with the player's self-exclusion / limit verdict:
{ source:'fidra-host', proto:'fidra:v1',
type:'fidra:v1:player_check_result', allow: boolean, reason?: string }
allow !== true→ non-bet mode: every bet is blocked at the wallet boundary — no debit, no roundId, nobet_placed— and the feed keeps running watch-only.- With
rg.requirePlayerCheck: true, bets start disabled until anallow: truearrives — a self-excluded player can never get a bet in before the check returns.
Hook 2 · Forced pause
fidra:v1:pause inserts a breather now, reusing the exact state the 3-loss trigger sets. One-way lever: an operator can force a pause, never suppress one.
Hook 3 · Operator risk state
Your platform sees the whole account — deposits, cross-product losses, limits. Send a risk state at mount or mid-session (fidra:v1:risk_state { state }) and the composition tightens:
| state | composition response (tighten-only) |
|---|---|
normal | default feed — the least strict state the composition will apply |
caution | promotional/streak cards suppressed; the post-breather non-bet quota is raised |
restricted | watch-only — every betting card removed from the pool |
cooloff | watch-only and the feed opens with a pause card |
blocked | the feed does not render — your app shows its own screen |
Every transition is written to the tamper-evident audit log with reason code operator_risk_state, and every composition decision stamps the risk state in force. Moving a player back toward normal is your clinical decision — fidra never loosens on its own.
What remains your duty
fidra's layer shapes presentation in response to a state you compute. Detecting harm (deposit velocity, chasing, self-exclusion, affordability), computing the risk state, and all statutory RG obligations remain entirely the operator's responsibility. fidra supplements your controls; it does not and cannot replace account-level harm detection.
docs/integration/RG.md
fidra is a B2B software supplier — no gambling services operated, no player funds held.
g.jgerenaia@tomsons.co