# Stash Origin Audit Spec

**task**: task-2570  
**status**: active  
**created**: 2026-05-14  
**author**: 카르티케야 (백엔드)  
**related**: task-2569+2 (finish-task _STASH_AUDIT_BEFORE/AFTER 박제 + 5개 초과 WARN)

---

## 1. 목적

누적된 git stash의 출처(origin)를 추적하는 read-only 진단 도구의 설계 표준을 정의한다.

- **무엇을**: 각 stash가 어디서, 왜, 언제 생성되었는지 파악
- **왜**: stash가 60개 이상 누적된 상태에서 각 항목의 맥락을 잃지 않기 위함
- **어떻게**: `git stash list` / `git stash show` 파싱만 수행 (실데이터 변경 없음)
- **절대 금지**: pop / drop / cleanup / push (task-2571 영역)

---

## 2. 메타데이터 표준 필드

각 stash 항목은 다음 필드로 분류된다:

| 필드 | 타입 | 설명 | 예시 |
|------|------|------|------|
| `index` | int | stash@{N}의 N | `0` |
| `task_id` | str \| None | 추정된 task ID | `"task-2569"` |
| `source` | str | 분류 카테고리 (아래 목록) | `"finish-task"` |
| `reason` | str | 자유 텍스트 (stash message에서 추출) | `"GIT-GATE: 다른 task scope dirty 격리"` |
| `caller_script` | str | 생성 스크립트 추정 | `"finish-task.sh"` |
| `timestamp` | str \| None | 생성 시점 추정 (stash@{N} reflog 기준) | `"2026-05-14T10:30:00"` |
| `raw_message` | str | 원본 stash 메시지 전체 | `"On main: [task-2569] ..."` |

---

## 3. Source 분류 카테고리

| source 값 | 설명 |
|-----------|------|
| `finish-task` | finish-task.sh 실행 중 생성된 stash |
| `pre-task` | task 시작 전 사전 격리 stash |
| `quarantine` | 다른 task scope 격리 목적 stash |
| `wip` | 작업 중 임시 보관 (WIP on ...) |
| `other-files` | 관련 없는 파일 임시 격리 |
| `unknown` | 패턴 매칭 실패, 분류 불가 |

---

## 4. Stash Message 표준 포맷 (권장)

신규 stash 생성 시 아래 포맷을 권장한다 (기존 stash 소급 불필요):

```
[task-NNNN][source=XXX][reason=YYY]
```

예시:
```
[task-2570][source=finish-task][reason=GIT-GATE 격리: test_replacement.py 다른 scope]
[task-2568][source=pre-task][reason=pre-task 사전 dirty 격리]
[task-2566][source=quarantine][reason=finish-task 격리 후 quarantine 보관]
```

---

## 5. 분류 패턴 (Regex)

stash 메시지에 대해 순서대로 매칭한다 (첫 번째 매칭이 우선):

```
# 패턴 → source 분류 규칙

1. pre-task[-_].*                     → source=pre-task
   (예: "pre-task-2568+3 stash", "WIP: pre-task-2569 stash")

2. .*-finish-task-quarantine.*        → source=quarantine
   (예: "task-2566-finish-task-quarantine")

3. .*-other-files[-_]stash.*          → source=other-files
   (예: "task-2564-other-files-stash", "task-2553-temp-other-tasks-dirty")

4. .*finish[-_]task.*                 → source=finish-task
   (예: "finish-stash-systems-unrelated", "[task-2569] finish-task GIT-GATE...")

5. ^WIP on .*:                        → source=wip
   (예: "WIP on main: 9a651f37 ...")

6. (매칭 없음)                        → source=unknown
```

### caller_script 추정 규칙

| source | caller_script |
|--------|--------------|
| `finish-task` | `finish-task.sh` |
| `quarantine` | `finish-task.sh` |
| `other-files` | `finish-task.sh` |
| `pre-task` | `pre-task (수동 또는 pre_push_guard.py)` |
| `wip` | `수동 git stash` |
| `unknown` | `unknown` |

### task_id 추출 규칙

```
regex: \[?(task-\d+[\+\d]*)\]?
```

- 매칭: `task-2569`, `task-2569+2`, `task-2568+3`
- 없으면 `None`

---

## 6. 호환성 (기존 stash fallback)

- 기존 stash 메시지는 위 표준 포맷을 따르지 않을 수 있음
- 패턴 매칭으로 최선 분류하되, 매칭 실패 시 `source=unknown`으로 fallback
- **실 데이터 변경 없음** — 메시지 수정, pop, drop, 재작성 일절 금지
- 분류 결과는 진단 목적으로만 사용

---

## 7. Read-Only 원칙

```
허용:  git stash list
허용:  git stash show stash@{N}
허용:  git stash show -p stash@{N}  (diff 조회)

금지:  git stash pop
금지:  git stash drop
금지:  git stash clear
금지:  git stash push  (stash_audit.py 내부에서)
```

stash 정리/복구 작업은 **task-2571** 영역으로 위임한다.

---

## 8. 구현 참조

- 진단 도구: `scripts/stash_audit.py`
- 출력 형식: 표(기본) / JSON(`--json`) / Markdown(`--markdown`)
- 파일 저장: `--out PATH`
- workspace 지정: `--workspace PATH`
- 개수 제한: `--limit N`

---

## 9. 관련 히스토리

| task | 내용 |
|------|------|
| task-2569+2 | finish-task.sh에 _STASH_AUDIT_BEFORE/AFTER 박제 + 5개 초과 WARN |
| task-2570 | stash 출처 추적 spec + stash_audit.py 도구 (본 문서) |
| task-2571 | stash cleanup/복구 작업 (예정, 별도 scope) |
