박재오 발견: Kling 공식 API key 발급 (Access Key + Secret Key).
PiAPI gateway가 아닌 native api.klingai.com 사용.
변경:
- providers/kling.py: JWT 인증 (HS256, iss=access_key, exp=now+1800, nbf=now-5).
POST /v1/videos/text2video → GET /v1/videos/{kind}/{task_id} 폴링.
data.task_result.videos[0].url 다운로드.
text2video / image2video 자동 분기.
- .env.example: PIAPI_API_KEY → KLING_ACCESS_KEY + KLING_SECRET_KEY
- docker-compose: 같은 env 교체
- requirements.txt: + PyJWT>=2.8.0
박재오 측: .env에 두 키 모두 입력.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review found: getattr(sys.modules[__name__], fn_name) raises
AttributeError if a dispatch table string entry is a typo. Now caught
and reported via webhook_update_task as 'internal dispatch error'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NAS sync 함수 4종 이식: generate_lyrics, get_credits,
get_timestamped_lyrics, generate_style_boost.
NAS main.py가 httpx로 forward하여 호출.
Plan-B-Music Phase 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review found: non-200 response from /audio/ endpoint was silently
written as MP3 body → corrupt file. Match T5 suno.py download pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NAS music-lab/app/local_provider.py 이식. DB 호출 webhook 변환.
MusicGen 호스트는 host.docker.internal:8765 (Windows native).
결과 MP3는 /mnt/nas/webpage/data/music/에 직접 저장.
Plan-B-Music Phase 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review found: f"{task_id}_v2" / "_inst" synthetic task IDs never
exist in NAS music_tasks table -> webhook returns 404 -> silent fail.
NAS music-lab/main.py._sync_library_with_disk() auto-registers any
.mp3 in the disk that has no DB row on next GET /api/music/library.
So Windows worker just writes the file to SMB; NAS picks it up on
the next library fetch -- matches NAS source behavior at file level.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review found: test 5 accepted caplog fixture but never asserted on it
— silent regression risk if logger.exception is removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NAS DB 직접 접근 불가 → webhook_update_task/webhook_add_track으로 변환.
X-Internal-Key 헤더 자동 첨부. 실패 시 raise 안 함 (logger.error).
env var는 call time에 읽어 monkeypatch 테스트 호환성 확보.
Plan-B-Music Phase 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NAS GET /api/insta/slates/{id}는 cover_copy/body_copies/cta_copy를
이미 dict/list로 parse해서 반환 (main.py:193-198). 워커가 json.loads(dict)
시도하다 TypeError로 즉시 fail.
_coerce 헬퍼로 string / dict-list 둘 다 처리하도록 보완.
3 unit tests PASS (영향 없음).
Plan-B-Insta T15 fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Windows WSL2 Docker용. NAS Redis 6379 + NAS API 18700 호출.
/mnt/nas SMB 볼륨 마운트. INTERNAL_API_KEY는 NAS .env와 같은 값.
.env는 .gitignore (박재오 머신 로컬 보관).
Plan-B-Insta Phase 2 마무리.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lifespan에서 Browser pool init + worker_loop spawn. shutdown 시 정상 cleanup.
GET /health (LivenessProbe용).
Plan-B-Insta Phase 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Windows WSL2 Docker용 Chromium 워커 컨테이너 기본 골격.
다음 task에서 main.py, worker.py, card_renderer.py 작성.
Plan-B-Insta Phase 2 시작.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
박재오가 python process 4개 종료 후 file lock 해제 → 디렉토리 이동 완료.
DEPRECATED 마킹은 그대로, 코드는 legacy/ 아래 참조용 보존.
CLAUDE.md의 "이동 예정" → "이동 완료" 문구 갱신.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
박재오 결정 2026-05-19 — V2를 정식 명칭 ai_trade로 graduation,
V1은 deprecated 마킹 (legacy 디렉토리 이동은 file lock 풀린 후 후속).
변경 사항:
- signal_v2/ → ai_trade/ (git mv, import 일괄 sed: signal_v2.x → ai_trade.x)
- root start.bat → legacy/start_v1.bat (V1 자동 시작 차단)
- ai_trade/start.bat 내부 uvicorn target signal_v2.main → ai_trade.main
- signal_v1/DEPRECATED.md 추가 (사용 금지 명시)
- CLAUDE.md 디렉토리 표·서버 시작 방식 갱신
- services/ 디렉토리 미래 예정 (Plan-B-Insta 작업 시 신설)
ai_trade tests 59/59 PASS 확인.
signal_v1/ 디렉토리 자체 이동(legacy/signal_v1/)은 telegram_bot.log +
data/news_snapshots.db file lock으로 보류. lock 해제 후 후속 커밋.
후속 작업: Plan-B-Insta (services/insta-render + NAS insta 분할)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
portfolio 60s → 180s (3분 폴링 → 3회당 1회 fetch)
news-sent 300s → 600s (sentiment는 자주 안 바뀜)
screener 60s → 300s (Top-20 분 단위 변화 미미)
V2 재시작 시점부터 NAS stock에 대한 인바운드 호출이
분당 12 → 분당 3~4 로 감소 예상. 캐시 hit ratio 0~50% → 66~80%.
회귀 테스트 3건 추가로 미래 의도치 않은 TTL 변경 차단.
Also update test_stock_client.py fake_time assertions from 61.0 → 181.0
to match the new 180s portfolio TTL (tests were TTL-dependent).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
logger was declared but unused. Operational visibility was zero —
trader debugging 'why no signal?' had to step through code mentally.
- INFO on emit: '[signal emit] 005930 buy conf=0.823 rank=3' / sell with reason
- DEBUG on each skip path: same-cycle sell, hard gate, low confidence,
dedup 24h (buy and sell)
Per final reviewer recommendation. 56 tests still pass.
poll_loop now accepts dedup + settings kwargs (backwards-compatible defaults).
After each in-window cycle (stock pull + minute momentum + optional post-close),
generate_signals is called to populate state.signals for downstream Phase 5
pickup. main.py lifespan wires _ctx.dedup + settings into the poll_loop task.
1 integration test added (anomaly-free stop_loss path via direct generate_signals
call, exercises the same code path that poll_loop runs).
56 tests pass.
- generate_signals now evaluates sell before buy; buy candidates with a same-cycle
sell signal are skipped (resolves silent overwrite of state.signals[ticker]).
- Added test_sell_signal_triggers_on_anomaly_path covering _try_anomaly path
(previously 0% covered).
- Fixed stale test comment referencing deprecated relative spread formula.
- _check_buy_hard_gate uses dict.get(..., 0) for defense against partial upstream state.
- _compute_buy_confidence clamps screener_norm to >= 0 for future Top-N changes.
ChronosBoltPipeline.predict_quantiles takes `inputs` positional, not
`context` keyword. Use positional with TypeError fallback for older
chronos versions.
FP16 caused inf overflow on Korean stock prices (e.g. 280,000원 >
FP16 max 65,504). Force FP32 for prices to avoid this. Chronos model
itself handles internal scaling.
Verified end-to-end: 60-day daily fetch → Chronos predict → quantile
output. Example 005930: median=-0.59%, q10=-8.9%, q90=+6.4%, conf=0.0
(low conf is mathematically correct when median is near zero relative
to distribution width).
45/45 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ChronosBoltPipeline.predict() does not accept `context` kwarg; it
uses positional-only and is deterministic (no num_samples). Switch
to predict_quantiles(context, prediction_length, quantile_levels)
which returns (quantiles_tensor, mean_tensor).
Implementation: if hasattr(pipeline, "predict_quantiles") → modern
quantile branch. Else fall back to legacy sample-based predict (T5).
Tests: switch to predict_quantiles mock returning (quantiles, None)
with shape [1, 1, 3] for q10/q50/q90 directly.
45/45 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ChronosPipeline (legacy T5) does not support amazon/chronos-2 or
chronos-bolt-* (input_patch_size). Switch to BaseChronosPipeline
which auto-detects variant and returns the appropriate sub-pipeline
(ChronosBoltPipeline / Chronos2Pipeline / ChronosPipeline).
Also handle the dtype kwarg deprecation: try newer `dtype=` first,
fall back to `torch_dtype=` for older versions.
Test mock_pipeline fixture updated to patch BaseChronosPipeline.
45/45 tests pass. Verified amazon/chronos-bolt-base loads on CUDA.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TR_ID FHKST03010100 (수정주가 일봉). KIS returns descending; client
reverses to ascending and trims to last N days.
1 new test, 34 total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
_run_kis_minute_cycle: portfolio + screener union 종목 분봉 fetch +
screener-only 종목 호가 REST fetch. WebSocket callback factory
(make_asking_price_callback).
poll_loop / _run_polling_cycle 에 kis_client optional param 추가
(Phase 5 까지 None 일 때도 정상 동작).
2 new tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>