From 49ea830dc04a0603d8af340f1b696115b78ce97a Mon Sep 17 00:00:00 2001 From: T3 Code Date: Tue, 8 Sep 2026 11:01:47 +0000 Subject: [PATCH 1/3] docs(playerbots): track the rewrite and release evidence --- docs/research/playerbots-azerothcore.md | 310 +++++++++++ docs/research/playerbots-execution.json | 547 +++++++++++++++++++ docs/research/playerbots-rewrite.html | 324 +++++++++++ docs/research/render-playerbots-execution.py | 267 +++++++++ 4 files changed, 1448 insertions(+) create mode 100644 docs/research/playerbots-azerothcore.md create mode 100644 docs/research/playerbots-execution.json create mode 100644 docs/research/playerbots-rewrite.html create mode 100644 docs/research/render-playerbots-execution.py diff --git a/docs/research/playerbots-azerothcore.md b/docs/research/playerbots-azerothcore.md new file mode 100644 index 000000000..698ec811f --- /dev/null +++ b/docs/research/playerbots-azerothcore.md @@ -0,0 +1,310 @@ +# AzerothCore playerbots as a LyraCore architecture reference + +## Source pin and scope + +This note examines `mod-playerbots/mod-playerbots` at commit +[`b949b50bfcdd4fab937781bac2d7765e39330e4b`](https://github.com/mod-playerbots/mod-playerbots/commit/b949b50bfcdd4fab937781bac2d7765e39330e4b), +committed 2026-09-04 and read on 2026-09-08. The fixed tree contains 1,374 C++ headers and source +files with 243,560 lines. Counts came from `find` and `wc` over `src/` in a shallow clone. + +The question is narrow: what decision architecture should LyraCore take for autonomous leveling and +questing, and for companions in a human-led party? This is source research, not a claim that every +upstream feature works well. Upstream describes itself as under development, warns that its docs can +be stale, and requires a custom AzerothCore fork rather than stock AzerothCore +([README lines 33-49](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/README.md#L33-L49), +[lines 60-70](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/README.md#L60-L70)). +The repository identifies its license as GPL-2.0 +([LICENSE](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/LICENSE)). + +LyraCore's comparison point is its current architecture: the Module owns durable state, gameplay +rules, and periodic work; the Gateway owns protocol and cross-shard coordination +([architecture](../architecture.md#2-what-runs-where--the-authority-boundary-precisely)). A Package is +trusted Rust compiled into that Module, with a versioned Package API +([Package API](../package-api.md)). + +## The decision kernel + +The useful part of this repository is a compact utility scheduler with a small authoring grammar. +It has five main pieces. + +1. A `Strategy` contributes default actions, trigger-to-action rules, multipliers, and action-node + factories. It also carries role flags such as tank, damage, heal, ranged, and melee + ([Strategy.h lines 25-86](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Strategy/Strategy.h#L25-L86)). +2. A `Trigger` checks one condition on its own interval and can carry an event. A `TriggerNode` maps + it to one or more named actions with relevance scores + ([Trigger.h lines 15-86](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Trigger/Trigger.h#L15-L86)). +3. An `Action` has separate useful and possible checks, then executes. An `ActionNode` adds + prerequisites, alternatives, and continuers to those supplied by the action itself + ([Action.h lines 48-142](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Action/Action.h#L48-L142)). +4. A `Multiplier` adjusts an action's relevance and can reduce it to zero + ([Multiplier.h lines 15-22](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Multiplier.h#L15-L22)). +5. A `Value` is a named fact. Calculated values cache by an interval; manual values retain state + in memory + ([Value.h lines 32-118](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Value/Value.h#L32-L118), + [lines 321-342](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Value/Value.h#L321-L342)). + +At initialization, the engine flattens all active Strategies into one trigger list, multiplier list, +and action-node factory map +([Engine.cpp lines 117-133](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L117-L133)). +Each decision tick checks due triggers, evaluates each shared trigger once, pushes its handlers, then +pushes Strategy defaults +([Engine.cpp lines 442-512](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L442-L512)). +The queue picks the highest relevance. It deduplicates by action name and raises the stored score +when a later proposal is higher +([Queue.cpp lines 11-27](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Script/WorldThr/Queue.cpp#L11-L27), +[lines 79-103](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Script/WorldThr/Queue.cpp#L79-L103)). + +Execution has useful failure behavior. Multipliers run before expensive possibility checks. +Prerequisites are queued ahead of their parent. A failed or impossible action queues alternatives. +A successful action queues continuers and ends the tick +([Engine.cpp lines 180-240](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L180-L240)). +The loop bounds work as `queue size * iterationsPerTick`, and old candidates expire +([Engine.cpp lines 157-164](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L157-L164), +[lines 246-256](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L246-L256)). + +This kernel is worth adapting almost directly. It is a better fit for the first release than a +general planner. Quest, follow, heal, flee, interrupt, eat, train, and repair decisions naturally +fit trigger, score, prerequisite, fallback, and follow-up rules. + +Two details should change in the Rust translation. First, action execution returns only `bool`, even +though the outer API recognizes unknown, impossible, useless, failed, and successful outcomes +([Engine.h lines 24-31](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.h#L24-L31), +[Engine.cpp lines 310-350](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L310-L350)). +LyraCore should carry a typed action outcome with the core Refusal or movement failure. A fallback can +then depend on why an action failed, and diagnosis can state the real cause. + +Second, queue identity is only the action name. When two triggers propose the same action for +different targets or events, the queue keeps the first basket and changes only its relevance. This +follows from `updateExistingBasket`, which never replaces the event +([Queue.cpp lines 64-77](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Script/WorldThr/Queue.cpp#L64-L77)). +The Rust candidate key should include the action kind and target or event identity. Equal scores need +a fixed tie-breaker, so replay produces the same decision. + +## State, goals, and getting unstuck + +Upstream has three top-level AI states: combat, non-combat, and dead. Each owns a separate engine. +Death clears transient targets before switching; resurrection switches back to non-combat +([PlayerbotAI.cpp lines 1483-1534](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L1483-L1534)). +This is a useful tactical partition. It should remain derived from durable Character state rather +than become a second authoritative state machine. + +The stronger lesson is `TravelTarget`. It retains a destination and point across ticks, tracks +prepare, travel, work, cooldown, and expired states, records two retry counts, and owns a deadline +([TravelMgr.h lines 744-843](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Mgr/Travel/TravelMgr.h#L744-L843)). +Travel validity changes status when the destination becomes inactive, the bot arrives, or the +deadline passes +([TravelMgr.cpp lines 1548-1667](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Mgr/Travel/TravelMgr.cpp#L1548-L1667)). +Quest destinations stay active only while their underlying quest or objective needs work +([TravelMgr.cpp lines 3942-3967](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Mgr/Travel/TravelMgr.cpp#L3942-L3967)). + +Movement uses a stable offset derived from the bot and destination, which prevents the destination +point from changing every tick. A failed move increments the target's movement retry count. More +than five failures move it to cooldown +([MoveToTravelTargetAction.cpp lines 76-123](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Actions/MoveToTravelTargetAction.cpp#L76-L123)). +The lower movement layer accepts normal, incomplete, and shortcut paths for combat movement +([MovementActions.cpp lines 824-843](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Actions/MovementActions.cpp#L824-L843)). +LyraCore should preserve path completeness in the action outcome. An incomplete path can justify a +short retry, while no path should cool down that goal and try another objective or destination. + +Goal retention has two limits. The chooser says it is mainly priority plus randomness and marks +itself for a smarter rewrite. It uses several independent random branches, then has a 90 percent +chance to continue the current destination +([ChooseTravelTargetAction.cpp lines 37-42](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp#L37-L42), +[lines 88-177](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Actions/ChooseTravelTargetAction.cpp#L88-L177)). +The result can look purposeful while still making poor choices. + +It also retains the goal only in memory. `TravelTargetValue` is a `ManualSetValue` with no save +override +([TargetValue.h lines 70-78](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Value/TargetValue.h#L70-L78)). +The base serializer emits `?`, which the context omits from saved data +([Value.h lines 32-41](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Value/Value.h#L32-L41), +[AiObjectContext.cpp lines 60-83](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/AiObjectContext.cpp#L60-L83)). +Logout or restart therefore loses travel purpose. LyraCore can improve on the reference with one +durable goal row per bot Character that holds goal kind, quest and objective identity, destination, +phase, deadline, retry count, last typed failure, and the catalogue revision used to choose it. + +Broad stuck recovery is too slow for the stated pain. Autonomous bots trigger reset after five +minutes without position change, and stronger checks wait ten to fifteen minutes. Both checks turn +off when a real player controls the bot +([StuckTriggers.cpp lines 13-58](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Trigger/StuckTriggers.cpp#L13-L58), +[lines 60-141](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Ai/Base/Trigger/StuckTriggers.cpp#L60-L141)). +LyraCore should detect lack of progress per goal and movement leg within seconds and a small number +of attempts. It should keep companion recovery active, with follow distance and leader movement as +its evidence. + +## Autonomous bots and human-led companions + +Upstream supports both modes through the same action grammar, with different context and active +Strategies. A real player master or a party containing one forces full activity instead of the +background activity rotation +([PlayerbotAI.cpp lines 4669-4694](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L4669-L4694)). +When group leadership changes, the bot chooses a new master, resets Strategies, and enables follow +outside battlegrounds +([PlayerbotAI.cpp lines 413-469](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L413-L469)). +It also watches both bot and master packet streams and maps packets to actions +([PlayerbotAI.cpp lines 167-228](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L167-L228)). + +LyraCore does not need synthetic World Sessions or packet observation inside the Package. Human-led +party intent is already durable realm state. The bot decision pass should read party membership, +leader, selected target, threat, health, auras, and position from Module tables. Cross-shard party +operations remain Group Intents for the Gateway. Ordinary combat, movement, spell, item, quest, and +loot operations stay in the Module. + +Role assignment is concrete and useful, though its exact rules are WotLK-specific. The factory maps +class and talent tab to tank, healer, or damage roles +([AiFactory.cpp lines 141-188](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/AiFactory.cpp#L141-L188)). +Role-bearing Strategies then affect targeting and positioning. The main tank uses an explicit party +flag first and otherwise chooses the first live tank +([PlayerbotAI.cpp lines 2408-2427](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L2408-L2427)). +LyraCore should make the party role an explicit durable choice with a deterministic default from +vanilla class, talents, spells, and equipment. Tactics can then compose a role Strategy with class +and situation Strategies. Do not copy WotLK talent-tab mappings. + +## Scheduling, population, and performance + +Several mechanisms are proven in source and worth adapting. + +- A per-bot delay gates the decision loop. `YieldThread` adds a deterministic zero to 200 ms offset + from the guid to spread work + ([PlayerbotAIBase.cpp lines 51-60](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/PlayerbotAIBase.cpp#L51-L60)). +- Trigger and Value intervals avoid repeating expensive reads every tick + ([Trigger.cpp lines 35-50](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Trigger/Trigger.cpp#L35-L50)). +- The random-bot manager updates and logs in only a configured batch, with separate initialization + pacing + ([RandomPlayerbotMgr.cpp lines 298-327](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/RandomPlayerbotMgr.cpp#L298-L327), + [lines 404-450](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/RandomPlayerbotMgr.cpp#L404-L450)). +- Background activity can scale down against measured world update time. Combat, instances, and + human-led parties remain active + ([PlayerbotAI.cpp lines 4595-4615](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L4595-L4615), + [lines 4788-4812](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotAI.cpp#L4788-L4812)). +- A separate world-thread queue caps itself at 10,000 operations, processes 100 every 50 ms, reports + queue pressure and slow work, and drops new work at capacity + ([PlayerbotWorldThreadProcessor.h lines 107-154](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.h#L107-L154), + [PlayerbotWorldThreadProcessor.cpp lines 33-65](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Script/WorldThr/PlayerbotWorldThreadProcessor.cpp#L33-L65)). + +For SpacetimeDB, deterministic scheduling and bounded scheduled batches should replace process-local +delays. A due row should carry the Character guid and next decision time. Each scheduled pass should +claim a fixed number in stable key order, run at most a fixed candidate and action budget, and write +the next due time in the same transaction as the action outcome. Combat and human-led companions need +shorter intervals. Idle autonomous Characters can use coarse intervals. An overloaded pass should +leave excess due rows for the next run and record lag; silently dropping durable work would be the +wrong translation of the upstream queue. + +Upstream performance instrumentation measures triggers, Values, actions, random-bot work, and total +time, with optional call stacks +([PerfMonitor.h lines 25-70](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Debug/PerfMonitor.h#L25-L70)). +LyraCore should record counts and bounded timings by decision phase plus queue lag, candidates +considered, chosen action, typed outcome, goal age, and consecutive no-progress count. The upstream +README claims thousands of bots, but this tree supplies no benchmark result that proves that claim. + +## Automatic progression support + +The upstream `PlayerbotFactory` is useful as a checklist for keeping autonomous bots playable. Its +refresh path learns default skills and available spells, chooses talents, equips items, supplies +bags, ammo, food, potions, reagents, and consumables +([PlayerbotFactory.cpp lines 679-829](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/PlayerbotFactory.cpp#L679-L829)). +Trainer spells still pass the trainer's own `CanTeachSpell` check before learning +([lines 3213-3257](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/PlayerbotFactory.cpp#L3213-L3257)). +Equipment replacement uses a score and requires a 20 percent improvement during incremental refresh +([lines 2345-2389](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/PlayerbotFactory.cpp#L2345-L2389)). + +Adapt these as explicit upkeep actions through existing vanilla Gates. The Operator can choose +Package Config for free training, gear floor, and supply replenishment. Each action should preserve +normal proficiency, level, class, equipment, inventory, and uniqueness rules. Keep quest XP and +credit tied to real gameplay outcomes. The full upstream refresh routine directly sets level, clears +quests and inventory, and can complete prerequisite or attunement quests +([lines 615-677](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/PlayerbotFactory.cpp#L615-L677), +[lines 3575-3603](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Factory/PlayerbotFactory.cpp#L3575-L3603)). +That routine is unsuitable as one LyraCore operation. + +## Direct adaptation and coupling + +There are two different port proposals. + +Translating the selection kernel is feasible and likely the best starting point. A reproducible +upper-bound inventory is 2,967 lines at this pin, counted with `wc -l` across these files: + +- `src/Bot/Engine/{Engine,AiObject,AiObjectContext}.{h,cpp}` +- `src/Bot/Engine/Action/Action.{h,cpp}` +- `src/Bot/Engine/Strategy/Strategy.{h,cpp}` +- `src/Bot/Engine/Trigger/Trigger.{h,cpp}` +- `src/Bot/Engine/Value/Value.{h,cpp}` +- `src/Bot/Engine/Multiplier.h` +- `src/Bot/Engine/WorldPacket/Event.{h,cpp}` +- `src/Script/WorldThr/Queue.{h,cpp}` + +That count includes comments, host-facing base objects, context serialization, and generic Value +helpers. It is not an estimate of the Rust result. The selection algorithm itself is much smaller. +A Rust translation would still be a small rewrite because upstream objects retain `PlayerbotAI*`, +`Player*`, `Unit*`, and `AiObjectContext*` directly +([AiObject.h lines 13-39](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/AiObject.h#L13-L39)). +Its events embed `WorldPacket` and `Player*` +([Event.h lines 10-44](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/WorldPacket/Event.h#L10-L44)). +The translation should keep the grammar and execution order while replacing pointers, strings, and +dynamic casts with Rust enums and durable identifiers. + +Porting the whole runtime would be a different project. It creates synthetic WotLK `WorldSession` +objects and routes packet queues through AzerothCore opcode handlers +([PlayerbotMgr.cpp lines 198-218](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotMgr.cpp#L198-L218), +[lines 259-274](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/PlayerbotMgr.cpp#L259-L274)). +Actions call AzerothCore `Player`, `Group`, `MotionMaster`, `PathGenerator`, object stores, spell +manager, threat manager, and packet handlers throughout the tree. The code also assumes WotLK +talents, death knights, LFG, vehicles, glyphs, Outland, Northrend, and WotLK raids. LyraCore targets +an unmodified 1.12.1 client, uses durable relational state, and has no in-process AzerothCore object +graph. A whole-runtime port would first recreate the host it expects, then replace it. That brings +little advantage over writing behavior against LyraCore's existing actor, combat, nav, quest, item, +group, and transfer operations. + +## Verification and diagnosis + +The source has useful operational diagnosis. The engine can log every trigger, queued candidate, +multiplier elimination, prerequisite, result, and current Value set +([Engine.cpp lines 143-149](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L143-L149), +[lines 613-682](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L613-L682)). +Travel path attempts have optional CSV output with path type and geometry +([TravelMgr.cpp lines 779-814](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Mgr/Travel/TravelMgr.cpp#L779-L814)). +These answer "what did the bot see and choose?", which LyraCore currently needs. + +The verification base is weaker. The main CI workflow compiles release builds against the custom +fork on three Linux compiler images +([core_build.yml lines 13-78](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/.github/workflows/core_build.yml#L13-L78)). +A separate job runs formatting and `cppcheck` +([codestyle_cpp.yml lines 20-41](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/.github/workflows/codestyle_cpp.yml#L20-L41)). +I found no automated behavioral tests in the fixed tree. The engine's `testMode` writes action lines +to `test.log`; it does not assert outcomes +([Engine.cpp lines 135-140](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L135-L140), +[lines 635-645](https://github.com/mod-playerbots/mod-playerbots/blob/b949b50bfcdd4fab937781bac2d7765e39330e4b/src/Bot/Engine/Engine.cpp#L635-L645)). +Maturity and breadth therefore do not prove stable decisions. + +LyraCore should test the translated kernel as a pure deterministic calculation, then test action +outcomes through Module operations. Scenario tests should cover quest objective retention, mixed +objective quests, no-path cooldown and reselection, no-progress detection, interruption by combat, +resumption after combat, leader movement, tank target choice, healer triage, supply replenishment, +and restart with a durable goal. A small Headless Client suite can verify the final party behavior +through the real 1.12.1 protocol. + +## Adopt, adapt, avoid + +| Decision | Upstream reference | LyraCore choice | +| --- | --- | --- | +| Strategy composition | Strategies register triggers, defaults, multipliers, and action nodes | Adopt the grammar in Rust for class, role, autonomous, companion, and situation Strategies. | +| Candidate selection | Highest relevance after multipliers | Adopt with integer scores, a stable tie-breaker, and candidate identity that includes target. | +| Action graph | Prerequisites, alternatives, continuers | Adopt. Store the typed outcome that chose each edge. Bound graph depth and work per pass. | +| Derived facts | Named Values with timed caches | Adapt to typed derived reads cached within a pass or by durable revision. Do not build a global string registry. | +| AI state | Combat, non-combat, dead engines | Adapt as a derived tactical mode. Durable Character state remains authoritative. | +| Quest and travel purpose | `TravelTarget` with phase, validity, deadlines, retries | Adopt the state shape and make it durable. Retain quest, objective, destination, progress, and failure. | +| Target choice | Layered random branches and 90 percent continuation | Avoid. Score eligible goals deterministically, then use saved random state only for equal valid choices. | +| Movement failure | More than five failed moves cool down a target | Adapt to typed path outcomes, short bounded retries, per-destination backoff, and prompt reselection. | +| General stuck reset | Five to fifteen minute heuristics, disabled for human masters | Avoid. Detect progress against the retained goal and keep recovery active for companions. | +| Party roles | Class and WotLK talent tabs imply role; Strategies carry role flags | Adapt to explicit durable role plus vanilla-derived default. | +| Human-led control | Master and packet observation select follow and party behavior | Adapt to durable party state and Module events. Use Group Intents only for realm-core operations. | +| Population pacing | Staggered updates, fixed batches, activity scaling | Adopt in scheduled Module batches with stable ordering, due-row lag, and no silent work loss. | +| Training, gear, supplies | Factory refresh directly grants them | Adapt as separate Operator-configured upkeep actions through vanilla Gates. | +| Full C++ runtime | 243,560 lines tied to the custom WotLK fork | Avoid. Its host objects, protocol path, expansion rules, and process-local state do not match LyraCore. | +| Verification | Compile/static CI plus rich logs, no behavioral suite found | Adopt the observability shape and add deterministic behavior, Module, and Headless Client tests. | + +The practical recommendation is a targeted rewrite with the AzerothCore decision grammar. Translate +the queue, scoring, Strategies, triggers, Values, action graph, and retained travel state into a +small typed Rust core. Implement each action through LyraCore's existing gameplay operations. This +keeps the part that explains why a bot chose something and discards the WotLK host coupling that +would make a direct runtime port larger and harder to verify. diff --git a/docs/research/playerbots-execution.json b/docs/research/playerbots-execution.json new file mode 100644 index 000000000..08d80101d --- /dev/null +++ b/docs/research/playerbots-execution.json @@ -0,0 +1,547 @@ +{ + "spec": { + "id": "PB", + "title": "Rewrite playerbots around durable objectives and typed action outcomes", + "problem": "The current playerbots Package can accept an action without proving that the action completed, loses route results, treats attempted combat as quest progress, bypasses the normal cast lifecycle, and retains too little purpose across interruption, restart, and Transfer. Bots can therefore stall, repeat work, choose an obsolete target, or abandon useful intent without explaining why. The current tests also do not prove the Package and core together against real actor operations, imported content, navigation, protocol transitions, and sustained load.", + "solution": "Replace the behavior control flow with one typed Rust decision runner shared by autonomous bots and human-led companions. The runner observes bounded facts, composes supported Strategies, ranks target-bearing candidates deterministically, executes actions through core operations, records typed outcomes, and retains one durable objective with bounded failure memory. Build the rewrite through a pinned real Module and Package fixture, then prove companion behavior, provisioning, seeded quest loops, recovery, commands, restart, Transfer, load, cutover, and attended client behavior before deleting the displaced implementation.", + "user_stories": [ + "As an Operator, I want every bot controlled by one eligible runner, so that two behavior systems cannot issue conflicting actions.", + "As an Operator, I want a stopped bot to report its objective, target, chosen action, outcome, retry count, next eligible time, and content revision, so that I can diagnose it without reading source.", + "As an Operator, I want decision work scheduled in bounded fair batches, so that a large roster cannot monopolize a Module tick.", + "As an Operator, I want excess due bots deferred with recorded lag, so that overload does not silently discard durable work.", + "As an Operator, I want repeatable provisioning profiles, so that I can explain why a bot received a spell, item, or supply.", + "As an Operator, I want deployment capacity based on measured runs of 10, 25, and 100 bots, so that release limits reflect this implementation.", + "As a developer, I want fixed facts and time to produce the same decision, so that policy changes have reproducible tests.", + "As a developer, I want candidates identified by action, target, and relevant event, so that a higher score cannot retain the wrong target.", + "As a developer, I want each supported action to return a typed outcome, so that success, waiting, Refusal, cancellation, expiry, and infrastructure failure remain distinct.", + "As a developer, I want action prerequisites, alternatives, and continuers to be bounded, so that retries and cycles cannot run forever.", + "As a developer, I want a reproducible Module and Package fixture at pinned revisions, so that failures and fixes can be compared against the same content and geometry.", + "As a developer, I want casts to use the normal core cast-start lifecycle, so that cast time, interruption, cancellation, cost, and completion use the same Gates as client casts.", + "As a developer, I want movement outcomes to preserve route completion and coverage evidence, so that policy can distinguish progress, a partial route, blockage, and unknown coverage.", + "As an autonomous bot, I want one objective retained across tactical interruptions, so that defending myself does not erase my quest purpose.", + "As an autonomous bot, I want quest admission to require an executor for every required objective, so that unsupported quests do not trap me.", + "As an autonomous bot, I want to accept, travel for, complete, and turn in a supported kill quest, so that I can earn normal quest credit and XP.", + "As an autonomous bot, I want to find the actual drop source, loot it, and turn in a supported collect quest, so that collection progress comes from gameplay outcomes.", + "As an autonomous bot, I want supported talk-only chains and simple GameObject objectives executed through normal core interactions, so that a quest route does not stop at a non-combat step.", + "As an autonomous bot, I want the actual quest ender retained from the catalog, so that I travel to the correct turn-in Character or GameObject.", + "As an autonomous bot, I want death, combat, full bags, absent targets, and temporary route failure to have finite recovery rules, so that I can resume or stop with a specific reason.", + "As an autonomous bot, I want a failed destination deferred by map, instance, and geometry revision, so that a restart cannot immediately choose the same failed target again.", + "As an autonomous bot, I want skill and spell training, vanilla talents, equipment, and supplies reconciled on spawn and level-up through core Gates, so that I remain playable without receiving invalid progress.", + "As a human party leader, I want a companion to follow or stay on command, so that I control its position.", + "As a human party leader, I want a companion to assist my chosen fight or a designated target, so that it does not pull an unrelated enemy.", + "As a human party leader, I want companions to respect controlled enemies, so that crowd control is not broken by autonomous target choice.", + "As a human party leader, I want each companion to retain an explicit tank, healer, or damage role, so that party behavior remains predictable through death and Transfer.", + "As an injured party member, I want a Priest companion to repair range or line of sight and complete one real heal cast, so that repeated decisions do not restart the cast bar.", + "As a party member, I want a Warrior tank to hold the chosen fight and a Mage damage companion to act at class-appropriate range, so that role does not erase class capabilities.", + "As a companion, I want joining a human-led party to suspend autonomous travel and leaving it to resume a still-valid solo objective, so that control changes preserve useful intent.", + "As a companion, I want my role, party intent, and retained objective reconciled after restart and Transfer, so that delayed work from the old location cannot act.", + "As a maintainer, I want the old behavior source and obsolete state retired after both release suites pass, so that one implementation remains authoritative.", + "As a party member, I want companions to heal and apply useful missing buffs between fights, so that the party starts the next fight ready without repeated redundant casts." + ], + "implementation_decisions": [ + "Use a targeted Rust rewrite of the useful AzerothCore decision grammar. Do not port its C++ runtime, synthetic World Sessions, packet queues, host object graph, or WotLK rules.", + "Keep durable gameplay authority in the Module. Keep party authority in Realm-core. Use existing Transfer and Group Intent routing only for their realm-wide responsibilities.", + "Give the Package one small decision interface, one action execution interface, and one explanation read. Keep internal behavior behind those interfaces.", + "Represent Strategies, triggers, facts, candidates, actions, targets, outcomes, tactical modes, objective stages, and failure reasons with typed values instead of strings and dynamic lookup.", + "Rank candidates with integer scores and stable tie-breaking. Candidate identity includes the action, target, and relevant event. Saved random state may break equal valid choices only.", + "Support bounded prerequisites, alternatives, and continuers. Limit candidate count, graph depth, transitions, and route expansion independently during each decision pass.", + "Allow one foreground action to own movement or a cast. A higher-priority action must explicitly cancel incompatible work before it starts.", + "Retain the quest or party objective across tactical interruption. Store its identity, destination, stage, deadline, last verified progress, deferred destinations, bounded failure memory, and catalog revision.", + "Keep route segments and live target observations transient. Correlate pending work with controller generation and location so stale completions cannot advance current state.", + "Treat action acceptance and actual progress as different facts. Track movement, combat, cast, and quest progress with separate evidence and clocks.", + "Expose typed outcomes from the owning core operations for the actions the selected behaviors require. Preserve existing Gates and atomic Refusal behavior.", + "Route bot spells through the normal cast-start and timed completion lifecycle. A running cast stays retained until completion, interruption, cancellation, or expiry.", + "Preserve complete, partial, blocked, and explicit unknown-coverage movement evidence. Do not infer missing coverage only from absent sparse navigation rows.", + "Derive tactical mode and active Strategies from durable Character, party, combat, aura, health, threat, target, position, and capability facts. Do not create a second authoritative state machine.", + "Use the bounded priority order from the report: lifecycle and Transfer restrictions, immediate survival, urgent party support, the current fight, human orders, maintenance, autonomous quest work, then idle activity.", + "Store an indexed next-decision time per bot, process due bots in stable order with a fixed batch limit, coalesce urgent reconsideration reasons, and record lag for deferred work.", + "Build a versioned supported quest catalog from imported quest relations, objectives, spawns, loot sources, and actual enders. Admit only quests whose required objectives have executors.", + "Start autonomous release coverage with a seeded Northshire and Elwynn catalog and ordinary quest credit and earned XP. Treat this as a bounded proof rather than level 1 to 60 coverage.", + "Start companion release coverage with Warrior tank, Priest healer, and Mage damage capabilities. Store the explicit role and derive a deterministic vanilla default when none is chosen.", + "Support durable follow, stay, assist, and designated-target orders through the existing command transport. Joining a human-led party suspends solo work; leaving rechecks and resumes it when valid.", + "Reconcile skill and spell training, vanilla talent choices, equipment, bags, food, potions, ammo, reagents, and bounded supplies as separate idempotent actions through core Gates. Provisioning never changes level, grants quest completion, deletes quest items, or duplicates owned resources.", + "Add new state through an additive migration and one durable controller selector. Use record-only comparison before a small active cohort, then retire the old controller and its obsolete state after release acceptance.", + "Keep a bounded history of transitions and failures. Do not retain one row for each successful idle decision." + ], + "testing_decisions": [ + "Use the highest real seam available. Pure tests cover deterministic policy, durable Module and Package fixtures cover gameplay operations and navigation, Headless Client scenarios cover protocol and world transitions, and attended client observation covers visible behavior.", + "The baseline fixture pins core commit 95e6ad8c61540f74471e3087897e8c3ef7e065d1 and Package Collection commit c32b2fb7aa405190728034b63ce6eb9a3c0dd6be together with named imported content and geometry revisions.", + "Every supported action has behavioral cases for success, waiting, Refusal, cancellation, and expiry. Infrastructure failures remain separate where the seam can produce them.", + "Durable fixtures call real actor, cast, movement, quest, loot, item, and lifecycle operations. They do not replace gameplay with a simulated combat model.", + "Decision fixtures cover stable candidate order, target-bearing identity, bounded transition graphs, survival against role work, healing against following, and combat interruption against retained quest work.", + "Movement fixtures measure route or waypoint advancement. After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.", + "Cast fixtures prove one long cast starts once, survives intervening decisions, and ends once by completion, interruption, cancellation, or expiry.", + "Companion fixtures cover follow, stay, assist, designated target, controlled enemies, poor range, loss of line of sight, wounded allies and missing buffs between fights, death, regrouping, and one instance entry and exit.", + "Autonomous fixtures run ten seeds per starter class through the supported Northshire and Elwynn catalog. At least 95 percent complete each supported scenario without Operator help, and every other seed terminates with an explained outcome.", + "Autonomous mandatory scenarios include kill, collect, talk-only chains, supported simple GameObject use, turn-in, death, interruption, full bags, absent targets, an unreachable giver, unsupported objectives, and restart with a retained objective.", + "Restart and Transfer fixtures interrupt active action and escrow stages. They prove no duplicate Character, equipment, supply grant, quest reward, or active controller and prove stale work cannot act on the old location.", + "Load fixtures run 10, 25, and 100 bots on one named disposable fixture and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and the slowest due bot before capacity is set.", + "Final observation requires one hour with 25 bots on imported content plus an attended companion session in a real unmodified 1.12.1 client. A human must collect and sign off this evidence if the implementation environment cannot run that client.", + "Review final behavior against this specification and repository standards after the focused and full relevant checks pass." + ], + "out_of_scope": [ + "A direct or mechanical port of the complete AzerothCore playerbots runtime.", + "Synthetic World Sessions or packet observation inside the Package.", + "A user-defined action language, global string factory, client addon, or new product UI.", + "Claims of general level 1 to 60 quest coverage, all classes, all regions, all dungeons, or thousands of bots.", + "Exploration, escort, scripted-event, transport, and other quest objective types until they receive explicit executors and catalog support.", + "Routine catch-up teleportation through blocked geometry.", + "A full economy simulation or provisioning that changes level, fabricates quest credit, clears inventory, or completes prerequisite quests.", + "A full Deadmines run unless the team later selects it as the first dungeon milestone.", + "Production realm changes, live database inspection, publication, or deployment as part of implementation and local acceptance." + ], + "notes": [ + "The source report proposes acceptance thresholds. Implementation must measure them before treating them as release facts.", + "Bad or stale imported geometry can imitate a policy defect. Every route fixture and observation record names its content and geometry revisions.", + "The source comparison found no behavioral assertion suite in the pinned AzerothCore tree. Its architecture is evidence for design choices, not proof of LyraCore behavior.", + "Record provenance if any reference code is copied or translated. The architecture proposal does not make a license-compatibility conclusion.", + "Attended real-client observation is a release gate that may require a human after agent implementation. The implementation tickets must prepare the exact scenario, capture format, and diagnostic reads without claiming that a client session already ran.", + "Unresolved product choices remain level range beyond the initial catalog, the first full dungeon milestone, equipment strength beyond level-appropriate starter gear, and any explicit catch-up travel policy. They do not block the bounded first release.", + "The user authorized autonomous implementation, PR ownership through review, and confident merges. The HTML is the tracker; no issue publication or planning interview is required. Production changes remain outside this authorization." + ] + }, + "groups": [ + { + "id": "S1", + "title": "Typed action foundation and durable runner", + "parent": "PB" + }, + { + "id": "S2", + "title": "Companions and provisioning", + "parent": "PB" + }, + { + "id": "S3", + "title": "Autonomous questing and recovery", + "parent": "PB" + }, + { + "id": "S4", + "title": "Commands, Transfer, and restart", + "parent": "PB" + }, + { + "id": "S5", + "title": "Release evidence and retirement", + "parent": "PB" + } + ], + "tickets": [ + { + "id": "PB-001", + "title": "Prove typed outcomes in a real pinned fixture", + "parent": "S1", + "blocked_by": [], + "delivery": "Create the first tracer through a reproducible pinned Module and Package fixture. Drive attack, interaction, movement, and cast-start through real core operations, return typed outcomes to the Package, and capture the blocked-target and out-of-range-heal failures that the rewrite must fix.", + "acceptance": [ + "The fixture records the pinned core, Package, imported content, and geometry revisions and can reproduce the same initial state and outcome.", + "The fixture loads and runs the real Module with the real Package; it does not substitute a simulated gameplay engine.", + "Attack acceptance is distinct from damage and quest progress, and an attempted attack with no hit cannot clear a quest progress clock.", + "Movement reports complete, safe partial, blocked, or explicit unknown-coverage evidence with route or waypoint advancement where applicable.", + "Interaction and cast-start return typed success, waiting, Refusal, cancellation, and expiry outcomes supported by their owning operations.", + "A long bot cast uses the normal core cast lifecycle and completes once without restart on later decision ticks.", + "The blocked target and poor-range heal cases have reproducible inputs, observed outcomes, and enough evidence to compare later runner behavior.", + "A written extraction comparison chooses the smaller total implementation and records why the full AzerothCore runtime is not used." + ], + "model": "gpt-6-astra", + "effort": "high", + "estimated_tokens": 180000, + "status": "implementing", + "repo_scope": [ + "LyraCore Module action and navigation contracts", + "Official Package Collection playerbots fixture", + "Local durable integration tests" + ], + "owner": "PB-001 implementer", + "prs": [], + "evidence": [ + "Baseline on core 95e6ad8 and Package c32b2fb: both ignored personality durable tests passed in a private loopback Standalone. This proves the existing Package fixture, not the new outcome contract." + ], + "notes": [ + "The implementer owns the isolated core and Package worktrees and the serialized build slot. The orchestrator owns independent review and merge order." + ], + "acceptance_evidence": [] + }, + { + "id": "PB-002", + "title": "Run one durable objective through bounded decisions", + "parent": "S1", + "blocked_by": [ + "PB-001" + ], + "delivery": "Build the shared decision runner around typed facts and outcomes. Retain one objective, arbitrate one foreground action, schedule bots in stable bounded batches, and explain each meaningful choice through the Package's normal entry point.", + "acceptance": [ + "Fixed facts and explicit time produce the same target-bearing candidate order and chosen action.", + "Strategies compose supported triggers, defaults, and priority rules without a global string registry or a second authoritative state machine.", + "Prerequisites, alternatives, and continuers have explicit depth, transition, candidate, and route-work limits with cycle refusal.", + "Only one foreground movement or cast action owns the bot, and a higher-priority action explicitly cancels incompatible work.", + "The durable objective records identity, destination, stage, deadline, last verified progress, bounded failures, deferred destinations, and catalog revision.", + "Separate movement, combat, cast, and quest progress evidence prevents an accepted action from masquerading as completion.", + "Due bots run in stable indexed order under a per-pass limit; excess work remains due, gets a fair next turn, and records scheduler lag.", + "The explanation read reports the current objective and target, chosen action and reason, last outcome, progress age, retry count, next eligible time, and relevant revision with bounded history.", + "The additive state migration defines defaults and backfill and adds a durable controller selector before any bot can use the new runner. Record-only mode emits no gameplay actions; cohort mode has one eligible controller and supports freeze." + ], + "model": "gpt-6-astra", + "effort": "high", + "estimated_tokens": 180000, + "status": "ready", + "repo_scope": [ + "Official Package Collection decision and durable state", + "LyraCore Module scheduling and diagnostics", + "Pure decision and durable integration tests" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-003", + "title": "Make a Priest follow, heal, and resume", + "parent": "S2", + "blocked_by": [ + "PB-002" + ], + "delivery": "Complete the first human-led companion loop. A Priest follows its party leader, retains an injured ally as the heal target, repairs range or line of sight, casts through the real lifecycle, handles interruption, and resumes following.", + "acceptance": [ + "Joining a human-led party suspends autonomous travel and selects companion Strategies from durable party facts.", + "The Priest follows a moving leader without starting a fight against an unrelated nearby enemy.", + "An injured ally outranks ordinary following when the Priest has a usable heal and the survival policy permits it.", + "Poor range or line of sight produces a movement prerequisite that retains the injured ally and finds a reachable casting position or records a specific wait.", + "The heal starts one real timed cast, does not restart on repeated decisions, and observes completion or interruption through typed outcomes.", + "After healing, cancellation, or a recoverable interruption, the Priest resumes following without losing party control state.", + "Death and resurrection preserve the companion role and lead to regrouping rather than a permanent solo objective change." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection companion support behavior", + "LyraCore Module cast and party fact reads", + "Durable companion scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-004", + "title": "Complete starter roles, target choice, and crowd control", + "parent": "S2", + "blocked_by": [ + "PB-003" + ], + "delivery": "Add Warrior tank and Mage damage behavior beside the Priest healer on the shared runner. Make explicit durable roles, vanilla class capabilities, chosen-target assistance, controlled-enemy avoidance, death, rest, and regrouping work through repeated party pulls.", + "acceptance": [ + "Warrior, Priest, and Mage have validated ability sets at every level supported by the companion fixture.", + "Each companion retains an explicit tank, healer, or damage role, with a deterministic vanilla-derived default when no role was selected.", + "The Warrior tank chooses and holds the party's selected fight according to survival and threat facts rather than inheriting damage-only retreat behavior.", + "The Mage acts at class-appropriate range and role does not force a ranged class into melee.", + "All companions honor the party's chosen fight and designated target and do not initiate an unrequested pull.", + "Controlled enemies remain ineligible unless the control is intentionally broken by a higher-priority survival rule with a recorded reason.", + "Repeated-pull fixtures cover wounded allies between fights, target death or disappearance, loss of line of sight, companion death, rest, and regrouping without role abandonment.", + "Between fights, companions select useful missing class buffs, repair casting position when needed, apply them through real core casts, observe the resulting auras, and avoid redundant recasting while the buff remains valid." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection starter class and role behavior", + "LyraCore Module combat and capability facts", + "Durable repeated-pull party scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-005", + "title": "Provision playable bots without duplicating progress", + "parent": "S2", + "blocked_by": [ + "PB-002" + ], + "delivery": "Reconcile the supported bot's skills, spells, vanilla talents, equipment, bags, food, potions, ammo, reagents, and bounded supplies on spawn and level-up through real core operations. Make each action idempotent and explain it by provisioning profile and revision.", + "acceptance": [ + "Provisioning runs on spawn and level-up and periodically repairs only resources owned by the selected profile.", + "Spell learning, equipment, inventory, uniqueness, proficiency, class, and level rules pass through core operations. Free provisioning is an explicit profile choice; its grants remain bounded and attributable.", + "Skill training and vanilla talent choices follow the selected class profile through the owning core Gates. Prerequisites, earned talent points, rank limits, and level restrictions hold, and reconciliation cannot spend a point or train a rank twice.", + "Repeated reconciliation does not create duplicate equipment, unlimited supplies, repeated spell grants, or repeated costs.", + "The policy respects an equipped upgrade, does not delete quest items, and never raises a bot's level to match a leader.", + "Quest credit, earned XP, loot entitlement, and quest completion remain consequences of normal gameplay operations.", + "Full bags, missing consumables, resource recovery, rest, and death produce bounded next actions or an explained stop.", + "Decision history records the provisioning profile, revision, chosen action, and typed outcome." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection provisioning policy", + "LyraCore Module skill, spell, talent, item, inventory, and equipment operations", + "Durable idempotency scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-006", + "title": "Admit supported quests from a seeded catalog", + "parent": "S3", + "blocked_by": [ + "PB-002" + ], + "delivery": "Build a versioned quest catalog for the initial Northshire and Elwynn proof from imported relations, objectives, spawns, loot sources, and actual enders. Admit a quest only when every required objective has a supported executor, and retain the chosen objective and destination.", + "acceptance": [ + "The catalog records quest eligibility, each objective kind, target or drop source, actual ender, work area, destination evidence, and content revision.", + "The initial fixture contains a named supported Northshire and Elwynn catalog with deterministic seeds for each starter class.", + "Admission checks ordinary core eligibility and confirms an executor for every required objective before acceptance.", + "Unsupported exploration, escort, scripted event, transport, and complex GameObject requirements remain explicit and cannot enter a futile loop. Mixed quests are admitted only when every required kind has an executor, including supported talk-only and simple GameObject steps.", + "A live creature search chooses what can be acted on now but does not decide whether a quest destination exists in imported content.", + "The retained objective stores the actual ender and catalog revision and survives a tactical combat interruption.", + "If a held quest becomes unsupported, the bot records the missing capability and proceeds to another supported objective or a specific wait without repeated abandonment and reacceptance." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection quest catalog and admission", + "LyraCore imported quest and world relations", + "Seeded durable catalog scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-007", + "title": "Finish supported autonomous quest loops", + "parent": "S3", + "blocked_by": [ + "PB-005", + "PB-006" + ], + "delivery": "Complete supported kill, collect, talk-only, and simple GameObject quest loops. The bot accepts the quest, retains its objective, travels through real navigation, executes the required gameplay, earns ordinary credit and XP, turns in to the actual ender, and selects the next supported work.", + "acceptance": [ + "A supported kill quest completes through accepted combat, actual damage and death, kill credit, travel, and turn-in rather than a changed internal label.", + "A supported collect quest hunts an explicit eligible drop source, receives the item through real loot and inventory operations, and turns in to the catalog's actual ender.", + "A supported talk-only chain advances through actual quest eligibility, giver and ender interactions, and ordinary rewards without manufacturing prerequisite completion.", + "At least one cataloged simple GameObject objective completes through the owning core use or loot operation, respects range and object state, and earns credit once. Unsupported scripted object behavior is refused at admission.", + "Quest objective progress changes only when the authoritative core gameplay outcome changes it.", + "The retained quest objective survives combat interruption, death, rest, and provisioning, then resumes after rechecking eligibility.", + "Target death, disappearance, or ineligibility cancels only the current action and selects a new eligible target or an explicit respawn wait.", + "A completed turn-in grants ordinary rewards once and advances to another supported catalog entry without Operator help.", + "Seeded scenarios cover Warrior, Priest, and Mage and produce reproducible decision and outcome histories.", + "A supported quest destination outside the former home leash remains reachable under the current work area and retained destination. Tactical retreat returns to an appropriate safe position in the current partition and cannot reset travel to the spawn home." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection autonomous quest behavior", + "LyraCore Module quest, combat, loot, inventory, and navigation operations", + "Seeded durable quest scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-008", + "title": "Recover from blocked travel and stalled quest work", + "parent": "S3", + "blocked_by": [ + "PB-004", + "PB-007" + ], + "delivery": "Turn typed failure and progress evidence into finite recovery for both autonomous bots and companions. Change approach, defer destinations, invalidate stale targets, and explain waits without erasing the retained objective.", + "acceptance": [ + "The blocked-target fixture cannot clear its stall clock through attack acceptance when route, damage, and quest progress remain unchanged.", + "After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.", + "A safe partial route remains eligible while it advances a route or waypoint within a bounded route budget.", + "Repeated no-progress defers a destination by map, instance, and geometry revision for a bounded period and allows another useful action.", + "Unknown coverage stays distinct from a verified blocked route and reports the missing imported coverage evidence.", + "Death, full bags, absent targets, an unreachable giver, a controlled enemy, and a broken prerequisite each end in recovery or an explained finite stop.", + "Recovery remains active for companions and uses follow distance, leader movement, and casting position as its progress evidence.", + "Restarting the fixture preserves the bounded failure memory that prevents immediate reselection of the same failed target." + ], + "model": "gpt-6-astra", + "effort": "high", + "estimated_tokens": 180000, + "status": "ready", + "repo_scope": [ + "Official Package Collection travel and recovery behavior", + "LyraCore Module navigation evidence", + "Durable blocked-route and stalled-work scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-009", + "title": "Honor durable follow, stay, assist, and target orders", + "parent": "S4", + "blocked_by": [ + "PB-004" + ], + "delivery": "Complete the companion command contract through the existing command transport. Persist follow, stay, assist, and designated-target orders, apply them with party authority, and resume valid solo work when human-led control ends.", + "acceptance": [ + "A human party leader can issue follow, stay, assist, and designated-target orders through the existing command transport.", + "Each accepted order persists as typed control state and produces an explanation entry with Actor, target where relevant, and outcome.", + "Follow tracks the leader, stay holds the commanded location within movement tolerances, and assist limits initiation to the chosen fight.", + "A designated target participates in candidate identity and cannot be replaced by another proposal's target when scores change.", + "Controlled enemies remain ineligible while assist or target orders are active unless an explicit higher-priority survival decision records why control was broken.", + "Joining a human-led party suspends autonomous travel and opportunistic grouping without deleting the solo objective.", + "Leaving the party invalidates companion actions, rechecks the retained solo objective, and resumes it only when it is still eligible.", + "Role and command state survive companion death and remain consistent after regrouping." + ], + "model": "gpt-5.6-sol", + "effort": "high", + "estimated_tokens": 150000, + "status": "ready", + "repo_scope": [ + "Official Package Collection commands and control state", + "LyraCore Gateway command transport and Module party reads", + "Durable join and leave scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-010", + "title": "Preserve one controller through restart and Transfer", + "parent": "S4", + "blocked_by": [ + "PB-008", + "PB-009" + ], + "delivery": "Define and prove the lifecycle of every new bot row across Character deletion, Module restart, Gateway restart, party changes, and Transfer. Suspend local actions while Transfer is pending, rebuild transient observations on arrival, and prevent stale work from acting.", + "acceptance": [ + "Each durable Package row has an explicit keep, move, rebuild, or delete rule for Character deletion and Transfer.", + "A pending Transfer suspends local actions and relies on authoritative Transfer state rather than timeout to create another executor.", + "The retained quest or party objective, control mode, role, deadlines, deferred destinations, and bounded failure memory survive their defined restart and Transfer cases.", + "Transient targets and route segments do not Transfer; arrival rebuilds them against the destination's content and geometry revisions.", + "Pending work carries controller generation and location, and an old completion cannot advance a new action after restart or arrival.", + "Restart fixtures interrupt active movement, cast, provisioning, quest reward, and Transfer stages without duplicating a Character, item, supply grant, reward, or active controller.", + "A transferred companion retains the correct party and role on arrival, and a transferred autonomous bot resumes or invalidates its objective for a recorded reason.", + "One instance entry and exit through the real routing path preserves companion orders and produces arrival evidence." + ], + "model": "gpt-6-astra", + "effort": "high", + "estimated_tokens": 180000, + "status": "ready", + "repo_scope": [ + "Official Package Collection bot row lifecycle", + "LyraCore Module, Gateway, Realm-core, Transfer, and Group Intent integration", + "Durable restart and Transfer scenarios" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-011", + "title": "Pass autonomous, companion, and load acceptance", + "parent": "S5", + "blocked_by": [ + "PB-005", + "PB-007", + "PB-008", + "PB-010" + ], + "delivery": "Run the complete automated release suites on the pinned core, Package, imported content, and geometry. Prove seeded autonomous work, the fixed human-led companion route, restart and Transfer behavior, bounded recovery, scheduler fairness, and measured 10, 25, and 100 bot load.", + "acceptance": [ + "Ten seeded runs per starter class execute the supported Northshire and Elwynn catalog; at least 95 percent finish each supported scenario without Operator help and every other run ends with an explained outcome.", + "Autonomous acceptance includes kill, collect, talk-only chains, supported simple GameObject use, travel beyond the former home leash, turn-in, death, combat interruption, full bags, absent targets, an unreachable giver, and unsupported objective admission.", + "One human-controlled Character and four bots complete the fixed repeated-pull route with explicit roles, follow and stay, assist and designated target, wounded allies and missing buffs between fights, loss of line of sight, controlled enemies, death, regrouping, and one instance entry and exit.", + "The companion fixtures produce no unrequested pull, unexplained role abandonment, repeated cast start, or attack against an obsolete target.", + "Every supported action covers success, waiting, Refusal, cancellation, and expiry through the highest suitable behavior seam.", + "Restart and Transfer acceptance shows no duplicate Character, equipment, supply grant, quest reward, or controller and no stale action at the old location.", + "Named disposable load runs execute 10, 25, and 100 bots and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and slowest due bot.", + "The load report sets a measured deployment capacity, records fixture resources and revisions, and accounts for every deferred due bot without silent loss.", + "All relevant repository checks and both specification and standards reviews pass at the pinned revisions." + ], + "model": "gpt-6-astra", + "effort": "xhigh", + "estimated_tokens": 180000, + "status": "ready", + "repo_scope": [ + "LyraCore and Official Package Collection acceptance suites", + "Headless Client protocol and world-transition scenarios", + "Disposable imported-world load fixture and measurement report" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [] + }, + { + "id": "PB-012", + "title": "Cut over, observe, and retire the old behavior", + "parent": "S5", + "blocked_by": [ + "PB-011" + ], + "delivery": "Complete the additive state cutover with one durable controller selector, compare record-only decisions, activate a small cohort, gather imported-world and attended client evidence, then delete the displaced behavior source, obsolete tests, and active old state path. Leave old table retirement as its separately reviewed migration when required by repository rules.", + "acceptance": [ + "The additive state migration defines defaults and backfill, and exactly one durable selector makes one runner eligible to control each bot.", + "Record-only comparison on fixed facts issues no gameplay actions and reports deterministic policy disagreements before cohort activation.", + "A small active cohort can freeze without a second controller and can resume after the failure reason is recorded.", + "Both automated release suites from PB-011 pass again with the new runner selected and no old runner actions.", + "A one-hour imported-world observation runs 25 bots and records no unexplained stall, repeated Refusal spam, visible clipping, or idle injured healer.", + "An attended session in a real unmodified 1.12.1 client exercises the companion route and signs off follow, stay, assist, target choice, crowd-control respect, real casts, death, regrouping, and instance entry and exit.", + "If the implementation environment cannot run the real client, the exact observation script, fixture revisions, capture format, and diagnostic reads are ready, and this acceptance item remains explicitly pending human evidence.", + "The displaced behavior source, obsolete helper-shape tests, broad internal exports, active old controller path, and unused old state access are deleted after acceptance.", + "Repository checks prove the deleted behavior source cannot regain control and no production code reads or writes obsolete active state.", + "Any physical old-table removal has its own reviewed migration plan and does not weaken the completed single-controller cutover." + ], + "model": "gpt-6-astra", + "effort": "xhigh", + "estimated_tokens": 180000, + "status": "ready", + "repo_scope": [ + "Official Package Collection controller cutover and source retirement", + "LyraCore additive state migration and architecture checks", + "Imported-world observation and attended client evidence" + ], + "owner": "Unassigned", + "prs": [], + "evidence": [], + "notes": [], + "acceptance_evidence": [], + "required_observations": [ + "imported_world", + "attended_client" + ], + "observations": {} + } + ], + "updated_at": "2026-09-08 11:00 UTC", + "summary": "PB-001 is implementing the first tracer. The existing Package-enabled durable baseline passed both personality tests in a private fixture." +} diff --git a/docs/research/playerbots-rewrite.html b/docs/research/playerbots-rewrite.html new file mode 100644 index 000000000..444ba8c05 --- /dev/null +++ b/docs/research/playerbots-rewrite.html @@ -0,0 +1,324 @@ + + + + + +Playerbots rewrite proposal | LyraCore + + + +
+

Playerbots rewrite proposal

+

You want bots that stop getting stuck, make sound decisions, level and quest on their own, and work as companions in a human-led party. You permit automatic training, gear, and supplies. Every part of the current Package may change or disappear.

+

Recommendation: replace the behavior implementation with a small Rust decision system shaped by AzerothCore Playerbots. Give it retained objectives, explicit action outcomes, and bounded recovery. Rework core movement where its current interface cannot support those promises.

+

Research dated 8 September 2026. Core 95e6ad8, Official Package Collection c32b2fb, AzerothCore Playerbots b949b50. This is a source-based proposal. The deployed Package revision and runtime failure rate were not inspected.

+
+
+ +
+ +
+

Execution tracker

+

The spec and tickets below drive implementation. Expand a title for the behavior, acceptance criteria, and recorded evidence. Parent totals include every child. Completion requires reviewed evidence for every criterion and merged PRs. The final ticket also requires imported-world and attended-client observation records.

+

Updated 2026-09-08 11:00 UTC. PB-001 is implementing the first tracer. The existing Package-enabled durable baseline passed both personality tests in a private fixture.

+

Ready to start: No unassigned work is ready.. The orchestrator republishes progress to this URL. Filters operate on this published snapshot.

+
+ + + + +
+

12 tickets

+
IdentifierSpec and ticket hierarchyStatusOwnerBlocked byPull requests
PB
Spec
Rewrite playerbots around durable objectives and typed action outcomes

Problem statement

The current playerbots Package can accept an action without proving that the action completed, loses route results, treats attempted combat as quest progress, bypasses the normal cast lifecycle, and retains too little purpose across interruption, restart, and Transfer. Bots can therefore stall, repeat work, choose an obsolete target, or abandon useful intent without explaining why. The current tests also do not prove the Package and core together against real actor operations, imported content, navigation, protocol transitions, and sustained load.

Solution

Replace the behavior control flow with one typed Rust decision runner shared by autonomous bots and human-led companions. The runner observes bounded facts, composes supported Strategies, ranks target-bearing candidates deterministically, executes actions through core operations, records typed outcomes, and retains one durable objective with bounded failure memory. Build the rewrite through a pinned real Module and Package fixture, then prove companion behavior, provisioning, seeded quest loops, recovery, commands, restart, Transfer, load, cutover, and attended client behavior before deleting the displaced implementation.

User stories

  1. As an Operator, I want every bot controlled by one eligible runner, so that two behavior systems cannot issue conflicting actions.
  2. As an Operator, I want a stopped bot to report its objective, target, chosen action, outcome, retry count, next eligible time, and content revision, so that I can diagnose it without reading source.
  3. As an Operator, I want decision work scheduled in bounded fair batches, so that a large roster cannot monopolize a Module tick.
  4. As an Operator, I want excess due bots deferred with recorded lag, so that overload does not silently discard durable work.
  5. As an Operator, I want repeatable provisioning profiles, so that I can explain why a bot received a spell, item, or supply.
  6. As an Operator, I want deployment capacity based on measured runs of 10, 25, and 100 bots, so that release limits reflect this implementation.
  7. As a developer, I want fixed facts and time to produce the same decision, so that policy changes have reproducible tests.
  8. As a developer, I want candidates identified by action, target, and relevant event, so that a higher score cannot retain the wrong target.
  9. As a developer, I want each supported action to return a typed outcome, so that success, waiting, Refusal, cancellation, expiry, and infrastructure failure remain distinct.
  10. As a developer, I want action prerequisites, alternatives, and continuers to be bounded, so that retries and cycles cannot run forever.
  11. As a developer, I want a reproducible Module and Package fixture at pinned revisions, so that failures and fixes can be compared against the same content and geometry.
  12. As a developer, I want casts to use the normal core cast-start lifecycle, so that cast time, interruption, cancellation, cost, and completion use the same Gates as client casts.
  13. As a developer, I want movement outcomes to preserve route completion and coverage evidence, so that policy can distinguish progress, a partial route, blockage, and unknown coverage.
  14. As an autonomous bot, I want one objective retained across tactical interruptions, so that defending myself does not erase my quest purpose.
  15. As an autonomous bot, I want quest admission to require an executor for every required objective, so that unsupported quests do not trap me.
  16. As an autonomous bot, I want to accept, travel for, complete, and turn in a supported kill quest, so that I can earn normal quest credit and XP.
  17. As an autonomous bot, I want to find the actual drop source, loot it, and turn in a supported collect quest, so that collection progress comes from gameplay outcomes.
  18. As an autonomous bot, I want supported talk-only chains and simple GameObject objectives executed through normal core interactions, so that a quest route does not stop at a non-combat step.
  19. As an autonomous bot, I want the actual quest ender retained from the catalog, so that I travel to the correct turn-in Character or GameObject.
  20. As an autonomous bot, I want death, combat, full bags, absent targets, and temporary route failure to have finite recovery rules, so that I can resume or stop with a specific reason.
  21. As an autonomous bot, I want a failed destination deferred by map, instance, and geometry revision, so that a restart cannot immediately choose the same failed target again.
  22. As an autonomous bot, I want skill and spell training, vanilla talents, equipment, and supplies reconciled on spawn and level-up through core Gates, so that I remain playable without receiving invalid progress.
  23. As a human party leader, I want a companion to follow or stay on command, so that I control its position.
  24. As a human party leader, I want a companion to assist my chosen fight or a designated target, so that it does not pull an unrelated enemy.
  25. As a human party leader, I want companions to respect controlled enemies, so that crowd control is not broken by autonomous target choice.
  26. As a human party leader, I want each companion to retain an explicit tank, healer, or damage role, so that party behavior remains predictable through death and Transfer.
  27. As an injured party member, I want a Priest companion to repair range or line of sight and complete one real heal cast, so that repeated decisions do not restart the cast bar.
  28. As a party member, I want a Warrior tank to hold the chosen fight and a Mage damage companion to act at class-appropriate range, so that role does not erase class capabilities.
  29. As a companion, I want joining a human-led party to suspend autonomous travel and leaving it to resume a still-valid solo objective, so that control changes preserve useful intent.
  30. As a companion, I want my role, party intent, and retained objective reconciled after restart and Transfer, so that delayed work from the old location cannot act.
  31. As a maintainer, I want the old behavior source and obsolete state retired after both release suites pass, so that one implementation remains authoritative.
  32. As a party member, I want companions to heal and apply useful missing buffs between fights, so that the party starts the next fight ready without repeated redundant casts.

Implementation decisions

  • Use a targeted Rust rewrite of the useful AzerothCore decision grammar. Do not port its C++ runtime, synthetic World Sessions, packet queues, host object graph, or WotLK rules.
  • Keep durable gameplay authority in the Module. Keep party authority in Realm-core. Use existing Transfer and Group Intent routing only for their realm-wide responsibilities.
  • Give the Package one small decision interface, one action execution interface, and one explanation read. Keep internal behavior behind those interfaces.
  • Represent Strategies, triggers, facts, candidates, actions, targets, outcomes, tactical modes, objective stages, and failure reasons with typed values instead of strings and dynamic lookup.
  • Rank candidates with integer scores and stable tie-breaking. Candidate identity includes the action, target, and relevant event. Saved random state may break equal valid choices only.
  • Support bounded prerequisites, alternatives, and continuers. Limit candidate count, graph depth, transitions, and route expansion independently during each decision pass.
  • Allow one foreground action to own movement or a cast. A higher-priority action must explicitly cancel incompatible work before it starts.
  • Retain the quest or party objective across tactical interruption. Store its identity, destination, stage, deadline, last verified progress, deferred destinations, bounded failure memory, and catalog revision.
  • Keep route segments and live target observations transient. Correlate pending work with controller generation and location so stale completions cannot advance current state.
  • Treat action acceptance and actual progress as different facts. Track movement, combat, cast, and quest progress with separate evidence and clocks.
  • Expose typed outcomes from the owning core operations for the actions the selected behaviors require. Preserve existing Gates and atomic Refusal behavior.
  • Route bot spells through the normal cast-start and timed completion lifecycle. A running cast stays retained until completion, interruption, cancellation, or expiry.
  • Preserve complete, partial, blocked, and explicit unknown-coverage movement evidence. Do not infer missing coverage only from absent sparse navigation rows.
  • Derive tactical mode and active Strategies from durable Character, party, combat, aura, health, threat, target, position, and capability facts. Do not create a second authoritative state machine.
  • Use the bounded priority order from the report: lifecycle and Transfer restrictions, immediate survival, urgent party support, the current fight, human orders, maintenance, autonomous quest work, then idle activity.
  • Store an indexed next-decision time per bot, process due bots in stable order with a fixed batch limit, coalesce urgent reconsideration reasons, and record lag for deferred work.
  • Build a versioned supported quest catalog from imported quest relations, objectives, spawns, loot sources, and actual enders. Admit only quests whose required objectives have executors.
  • Start autonomous release coverage with a seeded Northshire and Elwynn catalog and ordinary quest credit and earned XP. Treat this as a bounded proof rather than level 1 to 60 coverage.
  • Start companion release coverage with Warrior tank, Priest healer, and Mage damage capabilities. Store the explicit role and derive a deterministic vanilla default when none is chosen.
  • Support durable follow, stay, assist, and designated-target orders through the existing command transport. Joining a human-led party suspends solo work; leaving rechecks and resumes it when valid.
  • Reconcile skill and spell training, vanilla talent choices, equipment, bags, food, potions, ammo, reagents, and bounded supplies as separate idempotent actions through core Gates. Provisioning never changes level, grants quest completion, deletes quest items, or duplicates owned resources.
  • Add new state through an additive migration and one durable controller selector. Use record-only comparison before a small active cohort, then retire the old controller and its obsolete state after release acceptance.
  • Keep a bounded history of transitions and failures. Do not retain one row for each successful idle decision.

Testing decisions

  • Use the highest real seam available. Pure tests cover deterministic policy, durable Module and Package fixtures cover gameplay operations and navigation, Headless Client scenarios cover protocol and world transitions, and attended client observation covers visible behavior.
  • The baseline fixture pins core commit 95e6ad8c61540f74471e3087897e8c3ef7e065d1 and Package Collection commit c32b2fb7aa405190728034b63ce6eb9a3c0dd6be together with named imported content and geometry revisions.
  • Every supported action has behavioral cases for success, waiting, Refusal, cancellation, and expiry. Infrastructure failures remain separate where the seam can produce them.
  • Durable fixtures call real actor, cast, movement, quest, loot, item, and lifecycle operations. They do not replace gameplay with a simulated combat model.
  • Decision fixtures cover stable candidate order, target-bearing identity, bounded transition graphs, survival against role work, healing against following, and combat interruption against retained quest work.
  • Movement fixtures measure route or waypoint advancement. After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
  • Cast fixtures prove one long cast starts once, survives intervening decisions, and ends once by completion, interruption, cancellation, or expiry.
  • Companion fixtures cover follow, stay, assist, designated target, controlled enemies, poor range, loss of line of sight, wounded allies and missing buffs between fights, death, regrouping, and one instance entry and exit.
  • Autonomous fixtures run ten seeds per starter class through the supported Northshire and Elwynn catalog. At least 95 percent complete each supported scenario without Operator help, and every other seed terminates with an explained outcome.
  • Autonomous mandatory scenarios include kill, collect, talk-only chains, supported simple GameObject use, turn-in, death, interruption, full bags, absent targets, an unreachable giver, unsupported objectives, and restart with a retained objective.
  • Restart and Transfer fixtures interrupt active action and escrow stages. They prove no duplicate Character, equipment, supply grant, quest reward, or active controller and prove stale work cannot act on the old location.
  • Load fixtures run 10, 25, and 100 bots on one named disposable fixture and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and the slowest due bot before capacity is set.
  • Final observation requires one hour with 25 bots on imported content plus an attended companion session in a real unmodified 1.12.1 client. A human must collect and sign off this evidence if the implementation environment cannot run that client.
  • Review final behavior against this specification and repository standards after the focused and full relevant checks pass.

Out of scope

  • A direct or mechanical port of the complete AzerothCore playerbots runtime.
  • Synthetic World Sessions or packet observation inside the Package.
  • A user-defined action language, global string factory, client addon, or new product UI.
  • Claims of general level 1 to 60 quest coverage, all classes, all regions, all dungeons, or thousands of bots.
  • Exploration, escort, scripted-event, transport, and other quest objective types until they receive explicit executors and catalog support.
  • Routine catch-up teleportation through blocked geometry.
  • A full economy simulation or provisioning that changes level, fabricates quest credit, clears inventory, or completes prerequisite quests.
  • A full Deadmines run unless the team later selects it as the first dungeon milestone.
  • Production realm changes, live database inspection, publication, or deployment as part of implementation and local acceptance.

Further notes

  • The source report proposes acceptance thresholds. Implementation must measure them before treating them as release facts.
  • Bad or stale imported geometry can imitate a policy defect. Every route fixture and observation record names its content and geometry revisions.
  • The source comparison found no behavioral assertion suite in the pinned AzerothCore tree. Its architecture is evidence for design choices, not proof of LyraCore behavior.
  • Record provenance if any reference code is copied or translated. The architecture proposal does not make a license-compatibility conclusion.
  • Attended real-client observation is a release gate that may require a human after agent implementation. The implementation tickets must prepare the exact scenario, capture format, and diagnostic reads without claiming that a client session already ran.
  • Unresolved product choices remain level range beyond the initial catalog, the first full dungeon milestone, equipment strength beyond level-appropriate starter gear, and any explicit catch-up travel policy. They do not block the bounded first release.
  • The user authorized autonomous implementation, PR ownership through review, and confident merges. The HTML is the tracker; no issue publication or planning interview is required. Production changes remain outside this authorization.
Parent: Root
0/12 completeOrchestratorNonePending
S1
Workstream
Typed action foundation and durable runner

Typed action foundation and durable runner

Parent: PB
0/2 completeOrchestratorNonePending
PB-001
Ticket
Prove typed outcomes in a real pinned fixture

Create the first tracer through a reproducible pinned Module and Package fixture. Drive attack, interaction, movement, and cast-start through real core operations, return typed outcomes to the Package, and capture the blocked-target and out-of-range-heal failures that the rewrite must fix.

Acceptance criteria

  • The fixture records the pinned core, Package, imported content, and geometry revisions and can reproduce the same initial state and outcome.
  • The fixture loads and runs the real Module with the real Package; it does not substitute a simulated gameplay engine.
  • Attack acceptance is distinct from damage and quest progress, and an attempted attack with no hit cannot clear a quest progress clock.
  • Movement reports complete, safe partial, blocked, or explicit unknown-coverage evidence with route or waypoint advancement where applicable.
  • Interaction and cast-start return typed success, waiting, Refusal, cancellation, and expiry outcomes supported by their owning operations.
  • A long bot cast uses the normal core cast lifecycle and completes once without restart on later decision ticks.
  • The blocked target and poor-range heal cases have reproducible inputs, observed outcomes, and enough evidence to compare later runner behavior.
  • A written extraction comparison chooses the smaller total implementation and records why the full AzerothCore runtime is not used.

Verified criteria: 0/8.

Execution model: gpt-6-astra, high effort. Repositories: LyraCore Module action and navigation contracts, Official Package Collection playerbots fixture, Local durable integration tests.

Recorded evidence

  • Baseline on core 95e6ad8 and Package c32b2fb: both ignored personality durable tests passed in a private loopback Standalone. This proves the existing Package fixture, not the new outcome contract.

Current notes

  • The implementer owns the isolated core and Package worktrees and the serialized build slot. The orchestrator owns independent review and merge order.
Parent: S1
implementingPB-001 implementerNonePending
PB-002
Ticket
Run one durable objective through bounded decisions

Build the shared decision runner around typed facts and outcomes. Retain one objective, arbitrate one foreground action, schedule bots in stable bounded batches, and explain each meaningful choice through the Package's normal entry point.

Acceptance criteria

  • Fixed facts and explicit time produce the same target-bearing candidate order and chosen action.
  • Strategies compose supported triggers, defaults, and priority rules without a global string registry or a second authoritative state machine.
  • Prerequisites, alternatives, and continuers have explicit depth, transition, candidate, and route-work limits with cycle refusal.
  • Only one foreground movement or cast action owns the bot, and a higher-priority action explicitly cancels incompatible work.
  • The durable objective records identity, destination, stage, deadline, last verified progress, bounded failures, deferred destinations, and catalog revision.
  • Separate movement, combat, cast, and quest progress evidence prevents an accepted action from masquerading as completion.
  • Due bots run in stable indexed order under a per-pass limit; excess work remains due, gets a fair next turn, and records scheduler lag.
  • The explanation read reports the current objective and target, chosen action and reason, last outcome, progress age, retry count, next eligible time, and relevant revision with bounded history.
  • The additive state migration defines defaults and backfill and adds a durable controller selector before any bot can use the new runner. Record-only mode emits no gameplay actions; cohort mode has one eligible controller and supports freeze.

Verified criteria: 0/9.

Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection decision and durable state, LyraCore Module scheduling and diagnostics, Pure decision and durable integration tests.

Parent: S1
plannedUnassignedPB-001Pending
S2
Workstream
Companions and provisioning

Companions and provisioning

Parent: PB
0/3 completeOrchestratorNonePending
PB-003
Ticket
Make a Priest follow, heal, and resume

Complete the first human-led companion loop. A Priest follows its party leader, retains an injured ally as the heal target, repairs range or line of sight, casts through the real lifecycle, handles interruption, and resumes following.

Acceptance criteria

  • Joining a human-led party suspends autonomous travel and selects companion Strategies from durable party facts.
  • The Priest follows a moving leader without starting a fight against an unrelated nearby enemy.
  • An injured ally outranks ordinary following when the Priest has a usable heal and the survival policy permits it.
  • Poor range or line of sight produces a movement prerequisite that retains the injured ally and finds a reachable casting position or records a specific wait.
  • The heal starts one real timed cast, does not restart on repeated decisions, and observes completion or interruption through typed outcomes.
  • After healing, cancellation, or a recoverable interruption, the Priest resumes following without losing party control state.
  • Death and resurrection preserve the companion role and lead to regrouping rather than a permanent solo objective change.

Verified criteria: 0/7.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection companion support behavior, LyraCore Module cast and party fact reads, Durable companion scenarios.

Parent: S2
plannedUnassignedPB-002Pending
PB-004
Ticket
Complete starter roles, target choice, and crowd control

Add Warrior tank and Mage damage behavior beside the Priest healer on the shared runner. Make explicit durable roles, vanilla class capabilities, chosen-target assistance, controlled-enemy avoidance, death, rest, and regrouping work through repeated party pulls.

Acceptance criteria

  • Warrior, Priest, and Mage have validated ability sets at every level supported by the companion fixture.
  • Each companion retains an explicit tank, healer, or damage role, with a deterministic vanilla-derived default when no role was selected.
  • The Warrior tank chooses and holds the party's selected fight according to survival and threat facts rather than inheriting damage-only retreat behavior.
  • The Mage acts at class-appropriate range and role does not force a ranged class into melee.
  • All companions honor the party's chosen fight and designated target and do not initiate an unrequested pull.
  • Controlled enemies remain ineligible unless the control is intentionally broken by a higher-priority survival rule with a recorded reason.
  • Repeated-pull fixtures cover wounded allies between fights, target death or disappearance, loss of line of sight, companion death, rest, and regrouping without role abandonment.
  • Between fights, companions select useful missing class buffs, repair casting position when needed, apply them through real core casts, observe the resulting auras, and avoid redundant recasting while the buff remains valid.

Verified criteria: 0/8.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection starter class and role behavior, LyraCore Module combat and capability facts, Durable repeated-pull party scenarios.

Parent: S2
plannedUnassignedPB-003Pending
PB-005
Ticket
Provision playable bots without duplicating progress

Reconcile the supported bot's skills, spells, vanilla talents, equipment, bags, food, potions, ammo, reagents, and bounded supplies on spawn and level-up through real core operations. Make each action idempotent and explain it by provisioning profile and revision.

Acceptance criteria

  • Provisioning runs on spawn and level-up and periodically repairs only resources owned by the selected profile.
  • Spell learning, equipment, inventory, uniqueness, proficiency, class, and level rules pass through core operations. Free provisioning is an explicit profile choice; its grants remain bounded and attributable.
  • Skill training and vanilla talent choices follow the selected class profile through the owning core Gates. Prerequisites, earned talent points, rank limits, and level restrictions hold, and reconciliation cannot spend a point or train a rank twice.
  • Repeated reconciliation does not create duplicate equipment, unlimited supplies, repeated spell grants, or repeated costs.
  • The policy respects an equipped upgrade, does not delete quest items, and never raises a bot's level to match a leader.
  • Quest credit, earned XP, loot entitlement, and quest completion remain consequences of normal gameplay operations.
  • Full bags, missing consumables, resource recovery, rest, and death produce bounded next actions or an explained stop.
  • Decision history records the provisioning profile, revision, chosen action, and typed outcome.

Verified criteria: 0/8.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection provisioning policy, LyraCore Module skill, spell, talent, item, inventory, and equipment operations, Durable idempotency scenarios.

Parent: S2
plannedUnassignedPB-002Pending
S3
Workstream
Autonomous questing and recovery

Autonomous questing and recovery

Parent: PB
0/3 completeOrchestratorNonePending
PB-006
Ticket
Admit supported quests from a seeded catalog

Build a versioned quest catalog for the initial Northshire and Elwynn proof from imported relations, objectives, spawns, loot sources, and actual enders. Admit a quest only when every required objective has a supported executor, and retain the chosen objective and destination.

Acceptance criteria

  • The catalog records quest eligibility, each objective kind, target or drop source, actual ender, work area, destination evidence, and content revision.
  • The initial fixture contains a named supported Northshire and Elwynn catalog with deterministic seeds for each starter class.
  • Admission checks ordinary core eligibility and confirms an executor for every required objective before acceptance.
  • Unsupported exploration, escort, scripted event, transport, and complex GameObject requirements remain explicit and cannot enter a futile loop. Mixed quests are admitted only when every required kind has an executor, including supported talk-only and simple GameObject steps.
  • A live creature search chooses what can be acted on now but does not decide whether a quest destination exists in imported content.
  • The retained objective stores the actual ender and catalog revision and survives a tactical combat interruption.
  • If a held quest becomes unsupported, the bot records the missing capability and proceeds to another supported objective or a specific wait without repeated abandonment and reacceptance.

Verified criteria: 0/7.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection quest catalog and admission, LyraCore imported quest and world relations, Seeded durable catalog scenarios.

Parent: S3
plannedUnassignedPB-002Pending
PB-007
Ticket
Finish supported autonomous quest loops

Complete supported kill, collect, talk-only, and simple GameObject quest loops. The bot accepts the quest, retains its objective, travels through real navigation, executes the required gameplay, earns ordinary credit and XP, turns in to the actual ender, and selects the next supported work.

Acceptance criteria

  • A supported kill quest completes through accepted combat, actual damage and death, kill credit, travel, and turn-in rather than a changed internal label.
  • A supported collect quest hunts an explicit eligible drop source, receives the item through real loot and inventory operations, and turns in to the catalog's actual ender.
  • A supported talk-only chain advances through actual quest eligibility, giver and ender interactions, and ordinary rewards without manufacturing prerequisite completion.
  • At least one cataloged simple GameObject objective completes through the owning core use or loot operation, respects range and object state, and earns credit once. Unsupported scripted object behavior is refused at admission.
  • Quest objective progress changes only when the authoritative core gameplay outcome changes it.
  • The retained quest objective survives combat interruption, death, rest, and provisioning, then resumes after rechecking eligibility.
  • Target death, disappearance, or ineligibility cancels only the current action and selects a new eligible target or an explicit respawn wait.
  • A completed turn-in grants ordinary rewards once and advances to another supported catalog entry without Operator help.
  • Seeded scenarios cover Warrior, Priest, and Mage and produce reproducible decision and outcome histories.
  • A supported quest destination outside the former home leash remains reachable under the current work area and retained destination. Tactical retreat returns to an appropriate safe position in the current partition and cannot reset travel to the spawn home.

Verified criteria: 0/10.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection autonomous quest behavior, LyraCore Module quest, combat, loot, inventory, and navigation operations, Seeded durable quest scenarios.

Parent: S3
plannedUnassignedPB-005, PB-006Pending
PB-008
Ticket
Recover from blocked travel and stalled quest work

Turn typed failure and progress evidence into finite recovery for both autonomous bots and companions. Change approach, defer destinations, invalidate stale targets, and explain waits without erasing the retained objective.

Acceptance criteria

  • The blocked-target fixture cannot clear its stall clock through attack acceptance when route, damage, and quest progress remain unchanged.
  • After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
  • A safe partial route remains eligible while it advances a route or waypoint within a bounded route budget.
  • Repeated no-progress defers a destination by map, instance, and geometry revision for a bounded period and allows another useful action.
  • Unknown coverage stays distinct from a verified blocked route and reports the missing imported coverage evidence.
  • Death, full bags, absent targets, an unreachable giver, a controlled enemy, and a broken prerequisite each end in recovery or an explained finite stop.
  • Recovery remains active for companions and uses follow distance, leader movement, and casting position as its progress evidence.
  • Restarting the fixture preserves the bounded failure memory that prevents immediate reselection of the same failed target.

Verified criteria: 0/8.

Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection travel and recovery behavior, LyraCore Module navigation evidence, Durable blocked-route and stalled-work scenarios.

Parent: S3
plannedUnassignedPB-004, PB-007Pending
S4
Workstream
Commands, Transfer, and restart

Commands, Transfer, and restart

Parent: PB
0/2 completeOrchestratorNonePending
PB-009
Ticket
Honor durable follow, stay, assist, and target orders

Complete the companion command contract through the existing command transport. Persist follow, stay, assist, and designated-target orders, apply them with party authority, and resume valid solo work when human-led control ends.

Acceptance criteria

  • A human party leader can issue follow, stay, assist, and designated-target orders through the existing command transport.
  • Each accepted order persists as typed control state and produces an explanation entry with Actor, target where relevant, and outcome.
  • Follow tracks the leader, stay holds the commanded location within movement tolerances, and assist limits initiation to the chosen fight.
  • A designated target participates in candidate identity and cannot be replaced by another proposal's target when scores change.
  • Controlled enemies remain ineligible while assist or target orders are active unless an explicit higher-priority survival decision records why control was broken.
  • Joining a human-led party suspends autonomous travel and opportunistic grouping without deleting the solo objective.
  • Leaving the party invalidates companion actions, rechecks the retained solo objective, and resumes it only when it is still eligible.
  • Role and command state survive companion death and remain consistent after regrouping.

Verified criteria: 0/8.

Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection commands and control state, LyraCore Gateway command transport and Module party reads, Durable join and leave scenarios.

Parent: S4
plannedUnassignedPB-004Pending
PB-010
Ticket
Preserve one controller through restart and Transfer

Define and prove the lifecycle of every new bot row across Character deletion, Module restart, Gateway restart, party changes, and Transfer. Suspend local actions while Transfer is pending, rebuild transient observations on arrival, and prevent stale work from acting.

Acceptance criteria

  • Each durable Package row has an explicit keep, move, rebuild, or delete rule for Character deletion and Transfer.
  • A pending Transfer suspends local actions and relies on authoritative Transfer state rather than timeout to create another executor.
  • The retained quest or party objective, control mode, role, deadlines, deferred destinations, and bounded failure memory survive their defined restart and Transfer cases.
  • Transient targets and route segments do not Transfer; arrival rebuilds them against the destination's content and geometry revisions.
  • Pending work carries controller generation and location, and an old completion cannot advance a new action after restart or arrival.
  • Restart fixtures interrupt active movement, cast, provisioning, quest reward, and Transfer stages without duplicating a Character, item, supply grant, reward, or active controller.
  • A transferred companion retains the correct party and role on arrival, and a transferred autonomous bot resumes or invalidates its objective for a recorded reason.
  • One instance entry and exit through the real routing path preserves companion orders and produces arrival evidence.

Verified criteria: 0/8.

Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection bot row lifecycle, LyraCore Module, Gateway, Realm-core, Transfer, and Group Intent integration, Durable restart and Transfer scenarios.

Parent: S4
plannedUnassignedPB-008, PB-009Pending
S5
Workstream
Release evidence and retirement

Release evidence and retirement

Parent: PB
0/2 completeOrchestratorNonePending
PB-011
Ticket
Pass autonomous, companion, and load acceptance

Run the complete automated release suites on the pinned core, Package, imported content, and geometry. Prove seeded autonomous work, the fixed human-led companion route, restart and Transfer behavior, bounded recovery, scheduler fairness, and measured 10, 25, and 100 bot load.

Acceptance criteria

  • Ten seeded runs per starter class execute the supported Northshire and Elwynn catalog; at least 95 percent finish each supported scenario without Operator help and every other run ends with an explained outcome.
  • Autonomous acceptance includes kill, collect, talk-only chains, supported simple GameObject use, travel beyond the former home leash, turn-in, death, combat interruption, full bags, absent targets, an unreachable giver, and unsupported objective admission.
  • One human-controlled Character and four bots complete the fixed repeated-pull route with explicit roles, follow and stay, assist and designated target, wounded allies and missing buffs between fights, loss of line of sight, controlled enemies, death, regrouping, and one instance entry and exit.
  • The companion fixtures produce no unrequested pull, unexplained role abandonment, repeated cast start, or attack against an obsolete target.
  • Every supported action covers success, waiting, Refusal, cancellation, and expiry through the highest suitable behavior seam.
  • Restart and Transfer acceptance shows no duplicate Character, equipment, supply grant, quest reward, or controller and no stale action at the old location.
  • Named disposable load runs execute 10, 25, and 100 bots and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and slowest due bot.
  • The load report sets a measured deployment capacity, records fixture resources and revisions, and accounts for every deferred due bot without silent loss.
  • All relevant repository checks and both specification and standards reviews pass at the pinned revisions.

Verified criteria: 0/9.

Execution model: gpt-6-astra, xhigh effort. Repositories: LyraCore and Official Package Collection acceptance suites, Headless Client protocol and world-transition scenarios, Disposable imported-world load fixture and measurement report.

Parent: S5
plannedUnassignedPB-005, PB-007, PB-008, PB-010Pending
PB-012
Ticket
Cut over, observe, and retire the old behavior

Complete the additive state cutover with one durable controller selector, compare record-only decisions, activate a small cohort, gather imported-world and attended client evidence, then delete the displaced behavior source, obsolete tests, and active old state path. Leave old table retirement as its separately reviewed migration when required by repository rules.

Acceptance criteria

  • The additive state migration defines defaults and backfill, and exactly one durable selector makes one runner eligible to control each bot.
  • Record-only comparison on fixed facts issues no gameplay actions and reports deterministic policy disagreements before cohort activation.
  • A small active cohort can freeze without a second controller and can resume after the failure reason is recorded.
  • Both automated release suites from PB-011 pass again with the new runner selected and no old runner actions.
  • A one-hour imported-world observation runs 25 bots and records no unexplained stall, repeated Refusal spam, visible clipping, or idle injured healer.
  • An attended session in a real unmodified 1.12.1 client exercises the companion route and signs off follow, stay, assist, target choice, crowd-control respect, real casts, death, regrouping, and instance entry and exit.
  • If the implementation environment cannot run the real client, the exact observation script, fixture revisions, capture format, and diagnostic reads are ready, and this acceptance item remains explicitly pending human evidence.
  • The displaced behavior source, obsolete helper-shape tests, broad internal exports, active old controller path, and unused old state access are deleted after acceptance.
  • Repository checks prove the deleted behavior source cannot regain control and no production code reads or writes obsolete active state.
  • Any physical old-table removal has its own reviewed migration plan and does not weaken the completed single-controller cutover.

Verified criteria: 0/10.

Imported world observation

Pending. Required before completion.

Attended client observation

Pending. Required before completion.

Execution model: gpt-6-astra, xhigh effort. Repositories: Official Package Collection controller cutover and source retirement, LyraCore additive state migration and architecture checks, Imported-world observation and attended client evidence.

Parent: S5
plannedUnassignedPB-011Pending
+
+ + + +
+

1. Replace the behavior system

+

The current code can issue gameplay actions. It has much less machinery for deciding whether an action worked, keeping a useful commitment, or escaping a failed attempt. Splitting its large file would leave that problem intact.

+

Preserve contracts that prove useful, then reimplement behind them. Real Characters, core gameplay Gates, Transfer, and the existing movement Relay are strong starting points because bots already share them with human-controlled Characters. None requires preserving the current goal table, branch order, or rotation format. Actor contract, Character-backed roster.

+
+ + + + + + +
OptionWhat it buysWhat it costsJudgment
Adapt the whole AzerothCore runtimeA large catalog of class, travel, social, and encounter behavior.Replace direct dependencies on AzerothCore world objects, sessions, navigation, scheduling, and WotLK gameplay. Reconcile its state with SpacetimeDB authority.Too much unrelated work for these release goals. Reconsider if LyraCore chooses AzerothCore as its underlying gameplay core.
Port its decision kernel mechanicallyReuse the existing runner and its prerequisite/fallback semantics.Separate its context, factories, action names, timing, and core object access. Still implement LyraCore actions and durable state.Compare the small kernel directly. Once host dependencies and string factories are removed, a Rust adaptation converges on the recommended rewrite.
New Rust behavior using its designKeep the useful action grammar. Make persistence, Refusals, and tests fit LyraCore directly.Build and verify each supported behavior. Audit reference strategies against vanilla mechanics.Recommended. Best fit for reliable questing and companions with a maintainable codebase.
Refactor the current branchesSmall initial change and familiar code.Add retained state, outcomes, recovery, support behavior, and travel across the existing control flow.Useful for extracting contracts and fixtures. Poor destination for the full change.
+

AzerothCore Playerbots requires a custom AzerothCore fork. The project describes random bots, companions, raids, and battlegrounds, but those features run inside that host. Its installation requirement is evidence of integration cost; its feature list is not proof of stability on LyraCore. Reference README.

+

The full reference tree contains about 244,000 C++ lines, including headers and comments. A scoped inventory of the decision kernel is 2,967 lines across the runner, base objects, context, actions, strategies, triggers, values, multipliers, events, and queue. The smaller extraction deserves consideration on its own. Even there, the base objects retain pointers to AzerothCore's Character and AI objects, and events carry packets. Replacing those dependencies with typed facts and durable identifiers is already a small rewrite. Object dependencies, Event dependencies.

+

Keep the comparison small and fair. Compare candidate ordering, prerequisites, alternatives, and continuers against the reference kernel on fixed facts. Separately prove LyraCore's actions and durable objective state with follow, heal, failed-route, and restart scenarios. A mechanical extraction wins only if its total integration is simpler. The recommended Rust adaptation keeps the reference semantics where useful and makes the deliberate changes listed below.

+
+ +
+

2. The code explains several failure modes

+

The findings below are source facts followed by their likely visible effect. They are not claims that a particular deployed bot was reproduced. The current collection has navigation fixes, including instance-aware queries. An older local branch and parts of the README still describe straight-line movement, so those descriptions are not a safe baseline.

+
+ + + + + + + + + + + +
Source factWhat a Character seesRequired change
Attempted combat counts as progresswork_quest calls fight, then reports progress. fight returns no result. A quest enemy behind geometry can keep clearing the stall clock without a hit or quest increment.Track action acceptance separately from damage, objective counts, items, XP, and route advancement. Quest work, Combat execution.
Movement loses the route resultThe shared search can distinguish complete and partial routes. nav_step exposes only coordinates. A failed search aims directly toward the target, and collision can clip that move back to the same position.Expose completion, partial search, blockage, and coverage evidence. Return movement outcomes to the action runner. Search result, Movement caller.
No retained quest/action destinationThe goal row stores a kind, timestamps, and one shared quest hub. Selection runs again while walking. It cannot remember an individual failed destination or the actual ender of each quest.Retain the chosen objective and destination, with invalidation and retry rules. Rebuild world references after Transfer. Goal state, Repeated giver selection.
Quest admission exceeds executionA mixed quest is admitted when any objective is kill or collect. Unsupported objectives can hold a slot indefinitely. Drop sources inform admission, but the hunting selector names only kill objectives; a collect-only quest relies on incidental kills.Require an executor for every mandatory objective. Choose creatures for wanted drops explicitly. Defer unsupported quests with a reason. Hunt selector, Admission policy.
Combat holds support behaviorHealing and buffs run through fight. A hurt ally between fights does not enter that rotation. Grouped healers hold position without a move-to-heal prerequisite; every other role closes to melee, including a Mage.Support strategies must run outside combat. Class capabilities determine range. Out-of-range healing must produce a positioning action. Main decision, Roles and rotation.
Fleeing precedes party contextA low-health bot runs toward its stored home coordinates before examining its party or current partition. That can displace a needed tank or send a bot toward coordinates that have no useful meaning on its current map.Separate survival from a universal flee rule. Pick a safe local retreat with party context. Give each role an explicit emergency policy. Flee ordering.
Failures are often discardedAttack outcomes are ignored; failed casts fall through to the next row. A cooldown, poor range, invalid target, or missing capability cannot drive a distinct recovery step.Return typed reasons at the core operation that owns them. Preserve client-facing results while giving bots actionable outcomes. Discarded outcomes.
Bot casts bypass cast-time schedulingactor::cast_at calls resolve_cast_at directly. The normal begin_cast path owns timed completion. Bot casts share resolution Gates, but do not follow the same full lifecycle.Use a cast-start operation and retain the running action until completion, interruption, or cancellation. Repeated decisions must not restart its cast bar. Bot cast operation, Timed cast lifecycle.
Behavior proof is incompleteThe collection tests its code against core main. Core durable CI explicitly skips Package personality tests because the Package is absent. The imported-world observation issue remains open.Test a pinned core and Package together through whole behavior sequences, then observe the real client. Collection check, CI gap, Open observation.
+

A rewrite cannot repair old navigation imports. Core change #479 fixes Abbey route generation and movement checks. The tracked follow-up still requires regenerated navigation and derived coverage. Establish a known content and geometry baseline before using stuck behavior to judge either implementation. This research did not inspect or change any realm. Abbey fix, Remaining import work.

+
+ +
+

3. Borrow AzerothCore's decision grammar

+

AzerothCore separates the question of what matters from the action that tries to satisfy it. Its strategies assemble behavior; triggers propose relevant actions; values provide reusable observations. The runner ranks candidates and handles prerequisites, alternatives, and follow-up actions. Combat, non-combat, and death use separate decision engines. Action selection, Tactical modes.

+
+ + + + + + + + +
Reference conceptUse in LyraCoreChange during adaptation
StrategyA small policy for following, healing, fighting, quest work, or recovery.Compose only supported policies. Use typed identifiers and explicit precedence.
Trigger and valueA condition and its required facts, such as an injured ally and its distance.Read shared facts once per decision. Keep derived observations transient unless measured costs justify a cache with invalidation.
Action and relevanceA candidate intent with a target, priority, and reason.Use named priority bands and a stable tie-breaker. Personality can vary preferences within allowed bands.
Prerequisite, alternative, continuerMove into healing range; choose a different reachable point; resume following after recovery.Represent bounded transitions. A prerequisite must make measurable progress. Limit retry depth and prevent cycles.
Travel targetA retained destination with prepare, travel, work, cooldown, and expiry stages.Persist logical identity and deadlines. Invalidate route details when map, instance, geometry, or target changes.
Population and provisioningSeparate keeping the population useful from moment-to-moment decisions.Use the automatic training, gear, and supply policy you selected. Avoid taking WotLK item, talent, or spell tables as vanilla truth.
+

Primary evidence: strategies, triggers, values, actions, and travel state.

+

Improve on specific weaknesses

+
    +
  • Keep the target in candidate identity. The reference queue merges proposals by action name and only updates relevance. The original event stays. LyraCore should key a candidate by action, target, and relevant event identity so a higher-priority heal does not accidentally keep another proposal's target. Queue behavior.
  • +
  • Return more than a boolean. The reference action's execution result is true or false. LyraCore needs the reason for failure, the prerequisite to repair, and the evidence that an accepted action later completed. Action result.
  • +
  • Make retained travel durable. Its travel target is a manual in-memory value without a save override. Keep its useful stages and deadlines, but persist the logical objective across Module restart and Transfer. Travel value, Save behavior.
  • +
  • Recover while a human is waiting. Travel movement enters cooldown after more than five failed attempts. Separate broad stuck triggers wait five to fifteen minutes and skip bots controlled by a real human. Keep prompt recovery active for companions; do not adopt those general reset thresholds. Travel retries, General stuck checks.
  • +
+

Its travel chooser also uses several random branches and explicitly calls for a smarter replacement. Use deterministic priorities and retained commitments first. Add variety among equally useful choices after behavior is reliable. Destination selection.

+
+ +
+

4. One owner decides, core operations act

+

The Package owns bot policy and a bot's durable objective. The Module owns all gameplay state and Gates. The Gateway continues to route Transfer and Group Intents. A new native process that keeps a second copy of bot decisions would add synchronization work before it solves the current behavior failures. Current authority.

+
+ +Proposed bot decision cycleRead world facts and retained objective. Strategies propose intents. One runner selects an intent and handles prerequisites. Core operations apply gameplay rules. Observed outcomes update the objective and diagnostic history. The Gateway handles realm-wide routing through existing intents. + + +ObserveWorld facts + retained objectiveProposeActive strategies + triggersChoosePriority + commitment rulesExecutePrerequisite or core operationOne compatible set of actionsObserve the outcomeAccepted, waiting, refusedThen confirm actual progressRetain or recoverAdvance, retry, defer, finishKeep a bounded decision recordGateway routes Transfer and Group IntentsRealm-core retains party authority + + +
Proposed design. Core timers still advance casts, swings, movement, and effects. The decision runner selects intent; it does not simulate those mechanics again.
+
+

Keep the external interface small

+
decide(facts, retained_state, now) -> decision
+advance(ctx, character_guid, decision) -> action_outcome
+explain(character_guid) -> current objective and recent decisions
+

These are proposed shapes, not new Package API commitments. The pure decision function receives bounded facts and explicit time. The executor calls real Module operations. Durable integration tests exercise both through the bot's normal entry point. There is no trait for every helper and no separate simulated combat model.

+

Allow one foreground action to own movement or an active cast at a time. Existing auto-attacks and core effect timers may continue. A lower-priority proposal cannot replace a running cast or route; a higher-priority interruption must cancel it explicitly. Starting a long cast and starting it again on the next tick is a failure, even if both calls return success.

+

Retain the objective; interrupt the action

+

A bot walking to turn in a quest should defend itself, heal, and then resume that turn-in. It should not discover a new quest because combat ended. Retain the quest and objective identity, chosen destination, stage, deadline, last verified progress, and deferred candidates. Keep path waypoints and live target observations separate so they can expire without erasing intent.

+

Use a bounded priority order: lifecycle and Transfer restrictions, immediate survival, urgent party support, the current fight, human orders, maintenance, autonomous quest work, then idle activity. A tank's survival policy may choose a defensive ability or local retreat. It should not inherit a damage bot's run-home action. Test each contested pair rather than rely on unexplained numeric scores.

+

Schedule decisions without repeated full work

+

The current pass scans the roster and makes each due bot think once a second. Start from the core-owned tick, then use an indexed due time, stable staggering, and a per-pass work limit. Hooks record an urgent reason to reconsider; they should not become competing policy writers. Coalesce repeated notifications and provide a fair next turn for bots deferred by the limit. Current scheduling, Current defensive hook.

+

Limit route expansions, candidate evaluation, and transition count independently. Do not assume AzerothCore's in-memory caches survive a Module invocation. Add longer-lived caches only with a concrete invalidation key and measured benefit.

+
+ +
+

5. Make failure change the next decision

+

Every running action needs a completion condition, an expiry condition, and a response to failure. An accepted command is not completion. A changed goal label is not progress.

+
+ + + + + + + + + + +
Observed resultRunner responseEvidence of recovery
Cast waits on cooldownKeep the target and wait until the relevant time, unless a higher-priority need appears.No repeated identical cast attempts during the known wait.
Heal has poor range or line of sightMove to a reachable casting position. Keep the injured ally as the target. Recheck health before casting.The next action repairs the failed prerequisite or reports that no position was found.
Route search reaches its budgetUse a safe partial route if it makes route progress. Continue with a bounded budget.Partial planning does not label a reachable destination permanently blocked.
Movement repeatedly makes no progressTry a different approach once, then defer this destination for a bounded period. Include map, instance, and geometry revision in its identity.Retry count is finite. Another useful activity runs, or the bot waits with a specific reason.
Coverage is unknownUse only the core's explicit fallback contract. Do not report a route as verified. Record which imported coverage is absent.A map-data problem is distinguishable from a policy failure. Sparse missing nav rows alone cannot prove missing coverage.
Target dies, disappears, or becomes ineligibleInvalidate that action. Keep the quest objective if it still applies; choose a new eligible target or wait for respawn.The bot does not swing at an obsolete target or restart the entire quest plan.
Quest cannot finish with available capabilitiesDefer it before acceptance. For an already-held quest, stop futile work and record the missing objective support.Its presence does not stop other supported quests or cause repeated abandonment and reacceptance.
Transfer is pendingSuspend local actions. Use authoritative Transfer state for recovery; timeout alone never authorizes a duplicate body or a second executor.Arrival resumes one bot with one objective. Delayed work from the old location cannot act.
+

The current nav format uses absent rows for both clear ground and unimported cells. Exposing NoCoverage therefore requires coverage evidence, not a rename of None. Similarly, Refusal categories belong where the core decides them; parsing arbitrary log strings inside the Package would create another fragile dependency. Sparse navigation contract, Coverage generation.

+

A worked stuck case

+

A wolf behind a wall matches a held quest. Today, the bot calls fight and can record quest progress even while movement stays still. In the proposal, starting an attack records only acceptance. The runner sees no route advancement, damage, or quest change. After the movement deadline, it tries another approach and then defers that wolf. It selects another eligible wolf or waits for one. This is a predicted sequence to turn into a failing fixture, not a test run performed for this report.

+

Measure movement against waypoint or route advancement, not just straight-line distance to the destination. A valid detour may first move away from the goal. Keep separate movement, combat, and quest progress clocks so a long route does not look like a broken quest.

+
+ +
+

6. Build both release goals on the same runner

+

Autonomous leveling and questing

+

Build a bounded catalog from LyraCore's imported quest relations, objectives, creature spawns, and loot sources. Admission checks both core eligibility and whether every required objective has an executor. Store the actual ender for each quest. A live creature search answers what can be acted on now; it should not decide whether a quest destination exists in the world.

+

The first complete loop should accept a quest, retain its objective, travel, kill or collect from the right source, loot, turn in, and continue after death or interruption. Add talk-only chains and supported GameObject use through their real core operations. Exploration, escort, scripted events, transport, and other unsupported objectives remain explicit capabilities to implement, not silent partial support.

+

Replace the permanent home leash with a current work area and a retained next destination. For an initial Northshire and Elwynn proof, choose a small supported quest catalog. General leveling later needs zone transitions, level-appropriate routes, and an explicit response when a chain or region has no supported continuation. A local 1-to-10 run is an initial proof, not a claim of 1-to-60 coverage.

+

Human-led companions

+

Joining a human-led party suspends autonomous travel and opportunistic grouping. The bot follows, assists the party's chosen fight, respects controlled enemies, heals and buffs between fights, and retains its role through death and Transfer. Leaving the party resumes the retained solo objective after rechecking it.

+

Start with Warrior tank, Priest healer, and Mage damage because the existing package already names those roles and classes. Validate the ability set at each supported level. Make range and available abilities class capabilities; role alone cannot decide whether a bot belongs in melee. Paladin and additional classes follow once the shared loop passes. This is a proposed delivery order, not a requirement to keep those existing kits. Current starter classes.

+

Companion orders need a small durable contract for follow, stay, assist, and a designated target. The command transport can use the existing chat path. A client addon and new product UI are not required to prove behavior. Do not start a pull solely because an unrelated enemy happens to be nearby.

+

Automatic training, gear, and supplies

+

This is part of the requested product, so build a provisioning policy early. On spawn and level-up, reconcile level-appropriate spells, equipment, and supplies through core operations. Check periodically for missing resources, with a bounded target quantity. Keep actual quest credit, XP, loot entitlement, spell costs, and combat Gates authoritative.

+

Make reconciliation idempotent. Repeating it must not create duplicate equipment or unlimited supplies. Define which items the policy owns, respect equipped upgrades, and avoid deleting quest items. Prefer starter gear at the earned level; do not silently raise a bot's level to match its leader. Record the chosen provisioning profile and revision so a balance change can be explained.

+

Provisioning reduces the need to build an economy simulation in the first release. Resting, resource use, inventory capacity, and death recovery still need explicit behavior. Automatic supplies should help a bot recover; they should not hide an action loop that never succeeds.

+

The reference factory provides a practical checklist for skills, spells, talents, gear, bags, food, potions, and reagents. Extract those concerns as separate actions. Its full refresh can also set level, clear inventory and quests, and complete selected quest prerequisites. Those additional effects are outside the automatic training, gear, and supplies you chose. Factory refresh, Prerequisite completion.

+
+ +
+

7. Change the Package and the core interfaces it needs

+
+ + + + + + + + +
OwnerProposed responsibilityDisposition of current code
Package entry and rosterPopulation, Operator commands, lifecycle hooks, one owner of each bot's decisions.Keep observable commands where useful. Replace broad pub use access to internal behavior.
Package decision and stateFacts, strategy composition, objective retention, outcomes, priority, recovery, explanation.Replace the control flow and goal-kind state in goals.rs. Do not move the same branches into smaller files and call it complete.
Package behaviorsCombat, support, following, quests, travel, recovery, provisioning.Rewrite around the action contract. Reuse a pure calculation only when its intended behavior survives.
Module actor and navigation operationsTyped gameplay outcomes, route status, safe movement and stopping, core Gates.Extend at the owning operation. Keep client and bot callers on the same rules. Scope changes to what the selected actions require.
Gateway and Realm-coreExisting Transfer and Group Intent routing, party authority, delivery and arrival evidence.Preserve these responsibilities. Strengthen acknowledgement or reconciliation only where a restart fixture shows a missing guarantee.
Tests and diagnosticsDecision tests, durable sequences, Headless Client scenarios, imported-world observations.Keep behavior assertions. Replace helper-shape tests for deleted paths with outcome tests at the new interface.
+

A reasonable private file shape is decision.rs, state.rs, actions.rs, and behavior files for combat, support, quests, travel, recovery, and provisioning. These are implementation locations, not a new plugin system. Add no global string factory or user-defined action language to ship the first release.

+

State that must survive

+

Keep Character identity, XP, quests, inventory, and group membership as core state. Persist the bot's objective, control mode, deadlines, and bounded failure memory. Make the handling of each Package row explicit for Character deletion and Transfer. A restart must not erase the only memory preventing a failed target from being selected again.

+

Keep derived facts and old route segments transient. On Transfer, preserve quest identity and rebuild local target and path observations. Correlate pending work with a controller generation and location so an old completion cannot advance a new action. The current Package already transports its roster but deliberately drops its goal row; the rewrite must choose those lifetimes separately. Roster lifecycle, Goal lifecycle.

+

Cut over without two active minds

+
    +
  1. Add the new state in an additive migration. Plan defaults and backfill explicitly. Keep one durable selector that makes exactly one implementation eligible to control a bot.
  2. +
  3. Run the new pure decision path on recorded facts. It may explain its choices but must issue no gameplay actions. This checks determinism and policy disagreements, not long-term world behavior.
  4. +
  5. Give a small test cohort to the new runner. Cancel incompatible old movement and retain Character state. Compare independent runs from equivalent fixtures.
  6. +
  7. Use a freeze mode if a cohort fails. Roll back to the old runner only where its state contract still works; do not call the old behavior safe by default.
  8. +
  9. After both release suites pass, remove the old control path and obsolete tests. Retire old table storage separately under a reviewed migration plan.
  10. +
+

Schema changes, generated bindings, and publication follow the repository's migration rules. This report proposes those future steps; it performs none of them.

+
+ +
+

8. Deliver observable loops

+

Each step ends with a behavior demonstration. Do not commission all class strategies or a generic planning system before the shared runner can recover from one blocked destination.

+
+ + + + + + + + + +
StepConcrete workExit evidence
0. Capture the failure and compare reusePin core, Package, imported content, and geometry. Record a blocked wolf or giver and a companion that cannot heal. Compare a minimal extracted reference runner with the Rust interface sketch.Reproducible input and observed outcome. Dependency inventory for extraction. Written choice based on the smaller total implementation.
1. Expose outcomesAdd typed results for the initial attack, cast, interaction, and movement operations. Give bot casts the core cast-start lifecycle. Preserve core Gates. Add progress and bounded decision records.An attempted attack cannot clear quest progress. A long cast completes once without repeated restarts. The same no-movement outcome has a reason and a finite retry policy.
2. Build the runner and first companionRetained state, strategy selection, prerequisites, cancellation, ownership selector, follow and move-to-heal.A Priest follows, heals an ally outside combat, repairs poor range, survives an interruption, and resumes following.
3. Complete combat and provisioningWarrior, Priest, and Mage behavior at the supported levels. Automatic loadout and supplies. Death, rest, and recovery.A human-led party handles repeated pulls with a role-correct tank, healer, and ranged damage bot. Repeated provisioning creates no excess items.
4. Complete autonomous questingQuest catalog, retained objectives, explicit drop-source hunting, actual enders, supported chains, deferral.Kill and collect quests finish. Death, full bags, absent targets, and an unreachable giver do not require Operator rescue.
5. Prove persistence and travelTransfer, join/leave, restart, stale actions, control changes, geometry invalidation.One bot continues with the correct objective and party on arrival. Delayed work cannot act on the old location.
6. Expand coverage and remove the old pathRun both release suites on imported content. Check budgets, delete displaced behavior, then add more classes and regions.Both suites pass at the pinned revision. Remaining unsupported content is explicit and does not trap bots.
+

Planning estimate, not a delivery promise. With one experienced implementer and a second person available for review and client observation, allow 2 to 4 engineering days for the baseline and extraction comparison, about 2 to 3 weeks for a reliable companion slice, and another 3 to 5 weeks for initial autonomous questing, recovery, and hardening. The phases overlap. A narrow release is roughly 6 to 9 engineering weeks if the required core mechanics and imported content work. Re-estimate after step 0; broad 1-to-60 quest and class coverage is outside this estimate.

+

One person owns the runner while its action contract settles. After step 2, quest and combat work can proceed independently against that contract. Core navigation and its imported-data verification should have one owner across the corresponding files.

+
+ +
+

9. Define stable with results

+

The thresholds here are proposed acceptance targets. They are not measurements of the current Package or AzerothCore.

+
+ + + + + + + + + +
ProofProposed bar
Decision behaviorFixed time and facts produce the same choice. Every supported action tests success, waiting, refusal, cancellation, and expiry. Test survival versus role, healing versus following, and combat interruption versus retained quest work.
Bounded recoveryNo unchanged failed action runs forever. For the initial fixture, after 10 seconds without movement progress the bot changes its approach; within 30 seconds it advances, defers the destination, or reports a specific wait. Tune separate deadlines for casts and long routes.
Autonomous releaseTen seeded runs per starter class through the supported Northshire and Elwynn catalog. At least 95% finish each supported scenario without Operator help; every remaining run terminates with an explained outcome. Kill, collect, turn-in, death, and interruption are mandatory.
Companion releaseOne human-controlled Character and a four-bot party complete a fixed route with repeated pulls, wounded allies between fights, loss of line of sight, controlled enemies, death, and regrouping. Include one instance entry and exit. No unrequested pull or role abandonment in these fixtures.
PersistenceRestart the Module fixture and Gateway at action and Transfer stages. No duplicated Character, equipment, supply grant, quest reward, or active controller. The retained objective resumes or is invalidated for a recorded reason.
Load and fairnessRun 10, 25, and 100 bots on a named disposable fixture. Record decision and movement time, scheduler lag, route expansions, row reads and writes, and slowest due bot. Set deployment capacity only after measurements; a reference claim about thousands of bots is not transferable.
Imported-world observationOne hour with 25 bots, plus an attended companion session in a real 1.12.1 client. No unexplained stalls, repeated Refusal spam, visible clipping, or idle injured healer. A full Deadmines run is a later coverage gate unless selected as the first dungeon milestone.
+

Durable fixtures must use real actor operations and navigation. Pure tests prove policy, not routing through a door. Headless Client tests prove protocol and world transitions, not whether following looks natural. The current open observation tasks already recognize this distinction. Playerbots observation, Dungeon client checks.

+

Make every stopped bot explain itself

+

The current-state read should show objective and target, selected action, winning reason, last core outcome, time since actual progress, retry count, next eligible time, and relevant content revision. Keep a bounded history of transitions and failures, not a row per successful idle tick. An Operator should be able to distinguish a corpse wait, missing route coverage, an unsupported objective, and a broken prerequisite without reading source.

+
+ +
+

10. What is settled and what remains open

+
+ + + + + + +
StatusDecision
Confirmed by youBoth autonomous leveling/questing and human-led companions are required. The main pain is bots getting stuck or choosing badly. All current implementation choices may change. Automatic training, gear, and supplies are allowed.
RecommendedReplace behavior in Rust using AzerothCore's strategy/action structure and retained travel model. Extend core movement outcomes. Keep durable authority in the Module and party authority in Realm-core.
Proposed initial scopeNorthshire and Elwynn as the first leveling proof; Warrior, Priest, and Mage first; one human-led instance crossing. Use ordinary quest credit and earned XP. Expand regions, classes, and encounter coverage after the shared runner passes.
Still to decideThe final level range and first dungeon milestone; equipment strength relative to the bot's earned level; whether companions may use explicit catch-up teleportation. Default proposal is level-appropriate gear and normal routing, with no teleport through blocked geometry as routine recovery.
+

The largest risks are incomplete core gameplay capabilities, bad or stale imported geometry, underestimated content coverage, and accepting short fixture success as evidence of long unattended operation. The migration also needs deliberate row lifetimes and a single controller during cutover. These are work items in the sequence, not reasons to keep the current implementation.

+

No C++ source was copied into LyraCore. The reference identifies its license as GPL-2.0; the Official Package Collection carries MIT, and LyraCore carries MIT and Apache-2.0 license files. Track source provenance separately if implementation later copies or translates code. This report makes an architectural recommendation and no license-compatibility conclusion. Reference license, Collection license, Core license files.

+
+ +
+

11. Source record

+

The report compares the current Official Package Collection with this worktree's core. The playerbots Package is not installed in this worktree. Older local Package branches were located, then replaced as evidence by a fresh read-only clone of collection main.

+
    +
  • LyraCore at 95e6ad8. Authority, actor operations, navigation, Package API, Transfer, CI, and repository migration requirements.
  • +
  • Playerbots Package at c32b2fb. Collection commit dated 8 September 2026. Its two Rust files contain 4,610 lines including comments and tests. File size is an inventory fact, not a measure of design quality.
  • +
  • AzerothCore Playerbots at b949b50. Reference commit dated 4 September 2026. Read README and source rather than infer architecture from feature claims.
  • +
  • Package API and domain glossary. The proposal follows the repository's tier ownership and language.
  • +
+
AzerothCore scheduling, diagnosis, and verification evidence
+ +
+

Initial research limits: no runtime reproduction, benchmark, deployment, database inspection, or AzerothCore build was performed for the research phase. Current implementation evidence is recorded in the execution tracker. Existing issue status was read on the research date and can change. The proposed performance budgets, schedule, and acceptance targets require verification during implementation.

+
+
+
+
Prepared for LyraCore. Research and implementation tracker. Use the source links to inspect the evidence and the delivery steps to scope the rewrite.
+ + diff --git a/docs/research/render-playerbots-execution.py b/docs/research/render-playerbots-execution.py new file mode 100644 index 000000000..6787c5db8 --- /dev/null +++ b/docs/research/render-playerbots-execution.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +"""Render the local execution record into the published playerbots report.""" + +import argparse +import html +import json +import re +from pathlib import Path + + +START = "" +END = "" +FINISHED = {"complete", "merged"} +STATUSES = {"ready", "planned", "implementing", "review", "approved", "merged", "complete", "blocked", "waiting-for-client"} + + +def escape(value): + return html.escape(str(value), quote=True) + + +def validate(plan): + """Refuse broken ownership and dependency graphs before publishing them.""" + spec = plan["spec"] + rows = [spec, *plan["groups"], *plan["tickets"]] + by_id = {row["id"]: row for row in rows} + if len(by_id) != len(rows): + raise ValueError("Execution identifiers must be unique") + tickets = {row["id"]: row for row in plan["tickets"]} + for row in rows[1:]: + if row["parent"] not in by_id: + raise ValueError(f"Unknown parent for {row['id']}") + seen = {row["id"]} + current = row + while current.get("parent"): + current = by_id[current["parent"]] + if current["id"] in seen: + raise ValueError("Parent cycle") + seen.add(current["id"]) + if current["id"] != spec["id"]: + raise ValueError("Every row must belong to the root spec") + visiting, visited = set(), set() + + def visit(identifier): + if identifier in visiting: + raise ValueError("Blocking cycle") + if identifier in visited: + return + visiting.add(identifier) + for blocker in tickets[identifier]["blocked_by"]: + if blocker not in tickets: + raise ValueError(f"Unknown blocker {blocker}") + visit(blocker) + visiting.remove(identifier) + visited.add(identifier) + + for row in tickets.values(): + if row["status"] not in STATUSES: + raise ValueError(f"Unknown status for {row['id']}") + if not row["acceptance"]: + raise ValueError(f"No acceptance criteria for {row['id']}") + verified = {} + for record in row.get("acceptance_evidence", []): + criterion = record["criterion"] + if criterion not in row["acceptance"] or criterion in verified: + raise ValueError(f"Unknown or duplicate acceptance evidence for {row['id']}") + if not record.get("reviewer", "").strip() or not record.get("evidence") or not all(item.strip() for item in record["evidence"]): + raise ValueError(f"Acceptance evidence for {row['id']} needs a reviewer and sources") + verified[criterion] = record + for pr in row.get("prs", []): + if not re.fullmatch(r"https://github\.com/[\w.-]+/[\w.-]+/pull/[1-9]\d*", pr["url"]): + raise ValueError("PR links must name GitHub pull requests") + if row["status"] in FINISHED: + if set(verified) != set(row["acceptance"]): + raise ValueError(f"Completed ticket {row['id']} needs reviewed evidence for every criterion") + if not row.get("prs") or any(pr.get("status") != "merged" or not re.fullmatch(r"[0-9a-f]{40}", pr.get("merge_commit", "")) for pr in row["prs"]): + raise ValueError(f"Completed ticket {row['id']} needs merged PRs with commit identities") + for kind in row.get("required_observations", []): + observation = row.get("observations", {}).get(kind, {}) + required = ["observer", "observed_at", "core_revision", "package_revision", "content_revision", "geometry_revision", "evidence"] + if not all(str(observation.get(key, "")).strip() for key in required): + raise ValueError(f"Completed ticket {row['id']} needs {kind} observation evidence") + if kind == "attended_client" and observation.get("client_build") != "1.12.1.5875": + raise ValueError("Attended observation must name the real 1.12.1.5875 client") + if kind == "imported_world" and (observation.get("minutes", 0) < 60 or observation.get("bots", 0) < 25): + raise ValueError("Imported-world observation needs at least 60 minutes with 25 bots") + visit(row["id"]) + if row["status"] in {"implementing", "review", "approved", *FINISHED}: + if any(tickets[key]["status"] not in FINISHED for key in row["blocked_by"]): + raise ValueError(f"Ticket {row['id']} started before its blockers completed") + return by_id, tickets + + +def state(ticket, tickets): + status = ticket["status"] + if status == "ready" and any(tickets[key]["status"] not in FINISHED for key in ticket["blocked_by"]): + return "planned" + return status + + +def paragraphs(items): + return "".join(f"

{escape(item)}

" for item in items) + + +def bullets(items, ordered=False): + tag = "ol" if ordered else "ul" + return f"<{tag}>" + "".join(f"
  • {escape(item)}
  • " for item in items) + f"" + + +def row_detail(row, kind): + if kind == "Spec": + parts = ["

    Problem statement

    ", paragraphs([row["problem"]]), "

    Solution

    ", paragraphs([row["solution"]])] + for title, key, ordered in [ + ("User stories", "user_stories", True), + ("Implementation decisions", "implementation_decisions", False), + ("Testing decisions", "testing_decisions", False), + ("Out of scope", "out_of_scope", False), + ("Further notes", "notes", False), + ]: + parts.extend([f"

    {title}

    ", bullets(row[key], ordered)]) + return "".join(parts) + if kind == "Workstream": + return paragraphs([row.get("delivery", row["title"])]) + parts = [paragraphs([row["delivery"]]), "

    Acceptance criteria

    ", bullets(row["acceptance"])] + verified = row.get("acceptance_evidence", []) + parts.append(paragraphs([f"Verified criteria: {len(verified)}/{len(row['acceptance'])}."])) + for record in verified: + parts.extend([paragraphs([record["criterion"], f"Reviewed by {record['reviewer']}."]), bullets(record["evidence"])]) + for kind in row.get("required_observations", []): + observation = row.get("observations", {}).get(kind) + label = kind.replace("_", " ") + parts.extend([f"

    {escape(label.capitalize())} observation

    ", bullets([f"{key.replace('_', ' ')}: {value}" for key, value in observation.items()]) if observation else paragraphs(["Pending. Required before completion."])]) + parts.append(paragraphs([f"Execution model: {row['model']}, {row.get('effort', 'high')} effort. Repositories: {', '.join(row['repo_scope'])}."])) + if row.get("evidence"): + parts.extend(["

    Recorded evidence

    ", bullets(row["evidence"])]) + if row.get("notes"): + parts.extend(["

    Current notes

    ", bullets(row["notes"])]) + return "".join(parts) + + +def render(plan): + by_id, tickets = validate(plan) + children = {key: [] for key in by_id} + for row in [*plan["groups"], *plan["tickets"]]: + children[row["parent"]].append(row["id"]) + + def descendants(identifier): + found = [] + for child in children[identifier]: + found.extend([child] if child in tickets else descendants(child)) + return found + + def table_rows(identifier, depth=0): + row = by_id[identifier] + kind = "Ticket" if identifier in tickets else "Spec" if depth == 0 else "Workstream" + if kind == "Ticket": + status = state(row, tickets) + progress = status.replace("-", " ") + else: + all_tickets = descendants(identifier) + complete = sum(tickets[key]["status"] in FINISHED for key in all_tickets) + progress = f"{complete}/{len(all_tickets)} complete" + status = "complete" if all_tickets and complete == len(all_tickets) else "planned" + blockers = row.get("blocked_by", []) + blocked_text = ", ".join(f'{escape(key)}' for key in blockers) or "None" + links = "
    ".join(f'{escape(pr.get("label", "PR"))}' for pr in row.get("prs", [])) or "Pending" + detail = row_detail(row, kind) + classes = "ticket-row" if kind == "Ticket" else "parent-row" + parent = row.get("parent", "") + output = [f'', + f'{escape(identifier)}
    {kind}', + f'
    {escape(row["title"])}
    {detail}
    Parent: {escape(parent) if parent else "Root"}', + f'{escape(progress)}{escape(row.get("owner", "Orchestrator" if kind != "Ticket" else "Unassigned"))}', + f'{blocked_text}{links}'] + for child in children[identifier]: + output.append(table_rows(child, depth + 1)) + return "".join(output) + + ready = [row["id"] for row in tickets.values() if state(row, tickets) == "ready"] + content = f'''{START} +
    +

    Execution tracker

    +

    The spec and tickets below drive implementation. Expand a title for the behavior, acceptance criteria, and recorded evidence. Parent totals include every child. Completion requires reviewed evidence for every criterion and merged PRs. The final ticket also requires imported-world and attended-client observation records.

    +

    Updated {escape(plan['updated_at'])}. {escape(plan.get('summary', 'Implementation is starting.'))}

    +

    Ready to start: {escape(', '.join(ready) or 'No unassigned work is ready.')}. The orchestrator republishes progress to this URL. Filters operate on this published snapshot.

    +
    + + + + +
    +

    {len(tickets)} tickets

    +
    {table_rows(plan['spec']['id'])}
    IdentifierSpec and ticket hierarchyStatusOwnerBlocked byPull requests
    +
    + + +{END}''' + return content + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--plan", type=Path, default=Path(__file__).with_name("playerbots-execution.json")) + parser.add_argument("--report", type=Path, default=Path(__file__).with_name("playerbots-rewrite.html")) + args = parser.parse_args() + plan = json.loads(args.plan.read_text()) + section = render(plan) + report = args.report.read_text() + if START in report: + before, rest = report.split(START, 1) + _, after = rest.split(END, 1) + report = before + section + after + else: + report = report.replace('
    ', section + '\n
    ', 1) + report = report.replace('

    Read or decide

    ', '

    Read or decide

    \nExecution tracker', 1) + report = report.replace(' target="_blank"', '') + report = report.replace("Prepared for LyraCore. Research and proposal only.", "Prepared for LyraCore. Research and implementation tracker.") + if len(report.encode()) > 512 * 1024: + raise ValueError("Report exceeds the 512 KB publication limit") + args.report.write_text(report) + print(f"Rendered {len(plan['tickets'])} tickets into {args.report.name}") + + +if __name__ == "__main__": + main() From f8bc2bd385b34b572354fdec414df1e95b24e283 Mon Sep 17 00:00:00 2001 From: T3 Code Date: Tue, 8 Sep 2026 11:03:04 +0000 Subject: [PATCH 2/3] docs(playerbots): require both release observation records --- docs/research/playerbots-execution.json | 7 +++++++ docs/research/playerbots-rewrite.html | 2 +- docs/research/render-playerbots-execution.py | 10 ++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/research/playerbots-execution.json b/docs/research/playerbots-execution.json index 08d80101d..7603404e2 100644 --- a/docs/research/playerbots-execution.json +++ b/docs/research/playerbots-execution.json @@ -98,6 +98,13 @@ "Attended real-client observation is a release gate that may require a human after agent implementation. The implementation tickets must prepare the exact scenario, capture format, and diagnostic reads without claiming that a client session already ran.", "Unresolved product choices remain level range beyond the initial catalog, the first full dungeon milestone, equipment strength beyond level-appropriate starter gear, and any explicit catch-up travel policy. They do not block the bounded first release.", "The user authorized autonomous implementation, PR ownership through review, and confident merges. The HTML is the tracker; no issue publication or planning interview is required. Production changes remain outside this authorization." + ], + "prs": [ + { + "url": "https://github.com/LyraCoreProject/LyraCore/pull/481", + "label": "Execution report #481", + "status": "draft" + } ] }, "groups": [ diff --git a/docs/research/playerbots-rewrite.html b/docs/research/playerbots-rewrite.html index 444ba8c05..981148ef8 100644 --- a/docs/research/playerbots-rewrite.html +++ b/docs/research/playerbots-rewrite.html @@ -46,7 +46,7 @@

    Execution tracker

    12 tickets

    -
    IdentifierSpec and ticket hierarchyStatusOwnerBlocked byPull requests
    PB
    Spec
    Rewrite playerbots around durable objectives and typed action outcomes

    Problem statement

    The current playerbots Package can accept an action without proving that the action completed, loses route results, treats attempted combat as quest progress, bypasses the normal cast lifecycle, and retains too little purpose across interruption, restart, and Transfer. Bots can therefore stall, repeat work, choose an obsolete target, or abandon useful intent without explaining why. The current tests also do not prove the Package and core together against real actor operations, imported content, navigation, protocol transitions, and sustained load.

    Solution

    Replace the behavior control flow with one typed Rust decision runner shared by autonomous bots and human-led companions. The runner observes bounded facts, composes supported Strategies, ranks target-bearing candidates deterministically, executes actions through core operations, records typed outcomes, and retains one durable objective with bounded failure memory. Build the rewrite through a pinned real Module and Package fixture, then prove companion behavior, provisioning, seeded quest loops, recovery, commands, restart, Transfer, load, cutover, and attended client behavior before deleting the displaced implementation.

    User stories

    1. As an Operator, I want every bot controlled by one eligible runner, so that two behavior systems cannot issue conflicting actions.
    2. As an Operator, I want a stopped bot to report its objective, target, chosen action, outcome, retry count, next eligible time, and content revision, so that I can diagnose it without reading source.
    3. As an Operator, I want decision work scheduled in bounded fair batches, so that a large roster cannot monopolize a Module tick.
    4. As an Operator, I want excess due bots deferred with recorded lag, so that overload does not silently discard durable work.
    5. As an Operator, I want repeatable provisioning profiles, so that I can explain why a bot received a spell, item, or supply.
    6. As an Operator, I want deployment capacity based on measured runs of 10, 25, and 100 bots, so that release limits reflect this implementation.
    7. As a developer, I want fixed facts and time to produce the same decision, so that policy changes have reproducible tests.
    8. As a developer, I want candidates identified by action, target, and relevant event, so that a higher score cannot retain the wrong target.
    9. As a developer, I want each supported action to return a typed outcome, so that success, waiting, Refusal, cancellation, expiry, and infrastructure failure remain distinct.
    10. As a developer, I want action prerequisites, alternatives, and continuers to be bounded, so that retries and cycles cannot run forever.
    11. As a developer, I want a reproducible Module and Package fixture at pinned revisions, so that failures and fixes can be compared against the same content and geometry.
    12. As a developer, I want casts to use the normal core cast-start lifecycle, so that cast time, interruption, cancellation, cost, and completion use the same Gates as client casts.
    13. As a developer, I want movement outcomes to preserve route completion and coverage evidence, so that policy can distinguish progress, a partial route, blockage, and unknown coverage.
    14. As an autonomous bot, I want one objective retained across tactical interruptions, so that defending myself does not erase my quest purpose.
    15. As an autonomous bot, I want quest admission to require an executor for every required objective, so that unsupported quests do not trap me.
    16. As an autonomous bot, I want to accept, travel for, complete, and turn in a supported kill quest, so that I can earn normal quest credit and XP.
    17. As an autonomous bot, I want to find the actual drop source, loot it, and turn in a supported collect quest, so that collection progress comes from gameplay outcomes.
    18. As an autonomous bot, I want supported talk-only chains and simple GameObject objectives executed through normal core interactions, so that a quest route does not stop at a non-combat step.
    19. As an autonomous bot, I want the actual quest ender retained from the catalog, so that I travel to the correct turn-in Character or GameObject.
    20. As an autonomous bot, I want death, combat, full bags, absent targets, and temporary route failure to have finite recovery rules, so that I can resume or stop with a specific reason.
    21. As an autonomous bot, I want a failed destination deferred by map, instance, and geometry revision, so that a restart cannot immediately choose the same failed target again.
    22. As an autonomous bot, I want skill and spell training, vanilla talents, equipment, and supplies reconciled on spawn and level-up through core Gates, so that I remain playable without receiving invalid progress.
    23. As a human party leader, I want a companion to follow or stay on command, so that I control its position.
    24. As a human party leader, I want a companion to assist my chosen fight or a designated target, so that it does not pull an unrelated enemy.
    25. As a human party leader, I want companions to respect controlled enemies, so that crowd control is not broken by autonomous target choice.
    26. As a human party leader, I want each companion to retain an explicit tank, healer, or damage role, so that party behavior remains predictable through death and Transfer.
    27. As an injured party member, I want a Priest companion to repair range or line of sight and complete one real heal cast, so that repeated decisions do not restart the cast bar.
    28. As a party member, I want a Warrior tank to hold the chosen fight and a Mage damage companion to act at class-appropriate range, so that role does not erase class capabilities.
    29. As a companion, I want joining a human-led party to suspend autonomous travel and leaving it to resume a still-valid solo objective, so that control changes preserve useful intent.
    30. As a companion, I want my role, party intent, and retained objective reconciled after restart and Transfer, so that delayed work from the old location cannot act.
    31. As a maintainer, I want the old behavior source and obsolete state retired after both release suites pass, so that one implementation remains authoritative.
    32. As a party member, I want companions to heal and apply useful missing buffs between fights, so that the party starts the next fight ready without repeated redundant casts.

    Implementation decisions

    • Use a targeted Rust rewrite of the useful AzerothCore decision grammar. Do not port its C++ runtime, synthetic World Sessions, packet queues, host object graph, or WotLK rules.
    • Keep durable gameplay authority in the Module. Keep party authority in Realm-core. Use existing Transfer and Group Intent routing only for their realm-wide responsibilities.
    • Give the Package one small decision interface, one action execution interface, and one explanation read. Keep internal behavior behind those interfaces.
    • Represent Strategies, triggers, facts, candidates, actions, targets, outcomes, tactical modes, objective stages, and failure reasons with typed values instead of strings and dynamic lookup.
    • Rank candidates with integer scores and stable tie-breaking. Candidate identity includes the action, target, and relevant event. Saved random state may break equal valid choices only.
    • Support bounded prerequisites, alternatives, and continuers. Limit candidate count, graph depth, transitions, and route expansion independently during each decision pass.
    • Allow one foreground action to own movement or a cast. A higher-priority action must explicitly cancel incompatible work before it starts.
    • Retain the quest or party objective across tactical interruption. Store its identity, destination, stage, deadline, last verified progress, deferred destinations, bounded failure memory, and catalog revision.
    • Keep route segments and live target observations transient. Correlate pending work with controller generation and location so stale completions cannot advance current state.
    • Treat action acceptance and actual progress as different facts. Track movement, combat, cast, and quest progress with separate evidence and clocks.
    • Expose typed outcomes from the owning core operations for the actions the selected behaviors require. Preserve existing Gates and atomic Refusal behavior.
    • Route bot spells through the normal cast-start and timed completion lifecycle. A running cast stays retained until completion, interruption, cancellation, or expiry.
    • Preserve complete, partial, blocked, and explicit unknown-coverage movement evidence. Do not infer missing coverage only from absent sparse navigation rows.
    • Derive tactical mode and active Strategies from durable Character, party, combat, aura, health, threat, target, position, and capability facts. Do not create a second authoritative state machine.
    • Use the bounded priority order from the report: lifecycle and Transfer restrictions, immediate survival, urgent party support, the current fight, human orders, maintenance, autonomous quest work, then idle activity.
    • Store an indexed next-decision time per bot, process due bots in stable order with a fixed batch limit, coalesce urgent reconsideration reasons, and record lag for deferred work.
    • Build a versioned supported quest catalog from imported quest relations, objectives, spawns, loot sources, and actual enders. Admit only quests whose required objectives have executors.
    • Start autonomous release coverage with a seeded Northshire and Elwynn catalog and ordinary quest credit and earned XP. Treat this as a bounded proof rather than level 1 to 60 coverage.
    • Start companion release coverage with Warrior tank, Priest healer, and Mage damage capabilities. Store the explicit role and derive a deterministic vanilla default when none is chosen.
    • Support durable follow, stay, assist, and designated-target orders through the existing command transport. Joining a human-led party suspends solo work; leaving rechecks and resumes it when valid.
    • Reconcile skill and spell training, vanilla talent choices, equipment, bags, food, potions, ammo, reagents, and bounded supplies as separate idempotent actions through core Gates. Provisioning never changes level, grants quest completion, deletes quest items, or duplicates owned resources.
    • Add new state through an additive migration and one durable controller selector. Use record-only comparison before a small active cohort, then retire the old controller and its obsolete state after release acceptance.
    • Keep a bounded history of transitions and failures. Do not retain one row for each successful idle decision.

    Testing decisions

    • Use the highest real seam available. Pure tests cover deterministic policy, durable Module and Package fixtures cover gameplay operations and navigation, Headless Client scenarios cover protocol and world transitions, and attended client observation covers visible behavior.
    • The baseline fixture pins core commit 95e6ad8c61540f74471e3087897e8c3ef7e065d1 and Package Collection commit c32b2fb7aa405190728034b63ce6eb9a3c0dd6be together with named imported content and geometry revisions.
    • Every supported action has behavioral cases for success, waiting, Refusal, cancellation, and expiry. Infrastructure failures remain separate where the seam can produce them.
    • Durable fixtures call real actor, cast, movement, quest, loot, item, and lifecycle operations. They do not replace gameplay with a simulated combat model.
    • Decision fixtures cover stable candidate order, target-bearing identity, bounded transition graphs, survival against role work, healing against following, and combat interruption against retained quest work.
    • Movement fixtures measure route or waypoint advancement. After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
    • Cast fixtures prove one long cast starts once, survives intervening decisions, and ends once by completion, interruption, cancellation, or expiry.
    • Companion fixtures cover follow, stay, assist, designated target, controlled enemies, poor range, loss of line of sight, wounded allies and missing buffs between fights, death, regrouping, and one instance entry and exit.
    • Autonomous fixtures run ten seeds per starter class through the supported Northshire and Elwynn catalog. At least 95 percent complete each supported scenario without Operator help, and every other seed terminates with an explained outcome.
    • Autonomous mandatory scenarios include kill, collect, talk-only chains, supported simple GameObject use, turn-in, death, interruption, full bags, absent targets, an unreachable giver, unsupported objectives, and restart with a retained objective.
    • Restart and Transfer fixtures interrupt active action and escrow stages. They prove no duplicate Character, equipment, supply grant, quest reward, or active controller and prove stale work cannot act on the old location.
    • Load fixtures run 10, 25, and 100 bots on one named disposable fixture and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and the slowest due bot before capacity is set.
    • Final observation requires one hour with 25 bots on imported content plus an attended companion session in a real unmodified 1.12.1 client. A human must collect and sign off this evidence if the implementation environment cannot run that client.
    • Review final behavior against this specification and repository standards after the focused and full relevant checks pass.

    Out of scope

    • A direct or mechanical port of the complete AzerothCore playerbots runtime.
    • Synthetic World Sessions or packet observation inside the Package.
    • A user-defined action language, global string factory, client addon, or new product UI.
    • Claims of general level 1 to 60 quest coverage, all classes, all regions, all dungeons, or thousands of bots.
    • Exploration, escort, scripted-event, transport, and other quest objective types until they receive explicit executors and catalog support.
    • Routine catch-up teleportation through blocked geometry.
    • A full economy simulation or provisioning that changes level, fabricates quest credit, clears inventory, or completes prerequisite quests.
    • A full Deadmines run unless the team later selects it as the first dungeon milestone.
    • Production realm changes, live database inspection, publication, or deployment as part of implementation and local acceptance.

    Further notes

    • The source report proposes acceptance thresholds. Implementation must measure them before treating them as release facts.
    • Bad or stale imported geometry can imitate a policy defect. Every route fixture and observation record names its content and geometry revisions.
    • The source comparison found no behavioral assertion suite in the pinned AzerothCore tree. Its architecture is evidence for design choices, not proof of LyraCore behavior.
    • Record provenance if any reference code is copied or translated. The architecture proposal does not make a license-compatibility conclusion.
    • Attended real-client observation is a release gate that may require a human after agent implementation. The implementation tickets must prepare the exact scenario, capture format, and diagnostic reads without claiming that a client session already ran.
    • Unresolved product choices remain level range beyond the initial catalog, the first full dungeon milestone, equipment strength beyond level-appropriate starter gear, and any explicit catch-up travel policy. They do not block the bounded first release.
    • The user authorized autonomous implementation, PR ownership through review, and confident merges. The HTML is the tracker; no issue publication or planning interview is required. Production changes remain outside this authorization.
    Parent: Root
    0/12 completeOrchestratorNonePending
    S1
    Workstream
    Typed action foundation and durable runner

    Typed action foundation and durable runner

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-001
    Ticket
    Prove typed outcomes in a real pinned fixture

    Create the first tracer through a reproducible pinned Module and Package fixture. Drive attack, interaction, movement, and cast-start through real core operations, return typed outcomes to the Package, and capture the blocked-target and out-of-range-heal failures that the rewrite must fix.

    Acceptance criteria

    • The fixture records the pinned core, Package, imported content, and geometry revisions and can reproduce the same initial state and outcome.
    • The fixture loads and runs the real Module with the real Package; it does not substitute a simulated gameplay engine.
    • Attack acceptance is distinct from damage and quest progress, and an attempted attack with no hit cannot clear a quest progress clock.
    • Movement reports complete, safe partial, blocked, or explicit unknown-coverage evidence with route or waypoint advancement where applicable.
    • Interaction and cast-start return typed success, waiting, Refusal, cancellation, and expiry outcomes supported by their owning operations.
    • A long bot cast uses the normal core cast lifecycle and completes once without restart on later decision ticks.
    • The blocked target and poor-range heal cases have reproducible inputs, observed outcomes, and enough evidence to compare later runner behavior.
    • A written extraction comparison chooses the smaller total implementation and records why the full AzerothCore runtime is not used.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: LyraCore Module action and navigation contracts, Official Package Collection playerbots fixture, Local durable integration tests.

    Recorded evidence

    • Baseline on core 95e6ad8 and Package c32b2fb: both ignored personality durable tests passed in a private loopback Standalone. This proves the existing Package fixture, not the new outcome contract.

    Current notes

    • The implementer owns the isolated core and Package worktrees and the serialized build slot. The orchestrator owns independent review and merge order.
    Parent: S1
    implementingPB-001 implementerNonePending
    PB-002
    Ticket
    Run one durable objective through bounded decisions

    Build the shared decision runner around typed facts and outcomes. Retain one objective, arbitrate one foreground action, schedule bots in stable bounded batches, and explain each meaningful choice through the Package's normal entry point.

    Acceptance criteria

    • Fixed facts and explicit time produce the same target-bearing candidate order and chosen action.
    • Strategies compose supported triggers, defaults, and priority rules without a global string registry or a second authoritative state machine.
    • Prerequisites, alternatives, and continuers have explicit depth, transition, candidate, and route-work limits with cycle refusal.
    • Only one foreground movement or cast action owns the bot, and a higher-priority action explicitly cancels incompatible work.
    • The durable objective records identity, destination, stage, deadline, last verified progress, bounded failures, deferred destinations, and catalog revision.
    • Separate movement, combat, cast, and quest progress evidence prevents an accepted action from masquerading as completion.
    • Due bots run in stable indexed order under a per-pass limit; excess work remains due, gets a fair next turn, and records scheduler lag.
    • The explanation read reports the current objective and target, chosen action and reason, last outcome, progress age, retry count, next eligible time, and relevant revision with bounded history.
    • The additive state migration defines defaults and backfill and adds a durable controller selector before any bot can use the new runner. Record-only mode emits no gameplay actions; cohort mode has one eligible controller and supports freeze.

    Verified criteria: 0/9.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection decision and durable state, LyraCore Module scheduling and diagnostics, Pure decision and durable integration tests.

    Parent: S1
    plannedUnassignedPB-001Pending
    S2
    Workstream
    Companions and provisioning

    Companions and provisioning

    Parent: PB
    0/3 completeOrchestratorNonePending
    PB-003
    Ticket
    Make a Priest follow, heal, and resume

    Complete the first human-led companion loop. A Priest follows its party leader, retains an injured ally as the heal target, repairs range or line of sight, casts through the real lifecycle, handles interruption, and resumes following.

    Acceptance criteria

    • Joining a human-led party suspends autonomous travel and selects companion Strategies from durable party facts.
    • The Priest follows a moving leader without starting a fight against an unrelated nearby enemy.
    • An injured ally outranks ordinary following when the Priest has a usable heal and the survival policy permits it.
    • Poor range or line of sight produces a movement prerequisite that retains the injured ally and finds a reachable casting position or records a specific wait.
    • The heal starts one real timed cast, does not restart on repeated decisions, and observes completion or interruption through typed outcomes.
    • After healing, cancellation, or a recoverable interruption, the Priest resumes following without losing party control state.
    • Death and resurrection preserve the companion role and lead to regrouping rather than a permanent solo objective change.

    Verified criteria: 0/7.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection companion support behavior, LyraCore Module cast and party fact reads, Durable companion scenarios.

    Parent: S2
    plannedUnassignedPB-002Pending
    PB-004
    Ticket
    Complete starter roles, target choice, and crowd control

    Add Warrior tank and Mage damage behavior beside the Priest healer on the shared runner. Make explicit durable roles, vanilla class capabilities, chosen-target assistance, controlled-enemy avoidance, death, rest, and regrouping work through repeated party pulls.

    Acceptance criteria

    • Warrior, Priest, and Mage have validated ability sets at every level supported by the companion fixture.
    • Each companion retains an explicit tank, healer, or damage role, with a deterministic vanilla-derived default when no role was selected.
    • The Warrior tank chooses and holds the party's selected fight according to survival and threat facts rather than inheriting damage-only retreat behavior.
    • The Mage acts at class-appropriate range and role does not force a ranged class into melee.
    • All companions honor the party's chosen fight and designated target and do not initiate an unrequested pull.
    • Controlled enemies remain ineligible unless the control is intentionally broken by a higher-priority survival rule with a recorded reason.
    • Repeated-pull fixtures cover wounded allies between fights, target death or disappearance, loss of line of sight, companion death, rest, and regrouping without role abandonment.
    • Between fights, companions select useful missing class buffs, repair casting position when needed, apply them through real core casts, observe the resulting auras, and avoid redundant recasting while the buff remains valid.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection starter class and role behavior, LyraCore Module combat and capability facts, Durable repeated-pull party scenarios.

    Parent: S2
    plannedUnassignedPB-003Pending
    PB-005
    Ticket
    Provision playable bots without duplicating progress

    Reconcile the supported bot's skills, spells, vanilla talents, equipment, bags, food, potions, ammo, reagents, and bounded supplies on spawn and level-up through real core operations. Make each action idempotent and explain it by provisioning profile and revision.

    Acceptance criteria

    • Provisioning runs on spawn and level-up and periodically repairs only resources owned by the selected profile.
    • Spell learning, equipment, inventory, uniqueness, proficiency, class, and level rules pass through core operations. Free provisioning is an explicit profile choice; its grants remain bounded and attributable.
    • Skill training and vanilla talent choices follow the selected class profile through the owning core Gates. Prerequisites, earned talent points, rank limits, and level restrictions hold, and reconciliation cannot spend a point or train a rank twice.
    • Repeated reconciliation does not create duplicate equipment, unlimited supplies, repeated spell grants, or repeated costs.
    • The policy respects an equipped upgrade, does not delete quest items, and never raises a bot's level to match a leader.
    • Quest credit, earned XP, loot entitlement, and quest completion remain consequences of normal gameplay operations.
    • Full bags, missing consumables, resource recovery, rest, and death produce bounded next actions or an explained stop.
    • Decision history records the provisioning profile, revision, chosen action, and typed outcome.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection provisioning policy, LyraCore Module skill, spell, talent, item, inventory, and equipment operations, Durable idempotency scenarios.

    Parent: S2
    plannedUnassignedPB-002Pending
    S3
    Workstream
    Autonomous questing and recovery

    Autonomous questing and recovery

    Parent: PB
    0/3 completeOrchestratorNonePending
    PB-006
    Ticket
    Admit supported quests from a seeded catalog

    Build a versioned quest catalog for the initial Northshire and Elwynn proof from imported relations, objectives, spawns, loot sources, and actual enders. Admit a quest only when every required objective has a supported executor, and retain the chosen objective and destination.

    Acceptance criteria

    • The catalog records quest eligibility, each objective kind, target or drop source, actual ender, work area, destination evidence, and content revision.
    • The initial fixture contains a named supported Northshire and Elwynn catalog with deterministic seeds for each starter class.
    • Admission checks ordinary core eligibility and confirms an executor for every required objective before acceptance.
    • Unsupported exploration, escort, scripted event, transport, and complex GameObject requirements remain explicit and cannot enter a futile loop. Mixed quests are admitted only when every required kind has an executor, including supported talk-only and simple GameObject steps.
    • A live creature search chooses what can be acted on now but does not decide whether a quest destination exists in imported content.
    • The retained objective stores the actual ender and catalog revision and survives a tactical combat interruption.
    • If a held quest becomes unsupported, the bot records the missing capability and proceeds to another supported objective or a specific wait without repeated abandonment and reacceptance.

    Verified criteria: 0/7.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection quest catalog and admission, LyraCore imported quest and world relations, Seeded durable catalog scenarios.

    Parent: S3
    plannedUnassignedPB-002Pending
    PB-007
    Ticket
    Finish supported autonomous quest loops

    Complete supported kill, collect, talk-only, and simple GameObject quest loops. The bot accepts the quest, retains its objective, travels through real navigation, executes the required gameplay, earns ordinary credit and XP, turns in to the actual ender, and selects the next supported work.

    Acceptance criteria

    • A supported kill quest completes through accepted combat, actual damage and death, kill credit, travel, and turn-in rather than a changed internal label.
    • A supported collect quest hunts an explicit eligible drop source, receives the item through real loot and inventory operations, and turns in to the catalog's actual ender.
    • A supported talk-only chain advances through actual quest eligibility, giver and ender interactions, and ordinary rewards without manufacturing prerequisite completion.
    • At least one cataloged simple GameObject objective completes through the owning core use or loot operation, respects range and object state, and earns credit once. Unsupported scripted object behavior is refused at admission.
    • Quest objective progress changes only when the authoritative core gameplay outcome changes it.
    • The retained quest objective survives combat interruption, death, rest, and provisioning, then resumes after rechecking eligibility.
    • Target death, disappearance, or ineligibility cancels only the current action and selects a new eligible target or an explicit respawn wait.
    • A completed turn-in grants ordinary rewards once and advances to another supported catalog entry without Operator help.
    • Seeded scenarios cover Warrior, Priest, and Mage and produce reproducible decision and outcome histories.
    • A supported quest destination outside the former home leash remains reachable under the current work area and retained destination. Tactical retreat returns to an appropriate safe position in the current partition and cannot reset travel to the spawn home.

    Verified criteria: 0/10.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection autonomous quest behavior, LyraCore Module quest, combat, loot, inventory, and navigation operations, Seeded durable quest scenarios.

    Parent: S3
    plannedUnassignedPB-005, PB-006Pending
    PB-008
    Ticket
    Recover from blocked travel and stalled quest work

    Turn typed failure and progress evidence into finite recovery for both autonomous bots and companions. Change approach, defer destinations, invalidate stale targets, and explain waits without erasing the retained objective.

    Acceptance criteria

    • The blocked-target fixture cannot clear its stall clock through attack acceptance when route, damage, and quest progress remain unchanged.
    • After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
    • A safe partial route remains eligible while it advances a route or waypoint within a bounded route budget.
    • Repeated no-progress defers a destination by map, instance, and geometry revision for a bounded period and allows another useful action.
    • Unknown coverage stays distinct from a verified blocked route and reports the missing imported coverage evidence.
    • Death, full bags, absent targets, an unreachable giver, a controlled enemy, and a broken prerequisite each end in recovery or an explained finite stop.
    • Recovery remains active for companions and uses follow distance, leader movement, and casting position as its progress evidence.
    • Restarting the fixture preserves the bounded failure memory that prevents immediate reselection of the same failed target.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection travel and recovery behavior, LyraCore Module navigation evidence, Durable blocked-route and stalled-work scenarios.

    Parent: S3
    plannedUnassignedPB-004, PB-007Pending
    S4
    Workstream
    Commands, Transfer, and restart

    Commands, Transfer, and restart

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-009
    Ticket
    Honor durable follow, stay, assist, and target orders

    Complete the companion command contract through the existing command transport. Persist follow, stay, assist, and designated-target orders, apply them with party authority, and resume valid solo work when human-led control ends.

    Acceptance criteria

    • A human party leader can issue follow, stay, assist, and designated-target orders through the existing command transport.
    • Each accepted order persists as typed control state and produces an explanation entry with Actor, target where relevant, and outcome.
    • Follow tracks the leader, stay holds the commanded location within movement tolerances, and assist limits initiation to the chosen fight.
    • A designated target participates in candidate identity and cannot be replaced by another proposal's target when scores change.
    • Controlled enemies remain ineligible while assist or target orders are active unless an explicit higher-priority survival decision records why control was broken.
    • Joining a human-led party suspends autonomous travel and opportunistic grouping without deleting the solo objective.
    • Leaving the party invalidates companion actions, rechecks the retained solo objective, and resumes it only when it is still eligible.
    • Role and command state survive companion death and remain consistent after regrouping.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection commands and control state, LyraCore Gateway command transport and Module party reads, Durable join and leave scenarios.

    Parent: S4
    plannedUnassignedPB-004Pending
    PB-010
    Ticket
    Preserve one controller through restart and Transfer

    Define and prove the lifecycle of every new bot row across Character deletion, Module restart, Gateway restart, party changes, and Transfer. Suspend local actions while Transfer is pending, rebuild transient observations on arrival, and prevent stale work from acting.

    Acceptance criteria

    • Each durable Package row has an explicit keep, move, rebuild, or delete rule for Character deletion and Transfer.
    • A pending Transfer suspends local actions and relies on authoritative Transfer state rather than timeout to create another executor.
    • The retained quest or party objective, control mode, role, deadlines, deferred destinations, and bounded failure memory survive their defined restart and Transfer cases.
    • Transient targets and route segments do not Transfer; arrival rebuilds them against the destination's content and geometry revisions.
    • Pending work carries controller generation and location, and an old completion cannot advance a new action after restart or arrival.
    • Restart fixtures interrupt active movement, cast, provisioning, quest reward, and Transfer stages without duplicating a Character, item, supply grant, reward, or active controller.
    • A transferred companion retains the correct party and role on arrival, and a transferred autonomous bot resumes or invalidates its objective for a recorded reason.
    • One instance entry and exit through the real routing path preserves companion orders and produces arrival evidence.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection bot row lifecycle, LyraCore Module, Gateway, Realm-core, Transfer, and Group Intent integration, Durable restart and Transfer scenarios.

    Parent: S4
    plannedUnassignedPB-008, PB-009Pending
    S5
    Workstream
    Release evidence and retirement

    Release evidence and retirement

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-011
    Ticket
    Pass autonomous, companion, and load acceptance

    Run the complete automated release suites on the pinned core, Package, imported content, and geometry. Prove seeded autonomous work, the fixed human-led companion route, restart and Transfer behavior, bounded recovery, scheduler fairness, and measured 10, 25, and 100 bot load.

    Acceptance criteria

    • Ten seeded runs per starter class execute the supported Northshire and Elwynn catalog; at least 95 percent finish each supported scenario without Operator help and every other run ends with an explained outcome.
    • Autonomous acceptance includes kill, collect, talk-only chains, supported simple GameObject use, travel beyond the former home leash, turn-in, death, combat interruption, full bags, absent targets, an unreachable giver, and unsupported objective admission.
    • One human-controlled Character and four bots complete the fixed repeated-pull route with explicit roles, follow and stay, assist and designated target, wounded allies and missing buffs between fights, loss of line of sight, controlled enemies, death, regrouping, and one instance entry and exit.
    • The companion fixtures produce no unrequested pull, unexplained role abandonment, repeated cast start, or attack against an obsolete target.
    • Every supported action covers success, waiting, Refusal, cancellation, and expiry through the highest suitable behavior seam.
    • Restart and Transfer acceptance shows no duplicate Character, equipment, supply grant, quest reward, or controller and no stale action at the old location.
    • Named disposable load runs execute 10, 25, and 100 bots and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and slowest due bot.
    • The load report sets a measured deployment capacity, records fixture resources and revisions, and accounts for every deferred due bot without silent loss.
    • All relevant repository checks and both specification and standards reviews pass at the pinned revisions.

    Verified criteria: 0/9.

    Execution model: gpt-6-astra, xhigh effort. Repositories: LyraCore and Official Package Collection acceptance suites, Headless Client protocol and world-transition scenarios, Disposable imported-world load fixture and measurement report.

    Parent: S5
    plannedUnassignedPB-005, PB-007, PB-008, PB-010Pending
    PB-012
    Ticket
    Cut over, observe, and retire the old behavior

    Complete the additive state cutover with one durable controller selector, compare record-only decisions, activate a small cohort, gather imported-world and attended client evidence, then delete the displaced behavior source, obsolete tests, and active old state path. Leave old table retirement as its separately reviewed migration when required by repository rules.

    Acceptance criteria

    • The additive state migration defines defaults and backfill, and exactly one durable selector makes one runner eligible to control each bot.
    • Record-only comparison on fixed facts issues no gameplay actions and reports deterministic policy disagreements before cohort activation.
    • A small active cohort can freeze without a second controller and can resume after the failure reason is recorded.
    • Both automated release suites from PB-011 pass again with the new runner selected and no old runner actions.
    • A one-hour imported-world observation runs 25 bots and records no unexplained stall, repeated Refusal spam, visible clipping, or idle injured healer.
    • An attended session in a real unmodified 1.12.1 client exercises the companion route and signs off follow, stay, assist, target choice, crowd-control respect, real casts, death, regrouping, and instance entry and exit.
    • If the implementation environment cannot run the real client, the exact observation script, fixture revisions, capture format, and diagnostic reads are ready, and this acceptance item remains explicitly pending human evidence.
    • The displaced behavior source, obsolete helper-shape tests, broad internal exports, active old controller path, and unused old state access are deleted after acceptance.
    • Repository checks prove the deleted behavior source cannot regain control and no production code reads or writes obsolete active state.
    • Any physical old-table removal has its own reviewed migration plan and does not weaken the completed single-controller cutover.

    Verified criteria: 0/10.

    Imported world observation

    Pending. Required before completion.

    Attended client observation

    Pending. Required before completion.

    Execution model: gpt-6-astra, xhigh effort. Repositories: Official Package Collection controller cutover and source retirement, LyraCore additive state migration and architecture checks, Imported-world observation and attended client evidence.

    Parent: S5
    plannedUnassignedPB-011Pending
    +
    IdentifierSpec and ticket hierarchyStatusOwnerBlocked byPull requests
    PB
    Spec
    Rewrite playerbots around durable objectives and typed action outcomes

    Problem statement

    The current playerbots Package can accept an action without proving that the action completed, loses route results, treats attempted combat as quest progress, bypasses the normal cast lifecycle, and retains too little purpose across interruption, restart, and Transfer. Bots can therefore stall, repeat work, choose an obsolete target, or abandon useful intent without explaining why. The current tests also do not prove the Package and core together against real actor operations, imported content, navigation, protocol transitions, and sustained load.

    Solution

    Replace the behavior control flow with one typed Rust decision runner shared by autonomous bots and human-led companions. The runner observes bounded facts, composes supported Strategies, ranks target-bearing candidates deterministically, executes actions through core operations, records typed outcomes, and retains one durable objective with bounded failure memory. Build the rewrite through a pinned real Module and Package fixture, then prove companion behavior, provisioning, seeded quest loops, recovery, commands, restart, Transfer, load, cutover, and attended client behavior before deleting the displaced implementation.

    User stories

    1. As an Operator, I want every bot controlled by one eligible runner, so that two behavior systems cannot issue conflicting actions.
    2. As an Operator, I want a stopped bot to report its objective, target, chosen action, outcome, retry count, next eligible time, and content revision, so that I can diagnose it without reading source.
    3. As an Operator, I want decision work scheduled in bounded fair batches, so that a large roster cannot monopolize a Module tick.
    4. As an Operator, I want excess due bots deferred with recorded lag, so that overload does not silently discard durable work.
    5. As an Operator, I want repeatable provisioning profiles, so that I can explain why a bot received a spell, item, or supply.
    6. As an Operator, I want deployment capacity based on measured runs of 10, 25, and 100 bots, so that release limits reflect this implementation.
    7. As a developer, I want fixed facts and time to produce the same decision, so that policy changes have reproducible tests.
    8. As a developer, I want candidates identified by action, target, and relevant event, so that a higher score cannot retain the wrong target.
    9. As a developer, I want each supported action to return a typed outcome, so that success, waiting, Refusal, cancellation, expiry, and infrastructure failure remain distinct.
    10. As a developer, I want action prerequisites, alternatives, and continuers to be bounded, so that retries and cycles cannot run forever.
    11. As a developer, I want a reproducible Module and Package fixture at pinned revisions, so that failures and fixes can be compared against the same content and geometry.
    12. As a developer, I want casts to use the normal core cast-start lifecycle, so that cast time, interruption, cancellation, cost, and completion use the same Gates as client casts.
    13. As a developer, I want movement outcomes to preserve route completion and coverage evidence, so that policy can distinguish progress, a partial route, blockage, and unknown coverage.
    14. As an autonomous bot, I want one objective retained across tactical interruptions, so that defending myself does not erase my quest purpose.
    15. As an autonomous bot, I want quest admission to require an executor for every required objective, so that unsupported quests do not trap me.
    16. As an autonomous bot, I want to accept, travel for, complete, and turn in a supported kill quest, so that I can earn normal quest credit and XP.
    17. As an autonomous bot, I want to find the actual drop source, loot it, and turn in a supported collect quest, so that collection progress comes from gameplay outcomes.
    18. As an autonomous bot, I want supported talk-only chains and simple GameObject objectives executed through normal core interactions, so that a quest route does not stop at a non-combat step.
    19. As an autonomous bot, I want the actual quest ender retained from the catalog, so that I travel to the correct turn-in Character or GameObject.
    20. As an autonomous bot, I want death, combat, full bags, absent targets, and temporary route failure to have finite recovery rules, so that I can resume or stop with a specific reason.
    21. As an autonomous bot, I want a failed destination deferred by map, instance, and geometry revision, so that a restart cannot immediately choose the same failed target again.
    22. As an autonomous bot, I want skill and spell training, vanilla talents, equipment, and supplies reconciled on spawn and level-up through core Gates, so that I remain playable without receiving invalid progress.
    23. As a human party leader, I want a companion to follow or stay on command, so that I control its position.
    24. As a human party leader, I want a companion to assist my chosen fight or a designated target, so that it does not pull an unrelated enemy.
    25. As a human party leader, I want companions to respect controlled enemies, so that crowd control is not broken by autonomous target choice.
    26. As a human party leader, I want each companion to retain an explicit tank, healer, or damage role, so that party behavior remains predictable through death and Transfer.
    27. As an injured party member, I want a Priest companion to repair range or line of sight and complete one real heal cast, so that repeated decisions do not restart the cast bar.
    28. As a party member, I want a Warrior tank to hold the chosen fight and a Mage damage companion to act at class-appropriate range, so that role does not erase class capabilities.
    29. As a companion, I want joining a human-led party to suspend autonomous travel and leaving it to resume a still-valid solo objective, so that control changes preserve useful intent.
    30. As a companion, I want my role, party intent, and retained objective reconciled after restart and Transfer, so that delayed work from the old location cannot act.
    31. As a maintainer, I want the old behavior source and obsolete state retired after both release suites pass, so that one implementation remains authoritative.
    32. As a party member, I want companions to heal and apply useful missing buffs between fights, so that the party starts the next fight ready without repeated redundant casts.

    Implementation decisions

    • Use a targeted Rust rewrite of the useful AzerothCore decision grammar. Do not port its C++ runtime, synthetic World Sessions, packet queues, host object graph, or WotLK rules.
    • Keep durable gameplay authority in the Module. Keep party authority in Realm-core. Use existing Transfer and Group Intent routing only for their realm-wide responsibilities.
    • Give the Package one small decision interface, one action execution interface, and one explanation read. Keep internal behavior behind those interfaces.
    • Represent Strategies, triggers, facts, candidates, actions, targets, outcomes, tactical modes, objective stages, and failure reasons with typed values instead of strings and dynamic lookup.
    • Rank candidates with integer scores and stable tie-breaking. Candidate identity includes the action, target, and relevant event. Saved random state may break equal valid choices only.
    • Support bounded prerequisites, alternatives, and continuers. Limit candidate count, graph depth, transitions, and route expansion independently during each decision pass.
    • Allow one foreground action to own movement or a cast. A higher-priority action must explicitly cancel incompatible work before it starts.
    • Retain the quest or party objective across tactical interruption. Store its identity, destination, stage, deadline, last verified progress, deferred destinations, bounded failure memory, and catalog revision.
    • Keep route segments and live target observations transient. Correlate pending work with controller generation and location so stale completions cannot advance current state.
    • Treat action acceptance and actual progress as different facts. Track movement, combat, cast, and quest progress with separate evidence and clocks.
    • Expose typed outcomes from the owning core operations for the actions the selected behaviors require. Preserve existing Gates and atomic Refusal behavior.
    • Route bot spells through the normal cast-start and timed completion lifecycle. A running cast stays retained until completion, interruption, cancellation, or expiry.
    • Preserve complete, partial, blocked, and explicit unknown-coverage movement evidence. Do not infer missing coverage only from absent sparse navigation rows.
    • Derive tactical mode and active Strategies from durable Character, party, combat, aura, health, threat, target, position, and capability facts. Do not create a second authoritative state machine.
    • Use the bounded priority order from the report: lifecycle and Transfer restrictions, immediate survival, urgent party support, the current fight, human orders, maintenance, autonomous quest work, then idle activity.
    • Store an indexed next-decision time per bot, process due bots in stable order with a fixed batch limit, coalesce urgent reconsideration reasons, and record lag for deferred work.
    • Build a versioned supported quest catalog from imported quest relations, objectives, spawns, loot sources, and actual enders. Admit only quests whose required objectives have executors.
    • Start autonomous release coverage with a seeded Northshire and Elwynn catalog and ordinary quest credit and earned XP. Treat this as a bounded proof rather than level 1 to 60 coverage.
    • Start companion release coverage with Warrior tank, Priest healer, and Mage damage capabilities. Store the explicit role and derive a deterministic vanilla default when none is chosen.
    • Support durable follow, stay, assist, and designated-target orders through the existing command transport. Joining a human-led party suspends solo work; leaving rechecks and resumes it when valid.
    • Reconcile skill and spell training, vanilla talent choices, equipment, bags, food, potions, ammo, reagents, and bounded supplies as separate idempotent actions through core Gates. Provisioning never changes level, grants quest completion, deletes quest items, or duplicates owned resources.
    • Add new state through an additive migration and one durable controller selector. Use record-only comparison before a small active cohort, then retire the old controller and its obsolete state after release acceptance.
    • Keep a bounded history of transitions and failures. Do not retain one row for each successful idle decision.

    Testing decisions

    • Use the highest real seam available. Pure tests cover deterministic policy, durable Module and Package fixtures cover gameplay operations and navigation, Headless Client scenarios cover protocol and world transitions, and attended client observation covers visible behavior.
    • The baseline fixture pins core commit 95e6ad8c61540f74471e3087897e8c3ef7e065d1 and Package Collection commit c32b2fb7aa405190728034b63ce6eb9a3c0dd6be together with named imported content and geometry revisions.
    • Every supported action has behavioral cases for success, waiting, Refusal, cancellation, and expiry. Infrastructure failures remain separate where the seam can produce them.
    • Durable fixtures call real actor, cast, movement, quest, loot, item, and lifecycle operations. They do not replace gameplay with a simulated combat model.
    • Decision fixtures cover stable candidate order, target-bearing identity, bounded transition graphs, survival against role work, healing against following, and combat interruption against retained quest work.
    • Movement fixtures measure route or waypoint advancement. After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
    • Cast fixtures prove one long cast starts once, survives intervening decisions, and ends once by completion, interruption, cancellation, or expiry.
    • Companion fixtures cover follow, stay, assist, designated target, controlled enemies, poor range, loss of line of sight, wounded allies and missing buffs between fights, death, regrouping, and one instance entry and exit.
    • Autonomous fixtures run ten seeds per starter class through the supported Northshire and Elwynn catalog. At least 95 percent complete each supported scenario without Operator help, and every other seed terminates with an explained outcome.
    • Autonomous mandatory scenarios include kill, collect, talk-only chains, supported simple GameObject use, turn-in, death, interruption, full bags, absent targets, an unreachable giver, unsupported objectives, and restart with a retained objective.
    • Restart and Transfer fixtures interrupt active action and escrow stages. They prove no duplicate Character, equipment, supply grant, quest reward, or active controller and prove stale work cannot act on the old location.
    • Load fixtures run 10, 25, and 100 bots on one named disposable fixture and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and the slowest due bot before capacity is set.
    • Final observation requires one hour with 25 bots on imported content plus an attended companion session in a real unmodified 1.12.1 client. A human must collect and sign off this evidence if the implementation environment cannot run that client.
    • Review final behavior against this specification and repository standards after the focused and full relevant checks pass.

    Out of scope

    • A direct or mechanical port of the complete AzerothCore playerbots runtime.
    • Synthetic World Sessions or packet observation inside the Package.
    • A user-defined action language, global string factory, client addon, or new product UI.
    • Claims of general level 1 to 60 quest coverage, all classes, all regions, all dungeons, or thousands of bots.
    • Exploration, escort, scripted-event, transport, and other quest objective types until they receive explicit executors and catalog support.
    • Routine catch-up teleportation through blocked geometry.
    • A full economy simulation or provisioning that changes level, fabricates quest credit, clears inventory, or completes prerequisite quests.
    • A full Deadmines run unless the team later selects it as the first dungeon milestone.
    • Production realm changes, live database inspection, publication, or deployment as part of implementation and local acceptance.

    Further notes

    • The source report proposes acceptance thresholds. Implementation must measure them before treating them as release facts.
    • Bad or stale imported geometry can imitate a policy defect. Every route fixture and observation record names its content and geometry revisions.
    • The source comparison found no behavioral assertion suite in the pinned AzerothCore tree. Its architecture is evidence for design choices, not proof of LyraCore behavior.
    • Record provenance if any reference code is copied or translated. The architecture proposal does not make a license-compatibility conclusion.
    • Attended real-client observation is a release gate that may require a human after agent implementation. The implementation tickets must prepare the exact scenario, capture format, and diagnostic reads without claiming that a client session already ran.
    • Unresolved product choices remain level range beyond the initial catalog, the first full dungeon milestone, equipment strength beyond level-appropriate starter gear, and any explicit catch-up travel policy. They do not block the bounded first release.
    • The user authorized autonomous implementation, PR ownership through review, and confident merges. The HTML is the tracker; no issue publication or planning interview is required. Production changes remain outside this authorization.
    Parent: Root
    0/12 completeOrchestratorNoneExecution report #481
    S1
    Workstream
    Typed action foundation and durable runner

    Typed action foundation and durable runner

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-001
    Ticket
    Prove typed outcomes in a real pinned fixture

    Create the first tracer through a reproducible pinned Module and Package fixture. Drive attack, interaction, movement, and cast-start through real core operations, return typed outcomes to the Package, and capture the blocked-target and out-of-range-heal failures that the rewrite must fix.

    Acceptance criteria

    • The fixture records the pinned core, Package, imported content, and geometry revisions and can reproduce the same initial state and outcome.
    • The fixture loads and runs the real Module with the real Package; it does not substitute a simulated gameplay engine.
    • Attack acceptance is distinct from damage and quest progress, and an attempted attack with no hit cannot clear a quest progress clock.
    • Movement reports complete, safe partial, blocked, or explicit unknown-coverage evidence with route or waypoint advancement where applicable.
    • Interaction and cast-start return typed success, waiting, Refusal, cancellation, and expiry outcomes supported by their owning operations.
    • A long bot cast uses the normal core cast lifecycle and completes once without restart on later decision ticks.
    • The blocked target and poor-range heal cases have reproducible inputs, observed outcomes, and enough evidence to compare later runner behavior.
    • A written extraction comparison chooses the smaller total implementation and records why the full AzerothCore runtime is not used.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: LyraCore Module action and navigation contracts, Official Package Collection playerbots fixture, Local durable integration tests.

    Recorded evidence

    • Baseline on core 95e6ad8 and Package c32b2fb: both ignored personality durable tests passed in a private loopback Standalone. This proves the existing Package fixture, not the new outcome contract.

    Current notes

    • The implementer owns the isolated core and Package worktrees and the serialized build slot. The orchestrator owns independent review and merge order.
    Parent: S1
    implementingPB-001 implementerNonePending
    PB-002
    Ticket
    Run one durable objective through bounded decisions

    Build the shared decision runner around typed facts and outcomes. Retain one objective, arbitrate one foreground action, schedule bots in stable bounded batches, and explain each meaningful choice through the Package's normal entry point.

    Acceptance criteria

    • Fixed facts and explicit time produce the same target-bearing candidate order and chosen action.
    • Strategies compose supported triggers, defaults, and priority rules without a global string registry or a second authoritative state machine.
    • Prerequisites, alternatives, and continuers have explicit depth, transition, candidate, and route-work limits with cycle refusal.
    • Only one foreground movement or cast action owns the bot, and a higher-priority action explicitly cancels incompatible work.
    • The durable objective records identity, destination, stage, deadline, last verified progress, bounded failures, deferred destinations, and catalog revision.
    • Separate movement, combat, cast, and quest progress evidence prevents an accepted action from masquerading as completion.
    • Due bots run in stable indexed order under a per-pass limit; excess work remains due, gets a fair next turn, and records scheduler lag.
    • The explanation read reports the current objective and target, chosen action and reason, last outcome, progress age, retry count, next eligible time, and relevant revision with bounded history.
    • The additive state migration defines defaults and backfill and adds a durable controller selector before any bot can use the new runner. Record-only mode emits no gameplay actions; cohort mode has one eligible controller and supports freeze.

    Verified criteria: 0/9.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection decision and durable state, LyraCore Module scheduling and diagnostics, Pure decision and durable integration tests.

    Parent: S1
    plannedUnassignedPB-001Pending
    S2
    Workstream
    Companions and provisioning

    Companions and provisioning

    Parent: PB
    0/3 completeOrchestratorNonePending
    PB-003
    Ticket
    Make a Priest follow, heal, and resume

    Complete the first human-led companion loop. A Priest follows its party leader, retains an injured ally as the heal target, repairs range or line of sight, casts through the real lifecycle, handles interruption, and resumes following.

    Acceptance criteria

    • Joining a human-led party suspends autonomous travel and selects companion Strategies from durable party facts.
    • The Priest follows a moving leader without starting a fight against an unrelated nearby enemy.
    • An injured ally outranks ordinary following when the Priest has a usable heal and the survival policy permits it.
    • Poor range or line of sight produces a movement prerequisite that retains the injured ally and finds a reachable casting position or records a specific wait.
    • The heal starts one real timed cast, does not restart on repeated decisions, and observes completion or interruption through typed outcomes.
    • After healing, cancellation, or a recoverable interruption, the Priest resumes following without losing party control state.
    • Death and resurrection preserve the companion role and lead to regrouping rather than a permanent solo objective change.

    Verified criteria: 0/7.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection companion support behavior, LyraCore Module cast and party fact reads, Durable companion scenarios.

    Parent: S2
    plannedUnassignedPB-002Pending
    PB-004
    Ticket
    Complete starter roles, target choice, and crowd control

    Add Warrior tank and Mage damage behavior beside the Priest healer on the shared runner. Make explicit durable roles, vanilla class capabilities, chosen-target assistance, controlled-enemy avoidance, death, rest, and regrouping work through repeated party pulls.

    Acceptance criteria

    • Warrior, Priest, and Mage have validated ability sets at every level supported by the companion fixture.
    • Each companion retains an explicit tank, healer, or damage role, with a deterministic vanilla-derived default when no role was selected.
    • The Warrior tank chooses and holds the party's selected fight according to survival and threat facts rather than inheriting damage-only retreat behavior.
    • The Mage acts at class-appropriate range and role does not force a ranged class into melee.
    • All companions honor the party's chosen fight and designated target and do not initiate an unrequested pull.
    • Controlled enemies remain ineligible unless the control is intentionally broken by a higher-priority survival rule with a recorded reason.
    • Repeated-pull fixtures cover wounded allies between fights, target death or disappearance, loss of line of sight, companion death, rest, and regrouping without role abandonment.
    • Between fights, companions select useful missing class buffs, repair casting position when needed, apply them through real core casts, observe the resulting auras, and avoid redundant recasting while the buff remains valid.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection starter class and role behavior, LyraCore Module combat and capability facts, Durable repeated-pull party scenarios.

    Parent: S2
    plannedUnassignedPB-003Pending
    PB-005
    Ticket
    Provision playable bots without duplicating progress

    Reconcile the supported bot's skills, spells, vanilla talents, equipment, bags, food, potions, ammo, reagents, and bounded supplies on spawn and level-up through real core operations. Make each action idempotent and explain it by provisioning profile and revision.

    Acceptance criteria

    • Provisioning runs on spawn and level-up and periodically repairs only resources owned by the selected profile.
    • Spell learning, equipment, inventory, uniqueness, proficiency, class, and level rules pass through core operations. Free provisioning is an explicit profile choice; its grants remain bounded and attributable.
    • Skill training and vanilla talent choices follow the selected class profile through the owning core Gates. Prerequisites, earned talent points, rank limits, and level restrictions hold, and reconciliation cannot spend a point or train a rank twice.
    • Repeated reconciliation does not create duplicate equipment, unlimited supplies, repeated spell grants, or repeated costs.
    • The policy respects an equipped upgrade, does not delete quest items, and never raises a bot's level to match a leader.
    • Quest credit, earned XP, loot entitlement, and quest completion remain consequences of normal gameplay operations.
    • Full bags, missing consumables, resource recovery, rest, and death produce bounded next actions or an explained stop.
    • Decision history records the provisioning profile, revision, chosen action, and typed outcome.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection provisioning policy, LyraCore Module skill, spell, talent, item, inventory, and equipment operations, Durable idempotency scenarios.

    Parent: S2
    plannedUnassignedPB-002Pending
    S3
    Workstream
    Autonomous questing and recovery

    Autonomous questing and recovery

    Parent: PB
    0/3 completeOrchestratorNonePending
    PB-006
    Ticket
    Admit supported quests from a seeded catalog

    Build a versioned quest catalog for the initial Northshire and Elwynn proof from imported relations, objectives, spawns, loot sources, and actual enders. Admit a quest only when every required objective has a supported executor, and retain the chosen objective and destination.

    Acceptance criteria

    • The catalog records quest eligibility, each objective kind, target or drop source, actual ender, work area, destination evidence, and content revision.
    • The initial fixture contains a named supported Northshire and Elwynn catalog with deterministic seeds for each starter class.
    • Admission checks ordinary core eligibility and confirms an executor for every required objective before acceptance.
    • Unsupported exploration, escort, scripted event, transport, and complex GameObject requirements remain explicit and cannot enter a futile loop. Mixed quests are admitted only when every required kind has an executor, including supported talk-only and simple GameObject steps.
    • A live creature search chooses what can be acted on now but does not decide whether a quest destination exists in imported content.
    • The retained objective stores the actual ender and catalog revision and survives a tactical combat interruption.
    • If a held quest becomes unsupported, the bot records the missing capability and proceeds to another supported objective or a specific wait without repeated abandonment and reacceptance.

    Verified criteria: 0/7.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection quest catalog and admission, LyraCore imported quest and world relations, Seeded durable catalog scenarios.

    Parent: S3
    plannedUnassignedPB-002Pending
    PB-007
    Ticket
    Finish supported autonomous quest loops

    Complete supported kill, collect, talk-only, and simple GameObject quest loops. The bot accepts the quest, retains its objective, travels through real navigation, executes the required gameplay, earns ordinary credit and XP, turns in to the actual ender, and selects the next supported work.

    Acceptance criteria

    • A supported kill quest completes through accepted combat, actual damage and death, kill credit, travel, and turn-in rather than a changed internal label.
    • A supported collect quest hunts an explicit eligible drop source, receives the item through real loot and inventory operations, and turns in to the catalog's actual ender.
    • A supported talk-only chain advances through actual quest eligibility, giver and ender interactions, and ordinary rewards without manufacturing prerequisite completion.
    • At least one cataloged simple GameObject objective completes through the owning core use or loot operation, respects range and object state, and earns credit once. Unsupported scripted object behavior is refused at admission.
    • Quest objective progress changes only when the authoritative core gameplay outcome changes it.
    • The retained quest objective survives combat interruption, death, rest, and provisioning, then resumes after rechecking eligibility.
    • Target death, disappearance, or ineligibility cancels only the current action and selects a new eligible target or an explicit respawn wait.
    • A completed turn-in grants ordinary rewards once and advances to another supported catalog entry without Operator help.
    • Seeded scenarios cover Warrior, Priest, and Mage and produce reproducible decision and outcome histories.
    • A supported quest destination outside the former home leash remains reachable under the current work area and retained destination. Tactical retreat returns to an appropriate safe position in the current partition and cannot reset travel to the spawn home.

    Verified criteria: 0/10.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection autonomous quest behavior, LyraCore Module quest, combat, loot, inventory, and navigation operations, Seeded durable quest scenarios.

    Parent: S3
    plannedUnassignedPB-005, PB-006Pending
    PB-008
    Ticket
    Recover from blocked travel and stalled quest work

    Turn typed failure and progress evidence into finite recovery for both autonomous bots and companions. Change approach, defer destinations, invalidate stale targets, and explain waits without erasing the retained objective.

    Acceptance criteria

    • The blocked-target fixture cannot clear its stall clock through attack acceptance when route, damage, and quest progress remain unchanged.
    • After 10 seconds without movement progress the bot changes approach; within 30 seconds it advances, defers the destination, or records a specific wait.
    • A safe partial route remains eligible while it advances a route or waypoint within a bounded route budget.
    • Repeated no-progress defers a destination by map, instance, and geometry revision for a bounded period and allows another useful action.
    • Unknown coverage stays distinct from a verified blocked route and reports the missing imported coverage evidence.
    • Death, full bags, absent targets, an unreachable giver, a controlled enemy, and a broken prerequisite each end in recovery or an explained finite stop.
    • Recovery remains active for companions and uses follow distance, leader movement, and casting position as its progress evidence.
    • Restarting the fixture preserves the bounded failure memory that prevents immediate reselection of the same failed target.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection travel and recovery behavior, LyraCore Module navigation evidence, Durable blocked-route and stalled-work scenarios.

    Parent: S3
    plannedUnassignedPB-004, PB-007Pending
    S4
    Workstream
    Commands, Transfer, and restart

    Commands, Transfer, and restart

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-009
    Ticket
    Honor durable follow, stay, assist, and target orders

    Complete the companion command contract through the existing command transport. Persist follow, stay, assist, and designated-target orders, apply them with party authority, and resume valid solo work when human-led control ends.

    Acceptance criteria

    • A human party leader can issue follow, stay, assist, and designated-target orders through the existing command transport.
    • Each accepted order persists as typed control state and produces an explanation entry with Actor, target where relevant, and outcome.
    • Follow tracks the leader, stay holds the commanded location within movement tolerances, and assist limits initiation to the chosen fight.
    • A designated target participates in candidate identity and cannot be replaced by another proposal's target when scores change.
    • Controlled enemies remain ineligible while assist or target orders are active unless an explicit higher-priority survival decision records why control was broken.
    • Joining a human-led party suspends autonomous travel and opportunistic grouping without deleting the solo objective.
    • Leaving the party invalidates companion actions, rechecks the retained solo objective, and resumes it only when it is still eligible.
    • Role and command state survive companion death and remain consistent after regrouping.

    Verified criteria: 0/8.

    Execution model: gpt-5.6-sol, high effort. Repositories: Official Package Collection commands and control state, LyraCore Gateway command transport and Module party reads, Durable join and leave scenarios.

    Parent: S4
    plannedUnassignedPB-004Pending
    PB-010
    Ticket
    Preserve one controller through restart and Transfer

    Define and prove the lifecycle of every new bot row across Character deletion, Module restart, Gateway restart, party changes, and Transfer. Suspend local actions while Transfer is pending, rebuild transient observations on arrival, and prevent stale work from acting.

    Acceptance criteria

    • Each durable Package row has an explicit keep, move, rebuild, or delete rule for Character deletion and Transfer.
    • A pending Transfer suspends local actions and relies on authoritative Transfer state rather than timeout to create another executor.
    • The retained quest or party objective, control mode, role, deadlines, deferred destinations, and bounded failure memory survive their defined restart and Transfer cases.
    • Transient targets and route segments do not Transfer; arrival rebuilds them against the destination's content and geometry revisions.
    • Pending work carries controller generation and location, and an old completion cannot advance a new action after restart or arrival.
    • Restart fixtures interrupt active movement, cast, provisioning, quest reward, and Transfer stages without duplicating a Character, item, supply grant, reward, or active controller.
    • A transferred companion retains the correct party and role on arrival, and a transferred autonomous bot resumes or invalidates its objective for a recorded reason.
    • One instance entry and exit through the real routing path preserves companion orders and produces arrival evidence.

    Verified criteria: 0/8.

    Execution model: gpt-6-astra, high effort. Repositories: Official Package Collection bot row lifecycle, LyraCore Module, Gateway, Realm-core, Transfer, and Group Intent integration, Durable restart and Transfer scenarios.

    Parent: S4
    plannedUnassignedPB-008, PB-009Pending
    S5
    Workstream
    Release evidence and retirement

    Release evidence and retirement

    Parent: PB
    0/2 completeOrchestratorNonePending
    PB-011
    Ticket
    Pass autonomous, companion, and load acceptance

    Run the complete automated release suites on the pinned core, Package, imported content, and geometry. Prove seeded autonomous work, the fixed human-led companion route, restart and Transfer behavior, bounded recovery, scheduler fairness, and measured 10, 25, and 100 bot load.

    Acceptance criteria

    • Ten seeded runs per starter class execute the supported Northshire and Elwynn catalog; at least 95 percent finish each supported scenario without Operator help and every other run ends with an explained outcome.
    • Autonomous acceptance includes kill, collect, talk-only chains, supported simple GameObject use, travel beyond the former home leash, turn-in, death, combat interruption, full bags, absent targets, an unreachable giver, and unsupported objective admission.
    • One human-controlled Character and four bots complete the fixed repeated-pull route with explicit roles, follow and stay, assist and designated target, wounded allies and missing buffs between fights, loss of line of sight, controlled enemies, death, regrouping, and one instance entry and exit.
    • The companion fixtures produce no unrequested pull, unexplained role abandonment, repeated cast start, or attack against an obsolete target.
    • Every supported action covers success, waiting, Refusal, cancellation, and expiry through the highest suitable behavior seam.
    • Restart and Transfer acceptance shows no duplicate Character, equipment, supply grant, quest reward, or controller and no stale action at the old location.
    • Named disposable load runs execute 10, 25, and 100 bots and record decision time, movement time, scheduler lag, route expansions, row reads, row writes, and slowest due bot.
    • The load report sets a measured deployment capacity, records fixture resources and revisions, and accounts for every deferred due bot without silent loss.
    • All relevant repository checks and both specification and standards reviews pass at the pinned revisions.

    Verified criteria: 0/9.

    Execution model: gpt-6-astra, xhigh effort. Repositories: LyraCore and Official Package Collection acceptance suites, Headless Client protocol and world-transition scenarios, Disposable imported-world load fixture and measurement report.

    Parent: S5
    plannedUnassignedPB-005, PB-007, PB-008, PB-010Pending
    PB-012
    Ticket
    Cut over, observe, and retire the old behavior

    Complete the additive state cutover with one durable controller selector, compare record-only decisions, activate a small cohort, gather imported-world and attended client evidence, then delete the displaced behavior source, obsolete tests, and active old state path. Leave old table retirement as its separately reviewed migration when required by repository rules.

    Acceptance criteria

    • The additive state migration defines defaults and backfill, and exactly one durable selector makes one runner eligible to control each bot.
    • Record-only comparison on fixed facts issues no gameplay actions and reports deterministic policy disagreements before cohort activation.
    • A small active cohort can freeze without a second controller and can resume after the failure reason is recorded.
    • Both automated release suites from PB-011 pass again with the new runner selected and no old runner actions.
    • A one-hour imported-world observation runs 25 bots and records no unexplained stall, repeated Refusal spam, visible clipping, or idle injured healer.
    • An attended session in a real unmodified 1.12.1 client exercises the companion route and signs off follow, stay, assist, target choice, crowd-control respect, real casts, death, regrouping, and instance entry and exit.
    • If the implementation environment cannot run the real client, the exact observation script, fixture revisions, capture format, and diagnostic reads are ready, and this acceptance item remains explicitly pending human evidence.
    • The displaced behavior source, obsolete helper-shape tests, broad internal exports, active old controller path, and unused old state access are deleted after acceptance.
    • Repository checks prove the deleted behavior source cannot regain control and no production code reads or writes obsolete active state.
    • Any physical old-table removal has its own reviewed migration plan and does not weaken the completed single-controller cutover.

    Verified criteria: 0/10.

    Imported world observation

    Pending. Required before completion.

    Attended client observation

    Pending. Required before completion.

    Execution model: gpt-6-astra, xhigh effort. Repositories: Official Package Collection controller cutover and source retirement, LyraCore additive state migration and architecture checks, Imported-world observation and attended client evidence.

    Parent: S5
    plannedUnassignedPB-011Pending