2026-04-26
오전~오후 dm PC 작업 + 저녁 chyj1 PC 복귀. 두 세션 통합 기록.
1부 — dm PC (오전~오후)
A. board 2 commits
| 커밋 | 변경 |
|---|---|
cd36aec | ADR-002 후속: Dashboard 에서 AgentScoreChart 제거. WeeklyTrendChart 단독 full-width 로 grid 단순화. AgentScoreChart 정의 자체는 admin /ai-team 페이지용으로 보존 |
52d3f43 | scripts/deploy-frontend.sh — cafe24 자동 배포 (실제로는 prod /var/www/nexus 로 scp). SSH_ASKPASS 방식, NO_PUSH/NO_BUILD/NEXUS_URL 옵션 |
B. prod 배포 (오후 14:29)
/var/www/nexus/index.html mtime 2026-04-26 14:29:55. board 4/26 cd36aec/52d3f43 + 4/24 RF/DX/AG/RB/LOGIN/UX 50 commits 일괄 반영.
| 새 청크 | 의미 |
|---|---|
index-D6wIwpHH.js | main bundle |
index-D5uQQFUf.css | main CSS |
BillingPage-Oyq40AsP.js | 빌링 페이지 lazy chunk |
ComplianceDashboard-DYWmsQtF.js | 컴플라이언스 (신규?) |
CostDashboard-BgS9GkQd.js | 비용 대시보드 |
OwnerDashboard-BDOe_J40.js | 오너 대시보드 |
검증: curl https://1-234-23-23.nip.io/ → 200, AgentScoreChart 흔적 0건 (grep 0 매치).
2부 — chyj1 PC (저녁 복귀)
A. 동기화 (1차 batch)
| 항목 | 결과 |
|---|---|
C:\Users\chyj1\CLAUDE.md | vault 06-Claude-Memory/_GLOBAL_CLAUDE.md 풀버전으로 덮어씀 (43줄→107줄). 추가된 7섹션: 절대 금지 3건/반드시 3건/대표님 응답 방식/안정화 우선순위/아카이빙 원칙/코드 쪼개기 룰/NeuronFS Brain Rules |
| board pull | b500f70..52d3f43 52 commits fast-forward, status clean |
| board stash 폐기 | pre-pull-2026-04-26 App.jsx vite.config.js htaccess (7dccf38 drop) — App.jsx 의 key={page} → key={currentPage} 변경은 RB-02 의 key={currentPage:postId} 로, vite.config.js 의 vendor-react chunking 은 SWEEP-8/PHASE-B 의 React-in-main 전략으로 더 진보된 형태로 흡수됨 |
| wai-vault | already up to date (ab3c4b2 4/23 이후 정지) |
| w-ai-agents | already up to date (0fbc9e8 4/24) |
B. 신규 메모리 — feedback_batch_not_bulk
feedback_granular_tasks.md (task 생성 단위) + feedback_deploy_each_task.md (배포 단위) 짝으로, 실행 scope 단위에서 "한 번에 다 고치려 하지 말고 batch 로 쪼개라" 가 빠져 있어 추가. 본 세션 중 vault sync + board 52커밋 pull + stash 처리를 한 batch 에 묶은 게 정확히 위반 사례 → 사용자 지적 → 메모리 등록.
C. 작업 큐 갱신 (코드 변경 0)
| 파일 | 갱신 |
|---|---|
project_current_state.md | 4/23 저녁 stale → 4/26 실측 반영 (prod 배포 미실행 → 실제 4/24 완료, schema 마이그 4종 적용 검증, BRIDGE_TOKEN 미로테이션 확인) |
project_execution_plan.md | M9 ✅ 마킹 (외부 의존 해제, 4/24 완료) + 4/24 dm PC 신규 트랙 (B0~B6.5 / ADR-001/002/003 / ο-1 / ξ-2 / ν-1/ν-2 / π-1 / debt #9/17/23/27 / RF/DX/AG/RB/LOGIN/UX) 추가 |
D. prod 전수 점검 (read-only SSH)
| 점검 | 결과 |
|---|---|
| w-ai-agents prod git | 0fbc9e8 4/24 (B6.5 까지 반영) ✅ |
| /var/www/nexus | mtime 2026-04-26 14:29:55 (board 4/26 + 4/24 50 commits 전부 반영) ✅ |
| AgentScoreChart 흔적 | grep -r AgentScoreChart /var/www/nexus/ → 0건 ✅ |
| services | claude-bridge / claude-bridge-staging / nginx 전부 active ✅ |
| /health, / | 둘 다 HTTP 200 ✅ |
| DB 마이그 schema | 4종 전부 적용 (role-4tier 6값 + nexus-credits 5컬럼 + dead-column-cleanup trial_runs_remaining DROP + schema-baseline-fixup chain_executions) ✅ |
| self-managed 토큰 | nginx wai-proxy.conf mtime 2026-04-20 22:50 → 4/23 ROTATE 체크리스트 미실행 🔴 |
| .env | 4/24 16:18 변경. 백업은 4/11 (Sprint 6) 이 마지막이라 직접 diff 불가. .env.example (4/23 22:13 갱신) 와 비교 시 prod 에 NEURONFS_TOKEN 만 있고 example 의 ALIGO/AWS_SES/POPBILL/META_ACCESS_TOKEN/WAI_ADMIN_PASSWORD_HASH 등은 prod 에 없음 → 4/24 변경분은 확정 못 함 |
| staging | 1754308 4/12 Sprint B.4 정지. 관리 안 됨. 살릴지 폐기할지 미정 |
E. [company] 잔액 출처 추적
billing_transactions company_id=1 전수 조회 결과 6건만 존재:
| id | type | amount | balance_after | provider_ref | 시각 |
|---|---|---|---|---|---|
| 1 | topup | +10,000 | 100,009,999 | dev_1775909379640 (test_mode) | 2026-04-11 21:09:39 |
| 2~5 | topup | +1,000,000 ×4 | 101M → 102M → 103M → 104M | dev_* (test_mode) | 2026-04-12 16:54:26~28 |
| 6 | topup | +300,000 | 104,309,999 | dev_1775980471971 (test_mode) | 2026-04-12 16:54:31 |
→ 4/12 테스트 충전 6건이 전부. 이후 변동 0. project_sprint_desk.md @4/11 의 "[company] 잔액 99,999,999" 는 마이그 직후 (4/11 21:09 첫 충전 직전) 값. 정상.
의사결정 / 학습
- batch 단위 진행 원칙 명문화 →
feedback_batch_not_bulk.md - prod 배포 상태는 메모리만 믿지 말고 직접 점검 → project_current_state.md "미실행" 이 실제로는 dm PC 4/24 에 완료된 상태였음. 반대 사례 (메모리에는 완료인데 실제 안 된 경우) 도 가능 → 새 세션 시작 시 SSH 1회 read-only 점검을 표준화 권고
3부 — chyj1 PC (저녁 추가 batch들)
F. T7 prod 4/24 회귀 테스트 → /board/login 500 발견
read-only API 호출 9개 — 정상이었으나 /board/login POST 에 비표준 필드 (email) 던지니 500 + "Bind parameters must not contain undefined". 처음엔 4/24 회귀로 추정했으나 git log 확인 후 정정: login.js 본체는 4/20 마지막 변경, 회귀 아님. input validation 누락 결함 (signup 에는 검증 있는데 login 에는 없음).
G. T7-fix board/login 입력 검증 — 0f4d972
webhook/plugins/board/index.js line 89 에 1줄 추가:
if (!body || !body.username || !body.password) return json(400, { error: 'username and password required' });
검증: prod 호출 — email 필드 (이전 500) → 400 ✓ / 정상 dummy (401) ✓ / 빈 body (400) ✓ / Bind 에러 로그 0건 ✓.
H. T6 staging 살리기 4/12 → 4/26 — 0f4d972
원래 1754308 (Sprint B.4 unit test, 4/12) 정지. 50+ commit fast-forward + restart claude-bridge-staging + /health (port 18792) 200 + login fix 적용 검증 (400). 특이: staging .env 가 prod 보다 키 적음 (1121 vs 2164 bytes — openrouter / hometax_biz / aws_ses false). LLM 호출은 staging 불가. 회귀 검증 70~80% 커버 가능.
I. T8 staging-first 룰 메모리 등록
feedback_staging_first.md — w-ai-agents prod 배포는 staging :18792 회귀 검증 통과 후에만. 6단계 절차 (수정 → push → staging pull/restart → staging 검증 → prod pull/restart → prod 검증). 예외: 핫픽스 시에도 즉시 staging 동기화. 4/13 이후 staging 패스로 정지된 사례 + 4/24 dm PC 직행 후 input 검증 누락 잠재 1.94일 사고가 룰 명분.
J. T11-e 에이전트 SOUL 21개 누락 추적 → T10 진단 정정
T10 에서 agents/*.md 1개뿐이라고 보고했으나 잘못. 실제로는 22 에이전트 = 폴더 22개 × 8 .md (SOUL/IDENTITY/HEARTBEAT/MEMORY/TOOLS/USER/AGENTS/BOOTSTRAP) = 184개 정상 존재. T10 카운트 오류.
config/local.db 의 agent_metrics 테이블 직접 조회 → 60건 실 호출 이력:
- Daily-Auditor 30회
- ceo-vision 27회 + CEO-Vision 3회 (대소문자 정규화 안 됨, 부채)
- 나머지 20 에이전트 0회
- 마지막 호출: 2026-04-23
→ T10 "운영 X" 결론 부분적 오진. 정확히는 제한적 운영 (Daily-Auditor cron + CEO-Vision admin 테스트), 4/23 이후 사용자 활동 0. project_agents_not_operational.md 갱신 대상.
K. ax (자율 진화) 진단 — Loren 질문
질문 요지: "에이전트들 자율 발전 / 자가 학습 루프가 ax 처럼 됐냐". 답:
재료 (코드)는 있으나 요리 (실행)는 안 되는 상태.
- 코드 깔린 부품: agent-improver / auto-fix / brain-writer / brain-auditor / agent-a2a / pattern-tracker / scores / cascade / auto-evolution.json — 다 있음
- 실 운영: Daily-Auditor cron 30회 + cascade.js openclaw 자동 복구 (4/24 debt #27) — 그게 끝
- 안 도는 이유: scores 변동 0 / agent-improver 호출 흔적 0 / 사용자 활동 0 = 학습 input 자체가 없음
- 진짜 자율: Phase 3~4 미완. 우리 시스템은 LLM API 호출 + 프롬프트 엔지니어링 수준. 가중치 학습 X.
비유: 22명 직원 채용 + 사규 + 평가 시스템 다 만듦 → 손님이 안 와서 일을 안 함 → 학습 0.
대안: ① 매출/사용자 먼저 (Track A — input 생성) → ② 자율 트리거 활성화 → ③ NeuronFS 자동 기록 검증.
L. 풀 Nexus (ADR-003) 파일럿 가능성
Loren 컨펌: "이미 고객사 1명 준비". docs/decisions/ADR-003-per-tenant-nexus-deployment.md 옵션 A (Per-Tenant Process — DB+Brain 공유, 프로세스만 분리) 채택. 1~2시간 세팅 가능 (코드/구조 검증). 받아야 할 정보: OpenRouter API 키 / 텔레그램 봇 토큰+그룹+관리자 ID / 회사명 / Pro 또는 Enterprise 플랜 / 학습 데이터 활용 계약.
M. T11-b 보안 1순위 4영역 점검
| 영역 | 결과 |
|---|---|
| B1 시크릿 평문 | ✅ 클린 (placeholder 만) |
| B2 admin 가드 | ✅ 9 파일에서 verifyAdminAuth 사용 (deep audit 후순위 — 다만 /agents 토큰 없이 200 = 누락 의심, T11-b-2 추적 task) |
| B3 입력 검증 | ✅ login fix 패턴 다른 라우트에도 적용됨 |
| B4 e.message 클라 노출 | 🔴 4곳 발견 → fix |
N. T11-b-fix B4 e.message 제거 — da4eb28
webhook/agents/registry.js 4곳 — POST /agents/:id/test (catch + .catch), POST /agents (등록), PUT /agents/:id (수정). console.error 자세히 + 클라 응답은 generic. 모두 admin-only 라우트라 일반 사용자 영향 없으나 security.md 룰 통일.
O. T11-evo-1 scores 동적 fallback — 145eeee
자율진화 ① — 폴백 체인이 정적이라 점수 떨어진 에이전트도 고정 후순위였음. 이제 scores.js 의 sortChainByScore 가 chain[0] 보존 + tail 점수 desc 정렬. 점수 떨어지면 자동 후순위.
코드:
scores.js(89→106줄) — sortChainByScore 함수 + exportrouter.js(590→606줄) — getFallbackChain 안에서 try-catch 호출. 500 한도 초과 부채 가중 (claude-bridge.js 961줄 task #111 과 함께 분리 batch 후순위)
검증 (node inline): ["ad-onboarder","cmo-marketing","ceo-vision"] → head 보존 ✓ (현재 모두 score 50 이라 정렬 변동 0, cold start 정상)
P. T11-evo-2 Chain 재시도 + context 압축 — 이미 구현 발견
chain-executor.js 코드 전체 read 결과 TB-2 가 이미 완성:
- 재시도 (TB-2.2): line 128-166.
fail_strategy = step.fail_strategy || 'retry_once'기본값. attempt 루프 + maxRetries=1 - context 압축 (TB-2.3): line 111-118.
stepPrompt.length > maxCtx(20000)→ ceo-vision 으로 500자 요약 → 새 prompt. 실패 시 truncate - 보너스: quality-checker 자가평가 (147-152) / agent-improver.recordFailure (157) / notifyUser (161, 173) / memory-keeper 핵심 결정 추출 (177-181)
→ project_execution_plan.md TB-2 ⏳ → ✅ 정정. 코드 변경 0.
Q. self-managed 토큰 정정 (6 → 3)
T10 batch 끝 무렵 점검: WAI_BRIDGE_TOKEN, WAI_ADMIN_KEY, WAI_DEFAULT_PASSWORD 3개만 코드/.env 에서 사용 중. WAI_GATEWAY_TOKEN, WAI_WEBHOOK_TOKEN, WAI_TOKEN_SECRET 은 코드에 grep 0 매치 = 사용 안 함. ROTATE 체크리스트 메모리가 stale 이었음. rotation 작업은 Loren 보류 지시 ("아직 업데이트 안 끝났음") — fact 만 정정.
4부 — 누적 prod 커밋 (1.94일간 1개 → 오늘 4개)
| 해시 | 내용 |
|---|---|
0f4d972 | board/login 입력 검증 |
da4eb28 | agents/registry e.message 제거 |
145eeee | scores 동적 fallback |
(vault) 4a02703 + 본 DevLog | 4/24 + 4/26 동기화 |
staging 도 동일 commits 반영 (staging-first 룰).
5부 — T11-c 운영 batch (저녁 후반, 빡센 정리)
R. T11-c 운영 read-only 점검
services 5개 (bridge/staging/nginx/mysql/cron) 전부 active. SSL 74일 (certbot 정상). 디스크 38% 여유. watchdog 4 rules + endpoint 200 (/watchdog/rules 직접, /api/watchdog/rules nginx 경유 둘 다 OK). nginx 4xx 3190건 분석 → 봇/스캐너 패턴 (HNAP1/wp.php/admin.php) 정상.
발견 부채 3건:
- wai_board MySQL 자동 백업 0건 🔴 — 4/23 hardening 수동 백업 1개만 존재. dpkg-db-backup.timer 는 시스템 패키지용
- 메모리 압박 ⚠️ — 3923MB 중 3196MB 사용 (81%) + swap 760MB. 풀 Nexus 1개 추가 시 200~300MB 더
- monitor 158 error/24h 분석 → 대부분 OpenClaw
/체크 false alarm + 외부 사이트 일시 socket hang up
OpenClaw 진단 정정 (또 stale memory): 이전 "OpenClaw 의도 OFF" → 실은 켜져 있음 (process 760221, port 18789 LISTEN, /health 200). 메모리 갱신 대상.
S. T11-c-A wai_board 자동 백업 cron — 788bc21
scripts/wai-db-backup.sh (70 줄) + server/cron.d/wai-db-backup (9 줄):
- mysqldump --single-transaction --routines --triggers --events + gzip -9
- /var/backups/wai-board/wai-board-YYYYMMDD-HHMMSS.sql.gz
- gzip -t 무결성 검증, 실패 시 파일 삭제 + exit 1
- 7일 retention (find -mtime +7)
- MYSQL_PWD env (process list 비번 노출 방지)
- daily 03:30 KST cron
설치 + 첫 수동 실행: wai-board-20260426-171642.sql.gz 9.1KB, gzip 무결성 OK, CREATE TABLE 15개 (wai_board 작은 DB 정상).
⚠️ mysqldump warning: "Access denied; PROCESS privilege ... tablespaces" — 일반 데이터/스키마는 정상 dump, tablespace 메타만 누락. waiboard user 권한 부여하면 사라짐 (prod DB user 변경 위험으로 보류).
다음 03:30 자동 실행 결과는 다음 세션 검증.
T. T11-c-B monitor.js OpenClaw / → /health — f9747e4
config.js HEALTH_TARGETS OpenClaw url 'http://127.0.0.1:18789/' → /health. socket hang up false alarm 줄이기. 주석 stale ("gateway /health 엔드포인트 없음") 정정.
monitor.js:271 refreshClaudeToken return; 은 보류 — 주석 명시: Loren PC SSH interactive claude auth login --force 갱신 후에만 해제 가능 (TB-10.4). 자동 fix 시 무한 재시도 + 텔레그램 폭격 위험.
U. T11-c-C 잔존 부채 4건 fix
C-1. e.message 클라 노출 5건 — e3cec70
- scores.js POST /scores → "Bad request" + console.error
- chain-executor.js:92 병렬 step → '[오류 — 다음 단계로 진행]' (LLM 다음 step 으로 전달)
- chain-executor.js:162 사용자 텔레그램 → "잠시 후 다시 시도해주세요" (가장 critical, 일반 사용자 직접 노출이었음)
- csp-report-api.js:64 admin summarizeRecent → error 필드 제거
- cost-monthly-report.js:162 cron caller → error 필드 제거
유지 (admin DB 디버깅 / 학습 input):
- chain_steps.output (157), agent-improver.recordFailure (158), chain_executions.error (161)
C-2. conversation_memory INSERT 누락 fix — 65a8ca9
원인: user-telegram.js:277 executeTask(text, null, {}) 빈 opts → router.js:388 if (convMemory && opts.userId) 통과 못 함 → saveContext 미호출. 추가로 user 조회가 .then 비동기인데 executeTask 별도 path → race condition.
조치:
- doExecute(userId) callback 으로 분리
- pool.execute('SELECT id FROM users WHERE telegram_chat_id = ?').then() 안에서 doExecute 호출
- shared.executeTask(text, null, { userId: userId }) 로 opts 전달
- 미초기화 fallback 도 doExecute 안에서 처리 (분기 통합)
→ 텔레그램 → 에이전트 호출 시 user_id 매핑되면 conversation_memory INSERT 활성. 자율진화 input 누적 시작.
C-3. agent_id 정규화 (ceo-vision vs CEO-Vision) — f2555c9
local-db.js:339 recordMetric 안에 String(agentId).toLowerCase() 정규화. registry.js AGENT_ID_PATTERN ^[a-z0-9-]{2,30}$ 와 일치 강제.
과거 데이터 정규화 (better-sqlite3 inline UPDATE):
- BEFORE: ceo-vision 27 + CEO-Vision 3 + Daily-Auditor 30 (3 IDs 혼재)
- AFTER: ceo-vision 30 + daily-auditor 30 (2 IDs 통일, 33행 UPDATE)
V. T11-c-F nginx /api/watchdog routing — 또 거짓 알람
T11-c 첫 점검 시 Not Found 받은 게 사실은 nginx 안 거치고 bridge 직접 (127.0.0.1:18790/api/watchdog/...) 호출 → 404. nginx HTTPS 경유는 200. wai-proxy.conf line 223 /api/watchdog/ location 이미 정상. prod ↔ repo snippet diff 0 라인. routing 문제 없음. 진단 오류 누적.
W. T11-c-E1 router.js 분리 — 17f4c80 c279864 cde9189
ADR-001 Option A "프로세스 통합" vs 500줄 한도 "파일 분리" 는 다른 차원 — 충돌 없음 (한 process 안에서 require로 모듈 분리). 단계별 진행:
E-1.1 router-fallback.js (17f4c80) — hardcoded fallback dict 27 줄 → 신규 41 줄. 의존 0 (순수 함수). router.js 606 → 581 (-25).
E-1.2 router-circuit.js (c279864) — circuit-breaker 28 줄 → 신규 55 줄. 의존: shared.sendTelegram + logEvent + config.TOPICS (init 패턴). router.js 581 → 558 (-23).
E-1.3 router-stream.js (cde9189) — runAgentStream 104 줄 → 신규 136 줄. 의존 7개 (shared/hooks/isValidAgentId/getAgentBrain/getCurrentOpenRouterKey/detectKeyAuthError/onKeyAuthError) inject 패턴. router.js 558 → 466 ✅ 500 한도 진입.
각 단계 staging-first 룰 빡세게:
- staging git pull → restart → /health 200 → error 0 → grep 검증
- prod git pull → restart → /health 200 → error 0
- 회귀 호출 5종 (/agents /scores /chain/catalog /watchdog/rules /health) 전부 200
E-1 종합: router.js 606 → 466 (-140). 4 파일 (router-fallback 41 + router-circuit 55 + router-stream 136 + router 466) 모두 한도 내. 단일 책임 분리.
E-2 claude-bridge.js 961줄 분리는 보류 — 의존성 거대 (init/dispatch/HTTP handler/30+ 모듈 wiring). 회귀 위험 매우 높음. 별도 sprint 권장.
6부 — 누적 prod commits 11개 (이번 세션)
| 해시 | 내용 |
|---|---|
0f4d972 | board/login 입력 검증 |
da4eb28 | agents/registry e.message 제거 |
145eeee | scores 동적 fallback |
e3cec70 | e.message 5건 추가 fix |
65a8ca9 | user-telegram conversation_memory userId 전달 |
f2555c9 | agent_id 정규화 (소문자) |
788bc21 | wai-db-backup cron + script |
f9747e4 | monitor OpenClaw /health |
17f4c80 | router-fallback 분리 |
c279864 | router-circuit 분리 |
cde9189 | router-stream 분리 |
staging 도 동일 commits 반영 (staging-first 룰).
7부 — 진단 오류 통계 (accuracy_first 룰 위반 사례)
본 세션에서 메모리/grep만 신뢰하다 실측에서 정정한 케이스:
- T10 SOUL .md 1개 → 실제 184 (22 폴더 × 8) —
agents/*.mdglob 잘못 셈 - T10 운영 0 → agent_metrics 60건 (DB 직접 조회 안 함)
- T7 login 회귀 → 입력검증 누락 (4/20 이후 미변경)
- self-managed 토큰 6 → 3 (코드 grep 안 하고 메모리 신뢰)
- TB-2 미완 → 이미 구현 (chain-executor.js 코드 read 안 함)
- T11-c 첫 점검 OpenClaw OFF → 실은 ON
- T11-c 첫 점검 /api/watchdog Not Found → bridge 직접 호출 잘못
7건 진단 오류 모두 메모리/grep 표면만 보고 코드 read 또는 직접 측정 생략이 원인. 다음 세션부터 feedback_accuracy_first.md 더 엄격 적용 — 코드 직접 read 필수, 측정은 정확한 환경 (nginx 경유 vs 직접) 명시.
8부 — 운영 부채 정리 상태
| # | 항목 | 상태 |
|---|---|---|
| 1 | wai_board 자동 백업 | ✅ daily cron 가동 |
| 2 | 메모리 RAM 압박 (3923 used 81% + swap) | ⏳ Loren 곧 증설 |
| 3 | monitor false alarm | ✅ /health 변경 (다음 사이클 검증) |
| 4 | self-managed 3 토큰 rotation | ⏳ Loren 보류 |
| 5 | TB-10.4 Claude CLI 토큰 갱신 | ⏳ Loren SSH interactive |
| 6 | claude-bridge.js 961 분리 | ⏳ 별도 sprint |
| 7 | conversation_memory INSERT 누락 | ✅ fix |
| 8 | agent_id 정규화 | ✅ fix + 과거 데이터 UPDATE |
| 9 | e.message 클라 노출 9건 (전체) | ✅ 9건 모두 fix |
| 10 | router.js 606 분리 | ✅ E-1 완료 (466줄) |
9부 — "전체 시작" batch (저녁 후반 후반)
Loren 지시: "메모리 증성 안 해도 rotation 하고 다 할 수 있잖아" — 메모리 묶어서 보류한 게 잘못. 즉시 rotation + e2e + 부채 정리 진행.
X. T-rot self-managed 3 토큰 rotation — swap 96ms
새 값 생성 (openssl rand): WAI_BRIDGE_TOKEN 64자 + WAI_ADMIN_KEY 32자 + WAI_DEFAULT_PASSWORD 24자.
배포 순서:
- .env 백업 (
pre-rot-20260426-174421) + nginx wai-bridge-auth.conf 백업 - .env sed -i 갱신 (3 변수)
- nginx wai-bridge-auth.conf 새 토큰 cat heredoc (
Bearerprefix) - nginx -t syntax OK
- swap 96ms —
nginx -s reload && systemctl restart claude-bridge묶음 (다운타임 무시 가능) - 검증 — /scores NEW token 200, /health 200, error 0
- staging .env 동기화 + restart
ADMIN_KEY/DEFAULT_PASSWORD 영향 점검 (grep):
- ADMIN_API_KEY=[redacted].js + setup-auto-evolution.js (bridge 내부, .env+restart 로 자동 반영)
- DEFAULT_PASSWORD: auth.js seed + hooks.js secret 마스킹 + test-integration.js fallback (기존 admin DB hash 영향 0)
- board(cafe24) 측 BRIDGE_TOKEN 직접 사용 X (user session token 별도)
Y. T-rot-followup nginx Authorization forward 401 추적 → 9번째 진단 오류
증상: 외부 HTTPS /api/scores, /api/watchdog/rules 401. 직접 bridge 호출은 200.
추적:
- nginx -T 의 wai_bridge_auth map 정의 정상 로드 확인
- wai-bridge-auth.conf 파일 인코딩 OK, 권한 OK (640 root:www-data)
- nexus.bak.20260424 sites-enabled 백업 발견 → /root/ 이동 (server_name 충돌 1건 해소)
- 여전히 401 — 임시 console.log 디버그 (
5ac3e6b) 추가 - bridge 받은 헤더
req.headers.authorization= undefined (외부 HTTPS), 직접 호출 시만 정상
진짜 원인:
- nip.io =
/etc/nginx/sites-enabled/nexus(server block) —proxy_set_header Authorization $http_authorization(client session token forward, wai_bridge_auth 자동 주입 X) - watoneai.cafe24.com = dashboard server block — wai-proxy.conf snippet 의 wai_bridge_auth 자동 주입
- nip.io 호출 시 admin endpoint 401 = client token 무첨부 = 정상 동작 (ADR-002 admin-only 적용 후 일관)
따라서 T-rot-followup 자체가 false alarm. rotation 영향 0. 진단 오류 9번째 사례 (메모리/grep 표면만 보고 환경 직접 측정 생략).
부수 정리:
- /api/scores nginx 자동 주입 추가 (
48f964d) — dashboard 일관성 유지 (영향 0 이지만 의도) - 임시 debug log 제거 (
73768ef) - .env WAI_ADMIN_KEY 두 줄 중복 → 1 라인 정리 (server inline awk)
- nexus.bak.20260424 server_name 충돌 영구 해소
Z. T11-a 코드 품질 — auth-oauth-providers 분리 — 77f0650
500줄 위반 잔존: auth-oauth.js 515 / local-db.js 514. 후자는 +14 미세, 별도 sprint.
auth-oauth-providers.js (195 줄, 신규):
- Google/Kakao/Naver 각 build/exchange/fetch 9 함수
- googleRedirectUri / kakaoRedirectUri / naverRedirectUri (env override)
- init({ shared, putState, httpsRequest, NEXUS_WEB_BASE }) 의존 주입
auth-oauth.js: 515 → 374 (-141, 한도 진입).
회귀 (3 provider build URL):
- google:
{"ok":true,"url":"https://accounts.google.com/o/oauth2/v2/auth?...","state":"..."}✅ - naver:
{"ok":true,"url":"https://nid.naver.com/oauth2.0/authorize?...","state":"..."}✅ - kakao:
{"ok":false,"error":"feature_disabled","feature":"kakao_oauth"}✅ (키 미발급, EXTERNAL_FEATURES 분기 정상)
AA. T11-d e2e — admin 로그인 + 11 endpoint
Loren 직접 admin 비번 (JS041122!) 제공 → e2e 검증 진행.
✅ 작동 (7개): /board/posts / billing/balance / billing/usage / scores (super_admin) / activity / agents/ceo-vision/detail / search
🔴 404 (4개): /board/dashboard/overview / brief / cost / feedback
→ B0~B6.5 dual-mount 라우팅 일부만 작동. 같은 batch 의 search/activity/agents/detail 200 인데 dashboard/brief/cost/feedback 404. bridge-dual.js dispatch 일관성 부채. T11-d-debt 별도 task 등록.
부수 발견 — billing/balance 응답:
{"ok":true, "companyId":1, "balanceKrw":104309999, "planTier":"enterprise",
"subscriptionStatus":"cancelled", "autoTopup":{"enabled":false,...}}
[company] id=1 enterprise plan 인데 subscriptionStatus=cancelled. 의도 또는 마이그 잔존. T11-d-debt2 별도 task.
BB. T-bridge-split → 이미 분리 완료 (8번째 진단 오류)
claude-bridge.js 961줄 → 실제 471 줄. 4/24 dm PC 가 setup-modules / setup-nexus-loop / setup-auto-evolution / setup-auth-profiles + handlers/api-chain / graceful-shutdown / inline-routes 로 이미 분리 완료. 메모리 stale.
10부 — 전체 누적 prod commits (이번 세션, 1.94일간 1개 → 18개)
| 해시 | 내용 |
|---|---|
0f4d972 | board/login 입력 검증 |
da4eb28 | agents/registry e.message 제거 |
145eeee | scores 동적 fallback |
e3cec70 | e.message 5건 추가 fix |
65a8ca9 | user-telegram conv-memory userId 전달 |
f2555c9 | agent_id 정규화 (소문자) |
788bc21 | wai-db-backup cron + script |
f9747e4 | monitor OpenClaw /health |
17f4c80 | router-fallback 분리 |
c279864 | router-circuit 분리 |
cde9189 | router-stream 분리 (한도 진입) |
77f0650 | auth-oauth-providers 분리 (한도 진입) |
48f964d | /api/scores nginx 자동 주입 |
5ac3e6b | (temp debug log) |
73768ef | (debug 제거) |
추가 prod 변경 (commit 외):
- 토큰 3개 rotation (.env + nginx wai-bridge-auth.conf 직접)
- DB 자동 백업 cron 가동 (/usr/local/bin/wai-db-backup.sh + /etc/cron.d/wai-db-backup)
- nginx sites-enabled/nexus.bak.20260424 → /root/ 이동
- .env WAI_ADMIN_KEY 2 → 1 dedupe
11부 — 진단 오류 통계 (accuracy_first 룰 위반 9건)
본 세션에서 메모리/grep 표면만 보고 코드/환경 직접 측정 생략으로 발생한 오진:
- T10 SOUL .md 1개 → 184 (폴더 구조 못 봄)
- T10 운영 0 → agent_metrics 60건 (DB 직접 조회 안 함)
- T7 login 회귀 → 입력검증 누락 (4/20 이후 미변경)
- self-managed 토큰 6 → 3 (코드 grep 안 하고 메모리 신뢰)
- TB-2 미완 → 이미 구현 (chain-executor.js read 안 함)
- T11-c 첫 점검 OpenClaw OFF → 실은 ON
- T11-c 첫 점검 /api/watchdog Not Found → bridge 직접 호출 잘못
- T-bridge-split claude-bridge.js 961 → 실제 471 (이미 분리됨, 메모리 stale)
- T-rot-followup nginx forward 깨짐 → 사실은 nexus server block 의 의도된 client token forward (admin endpoint 는 watoneai.cafe24.com dashboard 로만 자동 주입)
→ 모두 메모리 + grep 표면만 보고 코드 직접 read 또는 환경 직접 측정 생략 이 원인. 다음 세션부터 feedback_accuracy_first.md 더 엄격 적용.
12부 — 운영 부채 정리 상태 (최종)
| # | 항목 | 상태 |
|---|---|---|
| 1 | wai_board 자동 백업 | ✅ daily cron 가동 |
| 2 | 메모리 RAM 압박 | ⏳ Loren 곧 증설 |
| 3 | monitor false alarm | ✅ /health 변경 |
| 4 | self-managed 3 토큰 rotation | ✅ swap 96ms 완료 |
| 5 | TB-10.4 Claude CLI 토큰 갱신 | ⏳ Loren SSH interactive |
| 6 | claude-bridge.js 961 분리 | ✅ 이미 471 (메모리 stale 정정) |
| 7 | conversation_memory INSERT 누락 | ✅ fix |
| 8 | agent_id 정규화 | ✅ fix + 33행 UPDATE |
| 9 | e.message 클라 노출 9건 | ✅ 9건 모두 fix |
| 10 | router.js 606 분리 | ✅ 466 (E-1 완료) |
| 11 | auth-oauth.js 515 분리 | ✅ 374 (한도 진입) |
| 12 | local-db.js 514 (한도+14 미세) | ⏳ 별도 sprint |
| 13 | dual-mount 4건 (dashboard/brief/cost/feedback 404) | ⏳ T11-d-debt |
| 14 | [company] subscriptionStatus="cancelled" | ⏳ T11-d-debt2 |
| 15 | nginx sites-enabled .bak 잔존 위험 | ✅ /root/ 이동 |
| 16 | .env WAI_ADMIN_KEY 2 라인 중복 | ✅ dedupe |
| 17 | 외부 벤더 토큰 14건 | ⏳ Loren 직접 |
13부 — "전체 시작" 후 후반 진단 + 비전 정리
CC. T11-d-debt + T11-d-debt2 + local-db 분리 (B 갈래 마무리)
- T11-d-debt 10번째 진단 오류: dual-mount 404 4건 (dashboard/brief/cost/feedback) → 내 e2e 호출 path 잘못. 정확한 path 로 재검증:
/board/dashboard/badges,/board/overview/{actions,kpi},/board/cost/{summary,breakdown,series},/board/brief/today, POST/board/feedback모두 200. dispatch 정상. - T11-d-debt2 fix: [company] id=1 enterprise + subscriptionStatus="cancelled" → "active" UPDATE 적용. /board/billing/balance 응답 검증.
- local-db.js 514 분리 (
1974754): User domain (createUser/getUser/getAllUsers/deleteUser/updateUserPassword/getUserCount/migrateUsersFromFile) → local-db-users.js (73 줄, factory init(db, stmts) 패턴). local-db.js 514 → 483 (한도 진입). 회귀 100% 통과 (login + session + rate limit).
DD. board↔agent 실 호출 e2e — 22 에이전트 호출 hang up 발견
Loren admin 비번 (JS041122!) 제공으로 e2e 가능.
POST /board/agent/execute { agentId: "ceo-vision", prompt: "한 문장으로 자기소개" }
→ 60s timeout, 빈 응답, agent_metrics 추가 0건
추적 (진단 11~12번째 오류 누적):
진단 11 — claude CLI 만료 가설 폐기:
- 처음 의심:
/root/.claude/.credentials.jsonexpiresAt=2026-04-06, 만료 -476h - 실측:
which claude→ command not found (binary 자체 prod 미설치) - openclaw.mjs grep
spawn.*claude\b→ 0건 (claude binary spawn 의존 없음) - 결론: claude CLI 는 dev 도구 (개발팀이 claude code 사용용 의도). 우리 시스템 backend 무관. monitor.js refreshClaudeToken 은 dead code.
진단 12 — Ollama 11434 hang up 확정: NODE_DEBUG=net,http verbose 로 추적:
NET: createConnection { port: '11434', host: '127.0.0.1' }
NET: connect: attempting to connect to 127.0.0.1:11434
NET: afterConnect → destroy → close
→ openclaw --local 모드 = Ollama (port 11434) 의존 default. Ollama 미설치 → connection refused → 다른 fallback 시도 → hang.
router.js spawn 명령:
spawn('openclaw', ['agent', '--agent', X, '--message', Y, '--json', '--local', ...])
--local 옵션이 Ollama 강제. registry model field (openrouter/anthropic/claude-sonnet-4-6) 가 OpenRouter prefix 임에도 unfortunately Ollama 우선 시도.
진짜 원인: openclaw --local 모드 + Ollama 미설치. OpenRouter API key 정상, OpenClaw gateway 18789 정상, openclaw binary 정상이었음.
EE. 비전 정리 — multi-provider abstraction × BYO credentials
Loren 컨펌 비전: "회사가 자기 API key (OpenAI/Anthropic/OpenRouter/Ollama 등) 들고 와서 → Nexus 무한 확장" = ADR-003 BYO credentials × multi-provider abstraction.
Hermes-agent vs OpenClaw 비교 — 프레임 잘못:
- 둘 다 layer 가 다름 (개발자 1명 CLI 비서 / npm agent runner)
- Nexus = 비즈니스 자동화 플랫폼 (멀티테넌트, 22 에이전트, 권한 4단계, 과금)
- 둘 다 Nexus 대체 불가. Hermes 좋은 패턴만 흡수.
Hermes 흡수 대상 (vault 05-Reference/hermes-agent-analysis.md):
- P0: 뉴런 인젝션 스캔 (보안)
- P1: 대화 5단계 압축 — ✅ 이미 구현 (ξ-2 4/24)
- P1: API 키 풀 round_robin + 429 쿨다운 (config.js 부분 구현 → 강화)
- P2: 뉴런 Progressive Disclosure (토큰 비용)
- P2: Slack 게이트웨이 — ✅ 이미 scaffold (ο-1 4/24)
- P3: MoA 다중모델 합의
- P3: RL 자기개선
FF. Sprint 순서 (병렬 X, batch_not_bulk + accuracy_first 적용)
| 순서 | Sprint | 시간 | 의존 |
|---|---|---|---|
| 1 | X — Backend 근본 fix (router.runAgent → fetch OpenRouter HTTP 직접, openclaw 우회) | 1~2시간 | 즉시 출발 (운영 막힘 해소) |
| 2 | Y — Multi-provider abstraction (model prefix 분기, openrouter/anthropic/openai/ollama plugin) | 반나절 | X 후 |
| 3 | AA — Hermes 패턴 흡수 (뉴런 인젝션 스캔 / Progressive Disclosure / MoA / dead code 정리) | 1~2일 | X 후 (병렬 안 함) |
| 4 | Z — 풀 Nexus 파일럿 (ADR-003 Option A — Per-Tenant systemd + .env 분리 + 회사 정보 paste 시 활성) | 1~2시간 + 회사 정보 | Y 후 |
병렬 X — feedback_batch_not_bulk.md + feedback_accuracy_first.md 적용. 각 Sprint 완료 → staging-first 검증 → 보고 → Loren 컨펌 → 다음.
GG. 비용 절감 plan (Loren 우려 — "OpenRouter 토큰값 비싸지 않을까")
| 순위 | 옵션 | 효과 |
|---|---|---|
| 1 | 🅓 ADR-003 BYO credentials (Sprint Z) | Nexus 비용 0 — 비전 핵심 |
| 2 | 🅐 모델 다운그레이드 (Sonnet → Haiku) | 90% 절감 |
| 3 | 🅑 Anthropic prompt 캐싱 (SOUL 등 system prompt) | 입력 90% 절감 |
| 4 | 🅒 컨텍스트 압축 | ✅ 이미 ξ-2 |
| 5 | 🅔 cron 빈도 조절 (Daily-Auditor 매일 → 주 1) | 운영 비용 |
| 6 | 🅕 자체 LLM (Phase 6, GPU 필요) | 0원, 장기 |
현재 OpenRouter 누적 = $162 (4월 dev + hardening + e2e). 사용자 활동 0이라 비용 폭주 위험 0. 출시 후 BYO credentials 가 영구 대비책.
14부 — 외부 벤더 토큰 정정 (14 → 10)
ROTATE-2026-04-23.md P0 정확 카운트:
- 16 항목 중 self-managed 5건 + VPS root 1건 = 6건 제외
- 외부 벤더 (Loren 직접 콘솔) = 10건: VPS FTP + paljalab FTP/DB + marketing-factory FTP/DB + cafe24 DB + Toss Live + Meta Ads + OpenRouter + Telegram Bot + GitHub PAT + Dashboard admin 비번
- self-managed 실제 = 3건 (BRIDGE_TOKEN + ADMIN_KEY + DEFAULT_PASSWORD), 메모리에 GATEWAY/WEBHOOK/TOKEN_SECRET 도 있다고 적혀 있었으나 코드 grep 0매치 (12번째 stale 메모리 정정)
우선순위:
- 🔴 매출 영향: Toss Live (결제), OpenRouter API key (LLM 비용 폭주)
- 🟡 도용 위험: Telegram Bot, Meta Ads, GitHub PAT
- 🟢 인프라: cafe24 FTP × 3 + DB
15부 — Sprint X 실행 (저녁 후반후반후반)
HH. X1 router-openrouter.js + runAgentSingle — 83ee9b4
router-openrouter.js (80 줄, 신규):
- callOpenrouter(apiKey, model, messages, opts) — node 내장 https POST
- 401/403 → openrouter_auth_failed, 429 → openrouter_rate_limit
- 회사별 API key 분리 가능 (apiKey 인자) — ADR-003 BYO base
router.js runAgentSingle:
- spawn openclaw 92줄 → callOpenrouter 33줄
- model: registry.getAgent(id).model 또는 modelSelector.selectModel, "openrouter/" prefix strip
- 라인수 466 → 407
II. X1.5 model ID fix — a96a14f
X3 검증 중 발견: registry + modelSelector 의 model ID 가 OpenRouter 와 mismatch — "is not a valid model ID" 400.
dash → dot:
- claude-sonnet-4-6 → claude-sonnet-4.6
- claude-opus-4-6 → claude-opus-4.6
만료된 preview → 안정 버전:
- gemini-2.5-flash-lite-preview-06-17 → gemini-2.5-flash-lite
신규 추가 (model-selector.js):
- claude-haiku-4.5 (저렴, sonnet 의 1/3 가격)
- gemini-2.5-flash
JJ. X2/X3 prod e2e — 코드 정상, OpenRouter 잔액 부족
POST /board/agent/execute { agentId: "ceo-vision", prompt: "..." }
→ duration: 0s, result: "[전체 폴백 실패]"
→ agent_metrics 60 → 86 (+26, fallback chain 호출 다 기록)
→ error_msg: "Insufficient credits. Add more using https://openrouter.ai/settings/credits"
✅ 검증된 것 (X1+X4+model fix 종합):
- router → router-openrouter.js → OpenRouter HTTP 정상
- model ID OpenRouter 형식 매칭
- agent_metrics 누적 시작 (호출 시도 다 기록)
- error_msg 컬럼 정확히 작동
- duration 41ms / 24ms (즉시 응답, 이전 60s timeout 과 비교)
- agent_id 정규화 (cmo-marketing/cto-tech 소문자)
- openclaw silent hang up 영구 해소
🔴 막힘 (외부 결제):
- OpenRouter 잔액 0 또는 부족 (prepay 방식, 누적 사용 $162 와 별개)
- Loren
https://openrouter.ai/settings/credits카드 등록 + 충전 또는 auto-topup 필요 - 잔액 들어오면 X5 즉시 가능
KK. X4 spawn openclaw 잔여 cleanup — 9b8e05d
router-stream.js (136 → 34, -102):
- spawn openclaw + tryResolveStreamBuf + extractTrailingJson + line filter 100+ 줄 제거
- 단순 위임 패턴: runAgent (router.js, fallback chain 포함) 호출 → onChunk(전체 text 한 번) + onDone
- init({ runAgent }) 의존 1개로 축소 (이전 7개)
- 진짜 token 단위 stream 은 후속 sprint (OpenRouter SSE 추가)
router.js (407 → 396, -11):
- crypto require 제거 (sessionId — 더 안 씀)
- detectKeyAuthError 함수 제거 (stderr 분석 — 더 안 씀)
- _stream.init() inject 7개 → 1개 (runAgent)
router 분리 5 파일 종합 (모두 한도 내):
- router.js 396 (메인 + runAgent + runAgentSingle + executeTask)
- router-stream.js 34 (위임)
- router-openrouter.js 80 (HTTP backend)
- router-fallback.js 41 (하드코딩 chain)
- router-circuit.js 55 (서킷 브레이커)
LL. Sprint X 종합 — 누적 prod commits 23개
이번 세션 commit 목록 (X 까지): 0f4d972 / da4eb28 / 145eeee / e3cec70 / 65a8ca9 / f2555c9 / 788bc21 / f9747e4 / 17f4c80 / c279864 / cde9189 / 77f0650 / 48f964d / 5ac3e6b / 73768ef / 1974754 / 83ee9b4 (X1) / a96a14f (model fix) / 9b8e05d (X4)
- vault: 4a02703 / f4e3562 / bebd928 / 4a42163
openclaw silent hang up = 영구 해소 (Sprint X 핵심 가치). ADR-003 BYO credentials = router-openrouter.js 의 apiKey 인자로 base 마련 (Sprint Y/Z 의 prerequisite).
16부 — Sprint Y 완료 (multi-provider abstraction)
Loren 컨펌: "충전은 내일 — 할 수 있는 거 빠르게". 잔액 무관 코드 작업 자동 진행.
MM. Y1+Y2+Y3 router-anthropic.js — 78f4a97
router-anthropic.js (109 줄, 신규):
- callAnthropic(apiKey, model, messages, opts)
- POST https://api.anthropic.com/v1/messages
- Anthropic 형식: system 별도 필드 (messages 안 X), max_tokens 필수, anthropic-version 헤더
- messages 안 role:'system' 자동 분리 → opts.system 또는 payload.system
- 응답 .content[0].text (OpenRouter .choices[0].message.content 와 다름)
- 401/403 → anthropic_auth_failed, 429 → anthropic_rate_limit
router.js model prefix 분기:
anthropic/<model>→ callAnthropic (config.ANTHROPIC_API_KEY)openrouter/<model>또는 prefix 없음 → callOpenrouter (기본)- 에러 분기 통합 (provider 별 auth_failed / rate_limit / timeout)
config.js:
- ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || null
- OPENAI_API_KEY: 후속 placeholder
NN. Y4 staging+prod 배포 + 회귀
기존 OpenRouter path 회귀 0 ([전체 폴백 실패] = 잔액 부족, 분기 정상).
ANTHROPIC_API_KEY env 없어도 path 살아있음 (호출 시 적절한 에러 메시지).
OO. Y5/E router-openai.js — 91b2882
router-openai.js (85 줄, 신규):
- callOpenai(apiKey, model, messages, opts)
- POST https://api.openai.com/v1/chat/completions
- OpenAI 형식 (OpenRouter 와 거의 동일 — OpenRouter 가 OpenAI 호환 채택)
- opts.organization 지원 (OpenAI-Organization 헤더)
- 401/403 → openai_auth_failed, 429 → openai_rate_limit
router.js prefix 분기 추가:
openai/<model>→ callOpenai (config.OPENAI_API_KEY)
Sprint Y 종합 — multi-provider abstraction 4 plugin
| Plugin | 라인 | host | 활성 조건 |
|---|---|---|---|
| router-openrouter.js | 80 | openrouter.ai | OPENROUTER_API_KEY (현재 운영) |
| router-anthropic.js | 109 | api.anthropic.com | ANTHROPIC_API_KEY |
| router-openai.js | 85 | api.openai.com | OPENAI_API_KEY |
| router-stream.js (위임) | 34 | n/a | runAgent 위임 |
| router-fallback.js | 41 | n/a | hardcoded chain |
| router-circuit.js | 55 | n/a | 서킷 브레이커 |
| router.js (메인) | 414 | dispatch | model prefix 분기 |
ADR-003 BYO credentials base 완성: 회사가 자기 OpenRouter / Anthropic / OpenAI key 들고 와서 model prefix만 맞추면 자동 라우팅. 풀 Nexus 파일럿에서 .env 회사별 분리 시 즉시 작동.
17부 — 누적 prod commits 25개 (이번 세션)
| 해시 | 내용 |
|---|---|
0f4d972 | board/login 입력 검증 |
da4eb28 | agents/registry e.message |
145eeee | scores 동적 fallback |
e3cec70 | e.message 5건 |
65a8ca9 | conv-memory userId |
f2555c9 | agent_id 정규화 |
788bc21 | DB 백업 cron |
f9747e4 | monitor /health |
17f4c80 | router-fallback 분리 |
c279864 | router-circuit 분리 |
cde9189 | router-stream 분리 |
77f0650 | auth-oauth-providers 분리 |
48f964d | /api/scores nginx |
5ac3e6b / 73768ef | (debug 추가/제거) |
1974754 | local-db-users 분리 |
83ee9b4 | X1 router-openrouter HTTP 직접 |
a96a14f | model ID dash→dot fix |
9b8e05d | X4 router-stream cleanup (위임) |
78f4a97 | Y1+Y2+Y3 router-anthropic |
91b2882 | Y5/E router-openai |
vault: 4a02703 / f4e3562 / bebd928 / 4a42163 / c22c56f / 본 commit
18부 — 다음 Sprint 진입점
| 순위 | Sprint | 시간 | 비고 |
|---|---|---|---|
| 1 | UX-1 AgentChat token stream (router-openrouter SSE + router-stream 실 SSE) | 1.5~2시간 | 사용자 체감 큼 |
| 2 | UX-2 Telegram bot 인라인 키보드 + MarkdownV2 + multi-turn + 친화 메시지 | 1일 | 첫 사용 진입 장벽 |
| 3 | UX-3 Billing UI Toss SDK (충전 flow + 자동 충전 + 영수증) | 1~2일 | 매출 직결 |
| 4 | AA Hermes 패턴 흡수 (뉴런 인젝션 스캔 + Progressive Disclosure + MoA) | 1~2일 | |
| 5 | Sprint Z 풀 Nexus 파일럿 | 1~2시간 + 회사 정보 | Loren paste 시 |
외부 (Loren 영역, 자기 일정대로)
- 🔴 OpenRouter 잔액 충전 (내일) → X5 자율진화 input 검증 즉시
- ANTHROPIC_API_KEY 발급 (선택 — Anthropic 직접 호출 검증)
- 메모리 RAM 증설 (Sprint Z 다회사 시점 대비)
- 외부 벤더 토큰 10건 (
ROTATE-2026-04-23.md) - claude CLI dev 도구 (Loren PC, Anthropic API key 또는 OAuth)
19부 — Sprint UX-1 AgentChat token stream — 8cc06a8
X4 위임 패턴 (non-stream + onChunk 한 번) → 실 token 단위 SSE. 사용자 체감 quality 50%+ 향상.
router-openrouter.js (80→177): streamOpenrouter — POST stream:true / SSE event 파싱 (data: + [DONE]) router-anthropic.js (109→228): streamAnthropic — Anthropic SSE 형식 다름 (event: + data:, content_block_delta + message_stop) router-openai.js (85→175): streamOpenai — OpenAI 호환 (OpenRouter 와 동일 형식, opts.organization 헤더 지원) router-stream.js (34→104): runAgentStream prefix 분기 + SSE 실패 시 non-stream fallback (graceful degradation) router.js (414→423): _stream.init() inject 7개 deps 복원
검증: staging+prod 200 / 에러 0 / fallback 로그 정확 ("[router-stream] Insufficient credits → non-stream fallback").
20부 — Sprint UX-2 Telegram bot — f437ebf
REPLY_KEYBOARD: /status /help /unlink 자동 키보드 (callback_query 처리 X — ReplyKeyboardMarkup 으로 단순) handleStart + handleHelp: REPLY_KEYBOARD 첨부 + MarkdownV2 escape humanizeAgentResult: router 내부 토큰 + provider 에러 → 한국어 친화 메시지
- "Insufficient credits" → "AI 사용량 한도 도달, 관리자 문의"
- "[전체 폴백 실패]" → "모든 AI 에이전트가 응답하지 못했어요"
- "[타임아웃]" → "응답 대기 시간 초과"
- "[차단]" → "보안 정책 차단"
- "rate limit" → "1-2분 후 다시 시도"
doExecute 응답 path: humanized 분기 + raw escape 자동 처리.
21부 — Sprint UX-3 Billing Toss SDK v2 — a85cf6f (server) + a2b1071 (board)
vault reference_toss_v2_integration.md (paljalab v2 노하우) 그대로 적용.
server billing.js: getPlans 응답에 tossClientKey 추가 (publishable key, frontend SDK 초기화용).
board BillingPage.jsx (447→530):
- tossClientKey state (서버 plans 응답에서)
- Toss SDK v2 동적 로드 (https://js.tosspayments.com/v2/standard) — paljalab 함정 회피 (S3 더미 263 byte 아님)
- successUrl callback useEffect: query parameter (paymentKey/orderId/amount) parsing → billingTopup confirm. URL replaceState 로 중복 방지
- failUrl callback (USER_CANCEL 외 에러 표시)
- handleTopup 분기: · docs 테스트 키 (test_gck_docs_*) → 직접 billingTopup (기존) · 프로덕션 키 → tossPayments.payment().requestPayment() 결제창 · orderId: NEXUS-YYYYMMDD-HEX8 (paljalab 패턴) · customerKey: 'user_' + user.id · orderName: "Nexus Credits N만원 충전"
nginx CSP 갱신 (sites-enabled/nexus 직접 + reload):
- script-src: + js.tosspayments.com + *.tosspayments.com + blob:
- connect-src: + *.tosspayments.com
- img-src: + blob:
- frame-src: 신규 (js.tosspayments.com + *.tosspayments.com)
- worker-src: 신규 ('self' blob:)
board build + deploy: deploy-frontend.sh (npm run build → tar → scp → /var/www/nexus). HEAD a2b1071 적용.
22부 — Sprint AA Hermes 흡수 (12번째 진단 오류)
Hermes P0 (뉴런 인젝션 스캔) 이미 구현 됨:
webhook/modules/prompt-injection-guard.js(94 줄, 15+ 패턴)- brain-writer.append (line 45) + neuron.recordToNeuron (line 43) 양쪽 보호
- 패턴: ignore previous / disregard / forget all /
<\|im_start\|>/[INST]/ system: assistant: user: / developer mode / 등
내 신규 injection-scan.js 중복 → 폐기.
P1 (5단계 대화 압축 + API 키 풀 round_robin) 도 이미:
- ξ-2 4/24 conversation-memory 5단계 압축
- config.OPENROUTER_KEY_POOL (Phase A P1)
남은 가치 (별도 sprint, 잔액 충전 후):
- T-AA-P2: 뉴런 Progressive Disclosure (3단계 컴파일, 토큰 30~70% 절감)
- T-AA-P3: MoA 다중모델 합의 (Claude/Gemini/GPT/DeepSeek 병렬, 정확도 향상, 비용 4배)
23부 — 누적 prod commits 29개 + board 1 commit + vault 6 commits (이번 세션)
prod (29): 0f4d972 da4eb28 145eeee e3cec70 65a8ca9 f2555c9 788bc21 f9747e4 17f4c80 c279864 cde9189 77f0650 48f964d 5ac3e6b 73768ef 1974754 83ee9b4 a96a14f 9b8e05d 78f4a97 91b2882 8cc06a8 f437ebf a85cf6f (server billing)
board (1): a2b1071 (Toss SDK v2)
vault (6): 4a02703 f4e3562 bebd928 4a42163 c22c56f dbdab64 + 본 commit
24부 — 진단 오류 누적 12건
- T10 SOUL .md 1개 → 184
- T10 운영 0 → 60건
- T7 login 회귀 → input validation 누락
- self-managed 토큰 6 → 3
- TB-2 미완 → 이미 구현
- T11-c OpenClaw OFF → 실은 ON
- T11-c /api/watchdog Not Found → bridge 직접 호출 잘못
- T-bridge-split 961 → 이미 471
- T-rot-followup nginx forward → nip.io nexus block 의도된 client token forward
- T11-d-debt dual-mount 4건 → e2e path 잘못
- claude CLI 만료 → claude binary 자체 prod 미설치 (openclaw 의 Ollama 11434 의존이 진짜)
- AA P0 인젝션 스캔 → 이미 prompt-injection-guard.js 구현됨
→ 패턴 동일: 메모리 / grep 표면만 보고 코드 / 환경 직접 측정 생략. 다음 세션부터 accuracy_first 더 엄격 (코드 read 또는 grep 정확 매칭 후 확인).
25부 — T-spam 텔레그램 봇 누출 3건 fix — faf989a
사용자 4/26 보고: 빌링 에러 영문 spam 15+회 (8:22~17:57) + reasoning monologue 누출 (8:22) + feedback-api 빈 URL/Agent 표시 (18:14).
T-spam-D (humanizeAgentResult 패턴 확장) — user-telegram.js:
- "returned a billing error" / "run out of credits" / "insufficient balance" → "AI 사용량 한도 도달" (외부 cron 영문 누출 차단)
- "Context overflow" / "prompt too large" → "메시지가 너무 길어요"
- reasoning monologue ("We will output:" + "However" / "to be absolutely compliant" 등) → "AI 응답 처리 오류"
T-spam-A (응답 sanitize) — user-telegram.js:
<thinking>...</thinking>+<scratchpad>...</scratchpad>tag 제거- 빈 줄 정리 (3개 이상 → 2개)
T-spam-C (feedback-api.js) — 빈 URL "?" 또는 빈 Agent 표시 생략. 동적 lines 배열로 조건부 추가.
T-spam-B-internal (telegram.sendTelegram cooldown):
- 같은 메시지 1시간 내 중복 발송 차단 (외부 cron / monitor.js spam 방지)
- _sentHashes Map (text+topicId hash, 24h TTL, 5% 확률 cleanup)
- opts.bypassCooldown 으로 긴급 alert 우회 가능
- 첫 발송 통과, 같은 메시지 1시간 내 재발송 시 skip + console log
T-spam-B-external 잔액 후: 외부 cron (OpenClaw gateway / evolve.sh 자체 알림) 추적은 잔액 충전 + 실 호출 path 확인 후.
검증: staging+prod restart active / /health 200 / 에러 0 / 회귀 (login+billing+agents) 200 / telegram cooldown 코드 깔림.
26부 — UX-2-B 텔레그램 편의성 보강 — 864fcb8
사용자 요청 "텔레 편의성도 수정". /agents /chains 명령어 + 4096자 분할.
신규 명령어:
- /agents — registry.listAgentsForRole('client') 출력 (id + name + group)
- /chains — chain.getCatalog() 출력 (이름 + step 수 + 키워드 top 5)
- /help 도움말에 둘 다 추가
REPLY_KEYBOARD 갱신: [/agents /chains] [/status /help] [/unlink] 3행
응답 4096자 분할 (splitForTelegram helper):
- line break 우선 분할, line break 없으면 강제 limit
- doExecute 응답에 적용, parts.reduce 순차 await (메시지 순서 보존)
- 이전: text.substring(0, 3500) 잘라버림 → 정보 손실
- 이후: 여러 메시지 분할 발송, 손실 0
라인수: 490 (한도 +-10 미세 초과 — 별도 부채, panels/chains 분리 후보).
검증: staging+prod 200 / 에러 0 / 회귀 endpoint 200.
27부 — T-pipa-export-status false alarm (13번째 진단 오류)
/me/export-status 404 = 우리가 e2e 검증 시 임의 호출. board frontend grep 0건. server는 /me/export 동기 응답 (즉시 export, status endpoint 불필요). 출시 후 비동기 export 도입 시 status 추가 가능.
28부 — 진단 오류 13건 누적
12건 (24부) + 13: T-pipa-export-status false alarm. 패턴 동일 — 메모리/grep 표면만 보고 코드 read 또는 호출처 직접 검증 생략.
29부 — 최종 누적 prod commits 31개 + board 1 + vault 9 (이번 세션)
prod (31): 0f4d972 da4eb28 145eeee e3cec70 65a8ca9 f2555c9 788bc21 f9747e4 17f4c80 c279864 cde9189 77f0650 48f964d 5ac3e6b 73768ef 1974754 83ee9b4 a96a14f 9b8e05d 78f4a97 91b2882 8cc06a8 f437ebf a85cf6f faf989a 864fcb8
board (1): a2b1071 (Toss SDK) vault (9): 4a02703 f4e3562 bebd928 4a42163 c22c56f dbdab64 ce34486 b7a65bf + 본 commit
30부 — 완료 sprint 9개 + 잔여 task 6개
✅ 완료:
- X (router → OpenRouter HTTP)
- Y (multi-provider abstraction)
- UX-1 (token stream)
- UX-2 (텔레 인라인 + 친화)
- UX-2-B (/agents /chains 명령어 + 4096자 분할)
- UX-3 (Billing Toss SDK)
- AA-P0 (인젝션 스캔, 이미 구현)
- T-spam (텔레그램 누출 3건)
- T-pipa-export-status (false alarm)
⏳ 잔여 (잔액 충전 후):
- X5 자율진화 input 검증 (5분)
- AA-P3 MoA (코드 30~60분, 비용 정책)
- AA-P2 Progressive Disclosure (코드 1~2시간, 회귀 위험)
- T-spam-B-external 외부 cron 추적
- Z 풀 Nexus 파일럿 (회사 정보 paste)
⏳ Loren 외부 액션:
- 🔴 OpenRouter 잔액 충전 (4/27)
- ANTHROPIC_API_KEY / personal Toss 키 (선택)
- 외부 벤더 토큰 10건 (
ROTATE-2026-04-23.md) - 메모리 RAM 증설
3부 — chyj1 PC (밤 21시) 오늘 오류 일괄 fix 세션
배경: Loren 지시 "스파이럴/플라이라이트/텔레 로그 — 일단 오늘 오류 다 수정". 서버 텔레/에러 로그 24h 분 + 로컬 코드 + 서버 git/DB 전수 진단 후 6 카테고리 9건 식별. 코드 fix 가능 5건 task 분리 후 순서대로 진행, 각 task 마다 staging+prod 배포·검증.
오류 진단 (E1~E11)
| ID | 오류 | 발생 | 처리 |
|---|---|---|---|
| E1 | router Insufficient credits 무한 재시도 → 100+/h spam | 19:32~20:47 | F1 fix |
| E2 | gemini-2.5-flash-lite-preview-06-17 invalid model ID | 19:32 단발 4건 | 자연 해소 (OpenRouter alias deprecation, claude-bridge restart 시 1회) |
| E3 | router-stream → non-stream fallback | E1 부수 | F1 로 해소 |
| E4 | 텔레 raw 영문 에러 humanize | 미커버 경로 | 이미 적용 (user-telegram.js:283) |
| E5 | Board API DB connection unhandled (ECONNREFUSED/ETIMEDOUT) | 4/25 23:01~13 | F3 가드 보강 |
| E6 | monitor "socket hang up" | 4/26 곳곳 | 외부 서비스 health check, 코드 이슈 X |
| E7 | SQLite database is locked | 4/26 14:51 1건 | F4 진단만 (WAL+busy_timeout=5s 이미 적용, ROI 낮음) |
| E8 | Board API Bind parameters must not contain undefined | 4/26 16:23 | F2 fix |
| E9 | staging .env DB_PASSWORD 누락 → Access denied | 4/26 19:31 | F5 보고 (Loren 승인) |
| E10 | nginx 외부 스캔 봇 (.git/config, wp-content, owa) | 상시 | 정상 |
| E11 | nginx SSL bad key share | 외부 호환성 | 정상 |
F1 — router cooldown (commit a81844c)
webhook/modules/router-openrouter.js (178→235 라인):
- in-memory
cooldownsMap:provider:openrouter(5분) /model:<id>(30분) callOpenrouter/streamOpenrouter진입 시checkCooldown(model)→ 활성이면 즉시 reject- reject error 매칭 시
applyCooldownIfNeeded으로 set _getCooldowns()helper export (운영 가시성)- process restart 시 reset → 충전 후 systemctl restart 즉시 풀림
검증 (60s 후 journalctl):
- 첫 호출 1건:
Insufficient credits... - 동일 cycle 의 fallback 7건:
openrouter_cooldown_provider (Insufficient credits, retry in <5min)✅ - spam 100+/h → 1~2 회/h 로 감소 예상
F2 — board login() 진입 가드 (commit f04d0b0)
webhook/plugins/board/auth/login.js (96→101 라인):
- 4/26 16:23 stack:
pool.execute(SELECT * FROM users WHERE username = ?, [undefined])→ mysql2 reject - 진입 시
username/passwordstring + 비어있지 않음 + 길이 한도(128/256) 검증 → 실패 시 null 반환 (401)
검증: curl POST /board/auth/login {} → {"error":"인증 필요"} HTTP 401, unhandled trace 0건 ✅
F3 — board json() res.headersSent 가드 (commit 9e1bb08)
webhook/plugins/board/index.js (395→398 라인):
- DB connection lost 등 catch 진입 시 헤더 이중 전송 방지
- CLAUDE.md project 規則 ("응답 중복 방지: res.headersSent 체크") 준수
검증: prod /board/health 200 ✅
F4 — SQLite lock (코드 변경 X)
webhook/modules/local-db.js:
- L27
journal_mode = WAL✅ - L30
busy_timeout = 5000✅ - 1건/24h, monitor socket hang up 직후 동시 write 일회성 → 운영 패턴 (monitor 호출 빈도) 재검토는 별도 sprint
F5 — staging .env DB_PASS 적용 ✅
진단 정정 (1차 잘못 짚음): 실제 변수명은 DB_PASS (코드 전수 grep — webhook/plugins/board/shared.js:17, chain.js:18, conversation-memory.js:23 모두 process.env.DB_PASS). 1차에서 DB_PASSWORD 로 검색해서 prod 도 staging 도 둘 다 missing 으로 잡힘.
실제: staging .env 의 DB_PASS= 값만 빈 문자열. 키 자체는 존재.
처리 (Loren 승인 후):
- prod
/home/openclaw/w-ai-agents/.env의DB_PASS값을 pythonre.sub로 in-place replace (비번 stdout 노출 0) - staging
.env백업.env.bak.<ts>생성 후 갱신 systemctl restart claude-bridge-staging→ activecurl :18792/board/health→{"ok":true,"service":"board-api"} HTTP 200(이전 503 해소)access denied잔존 0건
영향: staging-first 회귀 다시 가능. prod 영향 0.
추가 점검 (말고는 없음 답변)
| 항목 | 결과 |
|---|---|
| nginx access 5xx 24h | 0건 |
| claude-bridge fatal/sigkill/oom 24h | 0건 |
| monitor "socket hang up" 24h | 10건 (외부 OpenClaw/팔자/마케팅팩토리/[company] health check, 코드 이슈 X) |
| 외부 cron (T-spam B 가설 검증) | certbot/e2scrub/php/popularity/wai-db-backup/neuronfs(10m). 외부 LLM 호출 cron 0건 → spam 출처 = watchdog 자체. F1 cooldown 으로 해소 |
| telegram bot 호출 빈도 today | 0 (잔액 부족 영향) |
| nemotron/gpt-4o journal grep | 0건 |
종합
✅ 코드 fix 3건 (F1 cooldown / F2 login 가드 / F3 headersSent 가드) — 각 staging+prod ff merge + restart + 검증 ✅ 운영 fix 1건 (F5 staging DB_PASS) — Loren 승인 후 적용 🟡 진단만 1건 (F4 SQLite lock — WAL+busy_timeout 5s 이미 적용, 1건/24h ROI 낮음)
남은 OpenRouter 잔액 충전(4/27) 후 즉시 진행 시퀀스는 project_current_state.md 참조.
4부 — Batch A 점검 중 발견: thumbnail.service 무한 재시작 → 제거
타임라인 (사건 복원)
- 2026-04-08 11:07:15 Loren PC 부재 기간에 누군가
/etc/systemd/system/thumbnail.service생성.WorkingDirectory=/root/youtube-thumbnail-generator. ExecStart=gunicorn 5000. - 2026-04-08 13:31
/root/youtube-thumbnail-generator/마지막 변경 (app.py + database.db + .env 등 완성). - 2026-04-08 14시쯤 systemd 가 service 시작 → gunicorn master pid 270853 + worker 270855/270856 LISTEN 127.0.0.1:5000. 정상 가동.
- 이후 어느 시점부터 systemd 가 같은 unit 을 또 띄우려는 호출이 들어옴 (재기동 trigger 불명). 새 gunicorn 인스턴스가 5000 점유 중인 270853 때문에
[Errno 98] Address already in use로 즉시 fail.Restart=always RestartSec=5→ 5초마다 재시도 → 무한 루프. - 2026-04-26 10:29:50 systemd 가 OpenClaw Gateway 에 SIGTERM (이유: 누적 메모리 압박으로 health failure 추정).
- 2026-04-26 10:30:20 OpenClaw 가 30초 grace 안에 죽지 못함 → SIGKILL.
- 2026-04-26 10:30:21 kernel
app.slice: A process of this unit has been killed by the OOM killer.(OpenClaw 자체) + systemd 자동 재시작. - 2026-04-26 21:09 chyj1 PC Batch A sweep 중 syslog 의 OOM 메시지 발견 → 추적 → thumbnail.service 무한 재시작 발견 (restart counter
149,982) → Loren 보고 → "우리 서버엔 필요없음 버려" 승인.
정체
| 항목 | 값 |
|---|---|
| Description | YouTube Thumbnail Generator |
| 종류 | Flask + OpenRouter 호출 (썸네일 이미지 생성기) |
| 모델 | gpt-5-image / gemini-2.5-flash-image / gemini-3.1-flash-image-preview |
| ADMIN_USERNAME | jis*** (지수님 추정) |
| ADMIN_PASSWORD | 회사 공용 패턴 |
| OPENROUTER_API_KEY | 동일 W AI 키 추정 |
| 외부 노출 | localhost:5000 만 (외부 X) |
| 멀웨어 가능성 | X (정상 Flask 앱 구조) |
처리 (Loren 승인 후 21:22~21:24)
systemctl stop thumbnail.service→ inactivesystemctl disable thumbnail.service→ multi-user.target.wants 링크 제거- 백업
tar czf /root/_archive/youtube-thumbnail-generator-20260426-212259.tar.gz(7.6MB) — 지수님이 나중에 필요하면 복구 가능 - master pid 270853
SIGTERM→ 270855/270856 worker 자동 정리, 5000 free rm /etc/systemd/system/thumbnail.service+systemctl daemon-reloadrm -rf /root/youtube-thumbnail-generator(백업 보관)- 검증: 1분 후 thumbnail 재시작 0건, failed units 0건, 5000 free, swap 1169MB→1103MB
영향
- 즉시 효과: 5초 간격 fork+import+fail spike 정지 → CPU 사이클 + RAM 압박 큰 폭 감소
- 메모리 회수: 즉시 swap 66MB. 더 큰 효과는 누적 압박 해소
- OpenClaw OOM 재발 방지: 4/26 10:30 사건의 진짜 원인이 thumbnail 무한 재시작 → 재발 가능성 크게 낮춤
재발 방지
- 새 PC 세팅 시
systemctl list-units --all+systemctl list-timers로 unknown service 점검 필수 - 모든 systemd unit 은
wai-vault/05-Reference/또는reference_infra.md에 등록 (출처/목적 명시) - 보고: 지수님께 thumbnail 작품 만든 거 맞는지 / 다시 필요하면 백업 복구 절차 (
/root/_archive/youtube-thumbnail-generator-20260426-212259.tar.gz)
5부 — Batch B/C/D 추가 점검 + 추가 fix 4건
Loren 지적 ("확실하더냐") 후 빈틈 보강 batch 4개 분리. read-only sweep + 신규 코드 fix.
Batch B — 누락 로그/DB 점검
| 항목 | 결과 |
|---|---|
| access.log + .1 24h 풀 5xx | F-B1 500 /api/chain/list 1건 (4/25 22:25), F-B2 504 SSE notifications 3건 (4/25 22:56~23:08) |
| board DB audit_logs 테이블 | 미존재 (audit 는 SQLite local.db 사용) |
| local SQLite tables | sessions/rate_limits/audit_cache(526)/agent_metrics/users/daily_counts/events(200)/watchdog_triggers/oauth_temp 정상 |
F-B1 — chain.js list/get catch console.error 추가 (commit 03059d7)
- 4/25 22:25 chain.js:272 의 catch 가 logging 없이 즉시 json(500) → root cause 추적 불가
- chain/list + chain/:id 양쪽 catch 에
console.error('[chain] list/get error:', e.message)추가 - chain/execute(256) 는 이미 logging
- CLAUDE.md security.md 規則 ("에러로깅 빈catch금지") 준수
- 영향: 정상 흐름 변화 0, 다음 500 발생 시 stack 추적 가능
F-B2 — 자연 해소 (코드 변경 X)
- 코드 측 keepalive 25s 적용 + nginx
proxy_read_timeout 24h적용 둘 다 정상 - 4/26 SSE 504 0건 — 4/25 시점 nginx prod drift 한정 (project_nginx_prod_drift.md ✅ 통합 후 해소)
Batch C — F1~F5 검증 보강
| 항목 | 결과 |
|---|---|
| F1 set 동작 | 21:00 검증 (1 DIRECT + 7 COOLDOWN) ✅ |
| F1 expire 동작 | 21:00~21:35 LLM 호출 0건 (서킷 브레이커 추정). 코드 로직 (Date.now() 비교 + delete) 단순 검증 충분, 다음 cycle 자연 검증 |
| F2 staging negative | POST /board/auth/login {} → 401 + unhandled 0건 ✅ |
| F3 staging /board/health | 200 ✅ |
| F5 staging git | 03059d7 (F-B1) 까지 ff merge 반영 ✅ |
Batch D — monitor socket hang up 코드 분석 + 추가 fix 2건
monitor.js (434라인) 검토: timeout 10s + 단일 요청 (retry 없음) + 1~2회는 console+logEvent, 3회 연속 시 telegram alert + cascade trigger. 코드 자체 정상 동작.
개선 영역 2건 식별 → Loren 결정 ("F-D2 + F-D3 추천대로 ㄱ"):
- F-D1 retry 1회 추가 — 보류 (콜백 중첩 + logEvent 빈도↑, ROI 낮음)
- F-D2 1~2회 카운트 logEvent 생략 — 진행
- F-D3 router system prefix 강제 (thinking 금지 + 한국어) — 진행 (영문 reasoning 토큰 낭비 직접 차단)
- F-D4 max_tokens 4000→1500 — 보류 (회귀 검증 필요, 잔액 충전 후 sprint)
- F-D5 응답 sanitize — 보류 (토큰 절감 X)
F-D2 — monitor logEvent 1~2회 카운트 생략 (commit e37ba91)
- monitor.js 의 req.on('error') / req.on('timeout') 에서 1~2회 카운트는 console.error 만, 3회 연속 cascade trigger 시점에만 logEvent
- 4/26 14:51 외부 4종 동시 socket hang up 시 logEvent 다발 호출 → SQLite database is locked 1건 발생 (E7) → 재발 방지
- 정상 cascade telegram alert + Neuron 기록은 변화 없음 (3회 연속 시)
- 433라인 (500 한도)
F-D3 — router system prefix 강제 — thinking 금지 + 한국어 (commit d3d70e4)
- router-openrouter.js 의 callOpenrouter / streamOpenrouter 진입 시 messages 에 system prefix prepend (덮어쓰기 X, 합치기만)
- prefix:
[필수] 사고 과정 출력 절대 금지. <thinking>, "Reasoning:", "Let me think", "We will output", chain-of-thought, monologue 모두 금지. 한국어로 결론만 간결히 - 한+영 양방향 명시로 모든 모델 대응 (Claude/Gemini/DeepSeek 등)
- SOUL.md 와 충돌 X (system role content 첫 부분에만 합침)
- 영향: 모델이 prefix 따르면 output_tokens 30
50%↓ (input +50100 증가, 절감이 더 큼). 텔레 봇 영문 누출 차단 (humanize 와 이중 안전장치) - 254라인 (500 한도)
- 검증: 잔액 충전 후 LLM 호출 cycle 도는 시점에 토큰 비용 비교
종합 (오늘 4/26 전체 fix)
✅ 코드 fix 6건:
- F1 router cooldown (
a81844c) - F2 board login 진입 가드 (
f04d0b0) - F3 board json headersSent 가드 (
9e1bb08) - F-B1 chain catch console.error (
03059d7) - F-D2 monitor logEvent 강등 (
e37ba91) - F-D3 router system prefix 강제 (
d3d70e4)
✅ 운영 fix 2건:
- F5 staging .env DB_PASS 적용
- thumbnail.service 무한 재시작 → 백업 후 제거 (OpenClaw OOM kill 진짜 원인)
🟡 진단 후 변경 X 2건:
- F4 SQLite WAL+busy_timeout 5s 정석 적용
- F-B2 SSE 504 자연 해소
⏳ 보류:
- F-D1 monitor retry 1회 (ROI 낮음)
- F-D4 max_tokens 4000→1500 (회귀 검증 필요)
- F-D5 응답 sanitize (토큰 절감 X)
6부 — 텔레그램 spam + 영어 메시지 fix (F-T1/F-T2)
Loren 지적 2건:
- "텔레로 다 영어로 보냄" → 영어 raw error 메시지 한국어화
- "씨발 100번 넘게 보내" → 같은 사이트 다운/복구 cycle 마다 알림 spam
F-T2 — 같은 사이트 텔레 알림 dedupKey 1시간 cooldown (commit 3a6677d)
진단:
- telegram.js 의
_COOLDOWN_MS=3600000(1시간) cooldown 이미 있었음 - 다만 hash = topicId + text 전체 → e.message 종류 (socket hang up / ECONNREFUSED / ETIMEDOUT / HTTP 502/503/504) 마다 hash 가 매번 달라져 cooldown 무력화
- 같은 OpenClaw 다운이라도 4종 에러 × 깜박임 = 24h 100+ 가능
수정:
sendTelegram(text, topicId, opts)의opts.dedupKey추가 — 명시적 키로 hash (text 전체 hash 우회)- monitor.js 사이트 다운/복구 4곳 명시:
· 다운:
dedupKey: 'site:' + key + ':down'(HTTP 에러 / network error / timeout 통합) · 복구:dedupKey: 'site:' + key + ':up' - 같은 사이트의 같은 상태 알림은 1시간 1번 cap
영향:
- OpenClaw 깜박임 시 1시간당 다운 1번 + 복구 1번 = 최대 2번 cap (이전 100+ → 2)
- 다른 sendTelegram 호출 (cascade/auto-fix/inline-routes) 은 기존 text hash 그대로 (호환)
F-T1 — sendTelegram 영어 에러 자동 한국어화 (commit 2a220b0)
진단:
- monitor/cascade/inline-routes/setup-nexus-loop/agent-improver 등
e.message/err.message영어 raw 를 그대로 sendTelegram 에 전달 - 호출자 일일이 humanize 강제 대신 sendTelegram 진입 시 1회 자동 변환
수정:
_ERR_REPLACEMENTS패턴 23종 추가:
| 영어 패턴 | 한국어 |
|---|---|
socket hang up | 연결 끊김 |
ECONNREFUSED | 접속 거부 |
ETIMEDOUT | 응답 시간 초과 |
ENOTFOUND | 주소 찾을 수 없음 |
EHOSTUNREACH | 호스트 연결 불가 |
EPIPE | 연결 단절 |
EAI_AGAIN | DNS 일시 실패 |
Address already in use | 포트 사용 중 |
Connection lost: The server closed the connection | DB 연결 끊김 |
Connection in use | 포트 충돌 |
Access denied for user ... | DB 접근 거부 (인증 실패) |
Bind parameters must not contain undefined | DB 입력값 누락 |
Insufficient credits ... | AI 사용량 한도 초과 |
openrouter_cooldown_provider (...) | AI 호출 일시 차단(잔액 부족) |
openrouter_cooldown_model (...) | AI 모델 일시 차단 |
openrouter_auth_failed | AI API 키 인증 실패 |
openrouter_rate_limit | AI 호출 한도 초과 |
openrouter_error | AI 호출 오류 |
is not a valid model ID | 잘못된 모델 ID |
request_error: ... | 요청 오류 |
parse_error | 응답 파싱 오류 |
empty_response | 빈 응답 |
Add more credits/using https://... | 잔액 충전 필요 |
humanizeError(text)helper export- sendTelegram 진입 시
opts.skipHumanize미설정이면 자동 변환 - 매칭 안 되는 정상 한국어 텍스트 영향 0
검증 unit test 6 케이스 모두 통과. 215라인 (500 한도).
종합 (오늘 4/26 최종 fix 8건 + 운영 2건)
✅ 코드 fix 8건:
- F1 router cooldown (
a81844c) - F2 board login 진입 가드 (
f04d0b0) - F3 board json headersSent 가드 (
9e1bb08) - F-B1 chain catch console.error (
03059d7) - F-D2 monitor logEvent 강등 (
e37ba91) - F-D3 router thinking 금지 prefix (
d3d70e4) - F-T2 telegram dedupKey cooldown (
3a6677d) - F-T1 telegram 영어 에러 한국어화 (
2a220b0)
✅ 운영 fix 2건:
- F5 staging .env DB_PASS 적용
- thumbnail.service 백업 후 제거 (OpenClaw OOM kill 진짜 원인)
🔴 다음 sprint — 4/27 dm PC
텔레 메시지 layout 재설계 (Loren 4/26 21시 발언: "텔레 이쁘고 효율적으로 애들 잘 만들던데 그거 내일 해야함")
- 시작 시 Loren 이 reference 봇 캡처/링크 가져옴
- 인프라 준비 완료 (오늘 4/26):
telegram.humanizeError(23 패턴 한국어화)sendTelegram(text, topic, { dedupKey })명시적 cooldown 키user-telegram.js humanizeAgentResult(reasoning monologue sanitize)
- 작업 영역 후보: WAT 그룹 알림 layout / 1:1 봇 응답 포맷 / 알림 종류별 일관 layout / 이모지·볼드·구분선 표준화 / 컴팩트 vs 상세 버전
- 호출자 인벤토리: monitor / cascade / auto-fix / inline-routes / setup-nexus-loop / agent-improver / billing