From 45c5b2a9feb1a91ee9e669aed7907be025cfb1bf Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 10 Jul 2026 14:16:19 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9A=A1=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0:=20ConfidenceMetric=EC=97=90=EC=84=9C=20reduce?= =?UTF-8?q?=EB=A5=BC=20for...of=20=EB=A3=A8=ED=94=84=EC=99=80=20early=20br?= =?UTF-8?q?eak=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 4 ++++ apps/desktop/src/App.test.tsx | 28 ++++++++++++++++++++++++++++ apps/desktop/src/App.tsx | 19 +++++++++++-------- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 38d4b7327..27e2c367e 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. + +## 2025-02-23 - Short-circuiting known absolute bounds +**Learning:** Using unconditional `.reduce()` to find a minimum or maximum value forces O(N) iteration, which is wasteful when an absolute bound (e.g., finding a 'low' confidence level) is known and can be found early. +**Action:** For performance optimizations involving finding a minimum/maximum value with a known absolute bound, replace unconditional `.reduce()` calls with a `for...of` loop and an early `break` to short-circuit the operation. diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 88a7abe34..27e1843db 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -359,6 +359,34 @@ describe("App", () => { expect(screen.getAllByText(/2 sections/i).length).toBeGreaterThan(0); }); + it("short-circuits confidence evaluation early when a 'low' confidence section is encountered", async () => { + const loadedProject = succeededResult().result; + // Add multiple sections to verify the loop breaks early and handles subsequent items correctly + loadedProject.sections.push( + { + ...loadedProject.sections[0], + id: "verse-2", + label: "verse", + confidence: { level: "low", source: "model", notes: "Difficult section." } + }, + { + ...loadedProject.sections[0], + id: "chorus-2", + label: "chorus", + confidence: { level: "high", source: "model", notes: "Very 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 afe103b2b..ecf387807 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -210,15 +210,18 @@ function sectionCountDetail(t: ReturnType, sectionCount function ConfidenceMetric({ song, t }: { song: RehearsalSong | null; t: ReturnType }) { 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; + let lowestConfidence: RehearsalSong["sections"][number]["confidence"]["level"] | null = null; + if (song?.sections) { + for (const section of song.sections) { + if (!lowestConfidence || confidenceOrder[section.confidence.level] < confidenceOrder[lowestConfidence]) { + lowestConfidence = section.confidence.level; } - return current; - }, - null - ); + // Performance: Early break if we found the absolute minimum + if (lowestConfidence === "low") { + break; + } + } + } const confidence = lowestConfidence ? `${lowestConfidence[0].toUpperCase()}${lowestConfidence.slice(1)}` : t("metricConfidenceReady"); const detail = sectionCountDetail(t, sectionCount); From 62c4caa118a64faeaa240fc38048750f7d196c16 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:09:32 +0000 Subject: [PATCH 2/3] dummy commit for CI --- .Jules/palette.md | 4 - .github/workflows/bandit.yml | 2 +- .github/workflows/build-baseline.yml | 90 +- .github/workflows/ci.yml | 4 +- .github/workflows/codeql.yml | 11 +- .github/workflows/dependency-review.yml | 30 + .github/workflows/ossf-scorecard.yml | 16 +- .github/workflows/release.yml | 2 +- .github/workflows/security-audit.yml | 2 +- .github/workflows/trivy.yml | 9 +- .gitignore | 1 - .jules/sentinel.md | 11 - .trivyignore | 6 +- AGENTS.md | 17 - CHANGELOG.md | 8 - CLAUDE.md | 75 - Cargo.lock | 586 --- Cargo.toml | 14 - README.md | 2 +- apps/desktop/.gitignore | 1 - apps/desktop/.storybook/main.ts | 23 - apps/desktop/.storybook/preview.ts | 14 - apps/desktop/core/Cargo.toml | 22 - apps/desktop/core/src/lib.rs | 1283 ------ apps/desktop/package.json | 14 +- apps/desktop/src-tauri/Cargo.lock | 152 +- apps/desktop/src-tauri/Cargo.toml | 2 - apps/desktop/src-tauri/build.rs | 6 - apps/desktop/src-tauri/capabilities/main.json | 8 +- .../src-tauri/gen/schemas/acl-manifests.json | 2 +- .../src-tauri/gen/schemas/capabilities.json | 2 +- .../src-tauri/gen/schemas/desktop-schema.json | 72 - .../src-tauri/gen/schemas/macOS-schema.json | 72 - .../src-tauri/gen/schemas/windows-schema.json | 2400 ----------- apps/desktop/src-tauri/osv-scanner.toml | 4 +- .../autogenerated/attach_score_pdf.toml | 11 - .../autogenerated/import_youtube_url.toml | 11 - .../autogenerated/load_project.toml | 11 - .../autogenerated/read_score_pdf.toml | 11 - .../autogenerated/remove_score_pdf.toml | 11 - .../autogenerated/save_project.toml | 11 - apps/desktop/src-tauri/src/main.rs | 981 ++++- apps/desktop/src/App.test.tsx | 99 +- apps/desktop/src/App.tsx | 274 +- apps/desktop/src/components/ui/accordion.tsx | 76 - apps/desktop/src/components/ui/breadcrumb.tsx | 107 - .../src/components/ui/button.stories.tsx | 22 - .../src/components/ui/checkbox.stories.tsx | 17 - apps/desktop/src/components/ui/checkbox.tsx | 39 - .../src/components/ui/dialog.stories.tsx | 39 - apps/desktop/src/components/ui/dialog.tsx | 120 - .../desktop/src/components/ui/in-page-nav.tsx | 67 - apps/desktop/src/components/ui/label.tsx | 21 - .../desktop/src/components/ui/radio-group.tsx | 50 - apps/desktop/src/components/ui/select.tsx | 128 - apps/desktop/src/components/ui/sonner.tsx | 33 - .../src/components/ui/step-indicator.tsx | 113 - apps/desktop/src/components/ui/switch.tsx | 34 - apps/desktop/src/components/ui/table.tsx | 122 - apps/desktop/src/components/ui/tooltip.tsx | 53 - .../src/components/ui/ui-added.test.tsx | 248 -- .../src/features/chords/index.test.tsx | 77 - apps/desktop/src/features/chords/index.tsx | 10 +- .../src/features/ranges/index.test.tsx | 88 - apps/desktop/src/features/ranges/index.tsx | 5 - .../src/features/score/ScoreView.test.tsx | 416 -- apps/desktop/src/features/score/ScoreView.tsx | 230 - .../src/features/score/ScoreViewer.test.tsx | 342 -- .../src/features/score/ScoreViewer.tsx | 317 -- apps/desktop/src/features/score/pdfjs.ts | 29 - .../src/features/score/scoreStorage.test.ts | 35 - .../src/features/score/scoreStorage.ts | 112 - .../src/features/workspace/RoleSwitcher.tsx | 2 +- .../src/features/workspace/SectionRoadmap.tsx | 6 +- .../src/features/workspace/Workspace.tsx | 75 +- apps/desktop/src/locales/en/common.json | 78 - apps/desktop/src/locales/ko/common.json | 78 - apps/desktop/src/setupTests.ts | 17 +- apps/desktop/vite.config.ts | 9 +- docs/security/dependency-policy.md | 3 +- eslint.config.js | 2 +- package-lock.json | 3796 ++--------------- package.json | 2 +- packages/shared-types/package.json | 4 +- packages/shared-types/src/index.ts | 43 +- packages/shared-types/test/index.test.ts | 27 - scripts/checks/verify_supply_chain.py | 38 +- .../release/build_tauri_bundle_with_retry.sh | 65 - services/analysis-engine/pyproject.toml | 5 +- .../src/bandscope_analysis/api.py | 63 +- .../src/bandscope_analysis/chords/__init__.py | 19 - .../src/bandscope_analysis/chords/capo.py | 189 +- .../chords/function_analyzer.py | 180 - .../bandscope_analysis/chords/key_detector.py | 153 - .../chords/section_harmony.py | 164 - .../chords/transposition.py | 332 -- .../bandscope_analysis/exports/__init__.py | 5 - .../src/bandscope_analysis/exports/chart.py | 259 -- .../src/bandscope_analysis/ranges/__init__.py | 8 - .../src/bandscope_analysis/ranges/analyzer.py | 99 +- .../src/bandscope_analysis/ranges/pressure.py | 220 - .../bandscope_analysis/roles/articulation.py | 161 - .../src/bandscope_analysis/roles/extractor.py | 4 + .../src/bandscope_analysis/roles/overlap.py | 131 - .../bandscope_analysis/sections/segmenter.py | 129 +- .../separation/audio_separator.py | 265 +- .../separation/separator.py | 4 + .../bandscope_analysis/temporal/__init__.py | 12 +- .../bandscope_analysis/temporal/analyzer.py | 41 +- .../src/bandscope_analysis/temporal/groove.py | 190 - .../src/bandscope_analysis/temporal/hits.py | 214 - .../bandscope_analysis/temporal/stability.py | 230 - .../bandscope_analysis/transcription/api.py | 172 +- services/analysis-engine/tests/test_api.py | 116 +- .../tests/test_articulation.py | 126 - .../tests/test_chart_export.py | 342 -- services/analysis-engine/tests/test_chords.py | 53 +- services/analysis-engine/tests/test_cli.py | 22 - .../tests/test_function_analyzer.py | 154 - services/analysis-engine/tests/test_groove.py | 127 - services/analysis-engine/tests/test_hits.py | 140 - .../tests/test_key_detector.py | 122 - .../tests/test_range_pressure.py | 173 - services/analysis-engine/tests/test_ranges.py | 90 +- .../tests/test_register_overlap.py | 151 - .../tests/test_section_harmony.py | 171 - .../analysis-engine/tests/test_segmenter.py | 56 +- .../analysis-engine/tests/test_separation.py | 498 +-- .../tests/test_supply_chain_policy.py | 69 +- .../tests/test_tempo_stability.py | 143 - .../analysis-engine/tests/test_temporal.py | 25 - .../tests/test_transcription.py | 231 +- .../tests/test_transposition.py | 174 - services/analysis-engine/uv.lock | 620 +-- 134 files changed, 2220 insertions(+), 18214 deletions(-) create mode 100644 .github/workflows/dependency-review.yml delete mode 100644 CLAUDE.md delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml delete mode 100644 apps/desktop/.gitignore delete mode 100644 apps/desktop/.storybook/main.ts delete mode 100644 apps/desktop/.storybook/preview.ts delete mode 100644 apps/desktop/core/Cargo.toml delete mode 100644 apps/desktop/core/src/lib.rs delete mode 100644 apps/desktop/src-tauri/gen/schemas/windows-schema.json delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/attach_score_pdf.toml delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/import_youtube_url.toml delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/load_project.toml delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/read_score_pdf.toml delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/remove_score_pdf.toml delete mode 100644 apps/desktop/src-tauri/permissions/autogenerated/save_project.toml delete mode 100644 apps/desktop/src/components/ui/accordion.tsx delete mode 100644 apps/desktop/src/components/ui/breadcrumb.tsx delete mode 100644 apps/desktop/src/components/ui/button.stories.tsx delete mode 100644 apps/desktop/src/components/ui/checkbox.stories.tsx delete mode 100644 apps/desktop/src/components/ui/checkbox.tsx delete mode 100644 apps/desktop/src/components/ui/dialog.stories.tsx delete mode 100644 apps/desktop/src/components/ui/dialog.tsx delete mode 100644 apps/desktop/src/components/ui/in-page-nav.tsx delete mode 100644 apps/desktop/src/components/ui/label.tsx delete mode 100644 apps/desktop/src/components/ui/radio-group.tsx delete mode 100644 apps/desktop/src/components/ui/select.tsx delete mode 100644 apps/desktop/src/components/ui/sonner.tsx delete mode 100644 apps/desktop/src/components/ui/step-indicator.tsx delete mode 100644 apps/desktop/src/components/ui/switch.tsx delete mode 100644 apps/desktop/src/components/ui/table.tsx delete mode 100644 apps/desktop/src/components/ui/tooltip.tsx delete mode 100644 apps/desktop/src/components/ui/ui-added.test.tsx delete mode 100644 apps/desktop/src/features/chords/index.test.tsx delete mode 100644 apps/desktop/src/features/ranges/index.test.tsx delete mode 100644 apps/desktop/src/features/score/ScoreView.test.tsx delete mode 100644 apps/desktop/src/features/score/ScoreView.tsx delete mode 100644 apps/desktop/src/features/score/ScoreViewer.test.tsx delete mode 100644 apps/desktop/src/features/score/ScoreViewer.tsx delete mode 100644 apps/desktop/src/features/score/pdfjs.ts delete mode 100644 apps/desktop/src/features/score/scoreStorage.test.ts delete mode 100644 apps/desktop/src/features/score/scoreStorage.ts delete mode 100755 scripts/release/build_tauri_bundle_with_retry.sh delete mode 100644 services/analysis-engine/src/bandscope_analysis/chords/function_analyzer.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/chords/key_detector.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/chords/section_harmony.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/chords/transposition.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/exports/__init__.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/exports/chart.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/ranges/pressure.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/roles/articulation.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/roles/overlap.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/temporal/groove.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/temporal/hits.py delete mode 100644 services/analysis-engine/src/bandscope_analysis/temporal/stability.py delete mode 100644 services/analysis-engine/tests/test_articulation.py delete mode 100644 services/analysis-engine/tests/test_chart_export.py delete mode 100644 services/analysis-engine/tests/test_function_analyzer.py delete mode 100644 services/analysis-engine/tests/test_groove.py delete mode 100644 services/analysis-engine/tests/test_hits.py delete mode 100644 services/analysis-engine/tests/test_key_detector.py delete mode 100644 services/analysis-engine/tests/test_range_pressure.py delete mode 100644 services/analysis-engine/tests/test_register_overlap.py delete mode 100644 services/analysis-engine/tests/test_section_harmony.py delete mode 100644 services/analysis-engine/tests/test_tempo_stability.py delete mode 100644 services/analysis-engine/tests/test_transposition.py diff --git a/.Jules/palette.md b/.Jules/palette.md index 5c1c16989..8eaf4a5ff 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -30,10 +30,6 @@ **Learning:** When native disabled buttons are wrapped in a focusable `span` to provide accessible tooltips, tests that previously found and clicked the `button` (by temporarily removing the `disabled` attribute) may fail or become overly complex. It is cleaner and more accurate to query the wrapper element (e.g. via its `title`) and fire events on it, reflecting the actual accessible DOM structure. **Action:** When testing UI components that wrap disabled buttons in a focusable span for accessibility (e.g., using a tooltip/title), use `screen.getByTitle(...)` to query the wrapper element for interactions like `fireEvent.click` rather than `screen.getByRole('button')`. -## 2024-05-24 - Avoid nesting native buttons with ARIA role button on wrappers -**Learning:** Adding `role="button"` to a `span` or `div` wrapper that contains a native ` - ); - })} +

- {t("localFirstDetail")} + Your rehearsal map stays on this device. Project files stay local. YouTube only leaves the app when you choose import.

- - + + Settings coming soon + + + + Help coming soon + +
-
- -
); } diff --git a/apps/desktop/src/components/ui/accordion.tsx b/apps/desktop/src/components/ui/accordion.tsx deleted file mode 100644 index 752e33a09..000000000 --- a/apps/desktop/src/components/ui/accordion.tsx +++ /dev/null @@ -1,76 +0,0 @@ -"use client" - -import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion" -import { ChevronDown } from "lucide-react" - -import { cn } from "@/lib/utils" - -/** Render a vertically stacked set of collapsible sections. */ -function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) { - return ( - - ) -} - -/** Render one collapsible accordion item. */ -function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) { - return ( - - ) -} - -/** Render the clickable header that toggles an item open or closed. */ -function AccordionTrigger({ - className, - children, - ...props -}: AccordionPrimitive.Trigger.Props) { - return ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - - ) -} - -/** Render the collapsible content panel of an item. */ -function AccordionContent({ - className, - children, - ...props -}: AccordionPrimitive.Panel.Props) { - return ( - -
{children}
-
- ) -} - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/apps/desktop/src/components/ui/breadcrumb.tsx b/apps/desktop/src/components/ui/breadcrumb.tsx deleted file mode 100644 index 760612931..000000000 --- a/apps/desktop/src/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import * as React from "react" -import { ChevronRight, MoreHorizontal } from "lucide-react" - -import { cn } from "@/lib/utils" - -/** Render the breadcrumb navigation landmark. */ -function Breadcrumb(props: React.ComponentProps<"nav">) { - return