Skip to content

feat(S15P11A705-339): 검색 고도화 3신호 — 재작성·키워드 재정렬·문자열 병합 (검증 게이트 통과) - #118

Merged
colosair merged 29 commits into
devfrom
search-upgrade
Aug 7, 2026
Merged

feat(S15P11A705-339): 검색 고도화 3신호 — 재작성·키워드 재정렬·문자열 병합 (검증 게이트 통과)#118
colosair merged 29 commits into
devfrom
search-upgrade

Conversation

@colosair

@colosair colosair commented Aug 7, 2026

Copy link
Copy Markdown
Member

요약

검색 고도화 트랙의 통합 브랜치를 dev 에 반영한다. 검색 신호 3종(LLM 질의 재작성 · 키워드 재정렬 · 문자열 병합)을 완성하고 검증 게이트 5기준을 통과한 상태다. 세 신호 전부 기본 꺼짐 플래그 뒤에 있어 이 병합으로 검색 동작은 바뀌지 않는다.

3레포(docs·back·ai)를 같은 이름의 통합 브랜치에서 함께 준비해 한 번에 릴리스한다. docs 계약 개정은 이미 병합했다(3c28c01).

Jira

변경 사항

런타임 (전부 기본 꺼짐)

  • app/client/rewrite_client.py — 질의 재작성 클라이언트. 강등 경로·질의 캐시·벤더 폴백 체인
  • app/service/search_service.py — 재작성 호출(길이 게이트 6자 이하)·키워드 재정렬(컷 통과 집합의 순서만 조정)
  • app/repository/context_keyword_repo.py — 재정렬 신호 조회. 판정 완료 Context 의 keyword 만 사용
  • app/core/config.pySEARCH_LLM_ENABLED · SEARCH_KEYWORD_RERANK_ENABLED(기본 false) + 채택값 3키

측정 하네스·산출물tools/search_cut/ 신규 6종, tools/e2e/run_gate.py(게이트 러너), .search/ 실측 artifact

문서 — 제안 P48P52, 구현 리포트 I52I57, 트러블슈팅 T73~T78

검증

  • pytest 519건 통과 · ruff · 문서 색인 정합 · 커버리지 게이트
  • 검증 게이트 5기준 전량 통과 (스냅샷 DB, back+ai 함께 기동, 사용자와 같은 경로)
    • ① 잔존 실패 3건(신한·부캠·신한 부캠) 실서버 회복
    • ② 관련 없는 질의 무노출 유지 (15건 중 11건, 분포까지 동일)
    • ③ 시연 정본 12건 무퇴행 (1위 적중 10/12로 현행과 동일)
    • ④ 전 플래그 끔 = 현행과 동일 응답
    • ⑤ 재작성 타임아웃 시 벡터 검색 복귀
    • 증거: .search/gate_{off,on,degraded,verdict}.json (커밋됨)
  • 표시명 정합 결함 해소 후 재측정 — 채택값 유지 확인, 게이트 재통과 (I57)

리뷰 포인트

  1. 기본 꺼짐이 이 PR 의 안전 근거다. 세 플래그가 전부 false 이고, 그 상태가 현행과 동일함을 계약 테스트와 게이트 기준 ④가 이중으로 고정한다.
  2. 재정렬은 후보를 바꾸지 않는다. 순서만 조정하며, on/off 후보 집합 불변을 계약 테스트가 고정한다. 응답의 similarity 는 원 코사인을 유지한다.
  3. 병합 방식은 merge commit 이다. 통합 브랜치에 티켓 3건이 쌓여 있어 squash 하면 티켓별 이력이 사라진다. 조직 표준(infra git-governance §1)이 squash 를 「GitHub 이 강제하지 않는 운영 convention」으로 분류하고, main 릴리스 3건이 이미 merge commit 선례다.

미결 / 후속

  • 잠정 리포트 번호(I52~I57)는 병합 직후 origin/dev 기준으로 재확인한다.
  • 프리셋 개정 번호 증가 경로 부재(S15P11A705-269) — 신선도 검사가 무력한 상태이며 I57 이 그 실사례를 기록했다.
  • P52(키워드 taxonomy 재설계)는 채택됐으나 실행은 별도 트랙이다.

🤖 Generated with Claude Code

tpals0409 and others added 29 commits August 5, 2026 21:52
기존 하네스(sweep.py · word_sweep.py)의 지표는 전부 컷 기준이다 — 정답이 잘렸는지,
무관 질의가 침묵했는지를 센다. 컷은 순위를 바꾸지 않고 자르기만 하므로 그것으로
충분했다.

그런데 P48 1단계 이후는 순위를 바꾸는 변경이다. 정답이 6위에서 2위로 올라와도 컷이
그대로면 kept 가 변하지 않아 개선이 0으로 보인다. 그 눈을 먼저 만든다.

새 데이터는 필요 없었다 — 행마다 rank 가 이미 들어 있어 세기만 하면 된다.
DB 0회 · GMS 0회.

세 가지를 가른다.

  컷 전 / 컷 후            컷 후만 보면 순위 개선이 가려진다
  단어형 / 문장형          두 대역이 겹치지 않는다(-266). 합산 평균은 어느 쪽도
                           설명하지 못한다
  정답 질의 / 무관 질의    좋은 방향이 반대라 섞으면 상쇄된다

MRR 만으로 판정하지 않는다. 단어형 정답은 본문 문자열 포함으로 계산돼 복수이고,
MRR 은 첫 정답만 보므로 정답 셋이 1·2·3위든 1·9·14위든 값이 같다. Recall@k 와
nDCG@k 를 함께 낸다.

재구성이 맞다는 증거 두 건이 독립적으로 나왔다.

  무관-문장형 침묵률 0.7333 = 11/15   -213 기록과 일치
  스팟 정답 유사도 0.2438             config.py 주석의 마진 0.0038 과 일치

판정 하나가 바뀐다 — -255 의 ①(그네는 컷이 잘랐다)은 -266 의 단어형 분기로 이미
해소돼 있다. 남은 신한·부캠은 tau_word 와 r·top1 양쪽 모두 아래라 한쪽만 풀어도
회복되지 않는다.

가드 4종은 수치를 내지 않고 실패한다(profile 불일치 · 필드 누락 · 정답질의에 정답
0건 · 무관질의에 정답 존재). 결정성은 두 번 실행 바이트 일치로 확인했다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
P48 1단계를 런타임에 넣기 전에 오프라인으로 재구성해 효과를 재기 위한 것이다.
app/ 은 건드리지 않았고 응답 계약도 그대로다.

  fusion.py         순수 로직. DB·GMS·파일을 읽지 않고 인자만 받는다
  keyword_matrix.py artifact 생성 (GMS 배치 1회 + DB 읽기)
  fusion_sweep.py   오프라인 비교 (GMS 0회 · DB 0회)
  word_matrix.py    results 행에 context_id 추가
  recall_probe.py   같음 — context_keyword 는 context_id 조인이다

fusion.py 가 순수한 덕분에 실데이터가 없어도 조인·NULL·visibility·상태·집계·결합식이
맞는지는 지금 검증된다. 픽스처 24종이 P48 규칙을 하나씩 고정한다.

  §1-a  Record 집계는 max — 평균이 아님을 명시 검증
  §1-b  keyword_status 미완료는 신호만 제거. Context 는 후보로 유지
  §1-c  BLOCKED 는 코사인 1위여도 제외, PRIVATE_ONLY 는 사용
  §1-d  NULL confidence 를 0 으로 치환하지 않음. 세 정책 비교
  §1-e  IDF 는 Record 기준 · COMPLETED · 비BLOCKED 모집단
  §2.1  합집합 후 limit. 벡터 상위 안에서 재정렬하지 않는다
  §2.2  가중합은 컷 재측정, RRF 는 cosine gate + cutoff 두 관문
  §2.3  similarity 는 cosine float 계약. fusion 은 정렬 전용

픽스처가 실데이터 전에 결함을 하나 잡았다. recall_probe.json 은 user_id 를 최상위에만
두는데 질의 행에서 읽고 있어 by_user 조인이 조용히 비었다 — 사례 4건이 전 방식에서
순위 불변이었고, 실데이터로 먼저 돌렸다면 "keyword 신호는 효과 없다"로 방식 자체를
기각했을 오판이다. user_id 가 없으면 계산하지 않고 멈추도록 고쳤다.

모집단 결함도 함께 제거했다. keyword_matrix 의 Context 질의에 embedding_status =
'COMPLETED' 가 빠져 있어 검색 후보가 아닌 Context 가 유령 후보로 올라왔고, 그것이
코사인 없는 행(sim=None)으로 나타났다. 검색 Query 와 모집단을 맞췄고, WHERE 계약을
테스트로 고정해 반대 방향 퇴행(keyword_status 를 WHERE 에 넣는 것)도 막는다.

rrf_k 는 하드코딩돼 있어 바뀌어도 흔적이 남지 않았다. CLI 축으로 빼고 결과에 행마다
기록한다 — 스케일이 바뀌면 cutoff 를 다시 재야 하기 때문이다. rrf_cutoff 기본값 0 은
비활성이지 개념 부재가 아니며, cutoff=0 결과는 단독 채택 불가로 표시된다.

fusion_sweep 의 --search-dir 은 픽스처로 배관을 검증하기 위한 것이다. 실측 전용인
.search/ 에 가짜 행렬이 들어가지 않는다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
현행 검색은 판단 근거가 질의-Context 코사인 하나다. 순위를 만드는 것도 그것이고 그
순위에서 무엇을 남길지 정하는 것도 그것이다. 원인이 여러 개인데 대응 수단이 하나뿐이라
그 하나를 질의 길이로 가르는 데까지 갔다(-266).

-255 가 가른 결정적 한 줄이 근거다. 본문에 그대로 있는 짧은 질의가 본문에 없는 같은
길이의 질의보다 낮은 유사도를 받는다 — 「본문에 있음」이 현행 신호에 반영되지 않는다.
컷의 문제도 임계값의 문제도 아니고 그 정보를 담은 신호가 없다는 문제다.

구조를 갈아엎지 않는다. 신호를 늘리고 그것을 합치는 자리를 만든다. 4단계로 나누고
0단계(순위 지표)를 나머지의 선결 조건으로 둔다.

  0  순위 지표          완료 — 이 브랜치의 rank_score.py · I51
  1  context_keyword    이 레포 안에서 끝남. 추가 모델 호출 없음
  2  질의 이해 LLM      「검색 경로에 LLM 없음」 원칙 변경. 1단계 결과 후 판단
  3  어휘 신호          본문이 core 소유라 back 협의 필요

RAG · ANN · 청킹 · placeMeta 결합 · HyDE 는 채택하지 않거나 보류하며 사유를 적었다.
특히 RAG 는 검색 정확도를 올리지 않는다 — 순위가 틀린 상태에서는 침묵을 유창한 오답으로
바꾼다.

두 차례 개정 이력을 머리말에 남겼다. 1차는 "컷은 그대로 둔다"가 RRF 에서 성립하지 않는
것과 visibility 판단(§6 만 읽고 BLOCKED 제외를 놓쳤다), 2차는 sim=None 허용 ·
embedding_status 누락 · RRF 자동 통과 · IDF 단위 넷이다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
keyword_matrix._parse_vector 가 코덱 등록 커넥션의 Vector 객체에서 TypeError 로
중단됐다(T76 잠정). 문자열·Vector·iterable 세 반환형을 모두 받는다 + 회귀 테스트.
rank_score.py·fusion_sweep.py 는 cp949 콘솔에서 — 출력 시 죽었다(T77 잠정) —
keyword_matrix.py 와 같은 reconfigure 방어를 복제한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
세션 조사·대행 실측의 영구 기록 2건. P49 의 P48 링크가 이 브랜치에서 해소된다.
번호는 잠정이며 병합 직전 확정한다(T48·T60).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…분, keyword_matrix 신규

word_grid·recall_probe 는 context_id 를 포함해 재생성했다(P48 §4.1 — keyword 조인용).
keyword_matrix.json 은 .gitignore 예외로 등록 — GMS 배치 비용이 있는 artifact 는
커밋한다는 기존 원칙(matrix.json 계열)을 따른다. 스윕 결과는 재구성 가능하므로 미커밋.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rade 트리거

실측 수치의 보존본을 I53 으로 정식화 — 병합 방식×floor 격자, 채택 기준 대조,
사례 4건, 못 잰 축(-339 몫). tools/search_cut/README 에 신규 4종+테스트 실행 절차.
ai-ci 트리거에 search-upgrade 추가 — base 가 통합 브랜치인 PR 이 CI 없이 병합되는
것을 막는다(T36 계열).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lexical_matrix.py 가 본문 매치를 (질의×소유자×Record)로 굳히고(본문 미저장·스냅샷
DB :25432 가드), lexical_sweep.py 가 게이트 3단×병합 3종 격자를 오프라인으로 훑는다.
측정 결과: 무관·타인소유·문장형에서 매치 0건(노출 증가 없음), 신한 회복(RRF 5위),
경계 게이트는 기대 정답 6건 제외 손해만 관측. 규칙 확정안(단어형 한정·부분일치 +
RRF k=60 + 컷·계약 불변 + 실패 시 벡터만)은 I54 리포트에 있다.
티켓 미발급(런타임 무변경 측정) — 티켓 귀속은 중앙 판단.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RewriteClient: 검색 전용 짧은 예산(SEARCH_LLM_TIMEOUT_SEC 5s · SEARCH_LLM_ATTEMPTS 2,
판정의 90s·3회를 상속하지 않음), 벤더 3종 폴백, 질의 단위 FIFO 캐시(비결정성 흡수),
빈 결과·4배 초과 결과는 원문 복귀. SearchService: SEARCH_LLM_ENABLED(기본 off)일 때만
재작성을 시도하고 실패는 강등 — 원문으로 현행과 동일 검색. 임베딩·컷 판정은 재작성문
기준(대역이 임베딩 텍스트를 따름). 계약 테스트 9건: off 무호출·성공 경로·강등 2종·
미주입 방어·컷 분기 추종·캐시·빈 결과·폭주 방어.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P50(3계층 분리와 Place metadata 결합)·P51(프리셋 거버넌스 — 열린 발견, 닫힌 사용)을
신설한다. 원천은 2026-08-06 사용자 안건 2건이며, P51 확정으로 -338(프리셋 어휘 보강)이
폐기되고 -339 는 재정렬 전용 의미의 축소 재측정 + 런타임 구현으로 재정의된다.

P48 은 Superseded in part 로 역사화한다 — 0·1단계 자산 실현, 2·3단계는 P49 승계,
§8 미결 전 항목에 처분 표기. P49 는 검증 세션 지적 2회분을 반영한다: P48(합집합·컷 전
융합)과 P49(컷 후 재정렬 전용)의 병합 의미 구분, 문자열 규칙의 I54 확정 반영(부분일치
채택·어절 경계 기각), 후보 집합 불변 계약(측정 지점·limit 1회 절단 포함), 공용 계약
개정 경로를 실행 그래프에 추가, 작업 그래프에서 프리셋 개정 체인 제거.

번호(P50·P51)는 잠정이며 병합 직전 확정한다. 티켓 귀속은 미정 — 배치는 후속 판단.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
실제 RewriteClient(운영 설정 체인) 호출 → 재작성문 임베딩 → 스냅샷 DB(:25432) 유사도 →
현행 컷(재작성문 기준 단어형/문장형 분기) 재구성. 재작성문 자체를 artifact 에 기록한다.
원문 기준 값은 굳힌 행렬(matrix·recall_probe)의 컷 재구성으로 얻어 GMS 호출을 재작성
20건 + 임베딩 배치 1회로 줄였다. 포트 가드(:25432)·profile 신선도 가드 포함.

artifact(rewrite_probe.json)는 GMS 비용이 든 실측 결과라 커밋한다(-336 의 artifact
커밋 선례). 판정: 약어 사례 회복(부캠 8위→1위·신한 부캠 4위→3위, 반환 회복), 무관
무노출 11/15→9/15 로 채택 기준(11 이상) 미달 — 후속 분석은 리포트가 담는다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P48 구조(후보 합집합 후 병합 점수에 컷)로 잰 I53 채택값은 P49 §4 가 확정한
재정렬 전용 구조에서 의미가 다르므로 같은 artifact 위에서 다시 잰다.

- fusion.rerank(): 컷 통과 집합의 순서만 조정하는 순수 함수. 후보 추가·제거가
  일어나면 FusionError 로 멈춘다. 재정렬 후 2차 절단 없음
- fusion_rerank_sweep.py: BASE·binary(floor×weight 격자)·RRF(k=60) 비교.
  무관 세그먼트가 BASE 와 다르면 구현 오류로 중단 — 구조적 불변을 스스로 검사
- artifact 신선도 가드: profile·preset_version·데이터셋(소유자 참조) 이 현행과
  불일치하면 수치를 내지 않고 실패 (기존 load 가드 위에 추가)
- 픽스처 8건: 후보 집합 불변·sim 보존·동점 결정성·강등 항등성 고정

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P49 §4 의 세 번째 검색 신호를 런타임에 넣는다. 컷이 후보를 확정한 뒤 keyword
신호는 그 순서만 바꾼다 — 후보 추가·제거 없음, 재정렬 후 2차 절단 없음.

- context_keyword_repo.keywords_for_records(): 컷 통과 Record 의 신호 조회.
  keyword_status=COMPLETED 만 신호로 사용(§1-b), BLOCKED 는 PresetCache 적재
  시점 제외가 후보 매치를 차단(§1-c)
- SearchService._rerank_by_keyword(): 정렬 점수 = 코사인 + weight×신호.
  질의-Preset 후보는 검색용 질의 임베딩 재사용(추가 모델 호출 0), 후보 규칙은
  측정 하네스(fusion.preset_candidates)와 동일 — floor 먼저·동점 preset_id 순
- 실패·신호 없음·캐시 미주입이면 벡터 순서 그대로 복귀. 응답 similarity 는
  원래 코사인 유지
- config: SEARCH_KEYWORD_RERANK_ENABLED(기본 false)·FLOOR 0.35·WEIGHT 0.05·
  TOP_K 3 — 재정렬 전용 구조 오프라인 실측의 채택값
- 계약 테스트 9건: on/off 후보 Record id 집합 불변(순서만 상이)·강등·플래그
  off 동일 응답·채택값 고정·하네스와 후보 규칙 일치

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
실측(I55)에서 재작성의 이득(부캠 8위→1위·신한 부캠 4위→3위 회복)은 전부 5자 이하
질의에서 났고, 손해(무관 무노출 11/15→9/15)는 긴 문장형 질의의 표현 정규화에서만
났다. 게이트 후보 8종 전수 비교에서 형태(길이) 기준만 회복·무노출을 동시 충족 —
성과 기반(결과 0건·top-1 임계)은 대역이 겹쳐 분리 불가에 회복 대상까지 놓치고,
단어형 판정 재사용은 공백 불허라 신한 부캠을 잃는다. 6 은 이득 실측 상한(5자)에
여유 1자를 더한 보수 값, 2026-08-06 사용자 확정.

- SearchService._should_rewrite(): 게이트 판정. 걸린 질의는 LLM 호출 없이 원문 검색
- SEARCH_REWRITE_MAX_CHARS(기본 6): 운영 관측 후 재배포 없이 조정
- 게이트 계약 테스트 6건(호출 0회·경계 6자·strip 판정·설정 가변) — 전체 500건 통과
- rewrite_probe: 게이트 재구성 반영(걸린 질의는 재측정 없이 원문 값) 후 재실행 —
  무노출 11/15 유지·회복 2건 유지로 채택 조건 충족. artifact 는 게이트 반영 최종판

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1차(전면 적용) 실측, 원인 해석, 게이트 후보 8종 전수 비교표, 6자 확정 근거,
게이트 반영 재측정 결과, 못 한 검증(6~12자 대역 무관측·모델 1종 1회차)을 담는다.
번호는 병합 직전 origin/dev 기준 재확정. 색인 두 표 등록.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
플래그만 다른 두 서버의 실응답으로 재정렬 런타임의 계약을 판정한다.

- collect: 행렬 3종의 질의 셋(93건)을 서버에 던져 응답 저장. --queries 로
  재시도용 부분 수집
- judge: ① off/on 후보 Record id 집합 불변 ② on 순서 = on 유사도 + 오프라인
  keyword 신호 재구성 ③ 무관 무노출이 (질의, 소유자) 단위 오프라인 기대와 일치
  ④ 기대 정답 포함 무퇴행 ⑤ off 순서 = 유사도 내림차순
- 어긋난 건은 컷 경계(τ·r×top1) 또는 후보 floor 와의 거리 0.0044(T68) 이내면
  흔들림으로 분류해 결함과 가른다. config 채택값과 거울값이 다르면 판정 중단

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
측정·런타임 구현·실서버 검증을 한 리포트로 완결한다. 사용자 승인에 따라
초안(DRAFT)을 정식화하고 색인 두 표에 I55 로 등록했다.

실검증 요지: 스냅샷 DB(:25432) 상대로 이 브랜치 코드를 플래그만 다르게 두 번
띄워 질의 93건을 대조 — 후보 집합 불변 93/93 · 재정렬 정확성 93/93 · 무관
무노출 15/15 · 정답 무퇴행 78/78 · off=현행(유사도 내림차순) 93/93 전부 통과.
재정렬이 순서를 바꾼 7건 전건 오프라인 재구성과 일치(만두 4위→1위),
신한·부캠 미회복 재확인(문자열 검색·재작성 역할 분담 검증), T68 흔들림 분류
미발동. 판정 도구 결함 1건(무관 기대의 질의 문구 키잉 → (질의, 소유자) 키로
수정) 정정 이력 포함.

번호 잠정: 병렬 브랜치(S15P11A705-337-rewrite-probe)도 잠정 I55 를 사용
중이다. 통합 병합 시 색인 검사가 중복을 잡으며, 나중에 병합되는 쪽이 I56 으로
재확정한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
P49 §6 규칙의 정기 동기화다. dev 신규 커밋(09f507a)은 spec·troubleshooting 문서
재구성으로, 이 트랙의 변경 파일과 교집합이 없음을 병합 전 확인했다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
프로브(4b7ecf2)·6자 게이트 확정 구현(84e684f)·리포트 I55 잠정(0fe4257).
병렬 브랜치 병합 순서는 -337 먼저 — 변경량이 작은 쪽을 기준으로 두고,
실서버 대조 도구를 가진 -339 가 뒤에서 충돌 해소를 스스로 검증한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
하네스(dddcef2)·런타임(a541c2c)·실서버 대조 도구(1171543)·리포트(da58a3d).
-337 과의 공통 수정 3파일(config·search_service·색인)은 3-way 자동 병합됐고,
코드 정합은 통합 브랜치 pytest 로, 잠정 번호 중복(I55)은 후속 커밋이 I56 재확정으로
해소한다 — 색인 검사가 중복을 잡는 것까지가 설계된 절차다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
병렬 브랜치 둘이 각각 잠정 I55 를 등록했고 통합 병합에서 색인 검사가 중복을
잡았다 — 설계된 절차 그대로다. 나중에 병합된 -339 쪽이 I56 이 된다. 최종 확정은
dev 병합 직후에 한 번 더 대조한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
통합 브랜치 빌드의 back(8928ecb)+ai(7092f0c)를 함께 띄워 사용자와 같은 경로
(JWT 쿠키 인증·CSRF 회전 동반, POST /v1/search/records)로 게이트 5기준을 쟀다.
스냅샷 DB(:25432), 플래그 phase 3종(off/on/degraded=LLM 타임아웃 0.001s 강제).

판정 — 전부 통과:
  ① 잔존 3건 회복: 신한(문자열·Spring 경로 첫 실증)·부캠·신한 부캠 전부 결과 포함
  ② 무관 무노출: 15건 중 11건 무노출 유지(현행과 동일)
  ③ 시연 12건 무퇴행: 퇴행 0건, 1위 10/12(현행 실측과 동일)
  ④ off=현행 동일: 1위 불일치 2건이 현행 실측(matrix.json)과 정확히 일치, 사례·정렬 일치
  ⑤ LLM 타임아웃 복귀: 응답 무실패, 재작성 몫만 소거(부캠·신한 부캠), 문자열 회복 유지

기준 ③④의 판정 기준을 명시한다 — 「기대 정답 유지」의 기준선은 현행이며, 현행의
시연 1위 적중은 10/12가 실측 기록이다(matrix.json 문장형 hit@1 0.8333, I53 표 동일).
1위 일치가 아니라 기대 정답 포함 유지 + off 대비 순위 비악화 + 현행 실측과의 일치를
판정한다. 불일치 2건(뉴오더클럽·동교어린이공원 질의)은 트랙 이전부터의 현행 상태이고
on 에서 각각 3→2위 개선·2위 유지다.

증거 4파일(.search/gate_*.json)은 릴리스 판단 근거라 커밋한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cy 판정 계약)

2026-08-07 사용자 채택. 실행(시딩·재판정·재측정)은 별도 결정이며 문서는 설계까지다.

- visibility 의미 재정의 + Privacy 판정 계약 2규칙(보편 이용 행위는 명시로 판정 /
  속성·적합성은 동행·행동·사건으로부터의 추론 금지)
- 기존 27종 전수 재평가: KEEP 15 · MOVE 10(visibility 8건 포함) · REPLACE 1
  (DATE_COURSE→DATING — code-semantic 불일치 해소, 처분 어휘의 대표 적용 사례)
- category 7축 재편(SITUATION 폐지, FACILITY=설비·운영 환경/SUITABILITY/OCCASION/
  MEMORY 신설), meta-domain 2종은 분석용으로만
- 신규 17종(TBD 논리 ID — numeric은 back id=축 결박 해소와 함께 확정) →
  활성 43종 = PUBLIC 25 · PRIVATE_ONLY 18 · BLOCKED 0(경계 정의 명시)
- 43은 P51 절대 가드 안이나 40 초과 사전조건 적용 대상 — 충족·조항 개정 전
  실행 가능성 비전제
- 정합 defect 식별: -292 표시명이 시연·스냅샷 DB 미반영(신선도 결함 실증) —
  독립 티켓 권고
- 추천 과다 노출 원인 4건은 taxonomy와 분리, 별도 작업 단위 권고

P26은 채택 시 supersede 대상, P47·P51·공용 계약은 후속 개정 대상으로 구분 기술.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
포트 가드가 :15432(시연 DB)로 남아 있었다. P48 1단계 때의 값이고, 트랙이 스냅샷
DB(:25432)로 옮겨간 뒤에도 이 도구만 갱신되지 않았다. lexical_matrix 와 같은 가드로
맞춘다 — 시연 DB 를 직접 재면 측정과 시연이 같은 데이터를 공유해 부수효과가 섞인다.

행렬 재생성의 이유는 표시명 정합이다. 프리셋 표시명 명사형 통일(-292)이 YAML 정본에만
반영되고 DB 에는 옛 표시명이 남아 있었다. 표시명은 프리셋 임베딩 입력에 들어가므로
기존 행렬은 옛 임베딩 위의 값이었다. 스냅샷 DB 를 정본으로 재적재한 뒤 다시 떴다.

재적재의 부수효과 없음을 md5 로 확인했다 — Context 임베딩·판정 상태·context_keyword
83행이 전부 불변이고 프리셋 임베딩만 바뀌었다. 프리셋 27건·version 1 유지.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
프리셋 표시명을 정본으로 재적재한 뒤(5159e37) 게이트를 3 phase 전량 다시 돌렸다.
부분 재실행은 성립하지 않는다 — judge 가 off·on·degraded 세 결과를 함께 읽으므로
한 phase 만 갱신하면 옛 결과와 새 결과가 섞인 판정이 조용히 나온다.

판정: ① 잔존 3건(신한·부캠·신한 부캠) 회복 ② 무관 무노출 11/15 ③ 시연 12건 퇴행 0
(1위 10/12, 현행과 동일) ④ 전 플래그 off 가 현행과 동일 ⑤ LLM 타임아웃 시 벡터 복귀.

④를 다시 실증한 것이 이번 재검증의 핵심이다 — 스냅샷 DB 에 쓰기가 들어간 뒤이므로
「끈 상태가 현행과 같다」가 여전히 성립하는지가 이 변경의 방어선이다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
프리셋 표시명 개정(-292)이 두 DB에 미반영이던 결함을 스냅샷 재적재로 고치고,
그 조작이 무효화한 측정을 전부 다시 뜬 기록이다. 조작 범위를 md5 4종으로 대조해
판정이 불변임을 고정했고, 새 임베딩 격자에서 채택값이 유지됨을 확인했다.

기록해야 할 변화가 하나 있다 — 선행 리포트(I56)가 적은 문장형 개선이 이번
측정에서는 사라지고 floor 0.40 구간으로 옮겨갔다. 재정렬의 이득이 단어형에
집중된다는 뜻이다. 채택 조건(퇴행 없이 개선)은 여전히 만족하므로 값은 그대로 둔다.

한계도 남긴다: 프리셋 개정 번호가 1로 고정돼 신선도 검사가 이 무효화를 자동으로
잡지 못했고, 기준선 0.35 인접 쌍 10건 중 9건이 임베딩 흔들림 폭 안에 있다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
병합 직전 dev 가 전진했다(#117 이미지 업로드 용량 상향). 이 브랜치의 변경과 파일
교집합이 없음을 확인하고 반영한다. dev 브랜치 보호가 strict 라 병합 시점에 dev 최신
상태여야 한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@colosair colosair changed the title feat(S15P11A705-336,337,339): 검색 고도화 3신호 — 재작성·키워드 재정렬·문자열 병합 (검증 게이트 통과) feat(S15P11A705-339): 검색 고도화 3신호 — 재작성·키워드 재정렬·문자열 병합 (검증 게이트 통과) Aug 7, 2026
@colosair
colosair merged commit bdabfe6 into dev Aug 7, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants