[High] [Bug] Cannot restart practicing a discipline after stopping it #319
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug: Cannot restart practicing a discipline after stopping it
Description
When a player stops practicing a discipline (clicks "Stop Practicing"), they are unable to restart it by clicking "Start Practicing" again. The button appears clickable but the discipline does not reactivate — it silently fails.
Reproduction Steps
Root Cause
The bug is in the interaction between
DisciplinesTab.tsxanddiscipline-slice.ts.In
DisciplinesTab.tsx(line 91), thehandleTogglecallback callsactivatewithout passingrawMana:In
discipline-slice.ts(line 72-86), theactivatemethod callscanProceedDiscipline(def, existing, gameState). After deactivation,existingis defined (it has{ id, xp, paused: true }), so the early-returnif (!disciplineState) return trueon first activation no longer applies.In
discipline-math.ts(line 70-86),canProceedDisciplinechecks:Since
rawManais never passed,gameState.rawManaisundefined, soundefined || 0=0, and0 >= 1(drain is 1) returnsfalse. The activation is silently rejected.Affected Files
src/components/game/tabs/DisciplinesTab.tsx— UI does not passrawManaingameStatesrc/lib/game/stores/discipline-slice.ts—activatemethod relies ongameState.rawManafor re-activation guardsrc/lib/game/utils/discipline-math.ts—canProceedDisciplinereturnsfalsewhenrawManais missingImpact
canProceedDisciplinerequires mana availability for re-activation but the UI never supplies itEvidence
src/lib/game/__tests__/discipline-reactivate-bug.test.tsdocuments this exact bug — the first test case explicitly asserts the broken behavior (activeIdsdoes NOT contain the discipline after reactivation withoutrawMana)Suggested Fix Direction
Pass
rawManafrom the mana store into theactivatecall inDisciplinesTab.tsx, or changecanProceedDisciplineto be optimistic (returntrue) whengameStatedoesn't include mana info, matching the first-activation behavior.Starting investigation. Root cause is clear:
DisciplinesTab.tsxdoesn't passrawManain thegameStateobject when callingactivate(id, { elements, signedPacts }), so on re-activation after deactivation,canProceedDisciplinefails silently. Reading all three affected files now.Fixed. The root cause was that
DisciplinesTab.tsxcalledactivate(id, { elements, signedPacts })without passingrawMana. After deactivation, the discipline state exists (withpaused: true), socanProceedDisciplineevaluates mana drain check — butgameState.rawManawasundefined, causingundefined || 0 = 0 >= drainto returnfalse, silently rejecting reactivation.Changes:
rawManafromuseManaStoreto thegameStatepassed toactivate()activatetype signature to includerawMana?: numberAll 1087 tests pass.
Root cause analysis & robust fix applied.
The previous fix (passing
rawManafrom the UI) was fragile — it only addressed raw mana disciplines, and any future discipline using a different mana type (earth, fire, metal, etc.) would have the same silent failure.The real problem: The
activate()method required the UI to manually construct and pass agameStatebag ({ elements, rawMana, signedPacts }). If any field was missing,canProceedDisciplinesilently returned false. This is a class of bug that would keep resurfacing.The robust fix:
activate()now readsrawMana,elements, andsignedPactsdirectly fromuseManaStoreandusePrestigeStoreviagetState(). The UI only needs to callactivate(id)— no gameState bag needed. Tests can still pass explicit overrides when they need to control the check.Changes:
discipline-slice.ts—activate()resolves game state from stores by default;gameStateOverridesparam kept for test controlDisciplinesTab.tsx— simplified to justactivate(id), removed all gameState bag constructiondiscipline-reactivate-bug.test.ts— updated to set mana store state directly instead of passing gameStateAll 1088 tests pass. This fix handles ALL 22 mana types (raw + 7 base + 1 utility + 8 composite + 6 exotic) and will not break when new mana types or new guard conditions are added.