# Step 0: Symmetric CSR Assembly ## 읽어야 할 파일 - `/AGENTS.md` - `/docs/PRD.md` - `/docs/ARCHITECTURE.md` - `/docs/ADR.md` - `/include/fesa/model/domain.hpp` - `/include/fesa/fem/dof_manager.hpp` - `/include/fesa/elements/beam/beam3d2.hpp` ## 작업 Beam local contribution으로부터 deterministic serial symmetric CSR과 full load vector를 조립한다. ```cpp struct SymmetricCsr final { std::size_t order; std::vector row_offsets; std::vector column_indices; std::vector values; }; struct EquationSystem final { SymmetricCsr stiffness; std::vector force; }; [[nodiscard]] EquationSystem assemble_serial( const Domain&, const DofManager&); ``` - sparsity pattern builder와 numeric contribution merge를 분리한다. - `(row,column,element-origin,local-order)`의 안정된 순서로 합산한다. - hand-calculated 2-element system, duplicate contribution, external ID 순서 변화, CSR invariant를 실패 테스트로 먼저 작성한다. ## Acceptance Criteria ```powershell cmake --build --preset windows-debug ctest --preset windows-debug -R "SparsePattern|SerialAssembly|SymmetricCsr" --output-on-failure ctest --preset windows-debug --output-on-failure ``` ## 검증 절차 1. expected CSR 구조와 값을 고정한 실패 테스트를 실행한다. 2. pattern과 numeric assembly를 최소 구현한다. 3. row offset, sorted column, upper/lower storage 계약을 확인한다. 4. 전체 테스트와 index를 갱신한다. ## 금지사항 - 공유 CSR에 병렬 누적하지 마라. 이유: 이 phase는 serial oracle을 만든다. - PARDISO를 호출하지 마라. 이유: backend step의 책임이다. - element formulation을 assembly에 복제하지 마라. 이유: 모듈 경계를 깨뜨린다.