Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 - 제너레이터 대신 컴프리헨션 사용 최적화
**Learning:** Python에서 tuple()이나 dict.fromkeys()에 제너레이터를 전달하면 오버헤드가 크므로, 리스트나 딕셔너리 컴프리헨션을 사용하여 C 속도로 처리해야 한다.
**Action:** Hot path에서는 제너레이터 대신 [ ]나 { }로 감싼 컴프리헨션을 tuple() 생성자 등에 전달한다.
Comment on lines +82 to +83

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Performance claim lacks a representative benchmark

The 30–40% speedup claim has no measurement here. Dict comprehensions still evaluate each reference in Python; benchmark typical rule messages before treating this transformation as general performance guidance.

Devin Review


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

4 changes: 2 additions & 2 deletions appguardrail_core/findings.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ def normalize_findings(
snippet_max_len: int = 400,
) -> tuple[dict[str, Any], ...]:
"""Normalize a finding collection into a stable tuple."""
return tuple(
return tuple([
normalize_finding(finding, snippet_max_len=snippet_max_len)
for finding in findings
)
])
Comment on lines +109 to +112

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Normalization duplicates the result container

For large scan batches, normalize_findings holds a complete list while tuple copies its entries. The previous generator avoided that intermediate container; benchmark memory and elapsed time with representative findings.

Devin Review


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



def severity_counts(findings: Iterable[dict[str, Any]]) -> dict[str, int]:
Expand Down
19 changes: 8 additions & 11 deletions appguardrail_core/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "")
)
)
return tuple({
" ".join(match.group(1).split()): None
for match in REFERENCE_RE.finditer(message or "")
})


def _category_for_references(references: tuple[str, ...], fallback: str) -> str:
Expand Down Expand Up @@ -174,8 +172,7 @@ 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
)
)
return tuple({
reference: None
for group in groups for reference in group if reference
})
Loading