# Step 3: analysis-model-view ## 읽어야 할 파일 먼저 아래 파일들을 읽고 프로젝트의 아키텍처와 이전 step 산출물을 파악하라: - `/AGENTS.md` - `/docs/PRD.md` - `/docs/ARCHITECTURE.md` - `/docs/ADR.md` - `/src/fesa/model/domain.hpp` - `/src/fesa/model/analysis_step.hpp` - `/tests/unit/model_domain_test.cpp` 이전 step에서 만들어진 Domain과 AnalysisStep을 꼼꼼히 읽고, Domain 복사 없는 step view를 유지하라. ## 작업 현재 step에서 활성화되는 해석 객체 view를 제공하는 `AnalysisModel`을 `/src/fesa/analysis/`에 구현한다. 필수 파일: - `/src/fesa/analysis/analysis_model.hpp` - `/tests/unit/analysis_model_view_test.cpp` 필수 interface: ```cpp namespace fesa::analysis { class AnalysisModel { public: AnalysisModel(const model::Domain& domain, core::StepId step_id); const model::Domain& domain() const; const model::AnalysisStep& step() const; const std::vector& active_elements() const; const std::vector& active_boundary_conditions() const; const std::vector& active_loads() const; const model::Property* property_for(const model::Element& element) const; const model::Material* material_for(const model::Property& property) const; }; } // namespace fesa::analysis ``` 구현 규칙: - `AnalysisModel`은 `Domain`을 복사하지 않고 const reference 또는 pointer view만 보유한다. - Phase skeleton에서는 모든 Domain elements가 active라고 간주한다. - Boundary condition과 load는 선택된 `AnalysisStep`에서 가져온다. - `property_for`와 `material_for`는 Domain lookup을 사용한다. - 없는 step id는 구조화된 exception 대신 `std::invalid_argument`로 실패해도 된다. 이 skeleton 단계에서는 별도 error hierarchy를 만들지 않는다. - `AnalysisModel`은 displacement, residual, equation number를 소유하지 않는다. ## Tests To Write First - `/tests/unit/analysis_model_view_test.cpp` - Domain에 node/element/material/property/step을 만든다. - `AnalysisModel(domain, step_id)`가 원본 Domain reference를 유지함을 pointer identity로 확인한다. - 모든 Domain element가 `active_elements()`에 const pointer로 나타난다. - step의 boundary condition과 load가 active view에 const pointer로 나타난다. - `property_for(element)`와 `material_for(property)`가 Domain 소유 객체를 반환한다. - 없는 step id는 `std::invalid_argument`를 던진다. RED 확인: 1. 테스트 파일을 먼저 작성한다. 2. targeted CTest를 실행해 missing `analysis_model.hpp`로 실패함을 확인한다. 3. 그 뒤 production header를 작성한다. ## Acceptance Criteria ```powershell python -m unittest discover -s scripts -p "test_*.py" python scripts/validate_workspace.py ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R analysis_model_view_test ``` ## 검증 절차 1. 위 AC 커맨드를 실행한다. 2. 아키텍처 체크리스트를 확인한다: - AnalysisModel이 Domain을 복사하지 않는가? - AnalysisModel이 현재 step view만 제공하고 mutable state를 소유하지 않는가? - active BC/load가 AnalysisStep에서 온 것임이 테스트되는가? 3. 결과에 따라 `phases/solver-core-skeleton/index.json`의 step 3을 업데이트한다: - 성공: `"status": "completed"`, `"summary": "AnalysisModel step view added without Domain copies"` - 3회 수정 시도 후 실패: `"status": "error"`, `"error_message": "구체적 에러 내용"` - 사용자 개입 필요: `"status": "blocked"`, `"blocked_reason": "구체적 사유"` 후 중단 ## 금지사항 - DofManager나 equation numbering을 이 step에서 구현하지 마라. - AnalysisState를 이 step에서 구현하지 마라. - JavaScript/TypeScript/npm fallback을 추가하지 마라.