From 4bb08152b9424af07ebbafe490627d9d95213dad Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 1 Sep 2026 04:58:31 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94:=20`dict.fromke?= =?UTF-8?q?ys(generator)`=EB=A5=BC=20=EB=AA=85=EC=8B=9C=EC=A0=81=20?= =?UTF-8?q?=EB=94=95=EC=85=94=EB=84=88=EB=A6=AC=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=ED=95=98=EC=97=AC=20=EC=A0=9C=EB=84=88=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=98=A4=EB=B2=84=ED=97=A4=EB=93=9C=20?= =?UTF-8?q?=EA=B0=90=EC=86=8C?= 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)`를 명시적인 `for` 루프와 딕셔너리(`seen = {}`)로 교체했습니다. 이를 통해 제너레이터 프레임 할당 오버헤드를 줄이면서도 순서가 보장되는 중복 제거 동작을 유지합니다. --- .jules/bolt.md | 4 ++++ appguardrail_core/rules.py | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 8ce7ce8f..69f2ffb1 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. + +## 2024-11-20 - Reduce dict.fromkeys generator overhead +**Learning:** Using `dict.fromkeys()` with generator expressions incurs significant generator overhead and frame allocation in hot paths compared to explicit loops building a dictionary (`seen = {}`). +**Action:** Replace `dict.fromkeys(item for ...)` with explicit loops and dictionary assignments (`seen[item] = None`) when deduplicating items while maintaining order in high-throughput functions. diff --git a/appguardrail_core/rules.py b/appguardrail_core/rules.py index c06ea203..aacab23b 100644 --- a/appguardrail_core/rules.py +++ b/appguardrail_core/rules.py @@ -106,12 +106,10 @@ 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 "") - ) - ) + seen = {} + 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 +172,9 @@ 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 - ) - ) + seen = {} + for group in groups: + for reference in group: + if reference: + seen[reference] = None + return tuple(seen) From 5ce3208ef941d00e0935d4606a15431956ae0c12 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 2 Sep 2026 04:50:20 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94:=20`dict.fromke?= =?UTF-8?q?ys(generator)`=EB=A5=BC=20=EB=AA=85=EC=8B=9C=EC=A0=81=20?= =?UTF-8?q?=EB=94=95=EC=85=94=EB=84=88=EB=A6=AC=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=ED=95=98=EC=97=AC=20=EC=A0=9C=EB=84=88=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=98=A4=EB=B2=84=ED=97=A4=EB=93=9C=20?= =?UTF-8?q?=EA=B0=90=EC=86=8C?= 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)`를 명시적인 `for` 루프와 딕셔너리(`seen = {}`)로 교체했습니다. 이를 통해 제너레이터 프레임 할당 오버헤드를 줄이면서도 순서가 보장되는 중복 제거 동작을 유지합니다.