Development Summary · 2026-05-01

24시간, v3.3.1 → v3.4.2

디자인 검증 → 보고서 파이프라인 통합 → 운영 가시성 → 사용자 제어. 한 흐름의 네 단계가 하루에 메인에 들어갔다.

4
Versions
5
PRs Merged
~1.5K
Lines Added
0
Breaking

시간 순으로 본 네 단계

각 버전은 바로 앞 버전의 결과를 받아 다음 단계를 푼다. 디자인 → 코드 → 운영 → 사용자 — 같은 기능이 네 면을 가진다는 점을 시간이 보여준다.

v3.3.1 PART 1 — DESIGN PROBE

모노 테마 + d3-geo 샘플 — 디자인 검증

What
라이트 모노 / 버건디 모노 두 팔레트에 동일 데이터셋 (동북아·동남아 항만 네트워크 + 16주 처리량) 을 입혀 비교한 단일 페이지. samples/theme_mono_map_chart.html 1 file, 747 lines.
Why
보고서에 지도 블록을 정식 도입하기 전, 실제 톤이 화면에서 어떻게 작동하는지 디자인 검증부터. 코드 리뷰가 아니라 눈으로 검증할 수 있는 살아있는 프로토타입.
How
maplibre-gl 4.7 raster 베이스맵 + CSS 필터로 톤 합성. d3.geoTransform 으로 maplibre map.project() 를 d3-geo path projection 에 위임 — move/resize 이벤트마다 SVG 오버레이가 따라옴. d3.geoInterpolate 64 분할로 great-circle arc.
Outcome
골드 #C9A84C 단일 하이라이트 원칙이 양 테마에서 작동함을 확인. 버건디 베이스 타일은 dark_nolabels 가 너무 어두워 처음에 바다·육지 구분이 안 됐고, voyager_nolabels + brightness 0.78 로 교체해서 해결 — 첫 사용자 피드백 1회로.
v3.4.0 PART 2 — INTEGRATION

map BlockType — 보고서 파이프라인 통합

What
17 → 18종 BlockType. 보고서가 maplibre+d3-geo 지도를 자동 임베드. geopolitical_strategic archetype 의 "전장·행위자" 섹션에 자동 포함, 데이터 없으면 자동 스킵.
Why
디자인 검증된 톤을 분석 결과에 직접 적용. 기존 Leaflet 시각화 (legacy six_act_theater) 는 그대로 보존하면서, 신규 archetype 은 maplibre 길로 일원화. 두 길을 동시에 가져가는 것이 과도기에 가장 안전한 선택.
How
데이터 소스는 기존 visual_analystleaflet_config 재사용 — 분석 흐름 코드 변경 0. build_map_payload() 가 leaflet 의 [lat,lng] 를 maplibre 의 [lng,lat] 로 변환하면서 highlight 룰·legend 자동 생성.
  • src/models.py:BlockType Literal 확장
  • src/templates/blocks/map.html 신설
  • src/templates/static/maps.{js,css} (정적 자산 동기화 대상)
  • src/visual_builder.py:build_map_payload() 변환기
  • src/agents/report_synthesizer.py:_payload_map() + _BLOCK_BUILDERS 등록
  • src/tests/test_map_block.py — 13 케이스
Live
아래는 v3.4.0 에서 도입된 map BlockType 이 실제로 렌더하는 모습. 페이지 안에 직접 임베드.
일반 항로
중점 회랑
관측 노드
v3.4.1 PART 3 — OBSERVABILITY

/status 에 git branch · commit · dirty

What
봇 시작 시점에 git rev-parse --abbrev-ref HEAD / --short=7 HEAD / git log -1 --format=%cd / git status --porcelain 4 호출로 git 상태 한 번 캡처해 BUILD_INFO 에 보관. 시작 로그 + 텔레그램 /status 응답 양쪽에 노출.
Why
실제 운영 중 발생한 디버깅 케이스: "v3.4.0 머지했는데 왜 v3.3.0 이 뜨지?" 원인은 옛 봇 프로세스가 안 죽고 살아있던 것. 디스크의 코드와 실행 중인 코드가 다를 때 가 운영의 가장 흔한 함정. import 시점 1회만 캡처 — pull 후 재기동 안 한 케이스에도 BUILD_INFO 는 *실행 중인* 커밋을 가리키므로 미스매치를 즉시 인지.
출력 예시
# /status 응답
✅ 봇 실행 중 — v3.4.1

  브랜치: main
  커밋: 181a620 (2026-05-01 15:33)  ⚠️ uncommitted
  가동시간: 0시간 5분
  ...
Outcome
/statusverifiable. 운영자가 더 이상 어느 버전이 도는지 헷갈리지 않음. 비-git 환경 / repo 외부에서는 모두 "?" 로 graceful degrade.
v3.4.2 PART 4 — USER CONTROL

/stop · /stopall — 진행 중 분석 중단

What
두 명령으로 분석 흐름을 사용자가 직접 제어:
  • /stop — 진행 중 1건만 cancel. 큐는 보존 (다음 건 자동 진행)
  • /stopall — 진행 중 cancel + 큐 전체 비움
Why
잘못 보낸 분석 요청을 무력하게 끝까지 기다릴 필요 없다. Claude API 호출 비용도, 사용자 시간도 절약. 두 명령으로 분리한 이유는 "지금 이거 잘못 보냈다" 와 "전부 다 취소하고 싶다" 는 다른 문제 이기 때문.
How
_run_analysis 시작 시점에 self._current_task = asyncio.current_task() 캡처. 핸들러는 그 task 의 cancel() 호출 → CancelledError 가 위로 전파. Python 3.8+ 부터 CancelledErrorBaseException 상속 → orchestrator/agent 의 except Exception: 블록을 통과해서 _run_analysis 의 전용 except CancelledError 까지 도달, 사용자 알림 후 re-raise.
취소 시그널 전파 경로
/stop handler
   └─ self._current_task.cancel()
       └─ raises CancelledError into _run_analysis()
           └─ propagates up through await orchestrator.run_analysis()
               └─ propagates up through await agent.run() (LLM call)
                   └─ subprocess.terminate() # Claude CLI gets SIGTERM
                       └─ finally: cleanup + reply "🛑 분석 중단됨"

map BlockType 데이터 흐름

v3.4.0 의 map 블록이 어떻게 분석 흐름에 끼워 들어갔는지. 회색 부분은 기존 코드, 골드 부분은 v3.4.0 신규.

visual_analyst LLM (deep mode) leaflet_config [lat,lng] markers + lines six_act_theater 만 report.html Leaflet (legacy 보존) build_map_payload() [lng,lat] + highlight 룰 v3.4.0 신규 map BlockType blocks/map.html maps.js maplibre-gl + d3-geo v3.4.0 geopolitical_strategic archetype "전장·행위자" + map block_types 선두 추가 기존 v3.4.0 신규

v3.4 의 윤곽

적당히 측정 가능한 것들. 의도된 것보다는 작게, 의도하지 않은 것보다는 크게.

5
PRs (#2~#5) main 머지
4
신규 버전 (v3.3.1~v3.4.2)
25+
touched files
~1.5K
lines added (net)
13
신규 테스트
0
breaking changes
2
신규 telegram 명령
18
BlockType (17 → 18)
maplibre-gl 4.7 d3-geo v7 d3 v7 python-telegram-bot Pydantic v2 Jinja2 asyncio Claude Code CLI (Max plan) CartoDB raster tiles Cloudflare Pages