# Step 0: Canonical Contribution Order ## 읽어야 할 파일 - `/AGENTS.md` - `/docs/PRD.md` - `/docs/ARCHITECTURE.md` - `/docs/ADR.md` - `/include/fesa/assembly/` - `/src/fesa/assembly/` - `/include/fesa/model/entity_origin.hpp` ## 작업 serial assembly를 변경하지 않고 병렬 계산이 사용할 canonical contribution record와 merge contract를 분리한다. ```cpp struct MatrixContribution final { std::size_t row; std::size_t column; ElementId element; std::uint16_t local_order; double value; }; [[nodiscard]] std::vector canonicalize_contributions( std::span); [[nodiscard]] SymmetricCsr merge_contributions( std::size_t order, std::span canonical); ``` - 입력 순열, 같은 row/column의 여러 element, cancellation, signed zero를 포함해 결과 CSR이 bit-for-bit 같은 테스트를 먼저 작성한다. - 정렬 key는 row, column, stable element identity, local order다. ## Acceptance Criteria ```powershell cmake --build --preset windows-debug ctest --preset windows-debug -R "CanonicalContribution|DeterministicMerge" --output-on-failure ctest --preset windows-debug --output-on-failure ``` ## 검증 절차 1. shuffled contribution 테스트의 실패를 확인한다. 2. stable total order와 단일 merge 구현만 추가한다. 3. serial oracle의 CSR과 bitwise 비교한다. 4. 전체 테스트와 index를 갱신한다. ## 금지사항 - tolerance 기반으로 assembly 값을 같다고 처리하지 마라. 이유: bitwise 재현성 계약이다. - parallel code를 추가하지 마라. 이유: 다음 step의 책임이다. - unordered concurrent accumulation을 준비하지 마라. 이유: 결정성을 깨뜨린다.