diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md index 90edcf4..87db156 100644 --- a/.gitea/PULL_REQUEST_TEMPLATE.md +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -8,6 +8,13 @@ - TASK: `TASK-...` - TEST: `TEST-...` +## Docs Sync (SSOT) + +- [ ] `docs/README.md` 라우팅/역할 영향 여부 확인 +- [ ] SSOT 문서(architecture/commands/testing/ouroboros registry) 업데이트 또는 "변경 없음" 명시 +- [ ] 요약 문서(`README.md`, `CLAUDE.md`)에 가변 수치 하드코딩 추가 없음 +- SSOT 반영 위치(링크): + ## Ticket Stage - Current stage: `Implemented` / `Integrated` / `Observed` / `Accepted` diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 9fa9522..63d5a67 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -47,6 +47,9 @@ jobs: - name: Validate Ouroboros docs run: python3 scripts/validate_ouroboros_docs.py + - name: Validate docs sync + run: python3 scripts/validate_docs_sync.py + - name: Lint run: ruff check src/ tests/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da84fc7..a8ace16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,9 @@ jobs: - name: Validate Ouroboros docs run: python3 scripts/validate_ouroboros_docs.py + - name: Validate docs sync + run: python3 scripts/validate_docs_sync.py + - name: Lint run: ruff check src/ tests/ diff --git a/CLAUDE.md b/CLAUDE.md index 9387fa9..861d9a7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,10 @@ AI-powered trading agent for global stock markets with self-evolution capabilities. +## Documentation Entry + +문서 우선순위/역할은 [docs/README.md](docs/README.md)를 기준으로 한다. + ## Quick Start ```bash @@ -83,7 +87,7 @@ SCANNER_TOP_N=3 # Max candidates per scan ### Trading Mode Integration -Smart Scanner runs in both `TRADE_MODE=realtime` and `daily` paths. On API failure, domestic stocks fall back to a static watchlist; overseas stocks fall back to a dynamic universe (active positions, recent holdings). +Smart Scanner behavior and mode integration are defined in [docs/architecture.md](docs/architecture.md). ## Documentation @@ -122,7 +126,7 @@ src/ ├── broker/ # KIS API client (domestic + overseas) ├── context/ # L1-L7 hierarchical memory system ├── core/ # Risk manager (READ-ONLY) -├── dashboard/ # FastAPI read-only monitoring (10 API endpoints) +├── dashboard/ # FastAPI read-only monitoring (endpoint details: docs/commands.md) ├── data/ # External data integration (news, market data, calendar) ├── evolution/ # Self-improvement (optimizer, daily review, scorecard) ├── logging/ # Decision logger (audit trail) @@ -133,7 +137,7 @@ src/ ├── main.py # Trading loop orchestrator └── config.py # Settings (from .env) -tests/ # 998 tests across 41 files +tests/ # Test suite (details: docs/testing.md) docs/ # Extended documentation ``` diff --git a/README.md b/README.md index 587ac0c..5aa8bf9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ KIS(한국투자증권) API로 매매하고, Google Gemini로 판단하며, 자체 전략 코드를 TDD 기반으로 진화시키는 자율 주식 트레이딩 에이전트. +## 문서 네비게이션 + +문서 전체 라우팅/역할/우선순위는 [docs/README.md](docs/README.md)를 기준으로 본다. + ## 아키텍처 ``` @@ -39,7 +43,7 @@ KIS(한국투자증권) API로 매매하고, Google Gemini로 판단하며, 자 | 컨텍스트 | `src/context/` | L1-L7 계층형 메모리 시스템 | | 분석 | `src/analysis/` | RSI, ATR, Smart Volatility Scanner | | 알림 | `src/notifications/` | 텔레그램 양방향 (알림 + 9개 명령어) | -| 대시보드 | `src/dashboard/` | FastAPI 읽기 전용 모니터링 (10개 API) | +| 대시보드 | `src/dashboard/` | FastAPI 읽기 전용 모니터링 (엔드포인트 목록은 `docs/commands.md`) | | 진화 | `src/evolution/` | 전략 진화 + Daily Review + Scorecard | | 의사결정 로그 | `src/logging/` | 전체 거래 결정 감사 추적 | | 데이터 | `src/data/` | 뉴스, 시장 데이터, 경제 캘린더 연동 | @@ -153,19 +157,10 @@ docker compose up -d ouroboros ## 테스트 -998개 테스트가 41개 파일에 걸쳐 구현되어 있습니다. 최소 커버리지 80%. +테스트 정책/실행/구성은 [docs/testing.md](docs/testing.md)를 기준으로 한다. -``` -tests/test_main.py — 거래 루프 통합 -tests/test_scenario_engine.py — 시나리오 매칭 -tests/test_pre_market_planner.py — 플레이북 생성 -tests/test_overseas_broker.py — 해외 브로커 -tests/test_telegram_commands.py — 텔레그램 명령어 -tests/test_telegram.py — 텔레그램 알림 -... 외 35개 파일 ※ 파일별 수치는 CI 기준으로 변동 가능 -``` - -**상세**: [docs/testing.md](docs/testing.md) +- 최소 커버리지: 80% +- 전체 수집 기준: `pytest --collect-only -q` ## 기술 스택 @@ -174,7 +169,7 @@ tests/test_telegram.py — 텔레그램 알림 - **AI**: Google Gemini Pro - **DB**: SQLite (5개 테이블: trades, contexts, decision_logs, playbooks, context_metadata) - **대시보드**: FastAPI + uvicorn -- **검증**: pytest + coverage (998 tests) +- **검증**: pytest + coverage (`docs/testing.md` 기준) - **CI/CD**: Gitea CI (`.gitea/workflows/ci.yml`) - **배포**: Docker + Docker Compose @@ -209,7 +204,7 @@ The-Ouroboros/ │ ├── config.py # Pydantic 설정 │ ├── db.py # SQLite 데이터베이스 │ └── main.py # 비동기 거래 루프 -├── tests/ # 998개 테스트 (41개 파일) +├── tests/ # 테스트 스위트 (세부는 docs/testing.md 참조) ├── Dockerfile # 멀티스테이지 빌드 ├── docker-compose.yml # 서비스 오케스트레이션 └── pyproject.toml # 의존성 및 도구 설정 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..169d6a3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +# Documentation Map + +이 문서는 저장소 문서의 단일 라우팅/역할 정의다. +각 문서는 아래 역할 범위를 넘지 않는다. + +## Reading Order + +1. [Project README](../README.md): 빠른 시작, 개요 +2. [Architecture](architecture.md): 시스템 구성/데이터 흐름 +3. [Workflow](workflow.md): 개발/PR/검증 절차 +4. [Commands](commands.md): 실행/운영 명령 레퍼런스 +5. [Testing](testing.md): 테스트 전략/작성/운영 +6. [Ouroboros Hub](ouroboros/README.md): 기획/요구사항/실행 통제 문서군 + +## Single Source of Truth (SSOT) + +- 아키텍처/동작 기준: [Architecture](architecture.md) +- 실행 명령 기준: [Commands](commands.md) +- 테스트 정책 기준: [Testing](testing.md) +- 요구사항/REQ 기준: [Requirements Registry](ouroboros/01_requirements_registry.md) +- 작업/TASK 기준: [Code Work Orders](ouroboros/30_code_level_work_orders.md) +- 수용/TEST 기준: [Acceptance Plan](ouroboros/40_acceptance_and_test_plan.md) + +## Authoring Rules + +- `README.md`, `CLAUDE.md`는 입문/요약 역할만 가진다. +- 가변 수치(테스트 개수, API 개수, 세부 파일별 케이스 수)는 요약 문서에 고정값으로 중복 기재하지 않는다. +- 수치/정책 상세는 SSOT 문서에만 기록하고, 요약 문서에서는 링크로 참조한다. +- 동일 내용이 2개 이상 문서에 반복되면 요약 + 링크 형태로 축약한다. diff --git a/docs/commands.md b/docs/commands.md index a667230..30fcbf5 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -136,9 +136,12 @@ No decorator needed for async tests. # Install all dependencies (production + dev) pip install -e ".[dev]" -# Run full test suite with coverage (998 tests across 41 files) +# Run full test suite with coverage pytest -v --cov=src --cov-report=term-missing +# Validate docs sync rules (SSOT/duplication guard) +python3 scripts/validate_docs_sync.py + # Run a single test file pytest tests/test_risk.py -v @@ -201,8 +204,8 @@ Dashboard runs as a daemon thread on `DASHBOARD_HOST:DASHBOARD_PORT` (default: ` | `GET /api/performance` | Performance metrics by market and combined | | `GET /api/context/{layer}` | Context data by layer L1-L7 (query: `timeframe`) | | `GET /api/decisions` | Decision log entries (query: `limit`, `market`) | +| `GET /api/pnl/history` | P&L history time series | | `GET /api/scenarios/active` | Today's matched scenarios | -| `GET /api/pnl/history` | P&L history over time | | `GET /api/positions` | Current open positions | ## Telegram Commands diff --git a/docs/ouroboros/82_doc_restructure_plan.md b/docs/ouroboros/82_doc_restructure_plan.md index 8bf0c84..2dcc4ff 100644 --- a/docs/ouroboros/82_doc_restructure_plan.md +++ b/docs/ouroboros/82_doc_restructure_plan.md @@ -1,96 +1,75 @@ -# 문서 재구조화 계획: 감사 → 실행 파이프라인 +# 문서 재구조화 실행 현황 -## Context +## 목적 -80_implementation_audit.md는 v2/v3 구현 감사와 수익률 분석을 수행했으나, 여러 차례 리뷰를 거치면서 리뷰 이력/데이터 품질 논의/SQL 쿼리 등이 혼재되어 **실행 문서로 사용하기 어려운 상태**다. +문서 중복/드리프트/탐색 난이도를 줄여, 에이전트가 문서 기반으로 기획/설계/구현/검증을 일관되게 수행하도록 운영 규칙을 고정한다. -목표: 이 감사 결과를 바탕으로 **티켓 생성 → 개발 설계 → 구현/리뷰 → 검증 → 실환경 테스트**까지 일관되게 진행할 수 있는 문서 체계를 만든다. +## 적용 범위 -## 변경 사항 +- 루트 요약 문서: `README.md`, `CLAUDE.md` +- 운영 문서: `docs/architecture.md`, `docs/commands.md`, `docs/testing.md`, `docs/workflow.md` +- 실행 통제 문서군: `docs/ouroboros/*` +- 검증 자동화: `scripts/validate_docs_sync.py`, CI 워크플로우 -### 1. 80_implementation_audit.md 정리 (감사 기록 문서) +## 완료 항목 (2026-03-01) -**역할**: 현재 상태의 팩트 기록. "무엇이 문제인가"에만 집중. +### 1) 문서 라우팅/역할 고정 -정리 내용: -- Section 3: P&L 분석을 핵심 수치만 남기고 간결화 - - 3.1(종합), 3.3(시장별), 3.4(통화 분리), 3.5(전략 진입분 분리), 3.6(무결성 결론) 유지 - - 3.2 일별 손익: 주의 문구 제거, 본문으로 통합 - - 3.7 데이터 품질: 핵심 결론만 남기고 세부 항목 제거 - - 3.8 SQL: 별도 파일(`scripts/audit_queries.sql`)로 분리, 본문에서 참조만 -- Section 6.1, 6.2 리뷰 반영 이력: 전부 제거 (git history로 추적 가능) -- Section 6 테스트: "재점검으로 확인" 항목을 "테스트 존재" 항목에 통합 -- 신규 Section 7: 후속 문서 링크 (85_ 참조) +- `docs/README.md` 신설 +- 읽기 순서 + SSOT + 작성 규칙 명시 -### 2. 85_loss_recovery_action_plan.md 신규 작성 (실행 계획 문서) +### 2) 요약 문서 중복 축소 -**역할**: "어떻게 고칠 것인가". 티켓 생성부터 실환경 검증까지의 실행 청사진. +- `README.md`, `CLAUDE.md`에 문서 진입점 추가 +- 가변 수치/세부 동작의 직접 중복 기재를 축약하고 SSOT 문서 링크 중심으로 정리 -구조: -``` -## 1. 요약 -- 목표: 손실 구간 탈출을 위한 7개 ROOT/5개 GAP 해소 -- 성공 기준 (정량) +### 3) 명령/테스트 문서 정합성 개선 -## 2. Phase별 작업 분해 -### Phase 1: 즉시 파라미터/로직 수정 (손실 출혈 차단) - 각 항목마다: - - ROOT/GAP 참조 - - Gitea 이슈 제목/설명 템플릿 - - 변경 대상 파일 + 현재 동작 + 목표 동작 - - 수용 기준 (acceptance criteria) - - 테스트 계획 - - 의존성/차단 관계 +- `docs/commands.md` 대시보드 API 목록 최신화(`pnl/history`, `positions` 포함) +- `docs/testing.md` 테스트 총량 확인 방식을 고정 수치 -> `pytest --collect-only -q`로 전환 -### Phase 2: 데이터 정합성 + v2 실효화 - (동일 형식) +### 4) 동기화 자동 검증 + CI 게이트 -### Phase 3: v3 세션 최적화 - (동일 형식) +- `scripts/validate_docs_sync.py` 추가 +- `.gitea/workflows/ci.yml`, `.github/workflows/ci.yml`에 `Validate docs sync` 단계 추가 +- `docs/commands.md`에 동기화 검증 명령 추가 -## 3. 검증 계획 -- 단위 테스트 기준 -- 통합 테스트 시나리오 (백테스트 파이프라인 활용) -- 실환경 검증: 소액 live 운용으로 직접 검증 - (paper trading 제외 — 실환경과 괴리가 커 검증 신뢰도 부족) -- Phase별 실환경 투입 기준: - 단위/통합 테스트 통과 → 소액 live → 모니터링 → 정상 확인 후 본운용 +## 잔여 작업 -## 4. 의존성 그래프 -- Phase 간 blocking 관계 -- Phase 내 작업 순서 +### A) SSOT 강제 범위 확장 +- `README.md`/`CLAUDE.md`의 남은 동작 설명을 더 축약하고 상세는 `docs/architecture.md`로 일원화 +- `docs/testing.md`의 파일별 테스트 개수 스냅샷 자동 생성 여부 결정 -## 5. 롤백 계획 -- 각 Phase 실패 시 롤백 절차 -``` +### B) 검증 규칙 고도화 +- `validate_docs_sync.py`에 추가 패턴(중복 정책 문구/금지 숫자 표현) 확대 +- 필요 시 `docs/architecture.md`를 API/모드 동작의 유일한 근거 문서로 명시 -### 3. README.md 업데이트 +### C) 유지보수 운영화 +- 릴리즈/스프린트 종료 시 문서 동기화 점검 체크리스트 정례화 +- 문서 변경 PR 템플릿에 "SSOT 링크 업데이트 여부" 체크박스 추가 검토 -- 85_ 문서 링크 추가 +## 검증 상태 -## 작업 순서 +- `python3 scripts/validate_docs_sync.py`: PASS +- `python3 scripts/validate_ouroboros_docs.py`: PASS +- `python3 scripts/validate_governance_assets.py`: PASS -1. 80_ 정리 (노이즈 제거, SQL 분리, 리뷰 이력 삭제) -2. `scripts/audit_queries.sql` 작성 (80_에서 분리한 SQL) -3. 85_ 신규 작성 (실행 계획) -4. README.md 업데이트 +## 운영 규칙 -## 작성하지 않는 것 +- 문서 구조 변경 시 `docs/README.md`와 동기화 검증 규칙을 함께 갱신한다. +- 요약 문서는 "개요/진입점" 역할만 유지하고, 상세 사실/수치 정책은 SSOT 문서에만 기록한다. +- 가변 수치(테스트 개수, 엔드포인트 개수)는 자동 확인 명령 또는 SSOT 링크로 대체한다. -- 30_code_level_work_orders.md, 40_acceptance_and_test_plan.md 업데이트: 85_를 기반으로 실제 구현 시점에 업데이트 (지금은 실행 계획 수립까지만) -- 01_requirements_registry.md: ROOT/GAP에서 파생되는 신규 REQ는 구현 착수 시 등록 -- Gitea 이슈 생성: 85_ 문서 확정 후 별도 진행 +## 참조 -## 검증 - -- 80_: 감사 팩트만 남았는지, 리뷰 이력이 제거되었는지 확인 -- 85_: Phase별 작업이 Gitea 이슈로 바로 전환 가능한 수준인지 확인 -- 85_ 각 항목에 수용 기준과 테스트 계획이 포함되었는지 확인 +- 문서 허브: [docs/README.md](../../docs/README.md) +- 실행 문서 허브: [docs/ouroboros/README.md](./README.md) +- 동기화 검증 스크립트: [`scripts/validate_docs_sync.py`](../../scripts/validate_docs_sync.py) diff --git a/docs/testing.md b/docs/testing.md index e385697..efe291e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -2,7 +2,13 @@ ## Test Structure -**998 tests** across **41 files**. `asyncio_mode = "auto"` in pyproject.toml — async tests need no special decorator. +테스트 총량은 지속적으로 변동된다. 최신 수치는 아래 명령으로 확인한다. + +```bash +pytest --collect-only -q +``` + +`asyncio_mode = "auto"` in pyproject.toml — async tests need no special decorator. The `settings` fixture in `conftest.py` provides safe defaults with test credentials and in-memory DB. diff --git a/scripts/validate_docs_sync.py b/scripts/validate_docs_sync.py new file mode 100644 index 0000000..8ca5fb0 --- /dev/null +++ b/scripts/validate_docs_sync.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""Validate lightweight documentation synchronization rules.""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path + + +ROOT = Path(".") + + +def read_text(path: Path, errors: list[str]) -> str: + if not path.exists(): + errors.append(f"missing file: {path}") + return "" + return path.read_text(encoding="utf-8") + + +def main() -> int: + errors: list[str] = [] + + docs_index = ROOT / "docs" / "README.md" + readme = ROOT / "README.md" + claude = ROOT / "CLAUDE.md" + commands = ROOT / "docs" / "commands.md" + + docs_index_text = read_text(docs_index, errors) + readme_text = read_text(readme, errors) + claude_text = read_text(claude, errors) + commands_text = read_text(commands, errors) + + if docs_index_text and "Single Source of Truth" not in docs_index_text: + errors.append("docs/README.md: missing 'Single Source of Truth' section") + + if readme_text and "docs/README.md" not in readme_text: + errors.append("README.md: missing docs/README.md routing link") + if claude_text and "docs/README.md" not in claude_text: + errors.append("CLAUDE.md: missing docs/README.md routing link") + + # Prevent volatile hard-coded scale numbers in summary docs. + volatile_patterns: list[tuple[str, re.Pattern[str]]] = [ + ("README.md", re.compile(r"\b\d+\s*개 테스트\b")), + ("README.md", re.compile(r"\b\d+\s*tests\s+across\b", re.IGNORECASE)), + ("README.md", re.compile(r"\(\d+\s*개 API\)")), + ("README.md", re.compile(r"\(\d+\s*API endpoints?\)", re.IGNORECASE)), + ("CLAUDE.md", re.compile(r"\b\d+\s*tests\s+across\b", re.IGNORECASE)), + ("CLAUDE.md", re.compile(r"\(\d+\s*API endpoints?\)", re.IGNORECASE)), + ("docs/commands.md", re.compile(r"Run full test suite with coverage\s*\(\d+", re.IGNORECASE)), + ] + text_by_name = { + "README.md": readme_text, + "CLAUDE.md": claude_text, + "docs/commands.md": commands_text, + } + for name, pattern in volatile_patterns: + text = text_by_name.get(name, "") + if text and pattern.search(text): + errors.append(f"{name}: contains volatile hard-coded scale text ({pattern.pattern})") + + # Command doc should list all dashboard endpoints exposed by app.py. + for endpoint in ("/api/pnl/history", "/api/positions"): + if commands_text and endpoint not in commands_text: + errors.append(f"docs/commands.md: missing dashboard endpoint {endpoint}") + + if errors: + print("[FAIL] docs sync validation failed") + for err in errors: + print(f"- {err}") + return 1 + + print("[OK] docs sync validation passed") + return 0 + + +if __name__ == "__main__": + sys.exit(main())