Playtesting

Use this guide to test the public demo ladder:

> Apple Crossing -> Bell Green -> Clover City

The goal is to confirm that a new player can learn the rules in Apple Crossing, then understand Bell Green as the shared small-town sandbox, and Clover City as the larger dense-world showcase.

The ladder uses layered guidance rather than a forced walkthrough. Room summaries name exit destinations, fixed boards provide route information, and hub guides answer spoken direction questions through normal validated speech actions. Players can ignore those hints and explore.

For model reasoning through these same tutorial objectives, see the model compatibility list and Ollama tutorial-ladder benchmark. The harness measures validated character-tool decisions in fresh worlds; it does not replace the browser, Discord, multi-client, or human-usability checks in this guide.

Shared setup

Record for every pass:

Pass criteria for every world:

1. Apple Crossing: Hungry Courier

Generator: apple-crossing

Apple Crossing is the first-run tutorial. The quest is Hungry Courier: help Pip eat, then watch him deliver a letter to Mira's Cottage through normal world actions.

Start

What to try:

Pass criteria:

Golden path

Expected beats:

  1. Pippa Bramble introduces Pip and the delivery problem.
  2. Player receives the Apple Crossing room view and can reread the notice board or ask Pippa.
  3. Player identifies Pip, Pippa, the courier letter, and exits from that view.
  4. Player goes east to Apple Hedge.
  5. Player takes the red crossing apple.
  6. Player returns west to Apple Crossing.
  7. Player drops the apple beside Pip, puts it in the open courier basket, or gives it to Pip.
  8. Player leaves Pip's courier letter on the post table, or drops it back in Apple Crossing if they picked it up.
  9. Pip retrieves basket food if necessary and eats through normal take and eat actions.
  10. Pip takes the courier letter.
  11. Pip moves through Old Footbridge and Mira's Cottage Lane.
  12. Pip reaches Mira's Cottage and writes the delivery ledger consequence.
  13. Player confirms the consequence in activity, history, memory, or the ledger.

Pass criteria:

Branch checks

Run these after the golden path:

Report:

2. Bell Green

Generator: bell-green

Bell Green is the small-town sandbox. It should feel like the next step after Apple Crossing: more rooms, more residents, and more shared-town context without becoming dense.

Town orientation

What to try:

Pass criteria:

Sandbox behavior

What to try:

Pass criteria:

Report:

3. Clover City

Generator: clover-city

Clover City is the advanced dense-world showcase. It should feel larger than Bell Green, with shared facilities, routines, and overlapping tensions.

City orientation

What to try:

Pass criteria:

Dense-world behavior

What to try:

Pass criteria:

Systemic story seeds

Use the same save and seed for each controller under evaluation. These are unresolved world conditions, not scripted outcomes; intervene with ordinary actions and record what actually happens.

Each run passes only if normal validated verbs drive it, at least three systems become observable, a human can change the trajectory, state survives checkpoint/reload, and the outcome remains recoverable rather than being forced by narration. Capture the bulletin, incident log, known-room map, obligations/relationships, recent activity, and player/admin explanations as evidence.

Report:

Release acceptance

Attach results to the release manifest.

Record:

Overall pass requires Apple Crossing golden path, Bell Green orientation, Clover City orientation, non-admin claim/play, feature-flag disclosure, and known-issues classification. The controlled preview additionally requires three reproducible systemic-story runs and a passing 40-client stream rehearsal; neither a focused green check nor later green legs can override a failed aggregate runner.

Concurrent LLM players

Use the multiplayer harness when the players themselves should be LLM agents sharing one live world. Each roster entry has its own player identity, character claim, system prompt, provider client, bounded conversation history, and harness memory. provider and model may be set per player; omitted values inherit shared_provider and shared_model.

Copy examples/playtests/multiplayer-llm.yml, expand players to any roster size, and keep credentials in environment variables named by access_token_env or password_env. The configuration file and result artifact must not contain bearer tokens, passwords, provider keys, or claim secrets. Ollama Local, Ollama Cloud, and OpenRouter are supported. Provider keys use the normal OLLAMA_CLOUD_API_KEY and OPENROUTER_API_KEY environment variables; ollama_host and openrouter_server_url optionally override their endpoints.

Run an opt-in live test against Ollama Cloud first, then run the roster:

BUNNYLAND_LIVE_LLM=1 uv run --extra llm -m pytest \
  tests/test_live_multiplayer.py -m live_llm
scripts/run-multiplayer-llm examples/playtests/multiplayer-llm.yml \
  --output artifacts/playtests/multiplayer-llm.json \
  --trace-output artifacts/playtests/multiplayer-llm.trace.ndjson

The trace is written and flushed after every turn, so an administrator can monitor all players during the run with:

tail -f artifacts/playtests/multiplayer-llm.trace.ndjson

Each record is attributed by run, player, character id/name, provider, model, and turn. It contains the configured system prompt, rendered world prompt, exact provider requests (including retained per-character history and retry corrections), every raw provider response, decoded tool choice, submission result, world epoch, and decision latency. The final JSON also retains those prompt/response pairs under each player's turns. Thinking is captured by default; set log_thinking: false if it should be removed from provider response records.

Both artifacts are sensitive admin evidence: prompts can contain private character context and raw responses can contain model reasoning. Store them with release evidence under operator-only access, do not publish them in tickets or player-visible logs, and delete them according to the playtest evidence retention policy. Credentials, access tokens, passwords, provider keys, and claim secrets are never added to either artifact.

For the ten-player release exercise, configure ten distinct player credentials and ten distinct claimable characters, set max_concurrency: 10, retain the 600-second per-player timeout, and attach the JSON artifact to the canonical release checklist. The generic harness reports completed only when supplied a scenario completion probe; its default run is exploratory and ends at the turn limit. Release acceptance still requires the Apple Crossing-specific aggregate: at least eight of ten fresh sessions complete within ten minutes.

To keep that exercise isolated from a soak or hosted world, prepare the checked-in local fixture in a fresh private directory and run a loopback server:

scripts/prepare-multiplayer-fixture --output artifacts/playtests/shared-10-fixture
source artifacts/playtests/shared-10-fixture/players.env
uv run --extra server --extra llm bunnyland serve \
  --load artifacts/playtests/shared-10-fixture/world.json \
  --save artifacts/playtests/shared-10-fixture/world.json \
  --auth-users-file artifacts/playtests/shared-10-fixture/auth-users.yml \
  --token-db artifacts/playtests/shared-10-fixture/auth-tokens.sqlite3 \
  --api-host 127.0.0.1 --api-port 18769 --ticks 0 --tick-seconds 1 --time-scale 1
scripts/run-multiplayer-llm examples/playtests/multiplayer-llm-10.yml \
  --output artifacts/playtests/shared-10.json \
  --trace-output artifacts/playtests/shared-10.trace.ndjson

The fixture refuses to overwrite an existing world or token database. Its bearer tokens expire after two hours by default, and its directory, token database, sourceable environment, manifest, result, and trace are local operator artifacts rather than files to commit. The checked-in ten-player scenario runs twelve turns per player (120 decisions total), which keeps the release exercise focused on concurrent authentication, isolation, and action handling rather than treating an external model provider's sustained throughput as a server gate.