modify harness framework

This commit is contained in:
김경종
2026-09-08 10:30:07 +09:00
parent 1239d5b9f6
commit 1a0f3c9aaf
68 changed files with 6729 additions and 957 deletions
@@ -5,168 +5,124 @@ description: Use when planning agentic implementation phases, creating phases/in
# Harness Workflow
이 프로젝트는 Harness 프레임워크를 사용한다. 아래 워크플로에 따라 작업한다.
Harness는 MSVC C++ 제품 개발을 위한 계획·실행 도구다. 제품 요구사항과 기술 결정을
Harness 자체 요구사항과 섞지 않는다.
## A. 탐색
## 탐색과 논의
`AGENTS.md`와 `docs/` 하위 문서(PRD, ARCHITECTURE, ADR 등)를 읽고 프로젝트의 기획,
아키텍처, 설계 의도를 파악한다. 병렬 탐색이 실제로 유용하고 현재 세션에서 허용될
때만 Codex subagent를 선택적으로 사용한다.
1. `AGENTS.md`를 읽는다.
2. 변경 범위와 직접 관련된 제품 문서, 코드, 테스트와 `.harness/config.json`만 읽는다.
3. 미정인 제품 요구사항이나 공개 계약이 구현 결과를 바꾸면 사용자와 논의한다.
## B. 논의
전체 `docs/`를 일괄 읽거나 그 본문을 step에 복사하지 않는다. 이전 대화 없이도 실행할
수 있도록 필요한 기존 파일을 명시적으로 참조한다.
구현을 위해 구체화하거나 기술적으로 결정해야 할 사항이 있으면 사용자에게 한 번에
하나씩 제시하고 논의한다.
## Step 설계
## C. Step 설계
하나의 step에는 다음 요소만 필수로 둔다.
사용자가 구현 계획 작성을 지시하면 여러 step으로 나뉜 초안을 작성해 피드백을
요청한다.
- 목표와 범위
- 관련 파일과 `context_files`
- 핵심 제약
- 실행 가능한 Acceptance Criteria
설계 원칙:
공개 API나 ABI 계약이 중요한 경우에만 시그니처를 적는다. 새 기능과 버그 수정은 한
step 안에서 실패 테스트 확인, 최소 구현, 성공 확인까지 끝낸다. 실제 설정과 기존
테스트 명령을 우선하며 확인되지 않은 예시 명령을 AC로 쓰지 않는다.
1. **Scope 최소화** — 하나의 step에서 하나의 레이어 또는 모듈만 다룬다. 여러
모듈을 동시에 수정해야 하면 step을 쪼갠다.
2. **자기완결성** — 각 step 파일은 독립된 Codex 실행에서 사용된다. 외부 대화
참조를 금지하고 필요한 정보를 모두 파일 안에 적는다.
3. **사전 준비 강제** — 관련 문서와 이전 step에서 생성하거나 수정한 파일 경로를
명시한다.
4. **시그니처 수준 지시** — 함수와 클래스의 인터페이스를 제시하고 내부 구현은
Codex 재량에 맡긴다. 멱등성, 보안, 데이터 무결성 같은 핵심 규칙은 명시한다.
5. **AC는 실행 가능한 command** — 추상적 조건 대신 실제 빌드와 테스트 command를
포함한다.
6. **주의사항은 구체적으로** — "X를 하지 마라. 이유: Y" 형식으로 적는다.
7. **네이밍** — step name은 핵심 작업을 표현하는 kebab-case slug로 정한다.
## Index 형식
## D. 파일 생성
사용자가 초안을 승인한 후에만 다음 파일을 생성한다.
### D-1. `phases/index.json`
여러 task를 관리하는 top-level 인덱스다. 이미 존재하면 `phases` 배열에 새 항목을
추가한다.
`phases/index.json`:
```json
{
"phases": [
"phases": [{"dir": "add-parser", "status": "pending"}]
}
```
`phases/{phase}/index.json`:
```json
{
"project": "<제품명 또는 미정>",
"phase": "add-parser",
"steps": [
{
"dir": "0-mvp",
"status": "pending"
"step": 0,
"name": "implement-parser",
"status": "pending",
"context_files": ["docs/ARCHITECTURE.md"],
"validation": "full"
}
]
}
```
- `dir`: task 디렉터리명
- `status`: `pending` | `completed` | `error` | `blocked`
- timestamp는 executor가 상태를 바꿀 때 기록하므로 생성 시 넣지 않는다.
- `name`은 kebab-case slug다.
- `context_files`는 선택 사항인 저장소 상대 파일 경로 배열이다. glob과 URL은 쓰지
않는다. 생략하거나 빈 배열이면 추가 문서를 주입하지 않는다.
- `validation`은 `full` 또는 `docs-only`이며 생략 시 `full`이다. `docs-only`는 실제
변경이 허용된 문서 경로에만 있을 때만 제품 검증 생략을 요청한다.
- 생성 시 status는 `pending`이다. timestamp는 executor가 기록한다.
### D-2. `phases/{task-name}/index.json`
상태 기록:
```json
{
"project": "<프로젝트명>",
"phase": "<task-name>",
"steps": [
{ "step": 0, "name": "project-setup", "status": "pending" },
{ "step": 1, "name": "core-types", "status": "pending" },
{ "step": 2, "name": "api-layer", "status": "pending" }
]
}
```
| 상태 | Codex 기록 | Executor 기록 |
|---|---|---|
| `completed` | 한 줄 `summary` | `completed_at` |
| `error` | `error_message` | `failed_at` |
| `blocked` | `blocked_reason` | `blocked_at` |
필드 규칙:
- `project`: `AGENTS.md`에 정의된 프로젝트명
- `phase`: task 이름이며 디렉터리명과 일치
- `steps[].step`: 0부터 시작하는 순번
- `steps[].name`: kebab-case slug
- `steps[].status`: 초기값 `pending`
상태와 기록 주체:
| 전이 | 기록 필드 | 기록 주체 |
|------|-----------|-----------|
| `completed` | `summary`, `completed_at` | Codex가 summary, executor가 timestamp |
| `error` | `error_message`, `failed_at` | Codex가 message, executor가 timestamp |
| `blocked` | `blocked_reason`, `blocked_at` | Codex가 reason, executor가 timestamp |
`summary`에는 다음 step에 유용한 생성 파일과 핵심 결정을 한 줄로 적는다.
task `created_at`과 step `started_at`은 executor가 기록하므로 생성 시 넣지 않는다.
### D-3. `phases/{task-name}/step{N}.md`
## Step 파일
````markdown
# Step {N}: {이름}
# Step N: <name>
## 읽어야 할 파일
## 목표와 범위
<한 가지 책임과 범위 밖 항목>
먼저 아래 파일을 읽고 프로젝트의 아키텍처와 설계 의도를 파악하라:
## 관련 파일
- `<path>`
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- 이전 step에서 생성하거나 수정한 파일 경로
이전 step의 코드를 꼼꼼히 읽고 설계 의도를 이해한 뒤 작업하라.
## 작업
구체적인 구현 지시를 파일 경로, 클래스와 함수 시그니처, 로직 설명과 함께 적는다.
구현체는 Codex에 맡기되 설계 의도에서 벗어나면 안 되는 핵심 규칙은 명시한다.
## 핵심 제약
- <유지할 계약과 이유>
## Acceptance Criteria
프로젝트 형식에 맞는 명령을 사용한다. `.harness/config.json`이 있으면 해당 preset,
solution, configuration, platform, test command를 우선한다.
```powershell
# CMake
cmake --build .harness/build --config Debug
ctest --test-dir .harness/build -C Debug --output-on-failure
# 직접 MSBuild
MSBuild.exe MyProject.sln /m /p:Configuration=Debug /p:Platform=x64
.\build\tests\Debug\MyProjectTests.exe
<실제 build/test 명령>
```
## 검증 절차
1. Acceptance Criteria command를 실행한다.
2. ARCHITECTURE 디렉터리 구조를 따르는지 확인한다.
3. ADR 기술 스택과 `AGENTS.md` CRITICAL 규칙을 확인한다.
4. 결과에 따라 task index의 해당 step을 갱신한다.
- 성공: `status`를 `completed`로 바꾸고 한 줄 `summary` 기록
- 수정 3회 후 실패: `status`를 `error`로 바꾸고 `error_message` 기록
- 사용자 개입 필요: `status`를 `blocked`로 바꾸고 `blocked_reason` 기록 후 중단
## 금지사항
- 이 step의 범위 밖 기능을 추가하지 마라. 이유: step의 독립성을 깨뜨린다.
- 기존 테스트를 깨뜨리지 마라. 이유: 이전 동작을 회귀시킨다.
````
## E. 실행
현재 step보다 앞선 작업이 만든 파일은 관련 파일에 적고 실행 중 직접 읽는다. 이미
존재하는 제품 문서만 `context_files`에 넣는다.
```bash
python scripts/execute.py {task-name}
python scripts/execute.py {task-name} --push
## Phase 기록
`docs/phase/{phase}/handoff.md`는 최신 상태, 결정, 미해결 문제, 마지막 검증과 다음
시작점을 약 60줄 이내로 유지한다. `stepN.md`에는 변경 파일, 결정, 검증 결과와 유효한
시행착오를 기록한다. 성공·실패·차단을 보고하기 전에 둘을 갱신한다. 형식은
`docs/phase/README.md`를 따른다.
## 실행
```powershell
python scripts/execute.py <phase>
python scripts/execute.py <phase> --dry-run
python scripts/execute.py <phase> --push
```
환경에서 Python 3 실행 명령이 `python3`이면 그 명령을 대신 사용한다.
`--dry-run`은 첫 pending step의 주입 경로와 문자 수, 전체 프롬프트 문자 수만
출력하며 파일, Git, 상태와 Codex를 변경하지 않는다. `--push`와 함께 쓸 수 없다.
executor가 처리하는 작업:
프롬프트는 `AGENTS → 공통 규칙 → context_files → 최신 handoff 또는 호환 summary →
직전 실패 → 현재 step` 순서다. handoff가 없을 때만 현재 step보다 앞선 완료 step 중
가장 최근 하나의 summary를 최대 1,000자로 전달한다.
- `feat-{task-name}` 브랜치 생성 또는 checkout
- `AGENTS.md`와 `docs/*.md` guardrail 주입
- 완료 step의 summary를 다음 prompt에 누적
- 실패 시 최대 3회 재시도하며 이전 오류를 prompt에 전달
- 코드 변경과 metadata를 분리해 commit
- `started_at`, `completed_at`, `failed_at`, `blocked_at` 기록
Executor는 최초 호출을 포함해 Codex를 최대 3회 호출한다. 재시도 오류 본문은 총
4,000자 안에서 앞 1,500자, 중간 생략 marker와 끝부분 최대 2,500자를 보존한다. 원본 출력은
`phases/{phase}/stepN-output.json`에 온전히 쓰지만 다음 호출에서 덮어쓴다. 지속할
시행착오는 `docs/phase/{phase}/stepN.md`에 남긴다.
에러 복구:
- `error`: 해당 status를 `pending`으로 바꾸고 `error_message`를 삭제한 뒤 재실행
- `blocked`: 원인을 해결하고 status를 `pending`으로 바꾸고 `blocked_reason`을 삭제한
뒤 재실행
`completed`는 Codex 프로세스 exit code가 0일 때만 성공이다. `blocked`는 즉시 멈춘다.
`error`나 `blocked`를 재개하려면 원인을 해결하고 status를 `pending`으로 바꾼 뒤 해당
오류 필드와 timestamp를 제거한다.