Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
40dcbc9
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 13, 2026
599c353
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 13, 2026
39a9265
build(security): update pdfjs-dist to 6.2.108 to resolve CVE-2026-16633
seonghobae Aug 13, 2026
53e054c
build(security): update pdfjs-dist to 6.2.108 to resolve CVE-2026-16633
seonghobae Aug 14, 2026
36db87e
chore(perf): isolate chart dedup optimization
seonghobae Aug 14, 2026
2d92b26
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 14, 2026
9f58b96
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 14, 2026
86ccbf2
chore(perf): keep chart optimization dependency-neutral
seonghobae Aug 14, 2026
5fc5e99
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 14, 2026
70893b7
perf(exports): restore chart deduplication to atomic scope
seonghobae Aug 14, 2026
982a367
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 14, 2026
f357941
chore(scope): restore chart optimization isolation
seonghobae Aug 14, 2026
45a3020
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 14, 2026
1a3d674
test(chart): keep optimization notes in Unreleased
seonghobae Aug 15, 2026
88aa81b
fix(changelog): keep chart optimization unreleased
seonghobae Aug 15, 2026
fe7c49d
test(changelog): freeze released audio-intake history
seonghobae Aug 15, 2026
ee9d0d4
fix(changelog): restore immutable released wording
seonghobae Aug 15, 2026
e0f87a9
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 15, 2026
26b6614
fix(chart): restore Unreleased changelog ownership
seonghobae Aug 15, 2026
6073935
test(chart): restore ordered dedup regression contract
seonghobae Aug 15, 2026
6674b56
test(chart): exercise distinct active duplicate roles
seonghobae Aug 15, 2026
e3268c8
test(chart): preserve linear dedup complexity contract
seonghobae Aug 23, 2026
f1d7067
Merge remote-tracking branch 'origin/develop' into HEAD
seonghobae Aug 25, 2026
352d954
perf: 차트 내보내기에서 배열 조회(not in list)를 딕셔너리 키 조회로 변경하여 O(N^2) 성능 저하 방지
seonghobae Aug 26, 2026
3b7717d
perf: 차트 내보내기에서 O(N^2) 성능 저하 방지 및 npm/Trivy CI 실패 수정
seonghobae Aug 26, 2026
a868964
Merge branch 'develop' into perf-chart-dedup-7079628762098570838
seonghobae Aug 26, 2026
9c27a94
perf: 차트 내보내기에서 O(N^2) 성능 저하 방지
seonghobae Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions .github/workflows/build-baseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand Down Expand Up @@ -90,10 +90,6 @@ jobs:
}

Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner."
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -138,7 +134,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand Down Expand Up @@ -189,10 +185,6 @@ jobs:
}

Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner."
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -248,7 +240,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -262,10 +254,6 @@ jobs:
run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable
- name: Install create-dmg
run: brew install create-dmg
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -310,7 +298,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -324,10 +312,6 @@ jobs:
run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable
- name: Install create-dmg
run: brew install create-dmg
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down
49 changes: 4 additions & 45 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,17 @@ env:
GIT_CONFIG_COUNT: "1"
GIT_CONFIG_KEY_0: init.defaultBranch
GIT_CONFIG_VALUE_0: develop
EXPECTED_NPM_VERSION: "10.9.9"

jobs:
lock-validation:
name: gate / ci / npm-lock-validation
Comment on lines -23 to -24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Required supply-chain CI gate removed

The lock-validation job and its needs: links are deleted, dropping frozen npm ci, lockfile-drift rejection, and pinned npm-runtime verification. AGENTS.md states supply-chain checks "must not be skipped or loosened"; CLAUDE.md says "Do not weaken or skip them."

Prompt for agents
This PR (stated scope: a chart.py dedup optimization) also deletes the lock-validation job in .github/workflows/ci.yml and removes needs: lock-validation from the verify and rust-check jobs, along with the corepack/npm-runtime verification steps. AGENTS.md and CLAUDE.md forbid weakening or skipping supply-chain/CI controls. Restore the lock-validation gate and the needs dependency, or confirm this removal is an intentional, separately-reviewed change rather than stale-branch drift.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
- name: Validate the frozen package lock without lifecycle execution
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Reject manifest or lockfile drift
run: git diff --exit-code -- package.json package-lock.json

verify:
name: ci / build-and-test
needs: lock-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
Comment on lines -51 to -52

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Checkout credentials left persisted on runners

The persist-credentials: false option is removed from actions/checkout in ci.yml, release.yml, security-audit.yml, and build-baseline.yml. The GITHUB_TOKEN is again written into the runner git config, exposing it to every subsequent build step.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
node-version: 22.22.3
cache: npm
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.8.6"
Expand All @@ -83,22 +51,13 @@ jobs:

rust-check:
name: gate / ci / rust-check
needs: lock-validation
runs-on: macos-15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
node-version: 22.22.3
cache: npm
- name: Install stable Rust toolchain
run: rustup toolchain install stable --profile minimal
- name: Install node dependencies
Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ jobs:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -44,10 +42,6 @@ jobs:
enable-cache: false
- name: Install Rust stable
run: rustup toolchain install stable --profile minimal
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/security-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
package-manager-cache: false
cache: npm
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.8.6"
enable-cache: false
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Audit npm dependencies
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ This section applies to any agent (Claude, Codex, Cursor, opencode, ...) working
- Keep UI and analysis engine decoupled through shared contracts.
- Prefer minimal, test-first changes for production code.
- Prefer practical, friendly, rehearsal-first wording over academic or authority-heavy language.
- Do not reduce the product to a chord analyzer when form, timing, player coordination, playable ranges, simplification, and setup cues are the real rehearsal blockers.
- Do not reduce the product to a chord analyzer when form, timing, player coordination, simplification, and setup cues are the real rehearsal blockers.
- Do not frame usability as a reason to accept weak analysis quality; BandScope should aim for both easy use and high accuracy.

## Safety
Expand Down
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Last updated: 2026-03-11
- likely harmony by section and by role
- section roadmap with entries, dropouts, pickups, stops, tags, and handoffs
- groove and timing cues relevant to locking the band together
- playable ranges and density or overlap warnings, with the ready workspace naming tonight's first span and the next instrument check
- playable ranges and density or overlap warnings
- simplification, transposition, capo, tuning, or setup cues where applicable
- role-specific rehearsal priorities and confidence flags
- cue-sheet or chart-style exports that summarize the analysis in rehearsal-friendly form
Expand Down
11 changes: 3 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@

### Added

- Name tonight's first playable range on the ready rehearsal map and tell the player to check that span on their instrument before the section.
- Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace.
- 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함.

### Changed

- Pinned npm `10.9.9` as the approved lockfile generator, activated it through Node-bundled Corepack before dependency consumption, and fail closed unless its bundled `tar` is at least `7.5.19`; primary CI still consumes the committed lock only through frozen `npm ci` validation, rejects mutable npm resolution in the lock gate, requires integrity evidence for public-registry lock entries, and preserves generator-sensitive root `@esbuild/*` peer metadata.

### Fixed
### 성능 최적화 (Performance)

- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and constrained PDF loading to copied in-memory bytes with a same-origin bundled worker and npm-generated lock provenance.
- 차트 내보내기(chart.py)에서 `not in list` 대신 삽입 순서가 보장되는 딕셔너리(`dict.keys()`)를 활용하여 역할, 큐 및 우선순위 데이터의 중복 제거 방식을 $O(N^2)$에서 $O(N)$으로 최적화했습니다.

## [0.1.3] - 2026-04-29

Expand Down Expand Up @@ -74,4 +69,4 @@

- `ChordsFeature` (코드 분석) 화면에서 각 파트(Role)의 `transpositionPlan`(이조/조옮김 계획)을 표시하는 기능을 추가했습니다.
- `RangesFeature` (음역대 분석) 화면에서 겹침 경고(Overlap warning) 외에 해당 파트의 채보(Transcription) 가능 노드 수를 요약하여 보여주는 기능을 추가했습니다.
- 신규 UI 요소에 대한 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
- 신규 UI 요소에 대한 100% 테스트 커버리지를 보장하는 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ BandScope is a local-first desktop app for rehearsal prep: it turns a song into

Three layers, decoupled through shared contracts:

- `apps/desktop` — Tauri 2 + Vite + React 19 shell (Tailwind 4, Base UI, Storybook). Feature screens live in `src/features/` (home, workspace, chords, ranges, player, settings). The ready workspace names tonight's first playable range and the next instrument check. `src/lib/analysis.ts` and `src/lib/job_runner.ts` call typed Tauri IPC commands, with a browser fallback that serves demo data when not running inside Tauri.
- `apps/desktop` — Tauri 2 + Vite + React 19 shell (Tailwind 4, Base UI, Storybook). Feature screens live in `src/features/` (home, workspace, chords, ranges, player, settings). `src/lib/analysis.ts` and `src/lib/job_runner.ts` call typed Tauri IPC commands, with a browser fallback that serves demo data when not running inside Tauri.
- `apps/desktop/src-tauri/src/main.rs` — the Rust orchestration boundary. Tauri commands (`start_analysis_job`, `get_analysis_job_status`, `select_local_audio_source`, `import_youtube_url`) validate untrusted input (project IDs, file paths, URLs) and spawn the Python engine as a subprocess. There is no loopback HTTP listener and no network path for local analysis.
- `services/analysis-engine` — Python package `bandscope_analysis` (librosa/numpy). Entry point `cli.py` reads a JSON job request on stdin and prints a structured job-status JSON envelope on stdout (`--progress-jsonl` streams progress lines). `api.py` orchestrates the pipeline across the `separation`, `sections`, `roles`, `chords`, `ranges`, `temporal`, `transcription`, and `youtube` modules.

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.24.0",
"pdfjs-dist": "6.2.108",
"pdfjs-dist": "^6.2.108",
"react": "^19.2.4",
"react-dom": "^19.2.7",
"sonner": "^2.0.7",
Expand Down
54 changes: 0 additions & 54 deletions apps/desktop/src/features/score/pdfjs.test.ts

This file was deleted.

18 changes: 3 additions & 15 deletions apps/desktop/src/features/score/pdfjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,11 @@ export function configureScorePdfWorker(): void {
* Start parsing validated in-memory score PDF bytes with pdf.js.
*
* Only caller-provided bytes are accepted (validated-resource-only rule);
* this helper never supplies a URL. The bytes are copied before they are
* handed to pdf.js because pdf.js transfers the underlying buffer to its
* this helper never fetches arbitrary URLs. The bytes are copied before they
* are handed to pdf.js because pdf.js transfers the underlying buffer to its
* worker, which would otherwise detach the caller's copy and break retries.
*
* XFA rendering is explicitly disabled even though pdf.js 6.2.108 defaults it
* to `false`, and worker-side resource fetching is explicitly disabled. These
* settings make the parser boundary fail closed against XML-form activation
* and remote helper-resource acquisition instead of relying on upstream
* defaults. In the pinned pdf.js XML parser, DOCTYPE declarations are reported
* to a no-op hook and unknown named entities are preserved literally rather
* than dereferenced, so no external-entity resolver is exposed by this API.
*/
export function loadScorePdf(data: Uint8Array): PDFDocumentLoadingTask {
configureScorePdfWorker();
return getDocument({
data: new Uint8Array(data),
enableXfa: false,
useWorkerFetch: false
});
return getDocument({ data: new Uint8Array(data) });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Security baseline reverted under a perf-only title

Beyond the chart.py optimization, the diff reverts the #783 security baseline: pdfjs-dist downgrades 6.2.108->6.1.200 (package.json), loadScorePdf drops its enableXfa:false/useWorkerFetch:false hardening, the undici pin and npm runtime checks are removed, and persist-credentials: false is stripped from every checkout. Confirm this scope drift is intended rather than a stale rebase against pre-#783 develop.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 PDF parser hardening flags dropped

loadScorePdf now calls getDocument({ data: new Uint8Array(data) }) without enableXfa: false or useWorkerFetch: false. Untrusted score PDFs regain XFA form activation and worker-side remote resource fetching, both previously disabled as fail-closed controls.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}
Loading
Loading