9.1 KiB
Harness 운영 가이드
Harness는 Windows에서 C#·.NET 8 제품 개발의 step 실행, 편집 정책과 build/test를 지원하는 Python 도구다. 제품 목표와 기능은 PRD에 별도로 둔다. 상세 실행 흐름은 HARNESS_WORKFLOW.md를 참고한다.
요구 환경과 설정
설치, PATH·인증·훅 점검과 첫 검증은 환경 구축 가이드를 따른다.
- 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을 넣은 설정 파일을 만들지 않는다.
{
"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 실행
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에 필요한 기존 문서를 저장소 상대 경로로 적는다.
{
"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를 따른다.
검증 모드
{"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/를 통해 저장소 루트에서 다음 순서로 검증한다.
- SDK 선택 확인.
- target·test project와 평가된
ProjectReference로 연결되는 모든 프로젝트의 저장소 내부 경로·C# SDK 형식·실제 .NET 8 TFM 확인. - target과 모든 test project의 중복 경로를 제거한 뒤 같은 Configuration으로 각각 restore.
- 각 대상을
--no-restore -warnaserror로 build. - 각 test project를
--no-build --no-restore --logger trx로 실행. - 현재 호출의 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 검증:
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 기록에 남긴다.