modify harness framework
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# Harness 운영 가이드
|
||||
|
||||
Harness는 Windows에서 C#·.NET 8 제품 개발의 step 실행, 편집 정책과 build/test를
|
||||
지원하는 Python 도구다. 제품 목표와 기능은 [PRD](PRD.md)에 별도로 둔다.
|
||||
상세 실행 흐름은 [HARNESS_WORKFLOW.md](HARNESS_WORKFLOW.md)를 참고한다.
|
||||
|
||||
## 요구 환경과 설정
|
||||
|
||||
설치, PATH·인증·훅 점검과 첫 검증은 [환경 구축 가이드](ENVIRONMENT_SETUP.md)를 따른다.
|
||||
|
||||
- Windows, Git, 실제 `python` 명령으로 실행 가능한 Python 3.10 이상, 호환 Codex CLI
|
||||
- 루트 `global.json`을 만족하는 .NET 8 **SDK**와 NuGet restore 접근
|
||||
- 신규 테스트 기본값 xUnit v2 + VSTest; IDE는 선택 사항
|
||||
- Harness 자체 테스트에는 pytest/uv 사용
|
||||
|
||||
`global.json`의 기준은 SDK `8.0.424`, `latestPatch`, `allowPrerelease=false`다.
|
||||
SDK 선택과 `.csproj`의 제품 대상 TFM은 별개이며 신규 프로젝트 기본 TFM은 `net8.0`이다.
|
||||
|
||||
다음 경로는 실제 제품이 아닌 설정 예시다. `.harness/config.example.json`을 참고해
|
||||
실제 제품에 맞는 `.harness/config.json`을 작성한다. 제품이 없는 템플릿에는 가상의
|
||||
target을 넣은 설정 파일을 만들지 않는다.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 2,
|
||||
"projectType": "dotnet",
|
||||
"dotnet": {
|
||||
"target": "Example.sln",
|
||||
"configuration": "Debug",
|
||||
"testProjects": ["tests/Example.Tests/Example.Tests.csproj"]
|
||||
},
|
||||
"tdd": {
|
||||
"testRoots": ["tests"],
|
||||
"testPatterns": ["{stem}Tests.cs", "{stem}Test.cs"],
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`projectType`는 `auto`(기본값) 또는 `dotnet`이다. `dotnet.target`은 선택 사항이며,
|
||||
명시한 저장소 내부 `.sln` 또는 SDK 스타일 `.csproj`를 우선한다. 생략하면 루트의
|
||||
단일 solution, 다음으로 제외 경로 밖의 단일 C# project를 찾는다. 후보가 여러 개면
|
||||
target을 명시한다. C# 소스가 있지만 지원 metadata가 없으면 오류다.
|
||||
|
||||
제품이 있으면 `dotnet.testProjects`는 전체 제품 테스트를 담은 비어 있지 않은 명시
|
||||
목록이어야 한다. `configuration`의 기본값은 `Debug`다. 모든 설정 경로는 저장소
|
||||
상대 경로이며 외부 symlink/junction 대상, 없는 target, 알 수 없는 필드와 version 1은
|
||||
거부한다. `tdd.testRoots`와 `testPatterns`를 명시하면 빈 배열을 허용하지 않는다.
|
||||
`tdd.exclude: []`는 유효하다. 테스트 패턴은 `{stem}`을 포함하는 `.cs` 파일명이며
|
||||
경로 구분자를 넣지 않는다. SDK·TFM·패키지 버전을 Harness 설정에 중복하지 않는다.
|
||||
|
||||
## Phase 실행
|
||||
|
||||
```powershell
|
||||
python -X utf8 scripts/execute.py <phase-name> --dry-run
|
||||
python -X utf8 scripts/execute.py <phase-name>
|
||||
python -X utf8 scripts/execute.py <phase-name> --push
|
||||
```
|
||||
|
||||
먼저 `--dry-run`으로 첫 pending step이 읽을 파일과 프롬프트 문자 수를 확인한다. 이
|
||||
모드는 Codex 호출, branch 전환, timestamp, 파일 쓰기, commit과 push를 하지 않는다.
|
||||
`--push`와 함께 사용할 수 없다. 실제 실행은 자동 staging·commit을 수행하므로
|
||||
검토한 기준 commit이 있는 전용 checkout/worktree에서 시작한다.
|
||||
|
||||
## 선택 문맥과 호환성
|
||||
|
||||
step index의 `context_files`에 필요한 기존 문서를 저장소 상대 경로로 적는다.
|
||||
|
||||
```json
|
||||
{
|
||||
"step": 1,
|
||||
"name": "implement-parser",
|
||||
"status": "pending",
|
||||
"context_files": ["docs/ARCHITECTURE.md"]
|
||||
}
|
||||
```
|
||||
|
||||
필드를 생략하거나 빈 배열로 두면 `AGENTS.md`, 자동 인계와 step 이외의 문서는
|
||||
추가되지 않는다. glob, URL, 절대 경로와 저장소 밖 경로는 지원하지 않는다.
|
||||
이전에 모든 문서를 자동 주입하던 동작에 의존하는 phase는 필요한 문서를 명시한다.
|
||||
|
||||
현재 phase의 `docs/phase/{phase}/handoff.md`가 있으면 매 호출 다시 읽는다. 없을 때만
|
||||
현재 step보다 앞선 완료 step 중 가장 최근 하나의 summary를 최대 1,000자로 전달한다.
|
||||
상세 기록 형식은 [phase README](phase/README.md)를 따른다.
|
||||
|
||||
## 검증 모드
|
||||
|
||||
```json
|
||||
{"step": 2, "name": "update-docs", "status": "pending", "validation": "docs-only"}
|
||||
```
|
||||
|
||||
`validation` 생략 또는 `full`은 전체 제품 검증을 수행한다. `docs-only`도 실제 Git
|
||||
변경이 루트 `AGENTS.md`, `docs/**/*.md`, 현재 phase의 `index.json`과
|
||||
`stepN-output.json`에만 있고 실제 문서 변경이 있을 때만 제품 검증을 생략한다.
|
||||
Git 조회 실패, 빈 변경, bookkeeping만 있는 변경, 다른 코드·설정·스킬 파일이 섞인
|
||||
변경은 전체 검증으로 돌아간다. rename은 이전·새 경로를 모두 확인하며 symlink나
|
||||
junction 경로는 문서 전용으로 인정하지 않는다. 제품 build가 Markdown을 입력으로
|
||||
사용하면 `full`을 선택한다.
|
||||
|
||||
## .NET 검증
|
||||
|
||||
Stop 훅은 `scripts/dotnet_harness/`를 통해 저장소 루트에서 다음 순서로 검증한다.
|
||||
|
||||
1. SDK 선택 확인.
|
||||
2. target·test project와 평가된 `ProjectReference`로 연결되는 모든 프로젝트의 저장소 내부 경로·C# SDK 형식·실제 .NET 8 TFM 확인.
|
||||
3. target과 모든 test project의 중복 경로를 제거한 뒤 같은 Configuration으로 각각 restore.
|
||||
4. 각 대상을 `--no-restore -warnaserror`로 build.
|
||||
5. 각 test project를 `--no-build --no-restore --logger trx`로 실행.
|
||||
6. 현재 호출의 project별 고유 결과 디렉터리에 생성된 모든 TRX 검사.
|
||||
|
||||
TFM과 참조 확인은 각 `.csproj`에 `dotnet msbuild -getProperty:TargetFramework,TargetFrameworks
|
||||
-getItem:ProjectReference -p:Configuration=<configuration>`을 실행한다. 다중 TFM은
|
||||
각 `TargetFramework`의 조건부 참조도 평가한다. 프로젝트 XML의 문자만 확인하지 않고
|
||||
상속된 props와 속성 참조를 평가한 결과를 검사한다. 값이 없거나 .NET 8 이외의 TFM이
|
||||
포함되면 restore 전에 실패한다. `net8.0`과 .NET 8의 플랫폼별 TFM을 허용한다.
|
||||
|
||||
참조별 `AdditionalProperties`, `GlobalPropertiesToRemove`, `SetConfiguration`,
|
||||
`SetPlatform`, `SetTargetFramework`로 평가 문맥을 바꾸는 구성은 현재 지원하지 않으며
|
||||
명확한 오류로 거부한다. 프로젝트는 공유 Configuration과 각 프로젝트의 TFM을 사용한다.
|
||||
|
||||
solution에 빠진 test project도 직접 restore/build한다. 한 단계라도 실패하면 이후
|
||||
단계를 멈춘다. 전체 deadline은 1,800초이며 명령은 shell 확장 없이 argv 배열로
|
||||
실행한다. NuGet 오류는 restore 실패로 보고한다.
|
||||
|
||||
실패·손상·누락된 TRX, 실행된 테스트 0건, skip-only 결과는 검증 실패다. 여러 결과
|
||||
중 하나라도 실패하면 성공 결과로 덮지 않는다. 오래된 TRX는 현재 실행의 근거가
|
||||
아니다. 기본 xUnit 이외의 기존 테스트도 VSTest/TRX 계약을 만족해야 한다.
|
||||
|
||||
C# 제품과 지원 metadata가 모두 없는 템플릿은 `제품 검증 대상 없음`으로 구분한다.
|
||||
`tests/fixtures/`는 도구 검증용이므로 제품 자동 탐색에서 제외한다. 대상 없음과
|
||||
docs-only 생략을 제품 빌드 성공으로 기록하지 않는다.
|
||||
|
||||
## TDD와 복구
|
||||
|
||||
`Foo.cs` 편집에는 기본 test root인 저장소 `tests/`와 편집 파일 옆 `tests/`, `test/`에서
|
||||
`FooTests.cs` 또는 `FooTest.cs`가 먼저 있어야 한다. 설정으로 테스트 루트·패턴을
|
||||
조정할 수 있다. 테스트 루트의 보조 코드, 중첩된 `bin/`, `obj/`, `.git/`, `.vs/`,
|
||||
`.harness/`, `TestResults/`, 외부 의존성·명시 generated 경로는 정책에서 제외한다.
|
||||
|
||||
`Program.cs`, DTO, interface, `.Designer.cs`는 파일명만으로 면제하지 않는다.
|
||||
필요하면 예를 들어 `src/Example/Program.cs`처럼 정확한 `tdd.exclude` 경로와
|
||||
composition root 등 실제 이유를 기록한다. 이 설정은 편집 전 테스트 요구만 면제하며
|
||||
제품 존재 탐색을 숨기지 않는다. 수동 작성 partial 파일은 각 stem에 대응 테스트가
|
||||
필요하다. 파일 존재 검사는 테스트 품질이나 실제 red-green 실행을 대신하지 않는다.
|
||||
|
||||
Executor는 Codex를 최초 호출 포함 최대 3회 호출한다. 재시도 입력은 marker를 포함해
|
||||
4,000자로 제한하며 앞 1,500자와 끝부분 최대 2,500자를 보존한다. 원본
|
||||
`stepN-output.json`은 온전히 저장되지만 다음 시도에서 덮어쓴다. exit code 0과
|
||||
`completed` 상태와 executor의 독립 제품 검증 성공이 모두 있어야 성공한다.
|
||||
Stop 실패도 CLI exit 0으로 끝날 수 있어 executor가 완료 보고 후 검증을 다시 실행한다.
|
||||
독립 검증은 별도의 1,800초 제한을 공유하며 실패하면 같은 호출 예산 안에서 재시도한다.
|
||||
`docs-only` 판정도 실제 변경을 다시 확인한다. `blocked`는 즉시 멈춘다.
|
||||
|
||||
`error` 또는 `blocked`를 재개할 때는 원인을 해결하고 step을 `pending`으로 바꾼 뒤
|
||||
오류 이유와 해당 timestamp를 제거한다. 인증이나 CLI 환경 오류는 즉시 중단한다.
|
||||
|
||||
Harness 자체 Python 검증:
|
||||
|
||||
```powershell
|
||||
uv run --with pytest python -m pytest tests/harness -v -rs
|
||||
uv run --with pytest python -m compileall -q scripts tests/harness
|
||||
```
|
||||
|
||||
실제 SDK 통합 테스트의 skip과 subprocess 대역 테스트 성공을 구분한다. 검증한
|
||||
OS·SDK·패키지 버전, 실행 건수, 경고와 남은 미검증 항목은 phase 기록에 남긴다.
|
||||
Reference in New Issue
Block a user