## 2026-05-04 — 릴리스 파이프라인: npm provenance + release notes 워크플로

### 배경

기존 릴리스 흐름은 두 가지 결함이 있었다 — (1) `chore(release)` 커밋과 태그가 먼저 박히고 `docs/release-notes/<tag>.md`는 그 뒤에 따라붙어, 태그 ref만 체크아웃하면 노트 파일이 트리에 없는 상태였다. 워크플로가 이를 별도 `origin/main` fetch로 우회했지만 태그 push가 main보다 먼저 도달하는 race가 잠재해 있었음. (2) npm 공급망 보호를 위한 sigstore 빌드 provenance가 빠져 있어 npmjs.com 패키지 페이지의 "Built and signed on GitHub Actions" 배지를 받지 못했고, `npm audit signatures`로 무결성 검증이 불가능했음. 두 갈래 모두 정리해서 태그가 노트 포함 트리를 가리키게 하고 sigstore 서명을 enable.

### 주요 변경

#### 1. release notes phase 도입 + 워크플로 body_path 와이어링 (`586e372`)

- **`.claude/skills/release/SKILL.md`** — Phase 4 추가: `docs/release-notes/v<ver>.md` 작성.
- **`.github/workflows/release.yml`** — body_path를 노트 파일에서 읽고, 파일 누락 시 자동 생성 노트로 fallback.
- **`docs/release-notes/.gitkeep`** seed.

#### 2. release notes를 main 브랜치에서 fetch (이후 폐기) (`50b1102`)

태그 체크아웃이 post-tag 노트 커밋을 포함 안 하는 문제를 우회하려는 임시 단계. `origin/main`을 fetch해서 노트 파일을 `/tmp`로 추출 후 release에 사용. 이 우회는 곧 (4)에서 phase 재배치로 폐기됨.

#### 3. npm provenance 활성화 (`78f095a`)

sigstore 기반 빌드 provenance를 enable해 npmjs.com이 "Built and signed on GitHub Actions" 배지를 표시하고, 소비자가 `npm audit signatures`로 특정 tarball이 이 레포의 특정 커밋에서 빌드되었는지 검증할 수 있게 함. 도용된 npm 토큰으로 변조된 버전을 publish 하는 공급망 공격 완화. OIDC 토큰이 GitHub Actions per run으로 발급되므로 secret 회전 불필요.

- **`.github/workflows/release.yml` (npm-release job)**:
  - `permissions: contents: write` 명시 (action-gh-release 유지)
  - `id-token: write` 추가 (sigstore attestation용 OIDC 토큰)
  - `npm publish`에 `--provenance --access public` 플래그.

#### 4. release notes를 release 커밋에 같이 묶기 (`a33b596`)

기존엔 chore(release) 커밋과 태그가 먼저 박힌 뒤 노트 커밋이 따라붙는 구조라, 태그 ref만 체크아웃하면 `docs/release-notes/<tag>.md`가 없는 상태였다. 워크플로가 별도 `origin/main` fetch로 우회 중이었으나 태그 push가 main보다 먼저 도달하는 race가 남아 있었음. 태그가 노트 포함 트리를 가리키도록 phase 재배치.

- **`.claude/skills/release/SKILL.md`** — phase 재배치. Phase 3에서 노트 파일만 작성하고, Phase 4가 `package.json`/`package-lock.json`과 함께 같은 커밋에 stage. 태그가 노트 포함 커밋을 가리킴.
- **`.github/workflows/release.yml`** — 'Fetch release notes from main' 단계를 'Locate release notes'로 단순화. 태그 체크아웃 트리에서 직접 `cp`, `origin/main` fetch 우회 제거.

### 수정된 주요 파일

| 파일 | 변경 내용 |
|------|----------|
| `.github/workflows/release.yml` | sigstore provenance(`--provenance`, `id-token: write`) + 태그 트리에서 release notes 직접 cp |
| `.claude/skills/release/SKILL.md` | release notes를 release 커밋 자체에 stage 하도록 phase 재배치 |
| `docs/release-notes/` | NEW — 버전별 노트 파일 보관 디렉터리 (.gitkeep) |

### 아키텍처 결정

1. **태그가 노트 포함 트리를 가리키도록 정렬**: 워크플로 측 우회(별도 main fetch)는 태그 push와 main push 사이의 race 윈도우가 남는 구조적 문제. release skill의 phase를 다시 짜서 `package.json` 버전 bump와 노트 작성을 같은 커밋에 묶고, 그 뒤에 태그를 박는 식으로 수정. 태그 체크아웃 단독으로 노트가 따라오므로 워크플로가 단순한 `cp`만 하면 됨.
2. **OIDC 기반 sigstore는 secret 회전 무관**: provenance 발급은 GitHub Actions가 매 run마다 OIDC 토큰을 mint하는 식이라 별도 cosign 키나 secret 등록이 필요 없음. `id-token: write` 권한만 job에 추가하면 끝. npm 토큰 자체는 그대로 쓸 수 있음.

---
