Status: Phase 0 is complete, Phase 1 wallet/balance foundations
are implemented, and Phase 2 rules, persistence, recovery, and gated command
paths are implemented, including room-scoped database rules/location bindings,
the supplied rule/limit revisions, and entry funding. The documented slot
baseline has 95.4383735% theoretical RTP. On 2026-10-15, the operator confirmed
successful live qualification of slots, roulette, and location access and
approved activation. CASINO_GAMEPLAY_ENABLED is now true for these chips-only
games. This records operator-reported evidence; no new live run or production
inspection was performed by the activation change.
Shared economy update: the wallet ownership, entry-grant approval, and retention decisions in the historical Phase 0/1 sections below are superseded by the shared economy design. Casino and future games use the shared per-member credits account; finalized economy ledger records are retained for 60 days. Migration and rollback steps are in the shared economy guide.
Specify a staged casino feature for the Veratown prototype that offers games with a real in-bot wager and a chip-denominated payout/reward, while preserving the current architecture and its BC, MongoDB, privacy, and action-journal invariants.
The plan uses the legacy casino in ~/repo/ropeybot/bin/games/casino* as
behavioral inspiration, not as a source of code, database schema, BC transport,
or permission policy. In particular, the existing prototype appearance
qualification supports mutations of the sender’s own character only. A
third-party clothing or bondage wager is therefore a hard feasibility gate,
not an assumed capability.
This document remains the plan for future games and gated casino capabilities. The current balance-only implementation is described in the casino guide.
veratown_prototype_test and a dedicated BC room/account set
before enabling any live behavior.The implementation must follow bot runtime architecture, commands and plug-ins, appearance foundation, and BC acknowledgement rules.
src/app/start.ts. Inject the existing BcClient, command parser,
communication API, ActionCoordinator, and Mongo Db. The casino owns no
Socket.IO connection, socket.emit, or Mongo client.CasinoFeaturePlugin, its dedicated command suite, and explicit
subscriptions/disposers. Register it before CommandRouterPlugin. Dispose
handlers, event listeners, timers, and in-flight session work in stop().src/features/casino/services/
and do not import adapters or other features. Persistence belongs in the
feature repository. Only the composition root wires collaborators. The
casino may depend on core/ contracts and injected BC/Mongo capabilities;
other features must not import the casino.socket.emit means only dispatched/dispatched_unconfirmed. Appearance
changes require a dedicated action and later matching BC observation; a
journal record alone never proves that a restraint was applied.ActionCoordinator operation, or dispatch generic BC packets from an
already-journaled action.veratown_prototype for production, or
veratown_prototype_test for test. Do not accept arbitrary database names
and do not use the legacy Ropeybot database as a runtime target or seed.bc-bot, browser code, packet emulation, or packet bypass.attempt() at boundaries. Clear timers
and listeners on terminal state, disconnect, plugin stop, and startup
rollback. Non-process-critical timers must be unref’ed.The architecture below does not require these answers, but production behavior does. They are release gates; do not fill them with undocumented assumptions.
| Decision | Required choice |
|---|---|
| Chip source | Starting balance, optional daily grants, and whether an operator may grant chips. |
| Chip sinks and movement | Whether transfers, purchases, refunds, and paid restraint removal are allowed. |
| Limits | Minimum/maximum wager, maximum payout, maximum active rounds/players, and any per-day limits. |
| House rules | Roulette wheel variant/odds; blackjack deck, dealer rule, payout, hit/stand and later options; dice/craps wager types; slot symbols/paytable. |
| Interruption policy | What happens on disconnect, bot restart, timeout, table closure, or ambiguous BC outcome for each game. |
| Consent | Whether future clothing/forfeit stakes and rewards are opt-in per game, what the opt-out mechanism is, and exactly which bounded consequences can be offered. |
| Appearance authority | Whether the pinned BC protocol and current access/permission behavior can support a dedicated, journaled mutation of another player’s appearance. |
| Fairness disclosure | Whether server-side cryptographic randomness is sufficient, or a published commit/reveal protocol is required. |
| Retention | Wallet-ledger retention, settled-session retention, and whether a separate operator audit export is needed. |
The current Phase 2 approvals and remaining gates are recorded below. Decisions for later games, transfers, purchases, and appearance stakes remain deferred.
The following decisions were approved for Phase 1 on 2026-10-12:
| Topic | Approved decision |
|---|---|
| Initial wallet | Create wallets with zero available and reserved chips. |
| Grants and chip movement | No starting grants, operator grants, daily grants, transfers, purchases, or public wagering in Phase 1. Do not expose grant or wager commands. |
| Wallet balance | The only player-facing casino command in Phase 1 is a private balance/help response. |
| Ledger retention | Apply a 30-day TTL to settled ledger entries. A reservation remains available for recovery while its session is unfinished; set its TTL only when the wager settles. |
| Session retention | Settled session records expire after 30 days. Open, settling, or recovery-pending sessions have no expiry date and must not be TTL-deleted. |
| House rules | Defer slot symbols, paytable, wager limits, and game interruption policies to Phase 2, before any player wager is accepted. |
| Appearance stakes | Clothing and bondage wagers/rewards remain disabled pending a separate feasibility and consent approval. |
The user authorized read-only inspection of veratown_prototype_test and
prohibited database writes unless absolutely required. A read-only hello
command against that database returned an Atlas replica-set topology with a
primary and three hosts; this supports Mongo multi-document transactions. No
application data was read or written.
The operator confirmed that production and test use the same MongoDB backend and that the test backend qualification applies to production. Combined with the observed test replica-set topology, this satisfies the Phase 0 transaction-topology gate for both runtime databases. Production was not directly inspected, and its credentials, connection, and transaction permissions were not independently tested. This is backend-capability evidence, not a live reserve/settle qualification or authorization to connect to production.
These original Phase 1 decisions did not approve any live wager, game, grant, or appearance mutation. The subsequent Phase 2 approvals below supersede the funding deferral without authorizing gameplay activation or live qualification.
The operator approved a baseline of 20 chips on room/map entry per rolling
24 hours, the existing refund-before-durable-result / settle-after-result
recovery policy, and the existing cryptographic randomness approach. The grant
amount and cooldown are room-scoped casino.rules settings (bounded to 1–20
chips and a 24-hour–365-day rolling interval); missing rules fail closed. Grants
are implemented independently of gameplay activation, with atomic
wallet/ledger writes and a durable optional lastEntryGrantAt. Reconnect/ready
checks current occupants without bypassing the cooldown; the bot itself is
excluded.
No grants accumulate while a player stays in the room or is absent.
The supplied revised game specification is implemented for offline qualification
as revised-2026-10-12. The first Option 2 schedule is retained as
revised-2026-10-12-option-2 for outcome recovery. Its lower-tier awards were
recalibrated in revised-2026-10-13-rtp95; wagers remain 1–100 whole chips.
Every reel independently draws a cryptographic integer ticket in 0–99:
| Symbol | Weight | Four-of-kind base | Three-of-kind base |
|---|---|---|---|
| Cherry | 35 | 1x | 1x |
| Apple | 25 | 1x | 1x |
| Banana | 18 | 1x | 1x |
| Peach | 12 | 1x | 1x |
| Diamond | 8 | 100x | 15x |
| Seven | 2 | 500x | 50x |
Special returns are 1.25x for two pairs, 1x for exactly one pair, and 1x for four distinct fruits (cherry/apple/banana/peach, no repeated symbol). Other results return zero. Categories are mutually exclusive: four-of-kind, then three-of-kind, two-pair, pair, and four-fruit result. The reels draw independently. No Lucky Seven or Diamond Booster applies. Multipliers are gross returns including the stake; fractional-chip returns are floored at settlement.
The requested 35/25/18/12/8/2 symbol weights are unchanged. The earlier Option 2
awards produced 128.102798% theoretical RTP, and weight-only adjustments did not
approach the target while preserving the jackpot schedule. The calibrated
revised-2026-10-13-rtp95 schedule retains 100x four diamonds, 500x four sevens,
15x three diamonds, and 50x three sevens while reducing lower-tier payouts.
Exhaustive RTP validation: all 1,296 ordered outcomes produce 95.438374% theoretical RTP. Whole-chip return rounding gives 92.684432% RTP for a one-chip stake and 95.438374% at 20- and 100-chip stakes. 89.479456% of outcomes return chips, including break-even pushes. Theoretical positive net-profit frequency is 11.211430%; with a one-chip wager and whole-chip rounding, only 0.195664% of outcomes return more than the stake. RTP contributions are pair 53.358912 percentage points, three-kind 21.339192, two-pair 13.769708, four-kind 2.434562, and four distinct fruits 4.536. The operator confirmed successful live qualification and approved activation on 2026-10-15; the gameplay release constant is now true.
Up to 20 players have independent slot rounds. A wager starts that player’s 10-second window; drawing and settlement occur at its deadline. There is one wager per player/round and no player cancellation. The result period lasts five seconds after durable terminal closure, followed by five seconds of renewal. Only then can the player submit a new wager. Slots never automatically repeat stakes. Failed/insufficient-funds reservations do not occupy a seat.
The uniform single-zero wheel supports all supplied selections:
| Selection | Gross multiplier | Command selection syntax |
|---|---|---|
| Straight-up | 36x | number 0-36 |
| Split | 18x | split a b |
| Street | 12x | street row (1–12) |
| Trio | 12x | trio 0 1 2 or trio 0 2 3 |
| Corner | 9x | corner a b c d |
| Four-number | 9x | four_number (0,1,2,3) |
| Six-line | 6x | six_line row (first row 1–11) |
| Red/black, odd/even, low/high | 2x | red, black, odd, even, low, high |
| Dozen / column | 3x | dozen 1-3 / column 1-3 |
Number lists must be ascending and obey standard layout adjacency; splits with zero cover 0–1, 0–2, or 0–3. Zero loses all outside bets. Multipliers include returned stake, so 35:1 profit is 36x gross. Every supported roulette bet has RTP 36/37 (97.2973%) and house edge 1/37 (2.7027%). Maximum gross return per roulette bet is 3,600 chips.
A valid funded first bet starts an idle table; room admins may still open one explicitly. Each round has 45 seconds of betting for up to 20 active participants, then 10 seconds of results and five seconds of renewal after durable terminal closure. Rounds renew automatically while the service runs after a played round, but no stakes are carried into the next round. An empty or fully cancelled round closes quietly without a draw, result, cooldown, or further renewal. A new valid bet wakes it again. Restart recovery restores pending renewal only for durable played results; interrupted no-result rounds refund and remain idle. Historical empty-round cooldown records do not prevent a first bet.
Multiple bets per participant receive distinct stable IDs; reconciliation of a lost reservation response reuses that request’s ID. Cancellation removes only the last active bet, with full refund before the deadline, and allows a new bet. Repeated cancellation undoes active bets in reverse placement order. Cancellation of every active bet frees the participant’s seat. A technical 1,000-entry history bound per round (including refunds) preserves bounded documents; reaching it explicitly rejects new reservations without debiting.
Settlement exposes winning number/color, every winning/losing bet, total stake, stake returned on winning bets, gross return, and net profit/loss. Individual bet details and per-player totals are private; room announcements contain only the round result and opening notice.
An interruption before durable outcome persistence refunds reservations; after
persistence, recovery settles that exact result without redrawing. A notification
failure never reverses a completed economic transaction. resultUntilAt and
nextRoundAt are optional terminal-session fields; a room/next-round index
supports restoring cooldowns after restart. Existing Phase 1 documents and old
provisional-2026-10-12 saved outcomes remain readable and retain their payouts.
Node cryptographic randomInt remains the approved RNG; no commit/reveal system
is requested. /bot casino fairness explains this is server-side randomness,
not independent draw verification. /bot casino rules exposes the current
paytables, odds, limitations, and measured RTP privately.
Activation update (2026-10-15): the operator confirmed successful live
qualification of slots, roulette, and location access and approved enabling
them. CASINO_GAMEPLAY_ENABLED is true. Existing authorization, location,
rules validation, and accounting safeguards remain unchanged. This approval
does not enable appearance stakes or other games, or authorize new live tests
or production database operations.
The first offline implementation used provisional-2026-10-12. These rules are
superseded for new rounds but remain supported for saved-outcome recovery:
No new rounds use this version. The current revised rules and activation approval are listed above. The game service and recovery now start in the runtime; entry funding is independent.
| Game / service | Complexity | Main state concerns | Planned phase |
|---|---|---|---|
| Slots | Low | One stake, one random result, one payout. | First game; validates the wallet and settlement path. |
| Roulette | Low–moderate | Shared betting window, close deadline, one round result. | First game; supports shared-table flow and has useful Ropeybot precedent. |
| Cocktail/cosmetic shop | Low | Chip debit and a cosmetic appearance reward. | Optional chip sink after wallet foundation; not itself a gambling game. |
| Dice / simple craps | Moderate | A roll or a point state with repeat rolls and table rules. | After roulette; begin with the simplest approved dice rules. |
| Blackjack | Moderate | Per-player actions, dealer turn, turn deadlines, disconnect and refund policy. | After the shared session framework is proven. |
| Solo strip poker | High | Private hand state plus clothing-state dependency and explicit consent. | Later, only after the appearance feasibility gate. |
| Multiplayer strip poker | Very high | Roster locking, simultaneous stakes, turn order, disconnects, pot settlement, appearance changes for several players. | Last; depends on all earlier wallet/session/recovery work and appearance approval. |
“Crabs” is interpreted here as craps/dice. If it means a different game, treat it as a separate pure rules module and do not fold it into the dice state machine without specifying its rules.
The first code-bearing release should introduce only the casino feature and wallet/rules foundation. Later game modules and appearance capabilities are added incrementally; the diagram shows extension points, not already-existing classes.
classDiagram
direction LR
class BotPluginHost
class CasinoFeaturePlugin {
+start()
+stop()
-dispose subscriptions and timers
}
class CasinoCommandSuite {
+register() Dispose
+balance
+play
+join
+hit / stand
+help
}
class CasinoSessionService {
+startGame()
+submitCommand()
+cancelOrExpire()
+recover()
}
class CasinoRules {
<<pure functions>>
+validate()
+advance()
+resolve()
}
class CasinoRandomSource {
<<injected>>
+uniformInt(min, max)
}
class CasinoWalletService {
+reserve()
+settle()
+refund()
+balance()
}
class CasinoRepository {
<<feature port>>
+loadWallet()
+applyWalletTransaction()
+createOrAdvanceSession()
+loadRecoverableSessions()
}
class MongoCasinoRepository
class CasinoLocationAccess {
+enter(member, key, shape)
+leave(member, key)
+canAccess(member, gameId)
+accessibleGames(member)
}
class MapLocationEventBus {
<<server-observed transitions>>
+locationEntered(member, key, shape)
+locationLeft(member, key, shape)
}
class BcClient
class CharacterCommunicationApi
class ActionCoordinator
class CharacterAppearanceApi {
<<future optional capability>>
+execute()
}
class MongoDB
BotPluginHost o-- CasinoFeaturePlugin
CasinoFeaturePlugin --> CasinoCommandSuite
CasinoFeaturePlugin --> CasinoSessionService
CasinoFeaturePlugin --> CasinoWalletService
CasinoFeaturePlugin --> CasinoLocationAccess
CasinoFeaturePlugin --> MapLocationEventBus : per-member enter/exit
CasinoFeaturePlugin --> BcClient : observed room and message events
CasinoFeaturePlugin --> CharacterCommunicationApi : private replies
CasinoCommandSuite --> CasinoSessionService
CasinoSessionService --> CasinoRules
CasinoSessionService --> CasinoRandomSource
CasinoSessionService --> CasinoWalletService
CasinoSessionService --> CasinoRepository
CasinoWalletService --> CasinoRepository
CasinoRepository <|.. MongoCasinoRepository
MongoCasinoRepository --> MongoDB
CasinoFeaturePlugin ..> ActionCoordinator : only for future BC actions
CasinoFeaturePlugin ..> CharacterAppearanceApi : future gate; injected
plugin.ts: owns subscriptions, command suite, recovery startup, location
access tracking, and shutdown. It never contains game rules or Mongo update
logic.commands/casino-command-suite.ts: parses strict arguments, verifies the
sender is a valid room participant, filters private help/rules for that
sender’s currently observed game locations, rechecks location permission on
every game command, privately replies via the injected communication API, and
delegates to services.services/casino-session-service.ts: serializes mutations per session,
enforces phase/revision/deadline transitions, and calls pure rules and
wallet operations.services/game-rules/*.ts: deterministic, typed reducers/calculators. Accept
a state, validated player action, and injected random outcome where needed;
return a new state/result without I/O.services/casino-wallet-service.ts: validates chip amounts and calls one
repository operation per economic transition. It does not dispatch BC
packets or write prototypeActions.repository.ts: typed Mongo access, validation of documents read from Mongo,
atomic compare-and-set/transaction behavior, and index initialization.actions/forfeit-appearance-action.ts: future dedicated action only if the
feasibility gate passes. It calls the existing injected appearance API;
it does not import a different feature or generic-dispatch packets.availableChips to reservedChips.prototypeActions; that collection records BC
action lifecycles.stateDiagram-v2
[*] --> Uninitialized
Uninitialized --> Available: create zero-balance wallet
Available --> Reserved: reserve accepted stake atomically
Reserved --> SettledLoss: outcome is loss
Reserved --> SettledWin: outcome is win and payout applied
Reserved --> Refunded: push, approved cancel, or pre-outcome abort
SettledLoss --> Available
SettledWin --> Available
Refunded --> Available
Available --> Available: idempotent grant or cosmetic purchase
Reserved --> RecoveryPending: outcome or transaction status is uncertain
RecoveryPending --> SettledLoss: durable outcome says loss
RecoveryPending --> SettledWin: durable outcome says win
RecoveryPending --> Refunded: approved interruption policy says refund
RecoveryPending --> RecoveryPending: no sufficient evidence; do not guess
flowchart TD
Input[Validated player command] --> Auth{Authorized sender and valid player?}
Auth -- no --> Reject[Private usage or denial reply]
Auth -- yes --> Parse{Amount is safe integer and within approved limits?}
Parse -- no --> Reject
Parse -- yes --> Id[Create stable operation or wager ID]
Id --> Txn[Begin repository atomic operation]
Txn --> Existing{Operation already recorded?}
Existing -- yes --> ReturnPrior[Return recorded result; no second mutation]
Existing -- no --> Balance{Available chips cover stake?}
Balance -- no --> NoFunds[Insufficient funds; no ledger entry]
Balance -- yes --> Reserve[Decrease available; increase reserved]
Reserve --> Ledger[Insert unique ledger entry in same atomic unit]
Ledger --> Commit{Commit succeeds?}
Commit -- no --> Error[Return explicit persistence failure]
Commit -- yes --> Reply[Private result; whisper delivery remains unconfirmed]
Use the prototype prefix and the fixed runtime-selected database. Do not add
casino player data to the allowlisted source-configuration copy script, migrate
Ropeybot profiles, or accept a configurable database name.
| Collection | Purpose and principal fields | Index / constraints |
|---|---|---|
prototypeCasinoWallets |
One wallet per BC memberNumber: _id, schemaVersion, availableChips, reservedChips, createdAt, updatedAt. No unbounded transaction array. |
_id is the unique member identity. Validate non-negative safe integers at reads and writes. |
prototypeCasinoLedger |
Immutable economic entries: _id stable idempotency key, memberNumber, operationId, optional sessionId, kind, integer availableDelta, integer reservedDelta, bounded reason code, and createdAt. Store no command/chat text. |
Unique _id; indexes { memberNumber: 1, createdAt: -1 } and { sessionId: 1, memberNumber: 1 } for approved query patterns. |
prototypeCasinoSessions |
Bounded session/round state: _id, schemaVersion, gameId, roomName, phase, status, revision, bounded participant IDs, bounded game-specific state, createdAt, updatedAt, optional deadlineAt, optional durable outcome, and stable settlementId. Never store wardrobe snapshots. |
_id; { status: 1, updatedAt: 1 }; { roomName: 1, status: 1, deadlineAt: 1 }. Add indexes only for actual production queries. |
prototypeCasinoForfeits (later, gated) |
Active managed consequence metadata only: stable ID, target member, session ID, approved item/lock identifiers, expiry, observed application/release status, and safe reason code. No full appearance payload. | { memberNumber: 1, status: 1 }; { status: 1, expiresAt: 1 }. Do not TTL-delete active records before reconciliation. |
The preferred wallet operation updates the wallet, inserts its unique ledger entry, and advances the related session settlement status in one MongoDB transaction. Before choosing this design, verify that the deployed MongoDB topology supports transactions in both test and production. Do not infer transaction support merely from a URI or from connecting successfully. The Phase 0 evidence satisfies this topology gate through the read-only test inspection and operator confirmation of the shared production/test backend; it does not establish production credential or transaction-permission testing.
If transactions are unavailable, stop before implementing multi-document settlement and approve a different design. A separate ledger insert and wallet update without an atomic/recoverable protocol can either double-pay or leave wallet and ledger disagreeing. Do not silently fall back to non-transactional read/modify/write logic.
Wallet/ledger records are economic source-of-truth data, not short-lived
diagnostic logs. Shared economy finalized entries use the approved 60-day
retention, distinct from the 30-day prototypeActions TTL. Settled game
sessions may be archived or TTL-cleaned only under their own retention policy.
Active/recoverable sessions must never expire automatically.
flowchart LR
Command[Command adapter] --> Validate[Parse and authorize]
Validate --> Session[Session service serializes by session and revision]
Session --> Rules[Pure game-rule reducer]
Rules --> Reserve[Wallet reserves stake]
Reserve --> Active[Persist accepted phase and deadline]
Active --> Actions[Validate player game actions]
Actions --> Result[Resolve outcome using injected secure random source]
Result --> Persist[Persist outcome and settlement ID before payout]
Persist --> Settle[Atomic wallet and ledger settlement]
Settle --> Complete[Persist settled state]
Complete --> Reply[Private summary; optional safe public summary]
Active --> Abort[Timeout, disconnect, shutdown, or cancel]
Abort --> Policy[Apply approved phase-specific refund/recovery policy]
Policy --> Complete
Each persisted transition uses a revision compare-and-set. In-process operations that can affect the same session are serialized. A timer is only a trigger to re-evaluate durable phase/deadline state; it is not proof a round settled. Timers are disposed on completion and unref’ed when appropriate.
BcClient ready/room-sync lifecycle. Recover only casino-economic state.node:crypto APIs; inject a
deterministic source for unit tests. Avoid Math.random() for wagers. A
commitment/reveal protocol is a separate fairness decision, not an implicit
property of using a secure RNG.stateDiagram-v2
[*] --> Created
Created --> AcceptingWagers: game opened
AcceptingWagers --> WagerReserved: atomic reserve succeeds
AcceptingWagers --> Cancelled: no accepted stakes / admin closes
WagerReserved --> Playing: game-specific start condition met
WagerReserved --> Refunding: cancel before outcome per approved policy
Playing --> OutcomePersisted: rules resolve and durable outcome saved
Playing --> Refunding: approved timeout or interruption before outcome
OutcomePersisted --> Settling: stable settlement begins
Settling --> Settled: wallet, ledger, and session commit
Settling --> RecoveryPending: transaction status unknown
RecoveryPending --> Settling: ledger/revision evidence allows safe retry
RecoveryPending --> RecoveryPending: unresolved; report and do not guess
Refunding --> Settled: refund committed idempotently
Settled --> [*]
All game reducers are pure, typed, and versioned. They return explicit invalid action, already-complete, result, and continuation outcomes. Player commands are not trusted rule inputs; the command adapter validates member identity, session membership, turn, phase, amount, and deadline before calling a reducer.
Current game: weighted four-reel solo rounds, up to 20 active players. No appearance wager or interactive BC animation is required. The calibrated RTP schedule was operator-qualified and approved for activation on 2026-10-15.
stateDiagram-v2
[*] --> Ready
Ready --> Validating: play command
Validating --> Ready: invalid wager or insufficient balance
Validating --> Reserved: wallet reservation committed
Reserved --> OutcomePending: individual 10-second deadline; secure draw
OutcomePending --> OutcomeSaved: result and rules version persisted
OutcomeSaved --> Settling: apply payout/loss once
Settling --> Settled: wallet transaction committed
OutcomePending --> RecoveryPending: interrupted before result persisted
OutcomeSaved --> RecoveryPending: payout transaction uncertain
RecoveryPending --> Settling: resume from persisted result
Settled --> Results: 5-second result period
Results --> Renewal: 5-second renewal
Renewal --> Ready: player may submit a new wager
flowchart TD
A[Player chooses chip stake] --> B[Validate limits and reserve chips]
B -->|Rejected| X[Reply privately; no spin]
B -->|Committed| Window[Individual 10-second window; no cancellation]
Window --> C[Draw four independent weighted reels using secure RNG]
C --> D[Persist symbols, paytable version, and gross return]
D --> E[Idempotently settle wallet and ledger]
E --> F[Privately report result, whole-chip return, net and balance]
F --> Cooldown[5 seconds results + 5 seconds renewal; persisted cooldown]
Current game: one shared European table, multiple bets for up to 20 active players. The supplied bet types, profit-plus-stake payouts, and 45/10/5-second pacing are implemented and approved for runtime activation.
stateDiagram-v2
[*] --> Idle
Idle --> BettingOpen: first valid funded bet / admin open
BettingOpen --> BettingOpen: reserve valid bet
BettingOpen --> BettingOpen: cancel last active bet before close; may bet again
BettingOpen --> Closing: deadline with active bets
BettingOpen --> Idle: empty or fully cancelled at deadline
Closing --> OutcomeSaved: draw once; persist number and rules version
Closing --> Refunding: approved abort before result
OutcomeSaved --> Settling: calculate each participant's return
Settling --> Settling: apply one idempotent settlement per wager
Settling --> Settled: every payout/refund reconciled
Settling --> RecoveryPending: any write status uncertain
RecoveryPending --> Settling: recover from saved outcome and ledger
Settled --> Results: private details and totals; 10 seconds
Results --> Renewal: 5 seconds
Renewal --> BettingOpen: automatically open next round; no repeated stakes
Refunding --> Idle: refund each reservation exactly once
flowchart TD
A[Open round with betting deadline] --> B[Accept and reserve each valid bet]
B --> C{Betting deadline reached?}
C -- no --> B
C -- yes --> D[Close bets; reject late/cancel commands]
D --> Active{Any active bets?}
Active -->|no| Idle[Close quietly; wait for a valid bet]
Active -->|yes| E[Draw one outcome and persist it before payout]
E --> F[Resolve each bet using versioned rules]
F --> G[Settle each player idempotently]
G --> H[Publish safe round summary and mark settled]
Start with a bounded ruleset such as hit/stand only. Deck count, dealer rule, blackjack payout, push behavior, seat count, and turn deadline are release decisions. Do not implement split/double/insurance until their reservation and settlement semantics have their own tests.
stateDiagram-v2
[*] --> Waiting
Waiting --> Betting: open hand
Betting --> Betting: reserve accepted player stake
Betting --> InitialDeal: betting closes and at least one player joined
InitialDeal --> PlayerTurns: persist hands and turn order
PlayerTurns --> PlayerTurns: valid hit below 21
PlayerTurns --> NextPlayer: stand, bust, or approved turn timeout
NextPlayer --> PlayerTurns: another active player
NextPlayer --> DealerTurn: all players complete
InitialDeal --> DealerTurn: no player actions required by rules
DealerTurn --> OutcomeSaved: dealer resolves; persist all results
OutcomeSaved --> Settling: calculate returns per player
Settling --> Settled: all reservations reconciled
PlayerTurns --> Refunding: approved abort before outcome
DealerTurn --> RecoveryPending: interrupted/uncertain dealer result
OutcomeSaved --> RecoveryPending: transaction uncertain
RecoveryPending --> Settling: resume durable results
Refunding --> Settled: refunds committed
Settled --> Waiting: next hand
flowchart TD
A[Open table and accept bounded seats] --> B[Reserve each player's stake]
B --> C[Close betting and deal from injected deck source]
C --> D[Persist hands and ordered active turn]
D --> E{Current player's action}
E -->|Hit| F[Validate turn; deal and persist next state]
F -->|Below 21| E
F -->|Bust or 21| G[Advance turn]
E -->|Stand| G
G -->|More active players| E
G -->|No active players| H[Dealer resolves by approved rule]
H --> I[Persist full outcome before any payout]
I --> J[Settle every reserved stake idempotently]
J --> K[Privately send each player's result]
Private hand details must be sent only to the participant using a private whisper. A whisper is still reported as unconfirmed delivery. Public messages must not reveal hidden cards or sensitive text.
Implement the simplest approved dice game first. If full craps is selected, the come-out/point resolution and eligible bet types must be specified before coding. Do not call a single-roll game “craps” if its settlement rules differ.
stateDiagram-v2
[*] --> Idle
Idle --> Betting: start round
Betting --> ComeOut: bets reserved and betting closed
ComeOut --> OutcomeSaved: immediate win/loss result persisted
ComeOut --> PointEstablished: point established by approved rules
PointEstablished --> PointEstablished: roll neither point nor seven
PointEstablished --> OutcomeSaved: point made or seven-out
OutcomeSaved --> Settling: resolve eligible bets
Settling --> Settled: idempotent settlement complete
Betting --> Refunding: approved abort before first roll
OutcomeSaved --> RecoveryPending: settlement uncertain
RecoveryPending --> Settling: resume saved rolls/outcome
Refunding --> Settled: reservations refunded
Settled --> Idle
flowchart TD
A[Open betting window] --> B[Reserve each approved dice bet]
B --> C[Close betting]
C --> D[Roll with injected secure random source]
D --> E{Approved rules resolve now?}
E -- yes --> F[Persist final outcome]
E -- no --> G[Persist point and round state]
G --> H[Roll again on the next permitted step]
H --> E
F --> I[Calculate and idempotently settle all bets]
I --> J[Mark round settled and report result]
The planned separation is between pure card rules and an optional consequence adapter. A no-appearance card game may be tested first, but must not be advertised as a clothing-changing game. Any clothing consequence requires explicit opt-in and the third-party appearance feasibility gate below.
stateDiagram-v2
[*] --> Idle
Idle --> Consent: player requests a clothing-stakes game
Consent --> Idle: decline, timeout, or capability unavailable
Consent --> Reserved: explicit opt-in and approved stake reserved
Reserved --> Deal: round starts
Deal --> PlayerTurn: deal and privately expose player hand
PlayerTurn --> PlayerTurn: valid poker action
PlayerTurn --> Evaluate: hand complete
Evaluate --> OutcomeSaved: compare hands and persist winner
OutcomeSaved --> ChipSettlement: settle chip component
ChipSettlement --> ConsequencePending: approved clothing/forfeit outcome
ConsequencePending --> AwaitBCObservation: dedicated action dispatched
AwaitBCObservation --> Completed: matching later BC observation
AwaitBCObservation --> Unconfirmed: timeout, disconnect, or no matching state
Unconfirmed --> Reconcile: wait for fresh authoritative observation
Reconcile --> Completed: observed state reconciled
Reconcile --> RecoveryPending: still ambiguous; do not retry blindly
Deal --> Refunding: approved interruption before outcome
PlayerTurn --> Refunding: approved interruption before outcome
Refunding --> Idle: refund committed; no consequence claimed
flowchart TD
A[Player asks to play] --> B{Approved game and appearance capability enabled?}
B -- no --> X[Decline consequence; no wager accepted]
B -- yes --> C[Explain bounded rule and obtain explicit opt-in]
C --> D{Consent and stake valid?}
D -- no --> X
D -- yes --> E[Reserve chip stake or record approved stake intent]
E --> F[Play pure card rules; keep private hand private]
F --> G[Persist outcome before economic settlement]
G --> H[Settle chips idempotently]
H --> I[Request only approved dedicated appearance action]
I --> J{Later matching BC observation?}
J -- yes --> K[Record observed outcome]
J -- no --> L[Unconfirmed; stop and reconcile after fresh sync]
The player must not be labeled a cheater solely because clothing changes. BC state observations can show that an item/slot changed but do not necessarily prove why it changed or who caused it. Until authorized third-party mutations and safe interruption are proven, this game may use chips only or remain disabled.
stateDiagram-v2
[*] --> Lobby
Lobby --> ConsentAndBuyIn: player joins
ConsentAndBuyIn --> Lobby: decline, leave, or invalid stake
ConsentAndBuyIn --> Lobby: reserve each buy-in atomically
ConsentAndBuyIn --> RosterLocked: host starts with valid minimum roster
RosterLocked --> Deal: freeze rules version and turn order
Deal --> PlayerTurn: expose only each player's private hand
PlayerTurn --> PlayerTurn: valid current-player action
PlayerTurn --> Evaluate: round/hand completes
Evaluate --> OutcomeSaved: persist result before payouts/consequences
OutcomeSaved --> PotSettlement: distribute chips idempotently
PotSettlement --> ConsequencePending: if explicitly opted-in
ConsequencePending --> AwaitBCObservation: journaled action per target
AwaitBCObservation --> NextRound: all required outcomes observed or policy resolved
AwaitBCObservation --> RecoveryPending: ambiguous/unconfirmed appearance result
PlayerTurn --> DisconnectPolicy: participant leaves or deadline expires
DisconnectPolicy --> PlayerTurn: approved forfeit/stand rule
DisconnectPolicy --> Refunding: approved cancel/refund rule
RecoveryPending --> RecoveryPending: do not continue with uncertain appearance state
NextRound --> Deal: next hand if enough players remain
NextRound --> Settled: table closes
Refunding --> Settled: return all eligible reservations once
This game is not ready until its exact poker variant, private-hand delivery, turn/disconnect rules, multi-member pot transaction, consent lifecycle, appearance feasibility, and restart policy are individually approved and tested. Do not lock a roster or accept buy-ins before all required capabilities are available.
Treat cocktails, outfit props, and other approved cosmetic items as a separate shop flow, not as a gambling result. The shop uses a bounded catalog of validated cosmetic reward definitions. A purchase debits chips once and then applies any appearance effect only through the existing permission-aware appearance action. A cosmetic purchase is complete only when its economic debit and item-application outcome are both represented honestly.
For the first shop release, prefer rewards that do not mutate another player’s appearance and do not imply an unsupported BC effect. If application fails after debit, follow an explicit idempotent refund/retry policy; do not claim the item was granted from a chat reply alone.
flowchart TD
A[Player selects catalog reward] --> B[Validate enabled definition and price]
B --> C[Atomically debit chips and record purchase ID]
C --> D{Purchase already processed?}
D -- yes --> E[Return prior recorded status]
D -- no --> F[Apply cosmetic through approved appearance API if needed]
F --> G{Required BC observation received?}
G -- yes --> H[Mark reward observed]
G -- no --> I[Mark unconfirmed and reconcile; no blind repeat]
C -->|debit failed| J[No reward request]
The current appearance qualification surface is room-admin-only and self-targeted: the sender may mutate only their own character. This is not authority to change another member. A player opting in does not by itself prove that BC permits the bot to perform the mutation.
Before implementing any clothing/bondage stake or reward:
timed_out_unobserved/unconfirmed. Reconcile against a later authoritative
snapshot before any retry. Do not optimistically patch or automatically
reapply an outfit.The casino must never promise to detect intent from a state change. It can detect that observed appearance no longer matches an in-memory rule condition; it cannot infer that the player cheated rather than responding to another event. Consequences for that state must be specified as a neutral round interruption/settlement rule, not an automatic accusation.
The eventual command surface should use the shared parser and a dedicated
command suite (for example /bot casino balance, /bot casino play slots 10,
/bot casino join, /bot casino hit, /bot casino stand, and help). Exact
syntax is a UX decision and must be documented with the implementation.
CharacterCommunicationApi. Room-visible status must omit
private hands and sensitive details.PrototypeConfig, .env.example, README setup, and the feature plan
together. A feature should default off until its live qualification gate has
passed.| Situation | Required behavior |
|---|---|
| Invalid command or insufficient chips | Reject before reservation; no session mutation or payout. |
| Wallet transaction fails | Return explicit failure. Do not report an accepted bet. |
| Duplicate economic operation | Read the stable ledger key and return/reconcile its result; never apply a second delta. |
| Bot stops before outcome persistence | Apply only that game’s approved interruption/refund policy. |
| Bot stops after outcome persistence | Resume settlement from the saved outcome; never reroll. |
| Wallet/ledger transaction result uncertain | Check transaction/ledger/session evidence. Stay recovery-pending if evidence is insufficient. |
| BC disconnect or target leaves during a future appearance action | Stop subsequent actions; keep the action unconfirmed/failed as supported by observed evidence; do not retry from stale snapshots. |
| Plugin stop | Stop accepting commands, cancel timers/listeners, await safe in-flight persistence/action work, then allow normal host shutdown order to continue. |
| Startup recovery | Load only validated casino records after DB indexes/repositories initialize; wait for BcClient room readiness before using live participant observations. |
Persisted casino state is a recovery aid for economy and game rules; it is not an authority for current room membership, character appearance, lock ownership, or BC action completion.
Exit gate passed: Phase 0 contracts and backend topology are qualified. The read-only test topology evidence and operator confirmation establish shared backend transaction capability, not independent production credential or live transaction testing. Do not enable player wagering until the remaining Phase 2 product approvals are obtained; live qualification requires separate authorization.
Exit gate passed: tests cover overdraw prevention, idempotent reserve and settlement, transaction rollback, and recovery-record durability. Only the zero-balance wallet is player-facing; no player data is copied from Ropeybot. Phase 1 does not itself authorize wagering.
game type and runtime access requires
an enabled server-observed location with the expected shape.The documented baseline is offline-qualified at 95.4383735% theoretical RTP.
Configured slot changes are exhaustively checked against a code-level 99% ceiling.
The baseline preserves the 100x diamond and 500x seven jackpots; roulette payouts
cannot exceed standard European gross returns.
The operator confirmed successful live qualification and approved activation
on 2026-10-15. Funding, RNG, recovery,
supplied wager limits, and shared-backend topology are no longer unresolved
decisions. CASINO_GAMEPLAY_ENABLED is true; offline tests alone do not qualify
live BC or production Mongo credentials/transaction permissions.
Exit gate: rule tests cover edge cases and state transitions; concurrent commands cannot advance the same turn twice; hidden cards are never posted to room chat.
Exit gate: purchase debit/reward status is idempotent and any unobserved appearance effect is surfaced without automatic retry.
Exit gate: if any required permission/recovery case cannot be safely represented, stop this phase and keep clothing/bondage wagers disabled.
Exit gate: separate review of appearance authority, privacy, no-double-pay settlement, and all player-exit paths.
Use the repository’s built-in node:test + node:assert/strict patterns and
the existing tsx runner. Add each new test file explicitly to the npm test
script.
Follow temporal test notes. In particular:
RUNTIME_TARGET=test, BC_ROOM=Veratown2, and only
veratown_prototype_test. The fixed config/database pairing must remain
enforced.For each code-bearing phase, run the standard required gates:
npm run lint
npm run format:check
npm run check
npm test
npm run build
The build is required for source/API changes. Update the feature plan into an implemented feature guide only when runtime behavior is actually wired and qualified; keep documentation status honest.
When an approved phase is implemented:
src/features/casino/; do not place business rules in
core/ or BC adapters.src/app/start.ts; register the plugin
statically before CommandRouterPlugin.package.json.docs/features/casino/README.md only when there is implemented behavior to
describe.