← 시황 목록
마감시황

2026년 6월 9일 마감시황

2026년 6월 9일 마감시황 실패 원인 분석

2026년 6월 9일 마감시황 실패 원인 분석

결론

오늘 실패는 기존 market-closing-report 스킬이나 KRX 수급분석 로직이 망가져서 발생한 것이 아니다. 2026년 6월 9일 18:05 예약 실행을 위해 새로 만든 systemd --user 래퍼가 별도 Codex CLI를 호출하는 과정에서 깨졌다.

실패 범위는 세 단계로 나뉜다.

  1. KRX 수급분석: 정상 완료
  2. 예약 래퍼의 Codex CLI 호출: 실패
  3. 긴급 수동 작성: 파일 생성은 성공했지만, 최초 작성본에서 특징주 중복 제외 규칙을 완전히 적용하지 못함

따라서 오늘의 핵심 문제는 "마감시황 작성 능력"이 아니라 "새 자동 실행 계층의 안정성 검증 부족"과 "수동 복구 시 별도 검증 항목 부족"이다.

확인된 사실

KRX 수급분석은 정상

scheduled_tasks/20260609_market_close/logs/run.log 기준:

  • 18:05:21 예약 작업 시작
  • 18:05:21 KRX 수급분석 시도
  • 18:05:29 summary JSON 생성 확인
  • 이후 마감시황 작성 시작

logs/krx_attempt_1.log 기준:

  • 전종목 시세, 외국인, 기관, 연기금 엑셀 4종 다운로드 성공
  • 순매수분석_20260609.xlsx 저장 성공
  • 순매수분석_20260609_summary.json 저장 성공
  • 검증 통과
  • 미분류 없음

생성 파일:

  • /home/nirvana/프로젝트/투자자별데이터/data_0001_20260609 종목시세.xlsx
  • /home/nirvana/프로젝트/투자자별데이터/순매수분석_20260609.xlsx
  • /home/nirvana/프로젝트/투자자별데이터/순매수분석_20260609_summary.json

systemd 서비스는 Codex CLI 인자 오류로 실패

journalctl --user -u market-close-20260609.service 기준:

  • 18:05:21 서비스 시작
  • 18:05:29 status=2/INVALIDARGUMENT
  • 결과 exit-code

첫 stderr:

error: unexpected argument '--search' found
Usage: codex exec [OPTIONS] [PROMPT]

의미:

  • 최초 래퍼가 codex exec --search ... 형태로 실행됐다.
  • 현재 Codex CLI 0.137.0에서 --searchexec 하위 옵션이 아니라 최상위 옵션이다.
  • 따라서 올바른 형태는 codex --search -a never exec ... 이다.

첫 번째 재시도 stderr:

error: unexpected argument '-a' found
Usage: codex exec [OPTIONS] [PROMPT]

의미:

  • --search 위치만 고치고 -a never를 여전히 exec 뒤에 둔 재시도였을 가능성이 높다.
  • -a/--ask-for-approval도 최상위 옵션이므로 exec 앞에 와야 한다.

두 번째 재시도 stderr:

Error: failed to initialize in-process app-server client: Read-only file system (os error 30)

의미:

  • 이미 Codex 샌드박스 안에서 다시 Codex CLI를 실행하면서, CLI 초기화가 쓰기 불가능한 경로를 건드렸다.
  • 이 문제는 systemd host 실행과는 별개로, "Codex 안에서 Codex를 다시 실행하는 수동 재시도"의 구조적 취약점이다.

세 번째 재시도는 실행 자체는 시작했지만, 완성까지 가지 못했다.

  • KRX 지수 MCP가 2026년 6월 9일 데이터를 주지 못하고 2026년 6월 8일로 fallback
  • 키움 테마 API는 단말 인증 오류
  • 기본 python3 환경에는 openpyxl, pandas, xlsx2csv가 없어 원천 엑셀을 직접 XML로 파싱
  • 뉴스 조회가 다수 반복

이 때문에 작성 시간이 길어졌고, 수동 작성으로 전환했다.

왜 "전에는 문제 없었는데 오늘만" 문제가 났나

이전 마감시황은 보통 현재 Codex 세션에서 스킬을 직접 읽고, 필요한 MCP와 로컬 파일을 직접 다루는 방식이었다.

오늘은 다르다.

  • 18:05 예약 실행을 위해 새 systemd --user 일회성 타이머를 만들었다.
  • 이 타이머가 shell script를 실행했다.
  • shell script가 다시 별도 codex exec 프로세스를 호출했다.

즉, 기존 마감시황 스킬을 바꾼 것이 아니라, 그 스킬을 자동으로 호출하기 위한 새 실행 래퍼가 추가됐다. 실패는 이 새 래퍼에서 발생했다.

재발 가능성

1. Codex CLI 옵션 위치 오류

현재 해당 스크립트는 codex --search -a never exec ... 형태로 수정되어 있어 같은 파일을 그대로 쓰면 재발 가능성은 낮다.

다만 새 날짜용 예약 스크립트를 다시 만들 때 사람이 직접 명령을 조립하면 재발 가능성은 중간 이상이다. codex exec --search, codex --search exec -a never처럼 잘못 놓기 쉽다.

회피 방법:

  • 매번 직접 조립하지 말고 공통 runner 함수로 고정한다.
  • 실행 전 codex --search -a never exec --help 또는 dry-run 수준의 사전 검사를 한다.
  • stderr에 unexpected argument가 나오면 즉시 실패로 보고하고, 5분 재시도가 아니라 명령 자체를 고친다.

2. Codex 안에서 Codex를 다시 실행하는 문제

재발 가능성은 높다.

현재 작업 환경은 Codex 샌드박스가 적용되어 있고, 별도 Codex CLI는 초기화 과정에서 PATH, app-server, 세션 파일, 임시 디렉터리를 건드릴 수 있다. 샌드박스 안에서 다시 Codex를 띄우면 read-only 초기화 오류가 날 수 있다.

회피 방법:

  • 자동화는 systemd host 환경에서 직접 실행한다.
  • 이미 Codex 세션 안에서 수동 복구할 때는 codex exec를 다시 호출하지 않는다.
  • 수동 복구는 현재 세션에서 직접 파일 생성, 로컬 venv Python, 검증 스크립트 실행으로 처리한다.

3. 외부 데이터 지연 또는 fallback

재발 가능성은 높다.

마감 직후에는 KRX 지수 MCP가 당일 지수를 못 주고 전일로 fallback될 수 있다. 오늘도 2026년 6월 9일 요청에 2026년 6월 8일 값이 반환됐다. 키움 테마 API도 인증 상태에 따라 실패할 수 있다.

회피 방법:

  • KRX 원천 종목시세 엑셀을 1차 기준으로 둔다.
  • 지수 MCP는 fallback_used=true이면 보고서 숫자에 사용하지 않는다.
  • 키움 테마 API가 실패하면 이미지 입력 자료, 수급 summary JSON, KRX 원천 종목시세, 뉴스만으로 작성한다.
  • fallback 여부를 보고서 참고 자료 또는 로그에 남긴다.

4. 기본 Python 의존성 문제

재발 가능성은 중간 이상이다.

오늘 별도 Codex 프로세스 안에서는 기본 python3openpyxlpandas가 없어 원천 엑셀 파싱이 지연됐다. 반면 KRX 파이프라인 venv에는 필요한 패키지가 있다.

회피 방법:

  • 모든 마감시황 자동화에서 Python은 /home/nirvana/Codex_Project/morning_report_bot/.venv/bin/python3.14로 고정한다.
  • 보고서용 시장 폭, 주요 종목, 이미지 종목 등락률 추출 스크립트를 venv 기반으로 만든다.
  • LLM에게 원천 xlsx를 직접 열게 하지 말고, 사전 계산된 JSON을 넘긴다.

5. 특징주 중복 제외 규칙 누락

재발 가능성은 높다.

오늘 최초 수동 작성본은 이미지 내용을 일부 반영했지만, 사용자가 준 핵심 규칙인 "위에서 이미 언급된 종목은 특징주에서 제외"를 완전히 지키지 못했다. 특히 테크윙, 미래에셋생명이 수급 분석 브리핑에 이미 있었는데 특징주에도 들어갔다.

현재 validate_report.py는 금지어, 파일명, 주요 종목 개수, 참고 자료 존재 정도만 검사한다. 특징주가 이미지 기준인지, 중복 종목을 제외했는지는 검사하지 않는다.

회피 방법:

  • 이미지 입력 종목을 구조화 JSON으로 보관한다.
  • 본문 상단, 주요 종목, 수급 브리핑에 등장한 종목명을 집합으로 만든다.
  • ● 특징주 종목이 그 집합에 포함되면 검증 실패로 처리한다.
  • 이미지 테마 배경 문구가 누락되거나 변형이 과하면 경고를 낸다.

권장 재설계

단기

  1. 예약 래퍼의 Codex 호출 형태를 고정한다.
    • 올바른 형태: codex --search -a never exec ...
  2. run_closing_report 뒤에 검증 스크립트를 반드시 실행한다.
  3. 생성 파일이 없거나 검증 실패하면 서비스 exit code를 실패로 남긴다.
  4. 마감시황 자동화 로그 마지막에 다음을 출력한다.
    • KRX 완료 여부
    • 마감시황 파일 생성 여부
    • 검증 통과 여부
    • fallback 데이터 사용 여부

중기

  1. prepare_closing_context.py를 만든다.
    • KRX 원천 종목시세에서 시장 폭, 시장별 시총 집계 등락률, 주요 종목 등락률 추출
    • 수급 summary JSON에서 수급 문단 생성
    • 이미지 입력 테마와 종목을 JSON으로 구조화
    • 이미 언급될 종목과 특징주 후보를 분리
  2. Codex에는 원천 파일이 아니라 사전 계산된 context JSON만 넘긴다.
  3. validate_report.py에 다음 검증을 추가한다.
    • 특징주 중복 종목 금지
    • 이미지 테마 배경 반영 여부
    • fallback_used=true인 MCP 지수값 사용 금지

장기

LLM이 직접 보고서를 처음부터 조립하는 방식을 줄이고, 데이터 추출과 검증은 deterministic script가 맡아야 한다.

권장 구조:

systemd timer
  -> KRX 수급분석 파이프라인
  -> prepare_closing_context.py
  -> report renderer 또는 Codex with context JSON
  -> validate_report.py
  -> validate_feature_stocks.py
  -> 성공/실패 로그 및 알림

이렇게 하면 외부 MCP 지연, Python 의존성, 특징주 중복 같은 문제가 보고서 생성 전에 잡힌다.

최종 판단

오늘 실패의 직접 원인은 새 예약 래퍼의 Codex CLI 인자 위치 오류다. 기존 마감시황 작성 규칙이나 KRX 수급분석은 정상이었다.

하지만 재발을 막으려면 단순히 명령 한 줄만 고치는 것으로 부족하다. 마감 직후 데이터 fallback, Codex 중첩 실행, 기본 Python 의존성, 특징주 중복 검증 부재까지 모두 자동화 실패 요인으로 봐야 한다.

가장 안전한 회피책은 마감시황 자동화에서 "데이터 추출·중복 필터·검증"을 스크립트화하고, LLM은 이미 정리된 context를 바탕으로 문장 작성만 하게 만드는 것이다.