veratown-prototype

Hot Seat

Hot Seat is a room-scoped, opt-in bluffing game. It is wired as an independent plugin but is disabled by default. Startup inserts a disabled room configuration and ten approved English starter prompts when absent. Existing configuration, enabled state, prompt edits, and moderation decisions are preserved.

The game evaluates a respondent’s private truth/bluff declaration against participants’ votes. It does not verify whether an answer is factually true. The respondent writes their own answer in room chat; the bot never receives, copies, logs, or stores that answer or a transcript.

Only current BC room administrators can change the configuration. Before enabling, the administrator must confirm that the room’s policy makes this an adults-only, opt-in activity. The bot does not infer, verify, or collect age.

Use native /bot commands or a private Whisper; chat and emote command forms are rejected so mode declarations and votes are not exposed:

/bot hotseat config show
/bot hotseat config enable confirm-adults-only <revision>
/bot hotseat config set minPlayers 3 <revision>
/bot hotseat config set minVotes 2 <revision>
/bot hotseat cancel
/bot hotseat config disable <revision>

Global and scoped help show Hot Seat commands only while the room config is enabled. While disabled, that also hides the admin setup/configuration help; the commands remain registered so room admins can use the documented paths to enable it.

Every write supplies the current configuration revision and uses a compare-and- set update. The first write uses revision 0. A conflict writes nothing; inspect the latest revision and retry. The Mongo adapter shares only the revision-CAS and optional-field clearing mechanics with Staged Table; this feature retains its own config/session validation and room isolation.

Settings are strictly validated:

Setting Default Bounds
minPlayers 3 3–12
maxPlayers 12 3–12 and at least minPlayers
answerWindowMs 120000 30000–300000
voteWindowMs 90000 30000–300000
minVotes 2 1 through maxPlayers - 1
bluffMultiplier 2 2–3
refusalPolicy no_penalty no_penalty, forfeit_available
timeoutPolicy no_penalty no_penalty, forfeit_available

An active round keeps its saved settings and configuration revision; admin changes apply to the next round. A room administrator may disable future rounds without changing an active round. /bot hotseat cancel releases an abandoned lobby only; it cannot cancel a started round.

Prompts

Trusted operators manage prototypeHotSeatPrompts directly in the selected, isolated runtime database. There is no in-game prompt authoring command. The repository validates each document and selects only moderationStatus: "approved" prompts with locale en; a missing or malformed approved prompt fails closed. Prompt text is limited to 250 characters. Records also require a bounded prompt ID, category, locale, positive contentRevision, and createdAt / updatedAt dates.

Review prompt content before setting it approved. Prompts must be appropriate for the adults-only room and must not request identifying, non-consensual, or otherwise unsafe personal disclosures. The bundled starter catalog uses non-explicit romantic-comedy scenarios and preferences suitable for truth/bluff declarations. Use the party-game provisioning workflow for dry-run-first population and explicit adults-only activation.

Round flow

  1. Each participant privately runs /bot hotseat join. This creates or joins a room lobby; the bot is never eligible.
  2. A joined, present participant runs /bot hotseat start. The command checks the enabled room config, current room presence, player bounds, and approved prompt availability. It freezes the current opted-in roster and randomly selects one respondent and one approved prompt.
  3. The bot posts the curated prompt to room chat and privately tells the respondent to answer in chat and then declare /bot hotseat mode truth or /bot hotseat mode bluff. The respondent may instead privately run /bot hotseat refuse.
  4. When mode is declared, only the other frozen participants may privately run /bot hotseat vote true or /bot hotseat vote lie. Each can submit one vote; it cannot be changed. Departed voters cannot vote while absent, and new arrivals are not part of the round.
  5. At the persisted deadline, fewer than minVotes voids the vote without an economic outcome. A strict lie majority exposes a declared bluff; a tie or true majority means the bluff fooled the room. A declaration of truth receives no bluff reward or forfeit. The result is described as a room vote, never as fact verification.

If the respondent leaves before declaring or refuses, the round closes without collecting their answer. Refusal and response timeout have independent policies; both default to no penalty. A configured forfeit_available timeout/refusal clears only available credits. Voters receive no reward.

An administrator can cancel an abandoned lobby before a round starts. Lobby membership is refreshed against current BC room observations when a participant joins or starts, so departed lobby members do not reserve player slots.

Credits and persistence

The shared EconomyPort owns accounts and ledger entries. An exposed bluffer forfeits available credits only; reserved credits from unrelated games remain untouched. A fooled bluffer receives the configured multiplier reward, bounded by a hard available-credit ceiling of 100,000. The ceiling is enforced atomically by the economy repository. A zero or ceiling-blocked award is reported as not applied, not as a successful payout. Stable operation IDs make settlement retries idempotent.

Collection Owner Retention
prototypePartyGameConfigs Hot Seat repository for <roomKey>:hot-seat Revisioned room config; no TTL
prototypeHotSeatPrompts Trusted operator Operator-managed; no TTL
prototypeHotSeatSessions Hot Seat repository Active sessions have no TTL; terminal sessions expire after 30 days
prototypeEconomyAccounts / prototypeEconomyLedger Shared economy See the economy guide

Session records contain a bounded member-number roster, selected respondent, prompt ID/revision, pinned settings revision, phase/revision, private intent, bounded votes, deadlines, outcome, and settlement operation metadata. They do not contain answer text, prompt text, or chat transcripts. A unique active-room key and revision-checked transitions prevent concurrent rounds and stale callbacks from advancing the same round twice. Deadlines are persisted; unref’ed timers are canceled on shutdown and rebuilt from active sessions at startup. Pending settlement is retried with the same operation ID after restart.

Runtime diagrams

flowchart LR
    Root["start.ts"] --> Plugin["HotSeatPlugin"]
    Plugin --> Commands["HotSeatCommandSuite"]
    Plugin --> Service["HotSeatService"]
    Commands --> Service
    Service --> Repo["MongoHotSeatRepository"]
    Service --> Economy["EconomyPort"]
    Commands --> PrivateReply["Injected private-reply capability"]
    Repo --> Config[("prototypePartyGameConfigs")]
    Repo --> Prompts[("prototypeHotSeatPrompts")]
    Repo --> Sessions[("prototypeHotSeatSessions")]
stateDiagram-v2
    [*] --> Lobby: enabled + explicit joins
    Lobby --> Response: min current players + approved prompt
    Response --> Voting: private truth/bluff declaration
    Response --> Complete: no-penalty refusal / departure / timeout
    Response --> Settling: configured refusal or timeout forfeit
    Voting --> Voting: one private vote per eligible participant
    Voting --> Complete: deadline below quorum / truthful declaration
    Voting --> Settling: quorum resolves declared bluff
    Settling --> Complete: idempotent economy result recorded
    Settling --> Settling: restart retries same operation
    Complete --> [*]

The service persists the terminal round outcome before settlement. The economy operation uses a stable session-derived ID; a restart retries that same operation and cannot forfeit or grant twice.