/** * byte-fallback — 새어나온 바이트 토큰 복원 * * 2026-08-12 실사고: 뉴스 요약 답변이 "눈에 <0xEB><0x9D><0x95>니다"로 나왔다. EB 9D 95는 * U+B755 = 띕. 모델은 정확한 바이트를 냈고 디토크나이저가 못 붙인 것뿐이라, 정답이 완전히 * 결정되는 무손실 복원이다. * * 이 테스트가 지키는 두 가지 안전선: * 1) 유효한 UTF-8로 디코드되는 것만 바꾼다 — 아니면 원문이 더 충실하다 * 2) 코드블록 안은 건드리지 않는다 — 거기 있는 <0xEB>는 내용이다 */ import { test, describe } from 'node:test'; import assert from 'node:assert/strict'; import { repairByteFallbackTokens } from '../src/providers/byte-fallback'; describe('복원', () => { test('실사고 문장', () => { assert.equal( repairByteFallbackTokens('정치적 갈등과 사회적 사건들이 눈에 <0xEB><0x9D><0x95>니다.'), '정치적 갈등과 사회적 사건들이 눈에 띕니다.', ); }); test('한 문장에 여러 군데', () => { assert.equal( repairByteFallbackTokens('<0xEB><0x9D><0x95>고 <0xEB><0x9D><0x95>고'), '띕고 띕고', ); }); test('바이트 토큰이 없으면 그대로 반환한다', () => { const s = '평범한 문장입니다. 0x1F 같은 표기도 건드리지 않습니다.'; assert.equal(repairByteFallbackTokens(s), s); }); test('빈 입력', () => { assert.equal(repairByteFallbackTokens(''), ''); assert.equal(repairByteFallbackTokens(null as any), ''); }); }); describe('안전선', () => { test('유효한 UTF-8이 아니면 원문을 남긴다', () => { // 0xFF는 UTF-8 어디에도 나올 수 없는 바이트다. 잘린 글자가 아니므로 U+FFFD로 바꾸면 // 복원이 아니라 정보 파괴가 된다. assert.equal(repairByteFallbackTokens('앞 <0xFF> 뒤'), '앞 <0xFF> 뒤'); }); test('코드블록 안은 건드리지 않는다', () => { const s = '설명입니다.\n```\nbytes = <0xEB><0x9D><0x95>\n```\n끝.'; assert.equal(repairByteFallbackTokens(s), s); }); test('인라인 코드도 건드리지 않는다', () => { assert.equal( repairByteFallbackTokens('토큰 `<0xEB>` 는 바이트 폴백 표기입니다.'), '토큰 `<0xEB>` 는 바이트 폴백 표기입니다.', ); }); test('코드블록 밖은 고치고 안은 남긴다 — 한 문서에 섞여 있어도', () => { assert.equal( repairByteFallbackTokens('눈에 <0xEB><0x9D><0x95>니다.\n```\n<0xEB><0x9D><0x95>\n```'), '눈에 띕니다.\n```\n<0xEB><0x9D><0x95>\n```', ); }); });