# FESA Session Handoff

## 1. 문서 목적

이 문서는 `fem-and-beam-kernel` 완료 후 새 세션에서
`equation-and-linear-solve` Phase를 바로 시작하기 위한 인수인계 기록이다.
요구사항과 설계의 기준은 이 문서가 아니라 다음 파일이다.

- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/HARNESS.md`
- `/docs/formulation/timoshenko-beam-3d.md`
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
- `/phases/equation-and-linear-solve/index.json`
- `/phases/equation-and-linear-solve/step0.md`부터 `step2.md`

내용이 충돌하면 위 기준 문서와 `phases/`의 현재 상태를 우선한다.

## 2. 현재 저장소 상태

2026-07-31 확인 기준:

- 현재 브랜치: `dev`
- 현재 `dev` HEAD:
  `fa48a4d9d717224ed84ec41f06c43fbc33d42780`
- `origin/dev`, `origin/HEAD`:
  `4ee3895915accf69c3f988bf14119fab7c318ed5`
- 로컬 `dev`는 `origin/dev`보다 10 commit 앞서고 0 commit 뒤처져 있다.
- 완료 Phase:
  - `solver-bootstrap`
  - `domain-and-input-skeleton`
  - `fem-and-beam-kernel`
- 다음 Phase: `equation-and-linear-solve`
- 다음 Step: `0 - symmetric-csr-assembly`
- `equation-and-linear-solve`의 Step 0~2는 모두 `pending`이다.
- `fem-and-beam-kernel`은 `dev`에 fast-forward 병합되었고 로컬
  `feat-fem-and-beam-kernel` 브랜치는 삭제되었다.
- 원격 push는 수행하지 않았다.

이 문서를 갱신하기 직전 작업 트리는 clean이었다. 이 문서 변경은 사용자가 별도로
요청하지 않는 한 커밋하지 않는다. 새 세션에서 Harness를 실행하기 전에
`docs/HANDOFF.md` 변경을 먼저 커밋하거나 별도로 정리해야 한다. 그렇지 않으면
executor의 feature branch와 step commit에 인수인계 문서가 섞일 수 있다.

## 3. 완료된 `fem-and-beam-kernel`

Phase metadata는 `/phases/fem-and-beam-kernel/index.json`에 기록되어 있으며 Step
0~3이 모두 `completed`다.

### FEM primitives

- `/include/fesa/fem/gauss_rule.hpp`
- `/include/fesa/fem/line2_shape.hpp`
- 1점/2점 1D Gauss rule
- 2절점 선형 shape function, 자연좌표 derivative와 \(J=L/2\)
- partition of unity, endpoint interpolation, 적분 정확도와 invalid-input 테스트

### `DofManager`

- `/include/fesa/fem/dof_manager.hpp`
- internal `NodeId` 정렬에 기반한 deterministic full DOF numbering
- 절점당 순서:
  \(u_x,u_y,u_z,r_x,r_y,r_z\)
- free equation mapping, prescribed value, 12-DOF Beam mapping과 full-vector 복원
- equation ID는 `Node`나 `BeamElement`에 저장하지 않는다.

현재 `DofManager::build(const Domain&)`는 `Domain::step().prescribed_dofs`를 읽어
구속 자유도와 prescribed 값을 이미 내부에 반영한다. 다음 Phase에서 이 상태를
중복 소유하지 않도록 주의한다.

### Beam frame와 transformation

- `/include/fesa/fem/beam_frame.hpp`
- scale-aware normalization과 Gram-Schmidt
- 오른손 기저 \(e_z=e_x\times e_y\)
- 요소축과 orientation의 평행 판정에 scale-aware tolerance 적용
- 12x12 global-to-local transformation과 회전/에너지 invariant 테스트

### Timoshenko stiffness kernel

- `/include/fesa/elements/beam/beam3d2.hpp`
- `/docs/formulation/timoshenko-beam-3d.md`
- local DOF 순서:
  `[u,v,w,theta_x,theta_y,theta_z]` per node
- strain component 순서:
  \([\epsilon,\gamma_y,\gamma_z,\kappa_x,\kappa_y,\kappa_z]\)
- \(\gamma_y=v'-\theta_z\), \(\gamma_z=w'+\theta_y\)
- constitutive diagonal:
  \([EA,GA_{sy},GA_{sz},GJ,EI_y,EI_z]\)
- 축·비틀림·굽힘은 2점, 전단은 1점 Gauss 적분
- global stiffness는 \(T^\mathsf{T}K_\mathrm{local}T\)
- 대칭성, 여섯 강체모드, 축, 비틀림, 양 축 굽힘과 전단, 세장비 sweep,
  좌표 회전 invariant 테스트

통합 설명은 구현처럼 upper triangle을 적분한 뒤 대칭 위치로 복사한다고
`fa48a4d`에서 정정했다.

## 4. 검증된 baseline과 개발환경

새 PowerShell 세션에서 configure 또는 Harness 실행 전에 다음 환경 변수를 설정한다.
절대경로를 tracked CMake 파일이나 Preset에 넣지 않는다.

```powershell
$env:MKL_DIR = "C:\Program Files (x86)\Intel\oneAPI\2026.1\lib\cmake\mkl"
$env:TBB_DIR = "C:\Program Files (x86)\Intel\oneAPI\2026.1\lib\cmake\tbb"
$env:HDF5_DIR = "C:\Program Files\HDF_Group\HDF5\2.1.1\cmake"
$env:GTest_DIR = "C:\Users\baram\AppData\Local\FESA\dependencies\googletest-1.17.0-v145-x64-crt\lib\cmake\GTest"

Test-Path "$env:MKL_DIR\MKLConfig.cmake"
Test-Path "$env:TBB_DIR\TBBConfig.cmake"
Test-Path "$env:HDF5_DIR\hdf5-config.cmake"
Test-Path "$env:GTest_DIR\GTestConfig.cmake"
```

2026-07-31 현재 네 package 경로가 모두 존재한다. 현재 `dev` HEAD에서 다음 baseline을
새로 검증했다.

- MSBuild 18.8.2, MSVC v145 Debug build 성공
- build 출력에 새 warning 없음
- CTest 22개 중 22개 성공
- Harness pytest 20개 중 20개 성공
- pytest가 실제로 20개를 수집했으므로 0-test 성공이 아님

검증 명령:

```powershell
cmake --build --preset windows-debug
ctest --preset windows-debug --output-on-failure
uv run --with pytest python -m pytest -v -rs
```

CMake cache가 없거나 package 경로가 바뀐 경우에만 같은 환경 변수 세션에서 먼저
다음을 실행한다.

```powershell
cmake --fresh --preset windows-debug
```

## 5. 다음 Phase 목표와 Step 순서

`equation-and-linear-solve`의 독립 deliverable은 Beam contribution과 nodal load를
full symmetric system으로 조립하고, essential BC를 소거한 뒤 MKL PARDISO로
reduced SPD system을 푸는 것이다. 세 Step을 순서대로 실행한다.

### Step 0 — `symmetric-csr-assembly`

- `/include/fesa/assembly/`와 `/src/fesa/assembly/`에 필요한 최소 계약을 만든다.
- `SymmetricCsr {order,row_offsets,column_indices,values}`와
  `EquationSystem {stiffness,force}`를 구현한다.
- `Domain`의 Beam, material, section, node와 `DofManager::element_full_dofs()`를
  사용해 `compute_beam3d2()`의 global contribution을 조립한다.
- sparsity pattern 생성과 numeric merge를 분리한다.
- `(row,column,element-origin,local-order)`의 안정된 순서로 합산한다.
- hand-calculated 2-element system, duplicate contribution, external ID 순서 변화와
  CSR invariant를 실패 테스트로 먼저 고정한다.
- 이 Step의 serial assembler는 후속 병렬 조립의 oracle이다. TBB 병렬화는
  `deterministic-parallel-assembly` Phase까지 미룬다.

### Step 1 — `essential-bc-elimination`

- `/include/fesa/constraints/`와 `/src/fesa/constraints/`에 essential-BC elimination을
  구현한다.
- 원래 full `EquationSystem`은 변경하지 않고 reduced symmetric system을 만든다.
- 0과 비영 prescribed value의 RHS shift를 모두 처리한다.
- free solution과 prescribed 값을 full vector로 복원한다.
- 반력은 reduced matrix가 아니라 원래 시스템의 \(r=Ku-f\)에서 계산한다.
- hand calculation으로 0/비영 지정값, all-constrained, 충돌 조건과 반력을 먼저
  테스트한다.

### Step 2 — `pardiso-linear-solver`

- `/include/fesa/solvers/linear/`와 `/src/fesa/solvers/linear/`에 backend 경계를
  구현한다.
- public `LinearSolver` 계약에는 MKL 타입을 노출하지 않는다.
- `PardisoLinearSolver`가 analysis, factorization, solve, release 수명을 RAII로
  관리한다.
- `mtype=2`, LP64 index, `iparm[34]=1`, matrix checker를 사용한다.
- 3x3 SPD, repeated solve, invalid CSR, dimension mismatch와 singular matrix를
  실패 테스트로 먼저 고정한다.
- 해와 상대잔차를 adapter 외부의 독립 계산으로 확인한다.

## 6. 다음 Phase의 핵심 계약과 확인할 설계점

### 아키텍처 경계

- `assembly`는 sparse pattern, local-to-global mapping, contribution 정렬·병합과
  CSR 변환만 담당한다. Beam formulation이나 PARDISO handle을 소유하지 않는다.
- `constraints`는 essential BC와 full/reduced vector 변환만 담당한다.
- `solvers/linear`만 MKL PARDISO API에 의존한다.
- `core`, `model`, `fem`, `elements`에 MKL 또는 TBB API를 유입하지 않는다.
- penalty, MPC, Lagrange multiplier, iterative solver, 병렬 조립과 analysis
  pipeline은 이번 Phase 범위가 아니다.

### 구현 전에 명시적으로 정렬할 점

1. `SymmetricCsr`의 upper/lower triangle 저장 계약이 Step 파일에 아직 하나로
   고정되어 있지 않다. Step 0에서 테스트와 주석으로 하나를 명시하고 Step 1~2와
   일관되게 사용한다.
2. `DofManager`는 이미 free equation mapping과 prescribed 값을 내부 소유한다.
   Step 1 초안의 별도 `prescribed` 인수와 `ReducedSystem` 상태를 그대로 중복하지
   말고, 기존 계약을 읽은 뒤 필요한 최소 query만 추가한다.
3. `Domain`은 material/section span을 제공하지만 현재 ID lookup public accessor는
   없다. 조립을 위해 mutable `Domain`이나 범용 registry를 만들지 말고, Phase 1에
   필요한 deterministic lookup을 최소 범위로 구현한다.
4. `BeamKernelResult`는 contribution 또는 diagnostic을 반환한다. 조립 계층이
   실패를 무시하거나 zero matrix로 대체하지 않도록 오류 전달 계약을 테스트한다.
5. all-constrained 문제는 reduced order가 0일 수 있다. constraint 계층에서 유효한
   결과로 다루되, 빈 system을 PARDISO에 넘기는 정책과 혼동하지 않는다.

위 항목은 범위를 넓히라는 의미가 아니다. 기존 코드와 Step 초안 사이의 중복 또는
미정 계약을 구현 전에 드러내고 가장 단순한 일관된 계약을 선택하기 위한 확인
목록이다.

## 7. Child sandbox의 MSBuild 실행 조건

`fem-and-beam-kernel` 실행 전 child sandbox를 실제로 조사한 결과:

- 앱 설치 경로의 `codex-cli 0.146.0`은 matching `codex-resources`를 찾지 못했다.
- 완전한 standalone 배포는 다음 위치에 있다.
  `C:\Users\baram\.codex\packages\standalone\releases\0.146.0-x86_64-pc-windows-msvc`
- child에서 WindowsApps 경유 PowerShell은 실패했고 Windows PowerShell 5.1은
  정상 동작했다.
- `[windows] sandbox = "elevated"`에서는 MSBuild FileTracker가 access denied로
  실패했다.
- 완전한 standalone Codex, 정리된 PATH와
  `[windows] sandbox = "unelevated"` 조합에서는 child MSBuild가 성공했다.

현재 `C:\Users\baram\.codex\config.toml`은 원래 값인
`[windows] sandbox = "elevated"`로 복원되어 있다. 다음 Harness 실행에서도 같은
문제가 재현되면 사용자가 이미 선택한 1번 방식에 따라 다음 순서를 사용한다.

1. 다른 Codex 작업에 미칠 영향을 확인하고 global config 원래 값을 기록한다.
2. Harness 실행 동안만 `[windows] sandbox = "unelevated"`로 바꾼다.
3. 현재 PowerShell 세션의 PATH 앞에 standalone `bin`과 Windows PowerShell 5.1을
   둔다. `Get-Command codex`와 `Get-Command powershell`로 실제 경로를 확인한다.

```powershell
$codexReleaseBin = "C:\Users\baram\.codex\packages\standalone\releases\0.146.0-x86_64-pc-windows-msvc\bin"
$windowsPowerShell = "$env:SystemRoot\System32\WindowsPowerShell\v1.0"
$filteredPath = $env:PATH -split ";" | Where-Object {
    $_ -and
    $_ -ne $codexReleaseBin -and
    $_ -ne $windowsPowerShell -and
    $_ -notmatch "\\Microsoft\\WindowsApps$" -and
    $_ -notmatch "\\OpenAI\\Codex\\bin$"
}
$env:PATH = (@($codexReleaseBin, $windowsPowerShell) + $filteredPath) -join ";"

(Get-Command codex).Source
(Get-Command powershell).Source
```

4. 같은 세션에서 package 환경 변수와 baseline을 확인한 뒤 Harness를 실행한다.
5. 성공·실패와 무관하게 global config를 즉시
   `[windows] sandbox = "elevated"`로 복원하고 실제 값을 다시 읽어 확인한다.

사용자 profile 전체나 드라이브 루트를 `--codex-add-dir`로 허용하지 않는다. 설치
버전이나 경로가 달라졌다면 위 절대경로를 맹목적으로 사용하지 말고 실제 standalone
release와 `codex-resources` 존재를 먼저 확인한다.

이전 Harness는 모든 Step과 phase commit을 완료한 뒤 stderr reader의 CP949/UTF-8
decode 예외를 한 번 출력했다. Phase metadata와 Git commit에는 영향이 없었고 root
검증은 모두 통과했다. 같은 메시지가 반복되면 제품 실패로 단정하지 말고 executor
종료 시점, phase status와 Git 이력을 함께 확인한다.

## 8. 새 세션 시작 절차

먼저 이 문서와 다음 Phase 파일을 모두 읽는다.

```text
/phases/equation-and-linear-solve/index.json
/phases/equation-and-linear-solve/step0.md
/phases/equation-and-linear-solve/step1.md
/phases/equation-and-linear-solve/step2.md
```

그 다음 저장소 상태를 재검증한다.

```powershell
git switch dev
git status --short --branch
git rev-parse HEAD
git rev-parse origin/dev
```

로컬 `dev`의 미push 10 commit을 보존한다. `origin/dev`에 맞추기 위한 reset, checkout
또는 rebase를 수행하지 않는다. `docs/HANDOFF.md` 변경이 남아 있으면 먼저 사용자의
의도대로 커밋하거나 정리한다.

4절의 package 환경 변수를 설정하고 baseline을 실행한다. Child MSBuild 문제가
재현될 가능성이 있으므로 7절 조건을 적용한 뒤 다음을 실행한다.

```powershell
python scripts/execute.py equation-and-linear-solve
```

executor는 `feat-equation-and-linear-solve` 브랜치를 생성하거나 checkout하고 Step
상태와 output metadata를 기록한다. 사용자가 명시적으로 요청하지 않은 한 `--push`를
사용하지 않는다.

각 Step은 다음 순서를 지킨다.

1. Step 파일의 필수 문서와 선행 구현을 모두 읽는다.
2. 성공 기준과 CSR/constraint/backend invariant를 명시한다.
3. 실패 테스트를 먼저 작성하고 예상한 이유로 실패함을 확인한다.
4. 테스트를 통과시키는 최소 production code만 구현한다.
5. focused test, 전체 CTest, Harness pytest를 실행한다.
6. Step summary와 output metadata가 실제 결과와 일치하는지 확인한다.
7. Phase 종료 전 전체 diff를 아키텍처·수치 계약·resource lifetime 기준으로
   review한다.

## 9. 다음 Phase 완료 조건

- `/phases/equation-and-linear-solve/index.json`의 Step 0~2가 모두 `completed`
- `/phases/index.json`에서 `equation-and-linear-solve`가 `completed`
- deterministic serial symmetric CSR의 구조·값·stable merge 테스트 통과
- full load vector와 Beam global contribution의 hand calculation 일치
- 0/비영 essential BC의 RHS shift와 full-vector 복원 검증 통과
- 반력이 원래 \(r=Ku-f\)에서 정확히 복원됨
- PARDISO SPD solve, repeated solve, invalid input와 singular diagnostic 검증 통과
- focused test와 전체 CTest 통과
- Harness pytest가 0개가 아닌 상태로 전체 통과
- 새 MSVC warning 없음
- MKL 타입과 handle이 `solvers/linear` adapter 밖으로 노출되지 않음
- TBB 병렬 조립, analysis pipeline 또는 범위 밖 solver 기능을 선행 구현하지 않음
- review의 Critical/Important 항목 해결
- 사용자 선택 전 원격 push나 `dev` 병합을 수행하지 않음

새 세션의 권장 첫 요청:

> `docs/HANDOFF.md`와 `phases/equation-and-linear-solve/step0.md`부터 `step2.md`를
> 읽고 현재 baseline과 child sandbox의 MSBuild 실행 조건을 확인한 뒤
> `equation-and-linear-solve` Phase를 시작해주세요.
