7.1 KiB
Agent Memory - Lessons Learned
This file documents issues encountered by previous agents and their solutions. Read this before starting work to avoid repeating mistakes.
Testing Issues
Issue: Mock project setup not navigating to board view
Problem: Setting currentProject in localStorage didn't automatically show the board view - app stayed on welcome view.
Fix: The currentView state is not persisted in localStorage. Instead of trying to set it, have tests click on the recent project from the welcome view to trigger setCurrentProject() which handles the view transition properly.
// Don't do this:
await setupMockProject(page); // Sets localStorage
await page.goto("/");
await waitForElement(page, "board-view"); // ❌ Fails - still on welcome view
// Do this instead:
await setupMockProject(page);
await page.goto("/");
await waitForElement(page, "welcome-view");
const recentProject = page.locator(
'[data-testid="recent-project-test-project-1"]'
);
await recentProject.click(); // ✅ Triggers proper view transition
await waitForElement(page, "board-view");
Issue: View output button test IDs are conditional
Problem: Tests failed looking for view-output-inprogress-${featureId} when the actual button had view-output-${featureId}.
Fix: The button test ID depends on whether the feature is actively running:
view-output-${featureId}- shown when feature is inrunningAutoTasks(actively running)view-output-inprogress-${featureId}- shown when status is "in_progress" but NOT actively running
After dragging a feature to in_progress, wait for the auto_mode_feature_start event to fire before looking for the button:
// Wait for feature to start running
const viewOutputButton = page
.locator(
`[data-testid="view-output-${featureId}"], [data-testid="view-output-inprogress-${featureId}"]`
)
.first();
await expect(viewOutputButton).toBeVisible({ timeout: 8000 });
Issue: Elements not appearing due to async event timing
Problem: Tests checked for UI elements before async events (like auto_mode_feature_start) had fired and updated the UI.
Fix: Add appropriate timeouts when waiting for elements that depend on async events. The mock auto mode takes ~2.4 seconds to complete, so allow sufficient time:
// Mock auto mode timing: ~2.4s + 1.5s delay = ~4s total
await waitForAgentOutputModalHidden(page, { timeout: 10000 });
Issue: Slider interaction testing
Problem: Clicking on slider track didn't reliably set specific values. Fix: Use the slider's keyboard interaction or calculate the exact click position on the track. For max value, click on the rightmost edge of the track.
Issue: Port binding blocked in sandbox mode
Problem: Playwright tests couldn't bind to port in sandbox mode. Fix: Tests don't need sandbox disabled - the issue was TEST_REUSE_SERVER environment variable. Make sure to start the dev server separately or let Playwright's webServer config handle it.
Code Architecture
Issue: Understanding store state persistence
Problem: Not all store state is persisted to localStorage.
Fix: Check the partialize function in app-store.ts to see which state is persisted:
partialize: (state) => ({
projects: state.projects,
currentProject: state.currentProject,
theme: state.theme,
sidebarOpen: state.sidebarOpen,
apiKeys: state.apiKeys,
chatSessions: state.chatSessions,
chatHistoryOpen: state.chatHistoryOpen,
maxConcurrency: state.maxConcurrency, // Added for concurrency feature
});
Note: currentView is NOT persisted - it's managed through actions.
Issue: Auto mode task lifecycle
Problem: Confusion about when features are considered "running" vs "in_progress". Fix: Understand the task lifecycle:
- Feature dragged to "in_progress" column → status becomes "in_progress"
auto_mode_feature_startevent fires → feature added torunningAutoTasks- Agent works on feature → periodic events sent
auto_mode_feature_completeevent fires → feature removed fromrunningAutoTasks- If
passes: true→ status becomes "verified", ifpasses: false→ stays "in_progress"
Issue: waiting_approval features not draggable when skipTests=true
Problem: Features in waiting_approval status couldn't be dragged to verified column, even though the code appeared to handle it.
Fix: The order of condition checks in handleDragEnd matters. The skipTests check was catching waiting_approval features before the waiting_approval status check could handle them. Move the waiting_approval status check before the skipTests check in board-view.tsx:
// Correct order in handleDragEnd:
if (draggedFeature.status === "backlog") {
// ...
} else if (draggedFeature.status === "waiting_approval") {
// Handle waiting_approval BEFORE skipTests check
// because waiting_approval features often have skipTests=true
} else if (draggedFeature.skipTests) {
// Handle other skipTests features
}
Best Practices Discovered
Testing utilities are critical
Create comprehensive testing utilities in tests/utils.ts to avoid repeating selector logic:
waitForElement- waits for elements to appearwaitForElementHidden- waits for elements to disappearsetupMockProject- sets up mock localStorage statenavigateToBoard- handles navigation from welcome to board view
Always add data-testid attributes
When implementing features, immediately add data-testid attributes to key UI elements. This makes tests more reliable and easier to write.
Test timeouts should be generous but not excessive
- Default timeout: 30s (set in playwright.config.ts)
- Element waits: 5-15s for critical elements
- Auto mode completion: 10s (accounts for ~4s mock duration)
- Don't increase timeouts past 10s for individual operations
Mock auto mode timing
The mock auto mode in electron.ts has predictable timing:
- Total duration: ~2.4 seconds (300+500+300+300+500+500ms)
- Plus 1.5s delay before auto-closing modals
- Total: ~4 seconds from start to completion
Issue: HotkeyButton conflicting with useKeyboardShortcuts
Problem: Adding HotkeyButton with a simple key (like "N") to buttons that already had keyboard shortcuts registered via useKeyboardShortcuts caused the hotkey to stop working. Both registered duplicate listeners, and the HotkeyButton's stopPropagation() call could interfere.
Fix: When a simple single-key hotkey is already handled by useKeyboardShortcuts, set hotkeyActive={false} on the HotkeyButton so it only displays the indicator badge without registering a duplicate listener:
// In views that already use useKeyboardShortcuts for the "N" key:
<HotkeyButton
onClick={() => setShowAddDialog(true)}
hotkey={shortcuts.addFeature}
hotkeyActive={false} // <-- Important! Prevents duplicate listener
>
Add Feature
</HotkeyButton>
// HotkeyButton should only actively listen when it's the sole handler (e.g., Cmd+Enter in dialogs)
<HotkeyButton
onClick={handleSubmit}
hotkey={{ key: "Enter", cmdCtrl: true }}
hotkeyActive={isDialogOpen} // Active when dialog is open
>
Submit
</HotkeyButton>