From df19a04dee7a60fce1f006bd64bcc341ebcdeda7 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 7 Sep 2026 04:07:25 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20O(N)=20=EB=B0=B0=EC=97=B4?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=EC=9D=84=20O(1)=20=EB=94=95=EC=85=94?= =?UTF-8?q?=EB=84=88=EB=A6=AC=20=ED=82=A4=20=EC=A1=B0=ED=9A=8C=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4?= 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 | 39 +++++++++++-------- .../tests/test_supply_chain_policy.py | 4 +- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10fc..3ac6575e4 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. +## 2026-09-07 - O(N) Array membership tests in tight loops +**Learning:** Checking for element membership within an array (`if item not in list: list.append(item)`) inside nested loops results in O(N^2) time complexity. +**Action:** Use an ordered dictionary (dict keys guarantee insertion order since Python 3.7) to keep track of elements (e.g. `d[item] = None`) and deduplicate keys with O(1) lookups, providing algorithmic performance improvements on large arrays while preserving order. diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 3a84b59c8..8e6bcd7f2 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -78,14 +78,16 @@ 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] = [] + # ⚡ Bolt: Used dictionary keys (O(1) lookup) instead of list 'in' operator (O(N)) + # for deduplication performance while preserving insertion order. + 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 +123,29 @@ 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] = [] + # ⚡ Bolt: Used dictionary keys (O(1) lookup) instead of list 'in' operator (O(N)) + # for deduplication performance while preserving insertion order. + 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] = [] + # ⚡ Bolt: Used dictionary keys (O(1) lookup) instead of list 'in' operator (O(N)) + # for deduplication performance while preserving insertion order. + 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 +194,9 @@ 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] = [] + # ⚡ Bolt: Used dictionary keys (O(1) lookup) instead of list 'in' operator (O(N)) + # for deduplication performance while preserving insertion order. + priorities: dict[str, None] = {} for section in sections: for role in _section_roles(section): name = _role_display_name(role) @@ -196,11 +204,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")