fix: 게이트 전수 감사 — 한국어 검색 랭킹이 관련성을 0으로 계산하던 버그 외 5건
실사용 로그의 사용자 메시지 1,011건(고유 782건)을 모든 게이트에 통과시켜 오탐/미탐을
실측했다([[feedback_calibrate_on_real_data]]).
가장 큰 건: rankResults의 토큰화가 `q.replace(/[^a-z0-9\s]/g, ' ')`였다. 이 문자 클래스는
한글을 전부 지운다. **모든 한국어 쿼리**에서 관련성 토큰이 빈 배열이 되고 rel 점수가 항상
0이 되어, 결과가 오로지 domainTrustScore로만 정렬됐다 — 질문에 답하는 페이지인지와 무관하게.
시어엔진 라이브 실측("영리의료법인 비영리 병원 비율"): 수정 전에는 "Chee Lai"라는 사람의
LinkedIn 프로필 4건이 1~4위였고 유일한 관련 기사가 아래로 밀려 있었다. 수정 후 그 기사가
1위가 된다. rankResults는 7개 provider 전부가 쓰므로 영향 범위가 검색 전체다.
유니코드 인식 토큰화로 교체(한글·한자 2자 / 영문은 기존 4자 유지). 시점 표현도 영어만
있어서 한국어 "지금/현재/최신"은 배수를 받은 적이 없었다.
나머지:
* isCancelIntent 오탐 — "하지마 유적지는 바다와 떨어져 있는데?"에서 지명 하지마(波島)가
`하지\s*마`에 걸렸다. 참이면 진행 중이던 작업이 일시정지되고 지리 질문이 작업제어 응답으로
하이재킹된다(server.ts 두 호출부 모두). 취소는 문장 끝 명령이므로 종결 위치로 앵커를 걸었다.
영어 쪽은 표본에 사례가 없어 건드리지 않았다.
* isExecutionLikeRequest 오탐 — 맨 "패치"가 목록에 있어 "인슐린 패치는 혈당 측정 기능이
없나?", "패치는 많이 비싼가?"가 실행형으로 분류됐다. 이 함수는 검증 강제에서 면제시키는
쪽이라, 실존 의료기기의 기능·가격을 검색 없이 기억으로 답해도 아무도 막지 않았다.
"구속"을 체포 맥락으로 좁힌 것과 같은 처리 — 소프트웨어 패치 활용형일 때만 걸린다.
* isFactualInfoRequest 미탐 — "얼마" 계열 수량·가격 질문. 표본에서 이 표현으로 물었는데
어떤 검증 게이트에도 안 걸린 5건이 있었고 전부 정당한 사실 질문이었다(오탐 0):
"tesla v100 32gb 메모리 대역폭은 얼마지?", "미국 올 해 예산은 전 부 얼마지?"(실제로
기억에서 $7조 5,400억이 나갔다), "이자 비용은 연간 얼마지?" 등. 맨 "얼마나"는 비-사실
용법이 흔해 넣지 않았다.
* tool-scope climate 오탐 — "메모리 가격 추세"가 기후 재분석 아카이브 4종(~820토큰)을
통째로 실었다. "추세"/"장기"는 기후·기상 명사와 같이 나올 때만 걸리게 좁혔다.
* tool-scope kakao 오탐 — `` 첨부 파일명이 kakao_send_message를 실었다.
executeTool은 스키마 소속을 확인하지 않으므로([[project_tool_schema_leak]]) 이름만 언급돼도
호출될 수 있는 종류의 도구다. 첨부 파일명을 판정에서 빼고 카카오맵도 제외했다.
순효과 측정(고유 782건): 검색 강제 리마인더 주입률 23.8% → 25.4%(+13건). 새로 잡힌 13건은
전부 정당한 사실 질문이고, 잃은 건 0건이다.
감사에서 이상 없음으로 확인한 것: EMPTY-GROUNDING·MESSAGING(전제를 직접 검증),
decideAutoRecover·correctNewsCategoryForBreadth(도구 출력 대조 안 함), link-validator(URL 직접
프로브), satellite 게이트("도달 > 비용" 원칙상 유지), 0건 발동 게이트 6종(전용 앱 탭 경로).
테스트 536개 통과(+15).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rfme1WVEPkpNwnf5oVNXXc
This commit is contained in:
@@ -453,3 +453,53 @@ describe('confirmsUserGuessWithoutGrounding — 근거 없는 동조', () => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 2026-09-04 도달률 감사 — 실사용 로그 1,011건(고유 782건)을 게이트에 통과시켜 나온 오탐/미탐.
|
||||
* 인용은 전부 로그의 실제 발화다.
|
||||
*/
|
||||
describe('도달률 감사 회귀 (2026-09-04)', () => {
|
||||
test('isCancelIntent: 지명이 취소 명령으로 읽히면 안 된다', () => {
|
||||
// "하지마(波島) 유적지"가 `하지\s*마`에 걸렸다. 이 게이트가 참이면 진행 중이던 작업이
|
||||
// 일시정지되고 사용자의 지리 질문은 답 대신 작업제어 응답으로 하이재킹된다.
|
||||
assert.equal(isCancelIntent('하지마 유적지는 바다와 떨어져 있는데?'), false);
|
||||
assert.equal(isCancelIntent('그만해도 되나 궁금한데 계속 할까?'), false);
|
||||
});
|
||||
|
||||
test('isCancelIntent: 진짜 취소 명령은 계속 잡는다', () => {
|
||||
for (const m of ['그거 하지마', '취소해', '작업 중단해', '이거 취소해줘', '그만해!', '멈춰주세요']) {
|
||||
assert.equal(isCancelIntent(m), true, m);
|
||||
}
|
||||
});
|
||||
|
||||
test('isExecutionLikeRequest: 의료용 "패치"가 실행형으로 분류되면 안 된다', () => {
|
||||
// 이 함수는 검증 강제에서 **면제**시키는 쪽이라, 오탐이면 실존 제품의 기능·가격을
|
||||
// 검색 없이 기억으로 답해도 아무도 막지 않는다.
|
||||
assert.equal(isExecutionLikeRequest('인슐린 패치는 혈당 측정 기능이 없나?'), false);
|
||||
assert.equal(isExecutionLikeRequest('패치는 많이 비싼가?'), false);
|
||||
});
|
||||
|
||||
test('isExecutionLikeRequest: 소프트웨어 패치는 계속 실행형', () => {
|
||||
for (const m of ['이거 패치해줘', '패치 적용해줘', '패치 파일 어디 있어']) {
|
||||
assert.equal(isExecutionLikeRequest(m), true, m);
|
||||
}
|
||||
});
|
||||
|
||||
test('isFactualInfoRequest: "얼마" 계열 수량·가격 질문', () => {
|
||||
// 표본에서 이 표현으로 물었는데 어떤 검증 게이트에도 안 걸린 5건 — 전부 정당한 사실 질문이었다.
|
||||
for (const m of [
|
||||
'tesla v100 32gb 메모리 대역폭은 얼마지?',
|
||||
'미국 올 해 예산은 전 부 얼마지?',
|
||||
'이자 비용은 연간 얼마지?',
|
||||
'서울에서 부산까지 거리가 얼마야?',
|
||||
'패치는 많이 비싼가?',
|
||||
]) {
|
||||
assert.equal(isFactualInfoRequest(m), true, m);
|
||||
}
|
||||
});
|
||||
|
||||
test('isFactualInfoRequest: 맨 "얼마나"는 넣지 않았다 — 비-사실 용법이 흔하다', () => {
|
||||
assert.equal(isFactualInfoRequest('얼마나 걸려?'), false);
|
||||
assert.equal(isFactualInfoRequest('시간이 얼마나 남았지'), false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user