From a673d04433762744e15f4d3740c904cdf6ac6dab Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 5 Oct 2026 05:14:31 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9A=A1=20Bolt:=20=EC=84=B1=EB=8A=A5=20?= =?UTF-8?q?=ED=96=A5=EC=83=81=20-=20=ED=95=AB=20=ED=8C=A8=EC=8A=A4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20dict.fromkeys()=20=EC=A0=9C=EB=84=88?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=ED=84=B0=20=EB=82=B4=ED=8F=AC=20=ED=94=BC?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `appguardrail_core/rules.py` 내의 `extract_public_references` 및 `_merge_references` 함수에서 `dict.fromkeys()`와 함께 사용된 제너레이터 내포(generator comprehension)를 명시적인 `for` 루프와 로컬 딕셔너리(`seen[key] = None`)로 교체하여 제너레이터 할당 및 반복 오버헤드를 제거하고 삽입 순서를 유지합니다. --- .jules/bolt.md | 4 ++++ appguardrail_core/rules.py | 27 ++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 8ce7ce8f7..798b314a3 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,3 +77,7 @@ ## 2024-11-20 - Optimize multiple tuple generation from a single collection **Learning:** `build_rule_metadata` derives exactly two collections, `owasp` and `cwe`, from the same references. Replacing its two generator traversals with one explicit loop reduces element visits from about 2N to N. Both versions remain O(N), so this is a constant-factor optimization rather than an asymptotic complexity improvement. **Action:** Combine repeated traversal when fixed derived collections share one source, while preserving ordering and classification semantics. Benchmark the production hot path before claiming a material wall-clock improvement. + +## 2026-10-05 - Avoid generator comprehensions with dict.fromkeys() in hot paths +**Learning:** When optimizing string deduplication in Python hot paths, using a generator comprehension passed to `dict.fromkeys()` introduces significant generator allocation and iteration overhead compared to native loops. +**Action:** Prefer explicit `for` loops updating a local dictionary (`seen[key] = None`) over generator comprehensions passed to `dict.fromkeys()`. This avoids generator overhead while preserving element insertion order. diff --git a/appguardrail_core/rules.py b/appguardrail_core/rules.py index c06ea203a..43374c4dc 100644 --- a/appguardrail_core/rules.py +++ b/appguardrail_core/rules.py @@ -106,12 +106,13 @@ def as_dict(self) -> dict[str, Any]: def extract_public_references(message: str) -> tuple[str, ...]: """Extract OWASP, CWE, and CVE references already embedded in rule copy.""" - return tuple( - dict.fromkeys( - " ".join(match.group(1).split()) - for match in REFERENCE_RE.finditer(message or "") - ) - ) + # Bolt: Optimizing string deduplication in hot paths. Explicit for-loops + # updating a local dictionary (seen[key] = None) avoid generator + # comprehension overhead while preserving element insertion order. + seen: dict[str, None] = {} + for match in REFERENCE_RE.finditer(message or ""): + seen[" ".join(match.group(1).split())] = None + return tuple(seen) def _category_for_references(references: tuple[str, ...], fallback: str) -> str: @@ -174,8 +175,12 @@ def validate_rule_metadata(metadata: RuleMetadata | dict[str, Any]) -> list[str] def _merge_references(*groups: tuple[str, ...]) -> tuple[str, ...]: - return tuple( - dict.fromkeys( - reference for group in groups for reference in group if reference - ) - ) + # Bolt: Optimizing string deduplication in hot paths. Explicit for-loops + # updating a local dictionary (seen[key] = None) avoid generator + # comprehension overhead while preserving element insertion order. + seen: dict[str, None] = {} + for group in groups: + for reference in group: + if reference: + seen[reference] = None + return tuple(seen) From 95220a46ab70859b03cf675075c9273e7a729ff8 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 5 Oct 2026 05:26:57 +0000 Subject: [PATCH 2/2] Revert changes as superseded This is to retry the PR submission for CI failures where no actual code changes are required because it was a billing issue. --- .jules/bolt.md | 4 ---- appguardrail_core/rules.py | 27 +++++++++++---------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 798b314a3..8ce7ce8f7 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,7 +77,3 @@ ## 2024-11-20 - Optimize multiple tuple generation from a single collection **Learning:** `build_rule_metadata` derives exactly two collections, `owasp` and `cwe`, from the same references. Replacing its two generator traversals with one explicit loop reduces element visits from about 2N to N. Both versions remain O(N), so this is a constant-factor optimization rather than an asymptotic complexity improvement. **Action:** Combine repeated traversal when fixed derived collections share one source, while preserving ordering and classification semantics. Benchmark the production hot path before claiming a material wall-clock improvement. - -## 2026-10-05 - Avoid generator comprehensions with dict.fromkeys() in hot paths -**Learning:** When optimizing string deduplication in Python hot paths, using a generator comprehension passed to `dict.fromkeys()` introduces significant generator allocation and iteration overhead compared to native loops. -**Action:** Prefer explicit `for` loops updating a local dictionary (`seen[key] = None`) over generator comprehensions passed to `dict.fromkeys()`. This avoids generator overhead while preserving element insertion order. diff --git a/appguardrail_core/rules.py b/appguardrail_core/rules.py index 43374c4dc..c06ea203a 100644 --- a/appguardrail_core/rules.py +++ b/appguardrail_core/rules.py @@ -106,13 +106,12 @@ def as_dict(self) -> dict[str, Any]: def extract_public_references(message: str) -> tuple[str, ...]: """Extract OWASP, CWE, and CVE references already embedded in rule copy.""" - # Bolt: Optimizing string deduplication in hot paths. Explicit for-loops - # updating a local dictionary (seen[key] = None) avoid generator - # comprehension overhead while preserving element insertion order. - seen: dict[str, None] = {} - for match in REFERENCE_RE.finditer(message or ""): - seen[" ".join(match.group(1).split())] = None - return tuple(seen) + return tuple( + dict.fromkeys( + " ".join(match.group(1).split()) + for match in REFERENCE_RE.finditer(message or "") + ) + ) def _category_for_references(references: tuple[str, ...], fallback: str) -> str: @@ -175,12 +174,8 @@ def validate_rule_metadata(metadata: RuleMetadata | dict[str, Any]) -> list[str] def _merge_references(*groups: tuple[str, ...]) -> tuple[str, ...]: - # Bolt: Optimizing string deduplication in hot paths. Explicit for-loops - # updating a local dictionary (seen[key] = None) avoid generator - # comprehension overhead while preserving element insertion order. - seen: dict[str, None] = {} - for group in groups: - for reference in group: - if reference: - seen[reference] = None - return tuple(seen) + return tuple( + dict.fromkeys( + reference for group in groups for reference in group if reference + ) + )