veratown-prototype

Shower System Implementation Plan

Status: implementation complete; operator-reported live BC qualification passed on 2026-10-23. The operator reported testing commit 928f6f9 with a dedicated test account, a non-production room, RUNTIME_TARGET=test, and veratown_prototype_test. The report is not independently observed by the assistant. The feature remains disabled by default. This plan ports the useful Ropeybot shower flow (~/repo/ropeybot/bin/games/veratown/showerSystem.ts) without carrying over its second-connection design or bypassing the prototype’s appearance permissions and action journal.

Observation requirement revised, 2026-10-23: matching inbound BC room updates are sufficient, loosely correlated state evidence. The current local snapshot can establish the starting appearance or already_satisfied; a later matching update can establish observed. Independent helper corroboration and an additional per-step confirmation are not required. Permissions, target/state matching, interruption handling, and unobserved timeouts remain enforced.

Outcome

A room participant who enters an enabled shower location can run one serialized shower sequence: the bot performs a permission-checked clothing-only change, narrates the shower, selects an enabled song from MongoDB, and restores the participant’s original supported clothing after completion. Room admins manage the feature settings and song catalog through /bot world shower .... The shower coordinates are ordinary enabled veratownLocations records with type: "shower".

The sequence is opt-in at feature level and does nothing on startup position seeding, for disabled features/locations, or when the required appearance permission is denied or unknown. The operation is per-member serialized and re-checks that the participant remains on an enabled shower tile between steps.

Non-negotiable feasibility gate

The current appearance qualification surface restricts appearance mutations to the bot’s own character. Ropeybot’s third-party strip/redress behavior must not be ported by weakening that rule or emitting raw BC packets. SWR-01 must prove from the pinned BC protocol and permission behavior that an explicitly authorized, journaled change to another character is supported before the clothing-changing behavior is enabled or deployed beyond the isolated prototype. If not, stop the mutation work and return for a product decision; the compliant fallback is a narration-only shower, not an implicit permission bypass.

The product owner authorized committing and opening the PR before qualification on 2026-10-23; the operator subsequently reported passing qualification that day. This record does not authorize tests with a production BC account or production database.

The original clothing snapshot may exist only in bounded in-memory session state; appearance payloads must not be logged, journaled, or persisted. The feasibility task must also demonstrate a safe interruption strategy within that restriction. Do not claim the system can recover the original clothing after a process crash unless a compliant recovery design is approved.

Functional Use Case Map

flowchart LR
    Participant[Room participant]
    Admin[Room admin]
    WorldAdmin[WorldAdminCommandSuite]
    Shower[Shower feature]
    Locations[(veratownLocations)]
    Config[(prototypeShowerConfig)]
    Songs[(prototypeShowerSongs)]
    BC[BC observed room and appearance state]
    Actions[Journaled shower actions]

    Admin -->|create / move / enable / disable type=shower| WorldAdmin
    WorldAdmin -->|existing world location CRUD| Locations
    Admin -->|show / configure / manage songs| WorldAdmin
    WorldAdmin -->|injected shower administration contract| Shower
    Shower --> Config
    Shower --> Songs
    Participant -->|enters an enabled shower tile| BC
    BC -->|core locationEntered transition| Shower
    Shower -->|permission check and observed clothing snapshot| BC
    Shower -->|remove / narrate / restore| Actions
    Actions -->|dedicated actions via single BC client| BC
    Shower -->|re-check location and observed state| BC

Use cases and acceptance

ID Actor / trigger Expected behavior
UC-01 Room admin configures the feature /bot world shower show displays the validated room-scoped settings; set operations validate bounds and persist through the shower administration service. Unauthorized callers receive no write path.
UC-02 Room admin manages shower tiles Existing /bot world location create | edit | deletemanages a point location of typeshower; its persisted enabledstate and(x,y) determine whether it triggers. No parallel shower-tile collection or static coordinate fallback is introduced.
UC-03 Room admin manages songs Admin commands list, add, edit, enable, and disable bounded song documents; runtime selection uses only enabled songs. No legacy lyric catalog is copied without rights review.
UC-04 Participant enters a shower tile Only a real entry transition (firstObservation === false) to an enabled shower location, while the feature is enabled, starts a sequence. Initial sync/reconnect seeding does not trigger one.
UC-05 Shower sequence runs The feature checks permission, captures only supported clothing in memory, removes clothing through a dedicated journaled action, sends narration through the injected communication port, chooses a persisted enabled song, then restores the saved supported clothing through journaled actions.
UC-06 Participant leaves, disconnects, or an action is unconfirmed Stop future narration/mutations. Never continue from stale observations, retry blindly, or claim an unobserved appearance change. Attempt only a permission-checked, state-safe compensation while the same connection/observations still support it; otherwise surface an interrupted/recovery-required outcome without persisting appearance data.
UC-07 Admin changes settings or an operator updates Mongo Refresh validated settings without restart; stream failures are reported and do not become successful reloads. Location edits continue to use the existing map configuration reload path.
UC-08 Process shuts down or restarts Dispose subscriptions and timers, await in-flight work in plugin shutdown order, and do not resume a stale session from a database snapshot. Any residual appearance risk is explicitly reported and covered by the feasibility gate.

Proposed UML

Component and contract diagram

classDiagram
    direction LR
    class MapLocationEventBus {
        <<core contract>>
        +locationEntered(member, location, firstObservation)
    }
    class ShowerFeaturePlugin {
        +start()
        +stop()
        -dispose subscriptions and timers
    }
    class ShowerService {
        +enter(member, location)
        +cancel(member, reason)
        -serialize by member
    }
    class ShowerAdministration {
        <<core contract>>
        +show()
        +update(settings)
        +manageSong(command)
    }
    class ShowerRepository {
        <<feature port>>
        +loadConfig(room)
        +saveConfig(room, settings)
        +listEnabledSongs(room)
        +watchConfig(room, reload, onError)
    }
    class MongoShowerRepository
    class WorldAdminCommandSuite {
        +world shower show|set|song
    }
    class ShowerCommunicationPort {
        <<core contract>>
        +emote(text)
        +chatRedacted(text)
        +whisper(member, text)
    }
    class CharacterAppearanceSequenceApi {
        <<shared action contract>>
        +executeSequence(member, mutations, source, onPieceOutcome)
    }
    class BcAppearanceAction
    class CharacterCommunicationApi
    class ShowerCommunicationAdapter
    class ActionCoordinator
    class ActionJournal
    class BcClient
    class MongoDB

    MapLocationEventBus --> ShowerFeaturePlugin : core event
    ShowerFeaturePlugin --> ShowerService
    ShowerFeaturePlugin --> ShowerRepository : load/watch
    ShowerFeaturePlugin ..> ShowerCommunicationPort : injected
    WorldAdminCommandSuite ..> ShowerAdministration : injected core port
    ShowerAdministration <|.. ShowerService
    ShowerService ..> ShowerRepository
    MongoShowerRepository ..|> ShowerRepository
    MongoShowerRepository --> MongoDB
    BcAppearanceAction ..|> CharacterAppearanceSequenceApi
    BcAppearanceAction --> ActionCoordinator
    BcAppearanceAction --> BcClient
    ShowerCommunicationAdapter ..|> ShowerCommunicationPort
    ShowerCommunicationAdapter --> CharacterCommunicationApi
    ActionCoordinator --> ActionJournal
    CharacterCommunicationApi --> BcClient

The contracts shown in core/ remain transport- and database-independent. ShowerFeaturePlugin must not import features/map, features/world, features/communication, or features/appearance; the composition root injects core ports and owns all concrete wiring. The map feature emits the existing core location event, and world administration calls the injected shower-administration contract. Mongo collections and BC side effects each have one owner.

Shower execution sequence

sequenceDiagram
    actor P as Participant
    participant BC as BcClient observations
    participant Map as Map feature
    participant Bus as Core location event bus
    participant S as ShowerService
    participant Repo as MongoShowerRepository
    participant A as Shared BcAppearanceAction sequence
    participant C as Communication port
    participant J as ActionCoordinator / journal

    P->>BC: move onto map tile
    BC->>Map: observed map position
    Map->>Bus: locationEntered(member, type=shower, firstObservation=false)
    Bus->>S: enter(member, location)
    S->>Repo: load current room settings
    Repo-->>S: validated enabled settings
    S->>S: reject disabled, initial, duplicate, or invalid entry
    S->>BC: inspect current location and appearance permission
    BC-->>S: current observation / permission result
    alt permission denied, unknown, or missing BC observation
        S->>C: private refusal/status (when target is addressable)
    else permission allows reviewed mutation
        S->>BC: capture supported clothing snapshot in memory only
        S->>A: remove supported clothing
        A->>J: journal requested / dispatch / observation outcome
        A->>BC: guarded appearance update
        BC-->>A: later appearance observation or timeout
        A-->>S: truthful action outcome
        S->>C: emote shower-start narration
        S->>Repo: select enabled song
        Repo-->>S: selected song
        loop each timed phase
            S->>BC: confirm still on enabled shower location
            BC-->>S: current location observation
            S->>C: emote phase/song narration
        end
            S->>C: rinse/dry emotes
            S->>A: restore saved supported clothing
            A->>J: journal each state-changing action
            A->>BC: guarded appearance update
            BC-->>A: later appearance observation or timeout
            S->>H: confirm each restoration step
            S->>C: private completion whisper
        A-->>S: truthful action outcome
        S->>C: private completion notification
    end

UML state flow

stateDiagram-v2
    [*] --> Idle
    Idle --> EntryCandidate: locationEntered
    EntryCandidate --> Idle: firstObservation / disabled / not shower / invalid member
    EntryCandidate --> DuplicateSuppressed: member already has an active sequence
    DuplicateSuppressed --> Idle: prior sequence ends
    EntryCandidate --> PermissionCheck: enabled real entry
    PermissionCheck --> Refused: denied / unknown / unsupported capability
    PermissionCheck --> SnapshotCaptured: current observation and permission valid
    Refused --> Idle
    SnapshotCaptured --> RemovingClothing: snapshot retained in memory only
    RemovingClothing --> RemovingClothing: matching observation; next supported item
    RemovingClothing --> Narrating: all supported clothing removed and observed
    RemovingClothing --> Reconcile: failed / timed_out_unobserved / stale observation
    Narrating --> Narrating: delay elapsed and member remains on shower tile
    Narrating --> Restoring: narration phases complete
    Narrating --> Interrupted: leaves / disconnects / stop
    Restoring --> Restoring: matching observation; next supported item
    Restoring --> Completed: restored state observed
    Restoring --> Reconcile: failed / timed_out_unobserved / stale observation
    Interrupted --> Reconcile: safe same-session compensation may be attempted
    Reconcile --> Restoring: observed state permits guarded compensation
    Reconcile --> RecoveryRequired: safe compensation cannot be proven
    RecoveryRequired --> Idle: operator/participant handles state; no auto-resume
    Completed --> Idle

dispatched is never treated as an observed appearance change. An unconfirmed mutation stops the sequence until fresh BC state is available; no later item uses a stale appearance snapshot. The action layer remains the sole journal owner for each state-changing operation.

Data and Configuration Contract

Shower tiles

Continue using the existing room-scoped veratownLocations documents:

{ key, name, type: "shower", x, y, enabled, roomKey, ... }

type: "shower" is already in the core location vocabulary and exposed by world location CRUD. Confirm repository validation enforces the required point coordinates for enabled shower entries; tighten it only if that invariant is not already enforced. Disabled or absent shower locations never trigger. shower_bot_home is not required: this design uses one bot and never opens a second Socket.IO connection or moves a second narrator.

Feature settings and song catalog

Feature-owned collections in the selected runtime database:

World administration exposes room-admin-only commands such as /bot world shower show, /bot world shower set <setting> <value>, and /bot world shower song list|add|edit|enable|disable. Writes go through a transport-neutral shower administration contract/service and feature-owned repository, with private replies. Configuration watchers are disposed during shutdown; change-stream errors are surfaced. Keep production/test database selection pinned to the existing runtime guard. These runtime collections are not added to the source-database copy allowlist.

Executable Work Breakdown

Each ID below is a small implementation unit suitable for a GitHub issue or tracked task. Complete prerequisites first; keep commits independently green. The matching session task IDs use the same shower-NN-* identifiers.

ID Work item Depends on Completion evidence
SWR-01 Prove third-party appearance permission and interruption feasibility — Operator-reported live qualification passed on 928f6f9 using the test runtime; see the scope and case list below.
SWR-02 Define core shower ports, validated config, and pure session rules SWR-01 No cross-feature imports; pure tests cover location eligibility, defaults/bounds, duplicate sessions, cancellation, and outcomes.
SWR-03 Add room-scoped Mongo settings/song repository SWR-02 Typed collections, bounded validation, idempotent indexes, atomic updates, explicit errors, repository tests, and runtime-database guard coverage.
SWR-04 Add shower settings/song use cases to world administration SWR-02, SWR-03 Room-admin authorization per command/answer, strict parsing, private replies, CRUD tests, and live config reload tests.
SWR-05 Implement shower location event qualification and per-member ownership SWR-02, SWR-03 Uses only core locationEntered, ignores initial observation/disabled locations, suppresses overlap, rechecks tile, resets state on reconnect, and disposes cleanly.
SWR-06 Use the permission-checked shared appearance sequence API SWR-01, SWR-02 Clothing-only, non-owner mutation uses the existing action journal owner, matching BC room observations, per-character serialization, and no appearance payload logging/persistence.
SWR-07 Implement timed narration, song selection, completion, and interruption handling SWR-04, SWR-05, SWR-06 Injected communication actions only; delays/timers are injectable and cleared; no blind retries; completion/refusal/interruption status is truthful.
SWR-08 Wire the static plugin and resource lifecycle SWR-04, SWR-05, SWR-07 start.ts constructs/injects repository and ports, registers the plugin in order, and shutdown stops subscriptions/timers and drains in-flight work.
SWR-09 Complete behavior tests, operational docs, and qualification SWR-08 Targeted tests plus required repository checks pass; feature guide, architecture, README, UML, database ownership, and dedicated-account test checklist agree.

Dependency graph

flowchart LR
    S1[SWR-01 permission and recovery gate] --> S2[SWR-02 core contracts and rules]
    S2 --> S3[SWR-03 Mongo config and songs]
    S2 --> S4[SWR-05 location runtime]
    S2 --> S6[SWR-06 appearance actions]
    S3 --> S4A[SWR-04 world admin]
    S3 --> S7[SWR-07 sequence orchestration]
    S4 --> S7
    S6 --> S7
    S4A --> S7
    S7 --> S8[SWR-08 composition and lifecycle]
    S8 --> S9[SWR-09 validation and docs]

Per-work-item implementation checklist

SWR-01 — Permission and interruption feasibility

SWR-02 — Core contracts and pure rules

SWR-03 — Mongo settings and songs

SWR-04 — World administration integration

SWR-05 — Location runtime

SWR-06 — Appearance action sequence

SWR-07 — Sequence orchestration

SWR-08 — Composition and lifecycle

SWR-09 — Verification, docs, and qualification

Scope and Explicit Non-Goals

Documentation to update when implementation begins