docs(phases): add harness self-test bootstrap step

This commit is contained in:
KOKO\Mimi
2026-07-29 23:34:10 +09:00
parent f5379472ce
commit b0ab8e77d5
6 changed files with 194 additions and 112 deletions
@@ -73,7 +73,7 @@ intentionally differs.
| Order | Harness phase | Plan tasks | Independent deliverable | | Order | Harness phase | Plan tasks | Independent deliverable |
| ---: | --- | --- | --- | | ---: | --- | --- | --- |
| 0 | `solver-bootstrap` | 1-2 | Reproducible C++20 build, dependency smoke tests, core IDs and diagnostics | | 0 | `solver-bootstrap` | Harness baseline, 1-2 | Harness self-tests, reproducible C++20 build, dependency smoke tests, core IDs and diagnostics |
| 1 | `domain-and-input-skeleton` | 3-4 | Flat or single-Instance B31 input becomes an immutable normalized `Domain` | | 1 | `domain-and-input-skeleton` | 3-4 | Flat or single-Instance B31 input becomes an immutable normalized `Domain` |
| 2 | `fem-and-beam-kernel` | 5-6 | Real Timoshenko Beam local stiffness with analytical sanity tests | | 2 | `fem-and-beam-kernel` | 5-6 | Real Timoshenko Beam local stiffness with analytical sanity tests |
| 3 | `equation-and-linear-solve` | 7-8 | Deterministic serial CSR system solved by PARDISO | | 3 | `equation-and-linear-solve` | 7-8 | Deterministic serial CSR system solved by PARDISO |
@@ -123,6 +123,9 @@ docs/VALIDATION.md benchmark matrix and qualification result
**Files:** **Files:**
- Create before CMake bootstrap: `tests/harness/test_config.py`
- Create before CMake bootstrap: `tests/harness/test_discovery.py`
- Create before CMake bootstrap: `tests/harness/test_process.py`
- Create: `CMakeLists.txt` - Create: `CMakeLists.txt`
- Create: `CMakePresets.json` - Create: `CMakePresets.json`
- Create: `cmake/FesaDependencies.cmake` - Create: `cmake/FesaDependencies.cmake`
@@ -141,6 +144,11 @@ docs/VALIDATION.md benchmark matrix and qualification result
- Produces presets: `windows-debug`, `windows-release` - Produces presets: `windows-debug`, `windows-release`
- Later tasks consume the common warning and include-directory policies. - Later tasks consume the common warning and include-directory policies.
Before the CMake task, add characterization tests for the existing Harness
configuration, project discovery, and validation-result contracts. This
precondition makes the repository-level pytest command collect at least one
test without changing production Harness behavior.
- [ ] **Step 1: Verify required installed packages without changing the machine** - [ ] **Step 1: Verify required installed packages without changing the machine**
Run: Run:
+7 -2
View File
@@ -4,16 +4,21 @@
"steps": [ "steps": [
{ {
"step": 0, "step": 0,
"name": "cmake-project-scaffold", "name": "harness-self-tests",
"status": "pending" "status": "pending"
}, },
{ {
"step": 1, "step": 1,
"name": "dependency-smoke-tests", "name": "cmake-project-scaffold",
"status": "pending" "status": "pending"
}, },
{ {
"step": 2, "step": 2,
"name": "dependency-smoke-tests",
"status": "pending"
},
{
"step": 3,
"name": "core-ids-and-diagnostics", "name": "core-ids-and-diagnostics",
"status": "pending" "status": "pending"
} }
+40 -37
View File
@@ -1,62 +1,65 @@
# Step 0: CMake Project Scaffold # Step 0: Harness Self Tests
## 읽어야 할 파일 ## 읽어야 할 파일
먼저 아래 파일을 모두 읽고 저장소 계약을 파악하라. 먼저 아래 파일을 모두 읽고 현재 Harness 계약을 파악하라.
- `/AGENTS.md` - `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/HARNESS.md` - `/docs/HARNESS.md`
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
- `/.harness/config.example.json` - `/.harness/config.example.json`
- `/pytest.ini`
- `/scripts/msvc_harness/config.py`
- `/scripts/msvc_harness/discovery.py`
- `/scripts/msvc_harness/models.py`
- `/scripts/msvc_harness/process.py`
- `/scripts/msvc_harness/tdd_policy.py`
- `/scripts/hooks/stop_validation.py`
## 작업 ## 작업
C++20/MSVC x64 프로젝트의 최소 실행 가능한 build/test 뼈대를 만든다. 현재 Harness Python 검증이 테스트 0개 수집으로 실패하는 기준선 문제를 해결한다.
production Harness 동작은 변경하지 않고, 이미 문서화된 핵심 계약을 검증하는 최소
자가 테스트를 작성한다.
- `CMakeLists.txt`, `CMakePresets.json`, `cmake/FesaDependencies.cmake`, - 다음 파일을 만든다.
`.harness/config.json`, `tests/CMakeLists.txt`를 만든다. - `tests/harness/test_config.py`
- 실제 target은 `fesa_core` 정적 라이브러리와 `fesa` CLI 두 개만 만든다. - `tests/harness/test_discovery.py`
- `include/fesa/core/version.hpp`, `src/fesa/core/version.cpp`, - `tests/harness/test_process.py`
`src/fesa/cli/main.cpp`에 다음 계약을 구현한다. - `test_config.py`는 기본 설정 로드, repository 밖 경로 거부, CMake preset 필드의
all-or-none 규칙을 실제 임시 디렉터리로 검증한다.
- `test_discovery.py`는 빈 저장소 건너뛰기, CMake 우선 감지, C/C++ 파일만 존재하는
orphan 프로젝트 거부를 실제 임시 디렉터리로 검증한다.
- `test_process.py`는 CTest JSON에 테스트가 0개이면 실패하고 하나 이상이면 통과하는
결과 검사를 안전한 fake command runner로 검증한다. subprocess shell을 사용하지
않는 계약도 유지한다.
- 각 테스트는 공개 함수인 `load_config`, `discover_project`, `execute_plan`을 통해
관찰 가능한 동작만 확인한다.
```cpp 이 step은 기존 production 동작의 characterization test만 추가한다. 테스트가 기존
namespace fesa { 문서 계약과 다르게 실패하면 production 코드를 임의로 고치지 말고 step을 `blocked`
[[nodiscard]] std::string_view version() noexcept; 표시하고 불일치를 기록한다.
}
```
- CLI는 이 step에서 `fesa --version`만 처리한다.
- 먼저 `VersionCommand` CTest를 등록해 실패를 확인한 뒤 최소 구현한다.
- `windows-debug`, `windows-release` configure/build/test preset을 정의한다.
- build 산출물은 `out/build/<preset>` 아래에만 둔다.
- MSVC가 아니거나 x64가 아니면 configure 단계에서 명확히 실패시킨다.
## Acceptance Criteria ## Acceptance Criteria
```powershell ```powershell
uv run --with pytest python -m pytest -v -rs uv run --with pytest python -m pytest -v -rs
cmake --preset windows-debug
cmake --build --preset windows-debug
ctest --preset windows-debug -R VersionCommand --output-on-failure
ctest --preset windows-debug --output-on-failure
``` ```
`fesa --version`은 비어 있지 않은 FESA 버전을 출력하고 종료 코드 0을 반환해야 한다. pytest가 테스트를 한 개 이상 수집하고 모든 테스트가 통과해야 한다.
CTest는 0개가 아니어야 한다.
## 검증 절차 ## 검증 절차
1. 테스트가 구현 전 실패하는 것을 확인한다. 1. 변경 전 명령이 테스트 0개 수집으로 실패한다는 기존 기준선 기록을 확인한다.
2. Acceptance Criteria 명령을 새로 실행한다. 2. 위 세 테스트 파일만 추가한다.
3. MSVC/C++20/x64와 산출물 경로를 확인한다. 3. Acceptance Criteria 명령을 새로 실행한다.
4. 성공 시 index의 step을 `completed`로 바꾸고 생성 파일을 summary에 기록한다. 4. production Harness 파일에 변경이 없는지 `git diff`로 확인한다.
5. 도구가 없으면 자동 설치하지 말고 `blocked`와 정확한 누락 항목을 기록한다. 5. 성공 시 index의 step을 `completed`로 바꾸고 테스트 파일을 summary에 기록한다.
## 금지사항 ## 금지사항
- 외부 패키지를 다운로드하지 마라. 이유: 사전 설치 의존성 정책을 위반한다. - production Harness 코드를 변경하지 마라. 이유: 이 step은 기존 계약의 기준선
- MKL, TBB, HDF5 기능을 구현하지 마라. 이유: 다음 step의 독립 범위다. 테스트만 마련한다.
- 빈 미래 모듈을 만들지 마라. 이유: Phase 1 최소 실체화 원칙을 위반한다. - C++ 프로젝트 파일이나 `.harness/config.json`을 만들지 마라. 이유: 다음 step의
독립 범위다.
- subprocess로 실제 CMake, MSBuild 또는 CTest를 실행하지 마라. 이유: self-test가
개발 머신 도구 설치 상태에 의존하게 된다.
+37 -27
View File
@@ -1,55 +1,65 @@
# Step 1: Dependency Smoke Tests # Step 1: CMake Project Scaffold
## 읽어야 할 파일 ## 읽어야 할 파일
먼저 아래 파일을 모두 읽고 저장소 계약을 파악하라.
- `/AGENTS.md` - `/AGENTS.md`
- `/docs/PRD.md` - `/docs/PRD.md`
- `/docs/ARCHITECTURE.md` - `/docs/ARCHITECTURE.md`
- `/docs/ADR.md` - `/docs/ADR.md`
- `/docs/HARNESS.md` - `/docs/HARNESS.md`
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md` - `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
- `/CMakeLists.txt` - `/.harness/config.example.json`
- `/CMakePresets.json` - `/tests/harness/test_config.py`
- `/cmake/FesaDependencies.cmake` - `/tests/harness/test_discovery.py`
- `/.harness/config.json` - `/tests/harness/test_process.py`
- `/tests/CMakeLists.txt`
이전 step의 CMake target과 preset을 그대로 확장하라.
## 작업 ## 작업
사전 설치된 oneMKL, oneTBB, HDF5 C API, GoogleTest/GoogleMock을 CMake imported C++20/MSVC x64 프로젝트의 최소 실행 가능한 build/test 뼈대를 만든다.
target으로 찾고 링크 계약을 검증한다.
- `tests/unit/dependencies/dependency_smoke_test.cpp`를 먼저 작성한다. - `CMakeLists.txt`, `CMakePresets.json`, `cmake/FesaDependencies.cmake`,
- 테스트는 MKL의 작은 vector 연산, TBB의 제한된 parallel loop, HDF5 임시 파일 `.harness/config.json`, `tests/CMakeLists.txt`를 만든다.
생성·닫기, GoogleTest 실행을 확인한다. - 실제 target은 `fesa_core` 정적 라이브러리와 `fesa` CLI 두 개만 만든다.
- `FesaDependencies.cmake` `MKL::MKL`, TBB imported target, HDF5 C target, - `include/fesa/core/version.hpp`, `src/fesa/core/version.cpp`,
GoogleTest target을 제공해야 한다. `src/fesa/cli/main.cpp`에 다음 계약을 구현한다.
- oneMKL은 LP64, dynamic link, TBB threading 조합을 사용한다.
- runtime DLL 또는 architecture 불일치는 configure diagnostic으로 보고한다. ```cpp
namespace fesa {
[[nodiscard]] std::string_view version() noexcept;
}
```
- CLI는 이 step에서 `fesa --version`만 처리한다.
- 먼저 `VersionCommand` CTest를 등록해 실패를 확인한 뒤 최소 구현한다.
- `windows-debug`, `windows-release` configure/build/test preset을 정의한다.
- build 산출물은 `out/build/<preset>` 아래에만 둔다.
- MSVC가 아니거나 x64가 아니면 configure 단계에서 명확히 실패시킨다.
## Acceptance Criteria ## Acceptance Criteria
```powershell ```powershell
uv run --with pytest python -m pytest -v -rs
cmake --preset windows-debug cmake --preset windows-debug
cmake --build --preset windows-debug cmake --build --preset windows-debug
ctest --preset windows-debug -R DependencySmoke --output-on-failure ctest --preset windows-debug -R VersionCommand --output-on-failure
ctest --preset windows-debug --output-on-failure ctest --preset windows-debug --output-on-failure
``` ```
네 의존성을 실제 호출하는 smoke test가 통과해야 하며 새 MSVC 경고가 없어야 한다. `fesa --version`은 비어 있지 않은 FESA 버전을 출력하고 종료 코드 0을 반환해야 한다.
CTest는 0개가 아니어야 한다.
## 검증 절차 ## 검증 절차
1. smoke test를 먼저 추가하고 link 또는 실행 실패를 확인한다. 1. 테스트가 구현 전 실패하는 것을 확인한다.
2. dependency discovery와 target link만 최소 수정한다. 2. Acceptance Criteria 명령을 새로 실행한다.
3. 전체 configure/build/test를 새로 실행한다. 3. MSVC/C++20/x64와 산출물 경로를 확인한다.
4. 성공 시 정확한 imported target과 탐색 파일을 summary에 기록한다. 4. 성공 시 index의 step을 `completed`로 바꾸고 생성 파일을 summary에 기록한다.
5. 패키지나 MSVC가 없으면 세 차례 임의 수정하지 말고 `blocked`로 종료한다. 5. 도구가 없으면 자동 설치하지 말고 `blocked`와 정확한 누락 항목을 기록한다.
## 금지사항 ## 금지사항
- FetchContent, vcpkg, Conan 또는 다운로드를 추가하지 마라. 이유: ADR-002 위반다. - 외부 패키지를 다운로드하지 마라. 이유: 사전 설치 의존성 정책을 위반다.
- vendor 절대경로를 public header에 노출하지 마라. 이유: backend 격리를 깨뜨린다. - MKL, TBB, HDF5 기능을 구현하지 마라. 이유: 다음 step의 독립 범위다.
- solver 기능을 구현하지 마라. 이유: 이 step은 build dependency 계약만 다룬다. - 빈 미래 모듈을 만들지 마라. 이유: Phase 1 최소 실체화 원칙을 위반한다.
+28 -45
View File
@@ -1,4 +1,4 @@
# Step 2: Core IDs and Diagnostics # Step 2: Dependency Smoke Tests
## 읽어야 할 파일 ## 읽어야 할 파일
@@ -6,67 +6,50 @@
- `/docs/PRD.md` - `/docs/PRD.md`
- `/docs/ARCHITECTURE.md` - `/docs/ARCHITECTURE.md`
- `/docs/ADR.md` - `/docs/ADR.md`
- `/docs/HARNESS.md`
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md` - `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
- `/CMakeLists.txt` - `/CMakeLists.txt`
- `/CMakePresets.json`
- `/cmake/FesaDependencies.cmake`
- `/.harness/config.json`
- `/tests/CMakeLists.txt` - `/tests/CMakeLists.txt`
- `/include/fesa/core/version.hpp`
이전 step의 CMake target과 preset을 그대로 확장하라.
## 작업 ## 작업
외부 라이브러리에 의존하지 않는 `core` 값 타입을 TDD로 구현한다. 사전 설치된 oneMKL, oneTBB, HDF5 C API, GoogleTest/GoogleMock을 CMake imported
target으로 찾고 링크 계약을 검증한다.
- 생성 파일: - `tests/unit/dependencies/dependency_smoke_test.cpp`를 먼저 작성한다.
`include/fesa/core/entity_id.hpp`, `vec3.hpp`, `source_location.hpp`, - 테스트는 MKL의 작은 vector 연산, TBB의 제한된 parallel loop, HDF5 임시 파일
`diagnostic.hpp`, `status.hpp`와 대응 테스트 생성·닫기, GoogleTest 실행을 확인한다.
- 인터페이스: - `FesaDependencies.cmake``MKL::MKL`, TBB imported target, HDF5 C target,
GoogleTest target을 제공해야 한다.
```cpp - oneMKL은 LP64, dynamic link, TBB threading 조합을 사용한다.
template<class Tag> - runtime DLL 또는 architecture 불일치는 configure diagnostic으로 보고한다.
class EntityId final {
public:
explicit constexpr EntityId(std::int64_t value);
[[nodiscard]] constexpr std::int64_t value() const noexcept;
auto operator<=>(const EntityId&) const = default;
};
struct Vec3 final { double x; double y; double z; };
struct SourceLocation final {
std::filesystem::path file;
std::size_t line;
std::size_t column;
};
enum class DiagnosticStage { io, syntax, semantic, model, equation, solver, results, validation };
enum class Severity { warning, error };
struct Diagnostic final {
DiagnosticStage stage;
Severity severity;
std::string code;
std::string message;
std::optional<SourceLocation> source;
};
```
- typed ID의 잘못된 암시 변환, 음수 ID, nonfinite vector와 diagnostic source 보존을
실패 테스트로 먼저 고정한다.
## Acceptance Criteria ## Acceptance Criteria
```powershell ```powershell
cmake --preset windows-debug
cmake --build --preset windows-debug cmake --build --preset windows-debug
ctest --preset windows-debug -R "Core|Diagnostic|EntityId" --output-on-failure ctest --preset windows-debug -R DependencySmoke --output-on-failure
ctest --preset windows-debug --output-on-failure ctest --preset windows-debug --output-on-failure
``` ```
네 의존성을 실제 호출하는 smoke test가 통과해야 하며 새 MSVC 경고가 없어야 한다.
## 검증 절차 ## 검증 절차
1. production header 전에 실패하는 GoogleTest를 작성한다. 1. smoke test를 먼저 추가하고 link 또는 실행 실패를 확인한다.
2. 최소 값 타입만 구현한다. 2. dependency discovery와 target link만 최소 수정한다.
3. focused test와 전체 CTest를 실행한다. 3. 전체 configure/build/test를 새로 실행한다.
4. `core`가 MKL, TBB, HDF5, Abaqus header를 include하지 않는지 확인한다. 4. 성공 시 정확한 imported target과 탐색 파일을 summary에 기록한다.
5. index와 summary를 갱신한다. 5. 패키지나 MSVC가 없으면 세 차례 임의 수정하지 말고 `blocked`로 종료한다.
## 금지사항 ## 금지사항
- 단위 변환 시스템을 만들지 마라. 이유: FESA는 일관 단위계만 사용한다. - FetchContent, vcpkg, Conan 또는 다운로드를 추가하지 마라. 이유: ADR-002 위반이다.
- 범용 reflection이나 serialization을 만들지 마라. 이유: 요구되지 않았다. - vendor 절대경로를 public header에 노출하지 마라. 이유: backend 격리를 깨뜨린다.
- equation ID를 정의하지 마라. 이유: `DofManager` 단계의 책임이다. - solver 기능을 구현하지 마라. 이유: 이 step은 build dependency 계약만 다룬다.
+73
View File
@@ -0,0 +1,73 @@
# Step 3: Core IDs and Diagnostics
## 읽어야 할 파일
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
- `/CMakeLists.txt`
- `/tests/CMakeLists.txt`
- `/include/fesa/core/version.hpp`
- `/tests/unit/dependencies/dependency_smoke_test.cpp`
## 작업
외부 라이브러리에 의존하지 않는 `core` 값 타입을 TDD로 구현한다.
- 생성 파일:
`include/fesa/core/entity_id.hpp`, `vec3.hpp`, `source_location.hpp`,
`diagnostic.hpp`, `status.hpp`와 대응 테스트
- 인터페이스:
```cpp
template<class Tag>
class EntityId final {
public:
explicit constexpr EntityId(std::int64_t value);
[[nodiscard]] constexpr std::int64_t value() const noexcept;
auto operator<=>(const EntityId&) const = default;
};
struct Vec3 final { double x; double y; double z; };
struct SourceLocation final {
std::filesystem::path file;
std::size_t line;
std::size_t column;
};
enum class DiagnosticStage { io, syntax, semantic, model, equation, solver, results, validation };
enum class Severity { warning, error };
struct Diagnostic final {
DiagnosticStage stage;
Severity severity;
std::string code;
std::string message;
std::optional<SourceLocation> source;
};
```
- typed ID의 잘못된 암시 변환, 음수 ID, nonfinite vector와 diagnostic source 보존을
실패 테스트로 먼저 고정한다.
## Acceptance Criteria
```powershell
cmake --build --preset windows-debug
ctest --preset windows-debug -R "Core|Diagnostic|EntityId" --output-on-failure
ctest --preset windows-debug --output-on-failure
```
## 검증 절차
1. production header 전에 실패하는 GoogleTest를 작성한다.
2. 최소 값 타입만 구현한다.
3. focused test와 전체 CTest를 실행한다.
4. `core`가 MKL, TBB, HDF5, Abaqus header를 include하지 않는지 확인한다.
5. index와 summary를 갱신한다.
## 금지사항
- 단위 변환 시스템을 만들지 마라. 이유: FESA는 일관 단위계만 사용한다.
- 범용 reflection이나 serialization을 만들지 마라. 이유: 요구되지 않았다.
- equation ID를 정의하지 마라. 이유: `DofManager` 단계의 책임이다.