계획 계약 명세서 정의 및 검증 기준 분석 (iss-6da9ba883259)
This commit is contained in:
parent
022ec6616c
commit
43e4786a44
1 changed files with 312 additions and 0 deletions
312
planning-contract/contract-validator.test.ts
Normal file
312
planning-contract/contract-validator.test.ts
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
/**
|
||||||
|
* 계획 계약 검증기 테스트
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
validateGoalClarity,
|
||||||
|
validateStepCompleteness,
|
||||||
|
validateExecutability,
|
||||||
|
validateRiskAssessment,
|
||||||
|
validateVerifiability,
|
||||||
|
validateTemporalConstraints,
|
||||||
|
validateRollbackCapability,
|
||||||
|
validateContract,
|
||||||
|
createEpitaph
|
||||||
|
} from './contract-validator';
|
||||||
|
import { Plan } from './types';
|
||||||
|
|
||||||
|
describe('계획 계약 검증기', () => {
|
||||||
|
describe('조항 1: 목표 명확성', () => {
|
||||||
|
it('명확한 목표는 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-1',
|
||||||
|
goal: {
|
||||||
|
description: '테스트 파일 10개 생성',
|
||||||
|
criteria: ['파일 10개 생성됨', '각 파일 크기 > 0'],
|
||||||
|
produces: ['test-files']
|
||||||
|
},
|
||||||
|
steps: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateGoalClarity(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
expect(result.issues).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('모호한 표현이 있으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-2',
|
||||||
|
goal: {
|
||||||
|
description: '테스트 파일을 잘 생성',
|
||||||
|
criteria: []
|
||||||
|
},
|
||||||
|
steps: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateGoalClarity(plan);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
expect(result.issues.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('판단 기준이 없으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-3',
|
||||||
|
goal: {
|
||||||
|
description: '파일 생성',
|
||||||
|
criteria: []
|
||||||
|
},
|
||||||
|
steps: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateGoalClarity(plan);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
expect(result.issues).toContain('목표 달성 판단 기준이 없음');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 2: 단계 완전성', () => {
|
||||||
|
it('올바른 의존성 순서는 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-4',
|
||||||
|
goal: {
|
||||||
|
description: '빌드 완료',
|
||||||
|
criteria: ['빌드 성공'],
|
||||||
|
produces: ['build-output']
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{ id: 'step1', description: '의존성 설치', produces: ['deps'] },
|
||||||
|
{ id: 'step2', description: '컴파일', dependencies: ['step1'], produces: ['build-output'] }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateStepCompleteness(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('순서 위반이 있으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-5',
|
||||||
|
goal: {
|
||||||
|
description: '빌드 완료',
|
||||||
|
criteria: ['빌드 성공']
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{ id: 'step1', description: '컴파일', dependencies: ['step2'] },
|
||||||
|
{ id: 'step2', description: '의존성 설치' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateStepCompleteness(plan);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 3: 실행 가능성', () => {
|
||||||
|
it('사용 가능한 명령어는 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-6',
|
||||||
|
goal: { description: '테스트', criteria: ['완료'] },
|
||||||
|
steps: [
|
||||||
|
{ id: 'step1', command: 'npm', timeout: 30000 }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateExecutability(plan, ['npm', 'node']);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('타임아웃 없으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-7',
|
||||||
|
goal: { description: '테스트', criteria: ['완료'] },
|
||||||
|
steps: [
|
||||||
|
{ id: 'step1', command: 'npm' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateExecutability(plan, ['npm']);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
expect(result.issues).toContain('단계 step1: 타임아웃 미설정');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 4: 리스크 평가', () => {
|
||||||
|
it('리스크와 완화 전략이 있으면 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-8',
|
||||||
|
goal: { description: '배포', criteria: ['성공'] },
|
||||||
|
steps: [],
|
||||||
|
risks: [
|
||||||
|
{
|
||||||
|
id: 'risk1',
|
||||||
|
description: '네트워크 오류',
|
||||||
|
severity: 'medium',
|
||||||
|
mitigation: '재시도 로직 구현'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateRiskAssessment(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('고위험 리스크에 대안 경로 없으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-9',
|
||||||
|
goal: { description: '배포', criteria: ['성공'] },
|
||||||
|
steps: [],
|
||||||
|
risks: [
|
||||||
|
{
|
||||||
|
id: 'risk1',
|
||||||
|
description: '데이터 손상',
|
||||||
|
severity: 'critical'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateRiskAssessment(plan);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 5: 검증 가능성', () => {
|
||||||
|
it('예상 결과와 어설션이 있으면 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-10',
|
||||||
|
goal: { description: '파일 생성', criteria: ['완료'] },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: 'step1',
|
||||||
|
description: '파일 생성',
|
||||||
|
expectedOutcome: '파일이 생성됨',
|
||||||
|
assertions: ['file.exists()']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateVerifiability(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('어설션 없으면 실패해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-11',
|
||||||
|
goal: { description: '파일 생성', criteria: ['완료'] },
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: 'step1',
|
||||||
|
description: '파일 생성',
|
||||||
|
expectedOutcome: '파일이 생성됨'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateVerifiability(plan);
|
||||||
|
expect(result.passed).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 6: 시간적 제약', () => {
|
||||||
|
it('시간 제약이 설정되면 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-12',
|
||||||
|
goal: { description: '빌드', criteria: ['완료'] },
|
||||||
|
steps: [
|
||||||
|
{ id: 'step1', timeout: 60000 }
|
||||||
|
],
|
||||||
|
estimatedDuration: 120000,
|
||||||
|
timeoutStrategy: '실패 후 롤백'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateTemporalConstraints(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('조항 7: 롤백 가능성', () => {
|
||||||
|
it('올바른 롤백 시퀀스가 있으면 통과해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-13',
|
||||||
|
goal: { description: '배포', criteria: ['완료'] },
|
||||||
|
steps: [],
|
||||||
|
rollbackCommands: [
|
||||||
|
{ id: 'rb1', command: 'rollback-step2', order: 2, verification: 'check-state' },
|
||||||
|
{ id: 'rb2', command: 'rollback-step1', order: 1, verification: 'check-state' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateRollbackCapability(plan);
|
||||||
|
expect(result.passed).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('전체 계약 검증', () => {
|
||||||
|
it('모든 조항 충족 시 A 등급 부여', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-full',
|
||||||
|
goal: {
|
||||||
|
description: '완전한 테스트 계획',
|
||||||
|
criteria: ['모든 단계 성공'],
|
||||||
|
produces: ['result']
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: 'step1',
|
||||||
|
description: '준비',
|
||||||
|
command: 'prepare',
|
||||||
|
timeout: 10000,
|
||||||
|
expectedOutcome: '준비 완료',
|
||||||
|
assertions: ['ready'],
|
||||||
|
produces: ['prepared']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'step2',
|
||||||
|
description: '실행',
|
||||||
|
command: 'execute',
|
||||||
|
dependencies: ['step1'],
|
||||||
|
timeout: 30000,
|
||||||
|
expectedOutcome: '실행 완료',
|
||||||
|
assertions: ['completed'],
|
||||||
|
produces: ['result']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
risks: [
|
||||||
|
{
|
||||||
|
id: 'risk1',
|
||||||
|
description: '실패 가능성',
|
||||||
|
severity: 'low',
|
||||||
|
mitigation: '재시도'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
estimatedDuration: 60000,
|
||||||
|
timeoutStrategy: '중단',
|
||||||
|
rollbackCommands: [
|
||||||
|
{ id: 'rb1', command: 'cleanup', order: 1, verification: 'check-clean' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = validateContract(plan, ['prepare', 'execute']);
|
||||||
|
expect(result.grade).toBe('A');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('에피타이드 생성', () => {
|
||||||
|
it('올바른 에피타이드를 생성해야 함', () => {
|
||||||
|
const plan: Plan = {
|
||||||
|
id: 'test-epitaph',
|
||||||
|
goal: { description: '테스트', criteria: ['완료'] },
|
||||||
|
steps: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const validation = validateContract(plan);
|
||||||
|
const epitaph = createEpitaph(plan, validation, {
|
||||||
|
status: 'success',
|
||||||
|
duration: 5000
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(epitaph.planId).toBe('test-epitaph');
|
||||||
|
expect(epitaph.timestamp).toBeDefined();
|
||||||
|
expect(epitaph.executionResult.status).toBe('success');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue