diff --git a/docs/plans/2026-09-06-mosstank-mode-arbitration.md b/docs/plans/2026-09-06-mosstank-mode-arbitration.md index 2b6d7c61..0c243149 100644 --- a/docs/plans/2026-09-06-mosstank-mode-arbitration.md +++ b/docs/plans/2026-09-06-mosstank-mode-arbitration.md @@ -166,3 +166,52 @@ appears, and drop to peace when nothing is left and Peace Mode When Idle is on. MossTank/Plugin filter (79 tests, incl. `MossTankMarkupContractTests`) stays green with no markup changes. Owner review still owed (Opus, two lenses) plus the connected gate in Acceptance. + +### Opus review of `c406942ef` against VTank's decompiled source (2026-09-06) + +Verdict PASS-WITH-FIXES; owner direction is knowledge base first, so the +fixes are DEFERRED to Campaign VT (VT2 re-judges this commit against +`docs/research/vtank-kb/02-scheduler-and-actions.md`). Oracle citations are +into `refs/vtank/decompiled/`. + +VTank facts established (cite these, do not re-derive): IdlePeace is one rule +type `cm` registered LAST after the `"END"` sentinel (`cLogic.cs:576-577`); the +engine runs strictly the first valid rule per tick (`cLogic.cs:220-253`); the +buff rule `fz` (`cLogic.cs:466`) is valid whenever a buff is DUE +(`fz.cs:69-86`), so a due buff suppresses idle-peace even between passes; +`cm(0)` is also a pre-chain on idle loot, corpse approach, target approach and +nav route (`cLogic.cs:530-570`, `LogicRulePreChain.cs:52-62`) — VTank drops to +Peace BEFORE those; `fd.cs:129-133` forces Magic in the tight-waypoint case. +Caster/mode sequencing is one idempotent per-tick function `ga.a` +(`ga.cs:1432-1565`): preferred item → wielded item if its class maps to the +wanted mode → profile scan in Items-page insertion order (`ga.cs:1400-1408`, +`eq.cs:85-93`; the "no buffs" spell field is ignored); no caster → one error +`"You must add at least one wand to your profile."` + `StopMacro()` +(`ga.cs:1469-1472`); retry counter per tick, exhaustion runs the bugged- +combat-state wand-use recovery, never a give-up (`ga.cs:1502-1524`); nothing +is restored after buffing — combat re-wields through the same function. + +Findings to fix in VT3 (numbers from the review): +1. BLOCKING — no-caster path re-posts the notice ~1 Hz forever (`Stop` clears + the latch, the auto scan restarts the pass); VTank posts once and stops the + macro. Fix: stop the macro (as `CombatController.Disable` does). +2. BLOCKING — 2.0 s × `DropToPeaceModeRetryCount`(34) = 68 s > the pass's + 30 s `StallTimeoutSeconds`, so the exhausted-budget stop is unreachable; + and VTank does not stop there anyway — it runs the wand-use recovery. +3. SHOULD-FIX — arbiter drops to peace while a buff is due (1 s scan gap); + add "a buff is due" to the idle set. +4. SHOULD-FIX — `MacroIdleModeArbiter.Status` is never displayed. +5. SHOULD-FIX — profiled-caster order must be Items-page insertion order, + not name order (needs an ordered profile list; `CombatItemNames` is a set). +6. SHOULD-FIX — equip stage re-issues `Equip` every frame with no cadence or + budget and no wieldability check (`ga.cs:1456-1460`). +7. NIT — `Mode == Unknown` spins the preparer (arbiter treats it as hands-off). +8. NIT — two caster predicates (`& 0x8000` vs exact); share one helper. +9. NIT — the notice text differs from VTank's ("…to your profile."). +10. CARRIED — the `cm(0)` pre-chains and the `fd.cs:131` Magic case are + unported; ours suppresses idle-peace on nav/loot instead. +Also: `CombatController.EnterDebuffMode` (`:1373`) and the meta +`setcombatstate` expression can fight the arbiter (no owns-action flag) — +add `HasPendingItemDebuff` and meta activity to the idle set. +Tests T3/T4/T5b/T5d are vacuous as written (pass with the defect present); +T1/T2/T5a/T5c/T6 are real pins.