하네스 규칙 검사 전역 위반 117→0, 회차별 검증(code-verifier opus 4도메인)으로 Critical/High 해소. 주문·리스크 - MDD 강제축소 반복 매도(종목별 완료 집합·재시도 상한·날짜 롤오버·잔고 오류 보류·epoch·장외 미주문) - KIS 거부 FAILED 기록, 결과 불명(전송 후) 재전송 금지·PENDING, 미전송 실패만 재시도(msg_cd 분류) - 국내 전량·손실 매도 시장가, 부분 익절 직전 현재가, 지정가만 미체결 취소(cancel_order_v2: TR 0013U·조직번호) + 0체결 롤백 - 누적 4%·현금·레버리지(신규분 포함)·사이클 내 매수 누적, 수동매수 공용 가드(buy_guards), 수동매도 DT 차감·락 - 가드 우회 엔드포인트 차단(/recommendations/auto-trade 위임, US /execute 매수 410·매도 가드) - 매수 슬롯=성공 매수, 평가 상한·회전, 업무거부/계좌 쿨다운, 프로세스 내 in-flight 주문 중복 차단 데이트레이딩 - 진입·청산 shield, 청산 진행 중 표식(소유 토큰), 2단계 청산 체크, 결과 불명 → 보유 감소 판정·비DT 차감 상한 - 전일 포지션 재시도(일시 실패 미산정), 분할매도 영속, ORB 구간 손절, /cycle 락, 사이클 내 현금 차감, 체결 수량 보정 스윙 - 손절 공백(판정 예외 시 하드 바닥), 단일 손절 소스·범위 검증, 매도 직전 KIS 잔고 상한(min(주문가능,보유)−DT) - 결과 불명 체결 대조·장부 반영, 대체가(나이·진입 이후·ATR 캐시), 분할 단계 기록, 국면 실패 fail-closed - 듀얼 플레이북·서킷브레이커 게이트, 평균회귀 우선·듀얼 독립, 시간손절 거래일 - 거래 확대(사용자 결정, 백테스트 미검증): RSI 46/35 정본 경로, 모멘텀 v2 ON, SIDEWAYS ADX AND, 트레일링 1차 익절 후, 20일 시간손절 ON 인프라·보안 - 계좌·손익 GET 인증, 세션 is_active·관리자 경로, 서명키 파생, realip, WS 토큰 마스킹 - KIS 토큰 즉시 실패(sleep 제거)·무효 시 캐시 삭제, 주문 5xx+JSON 본문 반환 - db_worker 종료 drain(멱등 재실행·커밋 불명 격리·예산·밴 커밋), stop_grace 40s, Redis 타임아웃·volatile-lru, /health DLQ·캐시 - KRX 휴장일, py3.11 비호환 f-string 수정 + Jenkins 이미지 내 compileall·헬스 실패 시 빌드 실패 하네스: rules_check 에 PEP 701 f-string 검사, 마커(allow-*), deploy 스모크 401 기준 CLAUDE.md: 실제 동작·플래그·백로그(§8.5-27~38) 갱신 backend 1451 passed / hooks 112 passed / tsc ok / py3.9 compile 0 errors Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
2.2 KiB
Bash
Executable File
44 lines
2.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# 운영 스모크 — GET 전용, API 키 없이 호출. KIS/주문 경로 호출 없음.
|
|
# - PUBLIC : 키 없이 200 + 유효 JSON 이어야 한다 (공개 시장 데이터)
|
|
# - AUTH : 키 없이 401 이어야 한다 (계좌·손익·리스크 상태). 200 이면 **노출 회귀**로 FAIL,
|
|
# 5xx/000 이면 기동 실패로 FAIL. (2026-10-02 H-1: journals/analysis 가 키 없이 응답하던 결함)
|
|
# 사용: .claude/scripts/prod_smoke.sh (환경변수 PROD_BASE_URL 로 대상 변경 가능)
|
|
set -u
|
|
BASE="${PROD_BASE_URL:-https://stock.shium.net}"
|
|
PUBLIC_ENDPOINTS=(
|
|
"/api/v1/market/indices"
|
|
)
|
|
AUTH_ENDPOINTS=(
|
|
"/api/v1/journals/stats"
|
|
"/api/v1/analysis/performance"
|
|
"/api/v1/market-intelligence/dashboard"
|
|
)
|
|
fail=0
|
|
echo "== 운영 스모크 ($BASE) $(TZ=Asia/Seoul date '+%Y-%m-%d %H:%M:%S KST') =="
|
|
probe() { # $1=kind(PUBLIC|AUTH) $2=endpoint
|
|
local kind="$1" ep="$2" tmp out code secs bytes valid mark
|
|
tmp="$(mktemp)"
|
|
out="$(curl -s -o "$tmp" -w '%{http_code} %{time_total}' --max-time 15 "$BASE$ep" 2>/dev/null)" || out="000 0"
|
|
code="${out%% *}"; secs="${out##* }"
|
|
bytes="$(wc -c < "$tmp" | tr -d ' ')"
|
|
valid="-"
|
|
if [ "$kind" = "PUBLIC" ]; then
|
|
if command -v python3 >/dev/null 2>&1 && [ "$code" = "200" ]; then
|
|
python3 -c 'import json,sys; json.load(open(sys.argv[1]))' "$tmp" 2>/dev/null && valid="json-ok" || valid="json-INVALID"
|
|
fi
|
|
if [ "$code" = "200" ] && [ "$valid" != "json-INVALID" ]; then mark="OK "; else mark="FAIL"; fail=1; fi
|
|
else
|
|
if [ "$code" = "401" ]; then mark="OK "; valid="auth-enforced"
|
|
elif [ "$code" = "200" ]; then mark="FAIL"; valid="LEAK(키 없이 200)"; fail=1
|
|
else mark="FAIL"; fail=1; fi
|
|
fi
|
|
printf '%s %-6s %s http=%s %ss %sB %s\n' "$mark" "$kind" "$ep" "$code" "$secs" "$bytes" "$valid"
|
|
if [ "$mark" = "FAIL" ] && [ "$code" != "200" ]; then head -c 200 "$tmp" | sed 's/^/ /'; echo; fi
|
|
rm -f "$tmp"
|
|
}
|
|
for ep in "${PUBLIC_ENDPOINTS[@]}"; do probe PUBLIC "$ep"; done
|
|
for ep in "${AUTH_ENDPOINTS[@]}"; do probe AUTH "$ep"; done
|
|
[ "$fail" = 0 ] && echo "== 스모크 통과 ==" || echo "== 스모크 실패 — Jenkins 로그/컨테이너 상태 확인 (LEAK 이면 인증 회귀) =="
|
|
exit "$fail"
|