Files
connectai/tests/conflictCheck.test.ts
T
koriweb 2afd1ac589 feat: Self-Evolving Digital Employee OS P0~P6 + 캘린더 충돌 게이트
신뢰성 코어 (P1~P2):
- Requirement Graph: 업무 유형(회의록/시장조사/업무조사/일정) 필수 요소 주입 + 커버리지 hook
- Confidence Engine(0~100 결정론적) / Escalation Engine(검토 요청) / Epistemic Guard(모름·추정·확실 3분류)
- Provenance: citationTrace 에 출처 수정일·오래됨 경고
- Critic Loop: 문제 신호 turn 만 LLM 검수 1회 + 보완 카드

성장 루프 (P3):
- Gap Detector(Requirement-Knowledge) / Need Engine(30/25/20/15/10 공식) / Knowledge Inventory
- Learning Queue(proposed 전용 병합 — 승인은 사람만) / Decision Journal / Reflection 기록
- 반복 누락 요소(3회+)는 다음 turn 체크리스트에 자동 강조 (T5 루프)

지식 운영 (P4) + 기억 (P5) + 학습 실행 (P6):
- Knowledge Validation + Belief Revision(중복 reject·충돌 시 update/add 권고)
- Knowledge Decay(분야별 반감기 감사) / Knowledge Debt(blocked x impact)
- Organizational Memory(.astra/organization.md 상시 주입)
- Research Agent(approved 큐 -> 조사 브리프+추정 라벨 초안+Validation 게이트 -> proposals/)
- Skill Score(전/후반 추세) + Success Pattern DB(전요소충족+확신도90+ 자동 적재)

병렬 트랙:
- 캘린더 충돌 게이트: conflictCheck + 구조화 이벤트 캐시 + create_calendar_event 차단(force 는 사용자 승인 후)
- Task Eval Harness: 회의록 골든셋 자동 채점 명령 + 성장 리포트/학습 큐/노후 점검 명령

신규 모듈 17종(src/intelligence/), VS Code 명령 5종, 설정 11종, 테스트 +89건(전체 508 통과).
설계 문서: docs/SELF_EVOLVING_OS_MASTER_PLAN.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:42:09 +09:00

66 lines
2.8 KiB
TypeScript

/**
* Schedule Conflict Check (Self-Evolving OS Track 6-2/6-3) 테스트.
*/
import { findScheduleConflicts, formatConflictReport, CachedCalEvent } from '../src/features/calendar/conflictCheck';
import { _parseCalEventAttrs } from '../src/agent/attrParsers';
// 로컬 ISO (timezone 없음) — 실제 캐시도 로컬 자정 기준 all-day 를 담으므로
// 테스트를 실행 머신 timezone 과 무관하게 만든다.
const EXISTING: CachedCalEvent[] = [
{ summary: '주간회의', startIso: '2026-06-12T14:00:00', endIso: '2026-06-12T15:00:00', allDay: false, location: '회의실 A' },
{ summary: '워크숍', startIso: '2026-06-13T00:00:00', allDay: true },
];
describe('findScheduleConflicts', () => {
it('구간이 겹치면 충돌', () => {
const c = findScheduleConflicts(EXISTING, { startIso: '2026-06-12T14:30:00', durationMinutes: 60 });
expect(c.length).toBe(1);
expect(c[0].summary).toBe('주간회의');
});
it('경계 접촉(끝=시작)은 충돌 아님', () => {
const c = findScheduleConflicts(EXISTING, { startIso: '2026-06-12T15:00:00', durationMinutes: 60 });
expect(c.length).toBe(0);
});
it('endIso 없으면 기본 60분으로 판정', () => {
const c = findScheduleConflicts(EXISTING, { startIso: '2026-06-12T13:30:00' });
expect(c.length).toBe(1); // 13:30~14:30 vs 14:00~15:00
});
it('종일 일정과 그 날짜의 시간 일정은 충돌', () => {
const c = findScheduleConflicts(EXISTING, { startIso: '2026-06-13T10:00:00', durationMinutes: 30 });
expect(c.some((e) => e.summary === '워크숍')).toBe(true);
});
it('잘못된 날짜 입력은 보수적으로 충돌 없음 (생성 단계에서 실패)', () => {
expect(findScheduleConflicts(EXISTING, { startIso: 'not-a-date' })).toEqual([]);
expect(findScheduleConflicts([{ summary: 'x', startIso: 'broken', allDay: false }], { startIso: '2026-06-12T14:00:00' })).toEqual([]);
});
it('빈 캐시면 충돌 없음', () => {
expect(findScheduleConflicts([], { startIso: '2026-06-12T14:00:00' })).toEqual([]);
});
});
describe('formatConflictReport', () => {
it('충돌 목록 + force 안내 포함', () => {
const msg = formatConflictReport([EXISTING[0]]);
expect(msg).toContain('주간회의');
expect(msg).toContain('force="true"');
expect(msg).toContain('보류');
});
});
describe('_parseCalEventAttrs force 속성', () => {
it('force="true" 파싱', () => {
const attrs = _parseCalEventAttrs(' title="미팅" start="2026-06-12T14:00" force="true"');
expect(attrs.force).toBe(true);
});
it('미지정이면 undefined (기본 차단 동작)', () => {
const attrs = _parseCalEventAttrs(' title="미팅" start="2026-06-12T14:00"');
expect(attrs.force).toBeUndefined();
});
});