From 9caa3ab4b7d032054d437267ef81e732c4c50d4c Mon Sep 17 00:00:00 2001 From: happybell80 Date: Thu, 5 Mar 2026 16:48:05 +0900 Subject: [PATCH] docs: sync all pending local updates for team consistency --- .../311_백엔드_구조_원칙.md | 4 + .../312_문서_작성_원칙.md | 38 +++++++- book/300_architecture/315_테스트_원칙.md | 4 + ...기개선루프_DB_구현_실행계획.md | 1 + ..._51124_먹통_근본원인_해결계획.md | 79 +++++++++++++++ ...간_코드차분_원인확정_리서치.md | 83 ++++++++++++++++ ...아영어노출_원인확정_리서치.md | 95 +++++++++++++++++++ journey/research/README.md | 5 + ...아영어노출_사용자시나리오.md | 42 ++++++++ journey/scenarios/README.md | 1 + ...05_51124_다운_상태_및_복구예정.md | 9 ++ ...루프_차단_및_23임시배포_완료.md | 45 +++++++++ 12 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 journey/plans/archive/260304_51124_먹통_근본원인_해결계획.md create mode 100644 journey/research/260304_51124_먹통_48시간_코드차분_원인확정_리서치.md create mode 100644 journey/research/260305_아침브리핑_형식혼선_동남아영어노출_원인확정_리서치.md create mode 100644 journey/scenarios/260305_아침브리핑_형식혼선과_동남아영어노출_사용자시나리오.md create mode 100644 journey/troubleshooting/2026-03-05_51124_다운_상태_및_복구예정.md create mode 100644 journey/troubleshooting/260305_rb8001_의도재진입루프_차단_및_23임시배포_완료.md diff --git a/book/300_architecture/311_백엔드_구조_원칙.md b/book/300_architecture/311_백엔드_구조_원칙.md index 6a112b9..92fab9e 100644 --- a/book/300_architecture/311_백엔드_구조_원칙.md +++ b/book/300_architecture/311_백엔드_구조_원칙.md @@ -47,6 +47,10 @@ - router 파일에서 main.py의 인스턴스(router, scheduler 등) 사용 시 의존성 주입 패턴 사용 - 예: `set_router_instance()`, `set_scheduler()` 함수로 주입 - router 파일에서 직접 import하지 않음 +- **`당장 동작` 우선 구현 절대 금지** + - 운영 중인 `main.py`에 스케줄/복구/외부 호출/무거운 초기화를 임시로 누적해 문제를 덮는 방식 금지 + - 임시 우회/폴백으로 증상을 숨기는 구현 금지 + - 위반 발견 시 기능 추가보다 책임 분리 리팩토링을 우선 수행 ### 폴더 명명 규칙 - `router/` 또는 `api/`: HTTP 처리 diff --git a/book/300_architecture/312_문서_작성_원칙.md b/book/300_architecture/312_문서_작성_원칙.md index 78fd037..5c5b450 100644 --- a/book/300_architecture/312_문서_작성_원칙.md +++ b/book/300_architecture/312_문서_작성_원칙.md @@ -1,11 +1,21 @@ # 문서 작성 원칙 **작성일**: 2025-10-13 -**수정일**: 2026-02-04 (아이디어·시나리오 관리 원칙 추가) +**수정일**: 2026-03-05 (SSOT 관리 기준 명시) **참고**: AGENTS.md, 311_백엔드_구조_원칙.md --- +## 0. SSOT 관리 기준 + +- 문서 작성 상세 원칙의 SSOT는 본 문서(`312_문서_작성_원칙.md`)다. +- 하위 폴더 `README.md`와 개별 문서는 원칙 본문을 반복하지 않고 SSOT 링크만 둔다. +- 동일 원칙을 여러 문서에 복제하지 않는다. 필요 시 본 문서를 수정하고 참조 링크만 갱신한다. +- 실행/코드 정책(예: 폴백·예외 처리 최소화, 원인 경로 직접 수정)은 `AGENTS.md`를 SSOT로 본다. +- 본 문서의 리서치/시나리오 원칙은 문서화 표현 기준이며, 코드 동작 정책을 대체하지 않는다. + +--- + ## 1. 문서 종류별 규칙 ### 트러블슈팅 문서 @@ -99,6 +109,18 @@ - **미구현 아이디어만 유지**: 구현 결과가 troubleshooting·plans에 정리되면 ideas 문서 삭제(또는 `deprecated/`로 이동) - **핵심만 기록**: 간단한 흐름·배경만 남기고 상세 구현 내용은 계획/트러블슈팅으로 이동 +### 리서치 문서 + +**경로**: `DOCS/journey/research/` +**규칙**: +- 원인 확정이 해결안 제시보다 우선이다. +- 원인 분석 정확도 목표는 100%로 둔다. 불확실하면 "미확정"으로 기록한다. +- 해결 포인트는 단일 경로로 좁히고, 비대상 프로젝트 영향은 0을 기준으로 분리한다. +- 사실/해석/결론을 분리해 기록한다. +- 출처 URL(또는 내부 문서 경로)과 확인 시점을 명시한다. +- 구현 코드 복붙 대신 파일 경로·핵심 위치 참조를 사용한다. +- README에는 원칙 본문을 반복하지 않고, 본 섹션(SSOT) 링크만 둔다. + ### 시나리오 문서 **경로**: `DOCS/journey/scenarios/` @@ -108,8 +130,13 @@ - UX 흐름만 기록하고 내부 구현 세부 설명은 링크로 참조 - 사용자/운영자 행동 기준으로 작성 (`누가`, `언제`, `무엇을 하려다`, `어디서 막히는지`) - 기술 용어보다 체감 결과를 우선 기록 (`기다림`, `재시도`, `업무 지연`, `실행 실패`) -- 수치는 `현재 관측값`과 `개선 목표`를 분리해 표기하고, 달성 전에는 목표를 결과처럼 쓰지 않음 -- 한 시나리오는 반드시 `실패 장면 1개`와 `개선 후 장면 1개`를 같은 맥락으로 짝지어 기록 +- 한 문서는 반드시 `문제` → `문제 상황(현재 체감)` → `해결 후 기대 상황` 3축으로 쓴다. +- `실패 장면 1개`와 `개선 후 장면 1개`를 같은 맥락으로 짝지어 기록한다. + +**시나리오 핵심 원칙(요약)**: +1. 사용자(인간) 시점으로 쓴다. +2. 기술 설명보다 체감 불편을 먼저 쓴다. +3. 해결 뒤 달라질 상태를 명확히 쓴다. --- @@ -216,6 +243,11 @@ ## 5. 참고 ``` +### 시나리오 문서 구조 +- 필수 섹션 3개: `문제` / `문제 상황(현재 체감)` / `해결 후 기대 상황` +- 필수 장면 2개: `실패 장면 1개` / `개선 후 장면 1개` +- 연결 문서: troubleshooting/plans/research 링크만 첨부 (구현 상세 복붙 금지) + --- ## 4. 파일 크기 제한 diff --git a/book/300_architecture/315_테스트_원칙.md b/book/300_architecture/315_테스트_원칙.md index 099707c..7701b67 100644 --- a/book/300_architecture/315_테스트_원칙.md +++ b/book/300_architecture/315_테스트_원칙.md @@ -18,6 +18,10 @@ DecisionEngine, intent, 캘린더 로직 등은 항상 테스트에서 기대 행동을 확정한 뒤 수정한다. +### 로빙 테스트 환경 단일화 원칙 + +로빙(`rb8001`) 프로젝트 테스트는 `rb8001/tests`와 단일 실행 기준만 사용하고, 임시/분기 테스트 환경은 만들지 않는다. + ### UX 검증 원칙 - 사용자가 실제로 보는 문구·행동만 검증한다 (예: 응답 문장, 버튼 노출 여부) diff --git a/journey/plans/260303_자기개선루프_DB_구현_실행계획.md b/journey/plans/260303_자기개선루프_DB_구현_실행계획.md index b354ccd..d8ca72c 100644 --- a/journey/plans/260303_자기개선루프_DB_구현_실행계획.md +++ b/journey/plans/260303_자기개선루프_DB_구현_실행계획.md @@ -10,6 +10,7 @@ - 코드 기능 확장 전에 DB/로그 구조를 먼저 고정한다. - 기존 자산(`intent_review_queue`, `ir_deck_feedback`, `conversation_log`)을 재사용한다. - 부족한 영역(정책 버전/반성 기록)을 신규 테이블로 보완한다. +- 구조/구현 원칙은 [311_백엔드_구조_원칙](../../book/300_architecture/311_백엔드_구조_원칙.md)을 단일 기준으로 따른다. ## 1-1) 로컬 개발자 실행 경계 (필수) diff --git a/journey/plans/archive/260304_51124_먹통_근본원인_해결계획.md b/journey/plans/archive/260304_51124_먹통_근본원인_해결계획.md new file mode 100644 index 0000000..1c6303f --- /dev/null +++ b/journey/plans/archive/260304_51124_먹통_근본원인_해결계획.md @@ -0,0 +1,79 @@ +# 260304 51124 먹통 근본원인 해결계획 + +**작성일**: 2026-03-04 +**상태**: 미구현 +**목표**: 51124 먹통의 근본 원인(의도분류 재진입 루프)을 제거하고 restart loop 재발을 차단한다. + +--- + +## 1. 기준 문서 +- [51124 먹통 원인 확정 리서치](../research/260304_51124_먹통_48시간_코드차분_원인확정_리서치.md) +- [51124 먹통 사용자 시나리오](../scenarios/260304_아침브리핑_지연_먹통_복구_사용자시나리오.md) +- [51123 임시복구 조치내역](../troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md) +- [문서 작성 원칙](../../book/300_architecture/312_문서_작성_원칙.md) + +## 2. 근본 원인(확정) +- `INTENT_ENGINE=graph` + `INTENT_USE_LANGGRAPH=true`에서 +- `IntentGraph.detect_with_workflow()` -> `classify_intent_node()` -> `IntentGraph.detect()` 재진입 루프가 발생한다. +- 이 재진입 루프가 `Restarting` 반복과 CPU 폭주의 직접 원인이다. + +## 3. 범위 고정 +### 포함 +- 51124 실환경 설정값 확인 +- 재진입 루프 차단 코드 수정 +- 회귀 테스트 추가 +- 51124 재배포 및 재발 판정 + +### 제외 +- 23/24 자동 전환(페일오버) +- 스케줄러 구조 개선 +- DB 풀 일반 튜닝 +- 타 서비스 기능 개선 + +## 4. 실행 계획 +1. 51124 실환경 값 확정 +- 51124에서 `INTENT_ENGINE`, `INTENT_USE_LANGGRAPH` 실제 값을 확인한다. +- 확인 증적(명령 출력)을 남긴다. +- 값 미확정 상태에서는 다음 단계를 진행하지 않는다. + +2. 재진입 차단 코드 수정 +- 파일: `robeing/rb8001/app/services/brain/intent_graph.py` +- `detect()`에 내부 호출 가드를 추가한다. +- workflow 내부 호출이면 `detect_with_workflow()`를 금지하고 `_detect_traditional()`만 실행한다. + +- 파일: `robeing/rb8001/app/services/brain/intent_langgraph_workflow.py` +- `classify_intent_node()`의 `IntentGraph.detect()` 호출에 내부 호출 가드를 명시한다. +- classify 단계는 단일 분류 실행으로 종료한다. + +3. 운영 기본값 안전화 +- 파일: `robeing/rb8001/docker-compose.yml` +- 기본값을 아래로 고정한다. +- `INTENT_USE_LANGGRAPH=${INTENT_USE_LANGGRAPH:-false}` +- `INTENT_ENGINE=${INTENT_ENGINE:-v1}` + +4. 회귀 테스트 추가 +- 파일: `robeing/rb8001/tests/test_intent_workflow_no_reentry.py` +- 검증 항목: +- workflow classify 단계에서 `detect_with_workflow()` 재호출 0회 +- `INTENT_ENGINE=graph` + `INTENT_USE_LANGGRAPH=true`에서도 단일 요청 정상 종료 + +5. 51124 배포 및 검증 +- 배포: `docker compose down && docker compose up -d --build` +- 검증은 실도메인(`https://ro-being.com`) 기준으로만 수행한다. +- 30분 관찰 구간을 고정한다. + +## 5. 완료 판정 +- `rb8001` 컨테이너 `Restarting` 0회 +- `RecursionError` 0건 +- `GRAPH_RECURSION_LIMIT` 0건 +- `https://ro-being.com/api/message` 3회 연속 성공 +- 30분 관찰 동안 운영자 조작 불가 구간 0회 + +## 6. 실패 시 처리 +- 완료 판정 1개라도 미달이면 미완료로 유지한다. +- 실패 원인과 증적을 troubleshooting 문서로 분리 기록한다. +- 본 문서에는 troubleshooting 링크만 추가한다. + +## 7. 문서 상태 전환 +- 위 완료 판정 전부 충족 시 본 문서를 `plans/archive/`로 이동한다. +- 이동과 동시에 완료 troubleshooting 문서를 연결한다. diff --git a/journey/research/260304_51124_먹통_48시간_코드차분_원인확정_리서치.md b/journey/research/260304_51124_먹통_48시간_코드차분_원인확정_리서치.md new file mode 100644 index 0000000..00b6754 --- /dev/null +++ b/journey/research/260304_51124_먹통_48시간_코드차분_원인확정_리서치.md @@ -0,0 +1,83 @@ +# 51124 먹통: 48시간 코드 차분 기반 원인 확정 리서치 + +**작성일**: 2026-03-04 +**범위**: `rb8001`, `robeing-gateway`, `robeing-monitor`, `skill-email`, `skill-embedding`, `skill-rag-file` 최근 48시간 커밋/디프 +**목표**: 51124 CPU 폭주/먹통의 원인을 코드 근거로 확정하고, 재발 방지 해법을 운영 관점으로 고정 + +--- + +## 1. 결론(확정) +- 24 서버 먹통의 직접 경로는 `INTENT_ENGINE=graph` + `INTENT_USE_LANGGRAPH=true` 활성 시 의도 분류 워크플로우 내부 재진입 구조다. +- 재진입 지점은 `IntentGraph.detect_with_workflow()` → LangGraph `classify_intent_node()` → `IntentGraph.detect()` 재호출로 확인된다. +- 23 서버가 같은 증상을 재현하지 않은 이유는 임시복구 시 `.env`에서 `INTENT_ENGINE=v1`, `INTENT_USE_LANGGRAPH=false`로 강제 다운그레이드했기 때문이다. + +## 2. 근거(코드/문서) + +### 2.1 48시간 주요 변경 +- `rb8001` `3532600`: `docker-compose.yml` 기본값이 `INTENT_ENGINE=v1` -> `graph`로 변경됨. +- `rb8001` `1f39d08`: `/api/message` 응답 후 자기개선 아티팩트 DB 기록 경로 추가(부하 증가 요인). +- `robeing-gateway` `5b97bea`: 프록시가 method/body/content-type 전달하도록 변경(이전보다 실제 경로 실행률 상승). +- `robeing-monitor` `1221596`: `/health` 호환 엔드포인트 추가(먹통 직접 원인으로 보기 어려움). + +### 2.2 재진입(재귀) 경로 +- `rb8001/app/services/brain/intent_graph.py:39-41` + - `INTENT_USE_LANGGRAPH=true`면 `detect()`가 `detect_with_workflow()`를 호출. +- `rb8001/app/services/brain/intent_graph.py:65` + - `detect_with_workflow()`가 LangGraph workflow `ainvoke` 실행. +- `rb8001/app/services/brain/intent_langgraph_workflow.py:49-60` + - `classify_intent_node()` 내부에서 새 `IntentGraph` 생성 후 `intent_graph.detect(message, context)` 재호출. +- 위 3개가 결합되어, 워크플로우 내부 분류 노드가 다시 워크플로우 진입 경로를 호출하는 구조가 성립한다. + +### 2.3 23/24 차이의 확정 근거 +- `DOCS/journey/troubleshooting/260304_51123_임시복구_서비스연속성_조치내역.md:43-49` + - 51123 임시복구에서 `INTENT_ENGINE=v1`, `INTENT_USE_LANGGRAPH=false` 적용 기록이 명시됨. +- `rb8001/.env:185-188` + - 동일 임시복구 성능 오버라이드가 실제 파일에도 존재. +- 따라서 같은 코드 베이스라도 23은 재진입 경로를 비활성화했고, 24는 기본 `graph` 경로를 타서 증상이 확대될 수 있다. + +### 2.4 외부 근거(공식 문서) +- LangGraph는 종료 조건 없이 그래프를 순환 실행하면 `GRAPH_RECURSION_LIMIT` 오류가 발생할 수 있음을 명시한다. + - https://docs.langchain.com/oss/python/langgraph/GRAPH_RECURSION_LIMIT +- Python은 재귀 깊이에 한계가 있고, 한계를 넘으면 `RecursionError`가 발생한다(재귀 경로가 안전하지 않다는 일반 규칙). + - https://docs.python.org/3/library/sys.html#sys.getrecursionlimit +- Docker `restart` 정책(`always`/`unless-stopped`)은 프로세스가 비정상 종료될 때 컨테이너를 반복 재기동한다. + - https://docs.docker.com/engine/containers/start-containers-automatically/ + +## 3. 원인/비원인 구분 + +| 구분 | 항목 | 판정 | 이유 | +|------|------|------|------| +| 원인 | 의도 분류 워크플로우 재진입 구조 | 확정 | 코드 호출 체인이 직접 닫힌 루프를 형성 | +| 증폭 | `/api/message` 자기개선 DB 기록 추가 | 확정 | 요청당 DB 작업/연결 증가 | +| 증폭 | gateway 프록시 body/header 전달 확대 | 확정 | 기존 차단/오류 경로가 실제 실행으로 전환 | +| 비원인 | robeing-monitor `/health` 추가 | 제외 | 라우트 1개 추가로 CPU 폭주 구조가 생기지 않음 | +| 비원인 | RAM 부족 | 제외 | 기존 관측값 기준 swap/OOM 근거 없음 | + +## 4. 해결책(정확/우선순위) + +### P0 즉시(운영 보호) +1. 24 서버 배포 전 기본값을 재진입 없는 안전값으로 고정: + - `INTENT_ENGINE=v1` + - `INTENT_USE_LANGGRAPH=false` +2. 적용 후 30분 관찰 기준: + - 컨테이너 `Restarting` 0회 + - `python main.py` CPU 지속 고점 급등 재발 없음 + +### P1 구조 수정(근본) +1. `IntentGraph.detect()`에 워크플로우 내부 호출 구분 플래그를 추가해 재진입 차단. +2. 또는 `classify_intent_node()`가 `IntentGraph.detect()`가 아닌 전통 분류 함수만 직접 호출하도록 분리. +3. 회귀 테스트 추가: + - "workflow classify node가 detect_with_workflow를 다시 호출하지 않는다" 단언 테스트. + +### P2 검증 고정(재발 방지) +1. 배포 파이프라인에 스모크 테스트 추가: + - `INTENT_ENGINE=graph` 상태에서 단일 메시지 처리 시 호출 깊이/시간 상한 검증. +2. 런타임 가드: + - 의도 분류 단계 실행 횟수 카운터를 요청 단위로 기록, 임계 초과 시 즉시 오류/중단. + +## 5. 운영 판정 기준 +- 완료 판정은 "응답 속도"가 아니라 "먹통 재발 차단"이다. +- 아래를 동시에 만족해야 완료: + - restart loop 0회 + - 운영자가 전체 컨테이너 강제중지 없이 장애 제어 가능 + - 09:00~10:00 주요 스케줄 구간에서 CPU 급등/응답 중단 없음 diff --git a/journey/research/260305_아침브리핑_형식혼선_동남아영어노출_원인확정_리서치.md b/journey/research/260305_아침브리핑_형식혼선_동남아영어노출_원인확정_리서치.md new file mode 100644 index 0000000..bfd82aa --- /dev/null +++ b/journey/research/260305_아침브리핑_형식혼선_동남아영어노출_원인확정_리서치.md @@ -0,0 +1,95 @@ +# 260305 아침브리핑 형식혼선·동남아영어노출 원인확정 리서치 + +## 1) 목적 +- 대상 문제 2개만 원인 확정: +1. 아침 브리핑/뉴스 표시 형식 혼선 +2. 동남아 소식 영어 노출 +- 목표: 원인 정확도 100% 기준으로, 수정 포인트를 단일 경로로 좁힌다. + +## 2) 범위 / 비범위 +- 범위: `rb8001`, `skill-news`, `robeing-gateway` +- 비범위: 다른 프로젝트(StarsAndI, GooseFarm 등), 다른 기능 이슈 + +## 3) 사실(Facts) +### 3-1. 실행 버전/경로 +- `rb8001` 현재 커밋: `e9dcd1d` +- `skill-news` 현재 커밋: `d8a7c5b` +- 컨테이너: + - `rb8001` 생성시각: `2026-03-04T15:02:26Z` + - `robeing-skill-news` 생성시각: `2026-03-03T18:10:57Z` + +### 3-2. 아침 뉴스 브리핑 실행 사실 (2026-03-05) +- `09:10:00` daily_headlines 시작 +- `09:10:07` naver items 22 +- `09:10:25` sea headlines 3 +- `09:10:31` formatted text length 3213, Slack 전송 성공 +- 근거 로그: `rb8001` 컨테이너 로그 (`daily_headlines`, `naver items`, `sea headlines`, `formatted text length`) + +### 3-3. 동남아 영어 노출 직전 사실 +- `skill-news` 로그에 아래 2개 경고가 같은 실행 구간에서 확인됨: +1. `LLM 적합도 실패 ... 404 models/gemini-2.0-flash-exp is not found ...` +2. `제목 번역 실패, 원문 유지 ... 404 models/gemini-2.0-flash-exp is not found ...` +- 근거 로그: `robeing-skill-news` 2026-03-05 09:10 실행 구간 + +### 3-4. 관련 코드 사실 (정확 위치) +- 번역 모델 기본값: + - `skill-news/app/services/sea_news_filter.py:53` + - `os.getenv("GEMINI_MODEL", "gemini-2.0-flash-exp")` +- 번역 실패 시 원문 유지: + - `skill-news/app/services/sea_news_filter.py:159` + - `return list(articles)` +- 동남아 제목 번역 호출 경로: + - `skill-news/app/api/news_endpoints.py:66` (`translate_titles_to_korean`) +- rb8001이 해당 endpoint를 호출: + - `rb8001/app/commands/skill_commands.py:252-278` + - `POST /api/news/sea/headlines` + +### 3-5. 형식 관련 코드 사실 (정확 위치) +- 네이버 뉴스 본문 형식 생성: + - `skill-news/app/services/naver_startup_news_service.py:314-367` +- 오프닝/클로징/명언 일자 로테이션: + - `skill-news/app/services/naver_startup_news_service.py:95-123` +- rb8001에서 동남아 섹션/키워드 섹션 추가 삽입: + - `rb8001/app/services/workflows/headlines_workflow.py:40-83` + - `rb8001/app/services/workflows/headlines_workflow.py:163-173` +- 아침 브리핑(네이버웍스) 구조 변경 이력: + - 커밋 `3afb9c9` (중요메일 섹션 제거, 1줄 인사이트 구조 전환) + - 현재 코드: `rb8001/app/services/skills/naverworks_briefing.py:59-73, 261-319` + +### 3-6. 게이트웨이 영향 사실 +- daily_headlines는 rb8001 내부 스케줄러가 직접 Slack 전송: + - `rb8001/app/services/workflows/headlines_workflow.py:180-189` +- 본 경로는 gateway 프록시 경유가 아님. + +## 4) 해석(Interpretation) +### 4-1. 동남아 영어 노출 원인 (확정) +- `GEMINI_MODEL` 미지정 상태에서 기본값 `gemini-2.0-flash-exp` 사용 +- 해당 모델 호출이 404로 실패 +- 번역 실패 폴백이 "원문 유지"로 설계되어 영어가 그대로 노출 + +### 4-2. 형식 혼선 원인 (확정) +- 형식 생성 책임이 2개 서비스로 분산됨: +1. `skill-news`가 기본 포맷 생성 +2. `rb8001`이 동남아/키워드 섹션을 후삽입 +- 네이버웍스 아침 브리핑은 별도 경로에서 이미 구조가 변경된 상태(커밋 `3afb9c9`) +- 사용자 입장에서는 "아침 브리핑" 범주 안에서 서로 다른 형식 경로가 동시에 존재 + +## 5) 결론(Conclusion) +### 결론 A: 동남아 영어 노출 +- 확정 원인: `skill-news` 번역 모델 설정 불일치 + 원문 유지 폴백 +- 단일 수정 포인트: +1. `skill-news` 실행 환경 `GEMINI_MODEL` +2. `skill-news/app/services/sea_news_filter.py` 번역 실패 처리 정책 + +### 결론 B: 형식 혼선 +- 확정 원인: 아침 메시지 형식 책임 분산 + 브리핑 경로별 구조 차이 +- 단일 수정 포인트: +1. 뉴스 형식 최종 조립 책임을 한 경로로 고정 (`skill-news` 또는 `rb8001` 중 1곳) +2. 네이버웍스/뉴스를 "아침 브리핑 패밀리" 공통 템플릿 기준으로 정렬 + +## 6) 비영향 범위 (영향 0 기준 분리) +- 본 문제와 무관: + - `StarsAndI` 프로젝트 + - `GooseFarm` 프로젝트 + - gateway의 일반 API 프록시 경로 +- 근거: 해당 문제 실행 경로가 `rb8001 scheduler -> skill-news -> slack`로 닫혀 있음. diff --git a/journey/research/README.md b/journey/research/README.md index 3600970..690b9a7 100644 --- a/journey/research/README.md +++ b/journey/research/README.md @@ -3,8 +3,13 @@ ## 개요 로빙 프로젝트의 학술적 기반과 참고한 연구들을 정리한 섹션입니다. +리서치 문서 작성 원칙(SSOT): [`../../book/300_architecture/312_문서_작성_원칙.md`의 "리서치 문서" 섹션](../../book/300_architecture/312_%EB%AC%B8%EC%84%9C_%EC%9E%91%EC%84%B1_%EC%9B%90%EC%B9%99.md) + ## 연구 분야 +- [아침브리핑 형식혼선·동남아영어노출 원인확정 리서치 (260305)](./260305_아침브리핑_형식혼선_동남아영어노출_원인확정_리서치.md) +- [51124 먹통 48시간 코드 차분 원인 확정 리서치 (260304)](./260304_51124_먹통_48시간_코드차분_원인확정_리서치.md) + ### [기억(Memory)](./memory/README.md) - 장단기 기억 메커니즘 - 정보 엔트로피 이론 diff --git a/journey/scenarios/260305_아침브리핑_형식혼선과_동남아영어노출_사용자시나리오.md b/journey/scenarios/260305_아침브리핑_형식혼선과_동남아영어노출_사용자시나리오.md new file mode 100644 index 0000000..b766845 --- /dev/null +++ b/journey/scenarios/260305_아침브리핑_형식혼선과_동남아영어노출_사용자시나리오.md @@ -0,0 +1,42 @@ +# 아침 브리핑 형식 혼선과 동남아 영어 노출 사용자 시나리오 + +**상태**: 부분 +**작성일**: 2026-03-05 +**대상 사용자**: 아침 브리핑을 매일 확인하는 사용자 + +--- + +## 문제 +- 아침 브리핑을 볼 때마다 표시 형식이 달라져서, 어제와 오늘의 정보를 같은 기준으로 비교하기 어렵다. +- 동남아 소식이 영어로 나와 한 번 더 읽고 해석해야 해서, 아침에 빠르게 판단하기가 어렵다. + +## 문제 상황 (현재 체감) +- 사용자는 아침에 브리핑을 열어 핵심만 빠르게 확인하려고 한다. +- 그런데 줄 구성과 강조 방식이 매번 달라져 먼저 "읽는 방식"부터 다시 맞춰야 한다. +- 동남아 소식은 한국어로 나올 때도 있고 영어로 나올 때도 있어, 중요한 항목을 즉시 구분하기 어렵다. +- 결과적으로 확인 시간이 길어지고, 같은 내용을 다시 물어보거나 다시 확인하는 일이 늘어난다. + +## 해결 후 기대 상황 +- 브리핑 형식이 매일 동일하게 유지되어, 사용자는 위치를 외우듯 바로 핵심을 확인할 수 있다. +- 동남아 소식이 항상 한국어로 표시되어, 추가 해석 없이 바로 의미를 파악할 수 있다. +- 사용자는 한 번 읽고 바로 다음 행동(공유, 지시, 회신 준비)으로 넘어갈 수 있다. + +## 실패 장면 +1. 사용자가 09:10 브리핑을 열고 어제와 같은 방식으로 읽으려 한다. +2. 오늘 메시지의 구성이 달라져 어디가 핵심인지 다시 찾아야 한다. +3. 동남아 소식 일부가 영어로 표시되어 의미를 한 번 더 해석한다. +4. 사용자는 "정리본을 다시 알려달라"는 추가 요청을 하게 된다. + +## 개선 후 장면 +1. 사용자가 09:10 브리핑을 연다. +2. 매일 같은 형식이라 바로 핵심 구역부터 읽는다. +3. 동남아 소식이 한국어로 일관 표시되어 즉시 이해한다. +4. 사용자는 추가 질문 없이 바로 업무 행동으로 넘어간다. + +## 완료 기준 (사용자 기준) +- 사용자가 "형식이 다시 바뀌었다"는 피드백 없이 연속 사용한다. +- 동남아 소식 확인 시 추가 해석 요청이 발생하지 않는다. +- 브리핑 확인 후 재질문 없이 바로 다음 행동으로 이어진다. + +## 연결 문서 +- `../troubleshooting/260305_rb8001_의도재진입루프_차단_및_23임시배포_완료.md` diff --git a/journey/scenarios/README.md b/journey/scenarios/README.md index c0e8a01..7b997c1 100644 --- a/journey/scenarios/README.md +++ b/journey/scenarios/README.md @@ -61,6 +61,7 @@ - [베이지안 세미나 발표 시나리오](./251223_bayesian_seminar_presentation_scenario.md) - [자기개선 루프 미팅 요약 시나리오 (260303)](./260303_자기개선루프_미팅요약_피드백_시나리오.md) - [51124 먹통 사건 사용자 시나리오 (260304)](./260304_아침브리핑_지연_먹통_복구_사용자시나리오.md) +- [아침 브리핑 형식 혼선과 동남아 영어 노출 사용자 시나리오 (260305)](./260305_아침브리핑_형식혼선과_동남아영어노출_사용자시나리오.md) --- diff --git a/journey/troubleshooting/2026-03-05_51124_다운_상태_및_복구예정.md b/journey/troubleshooting/2026-03-05_51124_다운_상태_및_복구예정.md new file mode 100644 index 0000000..a31ca6a --- /dev/null +++ b/journey/troubleshooting/2026-03-05_51124_다운_상태_및_복구예정.md @@ -0,0 +1,9 @@ +# 2026-03-05 51124 다운 상태 및 복구 예정 + +- 기준일: 2026-03-05 +- 대상 서버: 51124 (192.168.219.52) +- 현재 상태: 다운(미가동) +- 복구 계획일: 2026-03-06 +- 임시 운영 상태: 51123에서 robeing 임시 가동 중 (rb8001, skill 계열) +- 원래 실행 위치: 51124 (robeing/skill 실행 서버) +- 비고: 본 상태/일정은 사용자 운영 지시 기준으로 기록함 diff --git a/journey/troubleshooting/260305_rb8001_의도재진입루프_차단_및_23임시배포_완료.md b/journey/troubleshooting/260305_rb8001_의도재진입루프_차단_및_23임시배포_완료.md new file mode 100644 index 0000000..eb7f32c --- /dev/null +++ b/journey/troubleshooting/260305_rb8001_의도재진입루프_차단_및_23임시배포_완료.md @@ -0,0 +1,45 @@ +# rb8001 의도재진입루프 차단 및 23 임시배포 완료 + +**날짜**: 2026-03-05 +**작성자**: Codex +**관련 파일**: `robeing/rb8001/app/services/brain/intent_graph.py:33-49`, `robeing/rb8001/app/services/brain/intent_langgraph_workflow.py:49-64`, `robeing/rb8001/docker-compose.yml:68-70`, `robeing/rb8001/tests/test_intent_workflow_no_reentry.py:10-80` + +--- + +## 문제 상황 +- 51124 먹통 원인으로 확정된 의도분류 재진입 경로가 존재했다. +- 경로: `detect_with_workflow() -> classify_intent_node() -> detect()` 재호출. +- 운영 상태는 24 장애로 23 임시운영 중이었다. + +## 해결 방안 +- `intent_graph.py:33-49` + - `detect()`에 `workflow_internal_call` 가드를 추가. + - 내부 호출 시 `detect_with_workflow()` 진입을 차단하고 `_detect_traditional()`로 고정. +- `intent_langgraph_workflow.py:49-64` + - `classify_intent_node()`에서 `IntentGraph.detect(..., workflow_internal_call=True)`로 호출. +- `docker-compose.yml:68-70` + - 운영 기본값을 안전 모드로 조정. + - `INTENT_USE_LANGGRAPH=${INTENT_USE_LANGGRAPH:-false}` + - `INTENT_ENGINE=${INTENT_ENGINE:-v1}` +- `tests/test_intent_workflow_no_reentry.py:10-80` + - 재진입 차단 회귀 테스트 2건 추가. + +## 구현 완료 +- 커밋: `e9dcd1d` (`fix(intent): block langgraph reentry loop and add regression test`) +- 푸시: `origin/main` 반영 완료 +- 23 임시운영 배포: `docker compose down && docker compose up -d --build` 완료 + +## 검증 +- 테스트: + - `cd /home/admin/robeing/rb8001 && PYTHONPATH=. pytest -q tests/test_intent_workflow_no_reentry.py` + - 결과: `2 passed` +- 서비스 상태: + - `rb8001` 포함 로빙 컨테이너 `healthy` + - 컨테이너 내부 `/health` 응답 정상 +- 실도메인 인증 호출: + - `Authorization: Bearer ` 포함 시 게이트웨이 인증 통과 확인 + +## 교훈 +- 근본 원인 경로는 예외 폴백이 아니라 호출 경로 차단으로 해결해야 재발을 줄일 수 있다. +- 24 장애 시 검증은 23 임시운영 경로를 기준으로 수행해야 운영 판단과 일치한다. +- 테스트 환경은 `rb8001/tests` + 단일 실행 기준으로 유지해야 검증 혼선을 줄일 수 있다.