Test reports

Bezgelor is tested by machines before it is tested by people. These reports are the results, published in full so that anyone can see how far the server gets and check our claims. Every run uses test characters and bots on a test server, never real players, so there is nothing private in them.

What the groups below are:

  • Day one (levelling): a new character is played from its starting zone towards level 15 by a headless client, using the real game protocol. The report says how far it got, how many quests it finished, how often it died and where it got stuck.
  • Combat audit and Quest audit: our rules checked behaviour by behaviour against what we know of the retail game, with the ones that matched, the ones we fixed and the ones we have no evidence for.
  • Encounter simulator: five bot players fight a boss in a real zone instance. Read the kill times as a relative measure, not a prediction of what a group of people would do; see how we test instances.
  • Soak and load, Zone tick: how the server copes with many bots and big zones.

None of this replaces playing. If a report shows something that does not match how you remember the game, we would like to hear it.

Combat audit

Day one (levelling)

Other

Quest audit

For developers

What follows describes the file formats and the commands that reproduce a run.

Day one

The day-one test (apps/bezgelor_world/test/e2e/day_one_test.exs, method in docs/research/2026-10-11-day-one.md) creates a new character through the real game protocol and plays it headless from its starting zone towards level 15: quests, combat with the class's abilities, loot, equipment, public events and path missions. Every packet the server sends is checked by the WildStar client's own message parser. Strict mode uses no GM command but teleports; fast mode also raises the level by GM command where content runs out.

Files:

  • day-one-<class>-<mode>-<date>.json and .md - one run
  • day-one-history.json - one summary per published run, appended to by each new run, so progress shows over time

To reproduce a run, use the command in its report. To publish one:

cd apps/bezgelor_world
DAY_ONE_CLASSES=warrior DAY_ONE_MODES=fast DAY_ONE_TIME_BUDGET=1500 \
  LIMIT_HEAVY=1 ../../scripts/limited.sh mix test test/e2e/day_one_test.exs --include day_one
cd ../..
python3 tools/day_one/publish_report.py tmp/day_one/warrior-fast.json

Run report: schema bezgelor.day_one.v1

Field Meaning
schema "bezgelor.day_one.v1"
date, commit when, and the commit the run ran on
class, faction, mode, start the character (start: veteran = the faction's level 3 start on Nexus, novice = the New Player Experience) and the mode (strict or fast)
target_level, time_budget_s, oracle the run's settings (oracle: packets checked by the client's parser)
runtime_s, result, final_level, deaths the outcome (result: reached_target or stopped)
quests_completed, quests_attempted counts
levels [{level, at_s}], seconds from the start of the run
worlds [{world_id, at_s, level}] worlds entered
quests [{id, title, level, state, accepted_at_s, completed_at_s, duration_s}] (state: the last event: offered, accepted, achieved, completed)
blockers [{kind, count, quest, quest_title, objective, level, world, at_s, cause, detail, issue}]: each point where progress stopped, with its GitHub issue on Bezgelor/bezgelor when one is filed
counters kills, deaths, casts, loot, activations, teleports, ...
notes the run's decisions and context
command the command that reproduces the run

New fields may be added; existing ones keep their meaning. A change that breaks that gets a new schema version.

History: schema bezgelor.day_one.history.v1

{schema, runs: [summary]}, one summary per run: date, commit, class, faction, mode, start, target_level, time_budget_s, runtime_s, result, final_level, deaths, quests_completed, quests_attempted, blockers (count), issues (the issue numbers its blockers point to), report (the run's file). A run with the same date, class, mode and commit replaces its earlier entry.

Encounter simulator

The encounter simulator (BezgelorWorld.EncounterSim, method in docs/research/2026-10-12-stormtalons-lair.md) runs five bot players (tank, healer, three damage dealers) against one boss in a real zone instance: the instance's spawns and scripts, every ability through the spell pipeline. Its reports tune bosses (Level 3 of the master plan's dungeon fidelity).

Files: <instance>-sim-<date>.json (schema bezgelor.encounter_sim.v1, documented in BezgelorWorld.EncounterSim.Report) and .md. To reproduce, use the command in the report, for example:

cd apps/bezgelor_world
SIM_RUNS=2 SIM_REPORT=../../docs/community/test-reports/stormtalons-lair-sim-2026-10-13 \
  LIMIT_HEAVY=1 ../../scripts/limited.sh mix test test/encounter_sim/stormtalons_lair_sim_test.exs --include encounter_sim

Coverage audit and coverage sweep

The audit and the sweep answer "does every level 1-15 quest, path mission and quest item work through the real server", per quest and per objective, as a generated worklist (zones in BezgelorWorld.Sweep.Scope.zones/0).

  • Coverage audit (static, no server, seconds): coverage-audit-<date>.json (schema bezgelor.coverage_audit.v1) and .md. Every quest objective, path mission and quest item is checked against the server's code paths. A quest is blocked (a player cannot finish it), at_risk (the mechanism exists but something it relies on, such as a spell effect type, is missing) or ok. Every reason has a code (no_rule, target_no_spawn, giver_no_spawn, receiver_no_spawn, no_giver, item_start_unhandled, accept_prereq_unhandled, activate_prereq_unhandled, activate_spell_unhandled_effect, quest_ability_unhandled_effect, pushed_item_missing, item_spell_unhandled_effect, path_no_plan, path_no_spawn, ...), a severity, a detail and, where useful, labels (objective type or effect type). JSON: {schema, scope, quests, items, path_missions, summary}; summary.reasons ranks the reasons by quests affected.

    cd apps/bezgelor_world
    ../../scripts/limited.sh mix test test/sweep/audit_test.exs --include audit

    SWEEP_ZONE=algoroc,celestion and SWEEP_QUEST=4023,4024 narrow it; SWEEP_REPORT sets the output base name.

  • Coverage sweep (dynamic, through the real listeners): coverage-sweep-<scope>-<date>.json (schema bezgelor.coverage_sweep.v1) and .md. Every quest the audit does not mark impossible is played by a fresh headless character: accepted at a live giver (earlier quests the quest requires are written as completed first and listed as seeded), each objective done beside its target (GM teleport for travel, GM kill for kills, activation / talk / quest ability / marker by client message), then handed in. Per quest a status (pass, fail, skipped), checks (accept, pushed_item, achieved, turn_in, item_use ... cast and consumed) and per objective checks (progress, progress_update = the client was sent the objective update, no_double_count = a second activation of the same unit did not count again). A fail says what was seen; a skip says why. JSON: {schema, meta, summary, results}; summary.failure_reasons ranks the failing steps by quests.

    cd apps/bezgelor_world
    SWEEP_ZONE=northern_wilds LIMIT_HEAVY=1 ../../scripts/limited.sh mix test test/e2e/coverage_sweep_test.exs --include sweep

    SWEEP_ZONE (comma list of zone keys), SWEEP_QUEST (ids), SWEEP_FACTION, SWEEP_LIMIT, SWEEP_BUDGET_S (per quest, default 240), SWEEP_ORACLE=1 (check every packet with the client's parser; slow) and SWEEP_REPORT narrow or direct a run. The sweep and the audit are excluded from mix test by default (tags :sweep and :audit).

    After committing a new audit or zone sweep, rebuild the Workshop's status page from them: python -I tools/status/build.py (the portal's docs test fails while it is stale).