docs(21): create phase plan
Phase 21: Chat Window Fixes - 1 plan(s) in 1 wave(s) - 1 parallel, 0 sequential - Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d162e6cd89
commit
76805f855c
|
|
@ -417,11 +417,11 @@ Plans:
|
|||
- [x] 20-01-PLAN.md — Add removeVuState function and integrate with mixer lifecycle - COMPLETE 2026-02-08
|
||||
|
||||
#### Phase 21: Chat Window Fixes
|
||||
**Goal**: Fix identified chat WebSocket listener and state cleanup issues
|
||||
**Goal**: Fix unbounded message accumulation and add session leave cleanup
|
||||
**Depends on**: Phase 19
|
||||
**Research**: Unlikely (fixing issues identified in Phase 19)
|
||||
**Requirements**: CHAT-01, CHAT-02, CHAT-03
|
||||
**Plans**: TBD (1-2 plans expected)
|
||||
**Plans**: 1 plan
|
||||
|
||||
**Success Criteria:**
|
||||
1. WebSocket listeners are properly removed when chat window closes
|
||||
|
|
@ -431,7 +431,7 @@ Plans:
|
|||
5. Redux state cleanup happens when session ends or user leaves
|
||||
|
||||
Plans:
|
||||
- [ ] 21-01: TBD
|
||||
- [ ] 21-01-PLAN.md — Bounded message storage and session leave cleanup (CHAT-01, CHAT-03)
|
||||
|
||||
#### Phase 22: Session Screen Fixes
|
||||
**Goal**: Fix identified session screen useEffect and polling cleanup issues
|
||||
|
|
@ -495,6 +495,6 @@ Phases execute in numeric order: 1 → 2 → ... → 18 → 19 → 20 → 21 →
|
|||
| 18. Integration Tests (Playwright) | v1.3 | 1/1 | Complete | 2026-02-08 |
|
||||
| 19. Audit and Discovery | v1.4 | 1/1 | Complete | 2026-02-08 |
|
||||
| 20. VU Meter Fixes | v1.4 | 1/1 | Complete | 2026-02-08 |
|
||||
| 21. Chat Window Fixes | v1.4 | 0/TBD | Not started | - |
|
||||
| 21. Chat Window Fixes | v1.4 | 0/1 | Not started | - |
|
||||
| 22. Session Screen Fixes | v1.4 | 0/TBD | Not started | - |
|
||||
| 23. Verification | v1.4 | 0/TBD | Not started | - |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
---
|
||||
phase: 21-chat-window-fixes
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- jam-ui/src/store/features/sessionChatSlice.js
|
||||
- jam-ui/src/components/client/JKSessionScreen.js
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Chat messages are limited to MAX_MESSAGES (500) per channel"
|
||||
- "Oldest messages are removed when new messages exceed the limit"
|
||||
- "Chat state is cleared when user leaves session"
|
||||
- "Memory usage does not grow unbounded with chat activity"
|
||||
artifacts:
|
||||
- path: "jam-ui/src/store/features/sessionChatSlice.js"
|
||||
provides: "MAX_MESSAGES constant and clearAllMessages action"
|
||||
contains: "MAX_MESSAGES"
|
||||
- path: "jam-ui/src/components/client/JKSessionScreen.js"
|
||||
provides: "Chat cleanup on session leave"
|
||||
contains: "clearAllMessages"
|
||||
key_links:
|
||||
- from: "sessionChatSlice.js addMessageFromWebSocket"
|
||||
to: "slice(-MAX_MESSAGES)"
|
||||
via: "array limit after push"
|
||||
pattern: "slice.*-MAX_MESSAGES"
|
||||
- from: "JKSessionScreen.js leave handler"
|
||||
to: "clearAllMessages action"
|
||||
via: "dispatch on session leave"
|
||||
pattern: "dispatch.*clearAllMessages"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Implement bounded chat message storage and cleanup to prevent unbounded memory growth.
|
||||
|
||||
Purpose: Fix CHAT-01 (unbounded message growth) and CHAT-03 (no cleanup on session leave) identified in Phase 19 audit. Without these fixes, the messagesByChannel Redux state grows indefinitely during active chat sessions, contributing to memory degradation over time.
|
||||
|
||||
Output: sessionChatSlice.js with MAX_MESSAGES limit enforced on all message additions, and JKSessionScreen.js dispatching clearAllMessages when leaving sessions.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/Users/nuwan/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/Users/nuwan/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/19-audit-and-discovery/19-AUDIT.md
|
||||
|
||||
# Key source files
|
||||
@jam-ui/src/store/features/sessionChatSlice.js
|
||||
@jam-ui/src/components/client/JKSessionScreen.js
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add MAX_MESSAGES limit to sessionChatSlice.js</name>
|
||||
<files>jam-ui/src/store/features/sessionChatSlice.js</files>
|
||||
<action>
|
||||
Add bounded message storage to prevent unbounded memory growth:
|
||||
|
||||
1. Add constant at top of file (after imports, before initialState):
|
||||
```javascript
|
||||
/**
|
||||
* Maximum messages retained per channel to prevent unbounded memory growth
|
||||
* Oldest messages are removed when this limit is exceeded
|
||||
*/
|
||||
const MAX_MESSAGES = 500;
|
||||
```
|
||||
|
||||
2. In `addMessageFromWebSocket` reducer (around line 202), after pushing and sorting:
|
||||
- Add slice to limit array: `state.messagesByChannel[channel] = state.messagesByChannel[channel].slice(-MAX_MESSAGES);`
|
||||
- This keeps only the last MAX_MESSAGES (most recent)
|
||||
|
||||
3. In `fetchChatHistory.fulfilled` reducer (around line 366), after merging and sorting:
|
||||
- Add same slice: `state.messagesByChannel[channel] = state.messagesByChannel[channel].slice(-MAX_MESSAGES);`
|
||||
|
||||
4. In `uploadAttachment.fulfilled` reducer (around line 517), after pushing and sorting:
|
||||
- Add same slice: `state.messagesByChannel[channel] = state.messagesByChannel[channel].slice(-MAX_MESSAGES);`
|
||||
|
||||
Why slice(-MAX_MESSAGES): Negative slice keeps last N elements, so oldest messages are dropped first (FIFO queue behavior).
|
||||
</action>
|
||||
<verify>
|
||||
1. Grep for MAX_MESSAGES in file: should appear 4 times (1 definition + 3 usages)
|
||||
2. Grep for "slice(-MAX_MESSAGES)" in file: should appear 3 times
|
||||
3. Run ESLint: `cd jam-ui && npm run lint -- --quiet src/store/features/sessionChatSlice.js`
|
||||
</verify>
|
||||
<done>
|
||||
MAX_MESSAGES constant defined (500), and slice(-MAX_MESSAGES) applied in addMessageFromWebSocket, fetchChatHistory.fulfilled, and uploadAttachment.fulfilled reducers. Message arrays are bounded to 500 per channel.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add clearAllMessages action and dispatch on session leave</name>
|
||||
<files>jam-ui/src/store/features/sessionChatSlice.js, jam-ui/src/components/client/JKSessionScreen.js</files>
|
||||
<action>
|
||||
Add chat cleanup when leaving sessions:
|
||||
|
||||
**In sessionChatSlice.js:**
|
||||
|
||||
1. Add new reducer `clearAllMessages` in the reducers object (after `clearUploadError`, around line 305):
|
||||
```javascript
|
||||
/**
|
||||
* Clear all messages when leaving session
|
||||
* Called from JKSessionScreen when user leaves to prevent stale data
|
||||
*/
|
||||
clearAllMessages: (state) => {
|
||||
state.messagesByChannel = {};
|
||||
state.unreadCounts = {};
|
||||
state.fetchStatus = {};
|
||||
state.fetchError = {};
|
||||
state.nextCursors = {};
|
||||
// Preserve lastReadAt for persistence across sessions
|
||||
// Preserve isWindowOpen and windowPosition for UX continuity
|
||||
},
|
||||
```
|
||||
|
||||
2. Export the action in the exports (around line 540):
|
||||
- Add `clearAllMessages` to the destructured exports
|
||||
|
||||
**In JKSessionScreen.js:**
|
||||
|
||||
1. Import clearAllMessages action (around line 58):
|
||||
- Add `clearAllMessages` to the imports from sessionChatSlice
|
||||
|
||||
2. In handleLeaveWithFeedback callback (around line 916 where clearSession is dispatched):
|
||||
- Add `dispatch(clearAllMessages());` BEFORE `dispatch(clearSession());`
|
||||
|
||||
3. In the cleanup useEffect (around line 944 where clearSession is dispatched):
|
||||
- Add `dispatch(clearAllMessages());` BEFORE `dispatch(clearSession());`
|
||||
|
||||
This ensures chat state is cleared both when:
|
||||
- User explicitly leaves via feedback modal
|
||||
- Component unmounts (navigation away, session end)
|
||||
</action>
|
||||
<verify>
|
||||
1. Grep for clearAllMessages in sessionChatSlice.js: should appear 2 times (reducer + export)
|
||||
2. Grep for clearAllMessages in JKSessionScreen.js: should appear 3 times (import + 2 dispatches)
|
||||
3. Run ESLint on both files:
|
||||
- `cd jam-ui && npm run lint -- --quiet src/store/features/sessionChatSlice.js`
|
||||
- `cd jam-ui && npm run lint -- --quiet src/components/client/JKSessionScreen.js`
|
||||
</verify>
|
||||
<done>
|
||||
clearAllMessages action added to sessionChatSlice.js, exported, and dispatched in both leave paths in JKSessionScreen.js (handleLeaveWithFeedback and unmount cleanup useEffect). Chat state is properly cleaned up when leaving sessions.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. **Syntax verification:** Both files pass ESLint without errors
|
||||
2. **Constant verification:** `grep -n "MAX_MESSAGES" sessionChatSlice.js` shows 4 occurrences
|
||||
3. **Action verification:** `grep -n "clearAllMessages" sessionChatSlice.js JKSessionScreen.js` shows 5 occurrences total
|
||||
4. **Build verification:** `cd jam-ui && npm run build` completes without errors (if environment supports)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
1. MAX_MESSAGES = 500 constant defined in sessionChatSlice.js
|
||||
2. slice(-MAX_MESSAGES) applied after message push in 3 reducers
|
||||
3. clearAllMessages action created and exported
|
||||
4. clearAllMessages dispatched in both leave paths (handleLeaveWithFeedback, unmount cleanup)
|
||||
5. Both files pass ESLint
|
||||
6. CHAT-01 and CHAT-03 requirements addressed
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/21-chat-window-fixes/21-01-SUMMARY.md`
|
||||
</output>
|
||||
Loading…
Reference in New Issue