Compare commits
No commits in common. "forge/iss-6da9ba883259-attempt-1-run-99a8b746f8fa" and "main" have entirely different histories.
forge/iss-
...
main
7 changed files with 0 additions and 910 deletions
|
|
@ -1,3 +0,0 @@
|
|||
# iss-6da9ba883259-attempt-1-run-99a8b746f8fa
|
||||
|
||||
Forge 이슈 작업 브랜치 `forge/iss-6da9ba883259-attempt-1-run-99a8b746f8fa`.
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
# 계획 계약 명세서 (Planning Contract Specification)
|
||||
|
||||
## 개요
|
||||
|
||||
MiniMax 기반 에이전트의 계획 계약은 에이전트가 수립한 계획의 품질, 완전성, 실행 가능성을 보장하기 위한 명세서이다. 본 문서는 계약의 각 조항과 그에 대한 검증 기준을 정의한다.
|
||||
|
||||
---
|
||||
|
||||
## 용어 정의
|
||||
|
||||
| 용어 | 정의 |
|
||||
|------|------|
|
||||
| **계약 (Contract)** | 에이전트의 계획 수립 행위에 대한 명시적 약속 및 조건 |
|
||||
| **조항 (Clause)** | 계약의 구성 단위로서 특정 요구사항을 표현 |
|
||||
| **검증 기준 (Verification Criteria)** | 조항의 성립 여부를 판단하는 성공/실패 조건 |
|
||||
| **계획 (Plan)** | 목표 달성을 위한 단계별 행동 시퀀스 |
|
||||
| **에피타이드 (Epitaph)** | 계획 실행 결과의 기록 및 평가 |
|
||||
|
||||
---
|
||||
|
||||
## 계약 조항 명세
|
||||
|
||||
### 조항 1: 목표 명확성 (Goal Clarity)
|
||||
|
||||
**설명**: 수립된 계획은 명확하고 측정 가능한 목표를 포함해야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 목표가 구체적인 수치 또는 상태로 표현됨<br>- 목표 달성을 판단할 수 있는 명확한 기준 존재<br>- 목표가 단일 책임 원칙을 따름 (하나의 주요 결과) |
|
||||
| **실패 조건** | - 목표가 모호한 표현으로 기술됨 (예: "좋게 만들기")<br>- 성공/실패 판단 기준이 없음<br>- 하나의 계획에 두 개 이상의 독립적 목표 포함 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 2: 단계 완전성 (Step Completeness)
|
||||
|
||||
**설명**: 계획은 목표 달성까지 필요한 모든 단계를 포함해야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 각 단계가 선행 조건을 만족함<br>- 모든 의존성 단계가 순서대로 배치됨<br>- 최종 단계에서 목표 달성 보장 |
|
||||
| **실패 조건** | - 필수 단계가 누락됨<br>- 단계 간 의존성 순서 위반<br>- 목표에 도달하지 않는 불완전한 시퀀스 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 3: 실행 가능성 (Executability)
|
||||
|
||||
**설명**: 계획의 각 단계는 현재 환경에서 실행 가능한 명령이어야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 각 단계의 명령어가 시스템에서 사용 가능함<br>- 필요한 리소스(파일, 권한, 도구)가 확보됨<br>- 단계 실행에 대한 타임아웃이 설정됨 |
|
||||
| **실패 조건** | - 존재하지 않는 명령어 또는 도구 참조<br>- 필요한 리소스 접근 권한 없음<br>- 무한 대기 가능성이 있는 단계 포함 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 4: 리스크 평가 (Risk Assessment)
|
||||
|
||||
**설명**: 계획은 잠재적 리스크를 식별하고 완화 전략을 포함해야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 각 단계별 잠재적 리스크 명시됨<br>- 리스크 발생 시 대안 경로 또는 복구 전략 존재<br>- 중요 리스크에 대한 회피 또는 감소 조치 포함 |
|
||||
| **실패 조건** | - 리스크 식별 없이 진행<br>- 복구 전략 없는 단일 실패 지점 존재<br>- 치명적 리스크에 대한 무시 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 5: 검증 가능성 (Verifiability)
|
||||
|
||||
**설명**: 계획의 각 단계는 실행 후 결과를 검증할 수 있어야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 각 단계에 대한 예상 결과 명시됨<br>- 성공/실패를 판단하는 어설션 존재<br>- 검증 방법이 자동화 가능함 |
|
||||
| **실패 조건** | - 단계 실행 결과 확인 방법 없음<br>- 주관적 판단에만 의존하는 검증<br>- 검증 불가능한 상태 변경 포함 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 6: 시간적 제약 (Temporal Constraints)
|
||||
|
||||
**설명**: 계획은 실행 시간에 대한 합리적인 제약 조건을 포함해야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 전체 계획에 대한 예상 소요 시간 명시<br>- 각 단계별 타임아웃 설정<br>- 시간 초과 시 대체 전략 존재 |
|
||||
| **실패 조건** | - 시간 제약 없이 무한 대기 가능<br>- 현실적이지 않은 시간 추정<br>- 타임아웃 없는 장시간 작업 |
|
||||
|
||||
---
|
||||
|
||||
### 조항 7: 롤백 가능성 (Rollback Capability)
|
||||
|
||||
**설명**: 계획은 실패 시 이전 상태로 복구할 수 있는 메커니즘을 포함해야 한다.
|
||||
|
||||
**검증 기준**:
|
||||
|
||||
| 구분 | 조건 |
|
||||
|------|------|
|
||||
| **성공 조건** | - 각 변경 단계에 대한 롤백 명령 정의됨<br>- 롤백 실행 순서가 명확함<br>- 롤백 성공 여부 검증 방법 존재 |
|
||||
| **실패 조건** | - 롤백 메커니즘 없음<br>- 일관성 없는 롤백 시퀀스<br>- 롤백 불가능한 영구 변경 포함 |
|
||||
|
||||
---
|
||||
|
||||
## 계약 등급
|
||||
|
||||
| 등급 | 충족 조항 수 | 설명 |
|
||||
|------|-------------|------|
|
||||
| **A (최상)** | 7/7 | 모든 조항 충족, 최고 품질 보장 |
|
||||
| **B (양호)** | 5-6/7 | 주요 조항 충족, 일부 개선 필요 |
|
||||
| **C (미흡)** | 3-4/7 | 기본 구조는 있으나 신뢰성 낮음 |
|
||||
| **D (위험)** | 1-2/7 | 심각한 결함, 실행 권장 불가 |
|
||||
| **F (실패)** | 0/7 | 계약 미충족, 계획 부적격 |
|
||||
|
||||
---
|
||||
|
||||
## 검증 프로세스
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ 계획 수립 │───▶│ 계약 검증 │───▶│ 등급 부여 │
|
||||
└─────────────┘ └──────────────┘ └─────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ 실패 조항 분석 │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 에피타이드 기록 스키마
|
||||
|
||||
```json
|
||||
{
|
||||
"planId": "string",
|
||||
"timestamp": "ISO8601",
|
||||
"grade": "A|B|C|D|F",
|
||||
"clauses": {
|
||||
"goalClarity": { "passed": boolean, "details": "string" },
|
||||
"stepCompleteness": { "passed": boolean, "details": "string" },
|
||||
"executability": { "passed": boolean, "details": "string" },
|
||||
"riskAssessment": { "passed": boolean, "details": "string" },
|
||||
"verifiability": { "passed": boolean, "details": "string" },
|
||||
"temporalConstraints": { "passed": boolean, "details": "string" },
|
||||
"rollbackCapability": { "passed": boolean, "details": "string" }
|
||||
},
|
||||
"executionResult": {
|
||||
"status": "success|partial|failure",
|
||||
"duration": "number (ms)",
|
||||
"deviationFromPlan": "string|null"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 버전 | 날짜 | 변경 내용 |
|
||||
|------|------|----------|
|
||||
| 1.0.0 | 2026-07-14 | 초기 버전 작성 |
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
/**
|
||||
* 계획 계약 검증기 테스트
|
||||
*/
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
/**
|
||||
* 계획 계약 검증기 (Planning Contract Validator)
|
||||
*
|
||||
* 조항별 검증 로직을 구현하여 계획의 계약 충족 여부를 판단한다.
|
||||
*/
|
||||
|
||||
import { Plan, ClauseResult, ContractGrade, Epitaph } from './types';
|
||||
|
||||
/**
|
||||
* 조항 1: 목표 명확성 검증
|
||||
*/
|
||||
export function validateGoalClarity(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
// 목표가 존재하는지 확인
|
||||
if (!plan.goal) {
|
||||
issues.push('목표가 정의되지 않음');
|
||||
return { passed: false, issues };
|
||||
}
|
||||
|
||||
// 목표가 구체적인지 확인 (모호한 표현 체크)
|
||||
const vaguePatterns = [
|
||||
/좋게|잘|빠르게|최적으로|최대한/g,
|
||||
/better|good|faster|optimal|best/g
|
||||
];
|
||||
|
||||
for (const pattern of vaguePatterns) {
|
||||
if (pattern.test(plan.goal.description)) {
|
||||
issues.push(`모호한 표현 감지: "${plan.goal.description.match(pattern)?.[0]}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// 측정 가능한 기준 존재 확인
|
||||
if (!plan.goal.criteria || plan.goal.criteria.length === 0) {
|
||||
issues.push('목표 달성 판단 기준이 없음');
|
||||
}
|
||||
|
||||
// 단일 책임 원칙 확인
|
||||
if (plan.goal.subGoals && plan.goal.subGoals.length > 2) {
|
||||
issues.push('두 개 이상의 독립적 목표 포함 (단일 책임 위반)');
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 2: 단계 완전성 검증
|
||||
*/
|
||||
export function validateStepCompleteness(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
if (!plan.steps || plan.steps.length === 0) {
|
||||
issues.push('단계가 정의되지 않음');
|
||||
return { passed: false, issues };
|
||||
}
|
||||
|
||||
// 각 단계의 선행 조건 확인
|
||||
for (let i = 0; i < plan.steps.length; i++) {
|
||||
const step = plan.steps[i];
|
||||
|
||||
if (step.dependencies) {
|
||||
for (const depId of step.dependencies) {
|
||||
const depIndex = plan.steps.findIndex(s => s.id === depId);
|
||||
if (depIndex === -1) {
|
||||
issues.push(`단계 ${step.id}: 존재하지 않는 의존성 ${depId}`);
|
||||
} else if (depIndex >= i) {
|
||||
issues.push(`단계 ${step.id}: 의존성 ${depId}가 순서 위반 (${depIndex} >= ${i})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 단계에서 목표 달성 확인
|
||||
const lastStep = plan.steps[plan.steps.length - 1];
|
||||
if (lastStep && plan.goal) {
|
||||
if (!lastStep.produces?.some(p => plan.goal?.produces?.includes(p))) {
|
||||
// 목표 달성을 위한产出가 최종 단계에 없음
|
||||
const hasGoalConnection = plan.steps.some(step =>
|
||||
step.produces?.some(p => plan.goal?.produces?.includes(p))
|
||||
);
|
||||
if (!hasGoalConnection) {
|
||||
issues.push('어떤 단계도 목표 달성에 기여하지 않음');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 3: 실행 가능성 검증
|
||||
*/
|
||||
export function validateExecutability(plan: Plan, availableCommands: string[]): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
if (!plan.steps) return { passed: false, issues: ['단계 없음'] };
|
||||
|
||||
for (const step of plan.steps) {
|
||||
// 명령어 존재 확인
|
||||
if (step.command && !availableCommands.includes(step.command)) {
|
||||
issues.push(`단계 ${step.id}: 명령어 "${step.command}" 사용 불가`);
|
||||
}
|
||||
|
||||
// 리소스 확인
|
||||
if (step.requiredResources) {
|
||||
for (const resource of step.requiredResources) {
|
||||
if (!availableCommands.includes(resource)) {
|
||||
issues.push(`단계 ${step.id}: 필요한 리소스 "${resource}" 없음`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 타임아웃 확인
|
||||
if (!step.timeout || step.timeout <= 0) {
|
||||
issues.push(`단계 ${step.id}: 타임아웃 미설정`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 4: 리스크 평가 검증
|
||||
*/
|
||||
export function validateRiskAssessment(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
if (!plan.risks || plan.risks.length === 0) {
|
||||
issues.push('리스크 식별 없음');
|
||||
}
|
||||
|
||||
if (plan.risks) {
|
||||
for (const risk of plan.risks) {
|
||||
// 리스크에 대한 완화 전략 확인
|
||||
if (!risk.mitigation) {
|
||||
issues.push(`리스크 "${risk.description}": 완화 전략 없음`);
|
||||
}
|
||||
|
||||
// 대안 경로 확인 (중간 리스크 이상)
|
||||
if (risk.severity === 'high' || risk.severity === 'critical') {
|
||||
if (!risk.alternativePath) {
|
||||
issues.push(`고위험 리스크 "${risk.description}": 대안 경로 없음`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 5: 검증 가능성 검증
|
||||
*/
|
||||
export function validateVerifiability(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
if (!plan.steps) return { passed: false, issues: ['단계 없음'] };
|
||||
|
||||
for (const step of plan.steps) {
|
||||
// 예상 결과 확인
|
||||
if (!step.expectedOutcome) {
|
||||
issues.push(`단계 ${step.id}: 예상 결과 미정의`);
|
||||
}
|
||||
|
||||
// 어설션 확인
|
||||
if (!step.assertions || step.assertions.length === 0) {
|
||||
issues.push(`단계 ${step.id}: 검증 어설션 없음`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 6: 시간적 제약 검증
|
||||
*/
|
||||
export function validateTemporalConstraints(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
// 전체 예상 소요 시간 확인
|
||||
if (!plan.estimatedDuration) {
|
||||
issues.push('전체 예상 소요 시간 미정의');
|
||||
}
|
||||
|
||||
// 각 단계 타임아웃 확인
|
||||
if (plan.steps) {
|
||||
for (const step of plan.steps) {
|
||||
if (!step.timeout || step.timeout <= 0) {
|
||||
issues.push(`단계 ${step.id}: 타임아웃 없음`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 시간 초과 시 대체 전략 확인
|
||||
if (plan.timeoutStrategy) {
|
||||
issues.push('시간 초과 시 대체 전략 없음');
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 조항 7: 롤백 가능성 검증
|
||||
*/
|
||||
export function validateRollbackCapability(plan: Plan): ClauseResult {
|
||||
const issues: string[] = [];
|
||||
|
||||
// 롤백 명령 정의 확인
|
||||
if (!plan.rollbackCommands || plan.rollbackCommands.length === 0) {
|
||||
issues.push('롤백 명령 미정의');
|
||||
}
|
||||
|
||||
// 롤백 시퀀스 순서 확인
|
||||
if (plan.rollbackCommands) {
|
||||
for (let i = 0; i < plan.rollbackCommands.length; i++) {
|
||||
const cmd = plan.rollbackCommands[i];
|
||||
if (!cmd.order || cmd.order !== plan.rollbackCommands.length - i) {
|
||||
issues.push(`롤백 명령 ${cmd.id}: 순서 미지정 또는 역순 아님`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 롤백 성공 여부 검증 방법 확인
|
||||
if (plan.rollbackCommands) {
|
||||
for (const cmd of plan.rollbackCommands) {
|
||||
if (!cmd.verification) {
|
||||
issues.push(`롤백 명령 ${cmd.id}: 성공 여부 검증 방법 없음`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
passed: issues.length === 0,
|
||||
issues
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 전체 계약 검증
|
||||
*/
|
||||
export function validateContract(
|
||||
plan: Plan,
|
||||
availableCommands: string[] = []
|
||||
): { grade: ContractGrade; results: Record<string, ClauseResult> } {
|
||||
const results: Record<string, ClauseResult> = {
|
||||
goalClarity: validateGoalClarity(plan),
|
||||
stepCompleteness: validateStepCompleteness(plan),
|
||||
executability: validateExecutability(plan, availableCommands),
|
||||
riskAssessment: validateRiskAssessment(plan),
|
||||
verifiability: validateVerifiability(plan),
|
||||
temporalConstraints: validateTemporalConstraints(plan),
|
||||
rollbackCapability: validateRollbackCapability(plan)
|
||||
};
|
||||
|
||||
const passedCount = Object.values(results).filter(r => r.passed).length;
|
||||
|
||||
let grade: ContractGrade;
|
||||
if (passedCount === 7) grade = 'A';
|
||||
else if (passedCount >= 5) grade = 'B';
|
||||
else if (passedCount >= 3) grade = 'C';
|
||||
else if (passedCount >= 1) grade = 'D';
|
||||
else grade = 'F';
|
||||
|
||||
return { grade, results };
|
||||
}
|
||||
|
||||
/**
|
||||
* 에피타이드 생성
|
||||
*/
|
||||
export function createEpitaph(
|
||||
plan: Plan,
|
||||
validationResult: { grade: ContractGrade; results: Record<string, ClauseResult> },
|
||||
executionResult: { status: 'success' | 'partial' | 'failure'; duration: number; deviationFromPlan?: string }
|
||||
): Epitaph {
|
||||
return {
|
||||
planId: plan.id,
|
||||
timestamp: new Date().toISOString(),
|
||||
grade: validationResult.grade,
|
||||
clauses: validationResult.results,
|
||||
executionResult
|
||||
};
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"name": "planning-contract",
|
||||
"version": "1.0.0",
|
||||
"description": "MiniMax 기반 에이전트의 계획 계약 명세서 및 검증기",
|
||||
"main": "dist/contract-validator.js",
|
||||
"types": "dist/types.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.2",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node",
|
||||
"moduleFileExtensions": ["ts", "js", "json"],
|
||||
"testMatch": ["**/*.test.ts"]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"lib": ["ES2020"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
* 계획 계약 타입 정의
|
||||
*/
|
||||
|
||||
/** 계약 등급 */
|
||||
export type ContractGrade = 'A' | 'B' | 'C' | 'D' | 'F';
|
||||
|
||||
/** 조항 검증 결과 */
|
||||
export interface ClauseResult {
|
||||
passed: boolean;
|
||||
issues: string[];
|
||||
}
|
||||
|
||||
/** 목표 정의 */
|
||||
export interface Goal {
|
||||
description: string;
|
||||
criteria: string[];
|
||||
produces?: string[];
|
||||
subGoals?: string[];
|
||||
}
|
||||
|
||||
/** 계획 단계 */
|
||||
export interface PlanStep {
|
||||
id: string;
|
||||
description: string;
|
||||
command?: string;
|
||||
dependencies?: string[];
|
||||
requiredResources?: string[];
|
||||
timeout?: number;
|
||||
expectedOutcome?: string;
|
||||
assertions?: string[];
|
||||
produces?: string[];
|
||||
}
|
||||
|
||||
/** 리스크 정의 */
|
||||
export interface Risk {
|
||||
id: string;
|
||||
description: string;
|
||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
||||
mitigation?: string;
|
||||
alternativePath?: string;
|
||||
}
|
||||
|
||||
/** 롤백 명령 */
|
||||
export interface RollbackCommand {
|
||||
id: string;
|
||||
command: string;
|
||||
order: number;
|
||||
verification?: string;
|
||||
}
|
||||
|
||||
/** 계획 */
|
||||
export interface Plan {
|
||||
id: string;
|
||||
goal: Goal;
|
||||
steps: PlanStep[];
|
||||
risks?: Risk[];
|
||||
estimatedDuration?: number;
|
||||
timeoutStrategy?: string;
|
||||
rollbackCommands?: RollbackCommand[];
|
||||
}
|
||||
|
||||
/** 에피타이드 (실행 결과 기록) */
|
||||
export interface Epitaph {
|
||||
planId: string;
|
||||
timestamp: string;
|
||||
grade: ContractGrade;
|
||||
clauses: {
|
||||
goalClarity: ClauseResult;
|
||||
stepCompleteness: ClauseResult;
|
||||
executability: ClauseResult;
|
||||
riskAssessment: ClauseResult;
|
||||
verifiability: ClauseResult;
|
||||
temporalConstraints: ClauseResult;
|
||||
rollbackCapability: ClauseResult;
|
||||
};
|
||||
executionResult: {
|
||||
status: 'success' | 'partial' | 'failure';
|
||||
duration: number;
|
||||
deviationFromPlan?: string | null;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue