47b3b9f93a
- v2.2.299 아키텍처 수렴: coreChat 통일(엔진 휴리스틱 3벌 제거), 기업 모드 검색 오케스트레이터 승격, lib/execUtil(실행 래퍼 6곳·Python 탐지 3벌 단일화), lib/kstSchedule(워처 4개 nowInKst 통합), estimateTokens 통합, 설정 접근 규칙 명문화 - v2.2.300 채팅 화면 정리: LiveReasoningFilter(스트리밍 중 <think>/Harmony 추론 토큰 단위 차단), 확신도·검토요청 footer 기본 숨김(계산·Reflection 은 유지) - v2.2.301 문맥·의도 이해: [답변 전 이해 원칙] 상시 주입, 워크플로우 의도 브리핑, Report QA 루프(규칙 레지스트리+실측치+회귀 게이트, 블로그_v3 개념 이식) - v2.2.302 /benchmark 비즈니스 렌즈(가격·수익·운영)+빌드 프롬프트 모드+QA 연계 - v2.2.303 handoff 모드(측정치 무손실 인수인계 문서)+/claude(Claude Code 터미널 위임) - v2.2.304 이식성: 지식 경로 두뇌-상대 규약(pickWikiDir 상대 해석), 이사 체크리스트 - v2.2.305 Claude 구독 엔진: claude: 프로바이더(CLI 위임, 모델 드롭다운 자동 노출, coreChat 지원 — 워크플로우·QA도 구독 모델 가능) - v2.2.306 Tone Guard: AI 상투어 금지 레지스트리(상담사 화법 실사례 8종+대조 예시) - v2.2.307 /benchmark 레이아웃 골격(sectionRoles 결정론 분석, 롤링 배너 즉답), 파트별 실패 격리, 합성 타임아웃 120→300초 검증: tsc 무오류 + jest 888 통과 + esbuild 정상 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.5 KiB
TypeScript
83 lines
3.5 KiB
TypeScript
import { buildLayoutSkeleton, classifyWidget } from '../src/features/datacollect/prompts/layoutSkeleton';
|
|
|
|
const SCAN = {
|
|
structure: {
|
|
sections: [
|
|
{ role: 'header', depth: 0, text: '메뉴', btns: 1, links: 8, imgs: 1, hint: 'site-header' },
|
|
{ role: 'section', depth: 1, text: '최신 글', btns: 0, links: 12, imgs: 10, hint: 'swiper-container hero-slider' },
|
|
{ role: 'section', depth: 1, text: '카테고리 글 목록', btns: 2, links: 20, imgs: 30, hint: 'post-grid archive' },
|
|
{ role: 'footer', depth: 0, text: '저작권', btns: 0, links: 4, imgs: 0, hint: 'site-footer' },
|
|
],
|
|
},
|
|
sitemap: {
|
|
pages: [
|
|
{ url: 'https://koritips.com/', role: 'other', primaryContentType: 'list-article', sectionRoles: [] },
|
|
{
|
|
url: 'https://koritips.com/about', role: 'about', primaryContentType: 'list-card',
|
|
sectionRoles: [
|
|
{ tag: 'header', hint: 'gnb', preview: '메뉴' },
|
|
{ tag: 'main', hint: 'about-content', preview: '소개 본문' },
|
|
{ tag: 'form', hint: 'newsletter-signup', preview: '구독하기' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
describe('classifyWidget — class/id 신호 위젯 판별', () => {
|
|
test('캐러셀 계열 class 를 롤링 배너로 감지', () => {
|
|
expect(classifyWidget('swiper-container hero-slider')).toContain('캐러셀');
|
|
expect(classifyWidget('slick-track')).toContain('캐러셀');
|
|
});
|
|
test('내비/푸터/구독 신호 판별', () => {
|
|
expect(classifyWidget('site-header gnb')).toContain('내비게이션');
|
|
expect(classifyWidget('newsletter-signup')).toContain('구독');
|
|
});
|
|
test('신호 없으면 null', () => {
|
|
expect(classifyWidget('random-xyz')).toBeNull();
|
|
expect(classifyWidget('')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('buildLayoutSkeleton — 결정론 골격 리포트', () => {
|
|
const md = buildLayoutSkeleton(SCAN);
|
|
|
|
test('홈의 위→아래 블록 순서를 그린다 (헤더→캐러셀→그리드→푸터)', () => {
|
|
const iHeader = md.indexOf('내비게이션');
|
|
const iCarousel = md.indexOf('캐러셀');
|
|
const iGrid = md.indexOf('카드/리스트 그리드');
|
|
const iFooter = md.indexOf('푸터');
|
|
expect(iHeader).toBeGreaterThan(-1);
|
|
expect(iHeader).toBeLessThan(iCarousel);
|
|
expect(iCarousel).toBeLessThan(iGrid);
|
|
expect(iGrid).toBeLessThan(iFooter);
|
|
});
|
|
|
|
test('롤링 배너 유무에 즉답한다', () => {
|
|
expect(md).toContain('롤링 배너/캐러셀: **있음**');
|
|
});
|
|
|
|
test('하위 페이지 골격도 포함한다', () => {
|
|
expect(md).toContain('`/about`');
|
|
expect(md).toContain('구독/CTA');
|
|
});
|
|
|
|
test('버튼/이미지/링크 수를 표기한다', () => {
|
|
expect(md).toContain('이미지 10');
|
|
expect(md).toContain('링크 8');
|
|
});
|
|
|
|
test('캐러셀 신호가 없으면 "신호 없음 + 실사이트 확인 권장"으로 정직하게', () => {
|
|
const noCarousel = buildLayoutSkeleton({
|
|
structure: { sections: [{ role: 'header', hint: 'site-header', text: '' }] },
|
|
sitemap: { pages: [] },
|
|
});
|
|
expect(noCarousel).toContain('신호 없음');
|
|
expect(noCarousel).toContain('실사이트 확인 권장');
|
|
});
|
|
|
|
test('빈 스캔에도 깨지지 않는다', () => {
|
|
expect(buildLayoutSkeleton({})).toContain('섹션 데이터가 스캔에 없습니다');
|
|
});
|
|
});
|