veratown-prototype

Lock management proposal

Status: Partially implemented. The shared appearance adapter discovers all 18 pinned BC lock assets and permits mutations for seven reviewed types. This document remains active because the other lock policies and live qualification are not complete; see the appearance guide for the implemented contract.

Purpose and scope

Provide one reusable, validated way for workflows to apply a BC lock to a character appearance item. The feature-neutral mutation contract is:

await appearance.execute(memberNumber, {
    operation: "lock",
    item: { group: "ItemArms", name: "HeavyYoke" },
    lock: {
        type: "TimerPadlock",
        options: { durationMs: 5 * 60_000, removeItemOnExpiry: false },
    },
});

The caller selects the target, item, lock, and supported options. The shared BC adapter resolves lock capabilities, validates current item and lock state, creates the canonical appearance mutation, dispatches it once, and reports the strongest BC observation available. Credential-bearing locks use the separate CharacterAppearanceLockApi.executeLock path so secrets never enter mutation documents or itemsets.

Scope assumption: “item” means an item in a character’s appearance, not a room map object, door, inventory stock count, or account-level setting. This proposal does not add a general-purpose lock command or enable automated gameplay behavior; the appearance qualification command remains test-only.

What BC means by a lock

At the pinned BC revision, the lock is an ItemMisc asset attached to an appearance item. The target item’s properties carry LockedBy and lock-specific fields; the lock itself is not a separate room object and there is no generic wire-level “lock item” request. InventoryLock checks that the selected asset is a lock and that the item’s current asset/configuration allows locks, then adds the lock metadata. The server validates the submitted appearance update.

The valid target is therefore an existing appearance item whose asset has AllowLock enabled. A typed or modular item can further restrict lockability to particular selected options through AllowLockType. PortalLinkPadlock has an additional PortalLinkLockable attribute requirement and is disabled in the general asset definition at this revision. The actual browser UI may also require inventory availability and interaction/relationship permissions; a catalog entry alone does not prove that a bot can apply the lock or consume an inventory item.

BC lock types at the pinned revision

The complete AssetLockType union contains 18 names. Timer values below are the asset-definition MaxTimer values, not unconditional guarantees: BC normalizes an expiry that exceeds the lock asset’s maximum and consults the target’s online LockTimerLimit for that normalization. BC’s observed state is authoritative.

BC lock type BC capability and relevant options Where / when it applies
MetalPadlock Standard keyed lock; the matching inventory key is MetalPadlockKey. Any currently lockable appearance item; no lock-specific timer or relationship flag in the definition.
IntricatePadlock Pick difficulty 7; has ExclusiveUnlock behavior and records the applying member. Any lockable item, subject to the browser’s exclusive-unlock/key behavior. It has specialized browser hooks; do not model it as a plain key lock.
HighSecurityPadlock Pick difficulty 10; ExclusiveUnlock; MemberNumberListKeys stores eligible keyholder member numbers. Any lockable item. Keyholder-list editing and permission semantics need explicit support; the list is not a generic allow-list for other lock types.
TimerPadlock Timer lock; definition has MaxTimer 300 seconds and RemoveTimer default 300 seconds. Supports RemoveItem on expiry. Any lockable item. BC’s effective timer limit may differ from the nominal five-minute maximum.
CombinationPadlock Four-digit CombinationNumber (0000 is the baseline); BC permits lock inspection while blind. Any lockable item. Combination configuration is sensitive and must use BC’s format.
PasswordPadlock Password is 1–8 uppercase letters; Hint, LockSet, and RemoveOnUnlock are lock-specific properties. Any lockable item. Requires a deliberate credential setup; the baseline value is not a user-selected secret.
TimerPasswordPadlock Password-style lock with timer; nominal MaxTimer 14,400 seconds. Also supports RemoveItem, ShowTimer, EnableRandomInput, and MemberNumberList. Any lockable item. Credential and timer settings must both be validated; timer controls are not all equivalent to arbitrary expiry writes.
OwnerPadlock OwnerOnly; matching OwnerPadlockKey; ownership and self-lock rules apply. Only where the target/actor relationship satisfies BC owner-lock validation.
OwnerTimerPadlock OwnerOnly; nominal MaxTimer 3,024,000 seconds (35 days); timer controls include RemoveItem, ShowTimer, EnableRandomInput, and MemberNumberList. Owner-lock rules apply, plus BC timer-limit handling.
LoversPadlock LoverOnly; matching LoversPadlockKey; lover relationship rules apply. Only where BC recognizes the required lover relationship.
LoversTimerPadlock LoverOnly; nominal MaxTimer 604,800 seconds (7 days); timer controls as for the other relationship timer locks. Lover relationship and timer-limit rules both apply.
FamilyPadlock FamilyOnly; matching FamilyPadlockKey; family relationship rules apply. Only where BC recognizes the required family relationship.
MistressPadlock Matching MistressPadlockKey; no OwnerOnly, LoverOnly, FamilyOnly, or timer flag in the asset definition. A distinct BC lock/key path. Do not infer relationship permissions from its name.
MistressTimerPadlock Matching MistressPadlockKey; nominal MaxTimer 14,400 seconds (4 hours), with timer controls. No relationship-only flag in the asset definition. Distinct BC lock/key path plus timer-limit handling.
PandoraPadlock Matching PandoraPadlockKey; extended configuration is copied from MistressPadlock. No timer or relationship-only flag in the definition. Specialized BC/game inventory path; not a generic alias for MistressPadlock.
ExclusivePadlock Specialized browser unlock rule: BC’s DialogCanUnlock does not allow the wearer to unlock their own item through the usual check. Any otherwise lockable item only when BC’s special interaction semantics are intended and qualified.
SafewordPadlock Uses the password-lock configuration/UI hooks with a distinct safeword lock path. Password-shaped properties include Password, Hint, and LockSet. Any lockable item, but safeword semantics must remain BC-owned; do not treat it as an ordinary password lock.
PortalLinkPadlock Disabled in the general asset definition; InventoryLock and server validation require PortalLinkLockable. Portal Link system only. Exclude from general-purpose appearance lock selection.

Timer locks in this list have a definition-level RemoveTimer default of 300 seconds. That default is not the same as a caller-selected duration. The relevant lock assets also declare RemoveItem behavior, and some timer-lock types have additional timer display/input controls. The proposal should expose only options validated for the selected type, not arbitrary BC property names.

Lock-option inventory

The pinned BC property declarations identify these lock-specific values:

Option family BC properties Types / caveats
Timer RemoveTimer, RemoveItem, ShowTimer, EnableRandomInput, MemberNumberList RemoveItem is used by the timer locks. Display/input/member-list controls are only documented for selected timer-lock types. The server may normalize the requested timer.
Password Password, Hint, LockSet, RemoveOnUnlock Password is 1–8 uppercase letters. RemoveOnUnlock is for PasswordPadlock; password and safeword setup must not be exposed as ordinary logged command arguments.
Combination CombinationNumber CombinationPadlock only; exactly four digits.
Authorized keyholders MemberNumberListKeys HighSecurityPadlock only; BC serializes the member-number list as a string.
Lock provenance / runtime LockedBy, LockMemberNumber, LockMemberName, LockMessage, LockPickSeed, Effect BC-owned state. Never accept these as caller-provided generic options. LockMessage also has feature-specific uses.

MemberNumberList and MemberNumberListKeys are distinct BC properties with different semantics. Their meaning must not be collapsed into one generic “allowed users” option.

Keep the feature-facing contract in core/ and BC-specific capability discovery/validation in the BC adapter. Features must not import each other or construct packets. The appearance feature remains responsible for user intent, authorization, and presentation; it does not own lock rules or BC mutation mechanics.

The CharacterAppearanceApi and AppearanceMutation model the general appearance operations. CharacterAppearanceLockApi adds a separate, ephemeral-secret input for credentials. BcAppearanceAction lives in the BC adapter and implements both API ports, keeping the executor feature-neutral while retaining its per-character queue, observation wait, cancellation, and single ActionCoordinator journal lifecycle.

Add a BC lock capability catalog beside the existing BC asset catalog. Derive basic facts from pinned asset metadata (IsLock, AllowLock, AllowLockType, OwnerOnly, LoverOnly, FamilyOnly, Enable, ExclusiveUnlock, PickDifficulty, MaxTimer, RemoveTimer, and baseline properties). Add a reviewed support policy for browser-specific hooks and special cases. Discovery of an upstream asset must not automatically enable headless mutation: unknown or unresolved behavior fails closed.

Use a typed, per-lock option schema at the BC boundary. The public request uses semantic fields such as duration, remove-on-expiry, timer presentation, password hint, or keyholder members; the adapter translates those fields to BC property names. Validate exact type, bounds, target relationship evidence, item lockability, selected typed/modular option, existing lock state, and special lock preconditions before dispatch. Reject replacing a different lock or silently reconfiguring a lock. If same-lock renewal is ever supported, make it an explicit policy with a test.

Do not persist or journal passwords, combinations, or appearance payloads. Never place a secret in a command string, itemset document, action desired metadata, debug output, or exception text. Journal only reviewed non-secret lock intent. BC observations can contain lock properties; keep them in memory for comparison and redact them from logs/journals.

Proposed UML: feature-neutral component boundary

classDiagram
    direction LR
    class AppearanceFeature {
        +request appearance lock
        +authorize caller
    }
    class FutureAppearanceWorkflow {
        +request appearance lock
    }
    class CharacterAppearanceApi {
        <<core port>>
        +execute(member, mutation) ActionOutcome
    }
    class CharacterAppearanceLockApi {
        <<core port; secrets are ephemeral>>
        +executeLock(member, request, secrets?) ActionOutcome
    }
    class BcAppearanceAction {
        <<shared technical implementation>>
        -per-character queue
        +execute(member, mutation) ActionOutcome
        +executeLock(member, request, secrets?) ActionOutcome
    }
    class BcAppearanceCodec {
        +plan(character, mutation, actor)
        +matches(observed, desired)
    }
    class BcLockCapabilityCatalog {
        <<pinned BC metadata plus reviewed support policy>>
        +get(type) LockCapability
        +validateOptions(type, options)
    }
    class ActionCoordinator {
        +executeObserved(request) ActionOutcome
    }
    class BcClient {
        <<transport adapter>>
        +updateCharacterAppearance(...)
        +getAppearanceObservation(member)
    }
    class CompositionRoot {
        +construct shared services
        +inject ports into plugins
    }

    AppearanceFeature --> CharacterAppearanceApi
    FutureAppearanceWorkflow --> CharacterAppearanceApi
    CharacterAppearanceApi <|.. BcAppearanceAction
    CharacterAppearanceLockApi <|.. BcAppearanceAction
    BcAppearanceAction --> BcAppearanceCodec
    BcAppearanceAction --> BcLockCapabilityCatalog
    BcAppearanceAction --> ActionCoordinator
    BcAppearanceAction --> BcClient
    CompositionRoot --> BcAppearanceAction : constructs and injects

Proposed UML: lock application sequence

sequenceDiagram
    actor Feature
    participant API as CharacterAppearanceApi
    participant Action as Shared BcAppearanceAction
    participant Catalog as BcLockCapabilityCatalog
    participant Codec as BcAppearanceCodec
    participant Journal as ActionCoordinator
    participant BC as BcClient / BC

    alt credential-free lock
        Feature->>API: execute(lock mutation)
    else password or combination lock
        Feature->>API: executeLock(request, ephemeral secrets)
    end
    API->>Action: validated mutation and separate ephemeral secrets
    Action->>BC: query interaction/item access
    BC-->>Action: allowed / denied / unknown
    Action->>BC: read latest observed appearance
    Action->>Catalog: resolve type and validate options
    Catalog-->>Action: supported capability or explicit rejection
    Action->>Codec: validate item, selected option, permissions, existing lock
    Codec-->>Action: planned full appearance bundle
    Action->>Journal: requested lifecycle
    Action->>BC: guarded full appearance update
    BC-->>Action: later appearance observation (if received)
    Action->>Journal: observed / timed_out_unobserved / failed
    Action-->>Feature: ActionOutcome

Proposed UML: action lifecycle

stateDiagram-v2
    [*] --> ValidateRequest
    ValidateRequest --> Rejected: unknown lock / malformed options
    ValidateRequest --> CheckObservedItem: valid request
    CheckObservedItem --> Rejected: missing / occupied / not lockable
    CheckObservedItem --> CheckBCPermission: current observed item valid
    CheckBCPermission --> Rejected: denied / unknown / relationship unsupported
    CheckBCPermission --> Plan: allowed
    Plan --> AlreadySatisfied: observed lock already matches
    Plan --> JournalRequested: planned mutation
    JournalRequested --> Rejected: journal unavailable
    JournalRequested --> Dispatch: journaled
    Dispatch --> AwaitObservation: packet emitted
    Dispatch --> Failed: cancelled / stale appearance
    AwaitObservation --> Observed: later full appearance matches
    AwaitObservation --> TimedOutUnobserved: no matching evidence
    AwaitObservation --> Failed: disconnect / target leaves / stop

An observed result means room-state convergence, not proof that BC persisted the character profile. No response must remain timed_out_unobserved; do not retry a potentially applied appearance mutation against stale state.

Current implementation and qualification gaps

BcLockCapabilityCatalog discovers all 18 source-declared IsLock assets. Discovery is deliberately separate from mutation policy: the first enabled types are MetalPadlock, IntricatePadlock, TimerPadlock, TimerPasswordPadlock, ExclusivePadlock, CombinationPadlock, and PasswordPadlock. Other locks remain inspectable but are rejected with explicit reasons until their relationship, keyholder, credential, portal, or inventory semantics are reviewed. Intricate and Exclusive lock application is supported; BC remains authoritative for their specialized key and unlock behavior.

Lock requests use AppearanceLockSelection with generic semantic options. Duration is relative milliseconds and is checked against the selected lock’s pinned MaxTimer; the adapter maps it to BC’s absolute RemoveTimer. Itemsets can configure timer duration, RemoveItem, and ShowTimer only when the lock policy allows them. Expiry overrides are converted to durations for any supported timer lock.

Password and combination input travels only through the separate executeLock(..., secrets) method. Explicit password/combination locks are not itemset-supported. TimerPasswordPadlock may receive a cryptographically generated, ephemeral password so Bunny itemsets do not contain credentials. Secrets and full appearance properties are excluded from journal metadata. Unit and fake-socket integration coverage verifies the contract, redaction, option mapping, and all-18 discovery. Intricate and Exclusive lock application passed live BC qualification; this does not establish account-profile persistence.

Owner, lover, family, high-security, mistress, Pandora, safeword, portal-specific, and other specialized locks remain unsupported. Do not broaden mutation support by accepting arbitrary Property fields or assuming that a syntactically valid appearance bundle will pass BC server-side validation.

Delivery status

  1. Implemented: discover all 18 lock assets and enable only the reviewed seven-type mutation policy, reporting unsupported types explicitly.
  2. Implemented: keep the generic appearance executor in the BC adapter, with feature-neutral API contracts and one journal/action lifecycle.
  3. Implemented: use bounded generic lock options, separate ephemeral credentials, per-lock timer limits, and itemset-supported presentation and removal options.
  4. Remaining: expand lock policy only after source review, dedicated tests, and explicit live BC qualification for each additional capability.

Confirmed design decisions

Source basis

This inventory’s original source snapshot was Bondage-College 1eb7f9e290c7f4f17d5f48f213edd2235fd93003; the prototype now pins 5eb495c5ced4ee92d40385b7521e6ca63ace12e5 (R133Beta1). The lock names and fields come from the AssetLockType declaration, the ItemMisc lock asset definitions, the extended lock baselines, the browser lock application and eligibility rules, the appearance lock validation and timer bounds, and BC’s unlock/key rules.

The existing prototype guarantees referenced above are documented in the appearance foundation and the BC API plane.