Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@
## 2024-05-24 - Memoizing inline array maps
**Learning:** Inline mapping of arrays inside JSX in large React components causes O(N) recalculation on every render.
**Action:** Wrap inline JSX elements that map over arrays (e.g., lists of tasks) in a `useMemo` hook with specific dependencies.

## 2025-02-12 - Avoided unused setdefault list allocations in grouping loops

**Learning:** `dict.setdefault(key, []).append(value)` evaluates the empty-list default on every iteration, including when the key already exists. In grouping loops, `defaultdict(list)` avoids those transient unused list allocations while preserving insertion order.
**Action:** Use `defaultdict(list)` when missing keys are intentionally initialized with lists. Keep `setdefault` when its eager-default behavior or an ordinary `dict` is part of the required contract, and benchmark before claiming a material end-to-end improvement.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

### 코드 건강성 개선 (Code Health)

- 백엔드 그룹화 루프에 `defaultdict(list)`를 적용해 기존 순서와 응답을 보존하면서 `setdefault`가 매 반복마다 만들던 미사용 빈 리스트 할당을 피했습니다.
- `WorkspaceHome`의 작업 완료 토글과 Reply SLA 팔로업 생성 로직을 `useTasks` hook으로 분리하고, 화면 쪽 formatter를 주입해 작업 제목 정규화 로직 중복을 방지했습니다.
- `backend/api/security.py`에서 사용하지 않는 `from __future__ import annotations` 구문을 제거하고 조건 표현식을 정리했습니다.
- `backend/alembic/env.py`에서 사용하지 않는 `from __future__ import annotations` 구문을 제거해 Alembic 환경 설정 코드를 간결하게 정리했습니다.
Expand Down
13 changes: 7 additions & 6 deletions backend/api/data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import base64
import binascii
from collections import defaultdict
from datetime import datetime, timezone
import hashlib
import json
Expand Down Expand Up @@ -1695,14 +1696,14 @@ def _diligence_risk_matrix(
groups: dict[
tuple[RemediationPriority, str, str],
list[DataDiligenceExceptionRegisterEntry],
] = {}
] = defaultdict(list)
for exception in snapshot.diligence_exception_register:
key = (
exception.severity_code,
exception.owner_area,
exception.related_artifact,
)
groups.setdefault(key, []).append(exception)
groups[key].append(exception)

entries: list[DataDiligenceRiskMatrixEntry] = []
for (severity, owner_area, related_artifact), exceptions in sorted(
Expand Down Expand Up @@ -1844,9 +1845,9 @@ def _diligence_close_decision_summary(
def _diligence_close_artifact_review_queue(
snapshot: DataEvidenceSnapshotResponse,
) -> list[DataDiligenceCloseArtifactReviewQueueEntry]:
groups: dict[str, list[DataDiligenceCloseProofPlanEntry]] = {}
groups: dict[str, list[DataDiligenceCloseProofPlanEntry]] = defaultdict(list)
for proof in snapshot.diligence_close_proof_plan:
groups.setdefault(proof.required_proof_artifact, []).append(proof)
groups[proof.required_proof_artifact].append(proof)

entries: list[DataDiligenceCloseArtifactReviewQueueEntry] = []
for artifact, proofs in sorted(groups.items()):
Expand Down Expand Up @@ -1889,9 +1890,9 @@ def _diligence_close_artifact_review_queue(
def _diligence_close_owner_handoff_queue(
snapshot: DataEvidenceSnapshotResponse,
) -> list[DataDiligenceCloseOwnerHandoffQueueEntry]:
groups: dict[str, list[DataDiligenceCloseProofPlanEntry]] = {}
groups: dict[str, list[DataDiligenceCloseProofPlanEntry]] = defaultdict(list)
for proof in snapshot.diligence_close_proof_plan:
groups.setdefault(proof.owner_area, []).append(proof)
groups[proof.owner_area].append(proof)

entries: list[DataDiligenceCloseOwnerHandoffQueueEntry] = []
for owner_area, proofs in sorted(groups.items()):
Expand Down
10 changes: 5 additions & 5 deletions backend/services/email_import_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import datetime
from collections import defaultdict
from email import policy as email_policy
import hashlib
import logging
Expand Down Expand Up @@ -575,7 +576,7 @@ def add_edge(
segments_by_source: dict[
tuple[str, str],
list[ContentSegmentRecord],
] = {}
] = defaultdict(list)
for segment in sorted(
email_obj.content_segments,
key=lambda item: (
Expand All @@ -585,10 +586,9 @@ def add_edge(
item.segment_path,
),
):
segments_by_source.setdefault(
(segment.source_kind, segment.source_record_uid),
[],
).append(segment)
segments_by_source[
(segment.source_kind, segment.source_record_uid)
].append(segment)
add_edge(
edge_kind="node_has_segment",
edge_path=f"{segment.content_node.node_path}/has/{segment.segment_path}",
Expand Down
14 changes: 8 additions & 6 deletions backend/services/project_graph/project_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import datetime
import hashlib
from collections import Counter
from collections import Counter, defaultdict
from dataclasses import dataclass
from typing import Any, Iterable, Mapping

Expand Down Expand Up @@ -612,9 +612,9 @@ def _candidate_groups(
*,
scope: ProjectGraphQueryScope,
) -> tuple[_CandidateGroup, ...]:
records_by_email: dict[int, list[ProjectGraphObjectRecord]] = {}
records_by_email: dict[int, list[ProjectGraphObjectRecord]] = defaultdict(list)
for record in records:
records_by_email.setdefault(record.email_id, []).append(record)
records_by_email[record.email_id].append(record)

groups: list[_CandidateGroup] = []
for group_records in records_by_email.values():
Expand All @@ -632,7 +632,9 @@ def _candidate_groups(
if explicit_candidate is not None
else _synthetic_project_uid(group_records, scope=scope)
)
groups.append(_CandidateGroup(project_uid=project_uid, records=tuple(group_records)))
groups.append(
_CandidateGroup(project_uid=project_uid, records=tuple(group_records))
)
return tuple(groups)


Expand Down Expand Up @@ -842,9 +844,9 @@ def _relation_summary(
``relation_count`` descending with a ``relation_type``-ascending tie-break so
the result is deterministic regardless of relation iteration order.
"""
grouped: dict[str, list[ProjectTraceRelation]] = {}
grouped: dict[str, list[ProjectTraceRelation]] = defaultdict(list)
for relation in relations:
grouped.setdefault(relation.relation_type, []).append(relation)
grouped[relation.relation_type].append(relation)
type_summaries = [
ProjectRelationTypeSummary(
relation_type=relation_type,
Expand Down
Loading