From f52dc9738f48001acf88384a422db206b26bc727 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:00:23 +0000 Subject: [PATCH 1/7] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvem?= =?UTF-8?q?ent]=20Replace=20O(N^2)=20list=20membership=20checks=20with=20O?= =?UTF-8?q?(1)=20dictionary=20key=20deduplication=20in=20chart=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 ++ .../src/bandscope_analysis/exports/chart.py | 31 +++++++++---------- .../tests/test_supply_chain_policy.py | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10fc..c0f9a50a7 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,3 +61,6 @@ ## 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. +## 2025-02-23 - Python O(N²) List Deduplication Anti-Pattern +**Learning:** Checking list membership (`if item not in lst: lst.append(item)`) inside loops creates a hidden O(N²) algorithmic bottleneck because `not in` on a list requires an O(N) scan. This can become a significant performance issue when analyzing songs with many sections or complex cue roles (e.g., in `chart.py` for chart export). +**Action:** When deduplicating strings or primitive items while preserving order in Python 3.7+, use dictionary key assignment (`dict_obj[item] = None`) inside the loop, and return `list(dict_obj.keys())` at the end. This reduces the complexity to O(N) by utilizing O(1) hashing for membership checks, without sacrificing readability. diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 3a84b59c8..9a2a6da40 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -78,14 +78,14 @@ def _active_role_ids(section: Mapping[str, object]) -> list[str] | None: part_graph = section.get("partGraph") if not isinstance(part_graph, list): return None - active: list[str] = [] + active: dict[str, None] = {} for node in part_graph: if not isinstance(node, Mapping) or node.get("is_active") is not True: continue role_id = node.get("role_id") - if isinstance(role_id, str) and role_id and role_id not in active: - active.append(role_id) - return active + if isinstance(role_id, str) and role_id: + active[role_id] = None + return list(active.keys()) def _active_roles(section: Mapping[str, object]) -> list[Mapping[str, object]]: @@ -121,25 +121,25 @@ def _role_display_name(role: Mapping[str, object]) -> str | None: def _active_role_names(section: Mapping[str, object]) -> list[str]: """Return de-duplicated display names for the section's active roles.""" - names: list[str] = [] + names: dict[str, None] = {} for role in _active_roles(section): name = _role_display_name(role) - if name is not None and name not in names: - names.append(name) - return names + if name is not None: + names[name] = None + return list(names.keys()) def _section_cue(section: Mapping[str, object]) -> str: """Join the active roles' cue values into a single cue string.""" - cues: list[str] = [] + cues: dict[str, None] = {} for role in _active_roles(section): cue = role.get("cue") if not isinstance(cue, Mapping): continue value = cue.get("value") - if isinstance(value, str) and value and value not in cues: - cues.append(value) - return "; ".join(cues) + if isinstance(value, str) and value: + cues[value] = None + return "; ".join(cues.keys()) def _confidence_level(section: Mapping[str, object]) -> str | None: @@ -188,7 +188,7 @@ def _section_lines(sections: list[Mapping[str, object]]) -> list[str]: def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object]]) -> list[str]: """Build the footer: per-role rehearsal priorities and the export focus.""" lines: list[str] = [] - priorities: list[str] = [] + priorities: dict[str, None] = {} for section in sections: for role in _section_roles(section): name = _role_display_name(role) @@ -196,11 +196,10 @@ def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object if name is None or not isinstance(priority, str) or not priority: continue entry = f" - {name}: {priority}" - if entry not in priorities: - priorities.append(entry) + priorities[entry] = None if priorities: lines.append("Priorities:") - lines.extend(priorities) + lines.extend(priorities.keys()) summary = song.get("exportSummary") if isinstance(summary, Mapping): headline = summary.get("headline") diff --git a/services/analysis-engine/tests/test_supply_chain_policy.py b/services/analysis-engine/tests/test_supply_chain_policy.py index 1d8224c5a..6a0853944 100644 --- a/services/analysis-engine/tests/test_supply_chain_policy.py +++ b/services/analysis-engine/tests/test_supply_chain_policy.py @@ -1275,9 +1275,7 @@ def test_workflow_concurrency_cancels_only_superseded_pr_heads() -> None: workflow = (workflows_dir / workflow_name).read_text(encoding="utf-8") assert "concurrency:" in workflow, workflow_name assert "cancel-in-progress: false" in workflow, workflow_name - assert "contents: read" in workflow or "permissions: read-all" in workflow, ( - workflow_name - ) + assert "contents: read" in workflow or "permissions: read-all" in workflow, workflow_name assert "pull_request:" not in (workflows_dir / "release.yml").read_text(encoding="utf-8") From 0725eb3ce0d5b416464566422839ff61c17b839e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:05:17 +0900 Subject: [PATCH 2/7] repair(ci): drop superseded chart note from Ruff owner --- .jules/bolt.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index c0f9a50a7..d54cf10fc 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,6 +61,3 @@ ## 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. -## 2025-02-23 - Python O(N²) List Deduplication Anti-Pattern -**Learning:** Checking list membership (`if item not in lst: lst.append(item)`) inside loops creates a hidden O(N²) algorithmic bottleneck because `not in` on a list requires an O(N) scan. This can become a significant performance issue when analyzing songs with many sections or complex cue roles (e.g., in `chart.py` for chart export). -**Action:** When deduplicating strings or primitive items while preserving order in Python 3.7+, use dictionary key assignment (`dict_obj[item] = None`) inside the loop, and return `list(dict_obj.keys())` at the end. This reduces the complexity to O(N) by utilizing O(1) hashing for membership checks, without sacrificing readability. From 1d38e8e62d66ebe6ad14df044cb29ede8e4ea7a6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:05:46 +0900 Subject: [PATCH 3/7] repair(ci): return chart optimization to canonical owner --- .../src/bandscope_analysis/exports/chart.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 9a2a6da40..44e92005b 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -7,7 +7,7 @@ Security Notes: - Pure dict-to-string transformation: no file, network, or process I/O. - Never reads source-path fields and never emits filesystem paths. - - Safe failure: ``None``, empty, or malformed input yields ``""`` / ``[]``; + - Safe failure: ``None``, empty, or malformed input yields ``\"\"`` / ``[]``; missing or malformed keys are skipped and no exceptions escape. """ @@ -78,14 +78,14 @@ def _active_role_ids(section: Mapping[str, object]) -> list[str] | None: part_graph = section.get("partGraph") if not isinstance(part_graph, list): return None - active: dict[str, None] = {} + active: list[str] = [] for node in part_graph: if not isinstance(node, Mapping) or node.get("is_active") is not True: continue role_id = node.get("role_id") - if isinstance(role_id, str) and role_id: - active[role_id] = None - return list(active.keys()) + if isinstance(role_id, str) and role_id and role_id not in active: + active.append(role_id) + return active def _active_roles(section: Mapping[str, object]) -> list[Mapping[str, object]]: @@ -121,25 +121,25 @@ def _role_display_name(role: Mapping[str, object]) -> str | None: def _active_role_names(section: Mapping[str, object]) -> list[str]: """Return de-duplicated display names for the section's active roles.""" - names: dict[str, None] = {} + names: list[str] = [] for role in _active_roles(section): name = _role_display_name(role) - if name is not None: - names[name] = None - return list(names.keys()) + if name is not None and name not in names: + names.append(name) + return names def _section_cue(section: Mapping[str, object]) -> str: """Join the active roles' cue values into a single cue string.""" - cues: dict[str, None] = {} + cues: list[str] = [] for role in _active_roles(section): cue = role.get("cue") if not isinstance(cue, Mapping): continue value = cue.get("value") - if isinstance(value, str) and value: - cues[value] = None - return "; ".join(cues.keys()) + if isinstance(value, str) and value and value not in cues: + cues.append(value) + return "; ".join(cues) def _confidence_level(section: Mapping[str, object]) -> str | None: @@ -188,7 +188,7 @@ def _section_lines(sections: list[Mapping[str, object]]) -> list[str]: def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object]]) -> list[str]: """Build the footer: per-role rehearsal priorities and the export focus.""" lines: list[str] = [] - priorities: dict[str, None] = {} + priorities: list[str] = [] for section in sections: for role in _section_roles(section): name = _role_display_name(role) @@ -196,10 +196,11 @@ def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object if name is None or not isinstance(priority, str) or not priority: continue entry = f" - {name}: {priority}" - priorities[entry] = None + if entry not in priorities: + priorities.append(entry) if priorities: lines.append("Priorities:") - lines.extend(priorities.keys()) + lines.extend(priorities) summary = song.get("exportSummary") if isinstance(summary, Mapping): headline = summary.get("headline") @@ -215,7 +216,7 @@ def build_chart_text(song: Mapping[str, object] | None) -> str: section (``[mm:ss-mm:ss] LABEL (confidence) roles: ...``), and a footer with rehearsal priorities and the export focus headline. Output is deterministic and never contains filesystem paths. Malformed input - yields ``""``. + yields ``\"\"``. """ if not isinstance(song, Mapping): return "" From a7b0030a3a6cc6296a19ba3f8eaf595d470d05bd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:06:39 +0900 Subject: [PATCH 4/7] repair(ci): restore protected chart bytes exactly --- .../analysis-engine/src/bandscope_analysis/exports/chart.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 44e92005b..3a84b59c8 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -7,7 +7,7 @@ Security Notes: - Pure dict-to-string transformation: no file, network, or process I/O. - Never reads source-path fields and never emits filesystem paths. - - Safe failure: ``None``, empty, or malformed input yields ``\"\"`` / ``[]``; + - Safe failure: ``None``, empty, or malformed input yields ``""`` / ``[]``; missing or malformed keys are skipped and no exceptions escape. """ @@ -216,7 +216,7 @@ def build_chart_text(song: Mapping[str, object] | None) -> str: section (``[mm:ss-mm:ss] LABEL (confidence) roles: ...``), and a footer with rehearsal priorities and the export focus headline. Output is deterministic and never contains filesystem paths. Malformed input - yields ``\"\"``. + yields ``""``. """ if not isinstance(song, Mapping): return "" From 340b0a343ecfc05f630c7da729b8af40c7da4a2c Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 22:47:54 +0000 Subject: [PATCH 5/7] Trigger CI retry From 8488a02a1b36a99c94b3e248e948d754ed446750 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 23:45:35 +0000 Subject: [PATCH 6/7] Trigger CI retry From 8fe6b6d99c009527ef0bcba419e6f6debdb23c23 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:15:16 +0000 Subject: [PATCH 7/7] Trigger CI retry