fix(tag-vocab): PR review round 1 — i1 dedup + m2 test gap (#3 v0.2.3)

- i1 (Important): AiWorker per-tag emit 루프에 res.tags Set dedup
  AI 가 같은 태그 중복 응답 시 hit count 2번 emit 되던 통계 왜곡 수정
  + 테스트 1개 (중복 태그 1 hit + 1 miss 검증)
- m2 (Minor): NoteRepository.getTopUsedTags LIMIT-then-filter 테스트 갭
  + 테스트 1개 (limit=3 + 한글 1 + kebab 2 → 결과 length=2 lock-in)

skip: m1 (per-tag serial await — ai_succeeded 패턴 일관),
      n1 (prompt 빈 줄 cosmetic), n2 (tagId positive — AUTOINCREMENT 1+)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
altair823
2026-05-02 12:49:36 +09:00
parent ff07738b02
commit d8621d55e0
3 changed files with 43 additions and 1 deletions

View File

@@ -716,6 +716,21 @@ describe('NoteRepository — failed retry helpers', () => {
expect(repo.getTopUsedTags(10)).toHaveLength(5);
});
it('getTopUsedTags result may be shorter than limit when top-N includes non-kebab tags', () => {
// 비-kebab 1개 (한글) + kebab 2개 → top-3 으로 SQL 가져온 후 regex 필터로 한글 제외
// 결과 length = 2 (limit=3 보다 작음)
const a = repo.create({ rawText: 'a' }).id;
const b = repo.create({ rawText: 'b' }).id;
const c = repo.create({ rawText: 'c' }).id;
repo.updateUserAiFields(a, { tags: ['회의'] }); // 한글 — SQL top 에 포함될 수 있지만 regex 통과 X
repo.updateUserAiFields(b, { tags: ['design'] });
repo.updateUserAiFields(c, { tags: ['meeting'] });
const top = repo.getTopUsedTags(3);
expect(top.length).toBeLessThan(3); // SQL 은 3개 가져왔지만 regex 가 1개 제거
expect(top).not.toContain('회의');
expect(top).toEqual(expect.arrayContaining(['design', 'meeting']));
});
it('getTagIdByName returns id when present, null when absent', () => {
const a = repo.create({ rawText: 'a' }).id;
repo.updateAiResult(a, { title: 't', summary: 'a\nb\nc', tags: ['hello'], provider: 'p' });