feat(multi-instance): dcy-009 BAT-013 — RabbitMQ 다중 인스턴스 토폴로지 (REQ-048~051)

dcy-009(다중 인스턴스 RabbitMQ 토폴로지) 전체 SDLC: draft-req → confirm-req →
draft-batch(BAT-013) → run-batch-delivery → confirm-req-implemented.

- REQ-048 (Configuration): DaemonInstanceConfig.from_toml + DaemonConfig.from_config
  (env 병합, portfolio_hub_token 주입) + 데몬 --config 필수 argparse + .gitignore 인스턴스
  TOML + config/instance.example.toml
- REQ-049 (Interface): topology 동적 큐명 빌더 intent/snapshot/control_queue(instance_key)
  — default=리터럴 큐명(하위호환), named=`{base}.{instance_key}` + daemon per-instance 구독
- REQ-050 (Integration): trex.direct(topic)/trex.broadcast(fanout) exchange +
  declare_topology(instance_key) per-instance binding + control dual binding + direct_routing_key
- REQ-051 (Documentation): interface-contract/runtime-flows/project-structure 정합

하위호환: instance_key="default" → 기존 리터럴 큐명·RPC 경로 무회귀(FR-5).
split-brain 방지(NFR-3): 인스턴스 전용 큐. 민감값(NFR-4): TOML + gitignore.

검증: 신규 9 단위 + RabbitMQ 라우팅 2, 단위 271 passed,
인프라 게이트 301 passed(directed 격리 S-2 + broadcast dual S-3 + default 무회귀 S-4),
ruff clean. REQ-048~051 Implemented, BAT-013 release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 15:10:36 +09:00
co-authored by Claude Opus 4.8
parent 7e23648489
commit 9f83c64a40
24 changed files with 1223 additions and 85 deletions
@@ -0,0 +1,48 @@
# BAT-013 Planning
- Status: confirmed
- Batch: BAT-013
- Profile: standard
## Included REQ
- REQ-048 (Configuration): `DaemonInstanceConfig.from_toml` (tomllib) + `--config` 필수 진입점 + `from_config` env 병합(`portfolio_hub_token` 주입) + `.gitignore` TOML + 토큰 로그 미노출.
- REQ-049 (Interface): `topology.py` 동적 큐명 빌더(default=리터럴 하위호환) + `declare_topology(instance_key)` + daemon intent/snapshot/control consumer per-instance 큐 구독.
- REQ-050 (Integration): `trex.direct`(topic)/`trex.broadcast`(fanout) exchange + per-instance direct binding + control dual binding + `direct_routing_key` 빌더.
- REQ-051 (Documentation): interface-contract(routing key)/runtime-flows(TOML 기동·라우팅)/project-structure(동적 큐명·설정 계층·exchange) 정합.
## Delivery Plan
1. REQ-049: `topology.py` 큐명 빌더(default 하위호환) → `rabbitmq.declare_topology(instance_key)` → daemon consumer per-instance. 큐명 단위 + 기존 회귀.
2. REQ-050: `trex.direct`/`trex.broadcast` exchange 선언 + binding(direct per-instance, control dual) + routing key 빌더. 토폴로지 단위 + 인프라 게이트(라우팅 격리/broadcast).
3. REQ-048: `DaemonInstanceConfig.from_toml` + `--config` argparse 진입점 + `from_config` 병합 + `.gitignore` + 토큰 미노출. 로더 단위.
4. REQ-051: baseline 3문서 정합.
5. 전체 회귀 + ruff + 인프라 게이트(default 무회귀 + 라우팅) + (가능 시) 2-인스턴스 e2e.
## Dependencies
- Internal:
- dcy-006/BAT-007 messaging(topology/rabbitmq/daemon consumer) — 변경 대상 기반.
- BAT-012 control 채널(`trex.control.req`) — control 큐가 broadcast dual binding 대상.
- BAT-008 PortfolioHubConfig.token — TOML 주입 지점.
- External:
- RabbitMQ(topic/fanout exchange). stdlib `tomllib`(py3.12).
## Design Gate
- Design Required Before Implementation: yes
- Reason: (a) `declare_topology` signature 변경 + 큐명 동적화는 **모든 messaging consumer/test 표면**에 영향 — default 하위호환 규칙(리터럴 vs suffix)을 설계에서 고정해야 회귀를 막는다. (b) topic/fanout exchange + per-instance/dual binding 의 정확한 binding 매트릭스와 routing key 계약을 설계에서 확정해야 strategy 계약과 일치한다. (c) TOML+env 병합 우선순위(`portfolio_hub_token` TOML 우선) + `--config` 진입점 구조를 설계에서 명시. → design.md 동일 턴 scaffold.
## Milestones
1. M1 — REQ-049 동적 큐명 + declare_topology(instance_key) + default 회귀 green
2. M2 — REQ-050 exchange + binding + routing key + 인프라 게이트(라우팅) green
3. M3 — REQ-048 TOML 로더 + --config + 병합 + .gitignore 단위 green
4. M4 — REQ-051 baseline 3문서
5. M5 — 전체 회귀 + ruff + 인프라 게이트 + 2-인스턴스 e2e(가능 시)
## Risks
- R-1 (Medium): `declare_topology`/큐명 변경이 기존 messaging 테스트 다수에 영향. 대응: default=리터럴 큐명 하위호환으로 기존 테스트 무변경 유지(REQ-049 핵심). 빌더에 default 특수 처리.
- R-2 (Medium): old durable 큐 잔류(dcy-009 R-2). 대응: 자연 소멸 허용(OQ-1), 배포 절차 외. 코드 무관.
- R-3 (Low): broadcast 중복 제어(dcy-009 R-3). 대응: kill-switch/pause idempotency(REQ-036/advisory lock).
- R-4 (Low): TOML 토큰 커밋 노출(dcy-009 R-4). 대응: `.gitignore` + 로그 미노출(REQ-048).
- R-5 (Low): pika BlockingConnection thread-safety. 대응: per-thread connection 유지(NFR-2), 바인딩만 추가.
## Notes
- 하위호환 우선: default 인스턴스는 기존 리터럴 큐명·RPC 경로 그대로 → 기존 277+ 테스트 무회귀가 1차 게이트.
- 2-인스턴스 e2e(라우팅 격리/broadcast)는 RabbitMQ 인프라 게이트 또는 manual; 단일 인스턴스 기본 검증은 단위로 충분.