Files
connectai/tests/lsepClosersAndLeaks.test.ts
T
koriweb c79eda1862 v2.2.313~319: 보고 품질·조사 신뢰성 수술 + 네이버 쇼핑인사이트/검색어트렌드 연동
- 파트별 완성, 웹 실접속 증빙, 턴 의도 브리핑, 본문 불일치 검증, 하위 질문
  체크리스트, 사이트 심층 수집 (PATCHNOTES.md v2.2.313~318 참조)
- /naver-shopping, /naver-trend: 네이버 데이터랩 API 연동. compare/discover
  자동 판별, API 배치 상한 캡슐화, 카테고리 트리 fuzzy 매칭, 자격증명은
  Astra 설정 패널 SecretStorage 로 관리
2026-08-05 18:20:32 +09:00

64 lines
3.3 KiB
TypeScript

/**
* [v2.2.314] 두 실사례 가드:
* 1) LSEP 마커 뒤 "마무리 인사"만 남고 본문이 추론 구간에 갇혀 증발한 답변.
* 2) "요청 요약/사용자 의도 추론/핵심 확인 질문" 내부 스캐폴딩 섹션 유출.
*/
import {
splitLsepReasoning,
isCloserOnlyAnswer,
looksLikeReportBody,
stripLeakedInternalSections,
} from '../src/lib/contextBuilders/outputSanitization';
const MARKER = '__LM_STUDIO_INTERNAL_LSEP_SYNTHETIC_REASONING_END_a1b2c3d4e5f6__';
describe('splitLsepReasoning / isCloserOnlyAnswer / looksLikeReportBody', () => {
test('마지막 END 마커 기준으로 before/after 분해', () => {
const body = '## 1. 구조\n분석 본문. '.repeat(50);
const r = splitLsepReasoning(`${body}${MARKER}이상으로 분석을 마칩니다.`);
expect(r.hasMarker).toBe(true);
expect(r.before).toContain('## 1. 구조');
expect(r.after).toBe('이상으로 분석을 마칩니다.');
});
test('마커 없으면 hasMarker=false, after=원문', () => {
const r = splitLsepReasoning('일반 답변');
expect(r.hasMarker).toBe(false);
expect(r.after).toBe('일반 답변');
});
test('마무리 인사만 = closer-only, 실질 본문은 아님', () => {
expect(isCloserOnlyAnswer('이상으로 ConnectAI 프로젝트에 대한 분석을 마칩니다. 추가 검토가 필요하시면 언제든 요청해 주세요.')).toBe(true);
expect(isCloserOnlyAnswer('## 구조 분석\n실제 본문이 여기 길게 이어진다.')).toBe(false);
});
test('헤딩 다수 장문 = 보고 본문, 짧은 텍스트 = 아님', () => {
const report = ['## 개요', '본문 문단. '.repeat(60), '## 구조', '본문 문단. '.repeat(60)].join('\n\n');
expect(looksLikeReportBody(report)).toBe(true);
expect(looksLikeReportBody('짧은 생각')).toBe(false);
});
});
describe('stripLeakedInternalSections — 내부 섹션 유출 제거', () => {
test('금지 4종 섹션과 "질문 의도:" 줄을 제거하고 본문·출처는 보존', () => {
const answer = [
'## 프로젝트 개요', '실제 분석 본문.',
'## 요청 요약', 'ConnectAI 프로젝트 분석 요청입니다.',
'## 사용자 의도 추론', '전체 그림을 이해하고자 하는 의도로 판단됩니다.',
'## 프로젝트 기록 대상 확인', '기록으로 관리될 예정입니다.',
'## 핵심 확인 질문', '심층 분석이 필요하신가요?',
'질문 의도: 범위 확장 여부 결정.',
'## 분석 결과 요약', '요약 본문.',
].join('\n');
const out = stripLeakedInternalSections(answer);
expect(out).toContain('## 프로젝트 개요');
expect(out).toContain('## 분석 결과 요약');
expect(out).not.toContain('요청 요약');
expect(out).not.toContain('의도 추론');
expect(out).not.toContain('기록 대상 확인');
expect(out).not.toContain('핵심 확인 질문');
expect(out).not.toContain('질문 의도');
});
test('금지 섹션이 없으면 원문 유지', () => {
const clean = '## 개요\n본문\n\n## 다음 단계\n제안';
expect(stripLeakedInternalSections(clean)).toBe(clean);
});
});