diff --git a/CLAUDE.md b/CLAUDE.md index 9fce4c34..605f4ace 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -393,6 +393,7 @@ troubleshooting table: [docs/DEV_WORKFLOWS.md](docs/DEV_WORKFLOWS.md) - **Python-to-.NET transition**: Legacy `ops:data-collect` remains until .NET collection validated in production (est. Q3 2026). - **Gitea Actions limitation**: Act runner ↔ Gitea network issues (workaround: manual SSH deployment active). - **도구 버전 관리 (2026-07-30)**: `_v1`/`_v2`... 접미사로 새 버전의 도구를 추가할 때, 이전 버전이 더 이상 쓰이지 않으면 삭제한다 — git 히스토리로 충분하다. 병행 존재 금지(예: `apply_engine_upgrade_v4.py`와 `_v7.py`가 동시에 남아있는 상태). 단, 다른 파일이 옛 버전을 이름으로 참조 중이면(lint 화이트리스트, 문서 등) 그 참조부터 정리한 뒤 삭제한다. +- **2026-07-30 전략 감사 세션 인수인계**: 미해결 항목(release DAG 전체 미검증, `engine_history`/`quantengine` 스키마 중복, OpenDART/KRX 미배선)과 재발 방지 트랩(문서 archive 전 `tools/`·`spec/`·`tests/` 전수 검색 필수, DbUp 정렬 버그 수정 완료, `runtime/`은 이력 데이터라 스크래치 출력 금지 등) — [docs/SESSION_HANDOFF_2026-07-30.md](docs/SESSION_HANDOFF_2026-07-30.md) 참고. ### Reliability & Data Quality diff --git a/docs/SESSION_HANDOFF_2026-07-30.md b/docs/SESSION_HANDOFF_2026-07-30.md new file mode 100644 index 00000000..936c588b --- /dev/null +++ b/docs/SESSION_HANDOFF_2026-07-30.md @@ -0,0 +1,60 @@ +# 2026-07-30 QuantEngine 전략 감사 세션 — 인수인계 + +19개 원칙(SOLID, 정공법, 홀루시네이션, 재현성, 데이터정합성, 과유불급, 정규화/역정규화, +프로세스 단순화, 패턴화, 표준화, 구조화, 바이브코딩, 현장감, 이력성, 안정성, 고도화, +컴포넌트화, 기술부채) 기준으로 저장소를 감사하고 발견된 문제를 수정한 세션의 기록이다. +8개 커밋이 `main`에 반영·푸시됐다 (HEAD: `823a9a6`). 무엇이 바뀌었는지는 `git log`가 +권위 있는 출처이니 여기서 반복하지 않는다 — 이 문서는 **커밋 로그만 봐서는 알 수 없는 +맥락**(미해결 항목, 판단 근거, 재발 방지 트랩)만 담는다. + +## 미해결 / 다음에 이어갈 것 + +- **전체 release DAG(`npm run ops:validate` / `full-gate`)를 끝까지 검증하지 못함.** + `GatherTradingData.xlsx`(gitignore 대상, 실거래 데이터 시드)가 이 개발 환경에는 없어서 + `convert_xlsx` 노드에서 막힌다. 이 파일이 있는 실제 환경(사용자 로컬 또는 운영 서버)에서 + 한 번 돌려서 이번 세션의 변경사항이 데이터 수집 경로를 깨지 않았는지 최종 확인 필요. +- **`docs/db/quantengine.dbml`의 `engine_history` vs `quantengine` 스키마 동명 테이블 4개** + — 실제 .NET 호출부를 grep으로 대조해 "둘 다 살아있는 서로 다른 모델"로 확정하고 DBML에 + 근거를 남겼지만, 코드 통합/리네임은 하지 않았다. "정리해달라"는 요청이 오면 DBML의 + `V8: PostgreSQL History-First Operating Model` 섹션 노트부터 다시 읽을 것 — 죽은 코드로 + 섣불리 판단하지 말 것. +- **OpenDART는 배선만 맞춰뒀고 실제로 호출하는 워크플로우가 아직 없다.** 환경변수명은 + `OPENDART_OPENAPI_KEY`로 코드·Gitea Secrets 양쪽 통일 완료. 나중에 + `tools/ingest_fundamental_raw.py`를 CI에서 처음 호출할 때는 별도 매핑 없이 + `secrets.OPENDART_OPENAPI_KEY`를 그 job의 `env:`에 바로 연결하면 된다. +- **KRX Open API는 구현이 전혀 없다** — CLAUDE.md에 환경변수명(`KRX_OPENAPI_KEY`, 실제 + Gitea Secrets 이름과 일치)만 예약해뒀다. 호출 한도 등은 사용자가 알려주지 않아 기록하지 + 않았다 — 추측해서 채우지 말 것. + +## 이번 세션에서 걸린 함정 — 재발 방지 + +- **문서를 "오래됐다"고 archive하기 전에 `tools/*.py`, `spec/*.yaml`, `tests/*.py`, + `.gitea/workflows/*.yml`까지 전부 grep할 것** — 다른 문서/CLAUDE.md만 검색해서는 부족하다. + `docs/ROADMAP_WBS.md`와 `docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md`를 이 방식으로 archive + 했다가, 실제로는 release gate 검증기와 `ci-frontend.yml`의 Enterprise Contract Parity + Test가 그 경로를 직접 참조하고 있어서 되돌려야 했다. 지금은 이 두 파일 다시 원위치, 검증기 + 3개 직접 실행해서 통과 확인 완료. +- **DbUp 마이그레이션은 파일명을 순수 문자열로 정렬한다** — `V10__`이 `V2__`보다 먼저 + 정렬되는 문제가 있었다. `MigrationScriptNameComparer`(이번 세션에 추가, `DbMigrator.cs`에 + 연결)로 해결됨 — 새 마이그레이션은 zero-padding 없이 다음 정수만 쓰면 된다. +- **`runtime/`은 대부분 git 추적되는 이력 데이터다** (`refactor_baseline_v*.yaml`, + `rollback_manifest_v*.yaml` 등) — 스크래치 공간이 아니다. 확인용 명령의 `--out`을 + 실수로 이 경로로 잡아서 이력 파일 2개를 덮어썼다가 `git diff`로 발견하고 + `git checkout --`으로 복구했다. 1회성 도구 출력은 `/tmp/` 등으로 보낼 것. +- **이 머신에 Python이 두 개 설치돼 있다** — `python`(3.11, 대부분의 서브프로세스가 + 실제로 쓰는 것)과 `python3`(3.14). 한쪽에 패키지를 설치해도 다른 쪽엔 없다. +- **repository entropy 감사(`audit_repository_entropy_v2.py`)가 git 추적 파일이 아니라 + 로컬 디스크 전체를 세고 있었다** — `.gitignore`와 제외 목록이 어긋나 있어 로컬 빌드 한 번에 + 4,523개까지 부풀었다(예산 2,200). `.gitignore`와 일치하도록 제외 목록을 갱신해 재발을 + 막았다 (`tools/audit_repository_entropy_v1.py`). 이 게이트가 다시 실패하면 먼저 "새로운 + 미추적 빌드 산출물 디렉터리가 생겼나"부터 확인할 것 — 바로 대규모 파일 삭제로 가지 말 것. + +## 이번 세션에서 확립된 작업 방식 + +- 작업 라운드가 끝나면 다음에 할 만한 구체적인 후보를 먼저 제안한다 (사용자가 같은 지시를 + 반복해서 보내는 걸 방지). +- 단순 기계적 조사/위임은 `model: "haiku"`로, 판단이 필요한 작업만 Sonnet급으로. +- 커밋/푸시는 명시적으로 요청받았을 때만, 항상 경로를 지정해서 스테이징(`git add -A` 금지), + 세션 시작 전부터 있던 무관한 변경사항은 요청 없이는 포함하지 않는다. +- 채팅에 붙여넣어진 실제 API 키(KIS, OpenDART, KRX)는 어떤 파일에도 적지 않는다 — 환경변수 + *이름*만 기존 KIS 관례(환경변수/Gitea Secrets 전용, 하드코딩 금지)에 맞춰 기록한다.