# v0.2.2 Dogfood 피드백 로드맵 (#7→#6 → v0.2.3) 설계

**작성일:** 2026-05-01
**저자:** 김태현 (dlsrks0734@gmail.com)
**문서 성격:** v0.2.2 dogfood 중 발견된 7개 항목 (`memory/project_v022_feedback.md` #1~#6 + 본 brainstorm 에서 추가된 #7 telemetry) 의 순차 작업 로드맵. 본 문서는 **순서·범위·게이트** 만 정의하며, 각 항목 내부 설계는 항목별 mini-brainstorm + writing-plans 에서 결정.

**선행 문서:**
- `memory/project_v022_feedback.md` (raw 피드백 6건)
- `docs/superpowers/specs/2026-04-26-feedback-roadmap-design.md` (v0.2.1 로드맵, 본 문서의 패턴 원형)
- `docs/superpowers/specs/2026-04-24-inkling-vertical-slice-design.md` (slice §1.1 invariant 4 — 본문 미기록)
- `docs/superpowers/strategy/strategy.md` (#6 에서 §2.3·§4.3·§8 동반 갱신 대상)

---

## 1. 결정 요약

| 결정 | 값 | 근거 |
|------|-----|------|
| Cut 패턴 | **단일 cut v0.2.3** (7항목 한 묶음) | v0.2.1 패턴 반복. 항목 간 결합도 (특히 #7 → #4~#6 emit) 분리 시 회전 비용. |
| 우선순위 기준 | **데이터 안전 우선** (v0.2.1 패턴) | 측정 인프라 (#7) → schema migration v3 (#4) → 안전망 위에서 기능 진행. |
| 첫 항목 | **#7 Telemetry skeleton** | 다른 6 항목이 emit hook 만 추가. 측정 없는 기능 출시는 다음 cut 까지 1주 본인 라벨링으로 후퇴. |
| 항목당 게이트 | **머지 + 테스트 통과** (typecheck + 205+ 단위 + e2e smoke) | v0.2.2 기준선. |
| 다음 빌드 | **v0.2.3** (7항목 모두 머지 후 단일 cut) | slice §7 strict-pin patch 증분. |
| 신규 dependency | **0 목표** | 모두 stdlib + 기존 better-sqlite3 / electron 으로 충분. |
| Schema 변경 | **migration v3** — 3 컬럼 한 번에: `deleted_at TEXT NULL`, `last_recalled_at TEXT NULL`, `recall_dismissed_at TEXT NULL` | #4 휴지통 + #6 회상 메타 한 묶음. 별 migration 두 번 회피. |
| Trash 와 export/backup | **B 정책** — F6-L1 backup 포함 (byte-for-byte), F5 export 제외, F6-L3 import 시 `deleted_at IS NOT NULL` 우선 (삭제 보존) | 백업은 회복 용도, export 는 외부 노출 형식. |
| Decision-pending 처리 | **항목별 mini-brainstorm** | 본 문서는 순서·In/Out 만, 항목 내부는 per-item. |

---

## 2. 순차 작업 순서

```
v0.2.2 ────────[ dogfood 동결, 병렬 진행 ]────────
                                                  │
개발 트랙 (main 직접 머지 또는 PR):                  │
  ① #7  Telemetry skeleton  [작음, 인프라 1번]      │
  ② #4  휴지통 + migration v3 [중, schema + 정책]   │
  ③ #5  만료 추천             [작음, #4 destination]│
  ④ #1  Ollama 회복 polling   [작음, 독립]          │
  ⑤ #2  AI retry / 수동 trigger [중, AiWorker 정책] │
  ⑥ #3  태그 vocab 주입        [작음, 독립]         │
  ⑦ #6  리마인드 1 spike        [중, strategy 갱신] │
                                                  │
                                       ┌──────────┘
                                       ▼
                          v0.2.3 cut (단일)
                                       │
                                       ▼
                          dogfood 재설치 + ≥ 1주 soak
                                       │
                                       ▼
                          telemetry export → 분석 →
                          v0.2.4 brainstorm
```

### 2.1 순서 결정 근거

1. **#7 (1번)** — 측정 인프라. 다른 항목이 emit hook 추가만 하도록 skeleton 먼저. Cross-cutting privacy invariant 강제도 1번에서 단위 테스트로 고정.
2. **#4 (2번)** — schema migration v3 가 #6 회상 메타 컬럼 동반. 휴지통 invariant (`deleted_at IS NULL` 모든 active 쿼리) 가 다른 항목에 영향. 회복 안전망 (pre-v3 snapshot, v0.2.1 메커니즘) 위에서 진행.
3. **#5 (3번)** — #4 휴지통 destination 직접 소비. 같은 영역 (Inbox 상단 배너).
4. **#1 (4번)** — #2 의 reliable health 의존성. polling 인프라 먼저.
5. **#2 (5번)** — #1 health 위에서 retry/manual trigger 정책 변경. AiWorker 의 unreachable infinite retry 로 #1 polling 결과 활용.
6. **#3 (6번)** — 독립 prompt 변경. PROMPT_VERSION 4. AI 영역 마지막에 묶어서 AiWorker 회귀 위험 격리.
7. **#6 (7번)** — strategy.md 갱신 + RecallBanner 1 spike. last_recalled_at / recall_dismissed_at 사용. 가장 마지막에 두는 이유: 다른 항목 telemetry hook 이 모두 박혀야 #6 측정 가치가 살아남.

---

## 3. 항목당 In (PR 범위) / Out (deferred)

각 항목 PR 범위 라인. 세부 결정 (decision-pending) 은 항목 시작 시 mini-brainstorm.

### #7 Telemetry skeleton (1번) ✓ 완료

**In:**
- `TelemetryService` (`src/main/services/TelemetryService.ts`):
  - `emit(kind, payload)` → 비동기 append to `<profileDir>/telemetry/events-YYYY-MM-DD.jsonl`
  - 일자별 rotation (KST 자정), 14일 후 rolling 삭제
  - write 실패 시 silent log only (앱 동작 영향 없음)
- 이벤트 zod schema: `{ ts: ISO string, kind: enum, payload: object }`. payload shape 는 kind 별 fixed.
- **Privacy invariant** (slice §1.1 invariant 4 강화): payload 에 `raw_text` / `ai_title` / `ai_summary` / `user_intent` / 태그 name 포함 시 zod parser 거부. 단위 테스트로 고정.
- 기본 emit hook 박기:
  - `capture` (CaptureService.submit 후): `{ noteId, rawTextLength, hasMedia }`
  - `ai_succeeded` (AiWorker.processJob 성공): `{ noteId, durationMs, attempts }`
  - `ai_failed` (AiWorker.processJob 실패): `{ noteId, reason: "unreachable"|"schema"|"timeout"|"other", attempts }`
- 트레이 메뉴 "사용 로그 내보내기...":
  - 폴더 다이얼로그 → `events.jsonl` (최근 14일 concat) + `stats.md` (집계 마크다운) zip
  - `stats.md` 내용: 항목별 일자별 카운트 표 + 핵심 ratio (AI 성공률, ollama uptime%, recall opened/shown, expired batched/shown 등)
- 트레이 콜백 (main 내부 — 별도 IPC 채널 불필요)
- 단위 테스트: emit, rotation, privacy invariant 거부, stats 집계, export zip

**Out:** 자동 업로드 / 원격 telemetry (모두 로컬), 실시간 대시보드 UI, opt-out 토글 (로컬이라 불필요), 14일 보존 기간 사용자 설정

### #4 휴지통 (2번) ✓ 완료

**In:**
- migration v3: `notes.deleted_at TEXT NULL` + `notes.last_recalled_at TEXT NULL` + `notes.recall_dismissed_at TEXT NULL` (3 컬럼 한 번)
- `NoteRepository`: `trash(id)` (`deleted_at = now()`), `restore(id)` (`deleted_at = NULL`), `emptyTrash()` (hard delete + media 정리). 기존 `delete()` 는 deprecate 후 `emptyTrash` 내부에서만 호출.
- **Active 쿼리 일괄 `WHERE deleted_at IS NULL` 추가**: `listNotes`, `countToday`, `findByTag`, search, F5 export, AiWorker `loop()` 진입 시 deleted_at 체크
- 휴지통 UI: Inbox 상단 탭 ("Inbox · 휴지통(N)") — 정밀 위치는 mini-brainstorm
- 휴지통 비우기 confirm dialog ("N개 영구 삭제. 되돌릴 수 없음.")
- F5 export 가 `deleted_at IS NOT NULL` 제외
- F6-L3 import 충돌 정책 추가: source 와 dest 중 `deleted_at IS NOT NULL` 우선 (삭제 보존)
- IPC: `inbox:trash` / `inbox:restore` / `inbox:emptyTrash` / `inbox:listTrash`
- Telemetry emit: `trash` / `restore` / `emptyTrash`
- 단위 테스트: trash/restore/emptyTrash, active query 제외, AiWorker skip, F5 export 제외, F6-L3 import 머지

**Out:** 자동 비우기 정책 (사용자 트리거만), 휴지통 검색, trash 안 노트 편집, 휴지통 UI 정밀 위치 (mini-brainstorm), per-note 영속 보호 플래그

### #5 만료 추천 (3번) ✓ 완료

**In:**
- `NoteRepository.findExpiredCandidates({today})`:
  - `WHERE due_date < today AND deleted_at IS NULL AND ai_status = 'done'`
  - ORDER BY `created_at DESC`
- Inbox 상단 **만료 배너** (펼침 가능):
  - "오늘 기준 만료 N개" 헤더
  - 펼치면 노트 카드 리스트 + 체크박스 멀티선택
  - "선택 휴지통" 버튼 → 일괄 trash + telemetry emit
  - "오늘 그만" → in-memory snooze (자정 KST 리셋)
- IPC: `inbox:listExpired`, `inbox:trashBatch`
- Telemetry emit: `expired_banner_shown` (`{ candidateCount }`), `expired_batch_trash` (`{ count }`)
- 단위 테스트: 후보 query, 멀티선택 batch trash, snooze 동작, deleted_at 제외 확인

**Out:** 시스템 알림 surface, 별 페이지, snooze 영속화, "안 옮김" 가중치 감소, 만료 임박 (D-7) 추천

### #1 Ollama 회복 (4번) ✓ 완료

**In:**
- HealthChecker 주기 polling (기본 60s — mini-brainstorm 에서 주기/backoff 확정):
  - `runOnce()` 가 setInterval 로 자동 발화
  - 회복 시 `onUpdate` fire → 구독 (renderer OllamaBanner) 자동 갱신
  - 실패 N회 후 polling 중단 정책 — mini-brainstorm
- 수동 "재확인" 버튼: `OllamaBanner` + 트레이 컨텍스트 메뉴
- IPC: `inbox:ollamaRecheck`
- Telemetry emit: `ollama_unreachable` (`{ reason }`), `ollama_recovered` (`{ downtimeMs }`), `ollama_recheck_manual` (`{}`)
- 단위 테스트: polling fire, manual recheck, 회복 status 전이 + telemetry emit

**Out:** 사용자 설정 가능 polling 주기, 회복 toast 알림, 모델 정상성 (tags 외) 체크

### #2 AI retry / 수동 trigger (5번) ✓ 완료

**In:**
- `AiWorker.processJob()` 정책 변경:
  - **ollama unreachable** 일 때 `attempts` 증가 안 하고 `next_run_at` 만 backoff (무한 retry while unreachable)
  - schema fail / invalid response / timeout 만 `attempts` 증가 (기존 max 3 유지)
  - reason 분류는 `LocalOllamaProvider` 결과 + zod 결과로 결정
- `markAiFailed` 한 노트 수동 re-enqueue 가능 (hard fail 도 회수 경로)
- 트레이 + Inbox 메뉴 **"지금 AI 처리 (실패 N건)"** → 모든 ai_status='failed' → pending_jobs 재투입
- `FailedBanner` (PendingBanner 형제, 실패 N건 + retry 버튼)
- IPC: `inbox:retryAllFailed`, `inbox:failedCount`
- Telemetry emit: `ai_failed` (#7 의 기본 hook 에 reason 분류 추가), `ai_retry_manual` (`{ failedCount }`)
- 단위 테스트: unreachable infinite retry, retry-all trigger, unreachable vs schema fail 구분, attempts 증가 정책

**Out:** per-note retry 버튼 (NoteCard), failed reason 별 차등 정책, retry progress UI, retry rate-limit

### #3 태그 vocab (6번) ✓ 완료

**In:**
- `NoteRepository.getTopUsedTags(N=20)`:
  - `SELECT t.name, COUNT(*) c FROM tags t JOIN note_tags nt ON nt.tag_id=t.id JOIN notes n ON n.id=nt.note_id WHERE n.deleted_at IS NULL GROUP BY t.id ORDER BY c DESC LIMIT 20`
- `buildPrompt()` 에 vocab 주입 라인:
  - "기존 태그를 우선 재사용. 새 태그는 vocab 에 없는 의미일 때만 만들기:" + kebab-case 리스트
  - vocab 빈 케이스 (신규 사용자) → 라인 자체 생략
- `PROMPT_VERSION` 3 → **4**
- AI 응답 후 vocab hit/miss 분류 → telemetry emit
- Telemetry emit: `tag_vocab_hit` (`{ tagId, vocabSize }`), `tag_vocab_miss` (`{ vocabSize }`)
- 단위 테스트: vocab 합성, 빈 vocab, 길이 cap, prompt version bump, hit/miss 분류

**Out:** 임베딩 유사도 dedup, 사용자 controlled vocabulary 화이트리스트, 자동 normalize ("회의" ↔ "미팅"), top-N 튜닝, vocab cache invalidation 정책

### #6 리마인드 1 spike (7번) ✓ 완료

**In:**
- `strategy.md` §2.3 / §4.3 / §8 갱신: Capitalize 본격 진입, "오늘 회상" surface 정의, F4-A/B/D deferred 항목의 측정 인프라 마련 명시
- Inbox 상단 **`RecallBanner`** — "오늘 회상해볼 노트" 1건 추천:
  - algo: `WHERE (last_recalled_at IS NULL OR last_recalled_at < date('now','-7 day')) AND (recall_dismissed_at IS NULL OR recall_dismissed_at < date('now','-30 day')) AND ai_status='done' AND deleted_at IS NULL AND (due_date IS NULL OR due_date >= today) ORDER BY created_at ASC LIMIT 1`
  - 사용자 액션 3개:
    - "열어보기" → 노트 카드 스크롤 + `last_recalled_at = now()`
    - "다음에" → in-memory snooze 1일 (영속화 X)
    - "더 이상" → `recall_dismissed_at = now()`
- IPC: `inbox:listRecallCandidate`, `inbox:markRecallOpened`, `inbox:dismissRecall`
- Telemetry emit: `recall_shown` (`{ noteId, ageDays }`), `recall_opened`, `recall_dismissed`, `recall_snoozed`
- 단위 테스트: algo selection, dismiss 만료 (30일 후 재추천), last_recalled 갱신, deleted_at 제외, 후보 0건 케이스

**Out:** 잠금해제 hook (F4-A), 무작위 토스트 (F4-D), ambient if-then (F4-B), 임베딩 유사도 추천 (#3 vocab 후속), spaced repetition (Leitner/SM-2), 다중 후보 추천

### 3.1 공통 게이트 (모든 항목)

각 항목 머지 전 필수:

- `npm run typecheck` 통과 (현재 0 에러)
- `npm test` 통과 (현재 205/205, 항목 신규 단위 추가)
- `npm run test:e2e` 통과 (현재 1/1)
- 항목 신규 단위 테스트 ≥ 1개 (TDD)
- main 머지

---

## 4. 항목당 작업 흐름 + Cross-cutting

```
[항목 N 시작]
   │
   ├─ mini-brainstorm  ← decision-pending 답변
   │     - 본 문서 §3 의 "Out" 후보 일부가 In 으로 승격 가능
   │     - per-item spec doc → docs/superpowers/specs/2026-MM-DD-v023-<slug>.md
   │
   ├─ writing-plans   ← TDD 구현 계획
   │
   ├─ 구현 (executing-plans 또는 직접)
   │     - 브랜치: feat/v023-<slug>  (예: feat/v023-trash, feat/v023-recall)
   │     - 게이트 통과 후 main 머지
   │
   └─ 다음 항목 시작
```

### 4.1 Cross-cutting 정책

| 영역 | 정책 |
|------|------|
| **버전 관리** | 7개 모두 머지될 때까지 `package.json` `0.2.2` 유지. v0.2.3 cut 은 7번 후 단일. |
| **CHANGELOG** | 기존 `CHANGELOG.md` 에 `[0.2.3]` section append (v0.2.2 에서 확립한 패턴). v0.2.3 cut 직전 한 번만 수정. |
| **브랜치 전략** | `feat/v023-<slug>` 단명. main 머지 후 삭제. 작은 항목 (#1, #3, #6 strategy 갱신) 은 main 직접 push 도 허용. |
| **테스트 추가 정책** | 항목당 최소 단위 1개. e2e smoke 영향 시 단언 동기화. AiWorker 변경 (#1, #2, #3) 은 integration (Ollama) 영향 시 검토. |
| **Slice invariant 위반 시** | 본 로드맵 결과로 invariant 변경 — slice §1.1 §7 도 PR 안에 동봉 수정. |
| **신규 dependency** | slice §7 strict-pin 그대로. 0 신규 dep 목표 — 위반 시 PR 안에 §7.2 갱신 + 합리화 동봉. |
| **로깅 정책** | slice §1.1 invariant 4 **강화**: telemetry payload 에 raw_text/title/summary/intent/tag name 포함 절대 금지. 위반 시 silent invariant 위반. #7 단위 테스트로 zod parser 가 거부. |
| **Strategy.md 동반 갱신** | #6 항목 (7번) 에서만. 다른 항목은 strategy.md 미수정. |
| **Schema invariant 추가** | `deleted_at IS NOT NULL` 노트는 모든 active 쿼리 (Inbox 리스트 / 카운트 / 검색 / 태그 필터 / AiWorker 처리 / F5 export) 에서 제외. F6-L1 backup 만 예외. 위반 시 dogfood-feedback 재오픈. |

---

## 5. v0.2.3 Cut 단계

7번 항목 머지 후:

```
[v0.2.2 dogfood 환경에서]
1. 트레이 → "지금 백업" 1회 클릭        ← F6-L1 첫 실증
2. 트레이 → "내보내기..." 1회            ← F5 schema-agnostic 백업
3. 트레이 → "사용 로그 내보내기..." 1회  ← #7 의 첫 실증 (없으면 v0.2.2 raw 데이터 손실)
4. Inkling 종료

[빌드 머신에서]
5. package.json version: 0.2.2 → 0.2.3
6. CHANGELOG.md 에 [0.2.3] section append
7. npm run dist
8. dist/Inkling Setup 0.2.3.exe 검증

[dogfood 머신에서]
9. Setup 0.2.3.exe 실행 → 같은 폴더에 설치
10. 첫 실행 → migration v3 자동 적용 (deleted_at + last_recalled_at + recall_dismissed_at)
11. 트레이 메뉴 "사용 로그 내보내기..." 항목 존재 확인
12. ≥ 1주 soak 시작
```

### 5.1 업그레이드 안전망

| 위험 | 완화 |
|------|------|
| migration v3 결함으로 DB 손상 | 2가지 복원 경로 (v0.2.1 부터): (a) `<dbFile>.pre-v3.bak` 자동 snapshot 으로 SQLite 복원 (v0.2.2 인스톨러 재설치 필요), (b) F5 export → v0.2.3 의 F6-L3 import 로 schema-agnostic 복원 (더 빠름) |
| `deleted_at IS NULL` 누락 — 휴지통 노트가 active 쿼리에 새는 회귀 | 단위 테스트로 모든 active 쿼리 확인. 실수 시 dogfood-feedback 즉시 재오픈. |
| Telemetry payload 에 본문 누출 | `TelemetryService.emit` 의 zod parser 가 거부. CI 단위 테스트로 고정. |
| AiWorker unreachable infinite retry 가 큐 폭주 | next_run_at 의 backoff cap (15분) — mini-brainstorm 에서 확정. |
| 자동시작 토글 / 데이터 디렉터리 손실 | v0.2.1 동일 — `HKCU\...\Run` + `<profileDir>` 보존됨 |

---

## 6. 측정

### 6.1 로드맵 측정

| 메트릭 | 임계값 | 측정 방법 |
|--------|--------|----------|
| 항목 평균 PR 사이즈 | < 800 lines diff | git log 통계 |
| 항목 평균 머지 간격 | < 5일 | git log 시간차 |
| 회귀 테스트 추가 | 항목당 ≥ 1개 단위 | `tests/unit` 카운트 |
| v0.2.3 cut 후 1주 데이터 손실 | 0회 | telemetry + 본인 라벨링 보강 |
| typecheck/test 회귀 | 0회 | CI · 로컬 |
| Telemetry 본문 누출 | 0건 | events.jsonl grep + zod parser |

### 6.2 dogfood soak 측정 (#7 의 본격 사용처)

`stats.md` 가 다음을 답해야 함:

| 질문 | 데이터 |
|------|--------|
| AI 가 실제로 동작 중인가? | `ai_succeeded / (ai_succeeded + ai_failed)` ratio 일자별 |
| Ollama unreachable 빈도? | `ollama_unreachable` count + 평균 `downtimeMs` |
| 수동 trigger 가 쓰이고 있나? | `ai_retry_manual` / `ollama_recheck_manual` count |
| 휴지통이 회수 도구로 동작? | `restore / trash` ratio |
| 만료 추천이 nudging 으로 동작? | `expired_batch_trash / expired_banner_shown` ratio |
| 회상 spike 가 의미 있나? | `recall_opened / recall_shown` ratio + `recall_dismissed` count |
| Tag vocab 재사용? | `tag_vocab_hit / (hit + miss)` ratio (목표: 시간 흐름에 따라 상승) |

### 6.3 silent invariant 후보

본 로드맵 결과로 slice §1.3 종료 조건에 추가 권장:

> **"Telemetry 본문 누출 0회"** — events.jsonl 의 어떤 payload 에도 raw_text/title/summary/intent/tag name 미포함. 발생 시 즉시 silent invariant 위반.

> **"`deleted_at IS NULL` 망각 0회"** — active 쿼리 회귀 시 즉시 dogfood-feedback 재오픈.

이 추가는 #7 / #4 항목 머지 시 slice §1.3 동봉 수정.

---

## 7. 본 로드맵의 종료 조건

**모두 만족해야 종결**:

1. #7·#4·#5·#1·#2·#3·#6 7개 항목 모두 main 머지
2. `CHANGELOG.md [0.2.3]` section + `package.json` 0.2.3 + slice §1.3 silent invariant 2개 추가 동봉 갱신 완료
3. v0.2.3 cut → dogfood 머신 재설치 → migration v3 적용 확인 → 첫 실행 정상 + 트레이 메뉴 신규 항목 ("사용 로그 내보내기...") 동작 확인
4. ≥ 1주 dogfood soak 완료 (데이터 손실 0회 + telemetry 본문 누출 0건 확인)
5. `events.jsonl` + `stats.md` export → 분석 → v0.2.4 brainstorm 진입

5 가 끝나면 본 로드맵 종결.

---

## 8. 미결정 항목 (각 항목 mini-brainstorm 에서 답변)

본 로드맵은 순서·In/Out 만 정의. 다음 결정들은 빨리 마주치게 됨:

- **#7**: events.jsonl rotation 주기 (자정 KST 확정), stats.md 집계 ratio 의 정확한 컬럼 list, payload schema 별 zod 파서 합성 정책, write 실패 시 백오프
- **#4**: 휴지통 UI 정밀 위치 (Inbox 탭 vs 트레이 별 윈도우 vs 별 페이지), 휴지통 비우기 confirm 카피, F5 export 의 trash 옵션 (제외 강제 vs 사용자 토글)
- **#5**: 후보 `due_date_edited_by_user` 필터 여부 (수동 입력만 vs AI 자동 추출 포함), 만료 임박 (D-7) 포함 여부, 멀티선택 default 상태 (전체 선택 vs 비선택)
- **#1**: polling 주기 (10/30/60s), 실패 N회 후 polling 중단, exponential backoff 적용
- **#2**: unreachable backoff cap (15분 후보), reason 분류 정밀도 (timeout vs unreachable 구분), per-note retry 승격 여부
- **#3**: top-N 값 (20 후보), vocab cache invalidation 정책 (write-through vs 매 prompt 시 fresh), 빈 vocab 임계값
- **#6**: dismiss 만료 30일 vs 14일 vs 60일, 후보 0건 시 RecallBanner 숨김 vs 빈 상태 카피
- **#5+#6 coexistence**: 둘 다 Inbox 상단 배너 noting. stack 순서 (만료 위 → 회상 아래 가 자연 — 시간 민감도 우선), 동시 N건 시 우선 표시 정책, 빈 상태 시 영역 collapse 여부. #5 → #6 순서 머지라 #6 mini-brainstorm 에서 #5 와 통합 layout 결정.

---

## 9. 변경 이력

| 일자 | 변경 |
|------|------|
| 2026-05-01 | 초안 — v0.2.2 dogfood 7항목 (#7 telemetry 신설 포함) 단일 cut 로드맵, 데이터 안전 우선 (C 채택), schema migration v3 3컬럼 한 묶음 (B 채택), trash↔backup/export B 정책, #6 = 1 spike 흡수 (B 채택). |
