# Step 1: DOF Manager ## 읽어야 할 파일 - `/AGENTS.md` - `/docs/PRD.md` - `/docs/ARCHITECTURE.md` - `/docs/ADR.md` - `/include/fesa/model/domain.hpp` - `/include/fesa/model/step_definition.hpp` - `/include/fesa/fem/` ## 작업 절점당 6자유도와 constrained/free equation numbering을 전담하는 `DofManager`를 구현한다. ```cpp enum class NodeDof : std::uint8_t { ux, uy, uz, rx, ry, rz }; struct DofAddress final { NodeId node; NodeDof dof; }; class DofManager final { public: [[nodiscard]] static DofManager build(const Domain&); [[nodiscard]] std::size_t full_dof_count() const noexcept; [[nodiscard]] std::size_t free_equation_count() const noexcept; [[nodiscard]] std::optional equation(DofAddress) const; [[nodiscard]] std::array element_full_dofs( const BeamElement&) const; [[nodiscard]] std::vector reconstruct_full( std::span reduced) const; }; ``` - external label 순서와 무관한 deterministic numbering, 비영 지정값, full/reduced reconstruction, invalid DOF를 실패 테스트로 먼저 고정한다. - equation ID를 Node/Element에 쓰지 않는다. ## Acceptance Criteria ```powershell cmake --build --preset windows-debug ctest --preset windows-debug -R "DofManager|EquationNumbering" --output-on-failure ctest --preset windows-debug --output-on-failure ``` ## 검증 절차 1. 실패 테스트를 먼저 실행한다. 2. Domain 읽기 전용 view만 사용해 numbering을 구현한다. 3. constrained/free mapping과 reconstruction을 직접 assertion한다. 4. 전체 테스트와 index 갱신을 수행한다. ## 금지사항 - sparse matrix pattern을 소유하지 마라. 이유: assembly 책임이다. - Node/Element에 equation ID를 저장하지 마라. 이유: 아키텍처 규칙 위반이다. - MPC나 penalty 자유도를 추가하지 마라. 이유: Phase 1 범위 밖이다.