# Milestone Closure — 2-retention-billing-monitoring

## Milestone

- ID         : 2-retention-billing-monitoring
- Name       : `01-retention.md` + `02-billing-cycles.md` + `03-monitoring.md`
- PRD        : `.claude/prds/insuniverse-docs-40-runtime-vendor-legal.prd.md` (Delivery Milestones 2행)
- Plan       : `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m2.plan.md`
- Status     : done
- Closed at  : 2026-08-25T10:57:57.163Z
- Closed by  : /mccp:milestone-close (run_id=4ef12564-8968-4a25-b32b-c48ce46b0299)
- HEAD       : `a6fa6681c01dd29ae23eec0d8a7bd19c24e78164`

## Acceptance Condition

사용자가 `/goal` 에 넘긴 조건 원문:

> `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m2.gates.mjs all` 이 13/13 통과하고,
> `docs/05-schedules/01-retention.md` · `02-billing-cycles.md` · `03-monitoring.md` 세 문서만 읽고
> 각 배치의 보존창·정산회차·감시주기와 그 근거 코드 좌표를 답할 수 있으며, PRD Delivery Milestones
> 에 2행 외 in-progress 잔여가 없다. 또는 20 turn 후 중단.

## Goal Loop Result

3항 전건 충족. 1 turn 에 수렴.

### 1) 게이트 13/13 — 통과

`node .claude/plans/insuniverse-docs-40-runtime-vendor-legal-m2.gates.mjs all` 최종 출력:

```
#0 ok M1 all 15/15 · 04-runtime-topology.md 워킹트리 변경 0 · schedules.yaml 키 17종 조인
OK — 4개 파일, 위반 0 (--strict-refs)
#1 ok doc-kit lint --strict-refs 통과 (4개 파일)
#2a ok 펜스 유도 쌍 17개 · M2 소관 14개
#2b ok 배치표 projection == 펜스 유도 (편차 0)
#2c ok 문서별 정책 id 집합 == 유도 집합 (3문서 편차 0)
#3a ok status 맵 14쌍 == 후보 인덱스 승계 맵 (편차 0)
#3b ok placement 맵 14쌍 == config.statuses 유도 배치 (편차 0)
#3c ok 본문 정책 0건 == 자격 0건
#4 ok 대조표 30행 · 코드 원문 일치 18건 · 기준값 재유도 일치 25건 (코드 측 13 · 주석 측 12) · 정규화 불가 5건 (수치 비교 제외) · 임계 없음 행 5건
#5 ok 주석 원문 일치 21건 · 판정 재계산 일치 30건 (임계 없음 5 정규화 불가 0 일치 7 불일치 2 코드 없음 12 주석 없음 4) · 복수 수량 행 0건 정규화 불가 고정 · 표기 다르고 ms 동치 0건 (고정 단위 5종 · 년·개월은 환산 안 함) · 어휘 밖 0건
#6 ok 참조 결박 14건 · M1 프론트매터 실재 14건 · dangling 0건
#6b ok M1 #9c 유도 — 진입 호출 증거 보유 16종 · 미호출 1종 [delete-fc] · M2 담당 문서 1건 문면 결박
#7 ok 부정 어휘 0건 (검사 어휘 14종 · 3문서) · M1 원본 리터럴 14종과 집합 동일 (드리프트 0)
#8 ok 앵커 52건 해석 · 행 초과 0 · 행 내용 대조 52건 · 저장소 부재 0
#9 ok 연혁 24행 (3문서) · 인덱스 해석 24건 · 앵커 경로 접촉 24건
#9b ok 절 머리 산문의 코호트 계수 == 유도값 (01-retention.md 235 · 02-billing-cycles.md 96 · 03-monitoring.md 199) · 인덱스 2587건 중
#10a ok 적용 범위 헤더 == config actors 6 + services 3 (3문서)
#10b ok 강제 지점 · 적용 범위 · 예외·폴백 id 집합 == 정책 집합 (편차 0) · 빈 칸 0 (196칸)
#11 ok --help 성공 · nosuchcheck rc=1 · 서브커맨드 16종 등록 · pairEq 자기검증 6건 통과
#12a ok 동작 행 유도 28행 == 스케줄러 파일 앵커 (14정책 편차 0) · 배제 규칙 3종 [주석 행(`//` · `*` · `/*`) · 프레임워크 3형태(`NestFactory.` · `app.close(` · `app.useLogger(`) · 루프 헤더(`for await (`)]
#12b ok docblock 수량행 11행 → 커버리지 단위 11개
#12c ok 로케이터 21건 심볼 미해석 0 · 스팬 유도 임계 15행 주석 21행 → 커버리지 단위 34개 + 영단위 로케이터 의무 5건 == 대조표 커버 (미충족 0)
#12d 사각: 어느 코드 측면과 어느 주석 측면을 한 행에 묶을지는 저자가 정하고 게이트는 그 짝의 옳음을 판정하지 않는다 (대조표 30행 전건 · 측면 소속은 #12e 가 본다) · 한글 수사 제외 1건 (검사 어휘 10종) · 시점 표기 2건 · 복수 쌍 제외 0건
#12e ok 대조표 측면 34개(영단위 5행 제외) 전건 유도 집합 소속 · 잉여 0건
all ok 13/13 통과
```

`#0` 이 M1 회귀 15/15 와 `04-runtime-topology.md` 워킹트리 불변을 선행 검사하므로, 이 출력은
M1 봉인이 이 창의 끝에서도 성립함을 함께 증명한다.

### 2) 세 문서 단독으로 보존창·정산회차·감시주기 — 답한다

세 문서의 `## 근거 대조표` 만 읽고 3축과 좌표가 나온다.

**보존창** (`01-retention.md` 94~102행)

| 배치 | 창 | 근거 좌표 |
|---|---|---|
| `retention:delete-analysis` | 30일 | `analyze.repository.ts:583` · `client-analyze.repository.ts:573` |
| `retention:delete-fc` | 1년 | `fc.repository.ts:587` |
| `retention:delete-invoice-files` | 30일 | `invoice.repository.ts:603` |
| `retention:delete-treat` | 30일 | `client.repository.ts:604` · `treat.repository.ts:446` |

**정산회차** (`02-billing-cycles.md` 98~106행) — 두 축이 갈리고 문서가 그것을 두 행으로 나눠 적는다.
실행 시점은 매월 1일 자정(`settlement-agency.schedule.ts:9` · `settlement-client.schedule.ts:9`),
대상 기간은 전월(`settlement-agency.schedule.ts:29` · `settlement-client.schedule.ts:22`,
`subtract(1, 'month')`). `billing:disable-subscription` 은 1일(`subscribe.repository.ts:334`).
`billing:expired-money` · `billing:regular-agency-subscription` · `billing:regular-subscription` 은
`임계 없음` — 코드가 조회만 하고 기간을 정하지 않는다(`money.repository.ts:1746` ·
`subscribe.repository.ts:479` · `:527`).

**감시주기** (`03-monitoring.md` 93~104행) — 동작주기와 임계가 별개 축이다.

| 배치 | 동작주기 | 임계 | 판정 |
|---|---|---|---|
| `monitoring:alimtalk-status` | 5분 (`alimtalk-status.schedule.ts:8`) | 없음 (`alimtalk.service.ts:648`) | 임계 없음 |
| `monitoring:analysis-stall` | 10분 (`analysis-stall.schedule.ts:9`) | 1시간 (`order-detail.repository.ts:292`) | 일치 |
| `monitoring:analysis-status` | 5분 (`analysis-status.schedule.ts:10`) | 코드 10분 (`order-detail.repository.ts:265`) · 주석 5분 (`:259`) | **불일치** |
| `monitoring:fax-status` | 1분 (`fax-status.schedule.ts:8`) | 코드 1시간 (`fax.service.ts:1195`) · 주석 3시간 (`fax-status.schedule.ts:12`) | **불일치** |

`analysis-status` 에는 별개 축으로 알림 중복억제 30분이 있다(`treat-alert.service.ts:6`).
불일치 2건은 문서가 숨기지 않고 `판정` 열로 드러내며, 게이트 `#5` 가 그 판정을 재계산해 대조한다 —
어느 방향으로든 저자가 유리한 값을 고르면 떨어진다.

### 3) PRD in-progress 잔여 — 2행뿐

`in-progress` 문자열은 PRD 201행(마일스톤 2) 하나. 196행은 `<!-- Status: pending | in-progress |
complete -->` 어휘 주석이지 표 행이 아니다. 1행은 `complete`, 3~6행은 전건 `pending`.

## 봉인 상태의 유보 — 이 closure 가 열지 않는 것

**계획서의 Codex 리뷰는 봉인됐으나 `converged` 가 아니다.** `mccp-plan-codex` receipt 의
`codex_verdict` 는 `skipped` 이고 `meta.codex_disabled=true` 다. 실제 리뷰는 R1~R3 3라운드가
있었고 전건 흡수했으나 **R4 재봉인은 companion 장애로 못 돌렸다** (계획서 §Codex Adversarial
Review). R4 가 겨냥한 축 — Patterns to Mirror 인용의 실재 · Files to Change 누락 · Task Action
실행 가능성 — 은 리뷰를 못 받았고 backlog 이월 대상이다.

이 closure 는 그 유보를 해소하지 않는다. **닫는 것은 산출물의 게이트 통과이지 계획서 리뷰의
수렴이 아니다.** `MCCP_CODEX_DISABLED=1` 이 전역 설정으로 살아 있는 동안에는 하류 게이트(PR-Codex)도
같은 env 정책으로 skip 된다 — 우회의 근거는 receipt 가 아니라 그 env 다.

## 미검증으로 남는 것

계획서 §Acceptance 가 `(미검증)` 으로 명시한 항목은 이 closure 로도 검증되지 않는다. 숨기지 않고 적는다.

| 항목 | 왜 미검증인가 |
|---|---|
| `bash docs/_meta/verify/verify.sh --check` 완주 | 이 worktree 는 서브모듈 워킹트리가 없어 실행 자체가 불가. 서브모듈이 실재하는 창에서 `run_lint_gate` 가 세 문서를 잡는지 확인이 남는다 |
| 주석과 코드 임계의 짝짓기가 옳은가 | 자연어 판단이다. 게이트 `#12d` 는 대조표 30행 전건이 미판정임을 계수로 찍을 뿐 짝의 옳음을 보지 않는다. 측면 소속만 `#12e` 가 본다 |
| 세 문서 `## 정책 (기획)` 사유 산문이 서로 다른 문장인가 | 리뷰 판정. 게이트에 없다 |
| 연혁 24행의 커밋이 정말 그 규칙을 바꿨는가 | 게이트 `#9` 는 인덱스 해석과 앵커 경로 접촉까지만 본다. 변경의 의미는 유지보수자 판정 |
| 문서가 Q16 · Q31 · Q33 을 문서만으로 답하게 하는지 | 유지보수자 판정. 이 closure 의 §2 는 세 문서 단독 답변 가능성을 3축에 대해서만 실측했다 |
| `docs/_meta/findings/40-runtime-vendor-legal.md` 신설 | M1 과 같은 사유로 이 창에서도 못 닫았다. `golden.txt` `findings.files` 갱신이 필요하고 `docs/_meta/verify/**` 는 40 소유가 아니다. backlog 이월 |
| `#7` 부정 어휘 목록의 사각 | 검사 어휘 14종은 표본이고 범위가 아니다. 목록 밖 표현의 부정은 못 본다. 그 사각은 `#6` 의 긍정 요구가 좁힐 뿐 닫지 않는다 |

## Provenance

- Lock run_id        : `4ef12564-8968-4a25-b32b-c48ce46b0299`
- Lock owner session : `unknown` (CLAUDE_SESSION_ID 미노출)
- Lock lifecycle     : 실측(lock 전) → enter → `/goal` 평가 → exit → 게이트 재확인 → closure
- Plan source        : `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m2.plan.md`
- Detection signal   : `{"row":2,"name":"`01-retention.md` + `02-billing-cycles.md` + `03-monitoring.md`","plan":".claude/plans/insuniverse-docs-40-runtime-vendor-legal-m2.plan.md","status":"in-progress"}`
- mccp version       : 1.32.1
- Gate receipts      : `mccp-plan-codex` · `mccp-implement-codex` (둘 다 `insuniverse-docs-40-runtime-vendor-legal-m2`) · `plan_hash` `sha256:5d9a55554adfb101dd37e21da5408d557763223d280661cba4c056cf073cf655` 양쪽 일치
- 체인 상태          : `validate --command mccp:pr` → `ok:true` · stale 0 · missing 0 · blocking 0 (경고 2건은 `impeccable_silent_skip` — design_signal=false)

**게이트 실측은 lock 진입 전에 했다.** `goal-phase-guard` 가 lock 활성 중 Bash 를 default-deny 로
돌려 하네스를 못 돌린다. 순서를 뒤집으면 closure 가 실측 없이 verdict 만 받는 구조가 된다.

**이 문서의 sha256 stamp 는 계획서 본문이 아니라 PRD 에 실린다.** 계획서 본문은
`mccp-plan-codex` · `mccp-implement-codex` 두 receipt 의 `plan_hash` 앵커이며, 여기에 절을
덧붙이면 두 게이트가 동시에 stale 로 떨어진다. 재앵커는 봉인된 판정을 사후에 옮기는 것이라
쓰지 않는다.
