# 디노이즈 규칙 작성 가이드

pi-vcc-ko의 노이즈 필터링은 내장 규칙 세트를 기본값으로 하고, `pi-vcc-ko-config.json`의 `rules`로 사용자가 규칙을 덧붙일 수 있다. 이 문서는 **내 pi 세션을 분석해서 내 환경에 맞는 규칙 파일을 작성하는 방법**을 다룬다.

```
~/.pi/agent/sessions/<프로젝트>/<세션>.jsonl   ← 분석 대상
~/.pi/agent/pi-vcc-ko-config.json              ← 규칙을 쓰는 파일 (이것만 편집)
<패키지 경로>/tools/analyze-sessions.mjs       ← 분석 스크립트
```

설정 파일은 압축이 발생할 때마다 다시 읽힌다. **저장하면 다음 압축부터 바로 적용**되고, pi 재시작은 불필요하다.

## 1. 규칙 그룹 5개

| 그룹 | 적용 대상 | 효과 | 언제 쓰나 |
|------|----------|------|----------|
| `agentNotices` | 사용자 역할 블록 **전체** | 블록 통초 드롭 | 하네스/에이전트가 주입한 공지·프로토콜 안내가 [Session Goal]이나 브리프를 오염시킬 때 |
| `goalExclusions` | 첫 사용자 메시지의 **라인** | 그 라인만 목표 후보에서 제외 | 목표 섹션에 문서 헤딩·붙여넣은 문서 래퍼·메타 지시가 섞일 때 |
| `blockerExclusions` | 마지막 20블록의 **라인** | 장애물 후보에서 제외 | 붙여넣은 데이터·통계·해소 보고가 [Outstanding Context]에 오판될 때 |
| `taskVerbs` | 후속 사용자 메시지 앞부분 | 후속 요청 추적(`[Latest request]`, `[Earlier requests]`)에 사용할 작업 동사 추가 | 도메인 특유의 명령형("배포준비", "머지 요청")이 후속 지시로 추적되지 않을 때 |
| `preferencePatterns` | 사용자 라인 | [User Preferences] 추출 패턴 추가 | 팀 고유 선호 표현("우리 팀은…", "레드펜 통과 후…")을 잡고 싶을 때 |

그룹별 내장 규칙 전체를 끄려면 `disableBuiltinRules: ["그룹명"]`. 규칙 하나만 골라 끄는 건 지원하지 않는다.

## 2. 3단계 워크플로

### 1단계 — 관찰: 내 세션에서 무엇이 잡히고 놓치는가

```bash
# npm으로 설치했다면 패키지 경로는 보통 ~/.pi/agent/npm/node_modules/@ryan_nookpi/pi-extension-vcc-ko
cd "$(npm root --prefix ~/.pi/agent/npm)/@ryan_nookpi/pi-extension-vcc-ko"
node --experimental-transform-types tools/analyze-sessions.mjs --sample 10
```

- `--sample N`: 최근 N개 세션 (기본 10). `--session <파일>`로 특정 세션만. `--config <경로>`로 실험용 설정을 시뮬레이션(원본 보호).
- 스크립트는 **프로덕션과 동일한 설정 파일과 파이프라인**을 쓴다. 여기서 보이는 것이 실제 압축에서 일어나는 일이다.

출력 태그 해석:

| 태그 | 의미 |
|------|------|
| `[목표]` | [Session Goal]에 캡처된 라인 |
| `[제외← /패턴/]` | 규칙에 걸려 제외된 라인 — **어떤 패턴이 걸었는지 소스가 그대로 보임** |
| `[미채택]` | 규칙에 안 걸렸지만 구조적 이유(URL 단독 줄, 길이, 템플릿 신호 등)로 목표가 아닌 라인 |
| `[드롭]` | `agentNotices`에 걸려 블록 통초가 버려진 공지 |
| `[이전 요청]` / `[최신 요청]` / `[스코프]` / `[선호]` / `[장애물]` | 각 섹션에 캡처된 항목. `[스코프]`는 "대신/계획 변경" 같은 명시적 방향 전환만, 일반 후속 지시는 `[최신 요청]` |

### 2단계 — 작성: 관찰 결과를 규칙으로

관찰에서 반복적으로 보이는 오염원을 골라 그룹에 넣는다. 판단 기준:

- **블록 전체가 공지**(작업 지시가 전혀 없음) → `agentNotices`
- **블록 안의 특정 라인만** 쓰레기(헤딩, 래퍼, 메타 지시) → `goalExclusions`
- 장애물 오판 → `blockerExclusions`
- 후속 지시가 `[최신 요청]`으로 안 잡힘 → `taskVerbs`

```jsonc
{
  "rules": {
    // 블록 전체가 공지인 경우 — 사용자 역할 블록의 전체 텍스트(trimmed)에 검사
    "agentNotices": [
      "\\bnot (?:sent|written) by (?:the )?user\\b",          // 예시: 자선언 공지 (일반 문형)
      "\\[우리 하네스 브리핑\\]"                                // 예시: 내 도구의 마커
    ],
    // 라인 제외 — 불릿은 이미 벗겨진 상태의 라인에 검사
    "goalExclusions": [
      "^무시하고 넘어가:",                                      // 예시: 내 워크플로의 버리는 라인
      "^캡처 컨텍스트:"                                         // 예시: 반복되는 문서 헤더
    ],
    // 장애물 오탐 제외 — URL은 이미 벗겨진 상태의 라인에 검사
    "blockerExclusions": [
      "대시보드에서 확인된 과거 이력"                            // 예시: 과거 데이터 인용
    ],
    "taskVerbs": ["배포준비", "머지 요청"],
    "preferencePatterns": ["우리 팀은\\s"]
  },
  "disableBuiltinRules": []
}
```

#### JSON에서 정규식 쓰기 — 가장 흔한 실수

JSON 문자열에서 백슬래시는 반드시 **두 개**로 쓴다. `"\b공지\b"`는 JSON 파싱 시점에 `\b`가 백스페이스 문자가 되어버려서 정규식이 엉뚱하게 동작한다.

```jsonc
"agentNotices": ["\\b자동 생성 공지\\b"]   // ✅ \b → 정규식 단어 경계
"agentNotices": ["\b자동 생성 공지\b"]     // ❌ \b → 백스페이스 문자
```

- 컴파일은 `i` 플래그(대소문자 무시)로 고정. `/…/` 구분자와 플래그는 쓰지 않고 **소스 문자열만** 넣는다.
- 문법이 틀린 패턴은 규칙에서 제외되고 압축 시 토스트 경고가 뜬다. 나머지 규칙은 계속 동작한다.

#### 좋은 패턴과 나쁜 패턴

```
✅ 좋음 — 일반 문형: 자기 선언, 구조 설명, 출력 지시
   "\\bnot (?:sent|written) by (?:the )?user\\b"
   "^Return\\b.{0,40}\\banswer\\b"

❌ 나쁨 — 특정 도구의 고유 문구를 문자열로 박제
   "Subsequent `# Picky turn` messages"
```

도구 고유 문구를 박제하면 그 도구가 업데이트되는 순간 규칙이 죽고, 다른 하네스를 쓰면 다시 추가해야 한다. 문형(자선언, 프로토콜 설명, 출력 지시)을 건다. 빌트인 규칙이 이미 이 원칙으로 작성되어 있으니 `src/core/rules.ts`의 `BUILTIN_*` 목록을 스타일 참고용으로 보라.

### 3단계 — 검증

```bash
# 1) 규칙 반영 전후 비교: 원본 설정을 남기고 실험 파일로 시뮬레이션
node --experimental-transform-types tools/analyze-sessions.mjs --sample 10
# (설정 수정 후)
node --experimental-transform-types tools/analyze-sessions.mjs --sample 10

# 2) 실제 압축: /compact 실행 → 토스트 "pi-vcc-ko: summarized …" 확인
#    요약의 [Session Goal]·[Outstanding Context]가 기대대로 바뀌었는지 눈으로 확인
```

무효 규칙이 있으면 스크립트와 토스트 양쪽에서 알려준다:

```
⚠ 무효 정규식 1건 (건너뜁니다):
   - agentNotices: 정규식 컴파일 실패 — ([잘못된
```

## 3. 그룹별 작성 팁

### `agentNotices` — 블록 통초 드롭 (파괴적)

이 그룹에 걸린 블록은 **완전히 버려진다**. 작업 지시가 한 줄이라도 섞여 있는 블록을 넣으면 그 내용이 유실된다. 원칙:

- 블록이 "공지/안내만"임을 확인한 뒤 넣는다 (분석 스크립트의 `[드롭]` 태그로 확인).
- 라인 단위 걸러내기는 `goalExclusions`의 역할이다. 구분: "블록 전체가 버려져도 되나?" → 예: agentNotices, 아니오: goalExclusions.

### `goalExclusions` — 첫 메시지 라인 정리

- 검사 대상은 불릿(`- `, `1. `)이 벗겨진 라인이다. `"^- 목차:"`가 아니라 `"^목차:"`.
- 스킬 본문(`<skill>…</skill>`)은 내장에서 이미 접어서 `[skill: 이름]` 한 줄로 바꾼다. 스킬 내용을 걸러내는 규칙은 불필요하다.
- 헤딩(`#`), 마크다운 표, 코드 선언문은 내장 규칙이 이미 처리한다. 새로 필요한 건 내 환경에서 반복되는 **문서 래퍼/메타 지시 문형**이다.

### `blockerExclusions` — 장애물 오탐 제거

- 검사 대상 라인에서 URL은 이미 제거된 상태다. `https://.../error-page/` 같은 URL 경로 단어는 규칙 없이도 걸러진다.
- 인용구(`"the pilot failed"`), 백틱 상태값(`` `BLOCKED` ``), "실패 0" 통계도 내장 제외 대상이다. 새로 필요한 건 도메인 데이터의 반복 패턴이다.

### `taskVerbs` / `preferencePatterns` — 감지 보강

- `taskVerbs`는 **후속 사용자 메시지**가 "최종 의도"인지 판단하는 데만 쓰인다. 첫 메시지 목표 추출에는 영향이 없다.
- 완료형("확인했어요")은 내장에서 이미 제외된다(`(?!했)` 가드). 추가하는 동사는 지시형이어야 한다.

## 4. 알아둘 경계

- **감지 패턴은 주입 대상이 아니다.** 장애물 단어(실패/막혔/여전히…), 템플릿 신호, 길이 임계치는 내장 고정이다. 도메인 특유의 장애물 *감지*가 필요하면 `src/core/rules.ts` 코드 수정이 필요하다.
- **구조 로직은 코드에 고정**이다. 제어문 코드 줄 감사(`if`/`return` + 한글 가드), URL/경로 토큰 처리, 문장 시작 판정은 정규식 한 줄로 표현되지 않는 조건부 로직이라 주입 대상에서 뺐다.
- 내장 규칙의 스타일 원칙은 "특정 도구 구문 박제 금지, 일반 문형으로"다. 커스텀 규칙도 같은 원칙을 따르면 도구가 바뀌어도 살아남는다.

## 5. 트러블슈팅

| 증상 | 확인할 것 |
|------|----------|
| 규칙이 전혀 적용 안 됨 | 설정 파일 경로(`~/.pi/agent/pi-vcc-ko-config.json`)와 JSON 문법. 스크립트 머리글의 "설정:" 줄이 어느 파일을 읽었는지 알려준다 |
| 특정 규칙만 안 먹음 | 무효 정규식 경고(토스트/스크립트). JSON 백슬래시 이중화(`\\b`) 여부 |
| 블록 통째로 사라짐 | `agentNotices`의 과잉 매칭. 패턴을 라인 앵커(`^`)나 더 좁은 문형으로 좁히기 |
| 목표에 원치 않는 라인이 남음 | 그 라인이 `[미채택]`인지 `[목표]`인지 확인. `[미채택]`이면 규칙이 아니라 구조적 사유(URL 단독, 길이, 템플릿 신호)다 |
| 내장 동작을 되돌리고 싶음 | `disableBuiltinRules`에 그룹명 추가. 단, 그룹 전체가 꺼지므로 커스텀 규칙으로 필요한 만큼 다시 채워야 한다 |
