Files
connectai/tests/meetPrompt.test.ts
T
koriweb 5d02a8a56f v2.2.257: /meet 회의록 책임 소재·근거 정책 4종
실제 회의록 산출물 분석에서 드러난 4개 결함을 프롬프트 정책으로 차단.
공유 출력 형식(단일샷+reduce)과 추출(map) 단계 모두에 적용.

- 익명·번호 화자("참석자 1")를 액션 담당으로 확정 금지 → [미지정-확인필요].
  한 익명에 액션 몰리면 "(동일 화자 여부 확인)" — 가짜 책임 배정 차단.
- 내용 없는 인용("이렇게 이렇게/그거") 근거 금지 → [내용 확인필요].
- 기한 역참조: 리스크·논의의 마감("다음 주 수요일")을 결부된 액션 기한에 반영.
- 참석자 명단 정합성: 본문 화자가 명단에 없으면 "(명단 외 화자 — 확인필요)".

§4 지시문·최종 점검 체크리스트 반영. 회귀 가드 +10건, 전체 694 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 18:19:20 +09:00

61 lines
2.7 KiB
TypeScript

/**
* Regression guard for the /meet prompt policy.
*
* These 4 rules were added after a real meeting record showed the failure modes:
* 1) anonymous/numbered speakers assigned as action owners (fake accountability)
* 2) content-empty deictic quotes ("이렇게 이렇게") passed off as 근거
* 3) deadlines mentioned in risks/discussion not reflected in action 기한
* 4) speakers in the body who aren't in the attendee list
*
* Prompts can't be unit-tested for model behavior, but we CAN guard that the
* policy text doesn't silently get dropped in a future refactor.
*/
import {
buildMeetPrompt,
buildMeetExtractPrompt,
buildMeetReducePrompt,
} from '../src/features/datacollect/prompts/meetPrompt';
const transcript = '참석자 1: 이거는 이렇게 이렇게 해주세요. 효희 팀장: 네 수정할게요.';
const metadata = '회의명: 테스트';
describe('/meet prompt — accountability & grounding policy', () => {
// The OUTPUT_FORMAT block is shared by the single-shot and reduce paths, so
// both must carry the policy.
const sharedFormatBuilders: Array<[string, string]> = [
['buildMeetPrompt', buildMeetPrompt(transcript, metadata)],
['buildMeetReducePrompt', buildMeetReducePrompt('## 액션\n- [미지정] 작업', metadata)],
];
test.each(sharedFormatBuilders)('%s forbids assigning anonymous speakers as owners', (_name, prompt) => {
expect(prompt).toContain('[미지정-확인필요]');
expect(prompt).toMatch(/익명·번호 화자/);
});
test.each(sharedFormatBuilders)('%s rejects content-empty deictic quotes', (_name, prompt) => {
expect(prompt).toContain('[내용 확인필요]');
expect(prompt).toMatch(/이렇게 이렇게/);
});
test.each(sharedFormatBuilders)('%s cross-references deadlines into action 기한', (_name, prompt) => {
expect(prompt).toMatch(/기한 역참조/);
});
test.each(sharedFormatBuilders)('%s flags speakers missing from the attendee list', (_name, prompt) => {
expect(prompt).toMatch(/명단 외 화자|참석자 명단 정합성/);
});
test('extract (map) stage also avoids anonymous owner assignment & empty quotes', () => {
const p = buildMeetExtractPrompt('참석자 1: 이거 이렇게요', metadata, 1, 3);
expect(p).toContain('[미지정]');
expect(p).toContain('[내용 확인필요]');
});
test('final checklist references the new gates', () => {
const prompt = buildMeetPrompt(transcript, metadata);
expect(prompt).toMatch(/익명·번호 화자를 담당으로 확정하지 않고/);
expect(prompt).toMatch(/빈 인용을 근거로 달지 않았는가/);
});
});