Spaces:
Running
Running
SessionState Implementation Plan
Status: π‘ IN PROGRESS (Design Complete, Implementation Pending)
Branch: feature/remove-global-state
Completed β
- Analysis - Identified all global variable usage (20+ functions affected)
- Design - Created
SessionStateclass with all required fields - Documentation - Wrote comprehensive analysis and risk assessment
Next Steps (Implementation)
Phase 1: Refactor Core Wrapper Functions (2-3 hours)
Functions to Update (in order):
get_current_sheet(session: SessionState)β reads 4 globalsload_character_wrapper(char_choice, session)β writes 3 globalsload_character_with_debug_wrapper(char_choice, scenario, session)β writes 3 globalschat_wrapper(message, history, session)β reads 4 globalsclear_history_wrapper(session)β writes 1 globalload_party_mode_wrapper(session)β writes 4 globalsadd_to_party_wrapper(choices, session)β writes 2 globalsremove_from_party_wrapper(name, session)β writes 2 globals
Pattern for Each Function:
# BEFORE
def function_wrapper(arg1, arg2):
global var1, var2
# ... logic ...
var1 = new_value
return result
# AFTER
def function_wrapper(arg1, arg2, session: SessionState):
# ... logic ...
session.var1 = new_value
return result, session # CRITICAL: Return session!
Testing After Each Function:
- Add type hints to catch missing parameters
- Test manually with single user
- Verify state flows correctly
Phase 2: Update Gradio Event Handlers (1-2 hours)
Event Handlers to Update:
- Load character button (play tab)
- Load party button (play tab)
- Delete character button (play tab)
- Chat submit button + Enter key (play tab)
- Combat control buttons (next turn, end combat) (play tab)
- Clear history button (play tab)
- Quick action buttons (attack, cast, use item, help) (play tab)
- Create character button (create tab)
- Add/remove party buttons (party tab)
Pattern for Event Handlers:
# BEFORE
component.click(
wrapper_function,
inputs=[arg1, arg2],
outputs=[output1, output2]
)
# AFTER
component.click(
wrapper_function,
inputs=[arg1, arg2, session_state], # Add session
outputs=[output1, output2, session_state] # Return session
)
Special Cases:
.then()chains need session passed through- Lambda functions need session parameter
- Multiple outputs need session appended
Phase 3: Create gr.State Component (30 min)
In app_gradio.py, after demo creation:
with demo:
# Create session state component (ONE per user session)
session_state = gr.State(create_session_state())
# ... rest of UI setup ...
Key Points:
- Only ONE
gr.Statecomponent created - Passed to ALL event handlers
- Gradio automatically manages per-session instances
Phase 4: Remove Global Variables (15 min)
Delete from app_gradio.py (lines 75-80):
# DELETE THESE:
current_character = None
conversation_history = []
party = PartyState(...)
party_characters = {}
gameplay_mode = "character"
Delete global gm (line 69):
# DELETE THIS:
gm = GameMaster(db)
Search for remaining global statements:
grep "global " web/app_gradio.py
# Should return NO results
Phase 5: Integration Testing (1 hour)
Test Scenarios:
Single User Flow:
- Load character β
- Chat with GM β
- Start combat β
- Use spells/items β
- Clear history β
Party Mode Flow:
- Create party β
- Add characters β
- Start combat β
- Remove characters β
Multi-User Test (CRITICAL):
- Open app in 2 browser windows (different sessions)
- Window 1: Load Character A
- Window 2: Load Character B
- Window 1: Chat "Hello"
- Window 2: Chat "Goodbye"
- Verify: Each window shows only its own character/chat
- Verify: No state leakage between sessions
Edge Cases:
- Reload page (state should reset)
- Switch between character/party mode
- Rapid clicking (race conditions)
Automated Test (Create Later):
# tests/test_session_state.py
def test_session_isolation():
"""Test that two SessionState instances are independent."""
session1 = create_session_state()
session2 = create_session_state()
session1.gameplay_mode = "party"
assert session2.gameplay_mode == "character"
session1.conversation_history.append({"role": "user", "content": "test"})
assert len(session2.conversation_history) == 0
Success Criteria
- No
globalstatements in app_gradio.py - All event handlers pass/return
session_state - App works with single user (smoke test)
- App works with multiple users simultaneously (isolation test)
- No race conditions or state leakage
- All existing tests still pass
Rollback Plan
If issues arise:
- Discard changes:
git checkout main - Delete feature branch:
git branch -D feature/remove-global-state - Start over with smaller scope (e.g., only character mode first)
Estimated Time
- Phase 1: 2-3 hours (function refactoring)
- Phase 2: 1-2 hours (event handler updates)
- Phase 3: 30 minutes (gr.State setup)
- Phase 4: 15 minutes (cleanup)
- Phase 5: 1 hour (testing)
Total: 5-7 hours of focused work
Current Status
Completed:
- β Analysis (30 min)
- β Design (30 min)
- β Documentation (30 min)
Remaining:
- β³ Implementation (5-7 hours)
Branch: feature/remove-global-state
Ready to merge: NO (implementation not started)
Blocking issues: None
Next action: Begin Phase 1 (refactor wrapper functions)