Commit Graph

611 Commits

Author SHA1 Message Date
ac4a574ef2 test(lotto-signals): floating-point 임계치 보정 + import 정리 + decide_fire 분리
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 02:36:32 +09:00
c985d2c605 test(lotto-signals): 메트릭 함수·adaptive baseline 단위 테스트
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 02:32:10 +09:00
b4e873b5b0 docs(plan): LottoAgent 능동성 확장 구현 plan (12 tasks, Phase 1-3)
Why: spec (2026-05-20-lotto-active-agent-design.md)을 12개 atomic task
(TDD: 테스트→fail→구현→pass→commit)로 분해. 24h 가동 검증 task 포함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 02:26:49 +09:00
6c5e93f64e docs(spec): LottoAgent 능동성 확장 설계 (능동 시그널·일일 요약)
Why: 매주 1회 무조건 큐레이션만 있는 현 구조를 다중 트리거+적응형
시그널 모니터링으로 확장. 좋은 수치(z≥1.5) 일 때만 텔레그램 보고.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 02:07:39 +09:00
6b7eb5a9c1 fix(deploy): register video-lab in deploy scripts (5 locations)
Plan-B-Video T6 가 docker-compose + nginx 만 등재했고 scripts/* 누락 →
deploy-nas.sh rsync가 video-lab/을 sync 안 함 →
NAS target 빈 context → docker buildkit "transferring dockerfile: 2B" →
"failed to read dockerfile: no such file or directory"

Fix:
- deploy-nas.sh SERVICES: + video-lab (rsync 대상)
- deploy.sh BUILD_TARGETS: + video-lab (docker compose build/up)
- deploy.sh CONTAINER_NAMES: + video-lab (orphan cleanup)
- deploy.sh HEALTH_ENDPOINTS: + video-lab (post-deploy health wait)
- deploy.sh DATA_DIRS: + video (단수형, /data/video volume mount)

memory feedback_nas_deploy_paths.md "depends_on 9개 lab 등재 완료" 패턴
정확히 이 케이스 경고했으나 plan T6에서 적용 누락. 메모리 → 10개 lab 갱신 예정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:59:51 +09:00
4b28ef3afa feat(nginx): /api/internal/video/ 3-layer 차단 (SP-8)
LAN(192.168.45.0/24) + Tailscale(100.64.0.0/10) + 127.0.0.1 allow.
deny all. X-Internal-Key forward → video-lab:8000.
insta/music 블록과 동일 패턴.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:33:37 +09:00
211aff1e45 docs(plan): Plan-B-Video port 18800 → 18801 (realestate-lab 충돌)
T6 implementer가 발견: realestate-lab이 이미 18800 점유.
video-lab 포트를 18801로 정정. plan 18 occurrence 일괄 변경.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:32:56 +09:00
37ca8e594e feat(video-lab): docker-compose entry + nginx routing (SP-8)
video-lab service: port 18801, REDIS_URL/INTERNAL_API_KEY env,
depends_on redis, /app/data volume mount.
nginx: /api/video/ proxy + /media/video/ direct serve alias.
frontend depends_on + volume mount 추가.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:31:37 +09:00
c9a094969d feat(video-lab): main.py — FastAPI + redis client + 2 endpoint (SP-8)
POST /api/video/generate (provider validation + Redis push + task_id 반환).
GET /api/video/tasks/{id} (DB 조회).
GET /api/video/providers (4 provider 메타).
SUPPORTED_PROVIDERS = sora/veo/kling/seedance.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:30:21 +09:00
e8dbf8092a feat(video-lab): /api/internal/video/update endpoint + tests (SP-8)
UpdatePayload schema (task_id/status/progress/message/video_url/error).
404 if task not found. insta/music-lab과 동일 패턴 + video_url 필드.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:29:05 +09:00
21cf0114f4 feat(video-lab): verify_internal_key + tests (SP-8)
X-Internal-Key 검증 dependency. insta-lab/music-lab 동일 패턴.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:27:38 +09:00
20f83cee33 feat(video-lab): app/db.py — video_tasks 테이블 + CRUD (SP-8)
WAL + busy_timeout 표준 fix. create_task / update_task / get_task.
provider 컬럼 추가(Sora/Veo/Kling/Seedance 구분). video_url 필드.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:26:19 +09:00
1e77123394 feat(video-lab): Dockerfile + requirements + app package skeleton (SP-8)
NAS video-lab 신설. python:3.12-alpine 기반. redis>=5.0 의존성.
영상 외부 호출 없음(gateway만) — 외부 API 의존 없음.
Plan-B-Video Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:24:50 +09:00
fbd8d26ec6 docs(plan): Plan-B-Video — video-lab 신설 + 4 provider Windows worker
SP-7 + SP-8 — 4 video provider (Sora 2, Veo 3.1, Kling via PiAPI, Seedance 2.0)
Windows video-render로 분산. NAS video-lab 신설 (port 18800).
spec §10 SP-7 갱신: 6 provider(Runway/Pika/Luma 포함) → 4 provider 축소
(박재오 2026-05-19 결정 — 실사용 provider만).

17 task: NAS video-lab 신설(1~6) → nginx 차단(7) → Windows video-render(8~14)
→ NAS push + 박재오 빌드(15) → Kling end-to-end(16) → 메모리 기록(17).

부록: 4 provider API 키 발급 가이드 (Sora/Veo/Kling/Seedance).
Plan-B-Music 3가지 함정 (WSL2 mirror + Redis chown + .env NAS_BASE_URL) 모두 사전 인지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:22:20 +09:00
6f505b8cb1 feat(nginx): /api/internal/music/ 3-layer 차단 (SP-6)
LAN(192.168.45.0/24) + Tailscale(100.64.0.0/10) + 127.0.0.1 allow.
deny all. X-Internal-Key forward → music-lab:8000.
insta 블록과 동일 패턴.
Plan-B-Music Phase 4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 05:24:41 +09:00
e1722e3963 refactor(music-lab): suno_provider/local_provider → stub (SP-6)
기존 13+1 외부 API 호출 함수는 web-ai/services/music-render/providers로 이식.
NAS는 SUNO_MODELS (정적 데이터)만 잔존. SUNO_API_KEY = "" sentinel.
Plan-B-Music Phase 3 (cutover 4/4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 05:22:05 +09:00
b1e28aa725 refactor(music-lab): batch_generator _generate_one_track → Redis push (SP-6)
기존 직접 run_suno_generation 호출 + asyncio.to_thread를
Redis push (queue:music-render, job_type=suno_generation) +
task 상태 polling 패턴으로 변경. 결과는 task_id로 music_library 조회.
Plan-B-Music Phase 3 (cutover 3/4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 05:19:41 +09:00
532b794c11 refactor(music-lab): sync helpers → Windows HTTP forward + cleanup (SP-6)
/api/music/{lyrics, credits, timestamped-lyrics, style-boost}
모두 sync_forward 모듈로 위임 → Windows :18711/api/music-render/sync/*.
SUNO_API_KEY가 NAS에 없으므로 직접 호출 불가.
run_*, generate_*, get_* import 제거 (Windows로 이전됨).
SUNO_MODELS만 잔존 (정적 데이터).

추가 cleanup (T11 reviewer 지적):
- _push_render_job의 datetime import를 모듈 상위로
- 11 endpoint의 unused BackgroundTasks 매개변수 제거

generate_batch: SUNO_API_KEY 체크를 os.getenv()로 전환 + 테스트 monkeypatch 갱신.

Plan-B-Music Phase 3 (cutover 2/4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 05:16:15 +09:00
e7f6edf7c5 refactor(music-lab): 13 background_tasks → Redis push (SP-6)
generate, extend, vocal-removal, cover-image, wav, stem-split,
upload-cover, upload-extend, add-vocals, add-instrumental, video
모두 _push_render_job 헬퍼로 queue:music-render에 push.
job_type 디스크리미네이터로 Windows worker가 분기.
Plan-B-Music Phase 3 (cutover 1/4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 05:10:20 +09:00
42cf39d0da feat(music-lab): wire redis client + internal_router + compose env (SP-6)
main.py에 redis.asyncio client 추가 + internal_router include.
docker-compose의 music-lab에 REDIS_URL/INTERNAL_API_KEY/MUSIC_RENDER_URL.
SUNO_API_KEY 라인 제거 (spec §9 — Windows로 이전).
Plan-B-Music Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 03:16:54 +09:00
74196396c5 fix(music-lab): track guard if payload.track is not None: (T1 follow-up)
Code review found: empty dict `{}` was falsy and would silently skip
add_track. Use explicit None check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 03:14:41 +09:00
4393ba706b feat(music-lab): verify_internal_key + /api/internal/music/update (SP-6)
X-Internal-Key 헤더 검증 dependency (insta-lab 동일 패턴).
Windows music-render webhook 수신 endpoint — update_task + 옵션 add_track.
Plan-B-Music Phase 1 (수신부).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 03:10:05 +09:00
714224a9b4 docs(plan): Plan-B-Music — music-render Windows worker + NAS 분할
SP-5 + SP-6 — 모든 Suno(13) + MusicGen(1) 외부 호출 + sync helpers(4)를
Windows music-render로 이전. NAS music-lab은 Redis push(async) +
httpx forward(sync)만. SUNO_API_KEY는 Windows .env 단독 보유 (spec §9).

17 task: NAS 수신부(1-2) → Windows worker(3-10) → NAS cutover(11-14) →
nginx 차단 + end-to-end 검증(15-17).

박재오 결정: 모든 Suno + MusicGen 일괄 이전 (Plan-B-Insta 패턴 + sync forward 추가).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 03:02:48 +09:00
ea93dc522b fix(insta): wire /media/insta nginx alias + frontend insta_cards mount (Plan-B-Insta)
End-to-end 검증 중 발견된 2 가지 인프라 누락 보완:

1) frontend 컨테이너에 /data/insta_cards 마운트 추가 (NAS의 실저장 위치는
   data/insta/insta_cards/<slate_id>/ 로 기존 insta-lab 컨테이너가 사용)
2) nginx /media/insta/ location → /data/insta_cards/ alias

이로써 Windows insta-render worker가 result_path "/media/insta/<id>/01.png"
로 보낸 URL이 NAS frontend nginx에서 정상 서빙됨.

Plan-B-Insta Phase 5 (검증) — T15 end-to-end 디버깅 fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:36:44 +09:00
408b6a3df7 feat(nginx): 3-layer block for /api/internal/insta/ (SP-4)
Layer 1·2: IP 화이트리스트 (192.168.45.0/24 LAN + 100.64.0.0/10 Tailscale).
Layer 3: X-Internal-Key 헤더 (FastAPI dependency, 별도 검증).

외부에서 직접 호출 시 403 (nginx deny), LAN에서 키 없으면 401 (FastAPI).
Windows insta-render만 호출 가능.

Plan-B-Insta Phase 4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:25:40 +09:00
e6ff234031 refactor(insta-lab): remove Playwright + slim Dockerfile (SP-4)
NAS에서 더 이상 카드 렌더 안 함 → Windows insta-render 워커로 완전 이전.
- card_renderer.py를 1줄 deprecation stub로 교체
- main.py의 import card_renderer 제거 + startup/shutdown hook 정리
- requirements.txt에서 playwright 삭제
- Dockerfile에서 Chromium 30+ dep 라인 + playwright install 제거 → image ~50% 감소
- test_card_renderer.py 폐기 (Windows 측 test_worker.py가 대체)
- test_main.py의 create_slate 테스트를 Redis-push 플로우에 맞게 업데이트

Plan-B-Insta Phase 3 완료.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:21:02 +09:00
912cd18e48 feat(insta-lab): cutover to Redis push, Playwright 렌더 호출 제거 (SP-4)
_bg_create_slate, _bg_render의 await card_renderer.render_slate(...)
호출을 Redis RPUSH queue:insta-render 로 전환.

NAS는 task_id 발급 + 큐 푸시 + 30~70% 진행률 보고만. Windows insta-render
워커가 BLPOP → 렌더 → webhook으로 succeeded 보고 시 NAS가
update_slate_status('rendered') 트리거.

Plan-B-Insta Phase 3 (cutover).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:18:12 +09:00
a06cc424ca chore(compose): insta-lab REDIS_URL + INTERNAL_API_KEY env + depends_on redis
박재오: NAS .env에 INTERNAL_API_KEY=$(openssl rand -hex 32) 추가 필요.
같은 값을 Windows insta-render .env에 보관 (대칭).

Plan-B-Insta Phase 1 완료.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 02:01:23 +09:00
e87c43a7a4 feat(insta-lab): wire internal_router + Redis client (SP-4 prep)
main.py에 internal_router include + 모듈 레벨 redis client.
requirements.txt에 redis>=5.0 추가 (playwright 제거는 Task 12에서).

Plan-B-Insta Phase 1 마무리. Task 11에서 _bg_render를 Redis push로 전환.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:59:55 +09:00
0c12c3527f feat(insta-lab): internal webhook /api/internal/insta/update (SP-4)
Windows insta-render worker가 작업 진행률·완료·실패를 보고할 수신부.
X-Internal-Key 인증 필수. 4건의 단위 테스트로 status·error·result_path 검증.

Plan-B-Insta Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:57:17 +09:00
5ed9d265f6 feat(insta-lab): verify_internal_key auth for Windows webhook (SP-4)
X-Internal-Key 헤더 검증 dependency. .env의 INTERNAL_API_KEY와 비교.
미설정 시 401 (fail-safe). Plan-B-Insta Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:51:38 +09:00
24229d00ae docs(plan): Plan-B-Insta — insta-render Windows worker + NAS 분할
16 task, 5 phase. NAS insta-lab의 Playwright Chromium 100% Windows로 이전.

Phase 1 (NAS 수신부): verify_internal_key + /api/internal/insta/update
  + main.py에 redis client + docker-compose env (Task 1-4)
Phase 2 (Windows worker 신설): web-ai/services/insta-render Docker
  컨테이너 (Dockerfile, requirements, card_renderer, worker, main, tests)
  (Task 5-10)
Phase 3 (NAS cutover): _bg_render·_bg_create_slate를 Redis push로
  + card_renderer.py stub + Dockerfile 슬림화 (Task 11-13)
Phase 4 (nginx 3-layer 차단): /api/internal/* IP 화이트리스트 (Task 14)
Phase 5 (end-to-end 검증): 폴링 + PNG 생성 확인 (Task 15-16)

NAS Redis + WSL2 Docker + SMB mount (Plan-B-Base) prerequisite 완료.
다음 plan은 Plan-B-Music (Suno+MusicGen), Plan-B-Video (외부 API gateway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:47:41 +09:00
43f8b111ad chore(deploy): retrigger deployer with new deploy.sh to start redis
Previous push synced new deploy.sh to /runtime/scripts but the deploy
that came with that push had already started under the old script —
so redis (INFRA_SERVICES) was not brought up. This empty commit
forces the deployer to run the new script.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 23:50:33 +09:00
a9f38e1248 fix(deploy): bring up infra services (redis) via separate up -d step
Previous deploy.sh only started services listed in BUILD_TARGETS, so the
newly-added redis service never came up after the SP-1 commit pushed to
NAS. Split image-based infra (redis) into INFRA_SERVICES and call
'docker compose up -d $INFRA_SERVICES' after the BUILD_TARGETS rebuild.

stop/rm is intentionally skipped for INFRA_SERVICES so AOF data
(/runtime/redis-data) survives each deploy cycle. Future infra services
(prometheus, grafana, ...) can join the same list.

Also add redis to HEALTH_ENDPOINTS so deployer's docker-inspect health
check waits for redis to report healthy before declaring DEPLOY_OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 23:47:51 +09:00
87651c9449 feat(infra): add redis container as 24/7 queue + cache base (SP-1)
redis:7-alpine, 256MB maxmemory, AOF appendonly ON, allkeys-lru.
docker volume ${RUNTIME_PATH}/redis-data로 영속화.
Plan-B 후속 트랙(insta-render/music-render/video-render Windows
워커)의 BLPOP 큐 + NAS↔Windows pub/sub의 base.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 23:44:00 +09:00
a1a37ead9e docs(plan): Plan-B-Base — NAS Redis + Windows WSL2/Docker/Tailscale/SMB
분산 아키텍처 base 인프라 셋업. 8 task:
- Task 1-2: NAS docker-compose redis 서비스 추가 + 검증
- Task 3-5: Windows AI WSL2 + Docker Engine + Tailscale 설치
- Task 6-7: NAS SMB 자격증명·마운트 (/etc/fstab 자동화)
- Task 8: 통합 검증 (redis PING, /mnt/nas 양방향 R/W, docker hello-world)

SP-2 작업은 박재오 Windows AI 머신 192.168.45.59에서 직접 실행 필요.
Claude는 SP-1만 직접 처리, SP-2는 명령어·검증 가이드 제공.

후속 Plan-B-Insta/Music/Video/Infra의 prerequisite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 22:07:43 +09:00
978aa14f8b feat(stock): apply webai_cache to portfolio/news/screener-preview (SP-A2)
3 endpoint cache 적용 — /api/webai/portfolio, /api/webai/news-sentiment,
/api/stock/screener/run (preview 모드만, auto는 캐시 미적용).
V1+V2 동시 호출도 NAS에서 1회 계산. web-ai 측 SP-A1 캐시와 2-layer로
작동하여 NAS 인바운드 부담 70% 감소 예상.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:47:23 +09:00
030365bed0 feat(stock): webai_cache module (TTLCache for SP-A2)
3개의 TTLCache (portfolio 120s · news 600s · screener 180s) +
헬퍼 함수. screener key는 mode + top_n + weights canonical hash로
분기. 다음 커밋에서 /api/webai/portfolio·news-sentiment·screener/run
3 endpoint에 적용.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:43:24 +09:00
8c5bfa453f chore(stock): add cachetools for server-side TTLCache (SP-A2 prep)
다음 커밋에서 /api/webai/portfolio·news-sentiment·screener/run에
in-memory TTLCache 적용 예정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:41:25 +09:00
11d86450c3 docs(plan): Track A cache hardening (SP-A1 + SP-A2)
web-ai stock_client TTL 증가 (60/300/60 → 180/600/300) + NAS stock
TTLCache 도입 (cachetools, webai_cache 모듈, 3 endpoint 적용).
2-layer cache로 V2 재시작 시점부터 NAS 인바운드 호출 70% 감소 예상.

8개 task, TDD 적용 (회귀 테스트 3건 + cache 단위 테스트 6건).
~40분 작업.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:30:43 +09:00
90f6af6ab3 docs(arch): NAS↔Windows 분산 아키텍처 통합 design spec
박재오 7결정 + Obsidian 3개 문서(7결정 통합/API 부하/역할 분담)를
실행 가능한 형태로 정리.

12개 SP 분할 (Track A Quick Win 2건 + Track B Infrastructure 10건),
의존성 그래프, 시간대 조건부 우선순위(평일 비휴장일만 트레이딩 HIGH),
Windows Render Worker 통합 패턴 (인스타·음악·영상 셋이 같은 구조),
Redis 큐 컨벤션, SMB direct write + NAS internal webhook,
X-WebAI-Key / X-Internal-Key 분리, 3-layer 차단(IP 화이트리스트 +
Tailscale + 헤더), Suno+영상 API 키 Windows 이전 명세.

첫 plan 대상: Track A (SP-A1 web-ai 캐시 TTL + SP-A2 NAS stock
TTLCache, ~40분 작업, V2 재시작 시 NAS 인바운드 70% 감소).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:24:37 +09:00
83113ab50c docs(check-point): mark #10 already-applied, #11 denied, #12 deferred
#10 NAS LLM 호출 → Windows AI 통일 — 확인 결과 이미 적용. NAS .env가
LLM_PROVIDER=claude + OLLAMA_URL=192.168.45.59:11435. NAS Celeron에서
LLM 추론 안 함. 코드 변경 불필요.

#11 컨테이너 리소스 제한 (cpus 0.5 등) — 박재오 진행 금지. J4025 2C
환경에서 오히려 throughput 손해라는 판단.

#12 NAS 하드웨어 업그레이드 — 박재오 보류 결정.

또한 web-ai V1(:8000)+V2(:8001)+launcher 총 4개 process 종료. NAS API
polling 부담 즉각 감소.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 11:00:04 +09:00
20514193e8 perf(infra): NAS CPU 중기 2건 + 1건 보류 (CHECK_POINT 🟡)
#6 insta-lab Chromium Browser Pool — Playwright/Chromium 인스턴스를
모듈 레벨에서 보관하고 매 슬레이트마다 reuse. 카드 10장 렌더의
launch 비용 (~3초/회)이 사라짐. startup/shutdown lifecycle hook 추가.
crashed/disconnected 시 lazy 재초기화.

#8 realestate-lab 수집 병렬화 — collect_all과 delete_old_completed가
서로 다른 데이터 영역이라 ThreadPoolExecutor(2)로 병렬. asyncio.gather
대신 thread executor를 쓴 이유는 BackgroundScheduler+동기 함수 환경
에서 자연스럽고 추가 의존성 없기 때문. 매칭은 일관성 유지로 순차.

#7 stock async — 보류. 재진단 결과 stock은 BackgroundScheduler 사용
중이라 main loop 블로킹 없음. fetch 4회는 network I/O wait가
대부분이라 to_thread도 의미 없음. 진짜 효과를 보려면 AsyncIOScheduler
전환 + aiohttp 병렬이라 큰 리팩토링. 박재오 판단 대기.

CHECK_POINT.md 갱신.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:42:43 +09:00
7a470aad44 perf(infra): NAS CPU 폭주 5건 일괄 fix (CHECK_POINT 🔴 즉시)
J4025 Celeron 2C/2.0GHz에서 oversaturation을 일으키던 5개 패턴 해소.

1) 09:00 cron 스태거링 — agent-office insta_trends 09:00 / lotto 09:05 /
   youtube 09:10, realestate-lab collect 09:15. 동시 실행 4개가 직렬
   분산되어 1분 단위로 분산됨.
2) lotto Monte Carlo 08:05 → 08:30 — stock 08:00 cron과 25분 분리.
3) insta-lab card_renderer.render_slate를 asyncio.Semaphore(1)로 감쌈.
   동시 슬레이트 렌더 요청이 와도 Chromium 인스턴스 1개만 직렬 launch.
4) docker-compose healthcheck interval 30s → 60s (9 백엔드 + frontend
   총 10개). 30초마다 동시 healthcheck로 인한 CPU 잡음 절반으로.
5) 9개 백엔드 Dockerfile CMD에 --workers 1 명시. 기본값 의존 제거.

CHECK_POINT.md 갱신 — 즉시 5건 체크 + 변경 이력 한 줄.
적용 효과 검증: NAS 재기동 후 `docker stats` 비교.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:31:02 +09:00
de8adaeadd refactor(agent-office): drop the random idle→break→idle cycle
The pixel-office game UI is gone, so simulating coffee-break /
nap / walk states no longer serves any purpose. Remove:
- scheduler's _check_idle_breaks job (no more 60s idle scan)
- BaseAgent.check_idle_break() and _break_until field
- 'break' from VALID_STATES and from transition() branches
- IDLE_BREAK_THRESHOLD / BREAK_DURATION_MIN / BREAK_DURATION_MAX
  config knobs
- 'idle/break' guard in each agent's on_schedule (now just 'idle')

Agents now sit in 'idle' between scheduled jobs and explicit
commands. Display reads 'Idle' instead of churning between idle
and break.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:44:50 +09:00
5cde24115b feat(insta-lab): minimal 테마 card.html.j2 추가 (host repo 영속화)
NAS docker exec로 design_importer minimal 실행한 결과를 컨테이너에서 docker cp로
추출 → host repo에 영속화. 이전엔 컨테이너 ephemeral state라 다음 webhook rebuild에
소실되면서 렌더러가 default 폴백 → 사용자가 본 카드는 minimal 무관.

검증:
- 25,158 bytes, UTF-8 no BOM, <!DOCTYPE 시작
- Jinja parse OK
- background-image 10건, _order.json 순서 일치 (1=start … 10=finish)
- page_no == 분기 10건, 각 페이지 사용자 PNG 정확히 매핑
- Jinja 변수: headline(10), body(9), cta(2), label(4), page_no(1)
2026-05-18 08:03:29 +09:00
318190c93f docs(insta-lab): design_importer는 로컬 실행 권장 — NAS docker exec 시 결과 소실 함정
docker-compose의 insta-lab volume mount는 /app/data만이라 /app/app/templates는
컨테이너 ephemeral state. NAS docker exec로 design_importer 돌리면 card.html.j2가
컨테이너 안에만 생성되고 다음 webhook rebuild에 소실됨 → 렌더러가 default 폴백.

- CLAUDE.md: "실행 위치 — 로컬 권장" 경고 + 로컬 셋업 흐름 + 응급 hotfix docker cp 패턴
- design_importer.py module docstring 동일 내용 반영

PNG 사이즈 1080×1350 → 4:5 비율 권장으로 문서 일치 (이전 검증 완화 반영).
2026-05-18 07:29:55 +09:00
c8684280af feat(insta-lab): minimal theme page_mapping을 _order.json으로 명시
기본 매핑(start→1, cta→10, 나머지 알파벳)으로는 finish.png가 page 3에
배정되는 문제 해결. 카드뉴스 자연스러운 흐름으로 명시:

1. start (인트로)
2. keyword (오늘의 키워드)
3. highlight (핵심 하이라이트)
4. observation (관찰)
5. memo (메모)
6. oneline (한 줄 정리)
7. checklist (체크리스트)
8. study (심화)
9. cta (액션 유도)
10. finish (마감)

다음 design_importer 실행 시 이 매핑이 우선 적용됨.
2026-05-18 00:55:22 +09:00
6895e2f8dc fix(insta-lab): design_importer dimension 검증을 4:5 비율로 완화
운영에서 사용자 디자인이 1122x1402로 작성됨. 1080x1350과 정확히 같은
4:5 종횡비지만 절대 사이즈만 다르므로 정확한 사이즈 강제는 과도.

- 검증: 종횡비 4:5 (±2% tolerance). 1080x1350·1122x1402 등 동일 비율
  높은 해상도 모두 통과.
- Vision은 base64로 원본 분석 (사이즈 무관).
- Playwright는 background-size: cover로 1080x1350 컨테이너에 자동 fit.
- 비율이 깨지면 (예: 1024x1024 정사각) 여전히 reject.

test_validate_images_accepts_higher_resolution_4_5_ratio 신규 (1 case).
2026-05-18 00:42:30 +09:00
34619dc70b fix(insta-lab): add Pillow to requirements.txt (design_importer 의존)
design_importer.py가 1080x1350 이미지 검증을 위해 `from PIL import Image`
사용. 운영 컨테이너에서 ModuleNotFoundError: No module named 'PIL' 발생.

card_renderer는 Playwright만 쓰므로 기존 requirements에 PIL이 없었음.
local pytest는 dev 환경에 Pillow가 이미 설치돼 있어 PASS — 운영 검증
구멍.

Pillow>=10 추가 → 다음 webhook 빌드 시 pip 설치.
2026-05-18 00:33:21 +09:00