Files
FESADev/docs/HARNESS.md
T
2026-09-06 00:52:59 +09:00

8.9 KiB

Harness 운영 가이드

Requirements

Windows와 Codex CLI가 필요하다. Executor는 Python 3.10 이상을 사용하며, 이 저장소의 계약 테스트는 표준 tomllib을 사용하므로 검증 환경은 Python 3.11 이상으로 준비한다. FESA는 Visual Studio의 Desktop development with C++ 워크로드, CMake/CTest와 Ninja를 사용한다. MSVC x64 developer 환경과 dependency 경로는 AGENTS.md의 최소 검증 진입점을 따른다.

역할·승인·상태 전이는 Agent 계약과 Harness skill을 따른다. 이 문서는 설치·실행 참고이며 solver Feature의 9개 stage와 evidence gate를 대신하지 않는다.

프로젝트 자동 감지

프로젝트 형식은 다음 순서로 결정한다: .harness/config.json의 명시적 type, 루트의 CMake metadata, 하나의 .sln, 하나의 .vcxproj 순서다. C/C++가 아닌 저장소는 건너뛰며, C/C++ 파일은 있지만 CMake/solution metadata가 없는 orphan-C++ 저장소는 오류로 처리한다.

설정 파일은 선택 사항이다. 기본 자동 감지와 .harness/build 경로를 그대로 사용할 때는 만들지 않아도 된다. 프로젝트별 override가 필요하면 다음처럼 예시를 복사한다.

Copy-Item .harness/config.example.json .harness/config.json

승인된 Feature와 Coordinator dispatch에 따라 Planning Agent가 할당된 phase 파일을 작성한다. 일반 계획 파일 작성에 반복 승인을 요구하지 않는다. 실행까지 할당된 경우에만 다음 명령을 사용하며, 계획 작성 요청만으로 Executor를 시작하지 않는다.

python scripts/execute.py <phase-name>

--push는 해당 원격 push를 사용자가 명시적으로 승인했을 때만 추가한다. 실행 전 Git top-level은 Harness root와 같고 선택된 phase 제어 파일 밖의 worktree는 clean이어야 한다. 실행 중 동시 편집과 커밋 범위의 한계는 동작 과정을 따른다.

모든 pending Step에는 승인된 정확한 상대 파일 목록인 owned_paths가 필요하다. 누락된 기존 phase는 Planning의 할당된 준비 작업에서 목록을 보완한 뒤 실행한다. []는 구현 파일 변경이 없음을 뜻하며 완료 이력에는 목록을 소급 추가하지 않는다. Executor는 실행 후와 staging/commit 경계에서 소유권을 검사하며 범위 밖 변경은 보존하고 중단한다. 상세 schema와 제한은 Harness skill을 따른다.

Executor가 시작하는 Codex 세션은 기본적으로 workspace-write sandbox를 사용한다. Windows native sandbox에서 MSVC compiler-id의 cl.exe가 정지하는 것이 재현되고 같은 명령이 sandbox 밖에서 정상 완료되는 경우에만, 사용자 승인을 받은 격리된 clean linked Git worktree에서 다음처럼 해당 실행에 한정해 fallback을 지정할 수 있다.

$env:FEM_HARNESS_CODEX_SANDBOX = "danger-full-access"
python scripts/execute.py <phase-name> --approve-danger-full-access
Remove-Item Env:FEM_HARNESS_CODEX_SANDBOX

허용값은 workspace-write와 danger-full-access뿐이다. 후자는 Codex Step에 workspace 밖의 파일 접근 권한도 부여하므로 일반 기본값으로 설정하지 않는다. 어느 모드에서도 .codex/hooks.json의 등록된 hook을 비활성화하지 않는다. 환경변수만으로 권한이 승인되지 않으며 Executor는 승인 flag가 없거나 primary/dirty worktree인 권한 상승 실행을 거부한다.

Stop은 유효한 동일 session/turn 편집 기록의 대상이 모두 저장소 내부 .md일 때만 build/test를 생략한다. 기록 누락·손상 또는 비문서 편집은 정상 검증 경로를 따른다. Shell 쓰기나 편집 기록 없는 읽기 전용 요청도 자동 생략을 보장하지 않는다. 문서 작업에서 사용자가 실행을 제외하면 수동으로 Hook·build/test를 실행하지 않고 미검증 사실을 보고한다.

Harness Python 검증

이 저장소의 테스트와 최종 acceptance 검증은 pytest를 시스템 Python에 설치하지 않고 다음 명령으로 실행한다.

uv run --with pytest python -B -m pytest -v -rs

CMake preset 설정

projectType을 cmake로 지정하거나 자동 감지를 사용한다. cmake.sourceDir, binaryDir, configurePreset, buildPreset, testPreset은 preset을 사용할 때 함께 지정해야 한다. 빌드 산출물은 저장소의 .harness/build/처럼 격리된 경로에 둔다.

{
  "version": 1,
  "projectType": "cmake",
  "cmake": {
    "sourceDir": ".",
    "binaryDir": ".harness/build-ninja-msvc-debug",
    "configurePreset": "windows-msvc-ninja-debug",
    "buildPreset": "windows-msvc-ninja-debug",
    "testPreset": "windows-msvc-ninja-debug"
  }
}
cmake --preset windows-msvc-ninja-debug
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
ctest --preset windows-msvc-ninja-debug --output-on-failure

위 예시는 현재 CMakePresets.json과 config 예시에 맞춘다. Preset 파일이 존재하는 것만으로 Stop이 그 preset을 선택하지는 않는다. 아래는 preset을 쓰지 않는 adapter의 명령 형태이며, FESA에서는 dependency 경로와 승인된 build 구성을 함께 확인한다.

cmake -S . -B .harness/build -A x64
cmake --build .harness/build --config Debug
ctest --test-dir .harness/build -C Debug --show-only=json-v1
ctest --test-dir .harness/build -C Debug --output-on-failure

직접 MSBuild 설정

다음은 재사용 가능한 Harness adapter의 예시다. FESA 제품 검증은 CMake/CTest를 사용하며 이 예시로 solution-only MSBuild 검증을 대체 승인하지 않는다.

projectType을 msbuild로 설정하면 msbuild.solution, configuration, platform을 지정한다. 직접 MSBuild 프로젝트에서는 msbuild.testCommand가 필수이며, 테스트 실행 파일과 인수를 JSON 배열로 적는다.

{
  "version": 1,
  "projectType": "msbuild",
  "msbuild": {
    "solution": "MyProject.sln",
    "configuration": "Debug",
    "platform": "x64",
    "testCommand": ["build/tests/Debug/MyProjectTests.exe"]
  }
}
MSBuild.exe MyProject.sln /m /p:Configuration=Debug /p:Platform=x64
.\build\tests\Debug\MyProjectTests.exe

TDD 확장

tdd.testRoots와 tdd.testPatterns로 테스트 위치와 이름을 확장한다. 패턴마다 {stem}이 필요하다. main, 테스트, 외부 의존성, 생성 파일, build directory 같은 기본 제외 항목은 Harness가 관리하며, tdd.exclude의 사용자 제외 항목은 이를 대체하지 않고 추가한다.

{
  "version": 1,
  "tdd": {
    "testRoots": ["tests", "integration-tests"],
    "testPatterns": ["{stem}_test.cpp", "test_{stem}.cpp"],
    "exclude": ["legacy/generated/**"]
  }
}

실패 복구

Executor는 명시적 error/blocked를 비정상 종료에서도 보존하며 자동 재시도하지 않는다. 인식된 sandbox helper 환경 오류는 종료 코드 0에서도 Step과 상위 phase를 blocked로 기록한다. 실제 wrapper timeout으로 결과를 받지 못했을 때만 최초 포함 최대 두 번 시도한다. 원인 미분류 nonzero와 completed/nonzero 불일치는 error다. 환경 차단은 종료 코드 2, 일반 실패는 1이며 preflight 실패는 branch/state 변경 전에 반환한다.

  • Visual Studio C++ workload가 없으면 Installer에서 Desktop development with C++를 설치한 뒤 다시 실행한다.
  • solution 또는 project가 여러 개라서 모호하면 projectType과 msbuild.solution을 명시한다.
  • MSVC가 아닌 컴파일러가 감지되면 MSVC Developer Command Prompt에서 실행하거나 toolchain을 MSVC로 전환한다.
  • CTest가 0개 테스트를 보고하면 enable_testing()과 테스트 등록을 확인한다.
  • 직접 MSBuild 구성에 test command가 없으면 msbuild.testCommand 배열을 추가한다.
  • timeout 또는 명령 실패 시 Stop 응답의 stage, 안전한 argv 배열, 작업 디렉터리, 종료 코드와 출력 tail을 확인한다. 실행이 할당된 범위에서만 재현 명령을 수행하며 문서 작업의 검증 제외 지시를 덮어쓰지 않는다. Stop은 별도의 빌드 로그 파일을 만들지 않는다.
  • 실패 분류와 재시작 결정은 Coordinator가 기록한다. Planning Agent는 명시적으로 할당된 복구 작업에서만 현재 실패 Step의 status를 pending으로 바꾸고, Executor가 재시작 시 오래된 outcome 필드와 timestamp를 정리하되 attempt_history는 보존한다. 실패 evidence를 먼저 보존하며 상세 절차는 Harness skill의 Recovery and handoff를 따른다.