미결 항목
예상 리스크
| 리스크 | 대응 |
|---|---|
| AI Hub 승인 지연 | 1주차 즉시 신청. 4.2절 오류 내성 실험은 텍스트 레벨 오류 주입이므로 승인과 무관하게 진행 가능 |
| 화자 분리 정확도 미달 | [V1] 모노 확인됨. diarization 필수, 데모는 물리 2채널(브라우저 2대)로 우회 |
| 7.2절 팀 개편(장민석이 백엔드·AI 합류)으로 구조적으로 해소. C-5·CI 운영은 정성윤에게 둔 기존 조치는 유지, F-2는 여전히 조건부 | |
| GPU 미확보 | [V2] 확인됨 — Apple M5, CUDA 없음. polyglot-ko-1.3b 등 소형 모델 MPS로 대응, 4개 오픈소스 모델 다운로드 완료 |
| 외국인 화자 한국어 음성 데이터 0건 (신규 2026-08-28) | 대응 미정 — A-3 최대 리스크. AI Hub 다산 데이터는 전부 내국인 발화다. 출처를 못 찾으면 A-3 의 STT 정확도를 측정할 방법이 없다(절대 원칙 10 — 측정할 수 없는 것을 측정한 것처럼 쓰지 않는다) |
| ⓑ 로 좁히면서 1차 지표가 번역 품질이 아니라 STT 정확도(WER/CER) 가 됐다. WER 은 규칙 기반이라 절대 원칙 1 과 충돌하지 않는다. 번역 채점 문제는 ⓐ 확장 시점으로 미뤄진 것이지 풀린 것이 아니다 | |
| 골든셋 13건 — 지표 신뢰 불가 (신규 2026-08-28) | 도메인 축소로 50 → 13건. 다산 기준 재확장 전까지 Recall@5·MRR 을 문서에 기록하지 않는다 |
| A-5 통번역 지연 예산 미계산 (신규 2026-08-28) | ⓑ 1차 범위에는 번역 경로가 없어 STT 지연만 얹힌다. 번역+TTS 왕복은 ⓐ 확장 시점의 문제다. 기획서 4.3절에 항목만 열어 두고 목표치는 비워 뒀다(절대 원칙 2) |
| 범위 과다 (F·G·H·I) | 코어(A~E, C-5)만 절대 사수, 나머지는 6주차 기준선 통과 시에만 조건부 착수 |
원격은 github.com/SeongYuna/call.solidbob.cloud로 연결 완료. 데모 도메인 연결은 Sprint 7 로 미뤄 뒀으나, 미룬 탓에 배포 사이트의 본문 링크가 전부 404 라 2주차로 앞당겼다(프로젝트 페이지의 /call.solidbob.cloud/ 한 겹과 루트 절대경로 링크 405곳이 어긋난다). _project/decisions/102 · w2-custom-domain |
2026-08-28 해소 — 트리거 허용 창을 1,500ms 로 확정했다(
_project/decisions/202). 새 결정이 아니라 2026-08-25 팀 확정의 누락된 반영이다. 코드·사이트는 그때부터 1,500ms 였고_project/plan.md만 800ms 로 남아 있었는데, 그 사실이 어디에도 적혀 있지 않아 3일간 같은 질문이 네 번 올라왔다. 팀 컨펌을 로그에만 적고 결정 기록으로 올리지 않은 것이 원인이다.
정하지 못한 것 (2주차로 넘어감)
골든셋 50건 — 비율은 정해졌고, 측정 방법 두 가지가 남았다
⚠ 2026-08-28 무효. 도메인이 다산 하나가 되면서(
decisions/201) 아래 배분 전체가 의미를 잃었다. 골든셋은 50 → 13건이 됐고, F-2 케이스는 0건이다(다산에 종결 유형이 없다). P1~P7 커버리지도 다시 확인해야 한다 — 아래에서 큰 소득이라 적은 그 커버리지가 삭제된 37건에 실려 있었을 수 있다. 재확장 계획은 부록 C 9번 항목.
배분은 확정됐다(F-2 가중: 금융보험 18 · 쇼핑 16 · 다산콜센터 9 · 질병관리본부 7).
근거는 w2-golden-set-50에 기록돼 있다. P1~P7 개인정보 패턴이
전부 커버된 것이 큰 소득이다 — 1주차 10건에는 P3·P5·P6·P7 이 아예 없어 C-5 “누락 0건”
절대 규칙을 4개 패턴에 대해 측정할 방법 자체가 없었다.
남은 것은 이 표본으로 지표를 어떻게 읽을 것인가다. 둘 다 숫자로 판단할 수 있다.
- B-0 도메인 분류 정확도(≥0.95)의 기저율이 올라간다. 도메인이 18/16/9/7 로 기울어 다수 도메인으로 찍기만 해도 36% 가 나온다(균등이면 25%). 6.1절이 이 지표를 “도메인 내 검색 지표보다 엄격”하게 잡은 취지가 흐려진다 → 균형 부분집합으로 따로 재거나, 다수 클래스 기저율을 함께 보고하면 해소된다
- B(검색) 14건은 2주차 베이스라인용으로 얇다. 도메인당 2~4건이라 Recall@5·MRR 의 분산이 크다. 잠정 베이스라인을 “여러 번 실행한 값 중 최저치”로 고정할 때(절대 원칙 4) 표본이 작으면 그 최저치가 실력이 아니라 운을 반영할 수 있다
배분을 다시 잡자는 게 아니다. 측정 방법에 반영할지만 정하면 되고, 3주차 150건 확장 때 비율을 다시 볼 기회가 있다.
인프라 런북을 하네스로 걸면서 드러난 어긋남 4건 (2026-09-04)
docs/infra-runbook.md 를 각 영역 규칙에 배선하면서(루트 CLAUDE.md §0) 저장소와 다른 곳이 나왔다.
전부 인프라(정성윤) 소관이라 고치지 않고 올린다.
- 배포가 한 파드인가 두 도메인인가. 런북은
server파드 하나에 임베딩·분류기까지 올리고server.solidbob.cloud만 연다(13-1·16-1·19장). 반면 루트CLAUDE.md§3 과ai/CLAUDE.md머리말은ai.solidbob.cloud를 배포 대상으로 적고 있다.decisions/024(검색 스포크를 같은 프로세스에서 꽂는다)와 같은 사안이고,STATE.md의 정성윤 회신 대기 항목이 아직 열려 있다 - 저장소 주소가 다르다. 런북 13장은
github.com/SeongYuna/call.solidbob.cloud.git을 클론하는데 루트 문서·실제 원격은github.com/solidbob02/call.solidbob.cloud다. 한쪽으로 맞춰야 서버에서 그대로 붙여 쓸 수 있다 - 부록 B 의 결정 기록 9건이 아직 없다. 런북 18장은 이미
decisions/103(Cloudflare 프록시 금지)을 참조하지만 파일이 없다. 번호대는 정성윤1xx다(§4) .env.example에OLLAMA_URL·HF_HOME키가 없다. 런북 16-1 은 파드에 둘을 주입한다..env.example은 자격증명 보호 훅이 편집을 막으므로 사람이 직접 채워야 한다(SEC-2)
프론트 연동을 막는 세 겹 중 인프라 몫 (2026-09-09)
프론트가 붙으려면 CORS → DB 스키마 → ES 적재 순서로 세 겹이 열려야 한다. CORS 는 server/ 에서
열었다(w3-cors-dashboard). 나머지는 kubectl 권한이 있는 쪽 일이라 올린다.
- 대시보드를 어디서 서빙할지 정해지지 않았다. 런북은 외부에 여는 주소가
server.solidbob.cloud443 하나라고만 적었고(16-2·18) 대시보드 호스팅은 어디에도 없다. 같은 도메인에서 Caddy 가 정적 파일로 내주면 CORS 가 필요 없고, 다른 origin 이면 배포 env 에CORS_ALLOWED_ORIGINS를 넣어야 한다(런북 16-1 주입 목록에 아직 없다). 런북 16-2 가 참조하는infra/docker/Caddyfile도 저장소에 없다 — 정성윤·조서희 - 런북에 지식베이스 적재 단계가 없다. 15장(Elasticsearch)은 기동·nori 확인까지만이고,
scripts/index_knowledge_base.py --to-es --recreate를 운영 ES 에 도는 절차가 없다. ES 는 ClusterIP 라 밖에서 못 치므로 클러스터 안 Job 이나kubectl exec절차가 필요하다. 이게 없으면/hub/search는 운영에서 계속 빈 인덱스를 본다 — 정성윤(실행)·류준(명령) - DB 스키마 적용은 런북 17장 그대로 정성윤 실행 항목이다. 09-04 의 어긋남 4건과 별개로, 배포 순서에
17장·위 2번 적재가 들어가야 프론트가 붙일 게 생긴다.
2026-09-11: 17장을 실물 기준으로 고쳤다 — 인스턴스에 클론이 없어
raw.githubusercontent.com에서 받고, 서버 파드 안에서 서버와 같은DATABASE_URL로 넣는다(12-2 시크릿 교체가 먼저). 실행은 아직이다 — w4-rds-prod-db
블랙컨슈머 수동 분류 카드 — 결정 기록 없음 (2026-09-10)
apps/dashboard에 통화 종료 후 상담원이 직접 판단해 분류하는 카드를 추가했다
(BlackConsumerAction.tsx). 코드 주석은 “C-6 확장”이라 적었지만, _project/plan.md
rev.5의 C-6은 자동 탐지(고객 욕설·폭언, 재현율 우선 분류기)로만 정의돼 있어
성격이 다르다. 뒷받침하는 결정 기록이 아직 없다(CLAUDE.md §1 원칙 미준수).
정할 것: 결정 기록(조서희 4xx)을 써서 plan.md에 이 서브기능을 공식화할지,
아니면 C-6과 무관한 별도 ID로 뗄지. 지금은 보류.
이번 주 할 일 (1주차)
- AI Hub 회원가입 + 휴대폰 인증 + 데이터 신청 — 5개 데이터셋(
data/raw/) 다운로드·정리 완료 - Google Cloud STT 키 발급 + 이중 캡 설정 완료 (2026-08-25) — 프로젝트
callguard-506606, 서비스 계정callguard-stt@. ① GCP 콘솔 쿼터 하드 리밋:Audio seconds per day1,728,000 → 600,Concurrent StreamingRecognize (global endpoint)→ 5 ② 예산callguard(월 ₩30,000, 50/90/100% 알림) ③.env의STT_MAX_SECONDS_PER_DAY=600/_MONTH=3600. 지출 한도(spending limit) 기능은 Cloud Run·Vertex AI 등만 지원해 STT 에는 걸 수 없다 - 5.6절 V1 확인 — AI Hub 데이터 전부 모노. diarization 필수, 데모는 물리 2채널 우회 필요
- 5.6절 V2 확인 — GPU: Apple M5 MacBook Air, 24GB 통합메모리, CUDA 없음(MPS 가속)
- 5.6절 V3·V4 확인 — Google STT 키 발급 완료, 실측 오디오로 검증. V3: 숫자 정규화가 케이스마다 다름(완전 정규화/부분 정규화/오인식 혼재), 자릿수 낭독형(인증코드류)은 저품질 통화 음성에서 오인식 위험 큼. V4: 첫 interim 962ms, 최종 결과는 발화 종료 후 +346ms — 자세한 수치는 5절 참고
- 인터페이스 스키마 3종 확정 (전사·카드·종결) — 7.3절 v2로 확정. 정성윤이 DB·골든셋과 대조해 불일치 4건(
verdict값,sourceID 기준,evidence유형별 부분집합,segment_id누락)을 잡아내 반영. 결정 기록:_project/decisions/002(v1)·003(v2) - 지식베이스 문서 초안 작성 완료 (
knowledge-base/— 요금제약관·응대매뉴얼·내부처리규정), 팀 리뷰 대기 - 골든셋 10개 초안 작성 완료 (
golden-set/v1-10.json), 팀 리뷰 대기 - 평가 하네스 골격 설계 완료(류준) —
services/core/eval/, 단위테스트 24개 통과. CI 연결(정성윤)은 남음 - 트리거 허용 창 확정 — 보완지시서 1번 안 A 채택, 0~800ms → 0~1,500ms로 확정(2026-08-25 팀 컨펌). 안 B(침묵 임계값 실측 후 역산)는 보유 데이터로 발화 간 침묵 길이를 잴 수 없어 기각. 3주차 v1은 자체 침묵 타이머 대신 Google STT
is_final기반으로 설계(정성윤 제안) — 1,500ms 산식도 “STT 엔드포인팅 +346ms 실측 + 판정 여유”로 갱신. 4.1절·6.1절·trigger.py반영 완료,harness.py가report["trigger"]["latency_ms"]로 p50/p95/p99 자동 계산 → 티켓 - 데모 도메인 확정 — 가상 통신사 “한별텔레콤” 대신 실제 확보 데이터 4종(금융보험·다산콜센터·쇼핑·질병관리본부) 전부 지원으로 확정(2026-08-26).
_project/decisions/004-데모-도메인-4종-확정.md - 골든셋 재작성 — 4개 도메인 기준으로 10건 재작성 완료(2026-08-26). 금융보험 4·다산콜센터 2·쇼핑 3·질병관리본부 1, F-2는 금융보험·쇼핑에만.
pytest services/core27개 통과.w1-golden-set-10.md. 팀 리뷰(지식베이스 포함) 완료 — 2026-08-26 팀 회의 - 검수 방식 — 규칙을 없앴다 (2026-08-27) — 완료 시 팀 리뷰·승인을 요구하던 규칙(§7.4, 4주차 말 체크포인트)과 계약 변경 시 합의를 요구하던 규칙(
ai·server/CLAUDE.md)을 전부 걷어냈다. 네 사람이 같은 공간에서 일하므로 필요하면 그 자리에서 말로 맞춘다 — 문서로 절차를 만들 이유가 없었다._project/decisions/023(008 철회) - DB 스키마·ERD 도메인 재검토 —
plan테이블 제거,subscriber→customer정리,call.domain컬럼 신설,closure.closure_type/evidence를 금융보험(상품해지·보상)·쇼핑(반품·교환) 기준으로 교체(2026-08-26, 17→16개 테이블)._project/decisions/006-db-스키마-도메인-정리.md, 16절 ERD - 도메인 라우팅 방식 확정 — 자동 분류로 결정(수동 선택 안 함, 2026-08-26). 평가 하네스에 B-0 배선 완료(정확도 목표 ≥0.95), 실제 분류기 구현은 후속.
_project/decisions/007-도메인-라우팅-자동분류-확정.md, 3.2절 - 팀 개편 확정 — 3인(정성윤·류준·장민석) → 4인(정성윤·류준·장민석·조서희). 플러터 앱 중단, 장민석 백엔드·AI 합류, 조서희 프론트엔드 신규 합류(2026-08-26).
_project/decisions/005-팀-개편-4인-체제.md - 백엔드·AI(류준·장민석) 내부 세부 분담 — 처음에는 기능별로 나누지 않고 둘이 함께 하기로 했으나(2026-08-26), 같은 날
fastapi/가server/·ai/두 서브도메인으로 갈리면서 나눌 경계가 실제로 생겨 디렉터리 경계를 그대로 담당 경계로 삼았다: 류준ai/(모델 학습·청킹·BM25·리랭크·임베딩·LangGraph·평가 하네스), 장민석server/(파이프라인·클린 아키텍처·계약·요청 경로). 경계에 걸친 작업은 여전히 함께 정한다._project/decisions/012-백엔드-ai-server-담당-분리.md, 7.2절 - AI 모델 구성 전면 확정 — Opus 교차검증 반영, 검증 가능한 주장(모델 존재·설정 파일·라이선스·추론 속도) 전부 확인 후 확정(2026-08-26). 임베딩
ko-sroberta-multitask→KoE5(128토큰 truncation 실측 확인, 1024차원), 생성exaone3.5:2.4b→EXAONE-4.0-1.2B(250토큰 2.0~2.1초로 더 빠름,think:false+/api/chat필수), 분류기·NER은 유지하고klue/roberta-base를 분류기 대조군으로 추가._project/decisions/010-AI-모델-구성-확정.md, 3.1절 - 분류기·NER 실제 비교 측정 (신규, 후속) —
klue/roberta-base대조군 vsKcELECTRA-base는 5주차 오류 내성 실험에서, 생성 대조군kanana-1.5-2.1b-instruct(6주차, 아직 로컬에 못 받음 — Ollama 공식 라이브러리·hf.co/kakaocorp/...GGUF 둘 다 안 됨, 재시도 필요) vsEXAONE-4.0-1.2B는 6주차 환각 건수 비교에서 실측한다. NER 의 P6(인명)·P7(상세주소)은 2026-08-27server/에 규칙 기반 폴백을 넣어 골든셋 누락 0건을 달성했다(w3-masking-c5done). 다만 규칙은 문맥 있는 이름·어절 2개 이상인 주소만 잡는다 — 일반 NER 은 여전히ai/몫이다 → 10-01 안 한다 — 학습하지 않기로 함(210), 발표 뒤 범위 밖(138) → 10-02 정정 — 「안 한다」 는 절반만 맞다. 생성 모델 비교는 09-15 에 끝났다(decisions/207— kanana 채택, 같은 조건 원출력 환각 96 → 27 카드,w6-generation-model-compare·w6-hallucination-eval). 하지 않은 것은 분류기·NER 비교다(210). 10-01 꼬리말은 티켓을 대조하지 않고 적었다 - 시멘틱 청킹 vs 「1 조항 = 1 청크」 — 4주차 비교 측정 (신규, 2026-08-27) — LG CNS AICC 페이지를 열어 보니 상용은 시멘틱 청킹을 쓴다고 밝히고 있다(9.3.1). 우리는 1 조항 = 1 청크 고정이고 근거도 있다 — 청크가 조항 경계를 넘나들면
doc_id정확 일치 채점이 깨진다(하나의 청크에doc_id를 하나만 달 수 있다). 다만 재본 적이 없다. 4주차 리랭킹·하이브리드를 붙일 때standard애널라이저 비교와 함께 시멘틱 청킹 인덱스를 따로 적재해 Recall@5·MRR 을 대조하면 된다(재적재가 1초라 비용이 거의 없다). 채점을 유지하려면 청크마다 «대표 조항 ID» 를 달아야 하므로 평가 방식도 같이 정해야 한다 — 류준 님 영역 → 10-01 안 한다 — 「1 조항 = 1 청크」 유지, 범위 밖(138) → 10-02 정정 — 「안 한다」 가 아니라 09-15 에 쟀다(w4-chunking-compare, 골든셋 v1-150 B 항목 n 96 · 커밋38f2fc3-dirty— dense 엄격 Recall@5 조항 0.979 · 고정 200/50 0.896 · 시멘틱 0.625, 느슨 채점으로도 94 > 90 > 89건). 그래서 「1 조항 = 1 청크」 를 유지한다. 10-01 꼬리말은 티켓을 대조하지 않고 적었다 - 배포를 한 컨테이너로 할지 둘로 나눌지 — 해소. 한 컨테이너·한 도메인 (2026-09-03,
_project/decisions/105) — ①을 골랐다.CLAUDE.md·docs/harness.md·README.md·docs/07·ai/CLAUDE.md의ai.solidbob.cloud서술을 지웠고, 클라우드플레어 자리표시자ai레코드도 지운다. 새 결정이 아니라024의 미반영분이다 —024가 「같은 프로세스」를 정한 순간 배포 단위는 이미 하나였다. 아래는 당시 기록 그대로다(절대 원칙 8). 검색 스포크를 같은 프로세스에서 꽂기로 했다(_project/decisions/024).ai/에 HTTP 표면도 웹 프레임워크 의존성도 없어(라이브러리이지 서비스가 아니다) HTTP 호출은 없는 서비스를 새로 만드는 일이 되고, 4.1절 p95 ≤1,000ms 예산에 네트워크 홉을 더할 이유도 없었다. 그런데CLAUDE.md는server.solidbob.cloud·ai.solidbob.cloud두 도메인을 적어 뒀다 — 같은 프로세스면 한 컨테이너에 둘이 함께 실린다. 지금은ai/에 서비스 실체가 없어 모순이 드러나지 않지만 배포를 짤 때 정해야 한다: ① 도메인 서술을 한 개로 고칠지 ② 나중에ai/를 서비스로 올리고 HTTP 어댑터로 전환할지(되돌리는 법은decisions/024에 있다). 참고로serverCI 는ai/의존성 없이도 그대로 돈다 — 못 꽂으면 조용히 501 로 남는다 - 프론트 ↔ 백엔드 계약이 어긋나 있다 — 연동 전에 맞춰야 한다 (신규, 2026-08-27) —
frontend를 일부러 머지하지 않고 백엔드끼리만 진행 중인데, 파일이 안 겹쳐도 계약은 어긋난다.apps/dashboard/src/types/contract.ts를 지금 값과 대조해 2건이 나왔다. ①ClosureType의"사고·보상"→"보상"— DBCHECK·골든셋 16건·F-2 게이트가 전부"보상"이다(3:1로 프론트만 다르다). 지금 값으로 종결 요청을 보내면 게이트가 422 로 거부한다 — 비슷한 이름을 눈감아 주지 않게 만든 규칙에 그대로 걸린다. 이건 오탈자에 가까워 프론트가 고치면 끝난다. ②segment_id를string으로 쓸지number로 쓸지 — 아직 아무도 정하지 않았다. 7.3절 예시가"seg_0031"이라 프론트가 문자열로 구현했는데,transcript_segment.segment_id는BIGINT이고 서버 요청 스키마도int다. 코드와 DB 는 서로 맞고 계약 예시만 어긋난 상태이며, 2026-08-27w2-mysql-persistence에서 이미 발견해 «예시를 고칠지 타입을 바꿀지 팀 결정»으로 남겨뒀던 건이다. 그 사이 프론트가 문자열 위에 컴포넌트를 쌓았다. 정할 것: 7.3절 예시를31로 고칠지, 아니면 DB·서버를 문자열로 바꿀지(후자는BIGINTPK·FK 를 건드려야 해서 비용이 크다). ⚠ 진짜 위험은 「머지를 미루는 것」이 아니라 「계약 변경이 코드 머지와 별개로 전파되지 않는 것」이다 — 지금처럼 가면 연동 시점에 한꺼번에 터지고, 그때는 프론트가 이미 그 타입 위에 쌓여 있다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
apps/call/src/types/contract.ts:39가 이미"보상"이고segment_id는 문자열로 정리됐다. 09-14closure재정의(decisions/305)로closure_type자체가 계약에서 빠졌다
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- 백엔드 생산성을 막는 규칙 4건 완화 — 팀 논의 필요 (신규, 2026-08-27) — 지금 백엔드를 굴리는 류준·장민석 둘이 규칙에서 계속 멈춘다. 규칙 대부분이 08-25~26에 코드가 거의 없던 시점에 세워졌고, 8-27 하루에
server/가 테스트 311개·엔드포인트 14개가 되며 전제가 달라졌다. 제안 4건: ① 담당 디렉터리 경계에서 「소유(알고리즘·판정)」와 「배선(포트 주입·import·문서 참조)」을 갈라 배선은 상호 가능하게 — 오늘 경계에서 멈춘 것이 6건이고 그중 하나가 하네스에 C-5·F-2 를 꽂는 3줄이었다(그 3줄이 프로젝트 첫 실측값이다)..importlinter계약 7종이 이미 구조 위반을 잡으므로 안전장치는 있다 ② F·G·H·I 동결에 해제 조건을 붙인다 — 지금은 조건이 「코어 기준선 통과」인데 기준선이 0개라 사실상 영구 동결이다 ③ 미결 항목 전용X-접두어 — 기획서에 없는 아이디어는 붙일 ID 가 없어 제안 단계에서 막힌다 ④ 결정 기록 번호를 담당자별 번호대로 — 하루에 두 번 겹쳐 참조 16곳을 고쳤다. ⚠ 절대 원칙 1·2·8·9·10 과 진행 기록·티켓 규칙은 건드리지 않는다 — 그건 프로젝트가 평가받는 근거다. 초안:_project/decisions/022-백엔드-생산성-규칙-완화.md. ① 의 핵심 마찰은 류준이decisions/023으로 해소했다(협의를 절차로 요구하던 규칙 전부 삭제). ✅ ②③④ 도 2026-08-27 확정·반영됐다 — 아래 「확장을 막던 규칙 4건 완화」 항목이 결과다. 그 과정에서 ②(동결 해제 조건)의 진단이 틀렸음이 드러났다: 해제 조건은 원래부터 기획서에 있었고(「6주차 종료 시점에」)CLAUDE.md에서만 빠져 있었다. 새 조건을 만들지 않고 원문을 복원했다- → 닫음 (2026-09-22 장민석): 본문대로 ①은
023, ②③④는 08-27 확정(아래 「확장을 막던 규칙 4건 완화」). 담당 잠금은302로 풀렸다
- → 닫음 (2026-09-22 장민석): 본문대로 ①은
- 평가 하네스에 C-5·F-2 를 꽂으면 이 프로젝트의 첫 실측값이 나온다 — 류준 님 확인 요청 (신규, 2026-08-27) — 하네스(
ai/apps/evaluation/harness.py)는Ports(...)에 구현을 꽂아야 채점하는데main()이Ports()빈 채로 부르고 있어 전부 「측정 불가 — 모듈 미구현」으로 보고된다. 그런데 C-5 마스킹·F-2 게이트는 2026-08-27 실제로 구현됐다(w3-masking-c5·w7-closure-gate-spokedone). 장민석이 파일을 고치지 않고 시험 삼아 꽂아 돌린 결과:masking {miss_count: 0, absolute_rule_passed: true, n: 12}·closure_gate {accuracy: 1.0, absolute_rule_passed: true, n: 16}(v1-50기준.v1-10은 각 n=3). 절대 원칙 2·5상 지금 이 프로젝트에는 문서에 쓸 수치가 하나도 없는데, 이 둘은 당장 낼 수 있다. 고칠 곳은harness.pymain()한 곳이고(Ports()→Ports(masking=..., closure_gate=...)+ import 2줄), 의존 방향(ai → server)은 열려 있어 계약 위반이 아니다. 정할 것: ①main()기본 골든셋을v1-10→v1-50으로 올릴지 ② CI 에서 하네스를 돌려 E-4 기준선 미달 시 실패를 언제부터 켤지 — 지금 켜면 미구현 4종 때문에 계속 빨간불이다.ai/apps/evaluation/은 류준 님 영역이라 손대지 않았다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
scripts/run_eval.py가Ports(...)에 masking·closure_gate 를 꽂아 돈다 — 09-21 재측정에서masking누락 0 · n 28 로 채점됐다. F-2 는 꽂혀 있으나 채점 케이스가 0건이라 측정 불가(decisions/118)
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- P6·P7 NER 구현 —
ai/몫 (신규, 2026-08-27) — ✅ 2026-09-15 구현됐다 —ai/apps/pii_ner(사전학습 NER + 규칙 두 겹), 골든셋 누락 0. ⚠ 운영 이미지에는 아직 모델 파일이 없어 규칙만 돈다(decisions/208대기) — 「구현했다」와 「운영에 올렸다」는 다른 문제다. 원문 —server/apps/masking/에 규칙 기반 폴백을 넣어 골든셋 C-5 누락 3건 → 0건이 됐지만, 이건 2.4절이 정한 NER 이 아니다.server/.importlinter계약 2 가server/안의transformersimport 를 금지하므로 모델은ai/에 있어야 한다. 규칙이 못 잡는 범위: P6 는 문맥 없는 이름("그 김민준 씨가"), P7 은 단독 어절 주소("테헤란로요"). 어댑터가PARTIAL_PATTERNS = ("P6","P7")로 이 사실을 드러내고, 한계를 고정하는 테스트도 있다(NER 이 붙으면 그 테스트가 뒤집히고 지워진다). 정할 것: ①ai/의 NER 을 어떤 포트로 부를지 ② 규칙과 NER 을 합칠지(누락 0건 우선이면 합집합) 아니면 대체할지. 류준 님과 경계를 맞춰야 한다 - ES 인덱스 — 단일 인덱스 +
domain필터로 확정 (2026-08-27) — 4개 도메인을 별도 인덱스로 만들지, 하나에domain필드로 두고 필터할지가 적재 자체를 막고 있었다.single(callguard-kb-single)로 간다. 근거: 조항이 102개뿐이라 나누면 인덱스당 20~34건이 되어 BM25 IDF 가 불안정해지고(health 21·dasan 20), 얻는 이점(도메인별 독립 재적재)은 전체 재적재가 1초도 안 걸리는 지금 있으나 마나다. ⚠ 이건 판단이지 실측이 아니다 — 점수를 내려면 검색 구현체가 있어야 하는데 아직 없다._project/decisions/017-es-인덱스-단일-인덱스와-도메인-필터.md, w2-kb-index - 도메인이 늘면 도메인별 인덱스로 전환 (조건부, 2026-08-27) — 위 결정은 지금 규모에 대한 것이다. 볼륨 증가만으로는 바꾸지 않는다(청크가 1000배 늘어도 40MB 라 샤드 하나에 들어간다). 아래 중 하나가 참이 되면
--layout per-domain으로 전환한다: ① 도메인이 4개를 넘어 크게 늘어난다(특히 고객사별 KB — 필터 선택도가 25%→1~2%로 떨어지면 filtered HNSW 의 recall 이 무너진다) ② 단일 인덱스가 샤드 2개 이상을 필요로 한다(BM25 점수는 인덱스가 아니라 샤드 단위라, 단일 인덱스의 “전역 IDF” 장점이 그때 사라진다) ③ 전체 재색인이 “커피 한 잔” 넘게 걸린다 ④ 도메인별로 보존기간·권한이 갈린다. 전환은 alias 를 앞에 세우는 방식으로 — 쓰기는 도메인별 인덱스, 읽기는callguard-kbalias. 소비 측 코드는 안 바뀐다. 코드는 이미 양쪽을 지원한다 → 10-01 조건 미충족(도메인 1개) — 닫는다 — 2026-08-28 실측하지 않고 닫는다. 도메인이 하나가 되어singlevsper-domain사후 실측 (2026-08-27)per-domain이single과 같은 것이 됐다. 비교할 대상 자체가 사라졌으므로 실측 없이 종료한다(측정 결과가 나온 것이 아니다). 원문: —w2-naive-rag로RetrievalPort구현이 생기면 골든셋v1-50의 B 케이스 14건으로 양쪽 Recall@5·MRR 을 재서 위 판단이 맞았는지 확인한다. 진행을 막지는 않는다 — 이미single로 간다. 반대 방향 요인도 있다: 도메인별 IDF 가 그 도메인 안에서는 더 잘 변별할 수 있다(“환불”이 쇼핑에서 흔하다는 사실은 쇼핑 검색에 반영되는 게 맞다)- Elasticsearch 로컬 구성을
infra/하나로 합쳤다 (2026-08-27) — 병합으로 루트docker-compose.yml(ES 9.5.1, 기동 시 nori 설치)과infra/docker-compose.yml(PostgreSQL + ES 8.15.3, 이미지에 nori 굽기)이 동시에 존재했다. 둘 다 9200 을 잡아 같이 뜨지 않는다.infra/하나로 합치고 ES 를 9.5.1 로 올렸다 — 버전은 논쟁이 아니라 실측이 정했다:ai/requirements.txt가 고정한 9.x 클라이언트는 8.x 서버에 접속 자체를 거부한다(media_type_header_exception ... found 9). nori 는 이미지에 굽는 쪽을 골랐다(오프라인·기동 속도).cd infra && docker compose up -d하나로 DB+ES 가 함께 뜬다. 실적재 102건·ai통합 테스트 5건 skip→통과로 확인._project/decisions/020-로컬-도커-환경-infra-단일화.md - RRF 를 어디서 계산할지 —
ai/코드로 확정 (2026-08-27) — ES 의retriever.rrf는 8.15.3·9.5.1 양쪽 다 basic 라이선스에서403 non-compliant다(장민석 실측). 버전을 올려도 안 풀린다. 30일 trial 은 만료가 2026-09-26 이라 프로젝트 종료(10-27)를 못 넘기고, OpenSearch 로 교체하는 건 2주차에 엔진을 바꾸는 비용이 크다. → 순위 병합을ai/검색 코드에서 계산한다(_project/decisions/021). RRF 는 원래1/(k+rank)합이 전부라 몇 줄이고, 우리 코드 안에 있으면 평가 하네스가k를 바꿔 가며 채점할 수 있다 — 절대 원칙 1·9 와 같은 방향이다. 막힌 것은 순위 병합 하나뿐이고 BM25·kNN·nori·dense_vector·collapse는 basic 에서 전부 된다. 4주차 하이브리드에 적용한다. 랭체인EnsembleRetriever도 검토했다 — 그게 하는 일이 정확히 weighted RRF 라 라이선스를 피해 가는 길이 아니고(같은 알고리즘·같은 클라이언트 위치),ai/CLAUDE.md4번(“랭킹 산식은 순수 파이썬”)과 계약 3(domain·evaluation에서langchain금지)에 걸린다. 게다가BaseRetriever↔RetrievalPort글루가 아끼는 10줄보다 길고, 같은 인덱스에 두 질의를 던지는 우리 구조에서는_msearch왕복 1회가 2회가 된다. 랭체인은orchestration(랭그래프)에 쓰고 랭킹 산식에는 쓰지 않는다 - 브랜치 구조 통합 — 하지 않기로 결정 (2026-08-26) — 네 브랜치(
PM/backend/ai/frontend) 체제를 그대로 유지한다. 통합 검토 과정에서 확인된 사실은 남겨둔다: ① 네 브랜치가 실제로는 같은 파일 영역(jekyll/_backlogs,fastapi/apps/hub/app/*)을 만지고 있어 격리 효과가 크지 않다 ②ai·backend는 둘 다 백엔드·AI 작업인데 7.1절은 그 일을 “둘이 함께” 하라고 정해 브랜치가 둘인 것 자체는 모순이다 ③main에 브랜치 보호 설정이 없다(2026-08-26 확인) —pages.yml이mainpush 시 즉시 공개 배포이므로 PR·CI 가 현재 유일한 게이트다. 통합을 안 하기로 한 이상 이 게이트를 계속 지키는 것이 더 중요해졌다. 충돌 자체는 브랜치 문제가 아니라 분담·티켓 선점의 문제이므로, 그쪽(착수 시status: in-progress로 선점 + 자주 푸시)으로 대응한다 - 수동 검색·통화 후 처리 메시지를 7.3절 계약에 올릴지 (신규, 2026-08-27) — B-6으로 “관련 문서 없음”이 떴을 때 상담원이 직접 찾는 경로를 화면에 넣었는데, 계약 3종(전사·카드·종결)에는 이 요청·응답이 없다. 프론트가 임시로
ManualSearchRequest { call_id, query }+ 응답은 카드 이벤트 재사용(source_type: "auto" | "manual"추가)으로 정의했고, mock 에서만 동작한다. 실서버 경로는 “아직 연결되지 않았습니다”로 응답한다 — 임의 형식을 보내면 서버가 모르는 메시지로 버려 화면이 결과를 기다리게 되기 때문이다. 결정할 것 두 가지: ① 자동 추천과 같은 WebSocket 채널로 보낼지, REST 로 뺄지(요청·응답이 1:1 이라 REST 가 자연스럽다) ②source_type을 계약에 정식으로 넣을지, 프론트 표시용으로만 둘지. D절 통화 후 처리(CallWrapUp { summary, category, follow_ups })도 같은 처지라 함께 정한다 — 요청·응답이 1:1 이고 통화가 끝난 뒤에 오가므로 REST 가 더 자연스럽다. 단 D-4(지식베이스 공백)는 서버가 줄 수 없는 값이라 계약 대상이 아니다 → 10-01 REST(POST /hub/search·/close)로 정착했다(w4-dashboard-live-contract) — 닫는다 - 브랜치 이름을 담당 디렉터리에 맞췄다 (2026-08-26) —
backend→ai(류준) ·ai→server(장민석). 브랜치 수는 넷 그대로다(위 항목의 “합치지 않는다”는 유지)._project/decisions/012가 이 개명을 “룰셋의 필수 통과 검사 이름까지 바꿔야 한다”며 미뤄뒀는데 그 전제가 틀렸다 — 검사 이름은test.yml의 job 이름(server·ai·jekyll)이지 브랜치 이름이 아니라서, 실제로 고친 곳은 push 트리거 한 줄뿐이고 admin 권한도 필요 없었다. 삭제 전 두 옛 브랜치가main의 조상임을 확인해 미머지 0건. ⚠ 오늘 이전 기록의ai브랜치는 장민석을 가리킨다 — 이름이 사람을 갈아탔다._project/decisions/015-브랜치명을-담당-디렉터리에-맞춘다.md, w2-branch-rename generation·compliance를ai/에 두는 것 — 장민석 확인 필요 (신규, 2026-08-26) —.claude/rules/rfp-harness.md §3.1은 B-4~B-6(generation)·C-1~C-4(compliance)의 코드 위치를server/apps/로 적어 뒀지만, 이건fastapi/분리 이전 표기다. 두 모듈 다 모델(EXAONE·분류기)을 로드하는데server/.importlinter계약 2가server/안의torch·transformers·langchain·langgraphimport를 금지하므로 거기서는 만들 수 없다. 문서를ai/apps/로 정정하고 architecture §1에 근거를 남겼으나, 담당이 류준으로 바뀌는 변경이라 장민석 님 확인을 받아야 한다. 이견이 있으면 대안은 “server/에 얇은 배선만 두고 모델 호출은ai/포트 구현으로 빼는” 쪽이다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
ai/apps/generation·ai/apps/compliance가 실제로 거기 있고server/.importlinter계약 2 가 그 위치를 강제한다. 담당 확인 절차는decisions/302로 없어졌다
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- Neo4j(그래프 DB) 도입 여부 — 보류 (2026-08-27) — 저장소 전체를 검색해도
Neo4j·그래프 DB·GraphRAG언급이 0건이다. 기획서·3.1절 투입자원 어디에도 없어 새 도구 도입 결정이 필요한 사안이다(1.1절 “투입자원 목록이 이미 답을 가리킨다” — 목록 밖 도구는 Ollama 처럼 예외 절차를 밟는다). 현재 지식베이스는 조항 102개짜리 평면 구조이고 검색은 BM25+임베딩이라 조항 간 그래프 관계를 쓰는 설계가 없다. 쓰려면 용도부터 정해야 한다 — 용도 없이 도입하면 투입자원 목록만 늘어난다 → 10-01 안 한다 — 범위 밖(138) - 랭그래프·랭체인 실제 도입 (
ai/— 류준 담당) — 영역 규칙이 “한다” 목록에 올려두고orchestration디렉터리도 예정 표에 있으나, 의존성·코드가 둘 다 없다(2026-08-27 확인).server/.importlinter에는 금지 대상으로만 등록돼 있다 —server/가 import 하면 계약 위반이라는 뜻이지 설치돼 있다는 뜻이 아니다. 파이프라인 배선은 이미 포트로 끝나 있어 오케스트레이션이 없어도 동작하므로, 실제로 필요한 시점(생성·리랭킹 체인)에 도입 여부를 정한다 → 10-01 안 한다 — 규칙 배선으로 끝났다(138) RetrievalPort에 도메인을 넘길 방법이 없다 (신규, 2026-08-27 실측) —retrieve(utterance, top_k)시그니처에 도메인이 없어서 평가 하네스가 B-0 라우팅 결과를 넘겨줄 수 없다. 지금은 4개 도메인 전체를 검색한다. 그 대가가 실측으로 보인다: 못 맞힌 2건(GS-001·GS-019)의 상위에 다른 도메인 문서가 올라와 있다(금융 질의에DASAN-MANUAL-4.1·HLT-MANUAL-1.4). 어댑터 생성자에domain=을 임시로 열어 뒀고 필터가 듣는 것은 확인했지만, 포트 시그니처 변경은server/소관이라 장민석 님과 합의가 필요하다.w2-naive-rag- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 도메인 라우팅은
decisions/201로 폐기됐다 — 다산 단일 도메인이라 넘길 도메인이 없다
- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 도메인 라우팅은
- nori 개선 폭을 잴 수 없게 됐다 (신규, 2026-08-27) — 8주 로드맵은 4주차에 “nori 인덱스”를 넣어 개선 폭을 보여주기로 했는데,
w2-kb-index색인 매핑이 이미 nori 라 베이스라인에 포함돼 버렸다(2주차 티켓 문구는 “nori 없이 BM25 만”이었다). 재려면standard애널라이저 인덱스를 따로 적재해 같은 골든셋으로 비교해야 한다 — 재적재가 1초라 언제든 가능하다. 4주차 비교 항목을dense_vector·RRF·청킹전략 3종으로 좁힐지, nori 대조군을 만들지 정한다 → 10-01 안 잰다 — 기준선은 BM25(nori) 구성(run 9)이다. 범위 밖 TranscriptEvent에 이벤트 도착 시각이 없다 — 트리거 지연을 잴 수 없다 (신규, 2026-08-27) → 2026-09-14 콜 미디에이터가received_at_ms를 싣고 트리거가 쓴다(w4-trigger-arrival-time). 실시간 경로의trigger_at_ms는 이제 측정값이다. 평가 하네스는 여전히 측정 불가 — 골든셋에 도착 시각이 없다. 아래 원문은 그대로 둔다 — —TriggerPort.decide(event)가 받는TranscriptEvent에는utterance_end_ms(발화가 끝난 시각)만 있고 이벤트가 언제 도착했는지가 없다. 그래서 발동 시각을 “발화 종료 + STT 최종 결과 지연(V4 실측 346ms)”으로 모형화했고, 그대로 채점하면 지연 분포가 상수 하나로 수렴한다(p50 = p95 = 346, 적절 발동률 1.0) — 숫자는 나오지만 측정이 아니다. 그래서 서버 경로에는 꽂고(발동 여부는 진짜 판정이라 파이프라인이 흘러야 한다) 평가 하네스에는 일부러 꽂지 않았다(절대 원칙 10). 고치려면 콜 미디에이터가 도착 시각을 실어 보내고 포트가 받아야 하는데 계약 변경이라server/(장민석)·콜 미디에이터(정성윤) 합의가 필요하다. 그때까지의 통로로IsFinalTrigger(now_ms=...)를 열어 뒀다. w3-trigger-v1- nori 복합명사 분해 — 사용자 사전으로 해결 (2026-08-27) — 장민석 님이 찾아준 건.
_analyze로 확인해 보니decompound_mode문제가 아니라 사전 미등재였다:mixed는 멀쩡하다(수수료→수수료·수수·료로 원형+조각을 제대로 낸다). mecab-ko-dic 에 없는 말이라 미등록어 분해로 떨어지면서해지가하+아+지(동사 활용)로 오분석된 것이다. 조항 제목의 4글자+ 명사 24개를 전수 검사해 3개를 찾았다 —중도해지수수료·생활하수도·에스컬레이션.user_dictionary_rules로 등록하니중도해지수수료 · 중도 · 해지 · 수수료로 정상화됐다. ⚠ 재측정 결과 Recall@5·MRR 은 변하지 않았다(0.857 / 0.702 그대로) — 골든셋 14건 중 이 세 용어를 쓰는 질의가 없다. 토큰화는 고쳤지만 개선 효과는 이 표본에서 미측정이다. 정밀도·IDF 오염을 줄이는 위생 조치로 남긴다. 내 초안 주석이 “mixed 가 원형을 남긴다”고 일반화한 것도 틀려서 함께 고쳤다 - hub 포트 계약 간극 3건 — 장민석 님 확인 대상 (2026-08-27 정리) —
ai/스포크를 붙이면서 계약으로는 표현할 수 없는 것이 셋 나왔다. 셋 다server/소관이라 손대지 않았고, 지금은 각각 우회로만 열어 뒀다. ①RetrievalPort.retrieve(utterance, top_k)에 도메인이 없다 — 하네스가 B-0 결과를 넘겨줄 수 없어 4개 도메인 전체를 검색한다. 못 맞힌 2건의 상위에 다른 도메인 문서가 올라온 것이 그 대가다(어댑터 생성자에domain=임시 통로) ②TranscriptEvent에 이벤트 도착 시각이 없다 — 트리거 발동 시각을 상수로 모형화할 수밖에 없어 하네스에 꽂지 못한다(IsFinalTrigger(now_ms=...)통로) ③DomainClassification.domain이str이라 “판정 불가”를 표현할 수 없다 — 결과가 0건일 때 런타임에None을 넣고 있다. 셋을 한 번에 논의하는 게 효율적일 것 같다- → 닫음 (2026-09-22 장민석): ①·③ 은 B-0 폐기(
201)로 대상이 없다 · ② 는 09-14received_at_ms(w4-trigger-arrival-time)로 풀렸다
- → 닫음 (2026-09-22 장민석): ①·③ 은 B-0 폐기(
- B-0 분류기 학습 — 두 번 시도했고 두 번 다 v1 을 못 넘었다 (2026-08-27) — AI Hub 민원 데이터로 KcELECTRA 파인튜닝. 골든셋은 학습에 쓰지 않았다(평가 세트). 2 epoch → AI Hub 0.815 / 골든셋 0.786. epoch 4 + 초반턴 증강(+13,204건) → AI Hub 0.879 / 골든셋 0.786 — 혼동 행렬까지 동일하다. 검색 기반 v1 은 0.857. 틀린 3건은 전부
finance로 가고 신뢰도 0.77~0.97 로 확신하며 틀린다 —발급·처리·비용이 AI Hub 금융에 압도적으로 많은 탓으로 보이고 학습을 키울수록 편향이 강해진다. 기본값을 v1 으로 고정했다.scripts/train_domain_classifier.py, w1-domain-routing - B-0 — 검색 v1 과 분류기를 합쳐 본다 (신규, 2026-08-27) — 두 방식이 겹치지 않게 틀린다: 분류기는 GS-016·018·021 을, v1 은 GS-002·019 를 놓친다. 합치면 둘 다 넘길 여지가 있다. RRF 병합 함수는 이미 있다(
decisions/021,retrieval/domain/services/fusion.py) — 검색 순위와 분류기 확률을 섞으면 된다. 다만 n=14 라 개선이 보여도 한두 건 차이이므로 표본 확장과 함께 봐야 한다- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
decisions/201)
- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
- dasan 보강 — 다산콜DB 6,614건 전사가 핵심 (신규, 2026-08-27) — dasan 이 두 방식 다 최하위다(AI Hub 0.746). 원인 세 가지를 데이터로 확인했다: ① 표본이 절반(7,600건 = health 16,237 의 47%) ② 어휘 겹침이 모든 쌍 중 최대(상위 400단어 dasan↔finance 0.47 —
수도요금·납부·지원금이 금융과 정면으로 겹친다) ③ 고유어(시내버스·지하철·대중교통)는 뚜렷한데 드물게 나타난다.data/raw/seoul-minwon-audio/민원상담_음성/다산콜DB/에 wav 6,614건이 있는데 전사가 없다 — 전사하면 dasan 이 7,600 → 14,000+ 로 불균형이 사라진다. 정성윤 님w2-stt-batch가 하는 일과 같다. 덤으로 전사본은 STT 오류 특성을 그대로 가져 “깨끗한 텍스트 vs 실제 입력” 간극까지 메운다(5주차 오류 내성 실험과 연결). 그 전까지의 임시 완화는 클래스 가중치(오버샘플링보다 낫다 — 복제하면 그 문장에 과적합) → 10-01 B-0 폐기로 목적 소멸(201), 배치 전사 취소(w2-stt-batch) - B-0 목표(≥0.95)를 판정할 표본이 없다 (신규, 2026-08-27) — 채점 대상을 B(검색) 항목으로 좁히니 n=14 다. 14건에서 0.95 를 넘으려면 14/14 여야 하고(13/14 = 0.929) 만점 말고는 통과가 없다. 두 방식의 차이(12/14 vs 11/14)도 한 건이라 의미를 두기 어렵다. 3주차 골든셋 150건 확장 때 도메인 판정용 표본을 따로 늘려야 이 목표를 잴 수 있다
- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
decisions/201)
- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
- 골든셋 문체와 실제 전사의 분포 차이 (신규, 2026-08-27) — 분류기가 AI Hub 에서 0.815 인데 골든셋에서 0.786 인 것이 이 차이 때문으로 보인다. 이건 B-0 만의 문제가 아니다 — 검색·컴플라이언스 지표도 같은 골든셋으로 재므로, 우리가 쓴 시나리오 문장이 실제 통화와 얼마나 다른지는 모든 지표의 해석에 걸린다. 3주차 150건 확장 때 AI Hub 실제 발화를 일부 섞을지 검토한다 → 10-01 한계로 발표에 적는다(문구 셋·데이터 한계,
138) - 프로젝트 종료 후 GCP 정리 (10-27 이후) — 무료 크레딧 유효기간이 2026-11-24 이라, 종료 뒤 리소스를 켜둔 채 두면 만료 시점부터 카드로 청구된다. 프로젝트 삭제 또는 결제 연결 해제로 마무리한다 → 10-01
w8-project-closeout티켓이 담당 — 여기서는 닫는다 - 확장을 막던 규칙 4건 완화 — 확정·반영 완료 (2026-08-27) — 「기능을 추가하려 하면 규약에 걸려 못 한다」는 지적을 규칙 파일에서 실제로 확인하고 고쳤다. 막고 있던 것은 넷이었다: ① F·G·H·I 동결이 시한 없는 상시 금지가 돼 있었다 — 규칙 파일이 기획서와 어긋나 있었던 것이다. 기획서 원문은 “6주차 종료 시점에 코어 기준선을 통과하지 못했다면” 인데
CLAUDE.md에서만 「6주차 종료 시점에」가 빠져 있었다. 시점이 빠지자 “기준선 통과를 증명하기 전까지 언제나 금지”가 됐고, 하네스가 전부 「측정 불가」를 보고하던 동안에는 그 증명이 불가능해 2주차에 이미 동결이었다. 빠진 경위는ee5c137(2026-08-25chore: 두 갈래 저장소 통합) — 공통 조상이 없는 두 저장소의CLAUDE.md를 손으로 합치며 문장을 다시 쓸 때 사라졌고, 기획서 5개 문서는 전부 원문을 유지했다. 같은 커밋에서 「B(검색)·E(평가)·C-5 절대 사수」(초판부터 7개 문서에 있던 문장)도 빠져 사수 대상이 「코어 전부」로 읽혔다. ② 기획서를 고칠 공식 경로가 문서에 없었다. 「기능 추가·변경」 논의가 2026-08-27 “상담 중 고객 자료 발송”에서 멈췄는데, 처음엔rfp-harness §1(새 접두어 금지)을 원인으로 봤으나 오독이었다 — 그 문장이 막는 것은SFR같은 ID 체계를 두 벌 만드는 것이지 새 기능이 아니다(새 기능은 기획서에B-7을 추가하면 된다). 실제 원인은_project/plan.md가 그때까지 “수정하지 않는 사본”이어서 ID 를 추가할 방법이 없었던 것이고, 더 근본적으로는 문서 우선순위에 결정 기록이 없어004·014·018·021·023이 실제로 기획서를 뒤집어 왔는데도 “그래도 되나”에서 매번 멈춘 것이다. ⚠CLAUDE.md:77은 2026-08-24 작성 보완지시서를 최상위로 두어 08-27 결정이 08-24 문서에 지는 역전까지 있었다(014가 이미 보완지시서 11번을 이긴 전례가 있는데도). ③decisions/012의 “경계에 걸친 작업”에 정의가 없어 남의 디렉터리는 3줄도 못 고쳤다(그날 6건이 멈췄고 그중 하나가 하네스에 C-5·F-2 를 꽂는 3줄, 즉 이 프로젝트의 첫 실측값이었다). ④ 도메인 4종 조항이 “예시로도” 까지 막아 문서·발표 예시도 못 들었다 — 그런데 이것도decisions/004에 없는 문구였다(결정은 “A. 4개 도메인 전부 지원” 한 줄뿐). → ①은 원문 복원, ②는 문서 우선순위에 결정 기록 최상위 명문화(CLAUDE.md §1·rfp-harness §1—X-접두어는 미결 후보 표기 편의로 성격 정정), ③은 합성 루트 정의(decisions/012— 류준의023이 협의 절차를 전부 걷어냈으므로 「소유는 담당자만」 표는 뺐다), ④는 근거 없던 제약 삭제. ①④는 파생 문서가 원문보다 빡빡해진 것이라 팀 합의가 필요 없고, ②③만 신규 규칙이다. 절대 원칙 1·2·8·9·10 과 진행 기록·티켓 규칙은 건드리지 않았다 — 그건 프로젝트가 평가받는 근거다. 근거·되돌리는 법:_project/decisions/022 - B-0 목표
≥0.95를 n=14 로는 판정할 수 없다 — 표본 설계 사안 (신규, 2026-08-27) — 6.1절이 도메인 분류 정확도에≥0.95를 걸어 뒀는데 현재 채점 표본이 B(검색) 항목 14건이다. 14/14 = 1.000 만 통과이고 13/14 = 0.929 는 실패라, 만점 말고는 통과가 없다. 검색 기반 v1(12/14 = 0.857)과 KcELECTRA 분류기(11/14 = 0.786)의 차이도 한 건이라 우열을 말할 수 없다. ⚠ 목표 수치를 지금 낮추지 않았다 — 지표 변경은 규칙 완화가 아니라 평가 기준 변경이고, 발표에서 “기준을 왜 내렸냐”에 답해야 하는 종류다(절대 원칙 2). 정할 것: ① 3주차 골든셋 150건 확장 때 도메인 판정용 표본을 따로 늘릴지(C·C-5 항목은 발화에 도메인 단서가 없어 채점 대상에서 이미 빠졌으므로, B 항목만 늘려야 한다) ② 아니면 표본 크기에 맞게 목표를 재설정할지. ⚠ 6주차 종료 시점의 「코어 기준선 통과」 판정에 직접 물린다 — 그때 B-0 가 ❌ 로 남아 있으면 F·G·H·I 착수가 막힌다. 지금 당장 막는 것은 아니지만(동결은 6주차 시점 판정이다) 판정 시점 전에 표본을 정리해야 한다- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
decisions/201)
- → 닫음 (2026-09-21 보드 최신화, 정성윤): B-0 폐기(
- 배포를 한 컨테이너로 갈지 — 해소 (2026-09-03,
_project/decisions/105). ⚠ 위 항목과 같은 건이 두 번 올라와 있었다 — 같은 날 두 사람이 각자 적었다. 아래는 당시 기록 그대로다(절대 원칙 8).decisions/024이 검색 스포크를 같은 프로세스에서 꽂기로 정했는데(HTTP 홉이 4.1절 p95 ≤1,000ms 예산을 먹는다), 그러면server컨테이너에ai/코드가 함께 실린다. 그런데CLAUDE.md §3은server.solidbob.cloud·ai.solidbob.cloud두 도메인을 적어 두고 있다. 실제로ai/에는 HTTP 표면도fastapi·uvicorn의존성도 없다 —ai/requirements.txt주석이 “의존성은server/requirements.txt에 있다” 고 적고 있고, 구조상 라이브러리다. 지금은ai/에 서비스 실체가 없어 모순이 드러나지 않지만 배포를 짤 때 정해야 한다. 정할 것: 문서의 두 도메인 서술을 고칠지, 나중에ai/를 별도 서비스로 세울지(후자는ai/에 웹 서버를 새로 만들고server/apps/hub/adapter/outbound/에 HTTP 어댑터를 둔다 — 그건server/안이라 계약 위반이 아니다). 담당: 정성윤(인프라) - 기획서 ↔ 파생 문서 대조 검사가 없다 — 어긋남 4건이 이번에 우연히 발견됐다 (신규, 2026-08-27) — 규칙 파일·공개 문서가 기획서를 옮겨 적은 것인데, 옮기는 과정의 어긋남을 잡는 장치가 없다. 2026-08-27 대조에서 4건이 나왔다: ① F·G·H·I 동결의 「6주차 종료 시점에」가
CLAUDE.md에서만 누락(ee5c137, 시한 있는 조건이 상시 금지가 됐다 — 팀이 3일간 여기 묶였다) ② 「B·E·C-5 절대 사수」가CLAUDE.md에서만 누락(초판부터 7개 문서에 있던 문장. 사수 대상이 「코어 전부」로 읽혔다) ③ 트리거 허용 창이plan.md800ms ·docs/041,500ms 로 갈림(팀 컨펌은 1,500ms 쪽이고plan.md가 낡았다 — 아직 안 맞췄다) ④server/.importlinter계약 수가 실제 4종인데CLAUDE.md는 3종(정정 완료). ⚠ ①②는 규칙이 기획서보다 빡빡해진 사례다 — 옮겨 적기 실수가 팀을 막았고, 팀은 그걸 “규칙이 빡빡하다”로 경험했다. 정할 것: 같은 값이 두 곳에 다르게 적힌 것을 찾는 검사를 CI 에 넣을지(check_site_links.py와 같은 자리), 아니면 값이 한 곳에만 살도록 문서 역할을 나눌지. 후자가 근본적이지만 문서 구조를 건드린다 → 10-01 자동 검사는 안 만든다 — 수동 대조 3회(09-23·09-28·10-01,w8-final-docs)로 갈음 STATE.md충돌 구조를 없앴다 (2026-08-27) — 네 사람이 매 세션 맨 위에 블록을 끼워 넣고 6행 「최종 갱신」을 각자 덮어써서, 그 파일 커밋 63건 중 19건이 머지 커밋이었고 08-27 네 브랜치 통합에서는 네 번 모두 여기서 걸렸다. 게다가 같은 날STATE.md에 세션 블록 14개 ·_logs/에 58개로 같은 내용을 두 곳에 쓰고 있었다(§4“같은 내용을 세 곳에 적지 않는다”와§0.5종료 루틴이 서로 모순이었다). → 「최종 갱신」 줄 삭제(git 이 이미 갖고 있다) · 세션 블록 24개를_project/STATE-archive.md로 이동(한 글자도 안 고쳤다, 절대 원칙 8) · 남는 것을 「영역별 상태」 표로 바꿔 각자 자기 줄만 덮어쓰게 했다 ·CLAUDE.md §0·§0.5·§3갱신. 809줄 → 130줄. ⚠ 파일을 쪼개지는 않았다 —_logs/·_backlogs/와 달리STATE.md는 “지금 상태”를 한 곳에서 봐야 하는 문서라 쪼개면 목적을 잃는다._project/decisions/101- 스케줄러를 무엇으로 할지 확정 — 현재는 지킬 칸반(/kanban/,
_backlogs/컬렉션). GitHub Projects를 메인 보드로 쓰고 지킬은 산출물 기록만 담당하는 방식도 있다. Projects는 드래그 앤 드롭·이슈 연동이 되지만 저장소 밖에 상태가 생겨 기록이 두 곳으로 갈린다. 한쪽으로 정한다 → 10-01 지킬 칸반 유지 — 남은 기간에 도구를 바꾸지 않는다(decisions/138동결) apps/platform랜딩을 아키텍처·역할 문서에 올릴지 (신규, 2026-08-27) — 상담원 대시보드(apps/dashboard)와 별개 배포 단위로 제품 소개 페이지를 프론트가 먼저 정의했다. 기획서·3절에는 아직 없다. 배포는 2026-08-28 Vercel, 공개 URL은 https://www.solidbob.cloud/. 히어로 1차(문장 타이핑)는 폐기했고, 지금은 밝은 랜딩(키워드·카드 제목 4도메인 2.8초 순환, 히어로100dvh). 정본으로 지시한reference/mockup.html은 저장소에 없었다. 아키텍처·역할 문서 반영은 팀이 정하면 적는다 → 10-01 README 에 소개 페이지로 적혀 있다 — 아키텍처 문서에는 안 올린다- 통화 목록 조회 API 필요 — 상담기록 화면 전제조건 (신규, 2026-08-28) — ✅ 2026-09-19 운영 실측:
GET /hub/calls가 있다(/openapi.json41경로). 09-15 에 대시보드 상담기록 화면이 실제로 붙었다. 원문 —GET /hub/calls/{call_id}/transcript는 있지만(call_id를 이미 알 때 그 통화 자막 재조회), 여러 통화를 나열하는 목록 조회 엔드포인트(예:GET /hub/calls?domain=&limit=&offset=)는 계약에 없다. 프론트는 mock으로 화면만 먼저 구현. - A-5 통번역 이벤트 계약 필요 (신규, 2026-08-28) — 고객 발화 원문+번역본+언어코드를 실어 보낼 메시지가 7.3절에 없다. 프론트는
TranslatedUtterance·AgentTtsStatus·통화targetLanguage(VI/EN/JA/ZH/TH)를 임시로 먼저 정의했다. 화면은LANGUAGE_META+LanguageBadge로 5개 언어 mock을 표시한다. 상담원 한국어 → 고객 모국어 TTS는 화면 「전송됨」만 표시하고 실제 음성 재생은 이번 범위가 아니다._project/decisions/201§2 · 부록 A. → 10-01 계약 안 만든다 — 번역·TTS 미착수(139) - C-6 콜가드 이벤트 계약 필요 (신규, 2026-08-31) — 고객 폭언 탐지 결과를 실어 보낼 메시지가 7.3절에 없다. 프론트는
CallGuardFlag와SupervisorAlert타입을 임시로 먼저 정의했다. 자막 mock은detectCustomerRisk(abuse/distress/pii) + 배너/마스킹이다. 텍스트만 보고 경고만 한다(오디오 톤·자동 차단은_project/decisions/201C-6 범위 축소). C-1~C-4와 방향이 반대이지 대체가 아니다. PII를 슈퍼바이저 알림에 넣을지는 아직 정하지 않았다(지금은 마스킹만). → 10-01 있다 —call_guard메시지(콜 미디에이터 0.2.x,call_guard_dto) - D 감정분석 기반 상담품질평가 계약 필요 (신규, 2026-08-31) — 통화 후 감정 분석 결과를 실어 보낼 필드가 7.3절에 없다. 프론트는
SentimentSummary타입을 임시로 먼저 정의했다. 모델은ai/(류준) 담당. 화면 mock은 정성 라벨과 C-6 건수만 쓰고 점수를 만들지 않는다(decisions/201D 확장). → 10-01 계약 안 만든다 — 「통화 온도」로 바뀌고 수치는 측정 불가(140·142) - D 감정분석 기반 상담품질평가 계약 필요 (신규, 2026-08-31) — 통화 후 감정 분석 결과를 실어 보낼 필드가 7.3절에 없다. 프론트는
SentimentSummary타입을 임시로 먼저 정의했다. 모델은ai/(류준) 담당. 화면 mock은 정성 라벨과 C-6 건수만 쓰고 점수는 만들지 않는다(decisions/201D 확장). → 10-01 중복 항목 — 위와 같음(140·142) - G-2 지역자원 연계 계약 필요 (신규, 2026-08-31) — 기관명·주소·연락처를 실어 보낼 메시지가 7.3절에 없다. 프론트는
LocalResource와 통화 후 화면 카드만 먼저 정의했다. 「연결하기」는 동작 없는 목업이다. → 10-01 계약 안 만든다 — G-2 미구현, 알려진 한계(138) - 해결률 통계에 재문의율 검증이 빠져있음 (신규, 2026-08-31) — 실제 데이터 필요, 지금은 단순 완료 여부만 표시. mock 8건에는 「같은 고객이 다시 전화했는지」가 없어 재문의율을 만들지 않았다. 화면은 데모 데이터 기준 해결 건수만 센다. → 10-01 mock 한계 그대로 — 화면에 「디자인 목업」 표기(09-22)
- 상담기록 해결률 통계 패널 — 팀 결정 아닌 개인 판단으로 추가함 (신규, 2026-08-31) — 팀 확인 후 유지·제거 결정 필요. 제거 시
ResolutionStats.tsx와CallHistoryPanel호출 한 줄만 지우면 된다. → 10-01 유지한다(목업 표기 있음,137) - 다산콜센터 필요서류 실측 데이터 필요 — POLICY.md/MANUAL.md에 서비스별 구비서류 목록 갱신 필요 (신규, 2026-08-28) —
_project/decisions/201§3 전제조건.knowledge-base/dasan/policy/POLICY.md는 구버전 카테고리(대중교통 안내·생활하수도·일반행정·코로나19) 기준으로 「F-2 미적용」이라고 적혀 있고, 결정이 말하는 69종 서비스별 필요서류 실측은 지식베이스에 없다. 프론트 체크리스트는 DTO만 재사용하고 mock은 「예시」로 표시한다. 콘텐츠 담당이 목록을 넣으면 화면 mock을 교체한다. → 10-01 규칙표 25절차로 완성(305), POLICY-1 은316이후 정정 — 닫는다 다산콜DB 6,614건 전량 전사 — 승인 보류, 정성윤 결정 대기— 2026-08-28 류준 철회. 전제가 사라졌다. 이 요청의 목적이 B-0 도메인 분류기의dasan표본 보강이었는데, 같은 날 다산 단일 도메인 전환으로 B-0 자체를 폐기하고ai/apps/training/을 삭제했다 (_project/decisions/201). 분류할 도메인이 없으니 표본을 늘릴 대상도 없다. 정성윤 님 결정을 기다릴 필요 없다 — 요청을 거둔다. ⚠ 정성윤 님이 적어 둔 분석은 그대로 살려 둔다(아래 원문) — 「56개 시나리오 × 2역할 = 고유 텍스트 상한 112건」이라는 지적은 B-0 과 무관하게 이 데이터셋 자체의 성질이라, A-5 평가셋을 뽑을 때 다시 쓰인다. 소량 검증(w2-stt-batch)은 계속 유효하다. 원문 — — 류준 님이 B-0dasan표본 부족(7,600건 =health16,237의 47%)을 메우려고data/raw/seoul-minwon-audio/민원상담_음성/다산콜DB/wav 6,614건 전량 전사를 요청했다. 전제 하나가 어긋난다: 서울 열린데이터광장이 이 데이터셋을 「56개의 시나리오에 대한 음성데이터」로 명시하고, 파일명<시나리오번호>_<연령대>_<성별>_<지역>_<민원인|상담사>_<take번호>.wav가 그 구조 그대로다(6,614 ÷ 56 ≈ 시나리오당 118개). 고유 텍스트의 상한은56 × 2역할 = 112이고 B-0 은 텍스트 분류기라 화자가 달라도 입력이 같다 — 늘어나는 6,000여 건은 그 112건의 복제본이고, 류준 님이3c84411에 적은 “복제하면 그 문장에 과적합” 이 그대로 해당한다. 같은 커밋의 실측도 같은 방향이다(초반턴 증강 +13,204건 → AI Hub +6.4%p, 골든셋은 혼동 행렬까지 한 자리도 안 바뀜). 권고: ① 소량 5~10건 검증만 지금 진행(무료 한도 안, w2-stt-batch 완료 조건) ② 클래스 가중치 학습 1회 — 지금 트레이너에 아예 없다(domain_classifier_trainer.py가 그냥model(..., labels=labels).loss) ③ 그래도 부족하면 시나리오 커버 112건만 전사(평균 7초면 13분·12초면 23분 → 무료 한도 60분/월 안). 정할 것: 이 순서로 갈지, 요청대로 전량 전사를 승인할지. 승인되면 결정 기록1xx로 남긴다- ⚠ ₩0 으로 확정 가능 — 다산콜DB 고유 시나리오 수를 직접 세야 한다 (신규, 2026-08-28) — 위 판단의 근거인 「56」은 서울시 페이지에서 온 숫자이고 파일을 직접 보지 못했다(이 머신에
data/raw/오디오도.venv도 없다). 오디오가 있는 머신에서ls .../다산콜DB/ | awk -F_ '{print $1}' | sort -u | wc -l한 줄이면 1분에 확정된다. 같이 확인할 것 —data/README.md의 「1.3G」와 류준 님이 잰 45,853초가 안 맞는다. 8kHz 16bit 모노면 734MB 여야 하므로 실제 파일은 16kHz 거나 스테레오다. 2026-08-28 수정으로transcribe_batch.py --dry-run이 헤더 조합을 요약에 찍으므로 같은 실행에서 함께 드러난다 → 2026-09-22 파일로 셌다: 고유 시나리오 56(1~56 빠짐없음) · (시나리오,역할) 112 · wav 6,614 — 「56」이 맞다. 곁다리: 파일명 형식이 셋이라(상담사 1,044건은 연령대·지역 필드 없음, 민원인 21건은 take 가 역할에 붙음)decisions/203의 「민원인 5,549건」은 실제 5,570건이다(아래 09-22 블록) - STT 비용 전제 정정 — 지금 스크립트로는 Dynamic Batch 가격을 못 받는다 (신규, 2026-08-28) — ① Dynamic Batch 는 $0.004 가 아니라 $0.003/분이지만, V2
BatchRecognize는gs://만 받는다 — wav 1.3GB 를 GCS 에 올리고 스크립트를 V2 로 고쳐야 그 가격이 나온다. 지금 코드는 V1 동기recognize()다 ② Standard $0.016/분은 V1 에서 데이터 로깅 옵트인 가격이다. 민원 음성엔 개인정보가 그대로 들어 있어 SEC-1 상 받을 수 없다 — 옵트인 없는 V1 은 $0.024/분(전량이면 약 ₩23,000, 월 예산 ₩30,000의 78%) ③ 크레딧 ₩435,523 이 미사용이라 카드 청구는 어느 쪽이든 0원이다. 전량 전사를 반대하는 이유는 돈이 아니라 얻는 게 없다는 것이다. 정할 것: 전량으로 간다면 V2 전환 + GCS 업로드를 티켓으로 뺄지, V1 그대로 비싸게 갈지 → 10-01 배치 전사 취소(w2-stt-batchcancelled) — 닫는다 - 중복 티켓 — 조서희 님 확인 필요 (신규, 2026-08-28) — 세션 종료 검사가
w1-dashboard-scaffold-seohee(statusdone) ↔w2-dashboard-scaffold(statustodo)를 같은 작업으로 경고한다. 제목이 「React 대시보드 스캐폴딩」으로 같고 담당도 둘 다 조서희다. 남의 티켓이라 손대지 않았다(§4).w2쪽이 아직todo라 보존할 수행 기록이 없으므로 합치거나 범위를 나누면 된다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
w2-dashboard-scaffold티켓이_backlogs/에 더는 없다 — 중복이 사라졌다
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
call.solidbob.cloud는 프론트, 지킬은docs.solidbob.cloud— 확정 (2026-08-28,decisions/104) —call(통화)은 제품 쪽 이름이라 상담 화면이 붙는 게 자연스럽고, 문서 사이트는 주소만 보고 알 수 있는docs가 낫다. 바꾸는 비용이 거의 없었다 — 본문 링크 405곳은 전부 루트 절대경로라 도메인과 무관하고,github.com/SeongYuna/call.solidbob.cloud는 저장소 이름이라 그대로다. ⚠ 저장소 이름과 사이트 주소가 달라진다(저장소 개명은 링크·클론 경로를 깨므로 안 한다). 원래 논의는 아래에 남긴다 — — DNS 이관 중에 프론트 담당이 가비아 존에call CNAME cname.vercel-dns.com(Vercel)을 추가한 것을 발견했다. 그런데call은 지킬 기획서 사이트가 쓸 이름으로 잡혀 있다(저장소 이름·표지·문서 링크 405곳이 전부 이 기준이고,decisions/102도 그렇게 정했다). 한 이름은 한 곳만 가리킨다. ⚠ 의도인지 확인이 먼저다 — 저장소 이름을 보고 넣은 것일 수도 있다. 프론트는 이미 apex(solidbob.cloud)·www를 갖고 있어서, 화면이 더 필요하면app·dashboard를 쓰면 된다. 정할 것: ①call= 지킬(권장 — 고칠 게 없다) ②call= 프론트(지킬은docs등으로,_config.yml·decisions/102·티켓을 함께 고쳐야 한다). 담당: 정성윤 ↔ 프론트- DNS 레코드를 넣는 곳이 바뀌었다 — 팀 전체 공지 필요 (신규, 2026-08-28) — 네임서버를 클라우드플레어로 옮기면 가비아 DNS 설정은 무시된다. 실제로 프론트 담당이 이관 중에 가비아에
call을 넣었는데 그건 전환 순간 사라진다. 앞으로 DNS 는 클라우드플레어에서만 넣는다. ⚠ 함께 겪은 것: 버셀이 요구하는wwwCNAME 대상값은 프로젝트가 바뀌면 같이 바뀐다(오전8511982eb7ecc120…→ 오후ea6aaafa6f786127…). 값의 정본은 버셀 대시보드 Domains 화면이지 우리가 적어둔 메모가 아니다. 레코드 원본·확인법:_project/dns-solidbob-cloud.md→ 10-01 런북 18장에 적혀 있다 — 닫는다- 2026-09-23 (정성윤) — 공지 내용은 이걸로 확정한다 — 네임서버가 클라우드플레어라 A·CNAME·TXT 는 전부 클라우드플레어 대시보드에 넣는다(가비아 쪽은 네임서버 지정만 남아 있다). 서브도메인 넷(
server·call·admin·www)이 이미 그렇게 들어가 있고,ai는 09-23 에 지웠다. 런북 17장이 정본이다. 팀 채널에 붙일 한 줄: 「DNS 는 클라우드플레어에서. 가비아에서 고치면 반영 안 됩니다」
- 2026-09-23 (정성윤) — 공지 내용은 이걸로 확정한다 — 네임서버가 클라우드플레어라 A·CNAME·TXT 는 전부 클라우드플레어 대시보드에 넣는다(가비아 쪽은 네임서버 지정만 남아 있다). 서브도메인 넷(
- 배포 사이트 본문 링크 404 — 해결 (2026-08-28) —
https://docs.solidbob.cloud/로 붙였다. 내부 링크 86개 전수 확인 200, HTTPS 강제, 인증서 정상. 아래는 원인 기록 — —https://solidbob02.github.io/docs/09/처럼 죽는다. 프로젝트 페이지라 사이트가/call.solidbob.cloud/아래 놓이는데 링크 405곳이/docs/09/같은 루트 절대경로라 한 겹이 어긋난다. 상단 내비만relative_url을 써서 내비는 되고 본문은 안 되는 모양이 됐다. CI 가 못 잡는 이유: 링크 검사는--baseurl없이 빌드한_site를 보고, 배포는--baseurl /call.solidbob.cloud로 다시 빌드한다 — 검사한 사이트와 배포된 사이트가 다르다. 해법은 커스텀 도메인이다(루트에 올라가면baseurl이""가 되어 405곳이 그대로 맞고, CI·배포 빌드도 같아진다). 저장소 쪽(_config.ymlurl·jekyll/CNAME·pages.yml주석)은 반영했다. 남은 것 — 정성윤: ① 가비아 DNS 에call CNAME solidbob02.github.io.② Settings → Pages → Custom domain 지정 후 Enforce HTTPS. ⚠jekyll/CNAME파일이 ①② 를 대신하지 못한다 — Actions 배포는 그 파일을 읽지 않는다._project/decisions/102· w2-custom-domain - 커스텀 도메인을 클라우드플레어로 걸지 — 건다. ⚠ 아래 판단은 같은 날 뒤집혔다 (2026-08-28,
decisions/103) — 존은 이미 클라우드플레어에 추가됐고 네임서버 전환 대기 중이다. 아래 우려 셋 중 둘은 순서를 지키면 사라진다(프록시를DNS only로 두면 인증서 발급이 막히지 않고, 암호화 모드를Full (strict)로 두면 루프가 안 난다). 남는 것은 「존을 통째로 옮겨야 한다」인데 레코드가 2건뿐이라 비용이 작고, 옮겨 두면 나중에server.solidbob.cloud(AWS)에 프록시·터널을 붙일 때 이관 단계가 없어진다. 지켜야 할 조건 4가지는decisions/103에 있다 — ①call은 항상 회색 구름 ②Full (strict)③ apex·www(Vercel)도 회색 구름 ④ NS 전환 전에 레코드 2건 대조(가져오기가 놓친 채로 바꾸면 그 순간 랜딩이 죽는다). 원래 판단은 아래에 그대로 남긴다(절대 원칙 8) — 클라우드플레어는 서브도메인만 위임받지 못해(부분 설정은 엔터프라이즈) 네임서버를 통째로 옮겨야 하고, 그러면 지금 살아 있는 apex·www(Vercel)를 다시 만들어야 한다. 프록시(주황 구름)를 켜면 GitHub 의 인증서 발급이 막히고, SSL 모드가Flexible이면 리다이렉트 루프가 난다. 지금solidbob.cloud존에는 apexA 216.198.79.1와wwwCNAME 둘뿐이고 MX·TXT 가 없어서, 나중에server.solidbob.cloud(AWS)에 프록시·터널이 필요해지면 그때 옮겨도 비용이 같다._project/decisions/102 - GitHub Pages 활성화 — Source를 “GitHub Actions”로 변경 완료, 배포 워크플로 정상 동작 확인(
https://seongyuna.github.io/call.solidbob.cloud/). ⚠ 커스텀 도메인 연결을 Sprint 7 로 미룬 것이 위 404 의 원인이다 — 2주차로 앞당겼다
3주차에 남긴 것
- A-1 콜 미디에이터를 같은 EC2 에 올릴지 — 인스턴스 등급이 걸린다 (신규, 2026-09-03) — ✅ 같은 EC2 에 올렸다 — 2026-09-19 실측: 한 노드에
callguard-server·callguard-call-mediator·elasticsearch-0·redis넷이 함께 돈다. 등급은t3.medium도g4dn도 아닌t3.large다(decisions/116에 사실로 기록). 원문 — w3-aws-deploy가 세운t3.medium(4GB)은server+ Elasticsearch 둘만 계산한 값이다(ES 힙 1g + JVM·mmap ≈ 1.5GB · FastAPI ≈ 0.3GB · OS·도커 ≈ 0.4GB).services/call-mediator(Node.js WebSocket + Google STT 중계)는 아직 코드가 0줄이라 빼고 쟀는데, 3주차 실시간화에서 만들면 올릴 자리를 정해야 한다. 정할 것: ① 같은 인스턴스에 얹고 등급을 올릴지 ② 콜 미디에이터만 따로 띄울지 ③ 데모 때만 로컬에서 돌릴지. ⚠ 오디오 중계라 지연이 곧 품질이고(4.1절 p95 ≤1,000ms), STT 할당량 가드(COST-1)가 인스턴스별 파일(data/processed/stt-usage.json)에 누적되므로 두 곳에서 돌면 캡이 두 배가 된다 — 나누기로 하면 그 상태를 공유할 곳이 필요하다 - 운영 배포를 CI 에 붙일지 (신규, 2026-09-03) — ✅ 붙였다 —
release.yml이 SSM·OIDC 로 배포한다(09-14 첫 실검증, 09-19 에도0.1.18이 떠 있는 것을 확인). 설계가 갈린 지점 넷은decisions/117에 남겼다. 원문 — 지금은 이미지를 손으로 굽고 손으로 올린다.test.yml에 붙이면 main 머지가 곧 운영 배포가 되는데, main 은 이미 push 즉시 사이트를 배포한다(pages.yml). 사이트가 잘못 나가는 것과 API 가 잘못 나가는 것은 되돌리는 비용이 다르다 — 붙인다면 태그를 달았을 때만 도는 쪽이 맞아 보인다. 함께 정할 것: OIDC 로 AWS 자격증명을 주입할지(권장 — 장기 키를 GitHub Secrets 에 두지 않는다, SEC-2) -
Terraform state 를 원격으로 옮길지 (신규, 2026-09-03) — ✅ 옮길 대상이 없어졌다 — terraform 은 설계서로만 남기고 콘솔로 세웠다(
w3-aws-deploy09-03 방향 변경 ·decisions/117「남는 한계」). ⚠ 그 대신destroy→apply재현 경로가 없다는 한계가 남고, 대체물인 AMI 도decisions/116으로 뜨지 않기로 했다. 원문 — 지금terraform.tfstate는 정성윤 로컬에만 있고.gitignore가 막고 있다(RDS 비밀번호가 평문으로 들어간다). 이 머신이 죽으면 인프라를 코드로 관리할 수 없게 된다 — 리소스는 살아 있는데 Terraform 이 그걸 모른다. S3 + 잠금으로 옮기면 해소되지만 버킷·키 관리가 늘어난다. 혼자 쓰는 동안은 로컬로 두되, 다른 사람이apply할 일이 생기면 그때가 아니라 그 전에 옮긴다 docsCNAME 을seongyuna.github.io로 바꾼다 (신규, 2026-09-03) — ✅ 끊긴 적 없다 — 2026-09-19https://docs.solidbob.cloud/200. 소유권 이전(decisions/106) 뒤에도 정상이라 CNAME 을 바꿀 급한 이유가 없다. 원문 — 저장소 소유권이solidbob02→SeongYuna로 넘어왔는데(_project/decisions/106)docs.solidbob.cloud는 아직 옛 계정 호스트를 가리킨다. 지금은 동작한다 — 두 이름이 같은 GitHub Pages 애니캐스트 IP(185.199.108~111.153)로 풀리고 GitHub 이 리다이렉트를 유지한다. 급하지 않지만solidbob02계정이 사라지거나 개명하면 그때 문서 사이트가 죽는다. 클라우드플레어에서 회색 구름 유지한 채 한 줄 바꾸면 끝난다- 랜딩 자동배포가 실제로 도는지는 아직 모른다 (신규, 2026-09-03) — w3-vercel-account-migration이 Git 연동을 붙이기로 했지만, 연동 후
main에 커밋을 한 번 밀어 배포가 도는 것을 보기 전까지는 「됐다」가 아니다. 지금까지 아무도 안 도는 걸 몰랐던 이유가 정확히 그것이다 — 수동 배포는 멈춰도 아무 일이 일어나지 않는다. 정할 것: 연동 확인 뒤pages.yml처럼 「머지 = 배포」를 문서에 못 박을지, 아니면 위 「운영 배포를 CI 에 붙일지」와 묶어 태그 기준으로 통일할지 → 10-01 09-22 Ignored Build Step 정정 뒤 배포 확인(_logs/2026-09-22-01) — 닫는다 api.solidbob.cloud가 TLS 미발급으로 안 열린다 (신규, 2026-09-03) — ✅ 고칠 대상이 아니라 지울 대상이다 —decisions/105(한 컨테이너·한 도메인)로 API 는server.solidbob.cloud하나가 됐다. 2026-09-19 확인:api.solidbob.cloud는 여전히 안 열린다(연결 실패). DNS 정리 자체는decisions/116으로 하지 않기로 했다(ai자리표시자와 같은 건). 원문 — Railway(uivwfh8v.up.railway.app)로 CNAME 은 살아 있는데 HTTPS 연결이 실패한다(인증서 발급 안 됨).decisions/104가 「api = Railway(임시)」로 적어 둔 것인데,105·w3-aws-deploy로 백엔드가 AWS EC2(server.solidbob.cloud)로 가기로 이미 정해졌다. 정할 것: Railway 를 고쳐 쓸지, 아니면 AWS 배포 때api레코드를 정리하고server로 일원화할지 — 후자가105(배포 단위 하나)와 맞다- GPU·EXAONE 을 이번 배포에 넣을지 (신규, 2026-09-08) — ✅ 넣지 않았다 — 2026-09-19 실측: 운영은
t3.large· GPU 없음이고 Ollama·EXAONE 파드가 없다. 모델을 운영에 올릴지는decisions/208(NER·임베딩) 쪽으로 옮겨 갔다. 원문 — 개인 운영 지침서(09-04)는g4dn.xlarge+ Ollama + EXAONE 을 전제하는데, w3-aws-deploy는 “생성 모델(EXAONE)을 EC2 에 올리지 않는다” 고 적었다. 지침서가 나중이라 방향이 바뀐 것으로 보이나 명시된 적이 없다. 지금 코드에는 GPU 를 쓰는 경로가 아예 없다 — 검색은 BM25 뿐이고(ai/apps/retrieval의 서드파티 import 는elasticsearch하나), 생성·분류·NER 은 미구현이다. 그래서 지침서 11장(GPU 공유)·14장(Ollama)을 건너뛰어도/health와 Swagger 는 그대로 뜬다. 정할 것: ① 11·14장을 뒤로 미루고 모델이 붙을 때 실행할지(권장 — 인스턴스 타입만 처음부터g4dn으로 잡아 AMI 를 한 번만 만든다) ② 처음부터 전부 세울지. ⚠ 비용이 걸린다 — 지침서 21장이 하루 8h×주5일 $142 vs 24/7 $597 로 잰다._project/decisions/107 -
카드 추천 “검색 중” 신호가 §7.3 계약에 없다 (신규, 2026-09-09) → 2026-09-14 §7.3 에
recommendation_pending을 올리고 콜 미디에이터에 넣었다 — 전송은 꺼 둠(w4-recommendation-pending-contract). 남은 것은 아래 「조서희 님께 — 검색 중 신호 수신」. 원문 — —fired필드 반영(_project/decisions/401)과 함께, 카드 응답을 기다리는 동안 로딩 인디케이터를 보여주도록 대시보드를 고쳤다. 그런데 “지금 검색 중”임을 알리는 신호 자체가 계약에 없어서 mock 콜 미디에이터만 그 신호(onRecommendationPending)를 보낸다 — 트리거 시점에 먼저 쏘고internal_latency_ms뒤 실제 카드를 배달하는 식으로 흉내냈다. 실서버는 이 신호가 없어 라이브 모드에서는 로딩 UI가 뜨지 않는다 —fired:false/cards:[]/cards:[...]세 상태 자체는 실서버에서도 정상 동작한다. A-5·C-6·D 처럼 프론트가 먼저 정의한 계약 미정 항목과 같은 처지다. 정할 것: 트리거 발동 시점을 알리는 신호를 §7.3에 추가할지(추가한다면 콜 미디에이터가 트리거 결정 직후 얇은 메시지를 먼저 쏴야 한다), 아니면 로딩 UI를 mock 전용으로 남겨둘지 - 프론트에 「
score·similarity_score둘 다 받는 방어 코드」가 없다 — 조서희 님 확인 필요 (신규, 2026-09-09) — 카드 필드명 수정 요청서는 “당분간 둘 다 받는 방어 코드가 프론트에 임시로 들어가 있다” 고 적었으나,apps/dashboard/src/lib/ws/realCallMediatorClient.ts:238parseCard는similarity_score하나만 읽고 없으면null을 반환해 카드를 통째로 버린다. 저장소 전체에"score"문자열 리터럴이 0건이고apps/dashboard에 미커밋 변경도 없다. 정할 것: 서희 님 로컬에만 있는 미푸시 코드인지, 아니면 넣으려다 만 것인지. ⚠ 서버는 고쳤으므로 방어 코드가 있었더라도 이제 지워도 된다 — 다만 없는 것을 지울 수는 없으니 후속 작업으로 잡아 두지 않는다 → 10-01 계약이similarity_score문자열로 정착, 파서 테스트 있음 — 닫는다 - 계약 필드명을 단언하지 않는 테스트가 또 있는가 (신규, 2026-09-09) —
score/similarity_score어긋남이 3주를 간 이유는test_recommendation_router.py의 「카드를 계약 형태로 돌려준다」가doc_id·summary·internal_latency_ms만 보고 점수 필드명을 단언하지 않았기 때문이다. 7.3절 계약은 3종(전사·카드·종결)인데 나머지 둘(전사 이벤트·종결 판정)에도 같은 구멍이 있는지 아직 안 봤다. ⚠ 이미 알려진 어긋남이 둘 더 있다 —ClosureType"사고·보상"vs"보상"(422 유발) ·segment_idstringvsint(7.3절 예시가 틀렸다). 정할 것: 계약 3종을 한 번에 대조하는 테스트를 둘지, 아니면 슬라이스별 단언으로 흩어 둘지 — 전자면 7.3절 JSON 을 픽스처로 떼야 한다 → 10-01 안 한다 — 범위 밖(138)
세부 진행은 8주 마일스톤의 칸반 보드, 완료 기록은 진행상황에서 확인하세요.
- 통화 시작이 §7.3 계약에 없다 — 콜 미디에이터가
POST /hub/calls를 먼저 불러야 한다 (신규, 2026-09-10) → 2026-09-14plan.md§7.3 에 올렸다 — 콜 미디에이터가 첫 채널을 열 때 부른다(09-11 구현). 원문 — —transcript_segment.call_id → call외래키 때문에 통화 행이 먼저 있어야 전사가 저장되는데, 계약 3종(전사·카드·종결)에 “통화가 시작됐다”는 메시지가 없었다. 서버에POST /hub/calls를 만들었다(_project/decisions/301). 정할 것: 콜 미디에이터(정성윤)가 통화를 여는 순간 이 엔드포인트를 부르는 것으로 §7.3 에 올릴지, 콜 미디에이터 → 허브 WebSocket 이 생기면 그 첫 메시지로 할지. 지금은 테스트하는 사람이 직접 부른다 - CI 에서 PostgreSQL integration 테스트가 돌지 않는다 (신규, 2026-09-11 · 같은 날 붙였다) — 권고안대로 붙였다:
test.ymlserverjob 에postgres:17서비스(trust 인증, 암호 없음) → 새 DB 에db/schema.sql적용 →pytest -m integration(0건·스킵이면 실패). 세 테스트 파일에 복사돼 있던.env읽기는server/conftest.py의integration_settings픽스처 하나로 합쳤고,CALLGUARD_TEST_DATABASE_URL이 있으면 그것만 쓴다. 로컬에서 같은 절차로 4 passed, 수정 전 어댑터로 되돌리면 2 failed 로 잡히는 것까지 확인했다. CI 에서 실제로 도는 것은 첫 PR 에서 확인한다(job 이름server는 그대로라 룰셋은 안 고친다). 원래 적힌 내용 —test.yml의serverjob 에 psycopg 도 PostgreSQL 서비스도 없어@pytest.mark.integration이 한 번도 CI 에서 안 돌았다. 그래서 09-09 스키마 QA(decisions/205)로 PK 가(call_id, segment_id)가 된 뒤 전사 저장 어댑터가 새 스키마에서 저장 전부가 실패하는 상태(InvalidColumnReference)로 사흘간 초록이었다(w4-segment-composite-upsert에서 고침). 게다가 integration 테스트는 루트.env에서 DB 를 읽는데 그 DB(Neon)는 옛 스키마다. 정할 것:postgres:17서비스 + 매번 새 DB 에db/schema.sql을 적용하는 픽스처를 CI 에 붙일지. 붙이면serverjob 이 느려지고test.yml을 고쳐야 한다(런북 13·21~22장) - 지식베이스에 여권 발급·재발급 조항이 없다 (신규, 2026-09-11) — 운영 ES 적재 뒤 「여권 재발급 서류가 뭐예요」로 검색하니 1위가
DASAN-MANUAL-4.1(의학적 판단 금지)이었다. 검색 결함이 아니라 정답 문서가 없다 —knowledge-base/dasan/98조항에서 「여권」은 신분 확인 서류 목록에 두 번 나올 뿐이다. 그런데decisions/201은 다산을 고른 근거로 서류 문의 상위 단어에여권이 4위라고 적었고, 외국인 지원(A-5)이 차별점이다. 정할 것: 여권 관련 절차 조항을 지식베이스에 넣을지(출처 확인 필요 — 절대 원칙 6, 원문 전재 금지), 골든셋에 「정답 없음」 케이스로 둘지. D-4(공백 리포트)가 잡아야 할 전형이다 → ✅ 2026-09-22 들어갔다 —DASAN-TERM-4.23(류준 PR #135) · 운영 ES 재적재 101청크 · 「여권 재발급 필요 서류」 검색 1위(0.878). 남은 부작용은 아래 「여권 조항 4.23 이 dense 에서 끼어든다」 항목. POST /hub/cards/{id}/feedback이 새 스키마에서 늘 500 (신규, 2026-09-11) —card_feedback.card_id가recommendation_card를 FK 로 참조하는데recommendation·recommendation_card를 쓰는 코드가 없고, 카드 응답에card_id도 없다. 피드백을 받을 카드가 DB 에 있을 수 없는 구조다. 정할 것: 추천 결과를 저장할지(카드 응답에card_id추가), FK 를 뺄지.db/schema.sqlFK ·INSERT INTO "recommendation…"0곳 · 카드 스키마에card_id없음을 grep 으로 확인했다(실행으로는 안 쟀다). 코드는 손대지 않았다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
decisions/308(추천을 요청 경로에서 저장하고card_id를 준다) · w4-recommendation-card-id done · 프론트 연결은 09-16
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- 서버는
segment_id를 정수로 보내는데 프론트 파서가 문자열만 받는다 — 전사가 조용히 버려진다 (신규, 2026-09-10 · 같은 날 해결) — 조서희 요청으로 서버 HTTP 표면을 문자열로 맞췄다. §7.3 예시가 문자열이고 프론트가 그대로 따르고 있었으므로 서버가 계약 쪽으로 간 것이다. DB 는 BIGINT, 내부 DTO 는 int 그대로이고 변환은 라우터(경계)에서만 한다. 요청은 정수·숫자 문자열 둘 다 받는다(pydantic lax)./openapi.json이string으로 공표하는지 테스트가 고정한다(test_segment_id_contract.py). 같은 날 오후, 범위가 «모든 응답의 모든 필드 문자열» 로 커졌다 — 조서희 파서가 전부 문자열을 전제로 만들어졌고 사용자가 그 범위를 택했다. 불리언은"true"/"false", 숫자는str(),null은 그대로. 변환은schemas/_types.pyStrField한 곳이고 라우터·DTO·DB 는 원래 타입이다./health만 예외(스키마 없는 dict, 런북 19장 배포 검증 항목이라 불리언 유지). ⚠ §7.3 계약 정본·프론트types/contract.ts(is_final: boolean·utterance_end_ms: number)와 이제 어긋난다 — 계약 문서를 «전부 문자열» 로 고치는 것이 남았다. 류준(ai 는 HTTP 표면을 안 쓰므로 영향 없음 — 확인함)·조서희와 같이 본다 - 운영 커넥션이 실제로 붙은 적이 있는지 확인 (신규, 2026-09-10 · 2026-09-11 답: 한 번도 없다) — 09-11 운영 파드 로그로 확정했다(정성윤):
connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed. 운영 시크릿의POSTGRES_HOST가 비어 있었고,DATABASE_URL은 임시로 넣은 Neon 이었으며, RDS 는 만들어진 적이 없다(describe-db-instances빈 결과). 아래 «운영은DATABASE_URL하나만 주입한다(런북 12-2)» 는 런북 기준이고 실제 시크릿은server-env(.env16키)였다. RDS 로 옮긴다 →_project/decisions/108· w4-rds-prod-db. 원래 적힌 내용: 커넥션 팩토리가DATABASE_URL을 안 읽고 개별POSTGRES_*만 읽었는데, 운영은DATABASE_URL하나만 주입한다(런북 12-2)./health의postgres_configured: true는 설정 «여부»라 이걸 못 잡는다. 09-10 에 고쳤지만 운영에 재배포되기 전까지는 운영 전사 저장이 실패하는 상태일 수 있다 — 정성윤 복귀 시 재배포 + 운영 DB 에서transcript_segment행 수 확인. 배포 확인 항목(런북 19장)에 «저장이 실제로 되는가»가 없다는 뜻이기도 하다 - ngrok 으로 연 서버에 인증이 없다 (신규, 2026-09-10) — ✅ 끝났다 — ngrok 터널은 닫혔고(
STATE.md) 바깥에 열린 것은server.solidbob.cloud하나다. 문 검사는 2026-09-19 에 다시 했다 — 토큰 없는/call-mediator/ws·/ingest는 401. 원문 — 주소를 아는 사람은 누구나/hub/transcripts로 Neon 에 쓰고/docs를 본다. basic auth 는 걸지 않기로 했다(09-10) — 브라우저 fetch 의 CORS preflight(OPTIONS)에는 Authorization 헤더가 실리지 않아 ngrok 이 401 로 끊고, 그러면 조서희의 fetch 가 통째로 실패한다. «데모 데이터·test-접두어·터널은 필요할 때만 연다» 로 감수한다. 주소는 임시 도메인이라 재시작마다 바뀐다 — 그것이 유일한 방어다 - 담당 디렉터리 잠금을 풀었다 — 프론트만 전담 (2026-09-10,
_project/decisions/302) — 사용자 지시.ai/·server/·infra/는 정성윤·류준·장민석 누구나 고친다. 전담이 남는 곳은 조서희의 프론트엔드(apps/) 하나다. 이유는 «구멍»이다 — 기능 하나가 배선(server/)·구현체(ai/)·배포(infra/) 셋에 걸치는데 담당이 갈려 각자 자기 몫을 끝내도 호출부만 있고 구현체가 없는 상태로 남았다.decisions/022①이 같은 것을 이미 적었고(하네스에 C-5·F-2 를 꽂는 3줄),023이 협의 절차를 없앴지만 경계 자체는 남아 있어 그 3줄은 여전히 못 고쳤다.012의 나머지는 그대로다 — 역할 구분(요청이 흐르는 길 / 품질을 만들고 재는 쪽)과 의존 방향(ai → server)은 담당자 문제가 아니라 아키텍처이고, 코드를 어디에 둘지는 여전히 그 기준으로 가른다. 브랜치도 넷 그대로(011) — 바뀐 것은 «어느 브랜치에서 어느 디렉터리를 고칠 수 있는가» 뿐이라test.yml트리거·job 이름·main 룰셋은 손대지 않았다. 잠금 대신 남는 것:.importlinter계층 계약 ·infra_runbook_guard.py(배포에 닿는 파일은 담당자든 아니든 런북 먼저) · 손대기 전grep으로 영향 범위 확인(023).infra/의 되돌리기 어려운 변경(자원 생성·삭제)은 정성윤과 말로 맞춘다. 고친 곳:CLAUDE.md§0·§1·§3·§4·§7 ·.claude/rules/rfp-harness.md§2 ·.claude/rules/dashboard.md·server/CLAUDE.md§5 ·ai/CLAUDE.md§6 ·infra/CLAUDE.md· 7.1절. 이 항목으로 풀리는 것: 위 「P6·P7 NER —ai/몫」(포트를 양쪽에서 같이 만들 수 있다) · 「generation·compliance를ai/에 두는 것 — 장민석 확인 필요」(담당이 바뀌는 변경이 아니게 됐다). ⚠ 남의 티켓 관련 항목(중복 티켓 — 조서희 님 확인 필요)은 그대로 남는다 — 프론트는 여전히 전담이다
- 「감정분석」 대신 쓸 이름 — 팀 확정 필요 (신규, 2026-09-09) —
_project/decisions/203이 D 의 판정 입력을 텍스트에서 음성으로 바꾸면서, 「감정분석」이라는 말 자체를 안 쓰기로 했다. 우리가 하는 것은 감정 추정이 아니라 음성 신호의 이상 구간 탐지이고, 그 말은 ① 부록 A-1이 금지한 점수화를 연상시키고 ② 하지 않는 일(심리 상태 판정)을 한다고 주장한다. 후보: ①「통화 온도 · Call Temperature」(1안 — 은유라 정의를 문서가 져야 한다) ②「음성 이상 구간 · Voice Anomaly」(정직하지만 밋밋) ③「통화 긴장도 · Call Tension」(「도」가 점수를 연상) ④「응대 난이도 신호」(고객을 평가하는 말로 읽힐 수 있다). 화면 문구·기획서 10절 차별화·발표 자료가 전부 이 이름을 쓰므로 빨리 정하는 게 낫다. → 10-01 「통화 온도」로 확정(decisions/140) - D-5 통화 온도를 오프라인으로 검증할 방법이 없다 (신규, 2026-09-09) — 통화 온도는 통화 안에서 화자별 기준선을 만드는 것인데, 우리가 가진 음성이 전부 발화 단위 클립이라 통화 단위가 없다. 다산콜DB 로 재 보니 시나리오당 화자별 발화가 8건을 넘는 경우가 민원인 2개·상담사 1개뿐이었다. 실시간 데모에서는 동작하지만 수치로 증명할 수 없다. 함께 걸리는 것: 상담 품질 정답 라벨이 어느 데이터셋에도 없어(가설 4) 「톤이 튀었다」가 품질 저하를 뜻하는지 주장할 수 없다. 정할 것: ① 통화 단위 음성을 새로 확보할지 ② D-5 를 「측정 불가, 데모 전용」으로 명시하고 갈지. ⚠ 지금 하네스에 꽂으면
NO_SAMPLES가 나온다 — 그게 정직한 상태다 → 10-01 측정 불가로 발표(decisions/142) - 가설 2 가 반대로 나왔다 — 데이터 탓인지 가설 탓인지 (신규, 2026-09-09) —
decisions/203의 가설은 “상담사 톤은 일정하고 고객 톤은 흔들린다” 인데, 다산콜DB 실측은 민원인 63.2Hz · 상담사 78.7Hz(비 0.80) 로 상담사가 더 흔들린다(n=150·200 에서 같은 값). 내 해석은 이 데이터셋에 격한 통화가 한 건도 없다는 것이다 — 서울시가 「56개 시나리오 음성」이라 명시한 연기 데이터라 가설의 전제인 「격해지는 고객」이 표본에 없다. 「가설 기각」과 「측정 불가」를 구분해야 한다(절대 원칙 10). 정할 것: 실제 불만 통화 음성을 구할 경로가 있는지, 없다면 D-5 를 어떤 근거로 발표할지. ⚠ 설계 하나는 검증됐다 — 상담사의 기본 억양 폭이 더 넓으므로 절대 임계값을 쓰면 베테랑 상담사가 통화 내내 걸린다. 화자별 기준선이 맞다 → 10-01 「이 데이터로는 못 잰다」로 고정(decisions/142) - C-6 갈래가 프론트·백엔드에서 다르다 — 조서희 님 확인 필요 (신규, 2026-09-09) — 프론트
CallGuardFlag.category는 한글 3종(폭언·욕설·위협)인데 백엔드(server/apps/hub/app/dtos/call_guard_dto.py)는 4종(insult·threat·sexual·distress)이다.sexual이 프론트에 없고,distress는 그냥 매핑할 수 없다 —DASAN-MANUAL-5.4가 위기 신호를 폭언과 반대로 다루라고 정한다(통화를 끊지 않고 전문 기관 연결). 하나로 뭉치면 위기 상황에서 전화를 끊게 된다.severity: "low"|"high"도 부록 A-1의 점수 표기에 가까운지 함께 봐야 한다. 정할 것: ① 프론트를 4종으로 맞출지 ②distress를 별도 이벤트로 뺄지(화면 대응이 아예 다르므로 이쪽이 나아 보인다) → 10-01 프론트가 4종(insult·threat·sexual·distress)으로 맞췄다(contract.ts) — 닫는다 - J(블랙리스트)가 §7.3 계약에 없다 — 서버 어댑터도 없다 (신규, 2026-09-09) — ✅ 만들었다 — 2026-09-14
w4-blacklist-api. 2026-09-19 운영 실측으로/hub/blacklist-requests·…/decision·/hub/blacklist-entries·…/expiry·…/expiry-changes·…/release·/hub/blacklist-retention/purge가 떠 있다. ⚠ 남은 것은admin_account.agent_id가 비어 승인이 409 라는 것뿐이다(decisions/304). 원문 —_project/decisions/204로 J 블록을 새로 만들었다. 도메인 규칙(server/apps/blacklist/, 테스트 19건)·DTO/포트·DB 3테이블·대시보드 화면 2개까지 있는데, 저장 어댑터와 라우터가 없어 지금은 대시보드 store 안의 mock 이다. 담당 경계상BlacklistPort구현과 HTTP 는 장민석 몫이다(decisions/012). 정할 것: ① J 이벤트를 §7.3 에 언제 넣을지 ② 관리자 화면을 같은 앱에 둘지 별도 앱으로 뺄지(지금은shell: "admin"으로 같은 앱에 있다 — 라우터가 없는 구조라 기존 패턴을 따랐다) - AI Hub 원문을 골든셋에 몇 건까지 실을 수 있나 (신규, 2026-09-09) —
golden-set/v1-150.json에 AI Hub 다산 전사 원문 12건을 그대로 실었다(source: "aihub"로 표시).data/README.md가 재배포 금지 조항을 적고 있고 이 저장소는 공개다(CLAUDE.md §8 — 커밋이 곧 발행). GS-101·GS-102 가 이미 원문을 싣고 있어 전례는 있지만 2건과 90건은 규모가 다르다 — 그래서 12건만 쓰고 나머지는 그 문체를 보고 직접 썼다. 정할 것: 원문 인용 범위를 넓혀도 되는지, 아니면 12건도 바꿔 써야 하는지. ⚠source필드로 갈라 뒀으므로 두 집단의 지표를 따로 낼 수 있다 — 위의 “골든셋 문체와 실제 전사의 분포 차이” 가 요구한 측정이 이제 가능하다 → 2026-09-22 닫음 — 바꿔 썼다(_project/decisions/212). 실제로는 14건이었다(source:"aihub"12 + notes 로만 원문이던 GS-101·102). 라벨 불변 · 판v1-150.1. 마스킹 테스트·탐지기의 짧은 조각은 그대로 두고 판단을 212 에 적었다. git 이력은 다시 쓰지 않았다 — 원문은 이력에 남는다. 비용: 「실제 발화 문체 vs 작성 문체」 비교를 이 골든셋으로는 더 못 한다 - 베테랑 기준 「근속 3년」의 근거가 없다 (신규, 2026-09-09) → 2026-09-15 관리자가 바꿀 수 있게 저장한다(
PUT /hub/routing-settings,decisions/313). 값의 근거는 여전히 없다. 원문 — —decisions/204가 검토에서 나온 예시를 그대로 1차 기준으로 삼았다. 우리에게 3년이 옳다는 근거가 없어(절대 원칙 2) 코드에 굳히지 않고 인자로 뺐다(routing.pyveteran_years). 정할 것: 조직 기준을 확인할 경로가 있는지, 없으면 발표에서 「예시값」이라고 명시할지. 함께 볼 것: 베테랑이 없어 일반 배정으로 떨어진 건수(routing_log.fell_back)가 운영 지표가 되도록 설계했는데, 우리 데이터로는 실측할 수 없다 → 10-01 「예시값 · 운영에서 조정」(decisions/141) distress_count를 저장하지 않기로 한 판단 — 팀 확인 (신규, 2026-09-09) —_project/decisions/205④ 로 컬럼을 지웠다. 근거는 자해·극단적 선택 암시 건수가 정신건강에 관한 정보이고, 고객 식별자와 같은 행에 반려·해제 뒤에도 무기한 남으면 “이 번호의 사람이 자해를 N회 암시했다” 는 레코드가 된다는 것이다. 화면 경고에 필요한 것은 불리언 하나이고 프론트가 이미 그렇게 쓴다(hasDistress()). 정할 것: ① 이 판단에 동의하는지 ② 운영 지표(전문기관 연결 건수)가 필요하면 고객 식별자 없는 일별 집계로 셀지. ⚠ 페르소나 QA 가 낸 판단이고 사람이 검토한 적이 없다 → 10-01 원칙으로 유지(decisions/141)- 블랙리스트 만료 기간을 얼마로 둘지 (신규, 2026-09-09) —
blacklist_entry.expires_at을 넣었고(decisions/205⑤) 프론트 mock 기본값은 6개월인데 우리에게 6개월이 옳다는 근거가 없다(절대 원칙 2). 만료가 없으면 영구 표시가 되고 번호 재할당 시 다른 사람이 대상이 된다는 것까지가 근거이고, 길이는 조직이 정할 사안이다. 함께 볼 것: 반려된 요청의context_excerpt·reason을 언제 비울지 — 지금은 무기한 남아 조치 대상이 아닌 사람이 가장 상세한 기록을 갖는다 → 10-01 「예시값」(decisions/141) agent.role은 컬럼만 있고 서버에 인증이 없다 (신규, 2026-09-09) — ✅ 2026-09-23 확인 — 09-09 의 위험은 사라졌다. J-4 결정 API 는get_blacklist_decider→require_admin을 지나야 하고(헤더 없으면 DB 전에 401), 요청 본문에role필드가 없다. 역할은 저장소가role=ROLE_ADMIN으로 박아서transition()에 넘긴다 — 호출자가 주장할 자리가 없다.admin_account↔agent매핑도decisions/314(처음 결정할 때admin-<id>행을 붙인다)로 정해졌고 운영에서 승인·반려·해제가 409 없이 돈다(수동 QA Q-62). ⚠ 남는 사실 하나: 역할이 박혀 있으니transitions.py의 역할 검사는 런타임에 절대 실패하지 않는다 — 도메인 층의 보호막으로만 남는다. 그 자체는 문제가 아니지만 「강제되고 있다」의 근거는 가드(require_admin)이지 그 검사가 아니다. 원문 —transitions.py가role="admin"일 때만 승인을 허용하는데, 그 역할을 호출자가 주장한다.server/apps/hub/adapter/inbound에 인증·권한 확인 코드가 0건이라 상담원이role: "admin"을 보내면 통과한다 —decisions/204의 핵심 보장(「승인은 관리자 몫」)이 끝에서 끝까지 강제되지 않는다. 정할 것: ① 인증을 언제 붙일지 ② 그 전까지 J-4 승인 API 를 열지 않을지(권고). 스키마에agent.role은 이미 넣어 뒀다. ⚠ 2026-09-14 추가: 관리자 로그인(admin_auth,decisions/403)이 생기면서 재사용 가능한require_admin가드가 생겼다 — J-4 승인 API 를 만들 때 이걸 붙이면 이 항목이 풀린다. 다만admin_account(구글 로그인 허용 목록)와agent.role='admin'(상담원 마스터의 역할 구분)은 서로 다른 테이블이라, 매핑을 어떻게 할지는 별도로 정해야 한다-
원문 열람 기능이 SEC-1 과 모순된다 (신규, 2026-09-09) — ✅ 2026-09-23 기능을 걷었다(
_project/decisions/408, 조서희) —plain_text를 계약·스토어·화면에서 전부 뺐고 운영 번들에 「원문」 문자열 0건을 확인했다(정성윤). 원문 —_project/STATE.md가 “권한 확인 후 스팬 클릭으로 원문 토글” 을 대시보드 기능으로 적고 있고contract.ts의 두 타입에plain_text?가 있다. 그런데 「원문 토글」이 정식 기능이 되려면 서버가 원문을 돌려줘야 하고, 돌려주려면 어딘가에 저장해야 한다 — 그 순간 SEC-1(마스킹 전 원문 미보관)이 깨진다. 지금은 mock 만 채우므로 실제 유출은 없다. 정할 것: ① 기능을 폐기하고contract.ts의plain_text를 mock 내부 타입으로 내릴지(권고) ② 「열람」의 뜻을 재정의할지. 함께:server/테스트에 「응답 스키마에plain_text·raw_text필드가 없다」를 고정하는 단언을 두면 회귀가 막힌다 - 구글 OAuth 클라이언트 ID가 아직 없다 (신규, 2026-09-14) — 관리자 로그인(
decisions/403)을 만들었지만 Google Cloud Console에서 OAuth 클라이언트 ID를 발급한 사람이 아직 없다.GOOGLE_OAUTH_CLIENT_ID(서버)·VITE_GOOGLE_OAUTH_CLIENT_ID(프론트)에 같은 값을 넣어야 실제로 로그인이 된다. 정할 것: 어느 GCP 프로젝트에 만들지(callguard-506606을 재사용할지 새로 팔지) — STT 키와 계정이 갈리면 청구가 흩어진다 → 닫힘 (2026-09-15) — 구글 클라우드 콘솔에 웹 OAuth 클라이언트를 만들어GOOGLE_OAUTH_CLIENT_ID(server-env)·VITE_GOOGLE_OAUTH_CLIENT_ID(Vercel) 양쪽에 넣었다. 절차는 런북 18-3. admin_account에 첫 행을 아무도 안 넣었다 (신규, 2026-09-14) — 회원가입이 없으므로 이 테이블이 비어 있으면 구글 인증을 통과해도 전원 403이다. 운영 RDS에 관리자로 둘 이메일을 SQL로 직접 넣어야 한다(INSERT INTO admin_account (email, name, created_at) VALUES (...)). 정할 것: 누구를 첫 관리자로 넣을지, 그리고 이후 등록·해제 절차(운영자가 직접 SQL — 지금은 이 방법뿐)를 문서화할지 → 닫힘 (2026-09-15) — 운영admin_account에 행 1건을 넣었고 실제 로그인이 됐다. 절차는 런북 17-4. ⚠ 그 행의agent_id는 여전히 NULL 이다 — 아래 295행 항목이 이어받는다.- 운영(k3s)에 Redis를 어떻게 띄울지 정하지 않았다 (신규, 2026-09-14) —
decisions/403은 로컬 스코프(docker run redis:7-alpine)만 다뤘다. ElastiCache(관리형)는 만들지 않기로 이미 정해져 있다(infra/CLAUDE.md§1-2). k3s 안에 컨테이너로 띄우는 선택지가 남는데, 퍼시스턴스(재시작 시 전체 로그아웃 허용 여부)·리소스 요청량을 정성윤과 정해야 한다. 그 전까지는 로컬 개발에서만 관리자 로그인이 동작한다 → 닫힘 (2026-09-15) —decisions/112— 클러스터 안 Redis 파드(infra/k8s/base/redis.yaml), 볼륨 없음(5분짜리 세션만 담고 refresh 는 RDS 에 있다). ElastiCache 는 만들지 않았다. 런북 16-3. - access 5분·refresh 10분은 테스트 값이다 — 운영 값을 따로 정해야 한다 (신규, 2026-09-14) — ✅ 2026-09-28 정했다 — access 30분 · refresh 12시간(
decisions/136, 값은 사용자가 골랐다). 운영 시크릿server-env에 넣고 재시작했다(이미지 변경 없음 — 두 키가 아예 없어 코드 기본값 300/600 으로 돌고 있었다). 코드 기본값도 같이 올렸다 — 키가 빠진 채 새로 배포돼도 조용히 5분으로 돌아가지 않게. ⚠.env.example두 줄은 보호 훅 때문에 사람이 직접 고쳐야 한다. 원문 — 운영 값을 따로 정해야 한다 (신규, 2026-09-14)** — 사용자가 “테스트만 진행할 것”이라는 전제로 준 값을 그대로 코드 기본값(.env.example)에 넣었다. 실제로 운영에 올리기 전에 이 두 숫자(그리고 리프레시 회전 주기가 사용성에 미치는 영향)를 다시 정해야 한다
콜 미디에이터를 붙이며 남은 것 (2026-09-11)
services/call-mediator 가 생겼다(w4-gateway-streaming-stt) — 실제 AI Hub 음성 →
Google STT → 로컬 server 마스킹 → 대시보드 WS 까지 관통했다. 거기서 나온 것들이다.
.env.example에 콜 미디에이터 키 넷을 사람이 넣어야 한다 (신규, 2026-09-11 · 같은 날 넣었다) — 사용자가!로 직접 붙였다(값 없이 키 이름·설명만, 보호 훅은 우회하지 않았다). 원래 적힌 내용 —CALL_MEDIATOR_PORT(기본 8080) ·CORE_API_URL(기본http://localhost:8000, 운영은http://callguard-server) ·CALL_MEDIATOR_INGEST_TOKEN·CALL_MEDIATOR_VIEW_TOKEN(둘 다 없으면 루프백만 받는다). 자격증명 보호 훅이 이 파일을 파일 이름으로 막아 Claude 가 넣지 않았다(우회하지 않았다). 값 없이 키 이름만 넣으면 된다(SEC-2). ⚠ 이 머신의.env는GOOGLE_APPLICATION_CREDENTIALS가 류준 님 Mac 경로(/Users/ryujun/…)라 그대로는 키를 못 찾는다 — 실제 키는~/.gcp/callguard-stt.json이고, 검증 때는 셸 변수로 덮어 썼다- 모노 한 줄에 섞인 두 화자는 가르지 못한다 — A-2 는 채널 분리만 (신규, 2026-09-11) → 2026-09-14
speaker=auto로 넣었다 — 먼저 말한 화자 = 상담원, 선택형(decisions/303, 사용자 선택). ⚠ 실제 구글 응답으로는 미검증 — 아래 신규 항목. 원문 — — V1 실측대로 AI Hub 녹음은 전부 모노라, 재생하면 한 화자로 찍힌다. 구글 화자 태그(diarization)는 final 에만 붙고 누가 상담원인지는 알려 주지 않는다 — 첫 화자를 상담원으로 치는 식의 추측을 넣으면 C-1~C-4(상담원)·C-6(고객) 방향이 뒤집힐 수 있어 넣지 않았다. 정할 것: 데모를 물리 2채널(브라우저 2대)로만 할지, 모노 녹음 재생용으로 diarization + 규칙을 둘지 - 콜 미디에이터 배포 — 위 「A-1 콜 미디에이터를 같은 EC2 에 올릴지」(2026-09-03)의 답이 런북에 이미 있다 (신규, 2026-09-11 · 같은 날 배포) —
→ 2026-09-11 운영에 올렸다(PR #68 — 같은 노드, Ingress
/call-mediator,infra/k8s/base/call-mediator.yaml). ①~⑥ 전부 반영 — ⑤ 장부는 hostPath, ⑥ 토큰은 배포가 인스턴스 안에서 만든다. 첫 배포는 Docker Hub 새 저장소가 비공개로 만들어져 멈췄다(아래 원문은 그대로 둔다). 원래 적은 것 — 런북 0장 사양표가 FastAPI server · Node 콜 미디에이터 · Caddy ≈ 1.0GB 를 같은 노드에 넣고 계산했다. 남은 것은 ① 이미지(infra/docker/call-mediator.Dockerfile) ② k8s Deployment·Service(시크릿server-env·gcp-stt-credentials재사용) ③ Ingress 경로 — 밖에 여는 주소는server.solidbob.cloud하나이므로/call-mediator같은 경로로 붙인다 ④release.yml이 server 이미지만 굽는다 ⑤ STT 사용량 장부가 파드 안 파일이라 재시작하면 0 이 된다 — 볼륨에 두거나 1차 방어선(GCP 쿼터)만 믿을지 ⑥ 인증 — Ingress 로 열기 전에/ws·/ingest접근 제어가 먼저다 (배포 선행 조건). 처음엔Origin검사뿐이라 브라우저만 막았다 — 밖에 열리면 비브라우저 클라이언트가call_id없이WS /ws로 모든 통화의 마스킹된 자막·추천을 받고,/ingest로 STT 캡까지 과금을 태울 수 있었다(a5 세션 지적). → 같은 날 토큰 두 개로 막았다(services/call-mediator/src/domain/access.ts). 루프백 밖은 문마다 토큰이 맞아야 하고, 토큰을 안 넣고 배포하면 전부 401(fail-closed)./ingest는 진짜 비밀(CALL_MEDIATOR_INGEST_TOKEN, 헤더로만),/ws는CALL_MEDIATOR_VIEW_TOKEN— 브라우저가 내므로 비밀이 아니다. 번들에서 뽑혀도 과금 문은 안 열리게 가른 것이다. ⚠ 그래서/ws는 아직 제대로 막힌 게 아니다 — 자막을 보는 사람을 가르려면 상담원 로그인이 있어야 하고, 서버에도 없다 (「서버에 인증이 없다」). 배포 때 할 일: 두 토큰을 시크릿에 넣는다(서로 다른 값). 공개 대시보드 번들에 뷰 토큰을 넣을지는 그 한계를 알고 정한다 ⚠ 지금 EC2 등급이 런북의 g4dn.xlarge 인지 확인이 먼저다 - 통화 시작(2026-09-10 항목)은 콜 미디에이터가 ①로 구현했다 — §7.3 문서 반영이 남았다 (신규, 2026-09-11) → 2026-09-14 §7.3 반영 완료 (「검색 중」 은 꺼 둔 채로 — 위 09-09 항목). 원문 — —
첫
/ingest채널이 열리는 순간POST /hub/calls를 부르고, 실패하면 채널을 열지 않는다(외래키 때문에 저장이 전부 실패하므로). 같은 통화에 화자가 둘이어도 한 번만 부른다. 「검색 중」 신호(2026-09-09 항목)도 콜 미디에이터가 추천을 부르기 직전에 쏘면 된다 — 계약만 정하면 붙일 자리가 있다 - ES 에 못 붙을 때
/hub/recommendations가 500 이다 (신규, 2026-09-11) → 2026-09-14 503 으로 고쳤다(w4-es-unreachable-503) —ConnectionError·ConnectionTimeout, 본문에 ES 주소를 싣지 않는다. 원문 — — 09-10 에 인덱스가 없을 때(index_not_found)는 503 + 「적재해야 한다」로 돌려주게 했는데, ES 자체에 연결을 못 하면(로컬 ES 없음) 여전히 500 이다. 콜 미디에이터는 둘 다 상태 코드만 로그에 남기므로 동작은 같지만, 운영에서 원인을 가르려면 503 쪽이 낫다 —server/(누구나)
콜 미디에이터 마무리에서 남은 것 (2026-09-14)
- 조서희 님께 — 「검색 중」 신호 수신 (신규, 2026-09-14) → 2026-09-15 파서가 main 에 들어와(PR #88) 콜 미디에이터
0.1.4에서announcePending·announceCallGuard·announceClosure셋 다 켰다. 원문 — — 콜 미디에이터가 추천 요청 직전에{"type":"recommendation_pending","payload":{"call_id","segment_id"}}을 보낼 수 있게 됐다(plan.md§7.3). 지금은 꺼 두었다 —apps/call/src/lib/ws/realCallMediatorClient.ts의parseCallMediatorMessage가 모르는type을null로 돌려 「알 수 없는 콜 미디에이터 메시지입니다」 배너를 띄우기 때문이다. 필요한 것: 그type을 받아listeners.onRecommendationPending?.(call_id)를 부르기(mock 과 같은 콜백). ⚠ 뜻이 mock 과 조금 다르다 — «트리거 발동» 이 아니라 «추천을 요청했다» 라서 상담원 발화에도 오고, 뒤따르는 카드가fired:"false"면 로딩을 거둬야 한다. 들어가면services/call-mediator/src/main.tsannouncePending을true로 켠다 (콜 미디에이터 이미지 태그를 올려야 한다) speaker=auto화자 분리를 실제 구글로 돌려 본 적이 없다 (신규, 2026-09-14) — 키·AI Hub 음성이 있는 머신에서 → 10-01 미검증 그대로 발표(138·w7-demo-infra-readiness) — 닫는다node scripts/stream_wav.ts <모노.wav> --speaker auto --watch로 확인한다. 볼 것: ①ko-KR기본 모델이 스트리밍 화자 분리를 받는가(거절이면 채널이1011로 닫힌다) ② 라벨이speakerLabel·speakerTag중 무엇으로 오는가 ③ 상담원이 실제로 첫 라벨인가. 결과는decisions/303「검증하지 못한 것」 에 적는다- 조서희 님께 — 대시보드가 받아야 할 서버·콜 미디에이터 계약 (신규, 2026-09-14) — 백엔드를 먼저 만들었고 프론트 연결이 남았다. → 10-01 09-23 전부 연결됐다(류준 인계 1.5절) — 닫는다
계약 정본은
_project/plan.md7.3절 끝 「허브 HTTP 표면」. ① 콜 미디에이터 WS 메시지 셋 —recommendation_pending·call_guard·closure. 셋 다 콜 미디에이터에서 전송을 꺼 두었다 (services/call-mediator/src/main.tsannouncePending·announceCallGuard·announceClosure). 받는 코드가 들어가면 켠다. ⚠call_guard.category는insult·threat·sexual·distress다(mock폭언·욕설·위협과 다름). ⚠closure는 새 형식이다 —procedure·procedure_title·verdict: complete/incomplete·conditional·detected,closure_type·reason(필수)·approved/blocked는 없다 ② REST — 수동 검색POST /hub/search(응답이 조항 목록이라 카드로 바꾸는 것은 화면 몫) · 상담기록GET /hub/calls· 자막GET /hub/calls/{id}/transcript· 블랙리스트 요청POST /hub/blacklist-requests· 카드 피드백·「못 찾았다」 신고(이미 있음) ③ 관리자(apps/admin, 로그인 필요) —GET /hub/blacklist-requests·POST /hub/blacklist-requests/{id}/decision(만료 일수 필수) ·GET /hub/blacklist-entries·POST /hub/blacklist-entries/{id}/release·GET /hub/call-guard-flags·GET /hub/knowledge-gaps(이미 있음) CUSTOMER_REF_HMAC_KEY를.env.example과 운영server-env에 넣어야 한다 (신규, 2026-09-14) — 보호 훅이.env.example→ 닫힘 (2026-09-15) — 운영server-env에 이미 있었다(2026-09-15 키 이름 조회로 확인)..env.example:81·secret.example.yaml:110도 되어 있다. ⚠ 있는 키를 새로 만들지 않는다 — HMAC 이라 바뀌면 기존 식별자를 못 찾는다(decisions/304). 편집을 막아 사람이 넣는다(키 이름만). 운영 시크릿에는 값을 넣고 보관한다 — 잃으면 기존 고객 식별자·블랙리스트 등록을 다시 찾을 수 없다. 없으면 통화는 열리고 고객 연결만 꺼진다(decisions/304).secret.example.yaml에는 적었다- ✅ 2026-09-22 ①로 정했다(
_project/decisions/314, 장민석 — 코드, 운영 배포 전). 처음 결정할 때 서버가 그 관리자 전용agent행(admin-<id>,role='admin')을 만들어agent_id가 비어 있을 때만 채운다. 운영자 SQL 불필요. 원문 —admin_account.agent_id를 채워야 블랙리스트 승인·해제가 된다 (신규, 2026-09-14) — 비어 있으면 409. 회원가입 화면이 없어 운영자가 SQL 로 넣는다 막히는 범위를 코드로 확인했다 (2026-09-15, 정성윤) —hub/dependencies/blacklist_decider_provider.py:16의if not admin.agent_id: 409하나가 전부다. 쓰기 경로만 막힌다(승인·해제 ·decisions/309만료 연장·단축). 조회와 로그인은 멀쩡하다 — 관리자 화면을 열고 둘러보는 데는 지장이 없고,decisions/113의 보존 정리 버튼도require_admin만 보므로 이 결정을 기다리지 않아도 된다. 정할 것 — 관리자의 결정을 어느 상담원 마스터 ID 로 기록할지. 선택지 셋: ① 관리자마다 대응하는agent행을 만들어 잇는다(사람 = 행 하나, 감사 추적이 자연스럽다) ② 운영용 공용agent행 하나(admin-console같은)로 전부 기록한다(누가 눌렀는지는 감사 로그로 본다) ③ 스키마를 바꿔decided_by가admin_account도 가리키게 한다(마이그레이션 필요, 되돌리기 어렵다) 정할 사람: 장민석(스키마·서버) · 정성윤(운영). J-4/J-5 를 실제로 쓰기 전까지는 막히지 않는다 - 운영·Neon DB 에 2026-09-14 스키마를 넣어야 한다 (신규, 2026-09-14) —
customer_id64자 ·admin_account.agent_id·closure재정의 + → 닫힘 (2026-09-15) — 적용돼 있었다(db/migrations/2026-09-14-…sql, 09-15 26 테이블 이름 일치 확인). Neon 은 진작 없앴으므로(decisions/108) 「Neon DB」 부분은 항목 자체가 낡은 것이었다.closure_item. 운영 확인(같은 날): 테이블 22개 ·admin_account없음 ·closure0건 → 넣을 파일은db/migrations/2026-09-14-customer-ref-admin-closure.sql(옛 스키마fd96adc에 적용 → 새schema.sql과 컬럼·제약·인덱스·주석 333항목 일치, integration 10 통과로 로컬 검증). 이미지0.1.5를 올리기 전에 넣는다(런북 17·19장). Neon 은 그 전 스키마 차이(transcript_segment복합키)도 남아 있다 document테이블을 채우는 경로가 없다 (신규, 2026-09-14) — 조항 본문은 ES 에만 적재된다. 그런데call_guard_flag·recommendation_card등이 → 닫힘 (2026-09-15) — 경로는scripts/seed_documents.py이고 2026-09-15 운영에 돌렸다 —document0행 → 98행. 런북 17-3.document를 외래키로 참조해 근거 조항을 넣으면 23503 이었다(E2E 로 재현 — 콜 가드 저장이 통째로 실패). 콜 가드는 조항이 있을 때만 잇도록 고쳤고, 새closure.source_doc_id는 FK 를 걸지 않았다. 정할 것:index_knowledge_base.py가document도 채울지, FK 를 걷을지- ✅ 2026-09-21 류준: 케이스 99건 작성(
w5-f2-golden-cases) — 하네스closure_gaten 99 ·test_golden_set_closure.pyskip 해제. 118 되돌림 여부는 팀 판단 — F-2 자동 판정·규칙표를 측정할 골든셋 케이스가 0건이다 — 류준 님께 (신규, 2026-09-14) — ✅ 2026-09-19 결정으로 정리됐다(_project/decisions/118) — 케이스가 0건이라 F-2 를 「설계 문서 전환」으로 확정했다(7주차 체크포인트를 앞당겨 판정). ⚠ 요청이 사라진 것은 아니다 — 케이스가 생기면 118 을 되돌려 「구현 완결」로 간다. 오늘 실측으로test_golden_set_closure.py가 3건 전부 skip 되는 것을 확인했다. 원문 — ** —decisions/305로 필요서류 조항 25개가 규칙이 됐고F2Case.procedure(조항 ID)·expected_verdict: complete/incomplete로 케이스를 넣을 수 있다. 키워드 판정은 부정 문맥을 몰라 누락을 못 잡는 쪽으로 틀린다 — 측정 전까지 「F-2 누락 0건」 을 인용하지 않는다. 조건 분기 조항 10개(EXCLUDED)도 조건 판정 규칙이 생기면 넣는다 - ✅ 2026-09-21 고쳤다(류준,
w5-f2-golden-cases— 「필요서류 체크리스트로 적용, 종결 차단은 미적용」. 골든셋 라벨에 POLICY-1 참조 0건) —DASAN-POLICY-1(「F-2 미적용」)이decisions/305와 어긋난다 (신규, 2026-09-14) — 지식베이스 문서라 고치지 않았다. 검색 인덱스에 들어가는 문서라 류준 님과 함께 고친다 - ◐ 2026-09-22 — ①은 09-15 상담원 토큰(
decisions/307)으로 · ②는 채우지 않기로 정했다(decisions/316— 전화번호 뒷자리도 P4) · ③은 180일 정리(decisions/312)로 닫혔다. ④(배정 판정을 부르는 곳)만 남았다(w7-j5-routing-caller). 원문 — 블랙리스트 남은 것 (신규, 2026-09-14) — ① 상담원 인증이 없어 요청은agent에 있는 아무 ID 로나 부를 수 있다 ②display_hint를 채우는 경로가 없다(늘 null) → 10-01 ④ 배정 판정 호출도 끝났다(w7-j5-routing-callerdone) — 닫는다 ③ 반려 요청 사유·자막을 일정 기간 뒤 비우는 작업이 없다(decisions/205) ④J-5 배정은2026-09-15POST /hub/routing-decisions로 열었다(decisions/313) — 부르는 곳(교환기)은 아직 없다. 원문: J-5 배정(find_entry)은 인입 경로에 아직 안 붙었다 - 재상담 고객 이력 요약(메모)이 없다 (신규, 2026-09-14) —
GET /hub/calls?customer_id=로 같은 고객의 지난 통화·문의 유형은 나온다. 프론트 mock 의 「메모」 는 → 10-01 안 만든다 — 범위 밖(138) 대응 컬럼이 없다(summary_text는 D-1 요약이고 채우는 경로도 501) - main 의 관리자 로그인 머지(
cb959a9)가 서버 이미지 태그를 안 올렸다 (신규, 2026-09-14) — ✅ 해소됐다 — 그 뒤tag-check(decisions/111·114)가 필수 통과 검사로 붙어 태그를 안 올리면 머지 버튼이 잠긴다. 실제로0.1.15~0.1.18이 PR 마다 올라갔고 09-19 운영에0.1.18이 떠 있다. 원문 — ** —server/가 바뀌었는데kustomization.yaml이0.1.3그대로 main 에 들어갔다.release.yml은 «코드 변경 + 태그 그대로» 면 실패한다 — 그 머지의 릴리스가 실제로 실패했는지는 안 봤다. 이번server브랜치 PR 이0.1.4로 올리므로 같이 풀린다
C-6 저장 배선 · 오류 주입기에서 남은 것 (2026-09-14, 류준)
- 운영 RDS 에
document행이 없다 (신규, 2026-09-14 · 같은 날 정정) — 콜 가드 기록·추천 카드의 근거 조항이 이 테이블을 외래키로 → 닫힘 (2026-09-15) — 2026-09-15 적재 완료(98행). 돌리기 전 쌓인call_guard_flag1건은source_doc_id가 NULL 로 남는다 — 적재는 과거 행을 소급하지 않는다. 가리킨다. 비어 있으면 근거가 NULL 로 저장된다(장민석 님 콜 가드 저장소가 FK 위반 대신 NULL 로 떨어뜨린다).500 이 난다는 걷어낸 류준 배선 기준의 서술이었다. 절차는 런북 17-3 —scripts/seed_documents.py. 정할 것: 누가 언제 돌리는가(정성윤 님 vs 류준) - C-6 배선이 두 벌이었다 (2026-09-14 해결) — 류준(PR #76, 전사 수신 안에서 탐지)과 장민석 님(
server브랜치, 콜 미디에이터가POST /hub/call-guard-checks)이 같은 날 따로 만들었다. 둘 다 들어가면 같은 발화를 두 번 탐지·저장한다. 사용자 결정으로 장민석 님 방식을 남기고 류준 쪽을 걷어냈다 — 결과를 대시보드로 보낼 수 있는 쪽이다. 걷어낼 때 민석 님 브랜치 기준과 같은 모양으로 되돌려 머지 충돌이 코드에서 나지 않게 했다 - E-3 곡선의 한계를 발표에서 어떻게 적을지 (신규, 2026-09-14) — 주입기는 실측 편집 81건 중 46.9% 를 흉내 내지 못한다 → 10-01 인용 문구 셋 확정(
decisions/138) (환청·의미 붕괴 — 넣을 말을 지어내야 한다). 같은 WER 에서 실제 STT 보다 덜 파괴적이라 곡선은 낙관 쪽으로 기운다. 프로파일도 내국인 낭독 20발화 × 2조건이라 작다. 정할 것: ① 이 곡선을 성공 조건의 수치로 쓸지, 「상한」 으로만 쓸지 ② 실측 쌍을 늘릴지 (다산콜DB 로 Chirp 전사를 더 뽑으면 STT 비용이 든다 — COST-1). 곡선 측정 자체는 모델 학습 후 진행 예정 - 학습한 모델을 어디에·어떻게 올리는가 (신규, 2026-09-14) — 모델 학습은 정성윤 님이 SSH 로 개인 컴퓨터에서 돌리고
모델 파일만 업로드하기로 했다. 운영 AWS·CI 에서는 학습하지 않는다. 칸반의 「모델 학습 후 진행 예정」 카드(A-5·D-5·E-3)가
이 업로드를 기다린다. 정할 것: ① 업로드 위치(런북 9-2 —
/mnt/scratch는 인스턴스 중지 시 비므로 가중치를 두면 안 된다) ② 파일 이름에 넣을 버전 표기 — §5 규칙상 수치마다 「어느 모델로 쟀는지」가 남아야 하는데eval_run에 모델 버전 칸이 없다 ③ 학습 데이터·시드·명령을 어디에 기록할지(개인 PC 라 저장소에 흔적이 안 남는다 — 절대 원칙 2·8) ④ 모델 파일에 원본 데이터가 섞여 올라가지 않게 할 것(AI Hub 데이터는 커밋·공개 금지)- → 닫음 (2026-09-21 보드 최신화, 정성윤):
decisions/210(모델을 학습하지 않는다 — 데이터는 측정용)으로 전제가 사라졌다
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- D-5 를 누가 부르는가 (신규, 2026-09-14) — 저장 경로(
VoiceOutlierRecordPort)는 있고 호출부가 없다. 톤 특징값은 오디오에서 → 10-01 안 부른다 — 시연 동작·수치 측정 불가(142·317) 나오는데server/는 텍스트만 받는다. 정할 것: 콜 미디에이터가 발화별 특징값(F0 흔들림)을 전사와 함께 보낼지, 통화 종료 때 콜 미디에이터가 한 번에 보낼지. 콜 미디에이터(services/call-mediator)·§7.3 계약에 걸린다
frontend 브랜치를 main 에 합칠 때 — 조서희 님께 (2026-09-11, decisions/109)
services/call-mediator가 두 벌이다 — main 쪽을 쓰고 frontend 쪽 것은 버린다. → 2026-09-11 정성윤이 직접 합쳤다(사용자 결정, 머지ce7f525). 아래 ①~③ 그대로 했고 ④ 는 해당 없음. frontend 브랜치 자체는 고치지 않았다 — 조서희 님은 main 을 받으면 이 정리가 그대로 들어온다. 원래 적은 것 — 같은 날 조서희 님(decisions/402, 브라우저 음성 인식 dev 경로)과 정성윤(정식 A-1, 운영 배포)이 서로 모르고 같은 디렉터리에 콜 미디에이터를 만들었다. 합치면README.md·package.json·package-lock.json이 충돌한다. 402 의 쓸모는 main 콜 미디에이터로 옮겼다(decisions/109) — 운영https://server.solidbob.cloud/call-mediator/dev가 같은 테스트 페이지이고 (ngrok 필요 없음),/dashboard경로도 그대로 받는다. 합칠 때 할 일: ①services/call-mediator/는 main 쪽을 고른다(git checkout origin/main -- services/call-mediator) — frontend 의server.js·devPage.js·hubClient.js·dashboardHub.js·Dockerfile·.dockerignore·.gitignore는 버린다(남으면 콜 미디에이터 이미지에 섞이고 릴리스 태그 검사가 막는다) ②apps/dashboard/src/lib/ws/types.ts의?call_mediator=덮어쓰기는 그대로 넣는다 — 정식 콜 미디에이터와 맞물린다. 운영 주소는?call_mediator=+encodeURIComponent("wss://server.solidbob.cloud/call-mediator/ws?token=<뷰 토큰>")(토큰 안에&는 없지만 인코딩해 두는 편이 안전하다) ③decisions/402머리에 «일부 대체됨 — 109» 를 적는다(콜 미디에이터 신설 부분). 대시보드 덮어쓰기 결정은 402 그대로 유효하다 ④w3-gateway-dev-testcall티켓은 그대로done이다 — 옮겨 온 쪽은 w4-gateway-dev-browser-stt- 뷰 토큰을 대시보드에 어떻게 줄지 (신규, 2026-09-11) —
?call_mediator=로 넣으면 localStorage 에 남고, Vercel env 로 넣으면 공개 번들에 들어간다. → 10-01?call_token=+ 주소창 가림(09-28)으로 정착 — 닫는다 → 10-02 정정 — 위 꼬리말은 다른 토큰 이야기다.?call_token=은 입력(과금) 토큰이고, 이 항목이 물은 뷰 토큰은 지금도 Vercel 환경변수로 공개 번들에 들어 있다 —decisions/127(09-21)이 감수하기로 정한 것이다(마스킹된 자막 구독만 되고 쓰기 문은 401, 10-01 밤 확인) 둘 다 비밀이 아니다(무작위 스캔만 막는다). 사람별 인증이 생기기 전까지는 그 한계를 알고 쓴다. 뷰 토큰 값은 인스턴스에서 꺼낸다(secret.example.yaml③) → 아래 「공개 데모를 라이브로 바꿀지」에 선택지를 정리했다.
공개 데모(call.solidbob.cloud)를 라이브로 바꿀지 — 조서희 님과 정할 것 (2026-09-11)
콜 미디에이터가 운영에 떴다(/call-mediator/health — 키·캡·토큰 둘 전부 true). 대시보드를 실제 콜 미디에이터에 붙이려면 Vercel 에
VITE_CALL_MEDIATOR_WS_URL=wss://server.solidbob.cloud/call-mediator/ws?token=<뷰 토큰> 을 넣고 재배포하면 된다 — 그런데 정성윤은
이 설정을 일부러 멈췄다. 기술 문제가 아니라 팀이 정할 일이라서다: 대시보드는 조서희 님 전담이고(decisions/302),
decisions/109 도 «프론트는 건드리지 않는다» 고 적었다.
먼저 알아 둘 사실 (2026-09-11 코드·운영 확인)
- 대시보드의 실시간 자막·추천은 전부 콜 미디에이터 WebSocket 으로 온다. 필요한 빌드 변수는
VITE_CALL_MEDIATOR_WS_URL하나다.VITE_CORE_API_URL은 지금 헤더REST배지만 켠다(AppHeader.tsx) — 통화 기록(coreClient.ts)은 아직 mock 이다. 그래서 운영 서버의 CORS(call.solidbob.cloud→ 지금 400)도 지금은 필요 없다. 통화 기록이 서버 REST 로 바뀔 때 넣는다 - 지금 배포된 번들에는 서버·콜 미디에이터 주소가 없다 → 가짜 시나리오(mock) 를 재생한다. 누가 열어도 자막·카드가 흐른다
- 라이브로 바꾸면 오디오를 보내는 쪽(생산자)이 있어야 화면에 뭔가 뜬다. 지금 생산자는 개발용
/call-mediator/dev(ingest 토큰 필요) 하나다 - 콜 미디에이터 허용 origin 은
https://call.solidbob.cloud· 로컬 Vite 뿐이다 — Vercel Preview(*.vercel.app)는 붙지 못한다
| 방법 | 좋은 점 | 나쁜 점 | |
|---|---|---|---|
| A | 공개 데모는 mock 그대로 · 라이브는 개발자가 ?call_mediator=<주소> 로 자기 브라우저에서만 |
바꿀 것 없음. 공개 데모가 늘 돈다. 자막이 밖에 노출되지 않는다 | 방문자는 실제 동작을 못 본다. 뷰 토큰을 쓸 사람에게 따로 건넨다. ⚠ ?call_mediator= 가 아무 주소나 받는다 — 아래 항목을 먼저 고쳐야 A 가 안전하다 |
| B | Vercel Production 에 VITE_CALL_MEDIATOR_WS_URL (뷰 토큰 포함) → 재배포 |
주소만 열면 라이브. 시연 준비가 간단하다 | ① 생산자가 없으면 빈 화면 ② 번들이 공개라 주소를 아는 누구나 모든 통화의 (마스킹된) 자막을 본다 ③ EC2 가 꺼지면(자동 중지를 걸면) 멈춘다 ④ 토큰을 바꾸면 재배포 |
| C | 기본은 mock, 화면에서 「라이브 연결」을 골라 토큰을 사람이 입력 | 공개 데모도 살고 라이브도 쉽다. 토큰이 번들에 안 들어간다 | 프론트 코드 작업이 필요하다(조서희 님). 지금의 ?call_mediator= 를 화면으로 올린 것에 가깝다 |
권고: 지금은 A — 단, ?call_mediator= 허용 목록을 먼저 고친 뒤에. 공개 데모를 망가뜨리지 않고 노출도 없으며, 라이브 확인은
?call_mediator= 로 충분하다. 그런데 그 ?call_mediator= 에 지금 구멍이 있다(바로 아래 항목 — A/B 선택과 상관없이 이미 운영 번들에 있다). B 로 가는 조건 —
① 시연 때 오디오를 누가 어떻게 보낼지 정해졌다(/call-mediator/dev 등) ② 「주소를 아는 사람은 자막을 본다」를 팀이 받아들였다
(상담원 로그인은 서버에도 아직 없다 — 「서버에 인증이 없다」). 발표 시연만 라이브가 필요하면 그날만 B 로 바꿨다가 되돌리는 방법도 있다.
B 를 고르면 할 일 (정성윤 — Vercel 계정):
뷰 토큰 꺼내기(sudo k3s kubectl -n callguard get secret call-mediator-tokens -o jsonpath='{.data.CALL_MEDIATOR_VIEW_TOKEN}' | base64 -d, 32자 — 48자인
INGEST 는 절대 넣지 않는다) → call.solidbob.cloud 가 붙은 Vercel 프로젝트(call-solidbob-cloud-kxu6, Root Directory apps/call — 09-14 개명 반영) → Settings →
Environment Variables → Production 만 → Deployments → Redeploy(VITE_ 는 빌드 때 박힌다) → 확인: 번들에 call-mediator/ws 가 들어갔는지 ·
대시보드를 연 동안 /call-mediator/health 의 dashboards 가 1 이 되는지.
- A / B / C 중 무엇으로 할지 — ✅ 2026-09-21 닫음 — 라이브로 둔다(
_project/decisions/127). 09-17 에 Vercel 변수로 이미 B 가 돼 있었고 그 상태를 기록했다. 번들의 뷰 토큰은 마스킹된 자막 구독만 열고, 발화를 보내는 문과 STT 과금 문은 번들 밖이다. 원문 — 조서희 님(대시보드) · 정성윤(Vercel). 정하면 위 「뷰 토큰을 대시보드에 어떻게 줄지」와 함께 닫는다 - ⚠
?call_mediator=가 아무 WebSocket 주소나 받아 저장한다 — 운영 대시보드에 이미 떠 있었다 (신규, 2026-09-11 · 2026-09-14 해결) —apps/call/src/lib/ws/types.ts(옛apps/dashboard) 가ws://·wss://로 시작만 하면 받아 localStorage 에 남기고 있었다(PR #70 으로 배포, 운영 번들index-ZZuCSHQN.js에callguard:callMediatorUrlOverride확인). 그래서call.solidbob.cloud/?call_mediator=wss://<남의 서버>/ws링크 하나를 누른 브라우저는?call_mediator=clear를 하기 전까지 그 서버에 붙고, 그 서버가 보내는 가짜 자막·「필요서류」 카드를 그대로 띄웠다. 상담원이 가짜 서류 안내를 믿고 고객에게 전하는 경로가 될 수 있었다(a5·33 세션 확인, bc 세션이 운영 번들로 재확인). 고친 것: ①isAllowedCallMediatorUrl()허용 목록 —wss://server.solidbob.cloud/call-mediator/*와ws://localhost·ws://127.0.0.1(로컬 개발)만 받고 나머지는 조용히 버린다(서브도메인 스푸핑server.solidbob.cloud.evil.com같은 것도 정확한 hostname 비교라 걸린다) ②CallMediatorOverrideBanner.tsx— 덮어쓰기가 켜져 있는 동안 화면 상단에 붙은 주소 + 「연결 해제」 버튼을 보여준다.npm run typecheck && npm run build통과 확인(사용자 지시로 조서희 진행).
배포하면 ES 가 매번 «configured» 로 나온다 (신규, 2026-09-11)
statefulset.apps/elasticsearch configured가 모든 릴리스에 찍힌다 — ✅ 2026-09-23 확인 — 표시만 그렇다. 노드에서kubectl diff -f current.yaml을 돌리니 차이 0이고,elasticsearch-0파드는 2026-09-08 생성 · 재시작 2회로 릴리스와 무관하다(오늘 세 번의 릴리스에도 그대로).apply가 패치를 보내며 찍는 문구일 뿐 실제로 바뀌는 것이 없다. 원문 —elasticsearch.yaml을 안 바꿔도 그렇다(릴리스 34580004558·34580734409· 34584307027 확인). 누가 클러스터를 손댄 흔적이 아니라 적용할 때마다 생기는 차이다(bc 세션 확인). 해는 없지만(검색 200, 인덱스 그대로) 진짜 변경이 생겨도 이 줄에 묻힌다. 추정:volumeClaimTemplates에 서버가 기본값을 채우는 필드. 확인은 인스턴스에서kubectl kustomize infra/k8s/base/ | sudo k3s kubectl diff -f -— 나온 필드를 매니페스트에 적어 두면 사라진다
릴리스 태그 게이트를 고치며 남은 것 (2026-09-14, decisions/111)
룰셋에— 2026-09-15 완료. 룰셋(tag-check·call-mediator를 필수 통과 검사로 등록21538648)의 필수 검사가jekyll·ai·server→ +call-mediator·tag-check로 다섯이 됐다. 나머지 규칙(deletion·non_fast_forward·pull_request·strict: true·승인 0건)은 그대로다. 이제server/·ai/를 고치면서newTag를 안 올리면 머지 버튼이 잠긴다(전에는 빨간 X 만 떴다)..github/branch-protection.json을 라이브 룰셋에 맞췄다 (2026-09-15, 정성윤) — 값 셋을 고쳤다:contexts셋 → 다섯(call-mediator·tag-check추가) · 승인1→0·enforce_adminsfalse→true(라이브bypass_actors: []= 우회 없음에 대응). 파일을 지우지 않은 이유:decisions/011이 «룰셋을 걷어내고 클래식으로 돌아갈 때를 위해 남겨 둔다»로 정해뒀다. 목적이 대비본이므로 값이 어긋나 있으면 되돌리는 순간 정책이 조용히 바뀐다 — 그게 이 항목의 위험이었다. ⚠ 형식이 다르다는 건 남는다 — 이 파일은 클래식 보호 API(branches/main/protection) 형식이고 라이브는 룰셋 API(21538648)다. 클래식에 대응물이 없는 라이브 설정 둘은 못 담았다:require_extra_approval_for_unattributed_changes: true·allowed_merge_methods. 룰셋 백업은 이미 있었고, 그것도 어긋나 있었다 —.github/ruleset-main.json은22c7983에 들어와 있었는데contexts가 셋인 옛 판이었다(같은 병). 2026-09-15 에 라이브 룰셋(21538648)에서 읽기 전용 필드 8개를 걷어낸 복원본이다(PUT --input으로 그대로 되살아난다). 쓰기 가능 필드 여섯이 라이브와 한 글자도 다르지 않음을 대조 확인했다. 뜨고 되살리는 명령은CLAUDE.md§7. ⚠ 룰셋을 고칠 때 이 파일을 같이 갱신하지 않으면 다시 어긋난다 — 그게 이 항목이 생긴 경위다.- OIDC 신뢰 정책 — 확인했다. 유효하다 (2026-09-15, 정성윤) —
callguard-deploy-role의 신뢰 정책은 실제로main한정이다.release.yml주석 ④ 가 맞았다.sub=repo:SeongYuna@280208914/call.solidbob.cloud@1344602683:ref:refs/heads/main— 이름이 아니라 계정·저장소의 숫자 ID 가 박힌 형태다(gh api repos/...로owner_id·repo_id대조 확인). 저장소 이름을 바꾸거나 같은 이름으로 새로 만들어도 사칭되지 않아 이름만 쓰는 것보다 강하다. 함께 본 것 — ①StringLike지만 값에*가 없어 사실상 정확 일치 ②aud는sts.amazonaws.com고정 ③ GitHub OIDC 공급자를 신뢰하는 역할은 이것 하나뿐이다(전 역할 전수 조사) ④ 오늘 05:33 에 실제로 쓰였다 — 릴리스 #90 의k3s-deploy→ 「AWS 자격증명(OIDC)」 success.#54·#55의 거부는 역할 생성(09-09 04:37) 직후 과도기였다. 그래서 「release.yml에pull_request를 더하면 머지 안 된 코드가 운영에 배포된다」는 성립하지 않는다 — OIDC 스텝에서 죽는다. 다만 이미지 push 는 AWS 를 거치지 않아 그대로 남는다(DOCKERHUB_*만 쓴다). 그쪽은 판정만 하는tag-check.yml을 따로 뗀 것으로 이미 닫혀 있다(decisions/111). ⑤ 왜 ID 형태인지 확인했다 (덧붙임, 2026-09-15) — 커스텀 템플릿이 아니라 GitHub 기본값이다:gh api repos/SeongYuna/call.solidbob.cloud/actions/oidc/customization/sub→{"use_default": true, "use_immutable_subject": true, "sub_claim_prefix": "repo:SeongYuna@…/call.solidbob.cloud@…"}.use_immutable_subject가 켜져 있어 이름 대신 ID 가 박힌다. ⚠ 그래서 이 토글을 끄면 배포가 전부 깨진다 —sub가 이름 형태(repo:SeongYuna/call.solidbob.cloud:ref:…)로 돌아가는데 신뢰 정책은 ID 형태로 고정돼 있어 더는 일치하지 않는다. 증상은#54·#55와 똑같은Not authorized to perform sts:AssumeRoleWithWebIdentity라 원인을 찾기 어렵다. 끄지 않는다. 덧붙여 신뢰 정책은 저장소 어디에도 코드로 없다(terraform 포함 — 전수 확인). AWS 콘솔에만 있으므로 역할을 잃으면 정책 원문도 같이 사라진다. ES 이미지는 CI 가 굽지 않는다— 2026-09-15 자동화했다 (decisions/114).release.yml의paths에infra/elasticsearch/**를 넣고es-image잡을 만들었고, 태그 게이트 (check_release_tags.py의IMAGES)에도es를 추가했다. 두 갈래가 다 닫혔다. ⚠ ES 태그는 ES 버전을 따라간다(Dockerfile의ARG ES_VERSION). Dockerfile 만 고치고 버전은 그대로일 때는 빌드 접미사를 붙인다 — 예:9.5.1-2. 같은 태그로 다시 구우면 노드가 캐시를 계속 쓴다.— 2026-09-15 한 줄 추가했다 (converge.sh가 콜 미디에이터 롤아웃을 보지 않는다decisions/114).rollout status deploy/callguard-call-mediator를 더해 부팅 경로도 릴리스 배포와 같은 것을 본다.— 2026-09-15 트리거를 좁혔다 (test.yml이 같은 SHA 에 검사를 2벌 단다decisions/114).push.branches를[main]으로 바꿨다.concurrency를 합치는 「싼 수정」은 쓰지 않았다 — 두 런이 같은 SHA 에 같은 이름으로 check-run 을 보고해서, 취소된 쪽이 나중에 기록되면 필수 검사가cancelled로 남아 머지가 막힌다(필수 검사가 다섯이 된 지금은 더 위험하다). ⚠ 잃은 것 하나 — 「PR 없이 브랜치에만 push 했을 때」는 CI 가 돌지 않는다. PR 이 열려 있으면 push 마다pull_request가 돈다. 일찍 보고 싶으면 초안 PR을 연다. 불편하면 되돌릴 수 있다(중복도 같이 돌아온다).운영 이미지에 테스트가 실린다— 2026-09-15.dockerignore로 뺐다 (decisions/114).**/tests·**/conftest.py·**/pytest.ini·**/.importlinter·ai/apps/evaluation추가.ai/apps/call_guard·voice_signal은 남겼다 — C-6·D-5 가 꽂힐 자리라 빼면 나중에 꽂는 사람이 로컬에선 되는데 운영에서만 ImportError 로 헤맨다. 같이 한 것: 안전망을 넓혔다.server/tests/test_image_layout.py는 Dockerfile 의COPY만 읽어서COPY ai/apps/가 그대로여도.dockerignore가 그 안을 빼면 테스트는 초록인데 이미지엔 없다._ignored_by()를 더해.dockerignore도 함께 보게 했다.
운영 스키마가 배포보다 늦게 따라간다 (신규, 2026-09-14)
- 「머지 = 배포」인데 스키마는 사람 손이라 구조적으로 뒤따라간다 — ✅ 2026-09-23 구조로 막았다 —
decisions/128의 배포 전 스키마 대조가 릴리스 워크플로에 들어갔고(w6-deploy-schema-precheck), 어긋나면 SSM 적용 전에 멈춘다. 오늘 네 번의 릴리스에서 전부 「어긋남 0 — 29 테이블 · 200 컬럼」으로 초록이었다. 사람이 마이그레이션을 잊어도 배포가 먼저 서는 구조다. 원문 — ⚠ 2026-09-22 또 났다: PR #111 머지로 server0.1.25가 10:26 KST 에 먼저 배포됐고2026-09-22-blacklist-request-note-unmeasured.sql은 10:37 KST 에 넣었다(_logs/2026-09-22-05-seongyun) — 그 11분은 블랙리스트 요청 경로가 500,/health는ok.decisions/128이 구현 전이라 못 막았다. 넣은 뒤 29 테이블 199 컬럼 어긋남 0. ◐ 2026-09-21 방식을 정했다 — 구현은 남았다(_project/decisions/128): 릴리스 워크플로가 적용 전에 SSM 으로 대조하고 어긋나면 멈춘다(w6-deploy-schema-precheck). 원문 — ⚠ 구조적 위험은 그대로 열려 있다. 다만 2026-09-20 현재 «실제로 어긋난 것은 없다» — 운영 DB 와db/schema.sql을 컬럼 단위로 대조해 29 테이블 198 컬럼, 타입·길이·NULL 여부까지 어긋남 0 을 확인했다(scripts/compare_prod_schema.py신설 — 일부러 어긋나게 만든 사본으로 탐지되는지 먼저 검증했다. 지금까지 대조는 테이블 「이름」까지였다). 배포마다 이 대조를 돌리면 구멍이 드러난다. 원문 — 09-14 에 실제로 났다. PR #79 머지 →release.yml자동 → server0.1.5가 06:33 배포됐는데 운영 DB 는 22 테이블(fd96adc, 09-09) 이었다. 런북 19장이 「이미지를 올리기 전에 스키마를 넣는다」고 적어 뒀지만 사람이 끼어들 지점이 없다. ⚠/health는 이 상태에서도ok다(0.1.5기대 출력과 일치) — 배포 판정으로는 안 드러나고 발신 번호 있는 통화 시작·F-2 저장·관리자 로그인만 500 이었다. 정할 것:tag-check.yml(PR 전용, 이미지를 굽지 않는다)에 스키마 선행 확인을 붙일지. 붙인다면 무엇으로 보나 — ①db/migrations/에 새 파일이 있으면 「적용했는가」를 묻는 체크박스 ②schema.sql의CREATE TABLE수와 운영 조회값 비교(운영 접근이 CI 에 필요해진다 — 반대급부가 크다). ①이 싸고, ②는 자격증명을 CI 에 들이는 값이 든다. admin_account행이 비어 있다 (2026-09-14) — 넣기 전까지 블랙리스트 승인·해제가 409. → 닫힘 (2026-09-15) — 행 1건을 넣었다(2026-09-15).agent_id는 아직 NULL 이라 승인·해제 409 는 그대로다 — 295행 항목이 이어받는다. 회원가입 화면이 없어 운영자가 SQL 로 넣고agent_id를 채운다.CUSTOMER_REF_HMAC_KEY는 09-14 에 넣었다.- 런북 8장의 SSH 키 이름이 실물과 다르다 (2026-09-14) — ✅ 2026-09-23 대조 완료 — 런북의 「실물 대조」 표가
assist-key→callguard-key로 이미 정정해 두었고, AWS 실물(aws ec2 describe-key-pairs)도callguard-key다. 원문 — 런북은~/.ssh/assist-key.pem인데 그런 파일이 없다(있는 것은callguard-key.pem·admin-keypair.pem). 09-14 에 고친 IAM 역할·S3 버킷 이름과 같은 부류다. 맞는 키를 아는 사람이 런북을 고친다 — 이름을 추측해서 적지 않는다.
5~8주차 티켓을 미리 만들었다 — 담당자는 «제안»이다 (신규, 2026-09-15)
- 27건의
assignee를 본인들이 확인해야 한다. 8주 마일스톤 로드맵과 → 10-01 09-16 부터 정성윤이 전부 수행(137) — 닫는다STATE.md「지금 막혀 있는 것」·미결 항목을 티켓으로 옮기면서 4~8주차를 한 번에 만들었는데, 담당자는 기획서 7.1절 역할표와 주 담당 디렉터리를 따라 적은 것이지 본인이 가져간 것이 아니다. §4 는 “assignee는 실제로 손대는 사람”이라고 정하고 있으므로, 착수할 때 본인이 고치는 것을 전제로 둔다. ⚠ 특히 류준 16건으로 쏠렸다 —ai/가 4~6주차 로드맵의 대부분이라 그렇게 됐지만,decisions/302로 디렉터리 잠금이 풀렸으니 나눠 가질 수 있다. 나눌지는 본인들이 정한다. - 4주차 로드맵 목표에 티켓이 하나도 없었다 — 4주차는 「nori · dense_vector · RRF · 청킹 3종 비교」인데 → 10-01 로드맵은 그대로 두고 실제 진행은 진행 기록이 정본 — 닫는다(
w8-final-docs) → 10-02 정정 — 로드맵의 4주차 과제 넷은 09-15 에 전부 쟀다(w4-chunking-compare·w4-dense-vector-index·w4-reranker·w4-rrf-hybrid, 전부 done). 어긋난 것은 주차 표기뿐이다w4-티켓 27건 중 해당하는 것이 0건이었다. 4주차에 실제로 한 일(콜 미디에이터·블랙리스트·관리자 로그인· 배포·스키마)은 전부 로드맵에 없던 일이고, 로드맵에 적힌 일에는 티켓이 없었다. 정할 것: 로드맵을 실제 진행에 맞춰 고칠지(docs/08수정), 아니면 4주차 검색 품질을 5주차로 미룰지. 지금은 티켓만 만들어 두고 주차는 로드맵 그대로 뒀다 — 미루는 판단은 팀 몫이다.
배포 확인용 프로브 — 걷어냈다 (2026-09-15 닫음)
— 09-15 지웠다. ① 그냥 지우기를 택했다 (티켓). 넣은 목적(「server 를 고쳐 머지하면 운영GET /admin/auth/test를 언제 걷어내나/openapi.json이 실제로 바뀌는가」)은 같은 날 완주해서 다 썼고, ②(상시 유지)로 가려면 «무엇을 보장하는 엔드포인트인지»를 먼저 정해야 하는데 그 답이/health와 겹친다. 이름이test인 채로 남기지 않는다는 것이 이 항목을 연 이유였다.- 배포됐다는 것을 «태그» 로 확인할 방법이 없다 — ✅ 길이 생겼다 (2026-09-19) —
ssm send-command로kubectl get deploy -o custom-columns=…image를 돌려 운영 이미지 태그를 직접 본다(릴리스 워크플로와 같은 통로라 포트를 열지 않는다). 09-19 실측:callguard-server:0.1.18·callguard-call-mediator:0.2.1. ⚠ 여전히 밖(공개 GET)에서는 안 보인다 —/openapi.json의version은 코드에 박힌0.1.0이다. 원문 — ** — 프로브를 걷어내면서 다시 열린 채로 남는다. 프로브의marker는 사람이 손으로 올리는 문자열이라 애초에 못 미더웠고(올리는 걸 잊으면 옛 값이 그대로 나간다), 그마저 없어졌다. FastAPIapp.version도0.1.0에 고정돼kustomization.yaml의newTag와 무관하다. 지금 어느 이미지가 도는지는 클러스터 안에서만 알 수 있다 (kubectl -n callguard get deploy/callguard-server -o jsonpath='{..image}'). 정할 것: 빌드 시점에 이미지 태그를 넣어(--build-arg→ 환경변수 →/health) 응답으로 알 수 있게 할지. 그러면server/core/config.py와secret.example.yaml이 같이 움직인다(런북 16-1).
w4-dashboard-live-contract 로 드러난 계약 구멍 셋 (신규, 2026-09-15)
- 카드 피드백(
POST /hub/cards/{id}/feedback)을 부를 방법이 없다 → 같은 날 장민석이 풀었다(decisions/308— 추천 카드에card_id추가, 아래 섹션 참고). → 2026-09-15 조서희가 마저 처리 —coreClient.ts의submitCardFeedback을 문자열 타입으로 정정(아래 「프론트 수정 5건」 ③과 같은 항목). → 2026-09-16 조서희가 화면에 연결 —callStore.ts의toggleAdoption이 채택 토글을 낙관적으로 먼저 바꾼 뒤card.card_id가 있으면(서버에 저장된 카드)submitCardFeedback을 best-effort로 부른다.cardId()(로컬 dedup 키)와 서버card_id는 다른 값이라 후자만 쓴다. 실패해도 채택 표시는 그대로 둔다(조용히 넘어간다). - 상담기록(통화 재생) 화면을 실제 API로 못 바꾼다 —
apps/call의 “상담기록”은 지금 카드·종결·감정분석까지 통째로 재생하는 mock 시나리오(mock/callHistory.ts) 기반인데, 실제 API(GET /hub/calls·GET /hub/calls/{id}/transcript)는 통화 목록+자막만 준다 — 카드·종결·감정분석 재조회 엔드포인트가 없다. REST 함수(fetchCallList·fetchCallTranscript)는 만들어 뒀다. → 같은 날 장민석이GET /hub/calls/{id}/record를 만들었다(아래 섹션 참고, 감정분석은 모델이 없어 빈 채로). 화면 연결은 아직. → 2026-09-15 조서희가 재설계·연결 — 코드를 보다가historyCards·historySegments등 인라인 자막 재생용 상태가TranscriptPanel·TermsPanel에 이미 있는데App.tsx의showSummary(viewMode === "history"면 무조건 요약 화면으로 이동)에 가려 실제로는 절대 렌더링되지 않는 죽은 코드였던 걸 발견했다(.claude/rules/call.md가 적어 둔 “왼쪽 자막 패널이 그 기록을 보여준다”는 설계와 실제 동작이 어긋나 있었다). 사용자 지시 (“둘 다 살리는 방향으로”)에 따라 죽이지 않고 요약 보기·자막 보기 두 화면을 오가는 토글로 되살렸다 —historyView: "record" | "transcript"(신규) 상태를 추가하고App.tsx의showSummary를phase === "wrapup" || (viewMode === "history" && historyView === "record")로 좁혔다.openHistory가 실 API 설정 시fetchCallTranscript+fetchCallRecord(신규,coreClient.ts)를 병렬로 불러historySegments·historyCards를 채운다 — 카드/판정은 실제 계약이 서로 다른 배열(recommendations[].cards[]vsclosures[])이라 mock처럼 “카드 하나에 판정 하나”가 아니다: 실 카드는 판정 없이 그대로, 판정마다 표시용 카드를 하나 따로 만든다(panelCardsFromRecord). 번역·TTS· 콜가드·악센트 힌트 재생은 실서버에 애초에 없어 항상 빈 채로 둔다(정직하게 — 지어내지 않는다).CallHistoryPanel(목록)도 실 API 분기 추가(GET /hub/calls, “다시 재생”은 mock 전용이라 뺐다). 카드 채택 토글은 상담기록 조회 중엔 숨김(채택 기록이state.callId— 실시간 통화 — 에 귀속돼 엉뚱한 통화에 붙는 걸 막는다). 확정된 요약이면 “요약 확정” 폼이 잠긴 채 열려 곧바로 재수정할 수 있다(historyConfirmedprop). 버그 하나 잡음: 대기화면의 「최근 상담기록」에서 열면shell이standby로 남아 있어 자막 보기로 전환하는 순간 대기화면이 대신 떴다 —openHistory가shell: "assist"도 같이 정하도록 고쳤다. 헤드리스 크롬 + CDP로 mock 모드 왕복(목록→요약→자막→요약→실시간 복귀) 스크린샷 확인, 콘솔 에러 없음.apps/calltsc --noEmit·vite build클린. - 관리자 “지식베이스 갭” 화면이 실제 계약과 모양이 다르다 — 화면(
KnowledgeGapTab.tsx)은지금→ 2026-09-16 조서희가 재설계·연결 — “질의 그룹핑 랭킹”에서 “module 뱃지(B/C/F) + 설명 + 열림/해제됨 필터 + 해제·다시 열기 버튼” 목록으로 다시 짰다.{call_id, query, found}(상담원이 직접 검색해 못 찾은 질의) 기준으로 묶어 세는데, 실제GET /hub/knowledge-gaps계약은{module: B|C|F, description, status: open|resolved}(더 넓은 D-4 공백 개념)라 필드가 아예 다르다 — 이름만 바꿔서 옮길 수 없다. REST 함수 (hubClient.ts의fetchKnowledgeGaps)는 만들어 뒀지만 화면엔 안 붙였다.hubClient.ts에resolveKnowledgeGap(PATCH /hub/knowledge-gaps/{gap_id})을 추가하고adminStore.ts의loadAll이 실제 목록을 받는다. mock(SEED_KNOWLEDGE_GAP_LOG,KnowledgeGapEntry)은 걷어냈다.
통화 후 초안 · 상담원 토큰에서 남은 것 (신규, 2026-09-15, 장민석)
- 운영 적용 순서 — 정성윤 님께 — 2026-09-15 확인: 운영 서버 파드에서 26 테이블, 이름이
schema.sql과 완전 일치(agent_token· 09-14 의admin_account·admin_refresh_token·closure_item포함). 두 마이그레이션 모두 한 트랜잭션이라 테이블이 있으면 파일 전체가 들어간 것이다. 컬럼 단위는 직접 보지 않았다. 원문 —db/migrations/2026-09-15-agent-token.sql(25 → 26 테이블)을 서버 이미지 태그를 올리기 전에 넣는다. 09-14 마이그레이션이 먼저 들어가 있어야 한다(파일이 확인하고 멈춘다). 안 넣으면POST /hub/blacklist-requests·/admin/agent-tokens가 500(42P01). ⚠ 09-14 마이그레이션 적용 후 출력도 아직 아무도 찍지 않았다 — 같은 SSM 세션에서 런북 19장 6번(테이블 수)으로 둘 다 확인한다.server브랜치는 이미지 태그를 일부러 안 올렸다 — 머지 = 배포라 순서가 뒤집히지 않게 - 조서희 님께 — 블랙리스트 요청 계약이 바뀌었다(
decisions/307) —POST /hub/blacklist-requests는Authorization: Bearer cga_…(상담원 토큰)이 필요하고 본문에서requested_by가 빠졌다(실어도 무시). 토큰은 관리자가POST /admin/agent-tokens {agent_id}로 발급하며 응답에서 한 번만 보인다. → 2026-09-15 조서희가 처리 — ①apps/call은 기존liveCallToken.ts(apps/platform)와 같은 패턴으로?agent_token=URL 쿼리 한 번 → sessionStorage(lib/agentToken.ts) ②apps/admin의SettingsTab.tsx에 발급·목록·폐기 화면을 새로 뒀다(원문 1회 노출 + 복사 버튼) - ◐ 2026-09-22 쓰기 둘은 걸었다(
_project/decisions/315, 코드, 운영 배포 전) —/close는 상담원 토큰 또는 서비스 토큰, 카드 피드백은 상담원 토큰을 확인하되 신원을 버린다(가드 반환값이 라우트 함수에 들어오지 않는다 — 아래 ⚠ 의 제약을 이렇게 풀었다). 상담원 토큰은 PC 에 남긴다(localStorage, PC 한 대당 한 번). 남은 것은 읽기 경로(수동 검색·통화 목록·전사 조회). 원문 — 상담원 토큰을 어디까지 걸지 — 지금 가드가 달린 곳은 블랙리스트 요청 하나다. 카드 피드백·수동 검색·통화 목록·전사 조회 등은 인증이 없다. → 10-01315배포됨(QA 2회차 Q-41·Q-50 확인) — 닫는다 모두 걸면 콜 미디에이터(services/call-mediator)가 부르는 허브 API 와 겹치는 것부터 갈라야 한다. 토큰 만료도 없다 — 폐기로만 끊는다 ⚠ 카드 피드백(POST /hub/cards/{id}/feedback)은 걸면 안 된다 — 상담원 ID 를 일부러 받지 않는 API 다(부록 A-1, 상담원 단위 집계 금지). 토큰을 달면 요청마다 상담원이 식별돼 그 설계를 뒷문으로 무너뜨린다 - §7.3 정본은 「응답 전부 문자열」 로 고쳤다 — 조서희 님
contract.ts가 남았다 (2026-09-15) —_project/plan.md7.3 절 머리에 규칙을 올리고 예시를 실제 응답으로 바꿨다.프론트→ 2026-09-16 조서희 확인: 오판이었다, 고칠 것 없음.apps/call/src/types/contract.ts는 아직is_final: boolean·utterance_end_ms: number다.contract.ts의 이 필드들은 와이어 그대로가 아니라 파싱 이후 내부 표현이다 — 문자열 경계는lib/ws/realCallMediatorClient.ts의readBoolean/readNumber와lib/api/coreClient.ts의*Wire타입 +toBool/toNum이 이미 따로 맡고 있다. UI·mock은 전부 파싱 후 네이티브 타입을 전제로 짜여 있어, 여기를string으로 바꾸면 계약을 맞추는 게 아니라 멀쩡한 경계를 무너뜨린다.contract.ts에 설명 주석만 추가했다. 공개 사이트docs/077.3 은 v2 기록이라 경고만 달았다 - PR #86 머지 순서 —
tag-check가 실패한 채 머지 가능으로 뜬다 (2026-09-15) — 필수 검사가 아니라서다. 운영 DB 에agent_token마이그레이션 →newTag올리기 → 머지 순서를 지킨다. 태그 없이 먼저 머지되면release.yml이 «코드 변경 + 태그 그대로» 로 실패해 배포되지 않는다(깨지진 않지만 릴리스가 빨갛다). 로컬origin은 옛 주소(solidbob02/…)라 바꿔야 한다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
tag-check가 09-15 에 main 룰셋 필수 검사가 됐다(decisions/114) — 실패한 채로는 머지 버튼이 잠긴다
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- 통화 후 초안은 규칙 발췌다 — 류준 님께(
decisions/306) —POST /hub/calls/{id}/close가 501 대신 발췌 초안을 준다(유형은 null). → 10-01 10-01 위반 발화를 발췌에서 뺐다(server 0.1.44) — 닫는다 w7-postcall-spoke의 «501 이 사라진다» 조건은 이것으로 먼저 채워졌지만 LLM 요약·D-2 분류·품질 측정은 그대로 류준 님 몫이다. LLM 이 들어오면 규칙 어댑터를 폴백으로 남길지 함께 정한다. 초안 저장은 w7-postcall-persistence - 과잉 마스킹 관찰 — 「주민센터로 가시면」 이
*********로 가려졌다(09-15 로컬 E2E, 기존 동작). → 2026-09-17 류준 해소: P7 규칙이 어미 「~시면」 · 조사 「~센터로」 를 주소로 보지 않는다(w5-c5-masking-gaps) C-5 는 재현율 우선이라 방향은 맞지만 통화 후 요약·자막 가독성을 깎는다. 어느 패턴(P6 인명 폴백 추정 — 미확인)이 잡았는지 먼저 본다. 과잉 마스킹률은 «측정·기록» 항목이다 - 관리자 가드가 «헤더 없음» 에도 500 이다 — 운영에서 확인 (2026-09-15) — ✅ 고쳐졌다 — 2026-09-19 운영 실측: 헤더 없는
GET /admin/auth/me·/admin/agent-tokens·/hub/blacklist-entries가 전부 401(500 아님).0.1.9의 「인프라 전에 가드가 먼저」가 운영에 반영된 것이다. 원문 — ** —0.1.8배포 뒤GET /admin/agent-tokens·GET /hub/blacklist-requests·/admin/auth/me가 로그인 없이 401 이 아니라 500.require_admin이Authorization을 보기 전에get_current_admin_use_case→ Redis 프로바이더를 먼저 풀어, Redis 가 없으면RuntimeError가 난다. 운영 Redis(w4-admin-auth-runtime, 정성윤 님)가 붙으면 증상은 사라지지만 헤더가 없으면 인프라를 타기 전에 401 이 맞다 — 가드에서 헤더 검사를 의존성 해석보다 앞에 두는 수정은server/몫(장민석). 이 상태로는 운영에서 상담원 토큰을 발급할 수 없다 - 조서희 님께 —
frontend병합분 대조에서 나온 프론트 수정 5건 (2026-09-15, 장민석) —apps/는 전담 영역이라 서버 쪽만 고치고 여기 모은다. 서버 쪽은 같은 날 고쳤다: 관리자·상담원 가드가 헤더 없으면 401 · 추천 카드에card_id(decisions/308). ① 막힘 — 블랙리스트 요청(apps/call/src/lib/api/coreClient.tscreateBlacklistRequest): 헤더 없이 본문requested_by를 보낸다 → 운영0.1.8에서 늘 401.Authorization: Bearer cga_…(관리자가/admin/agent-tokens로 발급) 를 붙이고requested_by를 뺀다. 토큰을 어디에 두고 누가 넣을지는 화면이 정한다(decisions/307) ② 만료 상한 — 관리자 설정 최대 24개월(SettingsTab.tsx) × 30일을 보내는데 서버 상한은 365일(decisions/205⑤) → 13개월 이상 승인은 422. 프론트 상한을 12로 권함 ③ 카드 피드백 — 추천 카드 응답에card_id(문자열, DB 없으면 null)가 생겼다.submitCardFeedback은 응답feedback_id·card_id를 숫자로 기대하는데 문자열이다 ④ 해제 사유가"관리자 해제"고정(AdminPanel.tsx) — 동작은 하지만 왜 풀었는지가 남지 않는다 ⑤fetchCallList주석 「customer_id늘 null」 은 낡았다 — 발신 번호가 넘어온 통화는 채워진다 ✅ 맞는 것: 관리자hubClient.ts경로·필드 전부 · 통화 목록·자막·수동 검색 · WSclosure(procedure·complete/incomplete)·call_guard(영어 4종)·recommendation_pending파서.apps/calltsc --noEmit통과 → 2026-09-15 조서희가 ①~④ 처리 — ① 토큰 인증으로 교체(위 항목 참고) ②RequestsTab.tsx·EntriesTab.tsx·SettingsTab.tsx상한 24→12개월 ③card_id/feedback_id문자열로 정정(coreClient.ts·types/contract.ts·realCallMediatorClient.ts) ④EntriesTab.tsx에 사유 입력창 추가,AdminPanel.tsx가 하드코딩 대신 실제 사유를 넘긴다(연장도 같이). ⑤는 아직 안 고쳤다 — 남겨 둔다.apps/call·apps/admin둘 다tsc --noEmit·vite build클린 - 조서희 님께 — 상담기록 재생·블랙리스트 연장 API 가 생겼다 (2026-09-15, 장민석) — 조서희 님 쪽 보고 「끝까지 못 한 것」 3·4번의 서버 몫이다.
③
GET /hub/calls/{call_id}/record— 한 통화의 요약 초안·후속조치·추천(카드card_id포함)·필요서류 판정(서류별)을 한 번에. 전사는 기존…/transcript. 감정분석은 저장되지 않아 없다(모델 없음) — 재생 화면의 그 칸은 비워 둔다.0.1.9전 통화는 추천이 저장되지 않아recommendations: []④POST /hub/blacklist-entries/{id}/expiry {expires_in_days, reason}+GET …/expiry-changes— 연장·단축 모두 «지금부터 N일 뒤»(1~365), 사유 필수.decisions/205「연장은 새 요청으로만」 을 철회했다(decisions/309). 관리자 화면extendEntry(개월 × 30, 로컬)를 이 API 로 바꾸고 사유 입력을 받는다 ✅ 2026-09-15 운영 반영(서버0.1.9, 운영 DB 27 테이블 확인) — 붙여도 된다 → 2026-09-15 조서희가 ④ 처리 —adminStore.ts의extendEntry를 로컬 날짜계산 mock에서POST .../expiry(사유 필수) 실호출로 바꿨다.GET …/expiry-changes(이력 조회 화면)는 아직 안 만들었다 — 요청받으면 착수. ③(상담기록 재생 화면)도 2026-09-15 나중에 처리 — 위 “w4-dashboard-live-contract로 드러난 계약 구멍 셋” 섹션에 처리 내역을 적었다(요약 보기·자막 보기 토글로 재설계). - 블랙리스트 연장을 되풀이하면 사실상 영구 표시가 된다 (2026-09-15,
decisions/309) → 같은 날 누적 상한 «승인일 + 365일» 로 막았다(사용자 선택, 넘으면 422). 이력 사유 보존 기간은 아직 안 정했다. 원문 — — 365일 상한은 변경 1회에만 걸린다. 이력으로 드러날 뿐 막지 않는다. 정할 것: 등록 1건의 누적 상한(예: 승인일로부터 N일)을 둘지. 이력 테이블의 사유 보존 기간도 함께 - 조서희 님께 — 요약 확정 API · 연장 누적 상한 (2026-09-15, 장민석) — ①
POST /hub/calls/{id}/summary-confirmation {summary_text, inquiry_type?, follow_up_actions[]}(상담원 토큰 필수) — 통화 후 화면에서 초안을 고쳐 확정한다. 확정은 한 번(409).GET /hub/calls/{id}/record의summary_confirmed가"true"가 된다(decisions/310) ② 연장·단축은 승인일 + 365일 을 넘으면 422 — 응답detail에 언제까지 가능한지가 있다. ③ 콜 미디에이터가recommendation_pending·call_guard·closure를 이제 실제로 보낸다(0.1.4배포 뒤) ④POST /hub/calls/{id}/summary-revision {summary_text, reason, …}+GET …/summary-revisions(상담원 토큰) — 확정된 요약을 사유와 함께 고친다. 확정 전 409(decisions/311) ⑤ 관리자POST /hub/blacklist-retention/purge— 끝난 뒤 180일 지난 문장을 비운다(decisions/312). 관리자 화면에 버튼이 필요하다 ✅ 2026-09-15 운영 반영(서버0.1.10· 콜 미디에이터0.1.4, 운영 DB 29 테이블 확인) — 붙여도 된다. 콜 미디에이터가 알림 3종을 이제 실제로 보낸다 → 2026-09-15 조서희가 ①·④·⑤ 처리 — ①RealCallMediatorClient.wrapUp()이 그동안 “계약 없음”으로 늘 실패하던 것을 고쳐POST /hub/calls/{id}/close(초안 생성)를 실제로 부르게 했고,CallSummaryPanel에 요약·유형·후속조치 편집 + 확정 버튼(SummaryConfirmationForm)을 추가했다. ④ 같은 폼에 “재수정” 버튼을 더해 확정 후에도 사유와 함께 고칠 수 있게 했다(취소 가능, 재수정 시각 표시) —GET …/summary-revisions(이력 목록)는 화면에서 안 씀, 필요하면 추가. ⑤SettingsTab.tsx에 “지금 정리하기” 버튼 추가(purgeBlacklistRetention, 확인 다이얼로그 있음,apps/admin의RetentionPurgeCard). ②·③은 프론트 몫 아님(②는 서버 규칙, ③은 콜 미디에이터).apps/call·apps/admintsc --noEmit·vite build클린 - 조서희 님께 — J-5 베테랑 기준 설정이 서버에 생겼다 (2026-09-15, 장민석) — 설정 탭 「근속 연차」 를
GET /hub/routing-settings(현재값,saved:"false"면 기본 3년) ·PUT /hub/routing-settings {veteran_years: 0.5~40}에 붙이면 된다(관리자 로그인). 화면의 «서버에 연결 안 됨» 문구는 운영 반영 뒤 걷어도 된다. 배정 판정 자체(POST /hub/routing-decisions)는 교환기가 부르는 것이라 화면이 부를 일은 없다.fell_back집계 화면이 필요하면 조회 API 를 따로 만든다 → 2026-09-15 조서희가 처리 —hubClient.ts에fetchRoutingSetting·saveRoutingSetting추가,adminStore.ts의loadAll이 로그인 직후 현재값을 받고setVeteranThresholdYears가PUT으로 저장(저장 성공 응답으로만 상태 갱신 — 실패해도 화면 값이 서버와 어긋나지 않는다).SettingsTab.tsx입력 상한을 서버 값(0.5~40)에 맞추고 «연결 안 됨» 문구 걷어냄. 배정 판정을 실제로 부르는 쪽(아래 항목)은 그대로 미결. - J-5 배정 판정을 부르는 곳이 없다 (2026-09-15,
decisions/313) — ◐ 2026-09-21 정했다 — 구현은 남았다(_project/decisions/126): 콜 미디에이터가 통화 시작 직후 부르고, 통화 종료는 화면 버튼 그대로다. 열쇠 꽂기 뒤에 구현한다(w7-j5-routing-caller). → 2026-09-22 시점 자체의 충돌을 확인 — 126이 313이 기각한 「통화 시작 때 판정, 기록만」과 같은 시점인데 313의 기각 사유(후보 상담사 불명)를 재검토 안 함.decisions/407로 126을 정본 확정하고 313의 「시점」 항목을 철회했다. 화면 문구(BlacklistRequestButton.tsx·EntriesTab.tsx)의 “완성형 인입 전 배정” 주장도 같이 고쳤다 — 구현(콜 미디에이터 호출)은 여전히w7-j5-routing-caller몫으로 남아 있다. 원문 — 교환기가 없고 콜 미디에이터도 부르지 않는다. 판정 API 는 인증도 없다(통화 시작과 같은 한계). → ✅ 2026-09-22 끝났다 — 콜 미디에이터가 통화 시작 직후 부르고(w7-j5-routing-caller), 운영에서 블랙리스트 고객 →demo-A03(근속 7년) 배정까지 확인(routing_log31,w6-routing-candidates-prod). 정할 것: 데모에서 콜 미디에이터/dev테스트 콜이 통화 시작 직후 부르게 할지 ·routing_log.fell_back집계를 관리자 현황판에 올릴지 2026-09-15 정성윤 확인 — 콜 미디에이터가 서버로 보내는 것은POST /hub/calls하나뿐이다(adapters/hub_http.ts:33). 배정 판정 호출은 코드에 없다. 프론트는 관여하지 않는다(화면이 부르는 API 가 아니다). 정할 것: ① 데모에서/dev테스트 콜이 통화 시작 직후 이어서 부를지, 아니면 「엔드포인트는 있다」로 남길지 ② 부르기로 하면 인증도 같이 — 지금 토큰 없이 열려 있고, 통화 시작 API 와 묶어서 보는 게 맞다. 정성윤(콜 미디에이터 코드) - 블랙리스트 보존 정리를 누가 언제 부르나 (2026-09-15,
decisions/312) — 관리자 API 만 있고 주기 실행이 없다. 부르지 않으면 비워지지 않는다. → 닫힘 (2026-09-15) —decisions/113— 관리자 화면 버튼으로 사람이 부른다. CronJob 을 만들지 않는다. 그 라우터가require_admin이라 CronJob 이 들 장기 토큰이 설계에 없다. 정할 것: 관리자가 주기적으로 누를지 · CronJob 으로 부를지(운영 인스턴스 02시 자동 중지와 겹치지 않게). 대상 밖으로 남긴 것 — 승인 요청 사유·자막, 해제 사유·승인 메모, 요약 재수정 사유 - 저장한 통화 후 초안을 읽는 경로가 없다 (2026-09-15) — ✅ 2026-09-23 확인 —
GET /hub/calls/{id}응답(CallRecordResponse)에summary_text·summary_confirmed가 들어 있다. 운영 실물에서도 34건 중 5건에 요약이 저장돼 있다. 원문 —POST /hub/calls/{id}/close가 이제call.summary_text·follow_up_action(draft)에 남기지만GET /hub/calls는inquiry_type·summary_confirmed만 준다. 상담원이 초안을 확정하는 API(summary_confirmed_at채우기)도 없다. 정할 것: 상담기록 화면이 목록에서 요약을 보여줄지(목록 응답에summary_text추가) 상세 조회를 따로 둘지 — 조서희 님 화면 흐름에 달렸다 ERD.png를 다시 그리지 못했다 — ✅ 2026-09-23 재생성 시도 —schema.sql·erd.dot은 차이 0(29 테이블),ERD.png만 이 머신에 graphviz 가 없어 못 만든다. 그림이 필요하면 graphviz 가 있는 곳에서python db/generate_schema_docs.py한 번이면 된다 — 저장소 쪽에 할 일은 없다. 원문 — graphviz 없는 머신.schema.sql·erd.dot은agent_token까지 갱신됐다.brew install graphviz뒤db/generate_schema_docs.py- 서버 이미지에 모델을 어떻게 실을지 — NER·임베딩·리랭커가 코드로는 있는데 운영에 못 켠다 (신규, 2026-09-15, 류준) —
PII_NER_MODEL_DIR·RETRIEVAL_EMBED_MODEL_DIR·RETRIEVAL_RERANK_MODEL_DIR을 넣어도 지금 서버 이미지에 torch·transformers·가중치가 없어 조용히 규칙·BM25 로 내려간다(/healthspokes로 구분). 가중치는 NER 0.45GB · KoE5 2.2GB · 리랭커 2.2GB. 런북 13-1 은 «이미지 ~12GB» 를 이미 예상했다. 정할 것: ① 이미지에 굽기 ②hf-cachePVC 로 붙이기(런북 12-3 이 이미 만든다) ③ 운영 ES 에 벡터 적재를 어디서 돌릴지(서버 파드는 torch 가 없어 BM25 만 적재한다 — 런북 15-1). ⚠ 켜기 전에 C-5 는 절대 규칙이다 — 로컬에서 규칙만으로는 골든셋 누락 4건, NER 을 붙이면 0건이다(w5-ner-p6-p7). 운영이 지금 그 4건을 그대로 흘리고 있다. 정성윤 님과 함께 정한다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
decisions/121— 서버 이미지에 싣지 않는다. 모델은 전용 GPU EC2 로 간다 → w6-gpu-model-instance
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
.env.example에 새 키 5개를 사람이 넣어야 한다 (신규, 2026-09-15, 류준) — ✅ 2026-09-21 넣었다 —PII_NER_MODEL_DIR·RETRIEVAL_EMBED_MODEL_DIR·RETRIEVAL_RERANK_MODEL_DIR·OLLAMA_URL·GENERATION_MODEL. 이름만, 값은 비웠다(SEC-2).server/core/config.py가 읽는 26개 키를.env.example과 전수 대조해 빠진 키 0 을 확인했다. 원문 —server/core/config.py가PII_NER_MODEL_DIR·RETRIEVAL_EMBED_MODEL_DIR·RETRIEVAL_RERANK_MODEL_DIR·OLLAMA_URL·GENERATION_MODEL을 읽는데.env.example은 보호 훅이 편집을 막아 넣지 못했다(server/CLAUDE.md§6 — 사람이 채운다). 전부 선택이고 비우면 지금 운영과 같다. 설명은infra/k8s/base/secret.example.yaml「모델 키 4종」에 적었다- B-4 생성·D-1 요약을 운영에 켤지 — kanana 모델 등록과 VRAM 표 (신규, 2026-09-15, 류준) —
decisions/207로 B-4 기본 모델을 kanana 로 바꿨지만 런북 14-2 는 EXAONE 을 받는다. 켜려면 ollama 파드에 kanana GGUF 를ollama create로 등록하고(207 「운영 반영」)GENERATION_MODEL을 넣는다. 정할 것: 켤지 자체 — 켜면 추천 한 번에 모델 호출이 붙어 로컬 p95 0.9~1.0초가 더해지고 4.3절 예산(트리거→카드 p95 ≤1,000ms)을 넘는다. 런북 11장 VRAM 합계도 kanana(≈1.5GB)로 갱신해야 한다 → 10-01 안 켠다(124) — 닫는다 - → 2026-09-21 케이스 24건·분포 측정(
w5-b6-no-answer-threshold) — 문턱 값은 팀 결정 · B-6 「관련 문서 없음」을 실제로 낼 규칙이 없다 (신규, 2026-09-15, 류준) — 검색이 점수 문턱 없이 항상 5건을 돌려줘 생성 측정 96문항에서 「관련 문서 없음」이 한 번도 안 나왔다. 지식베이스에 정답이 없는 문의(예: 여권 재발급 — 위 09-11 항목)에도 엉뚱한 조항 카드가 뜬다. 정할 것: 리랭커 점수 문턱을 둘지(골든셋에 「정답 없음」 케이스를 먼저 넣어야 문턱을 잴 수 있다 — 지금은 0건). 절대 원칙 9 대로 판정은 문턱(규칙)이 한다 → 10-01 수동 검색만 문턱(135), 자동 추천은 보류(215) — 알려진 한계(138) - C-5 규칙 폴백이 문맥 뒤 긴 후보를 버린다 — 오류 곡선 10% 에서 1건 (신규, 2026-09-15, 류준) → 2026-09-17 해소: 문맥 뒤 5~8자 덩어리는 동사 어미가 아니면 어절째 가린다(「애매하면 가린다」 쪽을 골랐다) —
server/apps/masking/domain/services/name_detector.py가 「이름 X」 뒤 후보에서 조사를 못 벗기면(5글자 이상) 가리지 않고 버린다. 주입기가 만든 가짜 음절(박서연이곴)에서 NER 도 놓쳐 규칙+NER 누락 1건(GS-037)이 남았다(w5-masking-recall-curve). 실제 STT 가 내기 어려운 음절이지만 절대 규칙 기준으로는 누락이다. 정할 것: 문맥이 있으면 긴 후보를 어절째 가릴지(과잉 마스킹이 늘어난다 — 「이름 변경하려면」 같은 말) · 주입기가 실재 음절만 만들게 할지(곡선이 달라진다). 장민석 님 규칙이라 함께 본다 - → 2026-09-22 닫음 —
decisions/211채택(기획서 C-4 = 「근거 없는 안전 보장 — 의학적 안심 발언 등」 탐지 갈래, 대체 표현은 C-1~C-4 공통 출력. 코드·골든셋·점수 무변경. 지식베이스 표지만 09-30 뒤) · 2026-09-21 초안_project/decisions/211(제안·팀 합의 전) — 골든셋의 C-4 라벨이 기획서 C-4 와 뜻이 다르다 (신규, 2026-09-15, 류준) — 기획서 2.4절의 C-4 는 「권장 대체 표현 제시」(기능)인데 골든셋 GS-312·GS-318 은 「의학적 안심 발언」(위반 갈래) 에 C-4 를 붙였다. 컴플라이언스 규칙 v1 은 채점 기준(골든셋)을 따라rule_code="C-4"로 낸다.compliance_rule카탈로그(C-1~C-4)에 들어갈 라벨이 둘 중 무엇인지 정할 것 — 기획서를 고칠지(결정 기록) 골든셋 라벨을 C-1(확정적 표현)로 옮길지 - STT 일 캡 600초면 하루 약 4통화다 — 시연 리허설에 걸린다 (신규, 2026-09-15, 류준) —
scripts/estimate_call_cost.py추정: AI Hub 다산 대화셋 턴 수 × 다산콜DB 발화 길이로 통화 1건 STT 약 146초(발화 합이라 하한).call-mediator.yaml캡(일 600s · 월 3,600s)으로는 하루 4건 · 한 달 25건이다(w7-token-cost). 정할 것: 시연·리허설 일정에 맞춰 캡을 조정할지 — COST-1 이중 가드라 GCP 쿼터와 함께 정성윤 님이 정한다 → 10-01143절차로 — 닫는다
운영 DB 에 저장소에 없는 테이블이 하나 있다 — 오인이었다. 닫는다 (2026-09-15, 정성윤)
blacklist_entry_expiry_change 가 저장소에 없다고 적었으나 틀렸다. decisions/309(장민석, 09-15)가
정한 정식 테이블이고 db/schema.sql 에 29개 중 하나로 들어 있다. 다섯 브랜치 전부에 있다.
행이 0인 것도 정상이다 — 관리자 만료 연장·단축(POST /hub/blacklist-entries/{id}/expiry)을
아직 아무도 쓰지 않았을 뿐이다. 지우지 않는다.
왜 틀렸나 — 남겨 둘 값어치가 있다. 검색을 돌린 시점의 작업 트리가 PR #90 이전이었다.
git pull --ff-only 출력을 tail -1 로 삼켜 실패를 못 보고, 그 상태에서 「전수 검색 0건」이라고 단정했다.
브랜치를 따로 보지도 않았다(git grep <ref> 로 다섯 브랜치를 봤으면 바로 나왔다).
교훈: 「저장소에 없다」를 말하기 전에 ① 트리가 최신인지 ② 다른 브랜치는 봤는지 둘을 먼저 확인한다.
드리프트 방향이 「운영에만 있다」로 보일 때는 대개 내 트리가 낡은 것이다.
Vercel 설정이 콘솔에만 있다 (신규, 2026-09-15, 정성윤)
- 프론트 3종의 Vercel 설정을
vercel.json으로 저장소에 옮길지 — ✅ 안 옮긴다 — 2026-09-22 결정대로 Vercel 프로젝트 설정에서 직접 껐다(w6-vercel-json-branch-deploys). 09-23 확인: 저장소에vercel.json0개. ⚠ 설정이 저장소에 없으므로 프로젝트를 새로 만들면 다시 해야 한다 — 런북 18-4 에 한 줄이 남아 있다. 원문 — 지금은 Root Directory · 빌드 명령 · 환경변수 · Ignored Build Step 이 전부 콘솔에만 있고, 저장소 쪽 기록은 런북 18-4 표 하나다. 같은 날branch-protection.json·ruleset-main.json이 어긋나 있던 것과 같은 구조다 — 콘솔만 바뀌고 저장소는 모른다. 옮기면apps/<앱>/vercel.json의ignoreCommand인데apps/는 조서희 전담이라 혼자 정할 수 없다(CLAUDE.md§1 — 전담이 남는 유일한 영역). 정할 것: ① 콘솔 유지 + 런북 18-4 를 정본으로(지금) ②vercel.json으로 옮기고 런북은 가리키기만. ⚠ ② 를 고르면 Root Directory 는 여전히 콘솔에만 남는다(vercel.json 이 그 안에 있어서 읽히는 구조다). - Root Directory 셋이 실제 폴더와 맞는지 눈으로 확인 — 어긋나면 Ignored Build Step 의
git diff가 → 10-01 09-22 대조 완료(런북 18-4) — 닫는다 항상 비어 빌드가 영원히 건너뛰어진다(빨간불이 아니라 조용한 초록). 09-14apps/dashboard→apps/call개명이 있었고 위 뷰 토큰 항목에도 옛 경로가 적혀 있었다(이번에 고쳤다). 확인법은 런북 18-4. - Ignored Build Step 으로는 배포 한도를 못 막는다 —
vercel.jsongit.deploymentEnabled가 필요하다 (신규, 2026-09-22, 정성윤) — ✅ 09-22 정성윤이 파일 대신 Vercel 프로젝트 설정에서 직접 막았다(w6-vercel-json-branch-deploysdone — 설정은 저장소 밖이라 프로젝트를 새로 만들면 다시 한다). 원문 — 09-22 다시 한도에 걸렸다(api-deployments-free-per-day100 · 24시간에 147건 생성). 취소된 빌드도 배포 1건으로 센다. 줄이는 길은 Root Directory 안vercel.json에{"git":{"deploymentEnabled":{"PM":false,"ai":false,"server":false}}}를 두는 것뿐이다(main·frontend 만 남겨 147 → 76).apps/call·apps/admin·apps/platform셋에 같은 파일 —apps/가 조서희 전담이라 여기서 정한다. 정할 것: ① 조서희 님이frontend에 넣는다 ② 정성윤이 넣고 조서희 님이 확인한다. 그때까지 운영 상담원·관리자 화면은a5450d8(PR #120) 에 멈춰 있고, 해제는 09-23 13:38 KST(런북 18-4 에 명령).
합성 통화 대본 · 학습 방향에서 남은 것 (신규, 2026-09-16, 류준)
- 모델을 학습하지 않는다면 — 결정 기록과 티켓 정리 — ✅ 2026-09-18
_project/decisions/210으로 채택·정리(①②③ 완료 — 티켓 메모를 실제 막힘으로,w5-classifier-ner-benchmark는 「측정 불가」로 닫음). ④ai/apps/training/은 지우지 않았다 — 보관·이동 방향은 아직 미정. S3 경로는 여전히 정성윤 님 확인. 원문 — 류준 메모(확정 아님): “모델을 따로 학습시키지 않고, 데이터는 S3 에 올려 정확도 측정용으로만 쓸 것 같다.” 확정되면 ① 결정 기록2xx②w3-a5-translation-spike·w3-call-temperature의 「모델 학습 후 진행」 메모를 실제 막힘(AI Hub 505/71479 미신청 · 음성 골든셋 없음)으로 고침 ③ 파인튜닝 전제인w5-classifier-ner-benchmark를 「측정 불가 — 학습 안 함」으로 닫음(지우지 않는다) ④ai/apps/training/처리. S3 버킷·경로는 정성윤 님 확인 — AI Hub 재배포 금지라 비공개여야 한다 - 합성 통화(
scripts/persona_sim/· 재생기services/call-mediator/scripts/replay_persona_call.ts)를 채택할지 — 결정 기록 없음 — ✅ 2026-09-18_project/decisions/209(제안): ① 데모·파이프라인 점검 전용 ② 발표에 쓰면source: synthetic+「STT 미경유 상한」 ③say기본 + Google TTS Wavenet 파일 캐시 ④ 공개 저장소에 둔다(가짜 값, 폭언은 추가하지 않는다). 원문 — 대본 10건 초안이 있다(w5-persona-sim-scripts). 정할 것: ① 용도를 데모·파이프라인 점검으로 한정할지(권고) ② 합성 수치를 발표에 쓸지 — 쓴다면source: synthetic분리 + 「STT 미경유 상한」 명시 ③ 재생 음성을 브라우저 TTS(무료)로 할지 Google TTS 파일 캐시로 할지 ④ 대본 JSON 을 공개 저장소에 두는 것 — 가짜 값뿐이지만 폭언·성적 표현 문장이 들어 있다 - QA 페르소나가 현재 마스킹·콜 가드 규칙을 합성 대본에 돌려 찾은 것 — 장민석 님·류준 (신규, 2026-09-16) — 대본이 아니라 규칙 쪽 문제라 대본을 규칙에 맞추지 않았다(
scripts/persona_sim/README.md). ⚠ 서브에이전트가 로컬에서 돌린 결과이고 하네스 측정값이 아니다 — 수치로 옮기지 말고 재현부터 한다. → 10-01 재현 안 함 — 범위 밖(138) → 10-02 정정 — 「재현 안 함」 이 아니다. 아래 ✅ 대로 ①②③ 은 09-17 에 고쳐졌고, 10-01 밤 지금 규칙(NER 없이, 로컬 재현 — 하네스 측정 아님)으로 다시 돌려 확인했다: 보고된 과잉 4건 · 번지·호수 4건 · 「박성호요」「김도윤이고요」「응우옌 티 란」 · 「멍청한 놈」「목소리만 예뻐」「다 끝내고 싶어요」 ✅. 남은 것 넷: 「김도윤 고객님이세요」 · 「제니 레예스 입니다」(P6 누락, 규칙만 기준) · 「이따위로」 · 「술이나 한잔」(C-6 사전에 없음) ✅ 09-17 ①②③ 해소(④ 중 distress·성적 표현·모독은 같은 날 C-6 규칙에 반영) ① P7 과잉 마스킹이 정상 대조군을 깬다 —_AREA_LOCAL이 「하시면」의면,_ROAD가 「~으로」의로를 주소 표지로 본다고 보고됐다(SYN-001 「신분증으로 하시면」 외 8턴). 09-15 「주민센터로 가시면」 과잉 마스킹과 같은 뿌리로 보인다 ② P7 번지·호수가 남는다 — 「새솔로 12, 305호」·「은하로 7-3」에서 숫자 건물번호가 안 잡혀 주소가 도로명에서 끊긴다(누락 — 절대 규칙 쪽) ③ P6 문맥 없는 이름(「박성호요」·「한지영이요」) · 조사 「이고요」 · 띄어 쓴 외국인 이름(「응우옌 티 란」→「응우옌」만) 누락 ④ C-6 사전에 없는 표현 — 「멍청한 놈」·「이따위로」·「술이나 한잔」, 「목소리만 예뻐」(「만」이 패턴을 끊음), distress 「다 끝내고 싶어요」 정할 것: 합성 대본을 하네스에source: synthetic으로 올려 이 넷을 회귀 표본으로 쓸지 — ✅ 2026-09-18 결정: 올리지 않는다. 하네스는 실제·작성 골든셋만 잰다. 합성 대본의 회귀 검사는scripts/persona_sim/e2e_check.py(왕복 검사,source: synthetic보고서)가 맡는다
09-17 운영 점검·로컬 E2E 에서 넘긴 것 — 팀원별 (신규, 2026-09-17, 류준)
페르소나 4명 점검 결과. 류준 몫은 w5-e2e-findings-ai에서 고쳤다. ⚠ E2E 는 로컬(규칙·BM25, NER·임베딩 없음 — 운영과 같은 구성) 결과다.
- 조서희·정성윤 —
call.solidbob.cloud번들에 콜 미디에이터·서버 주소 3개가 비어 있다 — ✅ 2026-09-23 운영 번들 확인 —server.solidbob.cloud2회 ·call-mediator/ws1회가 들어 있다. 홍보 페이지 번들에도 콜 미디에이터 주소가 있다. 원문 — (VITE_CALL_MEDIATOR_WS_URL·VITE_CORE_API_URL·VITE_CALL_MEDIATOR_DEMO_BASE_URL) — 기본이 mock 이고?call_mediator=로 붙어도 REST 기능은 에러. 위 「공개 데모를 라이브로 바꿀지」 결정과 같은 건이다. 🚫 과금 토큰은 넣지 않는다 - 장민석 — 이름·번지 규칙 누락(SEC-1) → 같은 날 류준이 고쳤다(
decisions/302—server/누구나). 장민석 님 검토 부탁 — — 「김도윤이고요」·「김도윤 고객님」·「제니 레예스」·「은하로 7-3」이 자막·DB 에 원문으로 남았다. NER 을 켜면 이름·「7-3」은 가려지지만 「햇살로 45,」·「별빛로 88, 5층」 번지는 NER 로도 남는다(decisions/208측정) — 규칙 보강 필요 - 장민석 — 통화 종료 상태를 쓰는 경로가 없다 — ✅ 2026-09-20 고쳤다(
decisions/302, server0.1.19).POST /hub/calls/{id}/close가 요약 초안을 쓰는 같은 UPDATE·같은 트랜잭션에서status='closed'·ended_at을 채운다.COALESCE라 초안을 다시 만들려고 여러 번 닫아도 끝난 시각은 처음 닫은 때로 남는다. 값closed는 새로 정한 것이 아니라 integration 테스트 7곳이 이미 쓰던 값이다 —call.status에 CHECK 가 없고 프론트 API 타입도 이 문자열에 기대지 않는다(전수 확인). ⚠ 조서희 님 참고: 통화 목록 API 의status가 이제closed로도 온다. 원문 — — 네 통화 모두in_progress·ended_atnull.POST /hub/calls/{id}/close는 요약 초안만 만든다. 누가(대시보드 종료 버튼 · 콜 미디에이터 채널 종료) 언제 닫을지 정할 것 - 장민석 —
compliance_flag가 0행 — ✅ 배선됐다 — 09-18 에 서버가 검사 결과를 DB 에 저장하도록 출력 포트·PostgreSQL 어댑터·합성 루트를 신설했다(server 0.1.18, 09-19 운영 확인). 「설계인지」에 대한 답: 설계가 아니라 빠져 있던 것이었다. ⚠ 운영compliance_flag는 아직 0행 — 그 경로를 타는 통화를 운영에서 안 걸어 봤기 때문이다(아래 09-19 항목). 원문 — ** —/hub/compliance-checks를 직접 불러 C-2 가 잡혀도 저장이 안 됐다(설계인지 확인) - 콜 미디에이터(누구나 · 주 담당 정성윤) — 컴플라이언스 미배선 — ✅ 배선됐다 — 콜 미디에이터
0.2.1이 상담원 확정 발화마다POST /hub/compliance-checks를 부른다(실패는 warn·통화 유지). 09-19 운영에callguard-call-mediator:0.2.1이 떠 있는 것을 확인했다. ⚠ 방송은 아직 꺼져 있다(announceCompliance기본 false) — 대시보드 파서가compliance를 안 받는다. 그 몫은 아래 조서희 님 항목이다. 원문 — ** —hub_http.ts가/hub/compliance-checks를 부르지 않고 방송 타입에도 없다. 콜 가드 배선을 본떠 상담원 확정 발화마다 호출 →compliance방송. 조서희 님ComplianceWarningBanner계약 맞추기 - 콜 미디에이터(누구나) — 필요서류 판정이 추천 1순위 한 번에 기댄다 — ✅ 고쳤다 — 09-18 에 카드 순서대로 「규칙 있는 첫 조항」까지 훑도록 바꿨다(상한 5, 422 는 건너뜀 — 절차를 지어내지 않는다. 콜 미디에이터
0.2.1, 09-19 운영 확인). ⚠ 엉뚱한 절차 자체가 사라진 것은 아니다 — 그건 검색 순위 문제라decisions/208(운영 임베딩) 몫이다. 원문 — ** — 오카드 한 번이면 엉뚱한 절차가incomplete로 계속 방송된다. 같은 절차가 두 번 이상 1순위일 때만 올리는 등. POLICY 가 1순위가 되던 경우는 검색에서 뺐다 - 정성윤 — 자동 중지가 설정돼 있지 않다 — ✅ 2026-09-19 결정: 하지 않는다(
_project/decisions/116). 런북의 «24/7 이면 예산 초과» 경고는 g4dn(GPU) 기준이고 운영은 t3.large 라 급함이 내려간다. EIP·AMI 와 한 묶음으로 함께 안 한다. 원문 — AL2023 에crontab이 없어 런북 21-1 명령이 안 먹는다(추정). 3일 연속 가동. EIP 부터 붙이고 EventBridge 스케줄 등으로 - 정성윤 — EC2 t3.large 결정 기록 · Name 태그 · AMI 0개 · EBS 30GB 비암호화 ·
aiDNS 자리표시자 · 안 붙은 SGlaunch-wizard-2(22 전체 개방) — ✅ 2026-09-19 결정: 여섯 전부 하지 않는다(_project/decisions/116— 티켓도 만들지 않는다). t3.large 라는 사실 자체는 그 결정 기록이 적었다(런북 0·7-2 의 g4dn 전제가 운영과 다르다는 것,decisions/208측정이 M5 맥 값이라 t3.large 재측정이 남는다는 것 포함). 받아들인 위험: AMI 가 없고 terraform 재현 경로도 없어 인스턴스를 잃으면 노드 재구축 반나절 이상(RDS·S3 는 별개라 데이터는 남는다).launch-wizard-2는 어느 인스턴스에도 안 붙어 있어 실제 노출 0 — 「열린 SSH」로 인용하지 않는다. 되살리려면 런북 해당 절만 따르면 된다(③ AMI 하나가 가장 싸다) - 정성윤·류준 —
decisions/208합의 — ✅ 2026-09-21 결정: 지금 노드에는 올리지 않는다 — 모델은 전용 GPU EC2 를 따로 세워 거기에 올린다(_project/decisions/121).208의 「NER·임베딩을 t3.large 에 먼저」는 채택하지 않고 「리랭커는 GPU 뒤로」만 같은 방향이다. ⚠ 함께 열린 질문 다섯(ai/가 라이브러리에서 서비스가 된다 · 네트워크 홉이 4.3절 예산에 더해진다 · GPU 는 자동 중지가 다시 필요하다 · GPU 가 꺼졌을 때 규칙·BM25 로 내려가야 한다 · 6주차 기준선 구성)은 121 에 적었다. 원문 — torch CPU 휠을 서버 이미지에 넣을지 · 모델 파일 위치 · t3.large 재측정 - 팀 — 운영 합성 통화 한 건(SYN-010)으로 콜 미디에이터→서버 경로 확인할지 — ✅ 2026-09-22 류준이 흘렸다 —
syn-prod-syn-010-20260922·syn-prod-syn-008-20260922. 경로는 확인됐고 통화는 시연용으로 남겼다(decisions/130과 같은 이유). 원문 — 운영 DB 에syn-통화 행이 남는다
C-5 규칙 보강에서 남은 것 (신규, 2026-09-17, 류준 — 주 담당 장민석)
w5-c5-masking-gaps에서 이름·번지 누락과 과잉 마스킹을 함께 고쳤다. 남은 것:
- 장민석 님 검토 — 주 담당 영역을 류준이 고쳤다. 특히
name_detector.py의 네 갈래(문맥·자기소개·호칭·이름만 답한 발화)와_NOT_NAMES목록이 실제 발화에서 걸린 것만 넣었는지- → 닫음 (2026-09-22 장민석):
w5-server-change-review(0.1.14→0.1.24) 범위(0.1.15) — 봤고 그대로 둔다
- → 닫음 (2026-09-22 장민석):
- 호칭·문맥이 전혀 없는 이름은 여전히 못 잡는다(
"김민준 그 사람이") — 규칙의 한계. NER 운영(decisions/208)이 풀 몫이다. 테스트가 한계를 고정해 두었다 → 10-01 한계 문구로 발표(138) — 닫는다 - 실제 발화의 남은 P7 과잉은 1건짜리들이다(「경기 침체로」·「3층 일자리」·「서울시 누수감면」 등) — 누락 0건 > 과잉 억제라 여기서 멈췄다. 자막 가독성 문제가 보고되면 같은 방식(실제 문장을 테스트로 고정 → 규칙)으로 줄인다 → 10-01 그대로 둔다(누락 0 > 과잉 억제) — 닫는다
- 이 측정은 라벨이 없다 — AI Hub 발화에서 「가려진 발화 수」 가 459 → 44 로 줄었다는 것은 과잉이 줄었다는 근거이지 누락이 없다는 근거가 아니다. 누락은 골든셋·합성 대본(라벨 있음)으로만 말한다 → 10-01 인용하지 않는다 — 닫는다
프론트 왕복 테스트로 드러난 것 셋 (신규, 2026-09-17, 정성윤)
- 홍보 페이지·상담원 박스가 통화 ID 를 각자 만든다 — 조서희 님과 정할 것 — ✅ 2026-09-22 진입 경로(UI)까지 마무리됐다(
a9e9642,LiveCallModal.tsx의 “상담원 링크 복사” 버튼 —w6-shared-call-entry, 2026-09-23 확인). ◐ 2026-09-21 로직은 고쳤다 — 진입 경로(UI)는 남았다. 두 화면이?call_id=를 읽어 같은 통화로 붙는다(apps/call·apps/platform의lib/sharedCallId.ts— 비밀이 아니라 URL 에서만 읽고 저장하지 않는다. 없으면 예전처럼 각자 만든다). 상담원 화면은 그 ID 로 그 통화만 구독한다(WS /ws?call_id=— 콜 미디에이터가 원래 지원하던 서버 쪽 필터를 안 쓰고 있었다). 타입 체크·두 앱 빌드 통과, 순수 함수는 node 로 11건 확인. 화면·디자인은 건드리지 않았다. 남은 것: 홍보 페이지의 「상담원에게 전화 걸기」가 상담원 화면을 같은call_id로 열어 주는 것 — 버튼 동작이 바뀌는 일이라 하지 않았다. 지금은 두 주소에 같은?call_id=test-…를 붙여 직접 연다. 원문 —apps/platform/src/lib/useLiveCallSession.ts:118(test-web-platform-*) ·apps/call/src/lib/useAgentCallSession.ts:128(test-web-agent-*). 콜 미디에이터는 두 통화로 갈라/hub/calls를 두 번 부르고, 상담원 화면은call_id없이 구독해 둘 다 받으며,callStore.applyTranscript가call_id대조 없이segment_id만으로 덮어쓴다(콜 미디에이터는 통화마다 1번부터 센다). 실제 프론트 코드로 재현: 고객 1번 줄이 상담원 1번 줄에 덮여 사라지고callId가 메시지마다 바뀐다. 같은 ID 를 넘기면 순서대로 남는다(09-17 두 번째 기록). 콜 미디에이터·서버 계약은 손댈 것 없음. 정할 것: 홍보 페이지가 만든 ID 를 상담원 화면에 넘겨 같은 값으로 붙게 하고(새 탭 + 쿼리), 상담원 화면은 그 ID 로 구독하거나 스토어에서 다른 ID 를 버린다 — 티켓 미작성 - 못 읽는 콜 미디에이터 메시지 하나가 「연결 끊김」 표시를 만든다 (조서희 님) — ✅ 2026-09-21 고쳤다 —
callStore.setError가connected:false를 같이 세우던 것을 걷었다. 연결 상태는setStatus만 바꾼다(진짜 끊김은 소켓 close 가 알린다 —realCallMediatorClient.ts). 오류 문구가 뜨는 자리·모양은 그대로다. 원문 —callStore.setError가connected:false를 같이 세운다. 소켓은 열려 있고 이후 자막도 계속 들어오는데 화면은 끊김으로 보인다. 파서 실패와 연결 상태를 분리할지 정한다 GS-204는 측정이 아니라 채점 기준 문제 — 결정 기록 필요 (류준 님과) — ✅ 2026-09-21 결정: 라벨을 고치지 않고 출제 규약을 적는다(_project/decisions/123). 「시민이 묻는 말이면 지침(TERM) 쪽이 정답, 같은 내용의 매뉴얼 조항은 방해 문서」를golden-set/README.md에 적었다. 해당 항목은 둘이다 —GS-204(TERM-1.3↔MANUAL-3.2) ·GS-216(TERM-2.9↔MANUAL-3.4). 6주차 판정 직전에 채점 기준을 느슨하게 하지 않는다. 대신 이 2건은 「검색기가 틀렸다」가 아니라 「구분 단서가 없는 기준으로 채점됐다」를 한계로 함께 적는다.GS-205(nori 토큰 확인)는 그대로 남는다. 원문 — 지침 1.3 과 매뉴얼 3.2 가 같은 규칙을 적은 쌍둥이인데 골든셋이 1.3 만 정답·3.2 는 방해 문서로 적었다. 사유(「시민 문의라 지침 쪽」)는 항목 메모에만 있고 README 규약에 없다(GS-216 도 같다). 선택지: ① 3.2 를 정답 목록에 추가(hit_at_k는 any-of) ② 지식베이스에서 쌍둥이 조항 통합 ③ 규약을 README 에 적고 감수. 점수를 올리려고 라벨을 조용히 고치는 것이 되지 않게 결정 기록으로.GS-205는 nori_analyze로 「결정」 토큰 생존 여부 확인이 먼저(09-17 두 번째 기록). 다음 측정부터scripts/compare_retrievers.py가 항목별 상위 k 도 저장하게 하면 파일만으로 분석된다
gateway → call-mediator 개명에서 남은 것 (신규, 2026-09-17, 정성윤 · decisions/115)
운영 전환이 아직이다— 끝났다 — 2026-09-17 14:00 1차 확인(/call-mediator/healthok · 옛/gateway/*404 · 번들의 구독 주소로 운영/ws열림) → 2026-09-19 재확인(토큰 넷 true · 토큰 없는/ws·/ingest401 · 번들 뷰 토큰으로/ws101 = 시크릿이 옛 값 그대로 · 프론트 번들에gateway문자열 0회). 룰셋 전환도 된 것으로 본다 — 안 됐으면 PR #101·#102 가 없는 검사를 기다리며 잠겼을 것이다- 옛 오브젝트 청소 — ✅ 2026-09-19 SSM 실측: 지울 것이 없었다. 옛
gateway이름의 Deployment·Service·Secret·Ingress 가 0개(시크릿은call-mediator-tokens·callguard-server-tls·gcp-stt-credentials·server-env넷뿐) · 로컬.env도CALL_MEDIATOR_*뿐 · 운영 이미지는callguard-server:0.1.18·callguard-call-mediator:0.2.1(파드 생성 09-18 08:23 UTC). 적용 스크립트에 prune 이 없어 남을 줄 알았는데 남지 않았다 - Vercel 옛 변수 둘 삭제 — 정성윤 (신규, 2026-09-19) —
kxu6(call.solidbob.cloud)의VITE_GATEWAY_WS_URL·VITE_GATEWAY_DEMO_BASE_URL. 개명 전환 중 마지막 한 줄이다. 새 변수가 이미 번들에 구워져 돌고 있어 지워도 화면에 영향 없다. 콘솔에서만 보이고 CLI·토큰이 로컬에 없다 → ✅ 2026-09-22 정성윤이 지웠다(대시보드). - 류준 님
origin/ai의services/gateway/미머지 작업 — ✅ 2026-09-18 PR #102 로 들어왔다(origin/ai끝 커밋c6fe2e7이 main 에 있고, 재생기는services/call-mediator/scripts/replay_persona_call.ts). 원문 — 합성 통화 재생기와 태그0.1.6. main 을 받을 때 경로·이미지 이름·태그(0.2.x)·/dev/text주소를 맞춰야 한다 - 개발자용 런타임 오버라이드 주소가 바뀌었다 — ✅ 2026-09-23 확인 — 저장소 전체에
gateway=잔재 0건(apps/·services/). 원문 —?gateway=→?call_mediator=, 저장 키도 바뀌어 브라우저에 저장해 둔 옛 오버라이드는 무시된다. 팀에 알린다
합성 통화 확장 · E2E 24건에서 남은 것 (신규, 2026-09-18, 류준 · decisions/209 제안)
- ✅ 2026-09-21 키 받았고
--prefetch SYN-0017턴 381자 합성 확인(캐시·장부 동작,w5-persona-tts-google닫음). SSMLvolume은 귀로 확인할 것. 원문 — Google TTS 키 발급 — 정성윤 님 —scripts/persona_sim/TTS.md §1절차(Cloud Text-to-Speech API 사용 설정 → API 키 → API 제한 TTS 하나만 → 콘솔 할당량 낮추기). 받은 키는.env의GOOGLE_TTS_API_KEY에. 첫 실행은--prefetch SYN-001(7턴)로 작게. 아직 실제 호출 0건이라 Wavenet 이 SSMLvolume을 얼마나 반영하는지·콘솔에서 문자 할당량을 낮출 수 있는지 미확인 - E2E 실패 21건의 시스템 결함 배정 (보고서
data/processed/persona-e2e/2026-09-18-1618.md, 로컬 규칙·BM25·NER 없음 — 측정값 아님) — → 10-01219이후 재측정 없음 — 범위 밖(138) → 10-02 정정 — 「재측정 없음」 이 아니다. 아래 ①~⑦ 은 09-18 에 각각 결정·수정됐고 그 뒤 세 번 다시 돌렸다 — 09-21 로컬 dense+리랭커 ✅23·❌1 · 09-22 밤 ✅7·❌17(전부 엉뚱한 절차 판정, 31쌍·186행) · 09-24219뒤 21쌍·127행·정답 절차 15/17(_logs/2026-09-21-07-ryujun·2026-09-22-09-ryujun·2026-09-24-02-ryujun. 구성이 서로 달라 나란히 비교하지 않는다,source: synthetic). 그 뒤 운영 실구성으로는 돌리지 않았다 ① 콜 미디에이터가/hub/compliance-checks를 안 부른다(라벨 있는 8건 전부 탐지 0, 09-17 과 동일 — 정성윤·장민석) → 09-18 결정: 콜 미디에이터에서 배선한다(상담원 확정 발화마다 호출·compliance_flag저장, 대시보드 방송은 프론트 파서가 받을 때). 태그 올라감 ②closure_rule.py에 TERM 4.5·4.20·4.12·2.6·4.9·6.12·3.3·4.8 규칙이 없다 — 대본이 고른 절차인데 판정이 영원히 없다(장민석) → 09-18 결정: 서버 규칙표에 추가한다 — TERM.md 「필요서류」 문구 글자 그대로, 조건부는conditional. 장민석 님 검토 요청. 서버 태그 올라감 ③ 필요서류 판정이 추천 1순위 카드 조항에만 걸린다(topSourceDocId) — BM25 1순위가 틀리면 엉뚱한 절차(SYN-020 화면에 「지방세 환급」「장애인콜택시」 진행 중으로 뜸). 임베딩을 켜면(decisions/208) 줄겠지만 구조 자체를 볼 것(정성윤·류준) → 09-18 결정: 콜 미디에이터가 상위 카드를 순서대로 보며 규칙표에 있는 첫 조항을 절차로 삼는다(1순위가 POLICY·MANUAL·규칙 없는 TERM 이면 다음 카드). 엉뚱한 절차 자체는 검색 순위 문제라208(임베딩)로 ④ C-5 누락 — SYN-020 #16 「저는 강민재고요, 아버지는 강영식이에요」 이름 둘이 자막·DB 에 원문(SEC-1). 「~고요」 어미 자기소개 + 가족 호칭 문맥. 화면에서도 재현 확인(류준·장민석) → 09-18 결정:server/apps/masking이름 규칙 보강(「~고요」 어미 자기소개 · 가족 호칭 문맥). AI Hub 실제 발화로 과탐지 재확인 후 반영 ⑤recommendation_card.source_doc_id가 전부 NULL —document테이블 0행이라 FK 를 못 채운다(B-6 출처가 DB 에 안 남음) → ✅ 09-18 코드 문제 아님 —scripts/seed_documents.py를 안 돌린 것. E2E 스택 절차(E2E.md②)에 넣었고 로컬 검사 DB 에 98조항 적재 확인. ⚠ 운영 RDS 에도 돌려야 한다(런북 절차 — 정성윤) ⑥ 대본↔규칙표 서류 이름 불일치 5건(SYN-002·005·013·015·017 — 「누수 수리 확인 서류」 vs 「누수 수리 사실을 확인할 수 있는 서류」 등) — 어느 쪽을 정본으로 맞출지 → ✅ 09-18 결정: 규칙표가 정본. 대본 11건의required_documents를 규칙표 기본 서류 이름으로 맞추고 조건부 서류는 새 필드conditional_documents로 뺐다(SYN-002·005·009·013·015·017·019·020·021·024). SYN-022 는 상담원 발화에 「가족 관계」 키워드를 넣었다. 라벨·PII·톤 불변, 생성기 24건 통과 ⑦ 한글 수사 휴대전화(「공일공 공공공공 …」)가 P4 가 아니라 P3 로 잡힌다(가려지긴 함) · P6 과잉 「고객님이요」·「위임장과」 → 09-18 결정: ④ 와 함께 서버 마스킹 규칙 보강(전화번호 형태 우선 분류 · 과잉 2종 제외 목록) - 대시보드
AgentCallBox모달이 합성 통화 라이브 보기를 가린다 — 조서희 — ✅ 2026-09-23 고쳤다(조서희, PR #145) — 「닫기」 버튼 + 자막이 들어오기 시작하면 스스로 사라진다. 원문 — 「통화 시작」 직후 마이크 데모 모달이 떠 뒤 자막이 흐리게만 보인다.call_token없이 「통화받기」를 누르면 닫히긴 하지만(마이크 안 켬) 시연자가 알기 어렵다. 합성 통화(재생기)일 때 닫는 방법을 프론트에서 정할 것. 또 상담기록 목록이customer_id해시를 그대로 보여 준다 -
작업 트리의 미커밋 D-5 파일 — ✅ 09-18 2차 커밋에 실었다(하네스 배선 전 모듈). 원문 — —
ai/apps/evaluation/metrics/call_temperature.py·ai/apps/evaluation/tests/test_call_temperature_metrics.py(이전 세션,w3-call-temperature). 09-18 커밋에서 뺐다 — 검토 후 별도 커밋(서버 태그 올라감) - ✅ 09-18 처리 결과(같은 날 2차) — ①②④⑤⑥⑦ 반영 후 E2E 24건 ✅22·❌2(
data/processed/persona-e2e/2026-09-18-1653.md·1655.md). 남은 ❌ 2 = SYN-011(3.14)·021(2.9) 검색 순위 — BM25 상위 5 에 정답 조항이 없어 필요서류 판정이 없다 →decisions/208(운영 임베딩). ③ 은 「카드 순서대로 규칙 있는 첫 조항」으로 바꿨다(콜 미디에이터0.2.1) → 2026-09-21 로컬 재검사: dense 만 켜도 둘 다 ✅(리랭커 불필요). 대신 SYN-023 이 새로 ❌ — 아래 「진행 중 티켓을 닫으며 남긴 것」 - 장민석 님 검토 요청 — 09-18 서버 변경(
0.1.18,decisions/302로 류준이 고침) — ①closure_rule에서decisions/305가 EXCLUDED 로 뒀던 2.6·4.5·4.9·4.12 를 되살렸다(갈래 공통 서류만 필수, 갈래별은 conditional) — 305 취지와 맞는지 ② 이름 규칙의 가족 호칭 문맥이 「아버지가 장애인이에요」 류를_NOT_NAMES목록으로만 막는다(실제 발화 신규 오탐 0) ③ P4 재라벨이 뒤의 「이」 한 글자를 함께 가린다(의도) ④compliance_flag저장 배선(신규) —compliance_rule카탈로그를 저장 직전 UPSERT 로 채우는 것(대안:scripts/seed_compliance_rules.py) ·default_severity전부medium(등급 정의 없음) · 저장 실패를 응답에서 숨기는 정책(콜 가드는 500)- → 닫음 (2026-09-22 장민석):
w5-server-change-review범위(0.1.18) —closure_rule29 복원은 공통 서류만 필수라305제외 사유와 모순 없음. 그대로 둔다
- → 닫음 (2026-09-22 장민석):
- 대시보드 컴플라이언스 경고가 서버 결과가 아니라 프론트 로컬 규칙(
apps/call/src/lib/compliance/detectComplianceRisk.ts)이다 — ✅ **2026-09-23 고쳤다(조서희, PR #143) — 실서버 모드에서는state.compliance의 서버 findings 를 그린다. 운영 재확인은 수동 QA Q-31~33 재시험에서 한다. 원문 — 조서희** — 서버는 이제 검사·저장까지 한다(콜 미디에이터0.2.1). 콜 미디에이터compliance메시지 파서를 추가하면announceCompliance를 켤 수 있다(정성윤 —main.ts)- → 09-22 켰다(정성윤, call-mediator
0.2.3,w6-compliance-broadcast) — 파서는349b18b로 main 에 있다. 조서희 님 요청으로 검사 실패 신호compliance_unavailable을 함께 넣었다(위반 =compliance· 실패 =compliance_unavailable· 없음 = 침묵). 남은 것은 프론트 몫 — 이 타입의 파서와 화면(3단계,w6-compliance-alert-ui) · 로컬 규칙(detectComplianceRisk.ts)을 걷을지
- → 09-22 켰다(정성윤, call-mediator
- 4.20 과태료 이의신청·4.8·3.3·6.12 는 규칙표에 없다(의도) — 「— 필요서류」 조항이 아니다. 대본 SYN-006·007·012 는
required_documents를 비워 「판정 0건이 정상」. 4.20 본문의 이의신청서·소명 자료를 규칙으로 둘지는 장민석 님 판단 → 10-01 그대로 둔다 — 닫는다
09-19 세션에서 남긴 것 (신규, 2026-09-19, 정성윤)
- 조서희 —
w1-platform-landing이 8-27 부터in-progress다 — 랜딩은www.solidbob.cloud로 떠 있고 → 10-01 done 처리됨 — 닫는다 3주차 다크 리디자인(w3-platform-landing-refresh)까지 끝났는데 앞 티켓의 상태가 그대로다. 중복 티켓 경고는 뒤 티켓에depends_on을 달아 껐지만(일부러 나눈 단계다), 상태는apps/전담인 조서희 님 몫이라 건드리지 않았다. 티켓 본문의 「아직 안 된 것」(아키텍처 문서에apps/platform을 올릴지)이 아직 살아 있으면 그것만 새 티켓으로 떼고 이 티켓은 닫는 쪽이 보드가 정직해진다 -
팀 — 운영
document98행이 정말 있는지 한 번 센다 — ✅ 2026-09-19 SSM 실측 98행. 런북 17-3 의 「09-15 적재 완료」가 맞았고STATE.md·09-18 미결이 낡은 기록이었다. 적재를 다시 돌릴 필요 없다 - 운영 DB 를 세어 보니 «저장된 적 없는 경로»가 드러났다 — 팀 (신규, 2026-09-19, 정성윤 SSM 실측) — → 10-01 D-4·G-2·D-5 는 알려진 한계(
138), eval_run 은 로컬 기록 DB(138정본) — 닫는다- 2026-09-23 확인(정성윤) — 2026-09-23 재측정(29 테이블) — 0행은 넷뿐이다:
eval_run·eval_result(하네스는 로컬 기록 DB 를 쓴다) ·knowledge_gap(공백 신고 0건) ·resource_center(G-2 미구현) ·voice_outlier(D-5 배선 보류317). 채워진 것:call34 ·transcript_segment157 ·recommendation_card445(source_doc_idNULL 1건뿐 —document99행이 들어와 ⑤가 풀렸다) ·closure53 ·closure_item131 ·masking_event37 ·call_guard_flag37 ·routing_log33. ⚠ 남은 구멍 둘:call.agent_id34/34 NULL(w8-call-owner-scope) ·call.inquiry_type·summary_text는 29/34 NULL(통화 후 처리를 돌린 5건만 채워진다 — 정상). 공개 테이블 29개.call13 ·transcript_segment11 ·masking_event5 ·call_guard_flag1 ·recommendation_card0 ·closure0 ·compliance_flag0 ·compliance_rule0. 즉 운영에서 B(추천 카드)·F-2(필요서류 판정)·C-1~C-4(컴플라이언스) 가 한 번도 저장된 적이 없다. 코드가 없어서가 아니라(셋 다0.1.18에 들어 있다) 그 경로를 타는 통화를 아직 안 걸어 봤기 때문으로 보인다 — 09-17 점검의 「바깥 실제 접속 0건」과 같은 이야기다. 정할 것: 시연 전에 운영으로 합성 통화 한 건 (SYN-010 등)을 태워 넷이 실제로 쌓이는지 볼지 — 운영 DB 에syn-행이 남는다(09-17 미결과 같은 건). ⚠ 이건 측정이 아니라 「안 돌아 본 것」의 확인이다. 수치로 인용하지 않는다
- 2026-09-23 확인(정성윤) — 2026-09-23 재측정(29 테이블) — 0행은 넷뿐이다:
6주차 판정(09-30)을 앞두고 — 공식 수치가 2주 낡았다 (신규, 2026-09-19, 정성윤)
주차 경계를 마일스톤 기준으로 다시 세면 오늘은 5주차이고 F·G·H·I 동결 판정은 6주차 종료 = 09-30,
남은 기간은 11일이다. STATE.md 가 「3주차」로 두 주 낡아 있어 이것이 가려져 있었다(같은 날 고쳤다).
- 류준 님 — 현재 코드로 하네스 재측정 +
--record— ✅ 2026-09-21 운영 구성으로 쟀다 — 도커 없이 ES 9.5.1 + nori 를 zip 배포판으로 띄워(운영과 같은 버전·설정) 98조항을 적재하고run_eval.py --runs 3 --no-ner --retriever bm25를 돌렸다(커밋261bce4-dirty· n 96/28). retrieval 0.833 / 0.666 ✅ · masking 누락 0 ✅(09-09 의 ❌ 가 풀렸다) · closure_gate·trigger 측정 불가. 값은STATE.md「실측값」. ⚠ 기록 DB 가 없어--record는 못 했다(run_id 없음) — 조건(날짜·커밋·명령·표본 수)은 STATE 에 글로 남겼다. ⚠ 모델 구성(dense·리랭커·NER)은 못 쟀다 — 모델 파일이 있는 머신에서 같은 명령에--retriever만 바꾸면 된다. 원문 — 판정에 쓸 수 있는 공식 수치가 09-09 값뿐이고 거기서masking이 ❌(누락 2) 다. 지금 판정하면 C-5 절대 규칙 미달로 동결이 걸린다. 그 뒤 들어온 dense·리랭커·NER·C-5 규칙 보강은 전부 로컬 측정이라 절대 원칙 2·5 상 인용할 수 없다. 이 저장소의 윈도 머신에는 ES·모델·.venv가 없어 돌릴 수 없다 — 맥이나 측정 인스턴스(런북 22장) 몫이다.docker build -t callguard-es:local infra/elasticsearch/ .venv/bin/python scripts/index_knowledge_base.py --to-es --recreate ELASTICSEARCH_URL=http://localhost:9200 .venv/bin/python scripts/run_eval.py --runs 3 --record볼 것: ①
masking이 0 으로 갔는지 ②NO_SAMPLES가 어디 남는지(C-5 표본은 일곱 패턴 다 있고 F-2f2_case는 0건 — 09-19 골든셋 파일 실측) ③ 여러 번 중 최저치로 고정(절대 원칙 4) - 팀 — 무엇을 «기준선 구성»으로 삼을지 먼저 정한다 — ✅ 2026-09-21 정했다(
_project/decisions/121) — 모델은 전용 GPU EC2 에 올린다. 판정일(09-30)까지 그것이 운영 경로에 붙어 있으면 모델 구성, 아니면 운영 구성(규칙+BM25)이 기준선이고 모델 구성은 로컬 측정 참고치로 나란히 적는다. 원문 — 운영은 규칙+BM25, 로컬 최고는 NER+dense+리랭커다. 로컬 최고 수치로 「통과」를 선언하면 운영에서 성립하지 않는 통과가 된다.decisions/208(운영에 NER·임베딩을 올릴지)이 «제안» 인 채라 그 결정이 곧 기준선의 정의다. 판정(w6-core-baseline-check)보다 이게 앞선다 - F-2 는 잴 수 없는 상태로 7주차 체크포인트를 맞는다 — 골든셋에
f2_case가 0건이라 「필수 항목 누락 0건 탐지」를 판정할 근거가 없다. 정할 것: ① 골든셋에 F-2 케이스를 넣어 측정 가능하게 할지 ② 계획대로 설계 문서 전환(w7-f2-checkpoint)을 미리 확정할지. 성공 조건은 F-2 가 아니므로 ②도 실패가 아니다- → 닫음 (2026-09-21 보드 최신화, 정성윤):
decisions/118— 체크포인트를 앞당겨 판정했고 F-2 는 설계 문서 산출로 갔다 → w8-f2-wrapup
- → 닫음 (2026-09-21 보드 최신화, 정성윤):
- 7주차 레이턴시가 지금 구조로는 또 「측정 불가」다 — 트리거는 이벤트 도착 시각이 없어 상수로 모형화 중이라 → 10-01 서버 내부 구간은 09-30 실측(
w7-latency-budget), 나머지는 측정 불가로 — 닫는다 채점하면p50=p95=346·발동률 1.0 이라는 가짜 만점이 나온다(STATE.md). 4.3절 지연 예산을 실제로 재려면 콜 미디에이터가 발화 종료·카드 도착 시각을 실어 보내는 계측이 먼저다 — 7주차에 시작하면 늦는다(w7-latency-budget)
/health/ready 를 새로 냈다 — 검토·배선은 남았다 (신규, 2026-09-19 · 주 담당 장민석)
- 장민석 님 검토 —
server 0.1.19(decisions/302) — ①/health는 싼 기동 확인 그대로 두고- → 닫음 (2026-09-22 장민석):
w5-server-change-review범위(0.1.19) — 그대로 둔다 실제 연결은 주소를 나눠(GET /health/ready) 잰 것 ② 타임아웃 3초·실패 시 503 · 설정이 없는 자원은 실패로 세지 않는다(configured: false) ③ 예외는 타입 이름만 싣는다(SEC-2 — 메시지에 접속 문자열이 들어 있다) ④ ES 는_wire_retrieval이 만든 같은 클라이언트를app.state.es_client로 재사용한다
- → 닫음 (2026-09-22 장민석):
- k8s 프로브에 붙일지 — 정성윤 — ✅ 2026-09-23 정했다 — 프로브는
/health를 본다,/health/ready는 안 쓴다. readiness 가/docs(스웨거)였던 것을/health로 바꾸고 liveness 를 새로 달았다(60초 뒤부터 30초 간격·3회)./health/ready를 프로브에 걸지 않는 이유: 그쪽은 DB·ES 를 실제로 찔러 못 붙으면 503 이라, ES 가 잠깐 내려가면 readiness 가 떨어져 자막·마스킹까지 같이 멈춘다. 검색만 죽는 편이 낫다(server/main.py의 같은 판단). 진단용으로는 그대로 쓴다(런북 19장·배포 스모크). 원문 — 지금은 어떤 프로브도/health/ready를 쓰지 않는다. 붙이면 ES 가 잠깐 흔들릴 때 파드가 서비스에서 빠진다 — 자막·마스킹은 ES 없이도 도는데 함께 멈추는 셈이라, 붙이려면 그 대가를 먼저 받아들여야 한다. 런북 19장 9-1 번에 수동 검사로만 넣어 두었다 - ES 가 설정됐는데 클라이언트가 안 꽂힌 배포는
degraded로 뜬다 — ✅ 2026-09-23 운영은 둘 다 초록이다 —/health/readypostgres ok(77ms)·elasticsearch ok(2ms). 「그 상황이 오면」의 이야기로만 남는다. 원문 —elasticsearch패키지 없이- 2026-09-23 확인(정성윤) — 지금 운영은
/health/ready가postgres ok(77ms)·elasticsearch ok(2ms)로 둘 다 초록이다. 이 항목은 「그 상황이 오면」의 이야기로 남는다.ELASTICSEARCH_URL만 있는 구성(검색은 501)이 그렇다. 의도한 동작이지만, 그런 구성을 정상으로 볼지는 팀 판단이다
- 2026-09-23 확인(정성윤) — 지금 운영은
레이턴시 계측에서 남은 것 (신규, 2026-09-20 · decisions/119)
- 콜 미디에이터 —
e2e_latency_ms를 채운다(누구나 · 주 담당 정성윤) — ✅ 2026-09-21 채운다(콜 미디에이터0.2.2) — 추천을 방송하기 직전에방송 시각 − utterance_end_ms를 문자열로 싣는다. 발동하지 않은 응답·발화 종료 시각이 없는 경우에는 넣지 않는다(0 으로 지어내지 않는다). 통화 기준 시계를 한 곳(callClockMs)으로 모았다. 타입 체크 0 · 테스트 132/132. ⚠ DB 의e2e_latency_ms는 여전히 NULL 이다 — 서버는 방송 전에 저장한다. 값은 방송 메시지로만 흐른다(119③). 원문 — 방송 직전에방송 시각 − utterance_end_ms를 계산해 싣는다. 컬럼·DTO 는 2026-09-09 부터 있었는데 아무도 값을 넣지 않아 늘 NULL 이었다(09-20 전수 grep). 서버는 그 시각을 모르므로 서버가 채우면 안 된다 - 장민석 님 검토 — 서버
0.1.19의 구간 분리(decisions/302) —- → 닫음 (2026-09-22 장민석):
w5-server-change-review범위(0.1.19) — 그대로 둔다 ①RecommendationCards에retrieval_ms·generation_ms추가(선택 필드) ② 응답 스키마에도 노출(콜 미디에이터가 중계) ③ DB 컬럼은 일부러 안 만들었다 — 운영recommendation이 0행이고 마이그레이션이 사람 손이라 미뤘다(119 ③) ④ 시계 호출이 2 → 4 로 늘어 기존 테스트 둘의 기댓값을 고쳤다(저장이 채점 구간 밖이라는 성질은 그대로 지킨다)
- → 닫음 (2026-09-22 장민석):
- 측정 —
e2e_check.py가 구간별 p50·p95 를 표본 수와 함께 낸다 — 지금 24건을 왕복시키고 있으니 거기에 얹는다. → 10-01 안 한다(w7-latency-budgetdone 사유) — 닫는다 ⚠ 합성 통화는 STT 를 안 거쳐 ①(발화 종료 → STT 도착)이 0 이다.source: synthetic+ 「STT 미경유」를 붙이고 ①은 V4 실측 346ms 를 더해 「추정 E2E」로 적되 합산이 추정임을 같은 줄에 쓴다 - 브라우저 렌더(⑥)는 재지 않기로 했다 — 되돌리려면 프론트 계측 + 되돌리는 엔드포인트가 필요하다(조서희 님 협의) → 10-01 확정 — 닫는다
운영 파이프라인 왕복에서 나온 것 (신규, 2026-09-20 — 런북 19장 11번 확장판)
운영에 테스트 통화 1건을 태워 전 구간을 처음으로 실제로 돌렸다(끝난 뒤 행 15개 전부 삭제). 잘 돈 것은 진행 기록에 있고, 여기는 고쳐야 할 것만 적는다.
- ⚠ 쓰기 경로에 인증이 없다 — 팀(주 담당 장민석·정성윤) — ◐ 2026-09-21 2단계까지 됐다 — 문은 아직 열려 있다. ① 서버 문(
0.1.19) ② 콜 미디에이터가CORE_API_TOKEN을Authorization: Bearer로 보낸다(0.2.2— 부르는 경로 전부에 실리는지 테스트로 고정, 없으면 헤더를 안 보낸다) · 매니페스트에call-mediator-tokens.CORE_API_TOKEN(optional) 주입 ·.env.example·secret.example.yaml에 키 이름. 남은 것은 운영 작업 둘: ③ 같은 값을 미디에이터 시크릿에 먼저, 그다음server-env에 넣는다 → 이때 잠긴다 ④ 서버를 fail-closed 로. 두 이미지가 배포된 뒤에 한다 — 순서를 뒤집으면 운영 통화가 전부 401 이다. 원문 — ⚠ 1단계만 됐다 — 문은 아직 열려 있다(2026-09-20,decisions/120). 서버에 서비스 토큰 문(INGEST_SERVICE_TOKEN,Authorization: Bearer)을 달았다(server0.1.19). 토큰이 없으면 연다 — 서버를 먼저 배포하는 순간 돌고 있는 미디에이터가 401 이 되지 않게 하려는 이행기 동작이고,/health의ingest_guard가open/locked로 그 상태를 말한다. 남은 것(순서를 지킨다): ② 콜 미디에이터가CORE_API_TOKEN을 헤더로 보낸다(TS — 이 머신에서 테스트 못 돌린다) ③ 같은 값을server-env와 미디에이터 시크릿에 넣는다 → 이때 실제로 잠긴다 ④ 서버를 fail-closed 로. ③을 ②보다 먼저 하면 운영 통화가 전부 401 이다. 또 대시보드가 직접 부르는 쓰기(/close·요약 확정·카드 피드백·공백 신고)는 이 문 밖이라 여전히 열려 있다 — 사람 토큰 몫이다. 원문 — —POST /hub/calls·/hub/transcripts·- → 닫음 (2026-09-22 장민석): ③ 시크릿(정성윤, 09-22) · ④ fail-closed(
w6-ingest-guard-fail-closed, server0.1.34) — 운영locked· 토큰 없는 쓰기 401 확인/hub/recommendations·/hub/call-guard-checks·/hub/compliance-checks·/hub/closure-checks가 토큰 없이 200 이다. 주소를 아는 사람은 누구나 운영 DB 에 통화·전사를 쓴다. CORS 는 브라우저에만 걸린다. 상담원 토큰 가드가 달린 곳은 블랙리스트 요청 하나뿐이다(기존 미결 「상담원 토큰을 어디까지 걸지」와 같은 건 — 이번에 「실제로 열려 있다」가 확인됐다). 콜 미디에이터는 자기 토큰으로 막혀 있으니 서버 쪽만 남았다
- → 닫음 (2026-09-22 장민석): ③ 시크릿(정성윤, 09-22) · ④ fail-closed(
- 없는 세그먼트를 참조하면 500 이다 — 장민석 — ✅ 2026-09-20 고쳤다(
decisions/302, server0.1.19).SegmentNotFoundError를 새로 두고 콜 가드 저장소가 FK 위반(23503)을 잡아 올린다 → 라우터가 404(「전사 구간이 없습니다: c#7 — POST /hub/transcripts 가 먼저 와야 한다」). 외래키가 아닌 실패는 그대로 올린다(아무 예외나 404 로 접으면 진짜 결함이 숨는다 — 테스트로 고정). 원문 — —segment_id가transcript_segment에 없으면call_guard_flagFK 위반이 그대로 터져 500 Internal Server Error(파드 로그에ForeignKeyViolation). 4xx 로 거절해야 한다 — 09-15 에 고친 「관리자 가드가 헤더 없으면 500」과 같은 부류다 - 컴플라이언스 저장 실패가 응답에 드러나지 않는다 — 장민석·류준 — ✅ 2026-09-21 맞췄다 — 둘 다 「200 + 로그」. 콜 가드도 저장이 우리 쪽 사정(DB 흔들림)으로 실패하면 탐지 결과를 그대로 돌려주고 경고 로그만 남긴다. 전에는 500 이라 상담원을 보호하려는 경고가 기록 실패 때문에 화면에서도 사라졌다. 삼키지 않는 것은 둘이다 — 호출자가 없는 전사 구간을 가리킨 것(404) · 스포크가 span 을 안 채운 것(우리 결함이라 500,
CallGuardFlagSpanMissingError). 원문 — ⚠ 절반만 닫았다(2026-09-20). 호출자 실수(없는 전사 구간)는 이제 두 스포크 다 404 다 — 인터랙터가SegmentNotFoundError는 삼키지 않는다. 저장소가 이 상황을CallNotStartedError(「통화가 없다」)로 올리던 이름 오류도 바로잡았다. 남은 절반은 «우리 쪽 실패(DB 흔들림)」 정책이다 — 컴플라이언스는 200 + 로그, 콜 가드는 500 으로 여전히 다르다. 09-18 에 장민석 님 검토 항목으로 올라가 있어 일부러 안 건드렸다. 원문 — — 세그먼트가 없으면compliance flag not stored … reason=CallNotStartedError를 로그에만 남기고 응답은 200 이다. 09-18 의 설계(「저장 실패는 로그, 응답 그대로」)가 의도대로 동작한 것이지만, 그래서 「운영에서 한 번도 저장 안 됨」이 조용히 이어질 수 있다. 콜 가드는 같은 상황에서 500 이라 두 스포크의 정책이 서로 다르다 — 맞출지 정한다 - 옛
test-deploy-*통화 3건이 운영에 남아 있다 — 정성윤 — ✅ 2026-09-21 지웠다 — 09-11 배포 검증이 남긴 셋(…111738·…111747-013·…111813-kb, 각각 전사 ≤1 · 마스킹 ≤1 · 확정 요약 없음)을 ID 를 명시해 자식부터 지웠다. 운영call13 → 10. ⚠ 남은 10건도 전부test-접두어다(test-dev3 ·test-e2e2 ·test-conn2 · 날짜형 3) — 그것들은 건드리지 않았다. 원문 — 이번 것은 지웠고, 이전 세션들이 남긴 것이다. 지우려면 자식부터(closure_item→closure…call).card_feedback·closure_item을 빠뜨리면 FK 로 막힌다 compliance_rule카탈로그에C-1한 행이 이번 테스트로 생겼다 — ✅ 2026-09-23 재확인 — 운영에 C-1·C-2·C-3 세 행이고compliance_flag는 C-1 2 · C-2 1 · C-3 1 건이다. 테스트 잔재가 아니라 실제 탐지 경로가 쓰는 카탈로그라 지우지 않는다. 원문 — 지우지 않았다.- 2026-09-23 확인(정성윤) — 운영에 이제 C-1·C-2·C-3 세 행이고
compliance_flag는 C-1 2 · C-2 1 · C-3 1 건이다. 테스트로 생긴 행이 아니라 실제 탐지 경로가 쓰는 카탈로그가 됐다 — 지우지 않는다. 내용은 맞고(확정적 보장 · 금액·기간 단정/medium), 09-18 설계가 저장 직전 UPSERT 로 채우게 돼 있다. ⚠ 다만 카탈로그가 「누가 언제 무엇을 검사했는가」에 따라 채워진다는 뜻이라, 시드 스크립트로 옮길지는 미정
- 2026-09-23 확인(정성윤) — 운영에 이제 C-1·C-2·C-3 세 행이고
.env.example에INGEST_SERVICE_TOKEN키를 사람이 넣어야 한다 (신규, 2026-09-20) — ✅ 2026-09-21 넣었다 —INGEST_SERVICE_TOKEN(서버)·CORE_API_TOKEN(콜 미디에이터) 둘 다. 이름만, 값은 비웠다. 훅이 막는 것은 편집 도구라 셸로 넣었고, 넣은 뒤 값이 들어간 새 줄이 0 임을 diff 로 확인했다. 원문 —server/core/config.py가 새로 읽는 키다..env.example은 자격증명 보호 훅(protect-files.sh)이 편집을 막아 일부러 우회하지 않았다.infra/k8s/base/secret.example.yaml에는 넣었다. 값은 비워 둔다(키 이름만 — SEC-2)
진행 중 티켓을 닫으며 남긴 것 (신규, 2026-09-21, 류준)
- 「감정분석」 대체 용어 — 팀 확정 —
w3-call-temperature를 닫으며 여기로. 1안 「통화 온도(Call Temperature)」. D-5 코드·화면 라벨·발표 자료에 다 들어간다(위 09-09 항목과 같은 건). → 10-01decisions/140 - D-5 음성 골든셋 출처가 없다 — 통화 단위 + 튀는/차분한 발화 라벨이 필요한데 다산콜DB(발화 단위 클립)·AI Hub 71479(단일 화자 과제 녹음) 둘 다 안 된다. 출처가 없으면 D-5 는 시연에선 동작, 수치는 「측정 불가 — 표본 없음」 으로 발표한다(절대 원칙 10). 어댑터·하네스 배선은 돼 있어 케이스만 생기면 채점된다(형식
golden-set/README.md). → 10-01decisions/142 - → 2026-09-21 AI 검토 완료(scripts/persona_sim/REVIEW-2026-09-21.md, 고침 3건) — 사람 확인은 권장 항목만 · 합성 대본 24건 사람 검토 — 류준·팀 —
w5-persona-sim-scripts를 닫으며 여기로. 매뉴얼 5.2 종료·5.4 위기 응대 해석과 어눌한 한국어 과장 여부는 AI 검수(QA 페르소나 3종)만 거쳤다. 시연 대본 SYN-004·010·020 부터. → 10-01 시연 대본은_project/demo-script.md(사람이 쓴 17줄)로 대체 — 닫는다 - → 2026-09-23 수동 검색 경로에만 걸었다 — 정성윤(
decisions/135,215를 되돌린 것이 아니다). 보류 사유(대화체 60% 기권)는 자동 추천 경로의 것이고, 문턱을 잰 보류 표본 24건이 수동 검색과 같은 모양(질문형·정답 없음)이다.AbstainingRetriever+provider.wrap_no_answer()(dense 단독일 때만) · 허브의get_search_retrieval_port자리 · 꽂는 곳은 합성 루트 하나. 운영 실측(0.1.40):ㅁㄴㅇㄹ0.540 ·ㅂㅈㄷㄱ0.527 ·ㅋㅋㅋㅋ0.532 → 0건 /전입신고0.792 · 「주민등록초본 떼려면 뭐가 필요해요」 0.835 → 5건. 0.67 이 정확히 가른다. ⚠ 자동 추천은 그대로라 맞장구에 카드 5장이 뜨는 문제는 남아 있다(w6-procedure-noise-redesign). → 10-01135로 정착 — 닫는다 - → 2026-09-22 값은 정했다 — 류준 결정, 팀 회의 합의 없음(
decisions/215): 사전 등록 후 보류 표본 24건으로 한 번 재서 dense 1순위 < 0.67 채택(걸러냄 12/24 · 정답 손실 1, 둘 다 경계값). 코드 반영(FallbackRetriever— 기권 시 BM25 로 안 내려감), ⚠ 같은 날 보류(E2E 24건에서 대화체 발화 60% 기권 · SYN-015·017 필요서류 절차 사라짐 → 기본 꺼짐,decisions/215갱신 · w6-b6-conversational-recalibration). 남은 것: 팀이 뒤집을지 · 「관련 문서 없음」 vs 「소관 안내」 카드 형식과 화면의 요청 단위 빈 상태 표시(지금은 누적 카드 0장일 때만 「관련 문서가 아직 없습니다.」 — 조서희 님) · 문턱이 못 가르는 타 기관 하드 네거티브(점수 밖 신호) · B-6 문턱 — 팀 결정 —w5-b6-no-answer-threshold측정 결과: 세 계열 모두 문턱 하나로 못 가른다. dense 0.67 안팎이 후보(손실 1/94 로 24건 중 15 걸러짐), BM25 는 권하지 않음. 타 기관 문의에 「관련 문서 없음」 카드가 맞는지 「소관 안내(MANUAL-2.2)」 카드가 맞는지도 프론트 카드 형식과 함께(조서희 님). 채택되면 새 B-6 케이스로 재측정한 뒤 어댑터에 규칙(새 티켓). → 10-01215보류 확정, 자동 추천 기권은 알려진 한계(138) — 닫는다 - A-5 실측 뒤 남은 것 — 팀 — 2026-09-21 등급별 WER/CER(8 kHz, n 20/등급, v1 기본 모델): Beginner 0.412/0.221 · Intermediate 0.266/0.198 · Advance 0.225/0.087 · Fluent 0.198/0.067 — 상한(온라인 녹음 다운샘플·낭독/QA 과제·3~6초 짧은 발화). ① A-5 를 코어(차별점)에 그대로 둘지 — Beginner 는 단어 다섯 중 둘을 틀린다. 「어눌한 한국어를 정확히 전사」가 이 수치로 차별점이 되는지 팀이 판단 ② Chirp 3(v2) 재측정 — 오늘은 v1 기본 모델로 쟀다(09-09 실험 호출 재사용). 표본·8 kHz 사본이 남아 있어 다음 날 캡 ~390초면 된다 ③ 왕복 지연(STT→번역→화면)은 번역 단계가 없어 측정 불가.
w3-a5-translation-spike·w5-a5-wer-by-proficiency참고 → 10-01 1차 범위만 실물, 확장 미착수(decisions/139) - 필요서류 절차 고르기 규칙이 «규칙 없는 1순위»를 건너뛰어 엉뚱한 절차를 잡는다 — 류준(09-18 결정 당사자) · 콜 미디에이터 주 담당 정성윤 — 2026-09-21 로컬 dense E2E 에서 SYN-023(옥내 배관 수리 — TERM-3.15, 규칙 없음 · 「판정 0건이 정상」)이 첫 고객 발화 직후부터 TERM-3.7(누수 요금 감면)
incomplete로 판정됐다(검사 DB 시각 대조). 09-18 결정 「카드 순서대로 규칙 있는 첫 조항」이 1순위 3.15 를 건너뛰었기 때문이다. BM25 에선 3.7 이 상위 5 밖이라 가려져 있었고, 검색이 좋아질수록 더 자주 드러난다. 제안: 1순위가 규칙 없는TERM이면 거기서 멈추고 판정하지 않는다(건너뛰는 것은POLICY·MANUAL만). 그러면 09-18 에 고친 「POLICY·MANUAL 이 1순위라 판정이 없던」 경우는 그대로 풀리고, SYN-006·007·012(규칙 없는 절차)도 「판정 0건」이 유지된다. 정할 것: 이 규칙으로 바꿀지 — 콜 미디에이터src/변경이라 태그가 오른다. 바꾸면 24건 E2E 를 BM25·dense 두 구성으로 다시 돌려 확인한다 → 10-01219점수 하한으로 채택(09-24) — 닫는다- 2026-09-22 운영에서 재현(류준) — 합성 통화 SYN-010(
syn-prod-syn-010-20260922)의 1순위는 정답TERM-2.12(규칙 없음)인데 판정이TERM-2.9 대중교통 분실물 수령incomplete로 떴다. SYN-008 은6.9·3.5를 번갈아 잡았다. 상담원 화면에 틀린 「빠진 서류」가 뜬다
- 2026-09-22 운영에서 재현(류준) — 합성 통화 SYN-010(
- Chirp 3 재측정에 IAM 역할이 필요하다 — 정성윤 님 — 서비스 계정(
callguard-506606프로젝트)에 「Cloud Speech 클라이언트」(roles/speech.client) 를 붙여 주시면 된다. v1(지금 쓰는 것)은 역할 없이 되지만 v2(Chirp)는speech.recognizers.recognize권한을 따로 본다. 스크립트는 준비돼 있다(w3-a5-translation-spike09-21 「Chirp 3」 절). 운영 콜 미디에이터의 STT 경로와는 무관하다(측정 전용) → 10-01 역할은 부여됐고(09-22) 재측정은 발표 뒤(138) — 닫는다 - 시연 전에 합성 음성을 사람 귀로 한 번 듣는다 — 류준 — 톤 음량은 측정으로 고쳤다(평온 대비 격앙 +3.8 · 고함 +7.1 dB). 전체가 8 dB 작아졌으니 시연 스피커 음량을 올린다. 대본 AI 검토의 「사람이 꼭 볼 항목」 8개도 같은 자리에서(
scripts/persona_sim/REVIEW-2026-09-21.md) → 10-01 시연 영상은 글자 채널이라 합성 음성을 안 쓴다 — 닫는다 - AI Hub 71479 원본 20 GB 의 S3 경로 — 정성윤 님 — ✅ 2026-09-23 정한다 —
s3://assist-apne2/datasets/aihub-71479/validation/(제안 그대로). zip 그대로 올리고 공개하지 않는다(버킷은 비공개·팀 IAM 한정, 런북 부록 A). 올린 뒤CHECKSUMS.md5로 대조하고 티켓에 경로를 적는다. 업로드는 원본을 가진 류준이 그 맥에서aws s3 sync로 한다. 원문 —decisions/210대로 경로·접근은 정성윤 님이 정한다. 제안s3://assist-apne2/datasets/aihub-71479/validation/(zip 그대로, 비공개·팀 IAM 한정). md5 는data/raw/aihub-foreign-proficiency-71479/validation/CHECKSUMS.md5. 정해지면 류준이 이 맥에서aws s3 sync로 올리고 티켓에 S3 키를 적는다.2026-09-22 갱신 — 올리는 사람이 바뀐다. 학원이 AWS 계정 관리자로 지정돼 있어 팀 안에서 자격증명(SSO·IAM 사용자 둘 다)을 만들 수 없다. 그래서 류준이 올리는 경로를 접고 성윤님이 AI Hub 에서 직접 받아 EC2 에서 올리는 방식으로 바꿨다 — 링크·절차는
_project/handoff/2026-09-22-ryujun-to-seongyun-dataset-download.md. 덤으로 AI Hub 이용정책 5번(승인받지 않은 제3자에게 제공 금지)에도 이 편이 맞는다 — 파일을 넘기는 게 아니라 각자 본인 계정으로 신청·수령한다.
재측정에서 새로 나온 것 (신규, 2026-09-21)
- ⚠ C-5 「누락 0」은 오류 없는 전사에서만 성립한다 — 운영 구성(규칙만)의 오류 내성 곡선: 0% 0건 → 5% 2건 → 10% 3건 → 15·20% 4건(판정 24, 시드 3개 중 최대). 5% 에서 새는 것은
GS-033·GS-415(둘 다 P7 주소), 10% 부터GS-056(P6 이름)이 더해진다. 실제 통화는 STT 를 거치므로 오류 0% 가 아니다 — 절대 규칙(누락 0건)을 「통과」로 인용할 때 반드시 「오류 없는 전사 한정」을 붙인다. 09-15 로컬 측정의 규칙+NER 은 0/0/1/1/1 이었다 — NER 이 필요한 근거가 이것이고, 모델을 올릴 자리는decisions/121(전용 GPU EC2)이다. ⚠ 주입기가 실측 오류의 46.9% 를 흉내 내지 못해 실제는 이보다 나쁠 수 있다 → 10-01 인용 문구로 고정(decisions/138) - ✅ 2026-09-21 이 맥(모델 파일 있음)에서 쟀다 — 값·조건은 티켓
w5-error-curve-model-series, 그림jekyll/assets/error-tolerance-2026-09-21-models.png(운영 2계열 + 모델 3계열 한 장). 모델 계열 곡선이 그림에 없다 —jekyll/assets/error-tolerance-2026-09-21.png는 운영 구성(bm25 · rule) 두 선뿐이다. 모델 파일이 있는 머신에서scripts/measure_error_tolerance.py→scripts/plot_error_curve.py를 돌리면 dense·리랭커·규칙+NER 이 같은 그림에 얹힌다(측정 스크립트가 있는 계열만 재고 빠진 계열을 그림 아래에 적도록 고쳤다) - 기록 DB 없이 잰 값이다 —
eval_run/eval_result에 남지 않았다(§5 의 네 조건은STATE.md에 글로 남겼다). DB 가 있는 환경에서 같은 명령에--record를 붙여 한 번 더 돌리면 run_id 가 생긴다 → 10-01 정본은 run 8·9(기록 DB 있음,138) — 닫는다
전수 조사에서 나온 것 — 고치지 않고 올린다 (신규, 2026-09-21, 정성윤)
낡은 서술은 고쳤다(w5-stale-docs-sweep). 아래는 서술이 아니라 결정이나 코드 작업이 필요해 남긴 것이다.
- 팀 — 개발기간과 스프린트 수가 안 맞는다 — ✅ 2026-09-21 닫음(
_project/decisions/129): 8스프린트는 10-14 에 끝나고 10-15 ~ 10-27 은 새 기능 없는 「마감 기간」이다. ⚠ 팀에 묻지 않고 PM 이 기본값으로 정했다 — 발표일을 아는 사람은 알려 주면 고친다. 원문 — 개발기간은 10-27 까지인데 1주 1스프린트 × 8 은 10-14 에 끝난다(STATE.md가 8주차를 10-08~10-14 로 적는다). 남는 약 2주가 무엇인지(발표 준비·버퍼·마감 정리) 어디에도 적혀 있지 않다.w8-*티켓의 마감일이 여기에 걸린다 - ✅ 2026-09-22 달았다(
_project/decisions/315, 코드, 운영 배포 전 — 프론트가 토큰을 싣게 바뀐 뒤 머지). 원문 — 장민석 님 —POST /hub/calls/{id}/close와 카드 피드백에 상담원 토큰 가드가 없다 —server/main.py주석은 「대시보드가 직접 부르는 쓰기(/close·요약 확정·카드 피드백)는 사람 토큰(require_agent) 몫」이라고 적는데, 실제로 걸린 것은 요약 확정·재수정뿐이다(postcall_router.py·card_feedback_router.py에require_agent0회, 2026-09-21 grep). 서비스 토큰 문(decisions/120)도 이 둘은 비껴간다 → 두 경로는 어느 토큰도 요구하지 않는다. 읽기 경로(통화 목록·전사·기록)가 무인증인 것은 기존 미결과 같은 건이다 - 정성윤 — 새 클러스터에서
CORE_API_TOKEN이 조용히 비는가(추정 — 확인 필요) — ✅ 2026-09-21 확인: 빈다.release.yml301줄은call-mediator-tokens가 없을 때만 만들고 그때 INGEST·VIEW 두 키만 넣는다. 지금 클러스터는 키를 손으로 더하면 배포가 지우지 않는다. 런북 단계는w5-ingest-auth-fail-closed완료 조건으로 옮겼다. 원문 —infra/k8s/base/call-mediator.yaml은call-mediator-tokens에서 그 키를 optional 로 읽는데,release.yml의 시크릿 생성은 INGEST·VIEW 두 키만 만든다. 사람이 손으로 넣는 전제라면 런북 12장에 그 단계를 적고, 아니면 워크플로에 넣는다. 비면 쓰기 문이open으로 남는다 - 류준 님 — 하네스가 부르지 않는 지표가 셋 있다 —
ai/apps/evaluation/metrics/의generation(B-4·B-5)·asr(A-5)·call_temperature(D-5)는harness.py·run_eval.py어디서도 import 하지 않는다. → 2026-09-22 닫음(w6-harness-silent-metrics) — 생성·A-5 가 리포트에 「측정 불가 + 사유」로 나온다. D-5(call_temperature)는 09-21f3f284b에 이미 배선돼 있었다 별도 스크립트로만 돌아서run_eval리포트에 「측정 불가」로도 나타나지 않는다(침묵 누락). 절대 원칙 10 의 취지로는 「측정 불가」 줄이라도 찍는 쪽이 맞다 - ✅ 2026-09-22 닫는다 — 발표 전에는 배선하지 않는다(
_project/decisions/317). 서버는 「미측정」(null)을 낸다(316). 화면 표시만 조서희 님 미결에 남았다. 이하 원문 — ◐ 2026-09-22 추정 확인: 맞다 — 늘 0 이었다(voice_outlier에 쓰는 곳이ai/평가 쪽뿐). 이제 0 대신 「미측정」(null) 이 나간다(_project/decisions/316, 스키마 마이그레이션 동반). 실제 배선은 남았다 — 오디오를 가진 콜 미디에이터가 판정해야 하고, 음성 골든셋이 없어 붙여도 판정 품질은 측정 불가다. 원문 — 류준·장민석 님 — D-5 음성 이상치 저장이 서버에서 배선되지 않는다 — 포트·DTO·voice_outlier_repository.py까지 있는데server/프로덕션 코드에서 한 번도 참조되지 않는다. 그래서blacklist_evidence_repository.py의voice_outlier집계는 서버 요청 경로에서 늘 0 일 것으로 보인다(추정) — J-4 근거의 한 축이 비어 있는 셈이다- 2026-09-22 류준 조사(에이전트) → 확인: 새 API 없이는 배선할 수 없다. 콜 미디에이터의 hub 호출 6개가 전부 텍스트만 싣고 오디오·특징값을 나르는 경로가 없다 — 그래서 블랙리스트 근거의
voice_outlier건수는 운영에서 늘 0 이다. 제안(류준): 확정 발화마다POST /hub/voice-samples로 보내고 서버가 F0 만 뽑은 뒤 오디오는 곧바로 버린다(하네스가 재는 파이썬 추출기 하나만 쓰게 된다). 결정은 w7-d5-server-wiring(장민석)
- 2026-09-22 류준 조사(에이전트) → 확인: 새 API 없이는 배선할 수 없다. 콜 미디에이터의 hub 호출 6개가 전부 텍스트만 싣고 오디오·특징값을 나르는 경로가 없다 — 그래서 블랙리스트 근거의
- 팀 — 「허브는 스포크를 import 하지 않는다」를 계약으로 걸지 — 서버 주석 세 곳이 인용하던 「계약 5」는
.importlinter에 없었다(주석은 사실대로 고쳤다). → 10-01 안 건다 — 주석 정정으로 끝(138) 지금은hub/dependencies/가masking·closure_gate·postcall·blacklist의 기본 구현을 직접 import 하고 허브 라우터 12개가admin_auth·agent_auth가드를 import 한다.docs/architecture.md§1 은 여전히 「계약 위반」이라고 적는다 — 문서를 코드에 맞출지, 계약을 새로 걸고 코드를 옮길지 정한다 - 팀 — 09-21 에 만든 티켓 25건은 «계획»이지 «합의»가 아니다 — 정성윤이 보드를 프로젝트 끝까지 채우며 남의 이름으로
todo티켓 16건을 만들었다 → 10-01137로 정성윤이 전부 수행 — 닫는다 (류준 6 · 장민석 6 · 조서희 4). 근거는 전부 로그·미결·결정 기록에 있던 「남은 것」이지만 주차와 담당은 정성윤의 배정이다. 각자 보고 — 맞으면 그대로, 아니면 옮기거나 지운다(todo는 보존할 수행 기록이 없어 지워도 된다,CLAUDE.md§4). 같이 옮긴 상태 넷(w4-admin-google-login·w4-dashboard-live-contract·w5-persona-e2e·w1-platform-landing→ done)도 판정이 틀렸으면 담당자가 되돌린다
2026-09-22 류준 — 남은 일을 돌리며 새로 생긴 것
- server 이미지 태그를 올려야 PR 이 통과한다 — 류준·정성윤 — 09-22
ai브랜치가 서버 이미지에 들어가는 코드를 바꿨는데newTag가0.1.24그대로다(scripts/check_release_tags.py로 확인).0.1.25는 이미 레지스트리에 있다(다른 브랜치가 구움) — 같은 번호로 올리면 우리 코드가 빠진 옛 이미지가 돈다. 비어 있는 다음 번호를 골라 같은 PR 안에서 올린다 → 09-22 풀렸다:0.1.25는main이 구운 것이었다.0.1.26은PM브랜치가 먼저 잡아ai는0.1.27로 올렸다 - nori 품사 필터를 넣을지 — 류준·팀 — ✅ 넣었다(
decisions/214, 2026-09-22). 분석기에nori_part_of_speech가 토크나이저 바로 뒤에 들어가 있고(es_index.py:128) 테스트로 고정돼 있다. 2026-09-28 확인 — 이 항목은 결정 뒤에 안 닫힌 것이다. 원문 — 류준·팀** — GS-205 가 틀린 원인은 분석기에nori_part_of_speech가 없어 조사·어미(해지의해,발생 시의시)가 순위를 정하는 것이다(BM25 상위 5 전부 내용어 매칭 0, 정답 26위). 임시 인덱스로 넣어 보니 GS-205 2위 · BM25 Recall@5 0.823→0.854(96건, 1회, 14건 바꿔 쓰기 전 판) — 대신 GS-206·241 을 잃는다. 골든셋 한 번으로 고르면 골든셋에 맞추는 것이라 채택하지 않았다. 고른 데 쓰지 않은 항목으로 다시 재고 결정 기록2xx로 남길 것 - 완료 티켓에 AI Hub 원문 한 건이 남아 있다 — 팀 —
jekyll/_backlogs/w2-golden-set-50.md57행이 GS-102 원문(18자)을 통째로 인용한다. 조각이 아니라 발화 한 건이다(decisions/212에서 손대지 않음). 바꿀지 정한다 → 10-01 바꿔 썼다(w2-golden-set-5057행,decisions/138예외) - AI Hub 이용정책 1번 — 출처 표기 — 팀 — 이용 시 한국지능정보사회진흥원 사업결과임을 밝혀야 하고 2차 저작물도 같다. 발표 자료·README 에 표기가 필요하다 → 10-01 README 「데이터 출처」 절 추가. 발표 자료는
w8-presentation에서 같은 문장으로 - 모델 HTTP 표면이 CI 에서 돌지 않는다 — 정성윤 —
ai/apps/model_serving(decisions/213) 테스트는 fastapi·httpx·uvicorn 이 필요한데test.yml의aijob 이 설치하지 않아 skip 된다(의존 방향 스캔만 돈다). 그리고server/.importlinter계약 2 의 금지 목록에model_serving·compliance·generation·pii_ner·postcall_summary가 없다 — 장민석 → 09-22 해당 없음: 표면을decisions/124로 철회하고 PR 에서 뺐다(213).server/.importlinter금지 목록에compliance·generation·pii_ner·postcall_summary가 없는 것은 그대로 남는다 — 장민석 decisions/203의 「민원인 5,549건」 → 5,570건 — 류준 — 위 다산콜DB 셈에서 나왔다. 결정 자체(음성 톤 이상치)는 바뀌지 않는다. 203 에 정정 한 줄을 붙인다 → 10-01 203 에 정정 한 줄 붙임decisions/2115번 — 지식베이스 표지는 09-30 판정 뒤 — 류준 —knowledge-base/dasan/manual/MANUAL.md4.1 끝에(C-4 탐지 대상), 1.4 의(C-4 대체 표현 제시 근거)→(C-1~C-4 대체 표현 근거). ES 색인 대상이라 운영 재적재가 따른다. 4.1·1.4 는 B 골든셋 정답·방해 조항이 아니어서 검색 수치에 닿지 않을 것이지만 전·후 Recall@5 를 나란히 남긴다(123과 같은 태도) → 10-01 발표 뒤(138동결 — ES 재적재가 따른다)- 운영 첫 검색 요청이 3,300ms — 예열인지 확인 — 정성윤 — ✅ 예열이 맞다(2026-09-22 확인, 09-23 재확인) — 이후 검색은 0.6초 안팎이고 오늘 운영 파드에서 친 여섯 질의도 같은 대역이었다. 원문 — ◐ 2026-09-22 오후 확인: 단순 예열로 재현되지 않았다.
0.1.31배포 직후(검색 요청 0건인 새 파드)에POST /hub/search를 서로 다른 질문 셋으로 보내니 0.58 / 0.58 / 0.62s(외부 왕복 포함), 같은 질문 반복은 0.05s(retrieval_cache). 1순위는 셋 다 정답 조항(2.12·2.6·4.4). 서버는 요청별 지연을 로그에 안 남기고 그 파드도 이미 교체돼 SYN-010 의 3,300 은 원인 미해결로 남긴다. 임베딩은 켜 둔다. 남은 것: 미디에이터가retrieval_ms를/ws로 중계하지 않아(류준 확인) 다음 합성 통화에서도 구간을 못 가른다 —w7-latency-budget수집 경로에 얹는다. 원문 — — 모델 탑재 뒤 첫 합성 통화 SYN-010 의 추천 2건internal_latency_ms3,300 · 2,118(상한). 바로 뒤 SYN-008 8건은 394~778. 첫 요청 예열로 보이지만 가설이다 — 서버 로그의retrieval_ms로 가른다. 예열이 맞으면 기동 때 더미 질의 한 번이 해법 후보(판정 규칙 124 ⑥ 「p95 1,000 넘으면 임베딩 끔」을 첫 요청 하나로 적용하지 않도록) - 합성 통화 재생기가 마지막 턴을 잃는다 — 류준 — SYN-010 은 저장 4/5(마지막 상담원 인사 누락), SYN-008 은 16/16. 마지막 확정 직후 연결을 닫는 경쟁으로 보인다(가설). E2E 판정이 마지막 턴에 라벨을 둔 대본에서 거짓 ❌ 를 낼 수 있다 → 10-01 확정 전사 재시도(
w6-replay-last-turndone, 0.2.x)로 해결 — 닫는다 - A-5 를 하네스 안에서 잴지 — 팀 — 지금은 늘 「측정 불가」다. 재려면 hub 에 STT 포트 + 음성 골든셋이 필요한데 STT 는 콜 미디에이터(Node)에 있다. 아니면
scripts/measure_a5_proficiency.py로만 재는 지금 방식을 유지한다 → 10-01 안 잰다 — 스크립트로만(decisions/139)
2026-09-22 에 남긴 것 (정성윤)
- STT 일 캡(600초) 올릴 날짜 — 리허설·시연 날짜가 없어 못 정했다. 통화 1건 ≈146초라 하루 4통화. 합성 통화·판정 측정은 STT 를 안 타 당장 영향 없음(류준 전달 문서 §1-6) → 10-01 날짜 없이 절차로 정했다(
decisions/143) - A-5 를 차별점으로 유지할지 — 초급 WER 0.412(상한). Chirp 3 재측정(
roles/speech.client09-22 부여) 값을 보고 정한다(§1-9) → 10-01decisions/139— Chirp 3 값이 나오면 재검토 - 필요서류 절차 고르기 규칙 — 「1순위가 규칙 없는
TERM이면 판정하지 않는다」에 동의. 콜 미디에이터src/라decisions/124② PR 과 함께 태그 한 번으로(§1-11) → 10-01219로 정착 — 닫는다 - 09-21 셋째 판 「남은 일 목록」의 미커밋 파일 회수 — ✅ 회수됐다 — 결정
125~128이 전부_project/decisions/에 들어와 있다(2026-09-23 확인). 원문 — 결정 125~128(일정 공백·배정 호출·공개 데모·스키마 대조)·09-30 판정문 초안·티켓 절차. 저장소 이력 어디에도 없다. 그 세션을 돌린 머신의git status를 볼 것. ⚠ 오늘124·125를 새로 썼으니 거기 남은 파일은 번호를 옮겨야 한다 - 쓰기 경로 ④ 서버 fail-closed — ✅ 2026-09-22 운영 배포(장민석,
w6-ingest-guard-fail-closed, server0.1.34— PR #131). 배포 뒤/healthlocked· 토큰 없는 쓰기 401 확인. 미설정이면 401,/healthunset. 기동 거부가 아니라 401 로 갔다.server은 #129 와 겹쳐 머지 때0.1.330.1.34로 올라갔다. 원문 — 시크릿은 09-22 에 들어가 잠겼고, 「없으면 연다」를 걷는 코드 변경만 남았다(w5-ingest-auth-fail-closed, 장민석 님 검토 대상) - 랜딩 라이브 통화 실제 동작 — 09-22 에
VITE_CALL_MEDIATOR_WS_URL을 넣고 재배포했지만 브라우저로 통화를 걸어 본 적은 없다. 조서희 님w6-shared-call-entry운영 확인과 같이 → 10-01 소개 사이트는 mock 시연으로 둔다 — 범위 밖(138) - 배포 태그 번호에 선점 장치가 없다 — 정성윤 — 09-22 하루에 server 태그
0.1.28이 #114·#117 에서 겹쳤고,0.1.29는server브랜치가 집어 두어 #117 을0.1.30으로 다시 올렸다.tag-check가 막아 사고는 아니지만 PR 마다 한 번씩 되돌아온다(결정 기록 번호와 같은 병,decisions/022④). 후보: ① 브랜치별 번호대(예: 패치 자리 대신 빌드 번호) ② 머지 시release.yml이 채번하고newTag는 «올려야 함» 표시만 ③ 지금대로 두고 ⑥ 경고를 오류로 격상 → ✅ 2026-09-22 ③ 채택(decisions/131) —check_release_tags.py가 다른 브랜치 선점을 오류로 낸다.
2026-09-22 에 남긴 것 (장민석)
코드는 server 브랜치에 있고 커밋·배포 전이다. 넷은 조서희 님 화면이 먼저 바뀌어야 서버를 내보낼 수 있다(사용자 결정 — 서버만 하고 넘긴다).
- 조서희 님 — 상담원 토큰을 PC 에 남긴다 — ✅ 반영됨 —
agentToken.ts가localStorage를 쓴다(main 확인, 2026-09-23). 원문 —apps/call/src/lib/agentToken.ts의sessionStorage네 곳을localStorage로(decisions/315③). 관리자는 PC 한 대당 한 번만 토큰을 준다. 교대 PC 는 로그아웃이 전제 - 조서희 님 —
closeCall·submitCardFeedback에 상담원 토큰 — ✅ 반영됨 —coreClient.ts가 다섯 경로에 상담원 토큰을 싣는다(main 확인, 2026-09-23). 원문 —apps/call/src/lib/api/coreClient.ts에서confirmSummary와 같이Authorization: Bearer ${readAgentToken()}. 안 싣으면 서버 배포 뒤 통화 후 처리·카드 「사용 표시」가 401 - 조서희 님 — 반려에 사유 입력 — ✅ 반영됨 —
b9bba04(관리자 반려 사유 입력 UI ·note전달). 원문 —apps/admin반려 버튼이 사유를 받아note로 보낸다(decideBlacklistRequestApi는 이미note를 싣는다). 비면 422. 응답 요청 항목에decision_note(반려 사유)가 생겼다 - 조서희 님 — 온도 이상
null= 「미측정」 — ✅ 반영됨 — 상담원·관리자 화면 둘 다temperature_outliers === null이면 「미측정」을 먼저 본다(w6-qa-ui-defects-three, 2026-09-23 확인). 원문 —temperature_outliers가null로 온다(decisions/316).toNum(null)이 0 이 되어 「0건」으로 보이면 안 된다(apps/adminhubClient.ts:133·apps/callcoreClient.ts:301) - 팀 — 쓰기 일곱 경로를 ingress 에서 외부 차단할지 — 콜 미디에이터는 서버를 클러스터 안(
http://callguard-server)으로 부른다. 인터넷에 열려 있을 이유가 없어 토큰이 새도 밖에서는 못 쓰게 된다(가장 효과 큰 개선). 대가: 런북 19-11 과 재생기--close를 클러스터 안에서 돌린다. 인프라 변경이라 정성윤 님과 — 티켓 미작성 → 10-01 발표 뒤(decisions/138동결 목록) - 장민석·조서희 — 동명이인이 한 상담원으로 합쳐진다 —
resolve_or_create(decisions/406)가 이름으로도 찾아서, 같은 이름의 두 번째 사람에게 토큰을 발급하면 첫 사람의agent_id로 발급된다(09-22 리뷰). 동시 발급의 PK 위반 500 은 고쳤다(ON CONFLICT) → 10-01 알려진 한계(138) — 시연 계정 이름을 겹치지 않게 한다 - ✅ 2026-09-22 정했다(
_project/decisions/318) — 화면에 나가는 판정은 기록 실패해도 결과를 돌려준다, 저장이 목적인 경로는 5xx, 호출자 실수는 4xx. 원문 — 팀 — 저장 실패 정책이 경로마다 다르다 — 콜 가드·컴플라이언스는 「200 + 로그」, 추천·필요서류 판정·전사 저장은 500(09-22 리뷰). 경고 화면이 저장보다 먼저라는 이유가 추천 카드에도 해당하는지 정해 문서에 적는다 - ✅ 2026-09-22 서버는 열었다 —
GET /hub/blacklist-requests/mine(상담원 토큰,w6-agent-my-requests-api). 화면 연결은 아래 조서희 님 항목. 원문 — 상담원이 반려 사유를 볼 경로가 없다 — 사유는 저장되지만 상담원용 「내 요청」 조회 API·화면이 없다(decisions/316⚠) - 조서희 님 — 현황판을
GET /hub/admin-stats하나로 (2026-09-22 추가, w6-admin-stats-api) — ✅ 반영됨 —w6-admin-stats-wallboard완료,hubClient.ts가 그 API 를 부른다(main 확인, 2026-09-23). 원문 — 관리자 토큰으로 부르면 여덟 칸(통화 전체·종료·콜 가드·승인 대기·활성 등록·배정 판정 셋)이 문자열로 온다. 「완료 통화 누적」을calls_total과calls_closed중 무엇으로 보일지는 화면 결정. 배정 셋은 부르는 곳(w7-j5-routing-caller)이 붙기 전엔 0 - 09-22 운영 확인 — PR #111(
0.1.25)이 프론트보다 먼저 나갔다 — ✅ 2026-09-23 세 건 다 프론트에 들어왔다 — 카드 피드백 토큰 · 관리자 반려 사유 · 온도null표시. 운영 번들에서 확인했다. 원문 — 운영 마이그레이션은 정성윤 님이 넣었다. #116 으로closeCall토큰은 들어갔고, 남은 셋이 운영에서 깨져 있다: 카드 「사용 표시」(토큰 없음 → 조용히 401) · 관리자 반려(사유 없음 → 422) · 온도 이상 null 이 「0건」으로 보임(toNum(null)). 고칠 곳은 위 「조서희 님」 넷 중 셋 - 정성윤 님 — 관리자 블랙리스트 승인·해제 운영 확인 (2026-09-22 추가, w6-admin-agent-mapping) — ✅ 2026-09-22 수동 QA 에서 확인했다 — Q-62 에서 승인 1 · 반려 1 이 409 없이 처리됐고 처리자(
decided_by)도 남았다(진행 기록2026-09-22-18-seongyun). 원문 —0.1.25부터 관리자가 처음 결정할 때 서버가 전용agent행(admin-<id>)을 붙인다(decisions/314, 운영자 SQL 불필요). 관리자 화면(admin.solidbob.cloud)에서 승인 1건 · 해제 1건이 오류 없이 되고 결정자가admin-<숫자>로 남는지 본다. 반려는 프론트 수정 전이라 422 다. 확인되면 티켓을 done 으로 - 조서희 님 — 상담원 「내 요청」 화면 (2026-09-22 추가) —
GET /hub/blacklist-requests/mine에 상담원 토큰을 실어 부르면 자기 요청의 상태·반려 사유(decision_note)가 온다. 어디에 보일지는 화면 결정 → 10-01 안 만든다 — 범위 밖(138) - 정성윤 님께 확인 — 백엔드 티켓 둘을 장민석이 넘겨받아도 되는지 (2026-09-22 추가) — ✅ 2026-09-22 넘겨받음 — 정성윤 님 12번 로그 「장민석 님께 넘기기로 한 둘」. 두 티켓
assignee를 장민석으로 옮겼다.w6-deploy-schema-precheck는 수동 QA 게이트(319) 뒤 착수. 원문 —w7-j5-routing-caller(콜 미디에이터가 통화 시작 직후 배정 판정 호출 — 서버 문은 09-22 에 잠갔다) ·w6-deploy-schema-precheck(release.yml에서 운영 스키마 대조 후 어긋나면 배포 중지). 둘 다todo라 넘겨받을 수 있지만 오늘 운영 작업이 활발해 겹칠 수 있어 먼저 묻는다
2026-09-22 최종 QA(페르소나 4 + 검증 웨이브) — 남은 것 (류준 정리)
원자료 data/processed/qa-2026-09-22/(gitignore). 합성 통화는 source: synthetic(STT 미경유) — 성능 수치가 아니다.
- C-5 글자 누출 — 「다나카 유이」의 「이」가 확정 자막·DB 에 남는다 (절대 규칙) — 류준 — SYN-017#12
*** *이. 규칙·NER 둘 다. 하네스 C-5 누락 0 은 골든셋에 이 형태가 없어서다 → 골든셋에 이름 끝 글자 경계 케이스 추가 + 규칙 보강. E2E 판정기는 이제 글자 단위로 ❌ 를 낸다(w6-replay-last-turn) → 2026-09-22 닫음(w6-c5-name-tail-leak) — 규칙_after_context가 「이」를 조사로 뗀 것. 같은 갈래(「소피아요」「첸 메이」 등)까지 고쳐 골든셋 글자 누출 규칙+NER 5→0 · 합성 대본 24건 1→0. 대가: 「란이에요」의 「이」 과잉 1턴 - C-5 중간 자막(interim)에 번호 앞자리가 가려지지 않고 나간다 — 류준·장민석 — ✅ 2026-09-28 운영 확인(정성윤). 어절이 늘어나는 중간 자막 7단계를 운영에 흘려 받아 보니
제 번호는 ***→*** ****→*************로 3자리에서 바로 가려지고 어느 단계에서도 앞자리가 보이지 않는다. 카드(9410 0000 …)·번호(010 …) 두 모양을 한 통화에 같이 넣었고 둘 다 가려졌다. 확정 자막도 같다.decisions/324가 의도대로 돈다 — 코드는 장민석, 확인은 정성윤. 원문 — 류준·장민석** — ◐ 2026-09-22 코드 들어감(장민석, 배포 전) — 가설이 코드로 맞았다: 확정 규칙은 완성된 번호(10~16자리)만 잡는다. 중간 자막에만InterimMaskingAdapter를 얹어 3자리 이상 이어진 숫자(낭독형 포함)를 전부 가린다 — 확정·DB 규칙은 그대로. 배포 뒤 운영 표본으로 다시 본다. ⚠ 확정 자막도 번호가 두 발화로 쪼개지면 같은 구멍이 있을 수 있다(미확인). 원문 — 표본 6건 중 5건: 카드9410 0000·전화010 0000. 확정 자막·DB 는 가려진다(화면에만). 번호가 다 들어오기 전이라 패턴이 안 맞는 것으로 보인다(가설). 절대 원칙 3 「애매하면 가린다」 - 읽기 경로 인증 없음 — 운영에서 열려 있다 — 장민석 — ✅ 2026-09-23 2단계까지 켰다 — 정성윤. 조서희 님이 읽기 넷에 상담원 토큰을 실은 뒤(
24f7df4, PR #145) 운영server-env에READ_AUTH_REQUIRED=true를 넣고 재시작했다(이미지0.1.38그대로 — 코드 배포가 아니다)./healthread_guard: locked· 토큰 없는GET /hub/calls·/transcript·POST /hub/search전부 401 확인. ⚠ 닫힌 것은 바깥문뿐이다 —GET /hub/calls가 요청자를 안 보고call.agent_id도 안 채워져 로그인한 상담원끼리는 서로의 통화가 보인다. 그 절반은 w8-call-owner-scope 로 옮겼다(수동 QA Q-14 는 ⚠ 로 적는다). 원문 — ◐ 2026-09-22 서버 1단계 들어감(decisions/322, 배포 전) — 읽기 넷은 상담원·서비스 토큰을 받는다(틀리면 401, 안 실으면 아직 지나감 ·/healthread_guard). 지식 공백은 바로 닫았다(조회·상태 변경 관리자 · 신고 상담원 · 설명 마스킹 후 저장). 남은 것: 상담원 화면 토큰(w6-read-path-token-ui, 조서희) →READ_AUTH_REQUIRED=true. 원문 —GET /hub/calls(토큰 없이 12건 · 실제 음성 테스트 통화 포함 · 고객 HMAC ·?customer_id=필터) ·/transcript·/record·GET/POST/PATCH /hub/knowledge-gaps(설명이 마스킹 없이 저장) ·POST /hub/search. 기존 미결 「남은 것은 읽기 경로」와 같은 건 — 09-30 전에 닫히지 않은 가장 큰 구멍 - 절차가 쌓이기만 한다 — 정성윤·조서희 — 1순위 규칙 뒤에도 엉뚱한 판정 67행 중 57행(85%)이 이미 잡힌 절차의 재판정. 빼는 규칙은 화면과 함께. 또 SYN-005·022 는 정답 절차가 1순위였던 적이 없어 틀린 판정만 남는다 → 10-01
219하한으로 엉뚱한 쌍은 줄었고 나머지는 알려진 한계(138) — 닫는다 - 대시보드 — 조서희 — ◐ 2026-09-28: ②~⑥ 은 09-23 에 끝났다(류준 인계 문서 1.5절). ① 은
started로 이르게 잡기(09-23) + 빈call_id덮어쓰기 차단(09-28,keepCallId)까지 — 운영에서 추천 0건 통화/close200 을 아직 눈으로 안 봤다(w6-close-callid-missing). P1 셋은 같은 날 화면 쪽을 끝냈다 — 발화별 「관련 문서 없음」에 필요했던 미디에이터segment_id는 같은 날 정성윤이 넣었다(0.2.11, PR #154) — 배포 뒤 운영 눈 확인만 남았다(w6-per-utterance-no-docs). 원문 — ① 미발동 추천의call_id누락으로callId가 빈 문자열이 돼/close404(요약·확정·블랙리스트 요청 사라짐,realCallMediatorClient.ts:384) ② 서버 컴플라이언스(C-1~C-4) 방송을 받아도 그리지 않는다 ③ 「미측정(null)」→「0건」(316 위반) ④ 위기 신호가 같은 구간 폭언 배지에 덮임 ⑤ 소개 페이지의 측정 안 한 「92%」「38%」(절대 원칙 2) ⑥ 블랙컨슈머 카드가 mock 인데 「관리자에게 전송됨」 → 10-01 ① 은w6-close-callid-missingdone(QA Q-50~53) — 닫는다 - 재생기 마지막 턴 유실 원인 — 정성윤 — 코드로 보면 재생기가 일찍 닫아도 DB 저장은 빠지지 않는다(가설 기각). 남은 가설: ① 마지막 확정이 미디에이터에 안 닿음 ② 미디에이터→서버 전사 실패 — 운영 미디에이터 로그에
전사 전달 실패 call=syn-prod-syn-010-20260922가 있으면 ② → 10-01w6-replay-last-turndone — 닫는다 - 테스트·CI 위생 — 공동 — ✅ 2026-09-23 확인 — 남은 것은 「설계된 skip」 뿐이다. ①
test_eval_wiring은v1-150.json을 읽는다(F-2 skip 해소) ② 삭제 도메인 전제 ES 테스트 2건은 09-22 재작성됐고 통합 테스트는 임시 인덱스만 쓴다 ③ 프론트 테스트는 vitest 11건이 CI 에서 돈다 ④CLAUDE.md§2.5 는 09-22 에 「F-2 99건 채점·통과」로 갱신됐다. 남은 skip 5건은 CI 에transformers·elasticsearch가 없어서다(로컬server에서도test_main_pii_ner1건만 skip,ai는 0건) — 모델을 CI 에 올리지 않기로 한 결과라 결함이 아니다. 원문 —ai/tests/test_eval_wiring.py가 옛 v1-50 을 읽어 F-2 검사가 늘 skip · ES 통합 테스트 2건이 삭제된 SHOP/HLT 도메인을 전제로 실패 + 공유 인덱스callguard-kb-single을 지우고 벡터 없이 다시 만든다 · CI server job 이 5건 skip(elasticsearch·transformers없음) · 프론트 테스트 0 ·CLAUDE.md§2.5 「F-2 0건 — 측정 불가」→ 실제 99건 채점·통과 - D-2 문의 유형이 24/24 NULL — 장민석 — ✅ 2026-09-22 지식베이스 장 어휘 규칙표로 제안한다(
decisions/323, 배포 전) — 안 걸리면 여전히 None. 측정 안 됨(D 케이스 0건). 원문 —/close는 요약을 저장하지만inquiry_type이 비어 있다(판정기는 요약 길이만 본다) - J-5 시연 준비 — 장민석 (2026-09-22 추가) — ◐ 같은 날 미리 만들었다 —
scripts/persona_sim/seed_demo_agents.py(페르소나 A01~A06 →demo-A01~demo-A06행 + 입사일, 토큰은 즉시 폐기) · 매니페스트ROUTING_CANDIDATES에 그 여섯(런북 12-2-c). 남은 것: 배포 뒤 관리자 토큰으로 스크립트 한 번 · 테스트 통화로routing_log확인. 원문 — 배정 판정 호출(320)과 입사일 API(321)는 들어갔다. 시연에서 SYN-007 이veteran으로 나오려면 운영에서 셋이 남았다 — ① 시연 상담원 입사일 넣기(PUT /admin/agents/{id}/hired-on, 관리자 토큰 · 화면은w6-admin-agent-hired-on-ui) ②ROUTING_CANDIDATES에 그 상담원agent_id들(미디에이터 시크릿·매니페스트 — 비면 늘 「후보 없음」) ③ 테스트 통화 1건으로routing_log행 확인. 페르소나 상담원(A01~A06)은 대본 배역이라 운영agent행과 이어져 있지 않다 — 어느 행을 시연 상담원으로 쓸지부터 정한다. 입사일은 페르소나 설정에 맞춘 시연용 값이다(측정값 아님) → ✅ 2026-09-22 저녁 정성윤이 시드 실행 —demo-A01~A06행 생성(A03 근속 7년) · SYN-006 → 요청·승인 → SYN-007 에서 베테랑 배정 확인. eval_run.components마이그레이션 — 운영 DB (2026-09-22 추가, 장민석) —db/migrations/2026-09-22-eval-run-components.sql. 서버 이미지와 무관하지만scripts/run_eval.py --record로 운영 DB 에 기록하기 전에 넣어야 한다(없으면 INSERT 실패). 배포 전 스키마 대조(decisions/128)가 붙으면 넣기 전까지 어긋남으로 잡힌다. 넣는 사람: DB 접근이 있는 사람(정성윤) → ✅ 2026-09-22 19:57 운영 적용(정성윤, 해시 대조 후 서버 파드에서). 배포 전 스키마 대조 어긋남 0(29 테이블 · 200 컬럼).
2026-09-22 밤 — 류준 티켓 일괄 처리 뒤 남은 것
- 엉뚱한 필요서류 판정 31쌍·186행(대본 24건 중 17건) — 류준 — ✅ 2026-09-24 점수 하한(C2, f=0.635)을 채택해 기본값으로 바꿨다(
decisions/219확정, 사전 등록 규칙을 기계적으로 적용 — 류준 결정, 팀 회의 합의 없음). 보류 표본 12건에서 10쌍·42행 → 3쌍·12행, 정답 절차 8/8 그대로. v0 24건은 31쌍·186행 → 21쌍·127행, 15/17 그대로. 떨어진 후보: C1(연속 두 번)·C3(C1+넓힌 맞장구 억제)은 필요한 절차를 8건 중 7건 잃었다. 운영 반영은 배포 태그가 올라간 뒤다. 원문 — 1순위 규칙으로 75→31쌍 줄었지만 맞장구·잡음 발화의 1순위가 절차가 되고 누적된다. B-6 문턱(215)을 켜면 10쌍이지만 필요한 카드가 사라진다 — 두 결정이 부딪친다. 새 표본으로 사전 등록 → w6-procedure-noise-redesign - 절차 누적이 남았다 — 류준·조서희 — 한 번 잡힌 절차는 내려가지 않아 상담원 발화마다 다시 판정된다(엉뚱한 «행»이 «쌍»의 4배인 이유). 새 절차가 잡히면 이전 절차를 내리는 동작은 절차 패널이 사라지는 화면 동작이라
apps/call과 함께 정해야 한다 — 219 후보에서 일부러 뺐다. 남은 3쌍(SYN-108 되묻기의 오답 1순위 · SYN-109 시 소관 아닌 민원)은 점수로 못 거른다 — 검색(B-2/B-3) 쪽 문제다 → 10-01 알려진 한계(138) — 닫는다 - 여권 조항 4.23 이 dense 에서 무관한 질문에 끼어든다 — 류준·장민석 — 로컬 E2E 대본 15개에서 카드 25장(여권을 말하는 대본은 1개), 골든셋 GS-702 운전면허는 1위. 그래서 필요서류 규칙표에서 제외했다(
decisions/217). 규칙은 끼어듦을 먼저 본 뒤 — 장민석 → 10-01 규칙표에서 제외(217)로 정착 — 닫는다 - 장민석 님 사후 검토 — 09-22 류준이 고친
server/— ✅ 2026-09-23 정성윤이 대신 봤다(decisions/302—server/는 누구나 본다. 장민석 님이 다시 볼 필요는 없지만 이견 있으면 말해 주면 된다). 셋 다 통과. ①name_detector.py— 「벗긴 조사가이로 시작하면 그 글자까지 가린다」는 원칙 3(애매하면 가린다)과 방향이 같다. 과잉은 조사 한두 글자뿐이고 누락은 절대 규칙이다. 조건 셋(이어진 어절 · 성씨+두 글자 · 문장 끝 홑 「이」)이 주석으로 근거까지 남아 있다. ⚠ 한계:_FOREIGN_SURNAMES_1은 하드코딩 목록이라 표본 밖 성씨에는 여전히 약하다 — 「호칭·문맥 없는 이름은 못 잡는다」와 같은 한계로 함께 적는다. ②closure_rule.pyEXCLUDED의DASAN-TERM-4.23—decisions/217근거가 값 옆에 문장으로 붙어 있다. 게이트(gate.py)가 그 목록을 보고 판정하지 않는다(거짓 판정 방지). 맞다. ③eval_run_repository._MODULE_ID의generation→B-4·postcall→D-1— 다른 행(call_guard→C-6·call_temperature→D-5)과 같은 규칙이고VARCHAR(10)넘침도 막는다. 맞다. 원문 — ①masking/name_detector.py(이름 끝 「이」·첫 어절 한 글자 성씨·호칭 경계에 괄호) ②closure_gate/.../closure_rule.pyEXCLUDED에 4.23 ③eval_run_repository.py_MODULE_ID에generation→B-4·postcall→D-1 - D-1 통화 후 요약이 서류·후속 조치를 놓친다 — 장민석(D-1)·류준 — ✅ 2026-09-23 고치고 같은 하네스로 다시 쟀다 — 정성윤. 규칙 발췌에 세 줄을 더한다(전부 자막에 있는 문장 그대로, 지어낸 문장 0 —
decisions/306): 필요서류 안내(서류 어휘가 든 상담원 발화 최대 3) · 후속 조치(이미 뽑던 D-3 을 요약에도 싣는다, 최대 5) · 마무리 안내(마지막 실질 상담원 발화). 핵심 항목 21/60 → 53/60(micro 0.35 → 0.883) · 갈래별 서류 2/23 → 23/23 · 조치 1/10 → 9/10 · 요청 5/7 → 7/7 · 문의 10/10 유지. 요약 길이 중앙값 160 → 373자. 측정:scripts/run_eval.py --no-ner, 골든셋postcall-v1.json10통화 60항목, 2026-09-23. ⚠ 남은 갈래는 「안내」 4/10 — 못 잡은 것은 「소관 부서 심사로 정해짐」·「대출 범위 제한」처럼 여러 발화에 흩어진 설명이라 한 줄 발췌로는 안 된다. 생성 요약(런북 14장)이 붙을 때 다시 잰다. 원문 — 장민석(D-1)·류준** — 새 채점(decisions/218)에서 핵심 항목 0.35(21/60), 서류 2/23 · 조치 1/10. 규칙 발췌가 「첫 실질 고객 발화 + 바로 뒤 상담원 발화」 두 줄뿐이라 중·후반 안내를 놓친다. 후보: 마지막 상담원 「정리하면 …」 발화도 싣기(측정 안 함). 유형은w6-d2-inquiry-type-null뒤에 숫자가 된다 - D-2 유형 이름표가 두 벌이다 — 류준·장민석 — ✅ 2026-09-23
ai/를 운영 쪽으로 맞췄다 — 정성윤.postcall_summary의CHAPTER_TO_TYPE값을 「대중교통 안내」→「대중교통」 식으로 운영 유형표(server/apps/postcall/.../inquiry_rules.py,decisions/323)와 글자까지 같게 했다. 어느 장이 투표하는지는 그대로다(6장은 여전히 표 밖 — 넣으려면 표본으로 재고 따로 정한다). ⚠ 지금 운영에는 영향이 없다 — 모델 스포크는OLLAMA_URL+GENERATION_MODEL이 둘 다 있어야 꽂히는데 운영에 없어서 규칙 어댑터(운영 유형표)만 돈다. 모델을 켜는 순간 두 벌이 섞여 들어갈 자리를 미리 막은 것이다.ai테스트 넷을 새 이름으로 고쳤고 전량 초록. 원문 — 운영(server/apps/postcall,decisions/323) 「대중교통·상하수도·일반행정·감염병·재난·생계 지원금」 vsai/apps/postcall_summaryCHAPTER_TO_TYPE「대중교통 안내·생활하수도 관련 문의·일반행정 문의·코로나19 관련 상담」. 정답 파일은 운영 쪽에 맞췄다(218). 모델 요약 경로(ai/)를 켜면 다른 이름이 저장된다 — 하나로 합칠 것 - 마지막 턴 유실 원인 — 실패 종류만 남았다 — 정성윤(선택) — ✅ 2026-09-23 운영 로그에 원인 ②의 흔적이 없다 — 콜 미디에이터 48시간 로그에
전사 전달 실패0건. 재생기 쪽(w6-replay-last-turn, 류준)이 09-22 에 「마지막 확정을/ws로 확인하고 닫는다」로 고쳐진 뒤로는 재현되지 않았다. 다시 나오면 그때 원인 ①(미디에이터에 안 닿음)부터 본다. 원문 — 원인은 ②(미디에이터→서버 전사 저장 실패)로 판정했고 재시도로 막았다(call_registry.ts, 로컬 재현 전후 4/5→5/5). 시간 초과·5xx·연결 끊김 중 무엇이었는지는 09-22 12:20 무렵 운영 미디에이터 로그로만 가른다 — 급하지 않다
2026-09-24 — 판정 자료 수치 정합에서 남은 것 (류준)
- 오류 내성 곡선이 한 세대 낡았다 — 류준 — 지금 인용 가능한 곡선은 커밋
e966b62· 골든셋v1-150.1· 검색 n 96 · C-5 판정 24(data/processed/error-tolerance/2026-09-22-all.json)인데, 본 표는5b2b4c4·v1-150.2· n 102(run_id 8·9)다. 같은 문장에서 두 표의 숫자를 섞지 않는다는 경고를 문서 세 곳(판정 초안 §3-1 ·STATE.md「실측값」 ·jekyll/docs/06)에 붙여 두었지만, 근본 해결은 동결 커밋에서measure_error_tolerance.py를 다시 돌리는 것이다 → w8-final-eval-run → 10-01 재측정은 발표 뒤 · 「한 세대 앞 판」으로 인용(decisions/138) - 기준선이 BM25 구성 하나뿐이다 — 류준·팀 —
scripts/check_baseline.py의 0.812/0.635 는 BM25 기준선 run_id 4 값이다(절대 원칙 4 대로 최저치를 둔다 — 올리지 않았다). 운영 실구성(NER+KoE5 dense)에는 기준선이 없다 — 그 구성 리포트에 이 값을 들이대면 느슨하다(run_id 8 은 0.971/0.875). 구성별로 기준선을 둘 것인지는 팀이 정할 일이다 → 10-01 구성별 기준선은 최종 측정 뒤(decisions/138) - D-2 유형 정확도 1.0 은 기록된 run 이 아니다 — 류준 — 판정용 run_id 8·9(커밋
5b2b4c4)는decisions/323머지 전이라 리포트에 「측정 불가 — 유형이 null」로 찍혀 있다. 09-22 밤의 1.0(10/10)은--record없이 잰 값이고, 5종 중 3종(일반행정 4·상하수도 3·대중교통 3) 표본이다 — 감염병·재난·생계 지원금은 0건(decisions/2182026-09-24 절). 판정문·발표에 쓰려면 다시 잰다 → 10-01 발표에서 D-2 는 「측정 불가」로 인용(138) — 닫는다 → 10-02 정정 — 10-01 최종 측정에 값이 기록됐다. 운영 RDSeval_runrun_id 1·2(커밋19b8400· 3회 최저)의postcall.type_accuracy1.0 ·type_null0 · n 10통화(data/processed/eval-export/2026-10-01-final-*.json). 표본은 여전히 5종 중 3종이다 — 인용할 때 「10통화 · 3종」 을 붙인다 - run 8·9 의
eval_run.components가 NULL 이다 — 류준 — 컬럼은 생겼지만(759b3d4, 09-22 16:53) run 8·9 는 그 11분 전 커밋(5b2b4c4, 16:42)에서 돌았다. 두 run 의 구성은data/processed/eval-export/2026-09-22-run-8-9.json과 명령줄에만 있다. 동결 측정에서는components가 두 구성에서 다르게 찍히는지 확인한다 → 10-01 정본 인용 시 명령줄로 구성을 밝힌다(138) — 닫는다
2026-09-28 — 류준이 정성윤에게 넘긴 다섯 건, 전부 처리 (정성윤)
_project/handoff/2026-09-24-ryujun-conflicts.md §1-⑥. 다섯 다 닫혔으니 새 미결로 남기지 않고 결과만 적는다.
- 런북 17장 지식베이스 적재 확인이 401 이었다 —
POST /hub/search를 토큰 없이 부르는 절차였다. 09-23 부터 읽기 문이 닫혀서(READ_AUTH_REQUIRED=true) 그대로는 401 이다. 19장처럼 노드에서 서비스 토큰을 읽어Authorization: Bearer로 싣게 고쳤다(값은 찍지 않는다). 런북 전체를 훑어 토큰 없는 읽기 호출은 이것 하나뿐이었다. - 배포 뒤
procedure_adoption눈으로 확인 —0.2.10배포 직후/call-mediator/health에"procedure_adoption": "score-floor"확인./health의spokes에retrieval_dense도 있다(하한이 dense 눈금 위에서 걸린다는 뜻). - 되돌리는 손잡이 —
infra/k8s/base/call-mediator.yaml:64에F2_PROCEDURE_ADOPTION: "top1"이 주석으로 있다. 확인했다. 시연 중 절차가 안 뜨면 주석을 풀고 적용한다 — 이미지 재빌드는 필요 없다. - 배포 중 WebSocket 끊김 — 머지 시점에
active_calls: 0이었고 미디에이터·서버 파드 둘 다 재시작 0으로 한 번에 떴다. - CI 가
scripts/persona_sim/tests/를 하나도 안 돌린다 —aijob 에 한 단계로 붙였다(새 job 을 만들지 않았다). job 이름은 main 룰셋의 필수 통과 검사라 늘리면 룰셋과.github/ruleset-main.json을 같이 고쳐야 하고, 그 동기화를 놓쳐 PR 이 머지되지 않은 적이 두 번 있다(CLAUDE.md§7). 내용도ai/쪽이고 스택 없이 0.1초에 도는 순수 판정 함수라 의존성도 더 필요 없다. 28건이 이제 모든 PR 에서 돈다.
2026-09-30 — 수동 QA 2회차에서 남긴 것 (정성윤)
결과표는 진행 기록 2026-09-30-01-seongyun. 게이트(decisions/319)는 통과했고, 아래는 그 과정에서 새로 보인 것이다. apps/ 항목은 조서희 님 몫이라 티켓을 만들지 않고 여기 적는다. → 09-30 decisions/137: 마감까지 정성윤이 apps/ 도 고친다. 아래 [x] 는 그날 코드로 닫은 것(배포 전).
- 조서희 님 — Q-29 ❌ 「상담원 보호 알림」 배너가 실서버 모드에선 원천적으로 안 뜬다 —
CustomerRiskBanner는 mock 감지기(detectCustomerRisk)만 켤 수 있고, 실서버에선 서버 콜가드 결과를 자막 줄 안의 「🚫 콜가드」 행으로만 그린다(TranscriptPanel.tsx:555~561). 1회차 「닫을 배너 자체가 안 떴다」와 같은 건 —w6-qa-call-screen-fixes의 「보호 배너」 항목 → 09-30 고쳤다(정성윤,decisions/137) — 실서버 콜가드 행에 「🚫 상담원 보호 알림」 핀·갈래별 문구·✕ 닫기(CALL_GUARD_COPY). 배포 전. 로그2026-09-30-03 - 조서희 님 — Q-30 ⚠ 콜가드 갈래가 화면에서 구분되지 않는다 — 서버는
insult·threat·sexual·distress를 나눠 보내는데(call_guard_dto), 위기 신호를 뺀 셋은 전부 「고객이 흥분한 상태입니다. 안내는 이어가시면 됩니다.」다(TranscriptPanel.tsx:731~735). 협박(threat, DASAN-MANUAL-5.2 즉시 종료 대상)에 「안내는 이어가라」가 나가 매뉴얼과 반대다. SYN-006 에서 성희롱·모욕·협박 세 갈래가 같은 문구였다 → 09-30 고쳤다 — 갈래별 문구(insult 5.1 · threat/sexual 5.2 · distress 5.4). 같은 수정 - 조서희 님 — Q-55 ❌ 「새 통화 시작」이 실서버 모드에서 아무것도 안 한다 —
replay()가client.mode !== "mock"이면return(useCallMediatorSession.ts:134~140). 통화 후 처리 화면의 버튼과 헤더 「새 통화 시작」 둘 다 이 함수를 부른다. 실서버에선 「대기화면」으로 나가는 것이 답이거나 버튼을 숨겨야 한다 → 09-30 고쳤다 —startNewCall: mock 은 재생, live 는 대기화면으로(useCallMediatorSession.ts) - 정성윤 — 콜 미디에이터가 채널이 전부 닫혔다 다시 열리면 통화 상태를 잃는다 —
dropIfEmpty(call_registry.ts:244)가 통화를 지우고, 같은 ID 로 다시 열면 발화 번호만 이어 붙이고(w6-segment-id-reuse)procedures·agentFinals·customerTops는 빈 채로 시작(:262~266). 그래서 채택된 절차가 있는데도 상담원 서류 안내가 판정에 안 돌고(QA-02에서/hub/required-docs-checks0회), 다시 열 때마다POST /hub/routing-decisions가 새로 불려 배정 판정이 중복 기록된다(한 통화에 10회+ — 현황판 「배정 판정 전체」 수치에 섞여 있다). 실제 2채널 통화에선 드물지만 재연결·파드 재시작 때 같은 일이 난다. 상태를 서버에서 되살릴지, 통화 종료(/close) 전까지 미디에이터가 들고 있을지 정한다 → 09-30 고쳤다 — 채널이 모두 닫혀도 5분 유예(CALL_RETAIN_MS) 동안 절차·상담원 발화를 잇고 배정 판정은 통화당 한 번. 서버 통화 행만 다시 확인(UPSERT). 테스트 3건, call-mediator0.2.12 - 정성윤 — 개발 페이지(
/call-mediator/dev)가 음성 인식 오류를 삼킨다 —rec.onerror가not-allowed만 알리고network·audio-capture·aborted는 조용히 다시 켠다. 이 PC 에선 8번 연결하고 글자가 한 자도 안 나왔는데 화면에 이유가 없었다. 오류 이름을 상태 줄에 찍기만 해도 된다(QA 도구 결함 — 운영 기능 아님) → 09-30 고쳤다 — 인식 오류 이름을 상태 줄에 그대로, 마이크가 안 돼도 **글자 입력 칸으로 확정 발화를 보낸다(같은/dev/text).0.2.12** - 팀 — 관리자 화면의 고객 표시가 전부
****라 항목을 못 알아본다 —decisions/316이display_hint를 채우지 않기로 한 결과가 블랙리스트·승인요청·감사 로그 세 곳에 그대로다. QA 중 「다 가려져 있어서 잘 안 보인다」(정성윤). 시연에서 관리자가 어느 요청인지 못 가리는 문제라 뒤 4자리 표시를 다시 열지 정한다(316 재검토) → 10-01 뒤 4자리를 연다(144, server 0.1.44) — 닫는다 - 조서희 님 — 화면 잔손질 묶음(2회차 관찰, 판정 아님) — ① 관리자 설정 탭 안내문·팝업창 카드 본문에 마크다운 원문(
**기본값**·`decisions/205`) 노출 ② 지난 통화 보기의 카드 제목이DASAN-TERM-4.3처럼 조항 ID 만(panelCardsFromRecord합성) ③ 우상단 「서류 0/1 안내 완료」가 카드 둘 중 첫 카드만 셈 ④ 근속 연차 도움말 「저장하면…」인데 버튼 없이 즉시 저장 ⑤ 요약 화면 「(규칙 발췌 초안)」 꼬리표가 확정·재수정 뒤에도 남음 ⑥ 「권장 표현」 자리에 대체 문장이 아니라 조항 ID(alternative_source.title) ⑦ 최근 상담기록 목록에 call_id 가 없어 QA 통화를 못 알아봄 ⑧ 자막 시각이 채널 재개마다 00:00 으로 리셋(재개 상황 한정) ⑨ 09-30 승인 항목 만료가 2027.1.28 — 6개월이면 3.30 이어야 한다(입력값이었는지 확인) → 09-30 ①③④⑥⑦ 고쳤다(마크다운 인라인 렌더 · 근거 합산 칩 · 도움말 문구 · 「근거 조항」 머리말 · 목록에 call_id). **남은 것 ②⑤⑧⑨ — ② 는/record응답에procedure_title이 없어 서버 몫(call_record_schema.py), ⑤ 꼬리표, ⑧ 재개 시각, ⑨ 승인 개월 입력값 확인** - 류준 님 — 요약이 위반 발화를 「안내」로 인용한다 — D-1 규칙 발췌가 C-1·C-3 경고가 붙은 상담원 발화(「무조건 공제됩니다」·「위임장까지는 없어도」)를 「상담원 안내/필요서류 안내」로 그대로 싣는다. 컴플라이언스 결과를 발췌 후보에서 빼거나 표시를 붙일지 정한다. 같이 본 것: 팝업창 3.16 카드 본문 끝에 다음 장 제목
## 4장 일반행정 문의조각이 붙어 있다(청킹 경계) → 10-01 10-01 위반 발화를 발췌에서 뺐다(server 0.1.44).## 4장청킹 조각은 알려진 한계 - A-2 화자 분리는 이 QA 로 검증되지 않았다 — 스크립트도 개발 페이지도 화자를 사람이 지정한다. Q-31~33 은 「상담원 줄에 경고가 붙는가」까지다.
speaker=auto실검증은w7-demo-infra-readiness(게이트 통과로 이제 착수 가능) → 10-01 미검증으로 발표(138) — 닫는다
2026-09-30 — 티켓 정리 뒤 남은 것 (정성윤)
- AWS 7월 잔재 삭제 — 사용자 결정 —
w4-aws-resource-hygiene의 명령(VPCvpc-0a2f05f0b6898780f·admin-security·launch-wizard-1· 쓰지 않는rds-monitoring-role). 되돌릴 수 없어 정성윤이 직접 «지운다» 고 해야 한다. RDS 권장 2건은 informational 이라 안 한다 → 10-01 사용자 결정 「티켓 닫아」 — 삭제 안 함, 종료 정리에서(w4-aws-resource-hygienecancelled) - 운영 지연 측정 —
!로 한 번 → 09-30 22:55 했다. 최근 7일 n 26 p95 655ms(예산 안) · 전체 n 115 p95 1,118ms(옛 실험 구성 섞임).w7-latency-budget에 표. 남은 것은 표본 확대(리허설)와e2e—scratchpad/qa-latency-check.sh(읽기 전용 SELECT). 값이 나오면w7-latency-budget에 §5 네 조건과 함께 적는다 - 눈 확인 두 개(각 1분) — ① 화면을 연 채 SYN-007 재생 → 「배정 판정 기록됨」 배너(
w6-routing-result-ui) ② 관리자 설정 탭에서 상담원 한 명 입사일 입력 → 목록 갱신(w6-admin-agent-hired-on-ui) → 10-01 아래 「완성 절차 뒤 남은 것」으로 옮김 - 지난 통화 보기 카드 제목이 조항 ID —
GET /hub/calls/{id}/record의closures[]에procedure_title이 없다(call_record_schema.py). 서버가 규칙표 제목을 실어 주면 화면은procedure_title ?? procedure로 이미 받는다(server 한 판) → 10-01 10-01/record에procedure_title실음(server 0.1.44) — 닫는다 - 시연 날짜가 정해져야 하는 것 — STT 캡 올리기·되돌리기(
w7-demo-infra-readiness) · 리허설(w8-demo-rehearsal) · 발표 구간(w8-presentation).speaker=auto실검증은 오디오 파일이 있어야 한다 — 없으면 발표에 「미검증」으로 적는다 → 10-01143절차 +138동결로 날짜 없이 준비 — 닫는다
2026-10-01 — 완성 절차 뒤 남은 것 (정성윤)
배포 + 마이그레이션— 10-01 PR #157(마이그레이션 → 0.1.44 · 0.2.12) · #158(화면 수정) · #159(측정 폴백·룰셋) 끝. QA 3회차 ✅: Q-29·Q-42 재개·뒤 4자리·요약 위반 제외·배정 배너·입사일·위기 신호 핀. 지난 통화 제목·카드 하나(#158)는 아직 다시 안 봤다눈 확인 둘— 배정 배너(QA 3회차 + act4demo-A03) · 입사일 저장 ✅(사용자 확인) · 근속 연차 표시(#158)는 배포만 — 다시 보지 않았다(10-01 밤 정정, 처음에 ✅ 로 적은 것은 과장)네 번째 배포 뒤 재확인— 10-01 저녁 운영에서 둘 다 봤다:?call_id=check-mix-01화면에 다른 통화(act3)가 섞이지 않음 · 지난 통화 보기(demo-act3-01) 카드 3.4·3.3·3.16 이름으로, 중복 없음(진행 기록2026-10-01-08·09)- 녹화 때 찍을 것 — act4 끝에 「요약 확정」(
w6-close-callid-missing조건 2). 온도 「미측정」 은 10-01 저녁에 봤다(check-mix-01) - 카드 본문에 다음 장 제목이 새어 들어옴 — 지난 통화 보기 3.16 요금 이의신청 카드 본문 끝에 「## 4장 일반행정 문의」 가 붙어 보인다(10-01 저녁 캡처). 청크 경계가 다음 절 제목을 물고 있는 것으로 보이나 원인은 재지 않았다. 판정에 영향 없고 발표 뒤(
138동결) - 「여보세요」 과잉 마스킹 — act4 에서 「여보세요 들리시나요」→「*** 요 들리시나요」. 원인(「여보세」를 이름으로 본 NER 추정)은 재지 않았다. 누락 0 > 과잉 억제(원칙 3)라 발표 뒤. 대본 1막·2막 첫 줄은 「안녕하세요 다산콜센터입니다」라 안 걸린다
- 시연 영상 —
_project/demo-script.md, 두 번 녹화 →w8-demo-rehearsaldone — PR #159(10-01),appsCI 잡을 룰셋 필수 검사에 올린다ruleset-main.json같이- 회고 단락 셋 — 류준·장민석·조서희가
docs/17에 직접 - 발표일·형식 — 정해지면
129·w8-presentation에 적고 초안(_project/__008)을 그 틀로 - 종료 정리 — 발표 뒤(
w8-project-closeout): 남길 것 결정 → 자원 내림 → 키 폐기 → 청구서 0 확인. AWS 잔재도 그때
2026-10-01 밤 — 최종 점검에서 나온 것 (정성윤)
- 녹화 때 같이 볼 것 셋 — 관리자 현황판 「오늘」 타일 · 설정의 근속 연차 표시 · 상담원 화면 재연결(탭을 둔 채 Wi-Fi 를 껐다 켠다). 셋 다 배포·테스트만 있고 운영에서 본 기록이 없다
- 글자 채널 대본 통화의 내부 지연이 예산을 넘는다 —
synthetic-scriptn 92 p95 2,404 ms(예산 1,000), 최악은 배포 직후 첫 act1(p50 2,406 · max 4,719). 음성 통화(n 25)는 p95 722 로 예산 안. 원인(모델 예열 / NER·임베딩 CPU 경합)은 재지 않았다. 녹화는 act1 을 한 번 예열한 뒤 한다(_project/demo-script.md). 발표 뒤 측정 done티켓에 남은 미체크 완료 조건 — 61건 104줄. 읽어서 가르니 대부분은 뒤에 충족됐거나(운영 반영·QA 로 확인) 줄 안에 「넘김·보류·해당 없음」 이 적힌 것이고, 실제로 미충족인 것은 열 건이다(10-02 — D-2 유형 채점은 10-01 최종 측정에 값이 있어 뺐다):w4-gateway-mono-diarization(화자 분리 실검증) ·w4-recommendation-card-id(지연 증가분 미측정) ·w5-persona-sim-scripts(대본 사람 검토) ·w5-c5-masking-gaps(장민석 검토 2줄) ·w5-error-curve-plot(모델 계열 한 그림 · 실을 곳) ·w5-b6-no-answer-threshold(「소관 안내」 대 「관련 문서 없음」) ·w6-b6-threshold-decision(추천 경로에서 카드 0장 운영 확인) ·w6-read-path-token-ui(로그아웃 탭 운영 확인) ·w7-agent-registration(Postgres 통합 테스트) ·w5-classifier-ner-benchmark(→cancelled로 고침). 옛 티켓 본문의 체크박스는 건드리지 않았다 — 그 시점의 기록이다. 발표에는 「알려진 한계」 로
2026-10-02 — 통화 후 모델 요약을 켜며 남긴 것 (정성윤)
.env.example에POSTCALL_MODEL=을 사람이 넣는다 — 보호 훅이 편집을 막는다.GENERATION_MODEL=아래 한 줄, 주석은 「D-1 요약만 모델로(decisions/146). OLLAMA_URL 과 둘 다 있어야 켜진다」- 모델 요약의 D-1 포함률은 미측정이다 — 하네스는 규칙 어댑터를 잰다(0.883). 모델 요약을 같은 10통화로 재려면 하네스에 Ollama 주소를 주고 돌린다(
run_eval.py --ollama-url) - 서버 등급 · 「상시 / 필요한 날만」 — 올린 직후 실측을 보고 정한다(
decisions/146갱신 절) → 10-02 새벽: 등급은c7i.2xlarge로 올렸고 쟀다(요약 한 건 2.5~8.0초). 남은 것은 상시로 둘지뿐이다 — 시간당 0.4032 USD(t3.large0.104). 고정 IP 가 있어 내렸다 올려도 주소는 그대로다 → ✅ 2026-10-08 정했다 — 등급은c7i.2xlarge로 유지하고 안 쓸 때 인스턴스를 내린다(사용자 결정). 요약이 느려지는 것은 받아들이지 않기로 했고, 고정 IP 가 붙어 있어 내렸다 올려도 CloudflareserverA 레코드를 다시 건드릴 필요가 없다. ⚠ 올린 뒤 첫 요약은 모델을 다시 올리느라 느리다 — 운영 실측 14.5초 · 10.7초, 그 뒤 3.7~3.9초(10-02). 올린 날은 예열 요청을 하나 던지고 시작한다(시연 대본의 「녹화 전act1예열」과 같은 이유). 내려도 루트 EBS · 고정 IP · RDS 요금은 계속 나간다 — 금액은 재지 않았다(Cost Explorer 로 봐야 한다). - 30분 쉰 뒤 첫 요약이 느리다 — 운영 실측 14.5초(모델을 다시 올리는 시간 포함, 그 뒤는 3.7초).
OLLAMA_KEEP_ALIVE=30m이라 30분 쓰지 않으면 모델을 내린다. 정할 것: 그대로 두고 촬영·발표 전에 버리는 통화로 깨울지, 모델을 계속 올려 둘지(메모리 약 2.2~2.7GB 를 상시 쓴다,ollama.yaml한 줄) → 10-02 새벽 정했다(사용자) — 모델을 계속 올려 둔다(OLLAMA_KEEP_ALIVE=-1). 파드가 새로 뜬 직후 첫 요청만 느리다. 배포 뒤 확인이 남는다 - 시험 통화
sum-model-1002-01이 운영 DB 에 남아 있다(10-02 운영 실측용 · 발신010-0000-0909) — 관리자 화면 통화 목록·오늘 타일에 잡힌다. 지울지 정한다 → 10-02 04:45 지웠다(사용자 지시 — 통화 1 + 딸린 행 115, 통화 58 → 57건) - 모델 요약이 같은 입력에 다른 글을 냈다 — Ollama 에서 temperature 0 · seed 고정인데 1막 요약이 142자 / 114자로 갈렸다(10-02 임시 실측, 두 번). 원인 미확인. 리허설과 본 촬영의 요약문이 다를 수 있다. 정할 것: 그대로 두고 발표에서 「초안이라 매번 조금 다르다」 고 말할지, 원인을 찾아 고정할지
2026-10-02 — 대체 표현 문장을 보내며 남긴 것 (정성윤)
- 지침만 있는 갈래 넷(1.6 · 3.1·3.4 · 3.2 · 4.1)은 여전히 조항 번호만 뜬다 — 매뉴얼에 권장 문장이 없고 「산정 기준과 조회 방법을 안내한다」 같은 지침뿐이다. 지침을 띄우려면 화면 머리말을 「권장 응대」 로 가르는 수정(
apps/callcomplianceLabel)이 같이 간다. 정할 것: 지침을 띄울지(w8-compliance-alternative-phrase) - 금지만 있는 갈래 둘(1.2 개인정보 요구 · 4.3 비공개 정보 약속) — 권할 문장이 매뉴얼에 없다. 띄우려면 매뉴얼에 문장을 새로 쓰고 ES 를 재적재해야 해서 발표 뒤다(
decisions/138) - 소개 사이트 시연 목업 카드 둘이 실물과 다르다(
apps/platform/src/mock/demoScenario.ts) — ① 00:21 컴플라이언스: 「저희가 해결할 수 있는 게 아니라서요」 는 실제 규칙이 잡지 않고(직접 넣어 확인), 「상담 품질 가이드라인 4.2항」 은 없는 조항이다(매뉴얼 4.2 는 에스컬레이션) ② 00:54 정서 위기: 「죽겠네」 는 C-6 이 일부러 면제하는 관용 표현이고, 「어조 격앙」 은 운영에서 돌지 않는 D-5 몫이며, 제목 「관리자 알림 발송」 이 본문 「연동 전」 과 모순된다.decisions/145가 정한 「목업」 꼬리말도 이 카드에는 빠져 있다. 정할 것: 실물이 잡는 문장으로 바꿀지 decisions/142제목의 「시연에서 동작하고」 는 실물과 다르다 — D-5 는 모듈·단위 테스트만 있고 서버 요청 경로에 배선이 없다(317). 시연 화면의 통화 온도는 「예시 라벨」 이다. 발표에서 「시연에서 동작한다」 고 말하지 않는다
2026-10-02 — 시연 촬영 중 나온 것 (정성윤)
- 개인정보만 말한 고객 발화가 절차 판정에 쓰인다 — 결함은 그대로, 대본만 피했다 — 시연 1막의 「제 이름은 이고요 주소는 **」 이 가려지고 나면 「이름·주소」 만 남아 검색 1순위가
DASAN-TERM-3.5(수도 사용자 명의변경, 0.653 ≥ 하한 0.635)가 되고 절차로 잡혔다(09-30 QA 에서 처음 확인, 10-02 운영 통화shoot1-a1에서 재현). 뒤의 상담원 「신분증 챙겨 오시면」 이 수도 쪽 서류까지 체크해 1/3 이 된다. 사용자 결정으로 **대본 문장만 바꿨다(「초본 받을 사람은 홍길동이고 주소는 …」 → 1순위4.30.763, 운영에서 확인). 고치려면 콜 미디에이터가 가려진 발화로는 절차를 새로 잡지 않게 한다(call_registry.tsrecommend) — 하한 0.635 는decisions/219사전 등록값이라 값을 바꾸는 길은 아니다. 「제 이름은 ***입니다」 만으로도 3.5 가 0.6345 로 하한 바로 아래다 - 개인정보 발화마다 관련 없는 카드가 팝업에 쌓인다 — 같은 통화에서 전화·카드·계좌·인증번호 줄의 1순위가 「6.12 지원금 사칭 사기 주의 안내」(0.667~0.713), 2순위에 「3.4 수도요금 자동납부」·「2.7 광역알뜰교통카드」 가 온다. 규칙표에 없는 조항이라 절차는 안 되지만 카드로는 남는다. 위 항목과 원인이 같다
- STT 하루 한도의 「하루」 는 UTC 다 — 한국 시간 09:00 에 풀린다 — 콜 미디에이터 장부가 파드의 로컬 날짜로 센다(
domain/budget.tslocalDay, 파드 시간대가 UTC). 10-02 새벽 촬영에서 전날 저녁(KST) 검증 두 번(240초)이 같은 날로 합쳐져, 세 번째 음성 통화shoot1-stt3가 8번째 턴에서 한도 600초에 닿아 끊겼다(로그 「STT 사용량 한도에 닿아 채널을 닫는다」). Claude 가 남은 양을 KST 기준으로 잘못 세어 「두 번 더 된다」 고 안내했다. 정할 것: 날짜를 KST 로 셀지, 문서에만 적어 둘지 - 음성 통화에서 영어를 한글로 받아 적은 말이 이름으로 가려진 것으로 보인다 —
shoot1-stt3의 「돈 * 아동 수당」·「* 엄마예요」(마스킹 P6 둘). 대본은 「돈, 음, child…」·「Yes, 네, 엄마예요」 다. 규칙만으로는 「차일드」·「예스」 가 가려지지 않는 것을 로컬에서 확인했으므로 운영의 이름 인식 모델(NER) 쪽으로 추정한다 — 원문을 저장하지 않아 어느 단어였는지는 확인할 수 없다. 짧게 끊겨 들어온 앞 통화(shoot1-stt)에서는 같은 말이 가려지지 않았다 - 음성 자막이 문장·쉼마다 끊긴다 — 음성 파일의 쉼을 줄여 피했다 — 발화 끝 기준 0.7초(
0.2.13)에 합성 음성의 쉼(약 0.9초)이 걸려 한 턴이 여러 줄이 된다(shoot1-stt상담원 8·고객 11줄). 기준은 그대로 두고 두 채널이 함께 조용한 구간을 0.3초로 줄인 파일(data/processed/stt-2ch/syn-004-tight-16k.wav, gitignore)로 한 턴 한 줄을 얻었다(shoot1-stt31~7턴). 실제 사람의 말에서는 기준을 올리는 것(로컬 예측 1.0초 이상이면 턴당 한 줄)이 남은 방법이다 — 재지 않았다 - 촬영 통화 일곱 건이 운영 DB 에 남아 있다 —
warmup-1·shoot1-a1·shoot1-b1(블랙리스트 요청 9 승인,****0903) ·shoot1-a2·shoot1-stt·shoot1-stt2·shoot1-stt3. 지울지, 시연 기록으로 둘지 정한다.0903은 승인돼 있어 다시 쓰면 통화 시작부터 배정 배너가 뜬다 → 2026-10-08 정했다 — 발표 뒤로 미룬다(decisions/138고정 갱신 절). 지우면 되돌릴 수 없고 영상에는 영향이 없다 — 지난 통화 보기에서 어느 통화를 열지만 고르면 된다. 10-08 검증 통화 셋(verify326-muz0sasl·encverify-045718·c6guard-052523)이 더 쌓여 지금 10건이다(encverify-045655·c6guard-052400은 통화 행이 안 만들어졌다). ⚠shoot1-b1은 특히 조심한다 — 마스킹 7종·폭언 3·위반 3·절차 complete·요약 확정·블랙리스트 승인(****0903)이 한 통에 다 든 유일한 완성본이고,blacklist_entry 7이 그 요청(request_id 9)을 가리켜 지우면 2막 배정 판정 시연의 블랙리스트가 사라진다(외래키는 전부ON DELETE NO ACTION).shoot1-stt·stt2·stt3는 STT 하루 600초 한도 때문에 다시 만들기 비싸다. 버려도 되는 것은warmup-1·shoot1-a1(같은 대본 3회 중복 47줄)·shoot1-a2·검증 셋이다
2026-10-06 — F-3 브리핑 · C-6 일시정지 안내 베타를 열며 남긴 것 (류준)
- C-6 폭언 감지는 베타다 — AI 분류기는 데이터가 생기면 학습해서 베타 안에서 쓴다(
_project/decisions/2215절). 지금 탐지는 규칙(어휘 사전)이고, 실제 고객 통화는 개인정보 때문에 모으기 어려워(절대 원칙 7) 학습·측정할 데이터가 없다. 데이터를 얻으면 ① 출처 확보 ② 학습용·측정용 분리 ③ 비속어·욕설 분류기 학습 →CallGuardPort교체(규칙과 합집합) ④ 하네스로 재현율·정밀도 측정 ⑤ 새 결정 기록으로 운영 켜기. 그전까지 탐지 성능은 측정 불가 — 발표·소개에서 「AI 가 욕설을 정확히 잡는다」 고 말하지 않는다 - C-6 베타의 「일시정지·AI 안내」는 상담원 화면에서만 일어난다 — 고객에게 소리를 보내는 경로(교환기 보류·안내 송출)가 없다. 조사: w8-c6-intervention-telephony(정성윤). 화면: w8-c6-intervention-overlay-ui(조서희)
- C-6 베타
pause_ms8,000ms 는 예시값이다(decisions/141) — 안내 문구를 읽는 시간을 어림했다. 잰 값이 아니다 - F-3 브리핑 카드는 조서희 님 대기 — w8-f3-briefing-card-ui. 서버 API 가 먼저 올라가야 실서버로 붙일 수 있다(10-14 머지 목표,
decisions/129)
2026-10-06 — 상담원 화면 원문 · 저장 마스킹 + 전사 암호화로 바꾸며 남긴 것 (장민석)
- 운영 키가 아직 없다 — 배포해도 전사는 마스킹본 평문이다(정성윤 님께 넘김 — w8-transcript-enc-key-ops) — 서버
0.1.46부터TRANSCRIPT_ENC_KEY가 있으면transcript_segment.text를 AES-256-GCM 으로 싼다. 넣는 절차는 런북 12-2-d. 키를 잃으면 암호화된 전사를 되돌릴 수 없다 — 시크릿 밖(SSM Parameter Store 등) 보관처를 먼저 정한다..env.example은 보호 훅이 막아 사람이TRANSCRIPT_ENC_KEY=를 넣는다 → ✅ 2026-10-08 켰다 —/health"transcript_encryption":"on". 보관처는 SSM Parameter Store SecureString/callguard/prod/TRANSCRIPT_ENC_KEY. 런북에 없던 것 하나 — 노드에 Parameter Store 권한이 없어 역할에 좁은 인라인 정책transcript-enc-key(그 파라미터 하나 + SSM 경유 KMS)를 더했다. 19장 11번 확인: DBenc:v1:…· API 마스킹본 · 옛 행 평문 그대로(w8-transcript-enc-key-ops). - 배포 순서 — 서버가 미디에이터보다 먼저(또는 함께)(정성윤 님 — 같은 티켓) — 미디에이터
0.2.14만 먼저 나가면 화면 자막(원문)이/close요약에 섞여 마스킹 없이 저장된다. 같은 PR 이면 같은 릴리스로 나가지만, 서버 쪽 배포가 실패하고 미디에이터만 바뀌는 경우를 본다 → ✅ 2026-10-08 — PR #166 이 server0.1.49· call-mediator0.2.16을 한 릴리스로 냈다(k3s-deploy success). - 프론트 문구가 옛 정책 그대로다(조서희 님께 넘김 — w8-agent-screen-plain-copy) — 자막 잠금 아이콘 title 「민감정보가 마스킹되었습니다」(원문이 보이는데 이 문구가 뜬다) ·
MaskedText.tsx·maskSensitiveText.ts주석 「실서버는 원문을 절대 주지 않는다」 ·.claude/rules/call.md §2. 프론트는 고치지 않기로 했다(사용자 지시) — 문구를 바꿀지는 프론트 쪽 판단이다 - 운영 DB 를 SQL 로 직접 보면 전사가
enc:v1:…다 — 운영 확인(로그 10-02 처럼 DB 로 자막 보기)은 API(GET /hub/calls/{id}/transcript)나 같은 키를 쓰는 스크립트로 바꾼다. 일회성 복호화 도구는 만들지 않았다 → 2026-10-08 실제로 그렇게 됐다 — 키를 켠 뒤 새 행은enc:v1:…다. 지금 쓰는 확인 경로는 서버 파드 안 API(GET /hub/calls/{id}/transcript)이고, 그것으로 10-08 검증을 했다. 일회성 복호화 도구는 여전히 만들지 않았다. - 전사 본문 밖의 저장 텍스트는 암호화하지 않는다 — 요약
summary_text· 블랙리스트 사유·메모 · 지식 공백 설명 · 추천·컴플라이언스 기록은 마스킹만 한다(사용자가 범위를 전사 본문으로 골랐다). 넓힐지는 마감 뒤에 정한다 - 10-02 촬영한 시연 영상은 마스킹된 화면이다 — 배포 뒤 화면(원문 + 강조)과 다르다. 영상을 다시 찍을지, 그대로 쓰고 발표에서 말할지 정한다
2026-10-08 — 부하 시험에서 나온 것 (정성윤)
- 검색 경로가 동시 4부터 500 을 낸다 —
RuntimeError: Already borrowed— 운영 노드에서POST /hub/search에 동시 1→16 으로 걸었더니 동시 4에서 1건 · 8에서 3건 · 16에서 23건(29%) 이 500 이다. 서버 로그의 예외 27건이 전부 같은 것이고ai/apps/retrieval/adapter/outbound/koe5_embedder.py:76의tokenizer(padding=True, truncation=True, …)에서 난다. HuggingFace fast tokenizer 가 RustRefCell기반이라 호출마다 객체에 설정을 쓰는데, 서버가 단일 uvicorn 워커(--workers없음)라 그 인스턴스 하나를 스레드풀이 공유한다. 고치는 법 셋을 안다 —threading.Lock(한 줄) ·threading.local()토크나이저(병렬까지 확보) ·--workers N/레플리카(모델 메모리 ×N). 고정 중이라 넣지 않았다(decisions/138) — 시연은 동시 1~2 라 천장에 안 닿는다. 발표에서는 「천장을 알고 원인을 알고 고르지 않았다」로 말한다(발표 자료 §7). 발표 뒤에 고칠지 정한다. - 검색 한 건이 196 ms 다 — 단일 워커라 이론 상한이 초당 5건 — 대조로 둔
GET /health는 동시 16 에서도 p95 14 ms · 1,246 req/s 라 HTTP 계층은 멀쩡하다. 노드도 끝까지 한가했다(load average0.05 → 0.19) — 8 vCPU 중 한 코어도 다 못 쓴다. - ⚠ 그 시험의 설계 결함 — p50 숫자는 쓰면 안 된다 — 단계마다 질의 번호를 0부터 다시 세어 앞 단계가 던진 질의가
retrieval_cache에 맞았다 (동시 2 의p50 4 ms·420 req/s가 그 흔적이다). 유효한 것은 동시 1 의 196 ms · 오류율 · p95 뿐이다. 다시 잴 거면 단계 사이에도 질의가 이어지게 고친다.
2026-10-07 — 컴플라이언스 권장 문장 확인에서 나온 것 (류준)
- 컴플라이언스 경고가 한 발화에 두 번 실린다 — 로컬
SYN-0167번 발화 「확실히」 에findings2건이rule_code·phrase·alternative_source까지 같았다(10-07, 류준). 규칙 두 개가 같은 낱말에 걸린 것으로 추정한다(원인 미확인). 화면에 같은 배너가 두 줄 뜰 수 있다 — 서버에서 같은 항목을 합칠지 정한다(w8-compliance-alternative-phrase)
2026-10-13 — AI 파트 심사 대비 검토에서 나온 것 (류준)
- NER 교체 — 대상은 정했고 반영만 남았다(
_project/decisions/222). 빼면 STT 오류 20%에서 누락 2→6 이라 빼지 않는다. 교체 대상vmaca123/korean-pii-ner-v3(KLUE 기반 CC-BY-SA-4.0): 누락 0(오류 20%까지) · 실제 발화 오탐 14→25 · 메모리 +1.35GB → 서버 파드 상한 3Gi→4Gi 가 함께 필요(정성윤 님). 10-08 고정 해제 뒤 - GCP 콘솔에서 Speech-to-Text 데이터 로깅이 꺼져 있는지 확인 — 기본값은 꺼짐, 코드에 옵트인 없음. 정성윤 님 콘솔 권한(
08§3) CLAUDE.md§1 「정부는 연내 300만 전망」 은 정부 자료로 확인되지 않았다 — 머니투데이 편집자주뿐(7월 말 290만 3,463명). 루트 규칙 파일이라 이번엔 고치지 않았다- 임베딩 토크나이저 동시성 수정 — 10-08 부하 시험의 원인
koe5_embedder.py:76(AI 파트 코드). 스레드별 토크나이저가 워커 증설보다 싸다. 동결 해제 뒤 - 운영 요약 모델이 후속조치를 빠뜨린다 — 포함률 0.717(규칙 0.883), 「조치」 2/10. 후속조치를 규칙 초안에서 붙일지 정한다(
03_new_measurements.mdM7)
2026-10-15 — 시연 최종본 확인 · 발표 지표 보강에서 나온 것 (류준)
- 브리핑 카드의 범주와 문장이 어긋난다 — 시연 최종본 4:08: 칩 「서류 보완」 · 문장 「재문의로 보입니다」. 모델 범주가 규칙과 같아 통과했지만
briefing_problems가 문장 속 다른 범주 이름을 보지 않는다. 문장에 다른 범주 이름이 있으면 규칙 문장으로 — 한 줄, 동결 해제 뒤 - 온프레미스 STT 가 정확도는 더 낫다 — 같은 20발화 8kHz 배치: Google STT v1 WER 0.358 · Whisper large-v3-turbo 0.137(
docs/ai-part-review/092-1). 스트리밍 구성과 운영 CPU 지연은 미측정 — 1년 로드맵 근거로만 쓴다 - 리랭커는 지금 골든셋에서 효과가 있다 — 후보 20 → 102/102 · MRR 0.929, 단 CPU 질의당 1.7~1.8 s. GPU 가 생기면 다시 본다(
07_metrics_fill.md)