diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10fc..9edf08b3a 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,3 +61,7 @@ ## 2026-07-13 - Array.from mapping optimization **Learning:** Using `Array.from({ length: N }).map(...)` creates an intermediate array of `undefined` values which requires memory allocation and garbage collection, adding O(N) unnecessary overhead in frequently re-rendered UI components. **Action:** Use `Array.from({ length: N }, (_, index) => ...)` to map elements directly during array creation, avoiding intermediate allocations. + +## 2026-09-26 - O(N) Callback overhead on massive arrays +**Learning:** Using `.every()` on massive arrays (e.g., megabyte-sized PDF byte buffers) incurs severe callback overhead and blocks the main thread. +**Action:** Replace `.every()` and similar array methods with a traditional `for` loop for massive arrays to achieve a measurable optimization and prevent main-thread blocking. diff --git a/apps/desktop/src/features/score/scoreStorage.test.ts b/apps/desktop/src/features/score/scoreStorage.test.ts index 0feec199e..dae73af10 100644 --- a/apps/desktop/src/features/score/scoreStorage.test.ts +++ b/apps/desktop/src/features/score/scoreStorage.test.ts @@ -33,3 +33,27 @@ describe("scoreStorage bridge resolution", () => { ); }); }); + + it("handles valid arrays of numbers", async () => { + vi.stubGlobal("window", { + __TAURI_INTERNALS__: { + invoke: async () => [1, 2, 3], + }, + }); + + const result = await readScorePdf("project-1", "score-1"); + expect(result).toBeInstanceOf(Uint8Array); + expect(result).toEqual(Uint8Array.from([1, 2, 3])); + }); + + it("throws error when array contains non-numbers", async () => { + vi.stubGlobal("window", { + __TAURI_INTERNALS__: { + invoke: async () => [1, "2", 3], + }, + }); + + await expect(readScorePdf("project-1", "score-1")).rejects.toThrow( + "Invalid score bridge response" + ); + }); diff --git a/apps/desktop/src/features/score/scoreStorage.ts b/apps/desktop/src/features/score/scoreStorage.ts index 492f12591..d80dc0d62 100644 --- a/apps/desktop/src/features/score/scoreStorage.ts +++ b/apps/desktop/src/features/score/scoreStorage.ts @@ -91,8 +91,19 @@ export async function readScorePdf(projectId: string, scoreId: string): Promise< if (response instanceof ArrayBuffer) { return new Uint8Array(response); } - if (Array.isArray(response) && response.every((byte) => typeof byte === "number")) { - return Uint8Array.from(response as number[]); + if (Array.isArray(response)) { + // Performance: Avoid massive O(N) callback overhead of .every() on large byte arrays (e.g. megabyte-sized PDFs). + // A traditional for loop significantly reduces main-thread blocking time during validation. + let isValid = true; + for (let i = 0; i < response.length; i++) { + if (typeof response[i] !== "number") { + isValid = false; + break; + } + } + if (isValid) { + return Uint8Array.from(response as number[]); + } } throw new Error(INVALID_RESPONSE_MESSAGE);