Skip to content

Latest commit

 

History

History

troubleshooting

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

트러블슈팅 (Troubleshooting)

구현·문서 작업 중 겪은 문제와 그 해결을 재현 가능한 형태로 남깁니다.

보존 원칙

이 폴더는 문제 해결 과정과 구현 이력을 기록합니다. 해결·완료된 항목도 삭제하지 않고 상태 표시만 갱신합니다. 회고와 복기에서 "무엇을 어떻게 해결했는가"를 추적하기 위함입니다.

  • 해결됨 → 문서 유지 + 상태: 해결됨 + 해결 경로·링크 추가
  • 무효화 → 문서 유지 + 상태: 무효(사유) 표기
  • 삭제 → 하지 않음. 잘못 작성된 문서도 정정으로 처리

※ spec/은 현재 유효한 명세이므로 이 원칙의 대상이 아닙니다(낡은 내용은 갱신·삭제).

개별 문서

문서 내용
mermaid-headless-validation.md Mermaid 다이어그램 브라우저리스 문법 검증 (T7·T8)
2026-07-23-fastapi-local-verification.md FastAPI 로컬 검증 중 런타임/드라이버 이슈 (T16~T18)
2026-07-24-e3-ci-and-search-path.md E3 CI·런타임 이슈 — lock 플랫폼 종속·pytest pythonpath·search_path (T19~T21)
2026-07-27-e2e-env-issues.md E2E 검증 환경 이슈 — .env CRLF·register_vector 미등록·한글 인코딩 (T22~T24)
2026-07-28-shared-worktree-and-env-cache.md 멀티세션 워킹트리 오염 · import 시점 .env 캐시 (T25·T26)
2026-07-30-seeding-quota-and-encoding.md AI API 판정 쿼터·콘솔 인코딩으로 인한 시딩 중단 (T27·T28)
2026-07-31-local-e2e-and-ci-pitfalls.md 로컬 E2E·CI 함정 — venv·로그 버퍼·jar 낙후·포트·로그인 쿠키 (T29~T36)
2026-07-31-tau-measurement.md 후보 임계값 τ 측정 — 틀린 진단·인코딩 재발·대조군 부재 (T37~T39)
2026-07-31-search-cut-measurement.md 검색 결과 컷 측정 — 반대 방향 질의 부재·worktree .env·배치 구성과 임베딩 재현성 (T40~T42)
2026-07-31-error-contract-pitfalls.md 오류 응답 계약 검증 — ASGITransport 예외 전파·AI API 스텁 URL 형식·시연 DB 자격증명·색인 갱신 중복 (T50~T52 · T56)
2026-07-31-judge-prompt-ab.md 판정 프롬프트 A/B — 죽은 설정 키·라벨 커버리지·조건 노출·사전 기준·1회 분포·번호 충돌 (T43~T49)
2026-07-31-db-error-pitfalls.md DB 오류 분류 — 접속 실패는 asyncpg 예외가 아니다·min_size=1 재현 불가·curl 한글 본문 (T53~T55)
2026-07-31-log-redaction-pitfalls.md 로그 마스킹 — 잘려서 에코되는 요청 값·거대 본문의 오해를 부르는 400·docstring을 잡는 소스 규약 검사 (T61~T63)
2026-07-31-judge-vote.md 판정 n회 다수결 — 사라진 선행 산출물·실패와 빈 선택의 혼동·전수 검정·번호 확정 시점 (T57~T60)
2026-07-31-docs-index-check.md 문서 색인 검사 — union 이 남긴 빈 줄이 표를 끊는다·「색인에 있다」의 범위 (T64·T65)
2026-08-03-dead-config-key-audit.md 죽은 설정 키 전수조사 — alias 매칭은 grep 으로 못 잡는다·「N 대 M」차집합은 한 방향이 아닐 수 있다 (T66·T67)
2026-08-03-preset-description.md 프리셋 개정 측정 — 임베딩이 결정적이라는 전제·rank 로 밀려난 손실이 τ 격자에서 사라진다 (T68·T69)
2026-08-03-repeat-incidents.md 하루에 갈래마다 서너 번 — 사본에서 꺼낸 값·반만 덮은 자동화·공개 저장소 실데이터 (T70~T72)
2026-08-05-multi-signal-investigation.md 다신호 검색 조사·실측 — 가중합의 정답·무관 동반 상승, Preset 출력 제한과 약어, 키워드 신호 적용 범위, 하네스 버그 2건, 사전 병합 코드의 배포 경로 (T73~T78 잠정)

문제 해결 — 전수 (AI 소유)

T 증상 해결
T1 main에 직접 커밋됨 백업→revert→피처 브랜치 재적용, Conventional Commits 채택
T2 draft/06·07·09 rebase 충돌(MINYONG 독립 반영) Option B rebase, 비-AI 개선 보존 + AI 스키마 교체, force-with-lease
T3 PR3 "가드 수정경로 적용 금지" ↔ PR1 모순 insert-first면 가드 자연통과 → "그대로 통과·특례 금지"로 통일
T4 updated_at 확정/미결 엇갈림 MINYONG 안 채택으로 확정 통일(제거)
T5 gh: command not found(bash) C:\Program Files\GitHub CLI\gh.exe 전체경로 호출
T6 ai 레포 기본 브랜치가 피처 브랜치 gh repo edit로 main 변경
T7 Mermaid 검증 실패(@mermaid-js/parser는 flowchart 미지원, jsdom navigator getter-only) mermaid@11+jsdom, Object.defineProperty로 navigator 우회 → 4/4 valid
T8 Mermaid 추출 파싱 오류(CRLF) 정규식 .replace(/\r\n/g,"\n")
T11 마이그레이션 실검증 필요 pgvector 컨테이너에서 V1→V102 순차·PK·extension·중복스키마 실패 확인
T12 preset YAML 규칙 위반 방지 Python 스크립트로 개수/배분/유일/visibility/examples 검증
T13 docs 11_개발_컨벤션.md 삭제 부작용(pgvector 검토 유일 출처) 소실 내용 식별·고지
T14 docs/ai-architecture-diagrams 브랜치가 eval 하네스 커밋 위에 오정렬 main 기준 재정렬(rebase --onto)
T15 back ADR "소유 파트: AI 파트" 혼란(표준 ADR엔 소유파트 필드 없음) 주도(Driver)로 격하 + 레포 스코프 명시(P36)
T16 .env UTF-8 BOM으로 첫 키(DATABASE_URL) 파싱 실패 BOM 없이 기록(UTF8Encoding($false)), 첫 3바이트 확인
T17 pgvector가 VECTOR 컬럼을 Vector 객체로 반환 → np.asarray TypeError to_numpy()/to_list() 변환(디코드 방향만)
T18 asyncpg now() - $2 interval 타입 추론 실패(timestamptz < interval) $2::interval 명시 캐스트
T19 Windows uv pip compile lock이 마커 없이 pywin32 고정 → ubuntu CI 설치 실패 uv pip compile --universal(sys_platform 마커)
T20 CI 러너에서 pytest가 app/tests import 실패(로컬은 PYTHONPATH 우회) pyproject [tool.pytest.ini_options] pythonpath=["."]
T21 search_path=ai 단독이 public 제외 → VECTOR 타입·register_vector가 멀티 커넥션에서 실패 ai, public으로 확장(public=vector 확장 소재, core는 경로 밖 유지)
T22 .env가 CRLF라 셸로 값을 뽑으면 \r이 섞여 JSON 파싱 실패(일부 요청만 깨져 혼동) tr -d '\r\n' 또는 셸 파싱 금지·get_settings() 사용 (T16 계열)
T23 raw asyncpg 연결은 register_vector 미등록 → VECTOR가 문자열로 디코딩되어 PresetCache 적재 실패 스크립트도 app.core.db.Database 사용(search_path+타입 등록 캡슐화). 시딩 재발 주의
T24 Git Bash + curl에서 한글 본문 인코딩 깨짐(ASCII 본문은 통과 → T22와 증상 동일) 한글 요청은 Python httpx로 전송, curl은 ASCII 경로에만
T25 멀티세션이 단일 git 워킹트리·인덱스·HEAD 공유 → 3파일 커밋에 타 세션 15파일 섞여 push 격리 git worktree 기본, git add 개별(-A 금지)·커밋 전 브랜치 확인
T26 main.py 모듈 레벨 create_app() import 시점 .env 캐시 → API 3건만 401(로컬 .env 우연 일치로 은폐) settings fixture에서 get_settings() 캐시 재설정 + conftest placeholder env 선주입
T27 AI API 판정 쿼터는 상수가 아니다 — 공용 게이트웨이라 시점·프로바이더 경로별로 다르다. 07-29 분당 2건 → 07-30 분당 30건 이상 --pace 기본값 1. 방어는 retry.py 백오프 + 회수 루프. 근본 대책은 벤더 폴백(-175)
T28 콘솔이 cp949면 — 한 글자에 UnicodeEncodeError → --reset 직후 죽어 데이터만 지워진 상태가 됨 sys.stdout.reconfigure(utf-8) + log() 최후 방어. 호출자가 PYTHONIOENCODING을 기억하지 않게 (T22·T24 계열)
T29 python -m uvicorn 이 시스템 Python 을 타서 No module named uvicorn — exit 0 이라 「완료」로 보인다 .venv/Scripts/python.exe -m uvicorn
T30 백그라운드 파이프(| tail)가 서버 로그를 버퍼에 가둔다 — 살아 있는 동안 0바이트 파이프 대신 > file 2>&1
T31 gms window 가 안 나오는 것을 계측 실패로 오판 — 창은 타이머가 아니라 다음 호출이 닫는다 60초 뒤 1건 더 넣으면 나온다
T32 back jar 이 낡으면 Flyway 가 Detected applied migration not resolved locally: 6 으로 기동 거부 git pull 뒤 ./gradlew bootJar
T33 ai/.env 의 DATABASE_URL 이 07-27 잔재 :5433 — 시연 정본은 :15432 preflight 가 BLOCK 한다. 기본값은 그대로
T34 브라우저 로컬 테스트 로그인은 logged_in=1 정확 일치 — true 는 안 걸린다 access_token + logged_in=1 + XSRF-TOKEN 셋을 심는다
T35 검색이 소유자별로 갈려 계정을 잘못 잡으면 데이터가 없는 것처럼 보인다 social_account 로 member 별 Context 수를 먼저 센다
T36 CI 검사를 dev 에만 넣으면 main 기반 PR 에 적용되지 않는다(PR CI 는 head 워크플로로 돈다) hotfix/* 로 main 에도 올린다
T37 「후보 임계값이 없어서 오분류가 난다」는 진단이 틀렸다 — _topk 에 이미 있었고 테스트도 둘 있었다. 후보도 10개가 아니라 평균 7.4개 「기능이 없어서」는 grep 한 줄로 확인하고 쓴다. 실제 원인은 적합·부적합 유사도 분포의 겹침
T38 스크립트에만 T28 방어를 넣으면 탐색용 python -c 한 줄에서 다시 죽는다 — 앞줄은 이미 찍혀서 완료로 보인다 한 줄에는 PYTHONIOENCODING=utf-8, 반복할 것이면 파일로 옮긴다
T39 재판정 차이를 대조군 없이 읽으면 전부 조건 탓이 된다 — 같은 τ 로 다시 판정만 해도 Context 26% 가 흔들린다 판정(LLM) 계층 측정은 대조군을 같이 돌린다. 임베딩은 결정적이라 불필요
T40 정답이 있는 질의만 재면 컷의 절반이 안 보인다 — r 이 무관 질의를 15건 중 0건도 침묵시키지 못한다는 사실이 검증 질의 12건에서는 드러나지 않는다 걸러져야 하는 입력을 표본에 넣는다. 「0건」의 부호가 축마다 반대이므로 표를 가른다
T41 worktree 에 .env 가 없어 get_settings() 가 GMS_API_KEY 부터 죽는다(env_file 은 CWD 기준·gitignore) .env 를 worktree 에 복사하고 DATABASE_URL 만 환경변수로 덮는다. .demo/ 키 분기(-198)와 같은 원인
T42 임베딩 배치 구성이 바뀌면 같은 텍스트의 유사도가 10⁻⁴ 규모로 흔들린다(0.5264→0.5258). 「임베딩은 결정적」은 같은 배치일 때의 이야기다 그 규모 차이가 결론을 가르는 값을 채택하지 않는다. 재현용으로 유사도 행렬을 커밋한다
T50 httpx.ASGITransport 는 앱 예외를 응답으로 바꾸지 않는다(raise_app_exceptions=True 기본) — 「500 이 나간다」를 단언하려는데 예외가 테스트로 튄다 500 을 보려면 raise_app_exceptions=False. 무엇이 새는지 보려면 기본값 그대로
T51 로컬 AI API 스텁 URL 에 /gmsapi/ 가 없으면 앱이 기동에서 죽는다(_gms_base_url_shape) — 증상이 「스텁이 안 불린다」가 아니라 「안 뜬다」다 스텁도 /gmsapi/api.openai.com/v1/embeddings 경로를 흉내낸다
T52 시연 DB 는 포트뿐 아니라 비밀번호도 .env 와 다르다(pinlog-local). T33 대로 :15432 만 고치면 InvalidPasswordError DSN 일부만 고치지 않는다. docker inspect 로 컨테이너 env 를 직접 읽는다
T43 .env 의 PINLOG_JUDGE_MODEL 은 -175 가 대체해 읽히지 않는데 값이 그럴듯해(체인 2순위) 리포트의 판정 모델을 잘못 적게 한다. 실제 응답은 체인 1순위 gpt-4o-mini 측정 도구는 벤더를 인자로 받고, 읽은 값이 아니라 답한 값(JudgeResult.model)을 남긴다
T44 labels.yaml 은 현행 판정 83행만 덮는다 — τ 스윕과 달리 재판정은 없던 행을 만들어 표 밖으로 나간다(24종). 빼고 세면 조건 비교가 기운다 원본은 고치지 않고 labels_extra.yaml 로 넓힌다. 남는 것은 unlabeled 로 세어 양극단으로 돌린다
T45 라벨을 붙일 때 어느 조건이 고른 행인지 보이면 라벨이 결론을 따라간다 — 증상이 없고 개선 폭만 부푼다 덤프에서 조건·회차를 뺀다. 본문과 description 만 보고 붙인다
T46 사전 기준(범위 비중첩)을 못 넘으면 자를 바꾸고 싶어진다. 표본이 늘면 그 기준은 오히려 통과하기 어려워져 교체가 정당한데, 교체 시점이 결과를 본 뒤다 표본을 늘리고 자를 더한다(순열검정). 앞의 자를 지우지 않고 둘 다 찍는다
T47 DB 에 저장된 판정 1회분의 confidence 가 라벨을 깨끗이 가르는 것처럼 보인다(fit min 0.70 · unfit 0.30~). 한 번 더 판정받으면 분리가 사라진다 — confidence 도 비결정적이다. DB 조회가 공짜라 여러 번 볼 생각을 안 하게 된다 저장된 판정에서 발견한 문턱은 후속으로 올리기 전에 같은 조건으로 한 번 더 받아 대조한다(42회·70초). 확인용 회차는 --outdir 를 나눈다
T48 트러블슈팅 번호를 분기 시점의 마지막 다음으로 매기면, 같은 날 병렬로 병합된 티켓과 겹친다(-213 이 T40~T42 를 먼저 썼다). 색인 표는 정렬되지 않아 중복이 나란히 서지 않는다 PR 직전 origin/dev 로 rebase 한 뒤에 번호를 확정한다. 재번호는 매핑 한 번으로(역순 치환은 뒤섞인다), 남의 행은 건드리지 않는다
T49 open(p,'w').write(f(s)) 에서 f 가 죽으면 파일이 0바이트로 남는다 — 'w' 가 인자 평가 전에 truncate 한다. 고쳐서 재실행하면 빈 파일을 읽어 빈 결과를 써서 조용히 성공한다 변환 결과를 먼저 만들고 임시 파일에 쓴 뒤 os.replace. newline='' 를 양쪽에. 문서 일괄 수정은 커밋 뒤에 돌린다
T53 DB 접속 실패는 asyncpg 예외가 아니다 — 포트 거부·DNS·타임아웃·풀 획득 타임아웃이 전부 stdlib OSError 다. 08xxx 는 붙어 있던 연결이 끊길 때의 SQLSTATE 다. asyncpg 만 분류하면 테스트는 전부 초록인데 「DB 연결 실패가 503」만 거짓으로 남는다 접속 단계에서만 OSError 를 함께 번역하고, 분류를 repository 함수가 아니라 세션 경계에 건다(pool.acquire() 가 함수 밖이다)
T54 닿지 않는 주소로 「요청 중 DB 불가」를 재현하려 하면 create_pool 이 min_size 만큼 즉시 접속해 픽스처에서 죽는다. connect() 를 건너뛰면 RuntimeError(우리 결함·500)라 다른 것을 측정한다 테스트용 min_size=0 풀로 접속 시점을 첫 acquire() 로 미룬다. 풀·드라이버·예외는 실물로 두고 예외를 주입하지 않는다
T55 Git Bash curl -d 로 한글 본문을 보내면 {"detail":"There was an error parsing the body"} 400 — 스키마 결함처럼 보인다 질의어만 ASCII 로 바꿔 같은 요청이 통과하면 원인은 본문 바이트다. 한글이 측정 대상이면 UTF-8 파일 + --data-binary @file
T56 merge=union 은 색인 행을 갱신하면 낡은 판을 되살려 같은 문서가 두 줄이 된다 — 추가만 할 때는 안 난다 행을 고쳤으면 병합 뒤 uniq -d 로 확인한다
T57 후속에 「하네스에 기록을 넣어 두었다」로 물려주면 코드에 기능이 있다는 뜻인데 읽는 쪽은 데이터가 남아 있다로 읽는다. .prompt_ab/ 는 .gitignore 에 이름조차 없어 수명을 정한 사람이 없었고 worktree 와 함께 사라졌다 산출물은 경로와 수명을 함께 물려준다. 안 남길 파일도 .gitignore 에 이름과 이유를 적는다
T58 다수결은 「고르지 않았다」를 정보로 쓰므로 「고르지 않았다」와 「묻지 못했다」가 같은 모양이면 호출이 실패할수록 오분류가 줄어 보인다. 판정 1회 집계에서는 둘을 가를 이유가 없어 드러나지 않는다 분모를 성공 수가 아니라 n 으로 고정하고 정족수 미달이면 저장하지 않는다(PROCESSING 유지). 서비스와 측정이 같은 함수를 부른다
T59 score_ab.py 의 순열검정은 근사가 아니라 전수라 조건 간 관측 수가 어긋나면 폭발한다(30 대 10 → C(40,10) ≈ 8.5억). 접어서 만드는 측정은 조건마다 관측 수가 자연히 달라진다 기술 수치는 관측 전부로 내고 검정을 걸 때만 --cap 으로 수를 맞춘다. 자를 무르는 것과 표본을 맞추는 것은 다르다
T60 색인이 낡아 번호를 틀리게 하고(본문 T50T52 인데 색인 T43T45), 본문에서 세도 틀린다 — 세는 시점이 PR 보다 앞이면 그 사이 병합된 병렬 티켓을 못 본다. -221 이 T53~T56·I32 를 먼저 가져갔다 T48 의 처방이 유일하게 듣는다 — 병합 뒤에 번호를 확정한다. 문서를 쓰는 동안은 번호를 미루고 매핑 한 번으로 치환. T 와 I 를 함께 본다
T64 merge=union 이 표 안에 남긴 빈 줄이 GFM 표를 끊는다 — 그 뒤 행이 파이프 문자 문단으로 렌더된다. 에디터·diff 에서는 표로 보여 아무 증상이 없다. union 은 「추가만 하면 안전」으로 통하지만(T56 은 갱신을 겨눴다) 추가하는 줄에 빈 줄이 딸리면 추가만으로 깨진다 새 행은 빈 줄 없이 마지막 행 바로 아래 붙인다. 색인을 고쳤으면 GitHub 의 렌더된 화면을 한 번 본다 — 색인은 고치려고 여는 파일이라 읽는 사람이 없다
T65 「색인에 있는가」를 README 전체 링크로 재면 전수 표(I##)의 링크가 파일 표의 누락을 가린다 — 착수 시점 dev 위반 3건 중 2건이 그 상태라 검사가 자기가 겨눈 사고(07-31 사고 3)를 못 잡는다 판정 범위를 파일 표 섹션으로 좁힌다. 어느 표가 색인인지를 먼저 정하지 않으면 검사는 가장 느슨한 해석을 택하고, 느슨한 해석은 원래 잡으려던 것을 통과시킨다
T61 오류 본문이 요청 값을 에코하는지 완전 일치로 재면 「안 샌다」가 나온다 — OpenAI 는 앞뒤 3자만 남기고 잘라서 되돌린다(Invalid value: 'PIN...def'). 이 사실이 마스킹 규칙의 근거 전체였다 완전 일치로 끝내지 않고 본문 원문을 본다. 자동화하려면 마커의 앞/뒤 n자도 함께 찾는다
T62 요청 본문이 아주 크면 AI API 가 Model not found in request for domain ... 400 을 낸다 — model 은 멀쩡히 들어 있다. PermanentError 로 분류돼 재시도 없이 FAILED 가 되는데 문구는 모델명을 가리킨다 「모델이 없다」400 은 설정을 고치기 전에 본문 크기부터 본다. 같은 모델명으로 짧은 요청이 통과하면 원인은 모델명이 아니다
T63 소스 규약(resp.text 를 마스킹 없이 쓰지 않는다)을 정규식으로 훑으면 그것을 설명하는 docstring 이 위반으로 잡힌다 — 예외 목록을 손으로 유지하면 검사가 규약보다 약해지는 방향으로만 고쳐진다 ast.parse 로 본다. 문자열 리터럴은 후보에 들어오지 않으므로 예외 목록이 필요 없다
T66 pydantic Settings 는 필드명을 소문자로 선언해도 alias= 로 지정한 대문자 env 를 읽는다 — .env·문서에 키 이름이 리터럴로 남아 있어도(전부 "이제 안 읽는다"는 설명 맥락) 그 문자열 존재가 "읽힌다"의 증거가 아니다. -210(threshold 가 config.py:114에 있었던 사고)과 정반대 모양의 오판 후보 키마다 sentinel 값을 주입해 실제로 Settings() 를 생성하고 필드 값에 반영되는지 확인한다. os.environ 을 통째로 비우면 Windows asyncio.windows_events 가 SYSTEMROOT 를 못 찾아 죽으므로 필요한 키만 얹었다 뗀다
T67 ".env 13 대 .env.example 12" 를 단일 방향 차집합(13-12=1)으로 예단하면 틀린다 — 실제로는 .env 만의 키가 2개(둘 다 죽음), .env.example 만의 키가 1개(살아 있음)였다. 공통 11 + 2 = 13, 공통 11 + 1 = 12 로 총계는 맞지만 "하나만 다르다"는 전제와 실제 구성이 다르다 두 파일의 키 이름 집합을 대칭차(symmetric difference)로 비교한다 — 숫자 차이만으로 "어느 하나를 채우면 끝"이라 판단하지 않는다
T68 임베딩 API 는 같은 배치 구성으로도 결정적이지 않다. 시드 그대로인 조건의 벡터가 DB 적재분과 코사인 0.9993 이라 "경로가 어긋났나"로 읽힌다 — 단건으로 다시 뜨면 1.000000 이 나와 "배치 경로 결함"으로 오진하기 쉽다. T42 가 배치 구성 변경을 원인으로 지목했으나 필요조건이 아니다. 실측 |Δsim| 최대 0.0044 · rank 43쌍 같은 배치를 두 번 떠서 서로 대조한다(DB 와만 비교하면 어느 쪽이 흔들리는지 모른다). 검증 문턱은 0.999 — 텍스트가 실제로 다르면 0.9 대로 떨어져 경로 어긋남은 그래도 잡힌다. base2(같은 텍스트) 조건을 상시 두어 흔들림이 후보 절단선을 넘는지 매 측정에서 본다
T69 tau_grid/score.py 의 τ 격자가 rank > K 로 밀려난 행을 어느 칸에도 세지 않는다 — 같은 파일의 라벨 분포는 fit 최솟값 0.2554 를 찍는데 τ=0.30 격자의 「fit 유실」은 0 으로 나온다. τ 만 조건일 때는 rank 가 고정이라 무해했고, 임베딩이 바뀌자 같은 코드가 조용히 틀린 값을 낸다(교환비가 0.00 으로 보이나 실제 0.67) 밀려난 행을 따로 세어 나란히 낸다. score.py 는 -210 수치의 재현 기준점이라 고치지 않았다. 고칠 거라면 「rank 로 빠짐」을 τ 유실과 다른 칸으로 센다 — 합치면 「τ 를 올려서 잃었다」와 「다른 프리셋이 밀어내서 잃었다」가 구분되지 않는다
T70 낡은 값이 새 결정의 근거가 되고 그 사실이 드러나지 않는다. 하루에 넷 — 철회된 단정이 그 문서를 근거로 인용하며 되살아나고, 코드 한 행을 인용하며 바로 다음 행을 놓친 오독이 이미 병합된 작업의 설계 근거가 되고, 원장에 적어 둔 정정이 계약에서 원래 문구로 되돌아오고, 계약에 실은 수치가 여러 번 틀렸다. 넷 다 사본이 아니라 원문을 연 다른 사람이 잡았다 — 사본을 읽는 쪽은 확인할 것이 있다는 사실 자체를 모르고, 「쓰기 직전 재조회」 규칙은 이미 있었는데도 났다 읽는 쪽이 아니라 쓰는 쪽에 규칙을 둔다(R-18 「값 대신 출처」) — 측정 수치·현행 상수·코드 행 번호·배포 상태 값을 옮기지 않고 파일명·모듈명·티켓·PR 번호로 좌표만 가리킨다. 기계 검사는 없다 — 「제안 내용인가 관측값인가」는 사람이 묻는다. 철회하는 쪽도 대상을 좁혀 적는다 — 폐기된 것은 값이 아니라 값의 항상성이다
T71 자동화가 success 로 끝나는데 아무것도 안 바뀐다. 병합 직전 재검사가 경합에 지면 PR 이 낡은 SHA 를 든 채 남고 갱신 워크플로가 다시 밀어야만 재시도되는데 그 cron 이 연속으로 빠졌다. 봉인 값은 갱신 도구의 수정 대상 필드 밖이라 틀려도 실패하는 검사가 없고, 감시 스크립트는 세션이 죽어도 살아남아 출력이 아무데도 안 닿는 고아가 된다. 개수로 세는 판정은 원리상 부정확해 이것을 오래 숨긴다 성공 판정을 네 층으로 가른다 — 프로세스 생존 ≠ 실행 성공 ≠ 실제 변경 발생 ≠ 최종 전달 성공. 감시는 heartbeat 로 자기 상태를 파일에 남기고 확인 경로가 나이·출처·중복을 보고하되 판정은 사람이 한다. 배포 자동화 둘은 인프라 소관이라 이슈로 기록만 했다. 「다음 스케줄이 복구한다」는 전제 자체가 약하다
T72 방어를 세운 뒤에도 같은 종류의 노출이 새로 생긴다. 대응을 정한 직후 측정 산출물이 새로 커밋됐다 — 훅은 바깥으로 나가는 발화(이슈·PR·코멘트·티켓)만 검사하는데 그 산출물은 스크립트가 만들고 사람이 git add 해 검사 지점을 한 번도 안 거쳤다. 커밋 시점 검사가 없고, .gitignore 예외가 「커밋하라」고 적극적으로 지시하고 있었다. 마스킹한 이슈의 코멘트가 가리지 않은 쪽을 안내하고 있었다 미정. 선택지 넷 — 산출물 마스킹본 교체(그것을 읽는 재판정 도구가 깨질 수 있다) · 산출물 제외(재측정 비용 감수) · 검사 범위를 커밋 시점으로 이동 · 마스킹 문구의 경로 안내 제거(이것만 즉시 가능). 재측정 비용과 노출이 정면으로 부딪히는 구조라 「지우면 끝」이 아니다. 위치·규모는 문서에 적지 않는다(위치 비공개 선례)
T73 (잠정) 키워드 점수를 가중합으로 더하자 컷 기준 아래의 정답이 결과에 복구됐지만, 같은 계산으로 관련 없는 후보도 기준을 넘어 노출됐다 — 관련 없는 문장형 질의의 무노출이 11/15 에서 9/15 로 감소. RRF 는 무노출을 유지했지만 문장형 hit@1 이 0.8333→0.5833 으로 퇴행. 검색 방식 수가 아니라 병합 규칙이 결과를 정한다 floor 를 sweep 필수 축으로. floor 0.35 · binary weight 0.05 조합만 채택 기준 4종 통과 — 대가는 키워드 적용 범위 축소와 신한 재제외. 검색 방식별 컷·게이트 분리(P49 §5)
T74 (잠정) P48 2단계가 LLM 출력을 Preset 목록으로 제한해, Preset 에 없는 부트캠프로 부캠을 확장할 수 없다 — 2단계의 목적인 약어 문제를 그 제한이 막는다. 문자열(본문에 「부캠」 없음)·임베딩(의미 연결 실패, 컷 전 8위)·Preset(표현 항목 없음) 모두 이 질의를 해결하지 못해, 검토한 대안 중 LLM 재작성이 가장 현실적 출력 제한을 풀고 자유 재작성으로 개정 제안(P49 §3). 잘못된 재작성 방어는 원문 복귀·질의 캐시·보수 프롬프트로. 재작성 목표 문장의 검색 성공은 기측정(부트캠프 1위)
T75 (잠정) 관련 없는 결과가 노출되지 않는 floor(0.35)에서 키워드 점수가 단어형 질의 66건 중 12건에만 반영된다(미반영 54건). 키워드 적용 범위와 무관 결과 차단이 floor 값 하나로 맞바뀐다 미반영 54건 목록을 Preset 개선의 설계 입력으로. 키워드 채택값 확정만 Preset 개정에 종속 — 인수·재작성·문자열 검색은 무관(P49 §8)
T76 (잠정) keyword_matrix.py _parse_vector 가 pgvector 코덱 등록 커넥션이 반환하는 Vector 객체를 처리하지 못해 TypeError 로 실행 중단 — 코덱 미등록 환경(문자열 반환)에서는 재현되지 않을 수 있다. T17 과 같은 반환형 차이 문자열·Vector·iterable 세 반환형을 모두 받는 분기(to_list). 실측은 로컬 패치 3줄로 완료
T77 (잠정) rank_score.py·fusion_sweep.py 에 stdout UTF-8 재설정이 없어 cp949 콘솔에서 — 출력 시 인코딩 예외로 중단 — 같은 브랜치 keyword_matrix.py 에는 재설정이 있다. 한 파일만 방어된 T28·T38 과 같은 유형 재설정 3줄을 두 파일에 복제. 실측은 PYTHONIOENCODING=utf-8 로 우회
T78 (잠정) dev 에 미리 병합한 코드가 다른 작업의 main 반영에 포함되어 배포될 수 있다 — -266 코드가 별도 릴리스 판단 없이 main 에 반영되고 dev 환경까지 배포된 선례. 기본 off 플래그 방식은 dev 에 코드가 존재하는 한 의도치 않은 배포 경로가 남아 기각 통합 브랜치(search-upgrade) 격리 + dev→통합 단방향 동기화 + 검증 기준 통과 후 한 번만 병합(P49 §6). 플래그는 운영 중 복귀 장치로만

T9(H2·pgvector)·T10(flyway.schemas)은 백엔드 아티팩트라 back 레포 docs/ai/troubleshooting에 있습니다.