# Step 1: Part and Assembly Set Resolution

## 읽어야 할 파일

- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/ABAQUS_INPUT_SUBSET.md`
- `/include/fesa/io/abaqus/`
- `/include/fesa/model/entity_set.hpp`
- `/tests/fixtures/abaqus/`

## 작업

Part 및 Assembly scope의 `NSET/ELSET`을 결정적으로 해석한다.

```cpp
struct ResolvedSet final {
    std::string scope_name;
    std::string set_name;
    std::vector<std::int64_t> sorted_unique_labels;
};
struct SetResolutionResult final {
    std::vector<ResolvedSet> sets;
    std::vector<Diagnostic> diagnostics;
};
[[nodiscard]] SetResolutionResult resolve_sets(const ParsedDeck&);
```

- explicit member, `GENERATE`, nested reference, forward reference, duplicate member,
  empty set, cycle, unknown set/entity, invalid range를 실패 테스트로 먼저 작성한다.
- Part와 Assembly의 같은 set 이름을 별도 scope로 허용한다.
- Assembly `INSTANCE=`는 활성 단일 Instance의 Part-local label만 lift한다.

## Acceptance Criteria

```powershell
cmake --build --preset windows-debug
ctest --preset windows-debug -R "SetResolution|PartSet|AssemblySet" --output-on-failure
ctest --preset windows-debug --output-on-failure
```

## 검증 절차

1. scope collision과 cycle 테스트의 실패를 확인한다.
2. graph resolution과 canonical sorted-unique 결과를 구현한다.
3. source diagnostic과 deterministic order를 assertion한다.
4. 전체 테스트와 index를 갱신한다.

## 금지사항

- Part와 Assembly set namespace를 합치지 마라. 이유: 이름 충돌 의미가 달라진다.
- cycle을 recursion overflow로 발견하지 마라. 이유: 명시적 cycle diagnostic이 필요하다.
- 여러 Instance key를 지원하지 마라. 이유: Phase 1 단일 Instance 범위다.
