refactor: CEO 지시 분기를 단일 지시점으로 통합하고 부정 판정 결함 5건 수정 - #416
Conversation
- 흩어진 6개 분기 지점의 합산 레인 판정을 질의 문자열 단위로 고정 - 현행유지 15건·목적지 미결정 3건을 회귀 기준으로 명시 - 결함 12건을 expectedFailure로 표기해 조용한 유지·변경 차단 - 주문 레인 4종(즉시·조건·복합·연계) 전부에 부정 문장 케이스 배치 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 세 곳에 흩어진 부정 어휘(주문 레인·부서 라우터·workflow_mode)를 합집합으로 통합 - 기존 세 판정은 폭을 그대로 둔 얇은 래퍼로 유지, 어느 하나도 좁히지 않음 - 배제 표현(건드리지 말고·빼고·제외하고·말고)을 별도 상수로 추가, 적용은 후속 커밋 - 부정 지배 구간 추출기 negated_spans·dominant_negated_keys 신설 - 의도 어휘·binding 어휘·비구속 문구 사전을 같은 모듈로 이동 - 골든 결과 불변, 전체 스위트 실패 수 기준선과 동일(49건, 전부 사전 존재) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 6개 분기 지점의 검사 순서를 번호 붙은 Stage 0~7 파이프라인으로 명문화 - CeoRouteDecision에 lane·workflow_mode·routing_basis·reason_codes·order_plan 반환 - 내부는 기존 결정론 함수를 그대로 호출, 판정 정책 중복 구현 없음 - LLM 플래너는 호출하지 않고 lane="llm_planner_required" 반환만 담당 - 골든 결과 이관 전과 동일(통과 3·xfail 12·서브테스트 18) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- apps/api/ceo.py 순차 if 체인 6단 제거, classify_ceo_request 호출 1회로 대체 - 주문 문법 판정 import(조건·즉시·연계) 및 infer_workflow_mode 직접 호출 제거 - ceo_mirror_api·accounting 별칭 경로가 같은 지시점에서 플랜 수신 - 미러 라우팅 로그에 lane 필드 추가 - 골든 결과·전체 스위트 실패 목록 기준선과 동일 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 조건·복합·연계 레인에 즉시 주문과 대칭인 부정 가드 적용 - 부정 지배 구간 안의 주문 행위만 차단해 정상 조건주문은 통과 유지 - explicit_non_execution 행위 어휘에 매수·매도 추가, 순수 부정 문장의 binding 오분류 해소 - "이평 깨지면 매도하지 마"가 "손실 나도 매도하지 마"와 같은 레인으로 수렴 - 결함 표기 7건 해제, 종목 부정 조건주문 통과 회귀 테스트 추가 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 건드리지 말고·빼고·제외하고·말고 계열을 부서 선택 단계의 부정으로 인정 - 되묻기 게이트는 좁은 어휘 유지 - 금지도 대상 지목이므로 재질문으로 떨어뜨리지 않음 - "회계쪽은 건드리지 말고 리서치만 해줘"에서 accounting 추가 제거 - 결함 표기 1건 해제, 되묻기 회귀 방지 테스트 추가 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 기본값 선적재 후 add만 하던 구조에 배제 단계 추가 - 부정이 직접 지배하는 어휘만 제거 대상, 조건절 어휘는 보존 - QA 어휘는 배제 근거가 될 수 없음(응답 primary가 아님), ceo는 제거 불가 - 응답 부서가 전부 사라지는 배제는 기본값 유지로 fail-closed - excluded_departments는 CeoRouteDecision에만 노출, 플랜 직렬화 모양 불변 - 결함 표기 1건 해제, 조건절 보존·전량 배제 회귀 테스트 추가 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- _is_prohibited_safety_term의 인라인 부정 어휘를 query_lexicon으로 이동 - 부정 판정 함수가 query_lexicon 한 곳에만 존재하도록 정리 - department_analysis 레인 전체가 verify_primary_route로 재현 검증됨을 고정 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- ceo_query_routing 충돌 해소: main의 is_operational_status_query 채택, 중복 재도입된 인라인 _QUERY_INTENT_TERMS는 query_lexicon 별칭으로 정리 - ceo.py·user_order_language는 자동 병합(분기 체인 구간은 main 변경 없음) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 한 음절 부정 표지(안·못)에 어절 경계 요구, "5거래일 동안 추적"의 `동안`이 부정으로 잡혀 트레일링 조건주문이 막히던 오탐 제거 - operational_status를 명시 레인으로 승격, 부서 primary 0개인 조회가 department_analysis에 섞이지 않도록 분리 - ceo.py의 deterministic_operational_status를 레인 판정에서 직접 도출, 플랜 마커 재검사 제거 - 골든에 바스켓·트레일링·운영상태 케이스와 어절 경계 회귀 테스트 추가 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 안·못 뒤에 공백을 요구하던 조건 제거, 용언 어간(하·되·된·할·함·해·했·사·살·팔)까지 인식 - "주문 안하고"·"매도 못하게"·"체결 안되게"가 조건주문 카드로 새던 경로 차단 - 앞 한글 경계는 유지해 안전·안정·안내·안건·불안·잘못은 계속 통과 - 띄어쓰기 변형 10건·유사 낱말 8건 회귀 테스트 추가 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
고려사항과 결정리뷰 전에 읽어야 할 판단 근거. 코드만으로는 안 보이는 것들이다. 1. 사전이냐 형태소 분석기냐 — 사전 유지주문 게이트에서 LLM/신경망 판정은 효율이 아니라 권한 문제라 후보가 아니다. 개발원칙 4와 ADR-0007이 "주문 후보는 결정론을 통과"를 요구하고, 실제 후보는 정규식 사전과 형태소 분석기(kiwi/mecab-ko) 둘뿐이고, 지연은 도입을 막는 이유가 아니다. 실측: 같은 경로의 도입하지 않은 진짜 이유 세 가지:
재검토 트리거 (개발원칙 8): 실사용 질의에서, 남은 개선 여지: 지금은 변형 처리가 정규식 곳곳에 흩어져 있다. 결정론적 정규화 패스 하나로 모으면( 2. 사전이 진짜 약한 곳은 게이트가 아니라 부서 선택
3. 임의로 정하지 않고 남긴 결정 (
|
문제 파악
CEO 지시가 어느 레인으로 가는지 정하는 로직이 6개 지점에 흩어져 있었다. 각자는 맞았지만 "어떤 순서로 무엇을 검사하는지"가 한 파일에도 한 함수에도 적혀 있지 않았다. 그 결과 부정 가드가 즉시 주문 레인에만 걸려 있는 것을 아무도 못 봤고,
"이평 깨지면 매도하지 마"가 조건주문 카드를 만들었다.이 PR은 판정 방식을 통일하지 않는다. 주문 판정은 결정론으로 남고(개발원칙 4, ADR-0007), 라우터 결과는
verify_primary_route가 질의만으로 재현 검증할 수 있어야 하며, LLM 플래너는 그 둘 중 어느 것도 대체하지 않는다. 합친 것은 순서다.작업 내용
구조
orchestration/ceo_request_classifier.py신설 — 번호 붙은 Stage 0~7 파이프라인 단일 지시점orchestration/query_lexicon.py신설 — 세 곳에 흩어져 어휘가 서로 달랐던 부정 판정을 합집합으로 통합apps/api/ceo.py의 순차 if 체인 6단 제거 →classify_ceo_request()호출 1회ceo_mirror_api·accounting별칭 경로도 같은 지시점 경유build_deterministic_bff_plan·build_ceo_task_plan·verify_primary_route)는 삭제하지 않고 유지고친 결함
explicit_non_execution에매수/매도누락하지 마계열뿐건드리지 말고·빼고·제외하고·말고인식동안의안이 트레일링 조건주문을 막던 오탐 제거 +안하고·못하게·안되게미탐 차단결함 5는 main 병합 과정에서 발견됐다. main이 새로 추가한 트레일링 문법(
"최대 5거래일 동안 추적")이 제 가드에 걸렸고, 반대로 띄어쓰기를 생략한 부정은 새고 있었다.main 통합
operational_status를 명시 레인으로 승격 — main이 추가한 이 레인은 부서 primary가 0개인데department_analysis에 섞여 있었다. 이름이 없으면 다음 사람이 또 호출부에 플래그를 만든다ceo.py의deterministic_operational_status를 플랜 마커 재검사 대신 레인 판정에서 직접 도출검증
routing_basis값experience_bank·d5_improvement_pipeline·ceo_kanban_read가 읽는 값 불변verify_primary_routedepartment_analysis레인 전체에 대해 여전히 유효 (테스트로 고정)52건 실패와 49건 collection error는 전부 main에도 존재한다(Windows에
fcntl없음).리뷰 포인트
orchestration/query_lexicon.py— 부정 판정 함수가 이제 여기 한 곳에만 있다. 인라인 정규식 0건orchestration/ceo_request_classifier.pyStage 2 — 부정 가드가 4개 레인에 대칭으로 걸리는 지점tests/orchestration/test_ceo_request_classifier_golden.py— 골든 케이스 표.expectedFailure3건은 담당자 결정이 필요한 미결 항목(코멘트 참조)🤖 Generated with Claude Code
배포