veratown-prototype

Anonymous Whisperer

Status: Implemented as Variant B and disabled by default in new databases. Enabling it is a separate, room-specific operator decision; database provisioning does not establish live-runtime qualification.

Anonymous Whisperer is a room-scoped guessing game for adults. Participants opt in, one participant privately answers a curated prompt, and the bot publishes that answer without naming its author. Other opted-in participants may each accuse one present room member. A correct accusation identifies the submitter; otherwise a configured one-time credit bonus is awarded only when the accusation quorum is met.

Commands

Commands work as !whisperer ... or /bot whisperer ..., with submissions as the sole private-only exception:

Command Behavior
!whisperer join Confirm adult status and opt in for the next round.
!whisperer leave Withdraw before a round starts.
!whisperer start Start a round as the submitter after enough opted-in players are present.
!whisperer submit I CONSENT TO PUBLISH: <response> Send as a direct private Whisper to the bot before the submission deadline.
!whisperer accuse <memberNumber> Accuse one present room member by positive member number.

The bot privately dispatches one selected database prompt to the submitter; delivery is unconfirmed. Each round snapshots the opted-in participant roster. The submitter cannot accuse; accusers must be different participants and must still be present. The bot, the accuser, absent targets, and duplicate accusations are rejected.

Room configuration

Startup idempotently creates a disabled default in the selected runtime database:

The prompt-based party games share the unique { roomKey: 1, gameId: 1 } configuration index. New databases use party_game_config_room_game; startup also accepts the legacy whisperer_room_game_config name with the same keys and unique option. Neither existing indexes nor configuration documents are replaced.

The default round settings are three minimum players, twenty maximum players, two-minute submission and accusation windows, a 280-character submission limit, a two-accusation quorum, a 10-credit bonus, and disabled follow-up. Code-level bounds are three to twenty players, 30 seconds to ten minutes per window, 280 Unicode characters and 1,024 UTF-8 bytes per submission, and zero to 100 bonus credits. Invalid configuration fails closed. The game also stays disabled unless adultsOnlyRoomConfirmed is explicitly true.

For an approved test-room enablement, update only the fixed test runtime database’s seeded document, increment its revision, and restart the runtime so the setting is reloaded:

db.prototypePartyGameConfigs.updateOne(
    { _id: "main:anonymous-whisperer", revision: 1 },
    {
        $set: {
            enabled: true,
            adultsOnlyRoomConfirmed: true,
            revision: 2,
            updatedAt: new Date(),
        },
    },
);

Use the exact database selected by RUNTIME_TARGET; never use the source database. Production enablement requires separate operator review and qualification. Runtime config changes are read at startup, not watched live. followupMode currently supports only disabled.

The party-game provisioning workflow can populate and explicitly activate all five prompt-based games in one approved runtime database. It preserves existing settings and prompt edits, checks catalog readiness, and increments existing config revisions only when activation changes their state. A restart is required for Whisperer to reload its configuration.

Curated prompt catalog

Startup seeds these ten reviewed, non-identifying adult conversation prompts into prototypeWhispererPrompts using stable IDs adult-01 through adult-10. Existing prompt records are preserved on later startups. A round chooses one enabled prompt; the submitter supplies a response, not a prompt ID.

  1. What quality can make someone immediately more attractive to you?
  2. What kind of flirtatious gesture do you find charming?
  3. What would your ideal date-night atmosphere feel like?
  4. What kind of compliment would make you blush?
  5. What small sign of confidence tends to catch your attention?
  6. What romantic setting would you enjoy sharing with a partner?
  7. What is a playful, respectful way to start a conversation with you?
  8. What makes chemistry feel mutual and comfortable to you?
  9. What boundary do you appreciate people respecting when flirting?
  10. What would make a bold but respectful invitation appealing to you?

Prompt documents are bounded and validated at the repository edge. Review changes before enabling prompts; never put player submissions or private information in the curated catalog.

Persistence, recovery, and settlement

prototypeWhispererSessions stores room/config metadata, prompt ID, participant and accusation member numbers, deadlines, phase, outcome, bonus metadata, stable settlement ID, and timestamps—never submission text. A unique sparse active-room key and revision compare-and-set transitions prevent parallel rounds and duplicate timer/vote outcomes. Terminal sessions expire after 30 days; pending bonuses remain durable until settled.

prototypeWhispererLeases holds one renewable owner lease per room. The lease is renewed every ten seconds and expires after 30 seconds. A second process cannot serve the same room while the lease is valid.

flowchart LR
    Root["start.ts"] --> Plugin["AnonymousWhispererPlugin"]
    Plugin --> Commands["WhispererCommandSuite"]
    Plugin --> Input["WhispererSubmissionHandler"]
    Plugin --> Service["WhispererService"]
    Commands --> Service
    Input --> Service
    Service --> Repo["MongoWhispererRepository"]
    Service --> Economy["EconomyPort"]
    Service --> Comms["WhispererCommunicationPort"]
    Repo --> Config[("prototypePartyGameConfigs")]
    Repo --> Prompts[("prototypeWhispererPrompts")]
    Repo --> Sessions[("prototypeWhispererSessions")]
    Repo --> Lease[("prototypeWhispererLeases")]
    Service -. "bounded ephemeral submission only" .-> Memory["Process memory"]
stateDiagram-v2
    [*] --> Disabled
    Disabled --> Lobby: enabled config + adults-only confirmation
    Lobby --> Submission: enough opted-in members; lease held
    Submission --> Accusation: valid private consented response dispatched
    Submission --> Voided: timeout / author leaves / restart / disconnect / lease loss
    Accusation --> Identified: correct observed-member accusation
    Accusation --> Voided: deadline without quorum
    Accusation --> BonusPending: quorum; no correct accusation
    BonusPending --> Complete: stable idempotent grant applied or replayed
    BonusPending --> BonusPending: grant failure; retry same operation ID
    Identified --> Complete
    Voided --> Complete
    Complete --> [*]

Disconnect, graceful shutdown, lease loss, and process restart void an active round, clear the in-memory submission, and do not award a bonus. After a restart, the old text is not reconstructed from BC history. A durable bonus-pending outcome is retried with the same economy operation ID. New rounds are blocked while a previous bonus remains unsettled. A missing accusation quorum voids the economic result; a correct guess identifies the author immediately and never earns a bonus. Plug-in shutdown still calls the service to release its lease if a listener or command disposer fails; cleanup errors are reported together.

Collections

Collection Owner Contents / retention
prototypePartyGameConfigs Whisperer repository Typed room config; disabled baseline; no TTL.
prototypeWhispererPrompts Whisperer repository Curated prompts and revisions; no TTL.
prototypeWhispererSessions Whisperer repository Metadata only; terminal records have 30-day TTL; pending bonuses remain durable.
prototypeWhispererLeases Whisperer repository Per-room owner and lease expiry; lease is application-enforced, not TTL-deleted.
prototypeEconomyAccounts / prototypeEconomyLedger Shared economy Submitter award through grantOnce; stable session-derived operation ID and approved whisper_bonus reason.

References