diff --git a/.jules/bolt.md b/.jules/bolt.md index 8ce7ce8f7..caae7e809 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-12-10 - O(N^2) Performance from list(dict).index(key) +**Learning:** Using `list(dict).index(key)` inside loops introduces significant performance overhead, effectively transforming an O(1) dictionary key check into an O(N^2) bottleneck. This requires creating a new list allocation and scanning it linearly for every loop iteration. +**Action:** When determining the insertion index or position of dictionary keys during list processing, avoid generating lists. Track indices dynamically in a separate companion dictionary mapping the key to its incremental sequence length or insertion order index (e.g. `rule_indices[rule_id] = len(rules)`) for an O(1) constant-time lookup. diff --git a/appguardrail_core/sarif.py b/appguardrail_core/sarif.py index ca4a9fb6b..8f0d9ddd1 100644 --- a/appguardrail_core/sarif.py +++ b/appguardrail_core/sarif.py @@ -39,12 +39,14 @@ def findings_to_sarif( normalized = normalize_findings(findings) rules: dict[str, dict[str, Any]] = {} + rule_indices: dict[str, int] = {} results: list[dict[str, Any]] = [] for f in normalized: rule_id = f["rule_id"] severity = f["severity"] refs = f.get("references") or () if rule_id not in rules: + rule_idx = len(rules) rule: dict[str, Any] = { "id": rule_id, "name": rule_id, @@ -64,11 +66,14 @@ def findings_to_sarif( }, } rules[rule_id] = rule + rule_indices[rule_id] = rule_idx + else: + rule_idx = rule_indices[rule_id] results.append( { "ruleId": rule_id, - "ruleIndex": list(rules).index(rule_id), + "ruleIndex": rule_idx, "level": _LEVEL.get(severity, "note"), "message": {"text": f["message"].strip()}, "locations": [