diff --git a/.jules/bolt.md b/.jules/bolt.md index 38d4b732..144d4f06 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -41,3 +41,7 @@ ## 2025-02-15 - Replace Array.from(map.values()).map with a for...of loop **Learning:** Using `Array.from(map.values()).map(...)` creates an unnecessary intermediate array which wastes memory allocation and garbage collection time, particularly for frequently re-rendered components handling large collections. **Action:** Use a `for...of` loop over `map.values()` to iterate and push mapped elements directly into the final array for O(1) memory and avoiding intermediate array allocations. + +## 2023-11-20 - Early Short-Circuiting for Performance in Minimums/Maximums +**Learning:** Using an unconditional `.reduce()` to find a minimum or maximum value iterates through all elements in an array, taking O(N) time even when the known absolute minimum or maximum bound (e.g., 'low' confidence) has already been reached. +**Action:** Replace unconditional `.reduce()` with a `for...of` loop with an early `break` for finding minimum or maximums with a known absolute bound to optimize for short-circuitable O(N) evaluation. diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index c039dfba..0481e38e 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -293,6 +293,31 @@ describe("App", () => { expect(screen.getAllByText(/2 sections/i).length).toBeGreaterThan(0); }); + it("short-circuits and summarizes confidence as low when a low-confidence section is encountered", async () => { + const loadedProject = succeededResult().result; + loadedProject.sections.push({ + ...loadedProject.sections[0], + id: "bridge-1", + label: "bridge", + confidence: { level: "low", source: "model", notes: "Low confidence." } + }); + loadedProject.sections.push({ + ...loadedProject.sections[0], + id: "chorus-1", + label: "chorus", + confidence: { level: "high", source: "model", notes: "The chorus form is clear." } + }); + mockLoadProject.mockResolvedValueOnce(loadedProject); + render(); + + fireEvent.click(screen.getByRole("button", { name: /open project/i })); + + await waitFor(() => { + expect(screen.getByText(/^Low$/i)).toBeTruthy(); + }); + expect(screen.getAllByText(/3 sections/i).length).toBeGreaterThan(0); + }); + it("selects a local audio source and starts a local-audio analysis job", async () => { tauriInvoke .mockResolvedValueOnce(bootstrapResponse()) diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 24f5fb09..6b7d8514 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -180,15 +180,21 @@ function MetricCard({ function ConfidenceMetric({ song }: { song: RehearsalSong | null }) { const sectionCount = song?.sections.length ?? 0; const confidenceOrder = { high: 3, medium: 2, low: 1 } as const; - const lowestConfidence = song?.sections.reduce( - (current, section) => { - if (!current || confidenceOrder[section.confidence.level] < confidenceOrder[current]) { - return section.confidence.level; + + // Performance: Avoid unconditional O(N) .reduce() for finding minimum with an absolute bound. + // Use for...of loop with early break when the known absolute minimum ("low") is encountered. + let lowestConfidence: RehearsalSong["sections"][number]["confidence"]["level"] | null = null; + if (song && song.sections) { + for (const section of song.sections) { + if (!lowestConfidence || confidenceOrder[section.confidence.level] < confidenceOrder[lowestConfidence]) { + lowestConfidence = section.confidence.level; } - return current; - }, - null - ); + if (lowestConfidence === "low") { + break; + } + } + } + const confidence = lowestConfidence ? `${lowestConfidence[0].toUpperCase()}${lowestConfidence.slice(1)}` : "Ready"; const detail = sectionCount > 0 ? `${sectionCount} section${sectionCount === 1 ? "" : "s"}` : "Local analysis";