Skip to content
Back to skills

Stabilize Milestone

ASecurity

Stabilize a milestone — run E2E + regression + refactoring/ADR review. No code changes, no commits.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 29, 2026
ai-agentspythongoshellbashvuerefactoringgitapi

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add kohj1018/agentic-dev-harness --skill stabilize-milestone --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Stabilize Milestone?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Stabilize Milestone
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kohj1018-stabilize-milestone-agentic-dev-harness/badge)](https://www.skillsdirectory.com/skills/kohj1018-stabilize-milestone-agentic-dev-harness)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: stabilize-milestone
description: Stabilize a milestone — run E2E + regression + refactoring/ADR review. No code changes, no commits.
argument-hint: "<milestone-id>"
disable-model-invocation: true
allowed-tools: Read Glob Grep Write Edit Bash Agent
---

본 skill은 evaluator-optimizer pattern의 evaluator orchestration이다 (ADR-068 D8).

이 skill은 **코드 수정·커밋·workitem status 변경을 하지 않는다.**
다음 네 종류의 문서 갱신만 정상 책임이다:
1. `docs/40-validation/QA_FINDINGS.md` 누적 기록 (결함 — 보고자 무관, ADR-070 D7).
2. `docs/40-validation/IMPROVEMENT_GUIDE.md` 누적 기록 (개선 — 보고자 무관 + deterministic preflight 결과).
3. milestone 문서의 `## 8. 회고` 섹션 자동 채움 ([ADR-068](../../../docs/90-decisions/boilerplate/ADR-068-milestone-closure-and-graduation-v3.md) graduation contract — status 변경 X, 본문 단락 갱신만).
   - 회고 본문: **graduation 줄(`YES|PENDING_ACCEPTANCE|NO|BLOCKED (날짜)` — 단계 8 판정 영속, ADR-057#amend-1·ADR-068 D4)** + `open 항목 스냅샷` + **`post-close 수정` 줄(ADR-068 D5)** + 4 항목: 목표 달성도 / scope creep / 비목표 위반 / 핵심 학습 3개 이내.
4. `docs/10-charter/DECISION_REGISTER.md` **append** — 점검에서 드러난 *기획 결정*을 `status: open` + `- 발견: 봉인 후 (M<N>)`으로 등재(ADR-060 D11 writer). 기존 항목의 상태는 바꾸지 않는다. 상세는 아래 `봉인 후 새 결정 등재` 절.
milestone 문서 `## 11. 수용 기록`은 본 skill의 write 대상이 **아니다** — `/accept-milestone`(마일스톤 스코프) 단독 소유다(ADR-066 D1).

그 외 변경은 금지한다 — milestone 문서의 `## 0. Status` / `## 1~7` 섹션 / 다른 workitem 문서 / 코드 일체.
후속 작업이 필요하면 `/repair-milestone <M>`으로 텍스트 제안만 출력한다. **inner-loop 4종(`/implement-workitem`·`/validate-workitem`·`/repair-workitem`·`/finalize-workitem`)의 호출을 권하지 않으며 새 task 자동 추가도 하지 않는다** (ADR-068 D1 / ADR-057#amend-3 결정 6).

**실행 single-origin (ADR-054)**: `validate`/`validate:e2e`/`npm audit` 실행 + QA_FINDINGS/IMPROVEMENT_GUIDE/회고 *쓰기*는 본 skill(origin)이 *한 번만*. **같은 checkout에서 stabilize 2개 동시 실행 금지**(포트·테스트DB·Playwright outputDir·빌드캐시 충돌 + tracked-doc clobber). 다른 모델 2nd opinion은 *읽기 전용* `/validate-milestone <M> --reviewer-tag <tag>` 병렬 → `/repair-milestone`이 종합(실행은 origin 1회).

입력:
- `$ARGUMENTS`에는 milestone ID(예: `M1`)가 들어온다. **`M[0-9]+` 패턴만 허용**(미일치 즉시 종료). 다른 인자·플래그는 없다 — 정의되지 않은 플래그를 받으면 안내 후 종료한다.

수행:
1. milestone 문서를 읽고 포함된 feature/task 목록을 회수한다.

### 1.0. Deterministic pre-flight (LLM 위임 전 cheap mechanical check)

LLM 호출 전 다음을 순서대로 점검 (모두 deterministic, fail-fast X — 보고만):

1. **docs/ 내부 markdown link 유효성** (기본: *내부 / ADR 참조 / 로컬 파일* 만 점검 — 외부 URL 검사는 optional):

   - **기본 (내부 link only — deterministic 보장)**: `markdown-link-check --config <(echo '{"ignorePatterns":[{"pattern":"^https?://"}]}') docs/**/*.md` (외부 URL 무시).
     - OS 별 glob 처리:
       - Unix/macOS bash: `markdown-link-check docs/**/*.md` (bash glob 자동 확장).
       - Windows PowerShell (glob 미확장 안전 패턴): `Get-ChildItem docs -Recurse -Filter *.md | ForEach-Object { markdown-link-check $_.FullName }`.
       - OS 무관 fallback: repo 의 `scripts/verify.{sh,ps1,mjs}` 에 한 줄 helper 박거나 `npx markdown-link-check` 를 *각 파일 인자로 직접 호출* — `glob` npm 패키지 의존 회피.
   - **optional (외부 URL 검사 — 네트워크 의존 / flaky)**: 위 명령에서 `ignorePatterns` 제거. 단 *deterministic preflight 의 기본 단계가 아님* — `--with-external-links` 플래그로 사용자 명시 발화 시만.
   - 깨진 link 발견 시 IMPROVEMENT_GUIDE.md 에 `P1 [Doc-link] <file:line> — <broken link>` 라벨 기록.
   - `markdown-link-check` 미설치 환경은 본 항목만 skip + 출력에 명시 (`Doc-link check skipped: markdown-link-check not installed`).
2. **ADR 참조 유효성 (ADR-045#d1·#d8)**:
   - `ADR-NNN` 참조 → 실제 파일 존재 매칭. 예외(오류 아님): (a) `<!-- -->` 주석 안 참조, (b) **allowlist된 ADR-100/101**의 bootstrap 전 미존재, (c) Reserved/Parked/Dropped 표 등재 번호. boilerplate(001~099) 미존재 → `P1 [ADR-ref]`. **그 외 project ADR(102+) 미존재 → `P2 [ADR-ref-project]`** (무시 X).
   - **앵커 존재 (ADR-045#d2)**: `ADR-NNN#amend-M` → 대상 ADR에 `## Amendment M`(또는 `<a id="adr-NNN-amend-M">`) 존재. 누락 시 `P1 [Ref-anchor] <file:line>`. (`#dK`는 token-only — 대상 ADR에 "K." 결정 항목 존재는 *best-effort*, 미존재 의심만 `P2`.)
   - **내부 anchor 링크 (ADR-045#d9)**: `[label](file.md#anchor)`의 anchor가 대상 파일에 `<a id>` 또는 대응 heading으로 실재. 누락 시 `P1 [Link-anchor] <file:line>`.
   - **Surfaces forward check (ADR-045#d3·#d4)**: `## Surfaces` 블록을 가진 각 ADR에 대해 — 등재 파일이 모두 존재하고 본문에 `ADR-NNN` 역참조를 갖는가. 누락 시 `P1 [Surface-backref] ADR-NNN → <file>`. 대상 ADR의 `## Status` **본문이 `superseded` 또는 `deprecated`로 시작할 때만** forward-check에서 skip한다(**아래 «죽은 ADR 인용»과 동일 기준** — `accepted (부분 superseded — ...)`는 살아 있으므로 skip하지 않는다. 느슨하게 «문자열 포함»으로 읽으면 부분 supersede된 **살아있는** ADR의 Surfaces drift가 조용히 검출되지 않는다). live sync 소스만 점검 — 죽은 ADR의 잔존 Surfaces는 별도 [Ref-dead]가 담당. **이 forward 방향만 Phase 4 범위** (역방향은 휴리스틱이라 Phase 5 검토).
   - **죽은 ADR 인용**: 인용된 ADR의 `## Status` **본문이 `superseded` 또는 `deprecated`로 시작할 때만** `P2 [Ref-dead] <file:line>`. **`accepted (부분 superseded — ...)`로 시작하는 ADR은 살아 있다** — 문자열 `superseded`가 괄호 안에 있다고 죽은 것으로 세지 않는다(이 구분을 빼면 부분 supersede된 ADR 하나가 100건 단위의 오탐을 만든다). **예외(오탐 아님, ADR-045#amend-2 D10)**: (a) 같은 줄에 `(현재 SSOT:`이 병기된 인용(역사 서술 + 현행 포인터를 함께 둔 정본형 — D10의 검사 제외 마커), (b) 그 ADR 자신을 가리키는 인용만 있는 줄(`## Status`·`## Amendment` 등), (c) `README.md` 인덱스 표 행의 supersede 계보 칸, (d) `<!-- -->` 주석 안. 예외에 해당하면 기록하지 않는다.
   - **인덱스 amend 동기**: `boilerplate/README.md` Amendments 컬럼 amend 수 ↔ 코드펜스(```)·`<!-- -->` 주석 *밖의* 본문 `## Amendment N` 수 일치(예시·주석 헤딩 제외; 불일치 `P1 [ADR-index]`). (review-doc과 중복 가능.)
3. **FAC ↔ AC unmapped 검출** ([ADR-037](../../../docs/90-decisions/boilerplate/ADR-037-spec-coverage-audit.md)#amend-1 영속 SSOT `## 7-1` 정합):
   - 본 마일스톤의 모든 feature 문서 `## 7-1. FAC ↔ AC 매핑표`에서 *unmapped* 또는 *비어 있음* 항목 회수. **우변이 `승인 스냅샷 <경로> (manifest: …)` 형식인 행은 unmapped 가 아니다**(ADR-037#amend-4 — 승인 표면이 검증자다). 우변이 비었거나 `(해당 task 없음)` 처럼 **검증자를 지목하지 않은** 행만 센다. `## 7-3` PX↔AC 도 같다(결정 1-b).
   - 발견 시 **QA_FINDINGS.md 본 마일스톤 `### P0`**에 `P0 [Spec-gap] F-NNN:FAC-N → unmapped`(`- 출처: preflight`)로 등재한다(ADR-073#amend-2 결정 4 / ADR-070 D7 — 계약 결함은 QA 원장, 그래야 졸업 item 5가 센다) + graduation NO 유지 + 사용자 보고. 구현 후에는 plan-workitem으로 task를 자동 추가하지 않으며, 담당 task가 있으면 repair, 없으면 ADR-057#amend-3 결정 6의 사용자 명시 결정 경로를 따른다.
3-1. **pattern-scan 범위 밖 잔존 회수 (deterministic)**: 본 마일스톤 산하 task 문서 `## 8`에서 **HTML 주석 밖의** `- pattern-scan` 줄을 회수해 `범위 밖 M건`이 1 이상인 항목을 모은다. 발견 시 IMPROVEMENT_GUIDE에 아래 스키마로 기록(WORKFLOW 4-A 면제 기록을 stabilize가 회수하는 것과 동형).
     - **폐쇄 후 라운드의 pattern-scan은 task `## 8`이 아니라 `IMPROVEMENT_GUIDE.md` `## 5`의 항목 하위 줄에 있다**(ADR-066#amend-1). 본 항목은 그 두 위치를 모두 읽는다 — task `## 8`은 폐쇄 전 `/repair-workitem` 라운드분, `## 5`는 폐쇄 후 마일스톤 층 라운드분이다.
     - **ID는 안정적으로 만든다** — `<task-id>-pspread-<패턴 슬러그>` (예: `T-004-pspread-null-guard`). 항목 형식: `- **<ID>** | P1 | [관측됨] | linked: <task-id> | status: open` + 하위 줄 `- [Pattern-spread] <패턴> — 범위 밖 M건 미수정: <경로>`.
     - **재등재 금지(dedup)**: 그 ID가 IMPROVEMENT_GUIDE에 이미 있으면(status가 `open`이든 `resolved`든) **다시 등재하지 않는다.** `- pattern-scan` 줄은 task 문서에 영속되므로 이 규칙이 없으면 매 마일스톤 같은 P1이 재생산된다.
     - **예외 — 같은 패턴의 새 출현**: 기존 ID가 `resolved`인데 그 task `## 8`에 **경로 목록이 다른** `- pattern-scan` 줄이 새로 append됐으면(두 번째 repair 라운드가 더 찾은 경우) `-2`·`-3` suffix를 붙인 새 ID로 등재한다. 판별 기준은 *경로 목록의 차이*이며, 같으면 재등재하지 않는다.
     - 후속은 `/repair-milestone`(cross-cutting) 또는 다음 마일스톤 후보로 라우팅한다. 잔존이 0건이거나 전부 기존 ID면 침묵한다.
3-2. **잠정 해석 회수 (deterministic — ADR-076 D5)**: 본 마일스톤 산하 task 문서 `## 8`(HTML 주석 밖)에서 `해석 잠정:` 줄 중 같은 AC의 `해석 확정:` 줄이 없는 것을 모아 `IMPROVEMENT_GUIDE.md` `## 2. 열린 항목`의 `### M<N>` 그룹에 기록한다. 사용자 authority 항목이라 6-S 채택 전 검토를 거치지 않고 판정값을 바로 적는다.
   - ID는 그 줄의 `확인: IMPROVEMENT_GUIDE <ID>`에 적힌 값을 그대로 쓴다(없으면 `<task-id>-prov-ac-<N>`). 형식: `- **<ID>** | P1 | [관측됨] | linked: <task-id> | status: open | decision: needs-confirmation` + 하위 줄 `- [Provisional-AC] AC-N = <선택> — 대안: <대안>` · `- 대상: AC-N 해석 / 확인 방법: 사용자 확인 (/repair-milestone) / 막힌 이유: 사용자 authority` · `- 출처: run-milestone`.
   - **재등재 금지**: 같은 ID가 IMPROVEMENT_GUIDE나 `docs/40-validation/archive/M<N>.md`에 이미 있으면(status 무관) 다시 쓰지 않는다.
   - **졸업을 막지 않는다** — IMPROVEMENT_GUIDE P1이라 graduation 판정 입력이 아니다. 대신 아래 «다음 단계»가 확인을 권한다.
   - 회수할 것이 없으면 침묵한다.
4. **모드 라벨 ↔ 본문 정합 휴리스틱** (ADR-012): 모든 `docs/00-meta/` 파일의 `> 모드: ...` 라벨이 본문과 명백히 어긋나는지 점검 (휴리스틱 한계 명시).
   - mismatch 시 P2 `[Doc-mode] <file>` 기록.

5. **DESIGN.md + ARCH 7-x cross-surface drift 검출** (ADR-073 D8) — *(5-2) 는 정규식 기반 deterministic, (5-3)(5-4) 는 mechanical/best-effort heuristic — 휴리스틱 한계는 항목별 echo*:

   5-0. **변경 파일 회수 — git diff 의존 금지**: stabilize-milestone 은 정상 lifecycle 에서 `/finalize-workitem` 으로 *이미 커밋된* 후 호출되므로 working tree `git diff` 는 비어 있다. 본 마일스톤 task 의 변경 파일 회수 우선순위:
   - **(a) 1차 — task 문서**: 본 마일스톤 산하 모든 task (`docs/30-workitems/tasks/T-*.md`) 의 `## 4-1. 변경 예정 파일/경로` 본문 회수. (TASK_TEMPLATE 정합 — finalize 시 `--apply` 또는 명시 update 로 채워짐)
   - **(b) 2차 — commit log fallback**: `## 4-1` 비어 있거나 git 실제 변경과 어긋난 task 는 `git log --grep "Refs: T-NNN" --name-only` 로 commit 로그의 변경 파일 회수 (ADR-008#amend-2 Refs footer 정합).
   - **(c) 3차 — validation report fallback**: 위 둘 다 비어 있는 task 는 `docs/40-validation/reports/<task-id>.md` 의 diff trace audit 단락 회수.
   - **(d) 4차 — 폐쇄 후 수리 기록**: `IMPROVEMENT_GUIDE.md ## 5`의 본 마일스톤 항목 `files:` 목록(ADR-073#amend-2 결정 3 — 마일스톤 층 수리가 바꾼 파일은 여기에만 있다).
   - **(e) 모두 실패 시**: 본 task 는 *조사 불가* 로 표시 + IMPROVEMENT_GUIDE 에 `P2 [Stabilize-recovery] T-NNN — 변경 파일 회수 불가` 기록 후 다음 task 로 계속.
   - **(f) 회수 결과 echo (ADR-073#amend-2 결정 3)**: `회수 파일 N개 ((a) x · (b) y · (c) z · (d) w)`. N = 0이면 5-2·5-2b·5-3을 실행하지 않고 `P2 [Stabilize-scope-empty] 회수 파일 0건 — 5-x 미실행`을 기록한다. 5-2·5-2b·5-3 출력은 `대상 K파일 / 위반 M건`으로 둘을 함께 적는다.

   5-1. **UI 프로젝트 판정** — **ADR-073 D9 "UI 판정 다중신호 절차"** 적용(부재→비-UI: 5-1~5-3 skip+사유 echo / status≠draft→UI: 5-1~5-3 활성 / status=draft+추가신호≥1→UI 의심: IMPROVEMENT_GUIDE에 `P1 [Design-draft] DESIGN.md status=draft + UI 신호 감지 — /bootstrap-design 권장` 기록 + 5-1~5-3 활성 / 신호 0→silent skip).

   5-2. **UI 프로젝트 — raw color grep** (정규식 deterministic, **기록 등급 — 진행 차단 안 함**): 5-0 에서 회수한 변경 파일 중 아래 두 갈래로 검사한다.
   - **웹 계열** — 확장자 `.tsx`/`.jsx`/`.ts`/`.js`/`.vue`/`.svelte`/`.astro`/`.css`/`.scss`/`.html`. **단축 hex 는 스타일시트에서만 잡는다**(ADR-072#amend-1 결정 3 — design gate 어댑터와 같은 규칙):
     - `.css`/`.scss`/`.sass`/`.less`: `#([0-9A-Fa-f]{8}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{3})\b`(3~8자리 전부)
     - 그 밖의 코드 파일(`.tsx`·`.ts`·`.vue`·`.svelte`·`.astro`·`.html` 등): `#([0-9A-Fa-f]{8}|[0-9A-Fa-f]{6})\b`(**6·8자리만**)
     `\b`로 더 긴 hex 런의 부분매치를 막는다. 일치 시 `P1 [Design-rawhex] <file:line> — DESIGN.md ## 2 token 으로 교체 권장`.
     **왜 갈랐는가**: 3~5자리 단축 hex 는 `#412` 같은 이슈·번호 표기와 구별되지 않아 카피 문자열·테스트 fixture 를 통째로 오탐한다(dogfood Round 11 실측 5/5 오탐 — 전부 「PR #412」). 대가는 «코드에 직접 쓴 `#abc` 단축 색을 놓친다»이며, 토큰 규율상 코드에 색 리터럴 자체를 두지 않으므로 수용한다.
   - **Dart 계열** — 확장자 `.dart`: ① `Color\(0x[0-9A-Fa-f]{6,8}\)` 및 `Color\.from(ARGB|RGBO)\(` → `P1 [Design-rawhex] <file:line>` ② `\b(Colors|CupertinoColors)\.(?!transparent\b)[a-zA-Z]+` (프레임워크 기본 팔레트 사용 — 값을 박은 것은 아니나 프로젝트 토큰을 우회함). **`Colors.transparent` 는 제외한다** — 그것은 색이 아니라 «색을 칠하지 않는다»는 뜻이고 어느 디자인 시스템에서도 토큰화 대상이 아니다(dogfood Round 11 실측 2건 오탐 — 발견 60). 한 낱말 예외라 미탐 위험이 거의 없고, 매번 브리프 `## 14` 에 사유 주석을 쓰게 만드는 비용을 없앤다 → `P1 [Design-token-grep] <file:line> — 테마에서 가져오도록 교체 권장`. 두 라벨은 원인과 수정 방법이 달라 분리한다. **`[Design-token]`(접미 없음)은 reviewer 의 LLM 판정 차원이 이미 쓰는 라벨이므로 grep 결정분에는 `-grep` 접미를 붙인다** — `[Design-voice-grep]`/`[Design-voice]` 분리와 같은 규칙이며, 회귀 신호 집계가 라벨 정확 일치로 동작하므로 겹치면 오집계된다.
   - **Dart 정의 라인 예외**: `static +const +(Color +)?[A-Za-z_][A-Za-z0-9_]* *= *Color\(` 형태의 줄은 토큰 *정의*이므로 제외한다(웹의 CSS custom property 정의 라인 예외와 동형). **타입 표기는 선택이다** — `static const paper50 = Color(0xFF…)` 처럼 중복 타입을 생략하는 것이 Dart 관례이고 `dart format`·lint 가 그쪽을 민다. 예전 패턴(`static +const +Color +…`)은 **타입을 적은 줄만** 잡아 토큰 정의 파일 전건을 오탐했다(dogfood Round 12 실측 — 발견 77).
   - **`_theme` 매니페스트 예외 (발견 77)**: `docs/20-system/prototypes/_theme/manifest.json` 의 `source[]` 에 등록된 파일은 **토큰 정의·표시 표면**이므로 본 검사 대상이 아니다. R6-1 이 만드는 쇼케이스(`theme_gallery.dart`·`Theme.stories.tsx`)는 **토큰 값을 라벨로 보여 주는 것이 존재 이유**라 hex 문자열이 정상이고, 매 라운드 같은 오탐을 낸다. **파일명 휴리스틱이 아니라 매니페스트를 근거로 삼는다** — 「파일명으로 파일 전체를 빼지 않는다」는 원칙과 충돌하지 않고, 제품 코드의 사용처 위반은 그대로 잡힌다(그 파일들은 `source[]` 에 없다).
   - **자가 검사 fixture 예외 (발견 77 ③)**: design gate 자가 검사 fixture 는 **색을 의도적으로 박아 둔 입력**이다(known-bad 의 2:1 대비 쌍이 그 파일의 존재 이유다). Dart 는 `@Tags(['design-gate'])` 가 붙은 파일, 웹은 게이트 어댑터 안의 인라인 HTML 이므로 `apps/**` 밖이다. **태그를 근거로 삼는다** — 그 태그는 이미 `--exclude-tags=design-gate` 로 통합 validate 에서 그 파일들을 빼는 데 쓰이고 있어 새 표식을 만들지 않는다.
   - **한계(사실 기록)**: 본 검사는 문자열 검색이라 문법을 이해하지 못한다. **주석 안·문자열 리터럴 안의 색값도 함께 잡는다**(실측 확인). 그래서 본 항목은 기록 등급이며 진행을 차단하지 않는다. 문법을 이해하는 검사가 필요하면 Dart 의 공식 analyzer plugin 방식과 별도 패키지인 `custom_lint` 중 하나를 고른다(둘은 같은 것이 아니다 — ADR-059 D6).

   > 웹 계열의 **제외 (ADR-072 — 정의/사용처 라인 구분)**: (a) DESIGN.md 자체 파일, (b) **CSS custom property *정의* 라인**(`--<name>: #hex` 형태 — 토큰 정의는 정상; dogfood `src/index.css :root` 오탐 해소). **파일명(`theme`/`tokens` 등)으로 파일 전체를 빼지 않는다**(사용처 위반 은폐 방지 — 정의/사용처는 (b) 라인 형태로만 구분). 검사 대상은 정의 밖 *사용처*(`color:#hex`·`background:#hex` 등) raw hex — 전면 `:root` 제외 금지.

   5-2b. **UI 프로젝트 — voice grep** (정규식 deterministic — ADR-073 D6): 5-0 회수 변경 파일 중 **UI surface 파일 집합**(ADR-073#amend-2 결정 1)의 파일에서, 각 줄의 **렌더되는 텍스트 구간** — 따옴표 안 문자열(`"…"`·`'…'`·`` `…` ``) **과 JSX·HTML 텍스트 노드**(`>`와 다음 `<` 사이) — 에만 (a) placeholder 카피 패턴(`lorem ipsum`/`TODO copy`/`sample text`/`여기에 텍스트`), (b) DESIGN.md `## 10` "금지 표현"의 `[grep 가능]` 정규식을 적용한다(ADR-073#amend-2 결정 2 — 식별자·키 이름은 대상이 아니다). 일치 시 `P1 [Design-voice-grep] <file:line> — DESIGN.md ## 10 위반`(기록 등급 — 차단 아님) 기록. DESIGN.md `## 10` 부재 시 (a)만 수행. **DESIGN.md 자체는 grep 대상 제외** (규칙 정의 영역 — 5-2와 동형). 출력은 `대상 K파일 / 위반 M건`.

   5-3. **UI 프로젝트 — 컴포넌트 인벤토리 drift** (best-effort heuristic): `src/components/`, `app/components/`, `components/`, `lib/widgets/`, `lib/**/widgets/` 중 존재하는 디렉터리의 컴포넌트 파일명 (예: `Button.tsx`, `Card.tsx`, `primary_button.dart`) 목록 ↔ DESIGN.md `## 7. Components` 본문에 명시된 컴포넌트 이름 비교. 코드에는 있지만 DESIGN.md 에 없는 컴포넌트 발견 시 `P1 [Design-inventory-drift] <component> — DESIGN.md ## 7 등록 권장` 기록. 반대 (DESIGN.md 에 있는데 코드에 없음) 는 unimplemented planned component → `P2 [Design-inventory-pending] <component>` 기록. **휴리스틱 한계 echo 권장** (`인벤토리 drift 검출은 free-form 문서 키워드 매칭 — false positive/negative 가능`).

   5-4. **7-x Don'ts 위반 grep** (best-effort heuristic): ARCH 의 `## 7-1` / `## 7-2` / `## 7-5` 의 `### Don'ts` 본문에서 *명시적 금지 키워드* 를 추출 → 5-0 회수 변경 파일에서 해당 키워드 grep. 위반 의심 발견 시 `P1 [Arch-iface-violation] <file:line> — ARCH ## 7-N Don'ts 위반 의심: <키워드>` 기록 — **free-form 키워드 적중은 확정 위반이 아니라 *확인 후보*이므로 P1 로 적고 `/repair-milestone` 의 4-판정에서 확인한다**(확정 위반과 같은 라벨을 쓰면 라벨을 읽는 쪽이 차단력을 오인한다 — 실측). **휴리스틱 한계 echo 강제** (`Don'ts 키워드 추출은 free-form 텍스트 기반 — false negative 多. 본 grep 미작동 시 reviewer 의 design surface 위임이 보조 catch`).

   > **7-3 백엔드 / 7-4 프론트 의 milestone-level deterministic gap 명시**: 현 ARCH TEMPLATE 의 `## 7-3` / `## 7-4` 는 `### Don'ts` 자리가 없어 본 5-4 grep 이 *skip* 한다(`## 7-5`는 `### Don'ts`를 가지므로 대상이다). 단 이것이 *전면 gap 은 아니다* — 7-3/7-4 결정과의 정합은 **per-task validate-workitem (validator.md 의 인터페이스 CHECK 규칙 — UI/API/CLI/7-x) 의 CHECK 단계가 task 단위로 점검**한다 (DB migration / 인증 / 트랜잭션 / 라우팅 / 상태관리 등). 즉 *milestone-level deterministic preflight* 에서만 빠지고, *task-level validation* 에서는 잡힌다. milestone 누적 drift 가 우려되면 stabilize 의 reviewer `code` surface (Step 5) 가 아키텍처 부채로 추가 catch. 향후 7-3/7-4 에 `### Don'ts` 자리를 TEMPLATE 에 추가하면 본 grep 도 확장 가능 (별도 ADR-073 amend 후보).

   5-5. **해당 스택 부재 시 본 항목 skip** + skip 사유 echo: `[Design/Arch-iface] check skipped: <reason>`. 예: `[Design] check skipped: docs/20-system/DESIGN.md 부재 (비-UI 프로젝트)`.

6. **고-stakes 설계 근거 누락 (ADR-053 backstop, best-effort)**: ARCHITECTURE_OVERVIEW `## 7`의 *실제 작성된*(HTML 주석 placeholder 제외) 결정 블록에서 필수 칸(옵션≥2/신뢰도/재검토)이 비면 `P2 [Design-rationale] <위치>` 기록. **한계**: 고-stakes 결정을 한 줄 산문으로 쓴 경우는 못 잡음(휴리스틱).

7. **Skill 로스터 fan-out 정합 (cross-doc, deterministic — ADR-010#amend-3 README SSOT + STRUCTURE 로스터 정합 집행)**:
   - `.claude/skills/*/` 디렉터리명 집합 ↔ `docs/00-meta/STRUCTURE.md`의 `Claude skill 본문` 행 괄호 목록이 일치하는가. 불일치 시 `P1 [Roster-drift] <skill> — STRUCTURE 로스터`.
   - `README.md`/`README_ko.md`의 *자연어 호출 skill 목록 두 곳*(정책 요약 문단의 "Remaining skills/나머지 skill" + "For remaining skills/나머지 skill(...)" 명시 목록)이 서로 일치하고, `(.claude/skills 집합) − (.agents/skills wrapper 집합)`과 같은가. 불일치 시 `P1 [Roster-drift] <skill> — README 자연어 목록(<어느 위치>)`.
   - **cross-LLM 리뷰 skill 등재 (D3 재발 지점, deterministic)**: `validate-plan`·`validate-discovery`·`validate-milestone` 각각이 `docs/00-meta/DELEGATION_STRATEGY.md` 위임 표에 등장하는가(skill 이름 grep). 미등재 시 `P2 [Roster-drift] <skill> — DELEGATION 위임 표`.
   - **cross-LLM 리뷰 skill wrapper 존재 (ADR-010#amend-4, deterministic)**: `validate-plan`·`validate-discovery`·`validate-milestone`과 각 repair 짝(`repair-plan`·`repair-discovery`·`repair-milestone`)에 `.agents/skills/<name>/SKILL.md`가 존재하는가. 부재 시 `P1 [Roster-drift] <skill> — Codex wrapper 부재 (ADR-010#amend-4)`.
   - 발견은 IMPROVEMENT_GUIDE에 기록(보고만 — 차단 X). **한계**: WORKFLOW 산문 흐름 등재는 본 grep 범위 밖(reviewer 위임이 보조 catch).

8. **검증 장치 노후 감지 `[Guard-drift]` (deterministic — ADR-063 D4)**: **침묵 우선 — 아래 (a)~(e) 가 전부 정상이면 출력에 한 줄도 남기지 않는다** (skip 사유 echo 도 하지 않는다. 정상 상태를 매번 보고하면 그것이 노이즈이고, 검증 장치가 매 마일스톤 변경되는 것은 정상이 아니다). **단 아래 "선행: 파일 부재 처리" 는 예외다** — 점검을 아예 수행하지 못했다는 사실은 침묵하면 안 된다.
   - **선행: 파일 부재 처리** — `docs/00-meta/STACK_SETUP_PLAN.md` 는 baseline 이 아니라 `/bootstrap-stack` 생성물이다. 부재 시 본 항목 전체를 skip 하고 `Guard-drift check skipped: STACK_SETUP_PLAN.md 부재` 1줄만 남긴다(§1.0 의 `markdown-link-check` 미설치·원장 부재 선례와 동형).
   - (a) **registry 경로 실재** — **대상 절·검사할 열·조건을 아래로 고정한다**(deterministic 이려면 같은 입력에 같은 판정이 나야 한다. 절마다 스키마가 다르므로 "registry 행"만으로는 무엇을 볼지 정해지지 않는다). 부재 시 `P2 [Guard-drift] <절>:<경로> 부재 — /stack-guard 재실행 권장`.

     | 대상 절 | 검사할 열 | 조건 |
     |---|---|---|
     | `## E2E Smoke Registry` | `smoke 파일 경로` | 그 **행**의 `status` 가 `n/a` 가 아닐 때 |
     | `## Design Gate Adapter` | `adapter path` **만** | **절**의 `status` 가 `ready` 일 때 |
     | `## Dart Source Roots` | `경로` (pubspec 위치 기준 상대경로) | 그 절이 존재할 때 (비-Dart 스택은 `/bootstrap-stack` 이 절을 삭제하므로 대상 0) |

     - **`output path` 는 검사하지 않는다** — `design-gate-shots/` 는 `.gitignore` 대상이고 adapter 가 매 실행 통째로 생성·초기화하는 ephemeral 산출물이라 **fresh clone·정리 직후 부재가 정상**이다. 검사하면 매 마일스톤 오탐이 나 침묵 우선 원칙과 충돌한다.
     - `## Dependency Tools` 는 경로 열이 없어 대상이 아니다. `status: n/a`·미대상 행도 대상이 아니다 — e2e 비대상·비-UI 프로젝트에서 경로가 없는 것은 정상이다.
     - 템플릿 예시 행(`(예: …)`)이 남아 있으면 그 경로는 실재하지 않으므로 그대로 `P2` 가 되며 처방(`/stack-guard` 재실행)이 정확하다 — 별도 예외를 두지 않는다.
   - (b) **design gate copied-from 4방향 판정 (ADR-063#amend-1)** — `status: ready`인 경우에만 세 값을 읽는다: canonical sha C(`.claude/skills/stack-guard/assets/design-gate.mjs`), registry `copied-from` R, 사본 sha P(`adapter path`). (i) P = R, C ≠ R → `P2 [Guard-drift] canonical 갱신됨 — /stack-guard 재실행 권장(무수정 사본이라 교체된다)` (ii) P ≠ R, C = R → `P2 [Guard-drift] 사본 로컬 수정됨 — 재실행해도 덮어쓰지 않음(diff 보고). 수정분을 canonical로 역류할지 검토: IMPROVEMENT_GUIDE [ADR-candidate]` (iii) P = C ≠ R → `P2 [Guard-drift] registry만 낡음(코드 동일) — copied-from 갱신 권장(/stack-guard 재실행이 갱신)` (iv) P ≠ R, C ≠ R, P ≠ C → 둘 다 + `사용자 결정 필요`. 전부 읽기 전용 — mtime·날짜 비교 없음; sha256 도구 부재 시 skip + 사유 echo.
   - (c) **등록 밖 소스 디렉터리** — **소스 루트 registry 를 갖는 스택에서만 수행한다.** 현재 그 registry 를 갖는 것은 `## Dart Source Roots`(Dart/Flutter)뿐이며, **비-Dart 스택에서는 `/bootstrap-stack` 이 그 절을 삭제하므로 판정 기준이 없다 → 이 항목을 건너뛴다**(사유 echo 불요 — 침묵). 기준 없이 "등록 밖"을 판정하면 TS/Python/Go 의 `src/`·`tests/` 가 매 마일스톤 오탐으로 찍혀 침묵 우선 원칙과 정면 충돌한다. Dart 스택에서 발견 시 `P2 [Guard-drift] 등록 밖 Dart source root: <경로> — /stack-guard 재실행 권장`.
   - (d) **probe 판정 기록** — `## 통합 명령 사용법` 의 `probe smoke:` 값으로 판정한다.
     - **정상(무출력)**: `PASS (probe verified, …)` 2종 · **`PROBE OK, PROJECT FAIL`**. 후자는 probe 전 회차가 기대대로였고 **프로젝트 코드만** 실패한 상태이므로 검증 장치의 노후가 아니다 — 재실행해도 같은 결과이니 처방이 무의미하고, 그 프로젝트 실패는 졸업 item 2(`통합 validate Pass`)와 단계 3 이 이미 잡는다.
     - **`P2 [Guard-drift] validate 판정력 미검증 — /stack-guard 재실행 권장`**: `PROBE FAIL(<단계>)` · `PARTIAL` · `SKIPPED (…)` · **줄 자체 부재**.
     - **여기서 probe 를 다시 돌리지 않는다 — 기록된 문자열만 읽는다**(read-only 계약). 이것이 `/stack-guard` 의 미검증 상태가 조용히 잊히지 않는 유일한 경로다(ADR-063 D3 기록 → D4 회수).
   - (e) **visual-QA 전제 기록 (ADR-058#amend-3 결정 5)** — `## 통합 명령 사용법`의 `visual-qa:` 값이 `PENDING`이면 `P2 [Guard-drift] visual-QA 전제 미준비 — /plan-workitem 이 전제 line item authoring 후 /stack-guard 재실행 권장`. 값이 `READY`거나, 줄이 없거나(비-UI·비대상), **줄은 있으나 미치환 angle-bracket placeholder면 침묵한다** — 비-UI 프로젝트에는 템플릿 복사분이 그대로 남을 수 있고(`/bootstrap-stack`은 *절* 단위로만 비해당 삭제한다) 그 placeholder 문자열 자체에 `PENDING`이 들어 있어, 명시하지 않으면 deterministic 검사가 오발화한다. **여기서 spec을 실행하지 않는다 — 기록된 문자열만 읽는다**((d)와 동형, read-only 계약).
   - `validate` 4단계 커버리지의 **재측정**은 본 항목이 아니다 — 실측은 `/stack-guard` 재실행 시 probe 가 하고, 본 항목은 (d) 로 그 **기록**만 읽는다(ADR-063 D1·D4 — 중복 회피 + read-only 유지).
   - 회수 경로는 기존과 동일하다 — IMPROVEMENT_GUIDE 에 기록하면 다음 `/plan-milestone` R0 의 open 항목 회수가 사용자에게 재실행을 안내한다(`[ADR-candidate]`·`[Stack-drift]` 와 동형, 신설 없음).

본 단계는 모두 *보고만* — 발견이 있어도 stabilize 후속 단계 차단 X (LLM 위임 단계로 계속). 후속 처리는 ADR-057#amend-3 결정 6 분기(기존 task 약속 결함=repair, cross-cutting=repair-milestone, 담당 없는 새 범위=사용자 보고+다음 M 후보)를 따른다.

**봉인 후 새 결정 등재 (ADR-060 D11)**: 마일스톤 점검에서 *기획 결정*(사용자가 정하거나 승인해야 할 것)이 드러나면 `docs/10-charter/DECISION_REGISTER.md`에 `status: open` + `- 발견: 봉인 후 (M<N>)` 줄로 등재한다. QA_FINDINGS/IMPROVEMENT_GUIDE는 *결함·개선*을 담고 원장은 *결정*을 담는다(둘 다 해당하면 양쪽에 각자 형식으로). 본 skill의 read-only 계약은 불변 — 원장 등재는 기존 QA_FINDINGS 기록과 동일한 정상 책임 범위다. 원장 파일이 없으면 등재를 건너뛰고 보고만 한다.

**review-doc 책임 분담**: [review-doc](../review-doc/SKILL.md)은 *단일 문서 ad-hoc 검토*에 한정. cross-doc / link / FAC↔AC는 본 deterministic preflight가 담당 — review-doc을 `--all`/`--milestone` 모드로 확장하지 않는다.

### 1.5. Graduation 판정 입력 수집 (ADR-068 D3)

MILESTONE 문서의 `## 5. 완료 기준` 각 항목을 아래 deterministic 평가로 계산한다(LLM 즉흥 판정 금지). **여기서는 계산만 하고 회고에 기록하지 않는다** — 최종 기록은 단계 8이다.

**정적 항목 (본 단계에서 확정하고 이후 재계산하지 않는다)** — 본 skill 자신이 단계 4~6에서 문서를 쓰므로, 그 쓰기가 아래 판정에 영향을 주지 않도록 여기서 값을 고정한다.

- **item 1 — 마감 스냅샷 유효**: 본 milestone에 속한 모든 task 파일(`docs/30-workitems/tasks/T-*.md`)에 대해
  1. `## 0. Status` 값이 `done`인가.
  2. `## 8. 메모`의 **HTML 주석 밖** 마지막 `- closure` 줄이 존재하는가.
  3. 그 줄의 `verdict`가 `Pass` 또는 `Pending Acceptance`인가. **`Needs Fix`는 미충족이다.**
  4. 그 줄의 `audit`가 `complete`인가. `미완:<축>`이면 미충족이며 graduation은 `BLOCKED (audit incomplete: <축>)`이다.
  - 하나라도 어긋나면 그 task를 미충족 목록에 넣는다(사유를 `status` / `closure 부재` / `verdict` / `audit`로 구분해 적는다). **`## 0. Status`가 `done`인데 `- closure` 줄만 없는 task**의 처방은 **«사용자가 그 task `## 8`에 `- closure` 줄을 직접 기재»** 다(ADR-068 D3 item 1). **`done`이 아닌 task에는 이 처방을 내지 않는다** — 그 task는 아직 task 층이고 단계 2가 종료시킨다. **`/validate-workitem`·`/finalize-workitem` 재실행도 처방하지 않는다** — 전자는 폐쇄 상태에서 종료하고 후자는 `done`에 read-only no-op이므로 그 처방은 실행 불가다. 수기 기재는 이 개선 이전에 마감된 task에서만 발생한다.
  - **채점표(`docs/40-validation/reports/`)를 읽지 않는다.** 졸업 판정은 커밋된 task 문서만 본다(ADR-068 D2).
- **item 4 — 관측 AC receipt 유효**: **각 task `## 6-1`에서 modality가 `[사용자 관측]`·`[플랫폼 관측]`인 AC를 전수 회수**하고, 그 AC마다 task `## 8`의 (HTML 주석 밖) **마지막 이벤트가 `- ac-acceptance`** 인가(ADR-065 D3 판독 규칙 2)를 본다. `- ac-pending`·`- invalidated`이거나 이벤트가 없으면 미충족. 관측 modality AC가 0건인 task는 해당 없음.
  - `- closure`의 `관측대기=` 목록은 **회수 편의용 색인**일 뿐이다. 그 목록만 읽으면 안 된다 — 수기 기재분이나 구 정의로 쓰인 closure 줄이 목록을 비워 둘 수 있고, 그러면 receipt 없는 관측 AC가 통과한다. **어긋나면 `## 6-1` 스캔 결과를 신뢰한다.**

**동적 항목 (단계 3~6 결과를 반영해 단계 8에서 확정한다)**

- **item 2 — 통합 `validate` Pass**: 단계 3에서 실행한 결과의 exit code 0. 마일스톤 층 수리가 추가한 회귀 테스트도 이 명령에 묶여 있으므로 함께 검사된다(ADR-068 D6).
- **item 3 — E2E Pass**: 단계 3의 e2e 상태 판정을 그대로 반영(ADR-052#amend-1 5상태).
  - **`NOT_APPLICABLE`** (비-UI ∧ item 6에 e2e 미선언) → 해당 없음(통과).
  - **`PASS`** → 통과.
  - **`EMPTY`** (선언된 e2e 디렉터리 하위에서 **실행된** 테스트 0개) → `졸업 가능: NO` (hard) + `Needs E2E Smoke`. 프로비저닝 단계와 달리 졸업 시점에는 차단한다(ADR-068 D3 item 3). *registry 미등록은 이 상태의 사유가 아니다* — 미등록은 `P1 [E2E-registry]` 기록 대상일 뿐이다.
  - **`FAIL`** → `졸업 가능: NO` (hard).
  - **`BLOCKED_ENV`** → **item 3 미충족** (hard, blocked-on-env). real failure가 아니므로 라벨을 구분해 출력하고 환경 복구를 안내한다. **최종 graduation은 `NO`가 아니라 단계 8이 확정하는 `BLOCKED (e2e blocked-on-env: <target>)`이다**(ADR-068 D4 — 우선순위 `BLOCKED` > `NO`).
- **item 5 — P0 severity finding 0건**: `docs/40-validation/QA_FINDINGS.md`의 본 milestone 헤더(`## M-N`) 아래 `### P0` 섹션에서 **`status: resolved`가 아닌 항목 수 0**. **«항목» 은 `- **<ID>** |` 로 시작하는 줄만 센다** — 항목의 하위 산문 줄에도 `status: open` 같은 문자열이 나올 수 있고(수리 라운드가 «`status: open` 유지» 라고 적는다), 문자열 grep 으로 세면 계수가 부풀려진다(dogfood Round 11 실측 — 2건이 4건으로). 단계 4의 qa 팬아웃이 새 P0를 등재할 수 있으므로 단계 8에서 확정한다.
- **item 6 — (선택) 본 마일스톤 한정 추가 기준**: 본문 텍스트 그대로 평가(사용자가 자유 기재한 영역 — 해당 항목만 LLM 해석 허용).

**본 단계의 출력** (판정을 회고에 쓰지 않는다):
- item 1 미충족 task 목록 (사유별 — status / closure 부재 / verdict / audit)
- item 4 미충족 `<task-id>:AC-N` 목록
- item 1·4가 전부 충족이면 그 사실 한 줄
- **조기 종료 옵션 (ADR-068 D3)**: **item 1이 미충족이면** 그 목록과 함께 조기 종료 옵션을 사용자에게 제시한다(강제 종료 아님 — 계속을 택할 수 있다). item 1이 깨진 상태로 단계 4~6 팬아웃을 끝까지 도는 것은 낭비다. **item 4만 미충족인 경우에는 제시하지 않는다** — 결함이 아니라 «사람 확인만 남은» 상태이므로 되돌아가 고칠 것이 없고, 그대로 진행해 단계 8에서 `PENDING_ACCEPTANCE`를 확정한다.

2. 각 task의 status를 점검 — `done`이 아닌 항목이 있으면 명단을 출력하고 종료(완료를 강제하지 않음).
3. 통합 `validate` 명령을 실행한다 + **e2e 필요성 판정 후 필수 실행**(ADR-052 — silent-skip 금지):
   - **3-a. e2e 필요성 판정**: 본 마일스톤이 e2e를 필요로 하는가를 deterministic 신호로 결정한다 —
     (i) **UI 프로젝트** (ADR-073 D9 다중신호 UI 판정: DESIGN.md status≠draft, 또는 status=draft+신호≥1) → 필요,
     (ii) graduation item 6 `(선택) 본 마일스톤 한정 추가 기준`이 e2e를 명시 선언 → 필요.
     둘 다 아니면 *불필요* → `E2E: 불필요 (비-UI ∧ item 6 미선언)` 한 줄 echo 후 통과 처리(이 경우만 skip 허용 — 사유 명시).
   - **3-b. 필요 시 `validate:e2e` 실행 (silent-skip 금지)**: e2e가 필요하면 반드시 실행하고 **구조화된 러너 출력**을 수집해 ADR-052#amend-1의 5상태로 분류한다. exit code만으로 판정하지 않는다.
     - **선행 확인**: `STACK_SETUP_PLAN.md ## E2E Smoke Registry`를 읽어 **선언된 runtime target 목록**과 각 target의 등록 여부를 회수한다. target이 둘 이상이면 아래 판정을 **target마다 따로** 내고, 하나라도 `PASS`가 아니면 졸업은 차단된다. **판정이 target마다 나므로 실행도 target마다 한다** — target이 둘 이상이면 `validate:e2e:<target>`을 target마다(또는 집계 `validate:e2e` 1회) 호출하고 target별 구조화 출력으로 각각 판정한다(ADR-059#amend-1). native target의 device id는 `scripts/e2e-target.mjs`가 registry의 *실행 대상 선택 규칙* 칸을 `flutter devices --machine` 출력에 대입해 실행 시점에 얻는다 — 규칙 문자열을 명령에 그대로 넣지 않는다. target이 하나면 1회 호출로 충분하다. **등록이 없는 target도 명령은 실행한다** — 판정은 아래 경로 기준으로 하고 `P1 [E2E-registry] <target> — canonical smoke 미등록`만 기록한다(ADR-052#amend-1 결정 4).
     - **판정 규칙은 여기서 재서술하지 않는다** — `PASS` 필요조건 넷과 **판정 순서**(`FAIL(wiring)`·`BLOCKED_ENV` → `EMPTY` → `FAIL(project)` → `PASS`, 먼저 성립하는 상태로 확정)는 **ADR-052#amend-1 결정 3이 SSOT**다. 그 절을 읽고 그대로 적용한다. 순서를 뒤집으면 기동 불가나 테스트 실패를 `EMPTY`로 오분류해 "테스트를 쓰라"는 틀린 처방이 나간다. 종료코드가 0이어도 e2e 경로 밖 suite만 돌았으면 `EMPTY`다.
     - `FAIL`은 **`FAIL(wiring)`/`FAIL(project)` 하위 라벨을 구분해 기록**하고, `BLOCKED_ENV`는 real failure와 라벨을 구분한다 — 후속 처리 주체가 다르다(stack-guard 산출물 / 프로젝트 코드 / 환경 복구).
     - **host 제약으로 `BLOCKED_ENV`인 target은 registry의 `마지막 PASS(host·날짜·커밋)` 칸을 증거로 쓸 수 있다**(예: Windows에서 iOS). **유효 조건은 하나 — `git diff --name-only <기록 커밋> <판정 커밋> -- . ':(exclude)docs/' ':(exclude)*.md'`가 종료코드 0으로 끝나고 출력이 비어 있을 때만**(기록과 판정 사이에 문서 밖 변경이 없음) 인정하고 그 target을 `PASS`로 본다. 출력이 있거나 명령이 실패하면(기록 커밋이 없으면 오류로 끝나도 출력이 비어 있다) `BLOCKED_ENV`를 유지한다 — 판정은 이 명령 하나이며 **"그 사이 앱 코드가 바뀌었는지"를 사람이 판단하지 않는다**(ADR-059 D4·#amend-3 — 증거 기록 커밋 자체가 문서 변경이라 이전의 «커밋 동일» 조건은 구성상 충족 불가능했다). 증거를 채택했으면 출력에 `<target>: PASS (registry 증거 — <host>·<커밋>)`로 근거를 남긴다.
     - 출력 문자열 매칭은 위 판정을 보조하는 용도로만 쓴다.
   - **stabilize는 read-only다 — 여기서 e2e/코드를 고치지 않는다.** 실패(real/env 무관)는 단계 8의 `/repair-milestone` 분기로 텍스트 라우팅만 한다.
3-P. **(옵션) 탐색적 QA via browser/E2E MCP** (ADR-048#d6 registry-driven / ADR-043 보안 — STACK_SETUP_PLAN `## Optional MCP Connectors`에 browser/E2E capability MCP가 *등재 + `agent access` 부여* + UI 프로젝트일 때만; 미등재·access 미부여·비-UI는 silent skip + 사유 echo): 실제 앱을 구동해 본 마일스톤 feature의 시나리오(happy/alt/fail) + qa 엣지케이스를 *탐색*한다(accessibility 트리·클릭/입력·스크린샷·네트워크). 발견한 결함을 `docs/40-validation/QA_FINDINGS.md`에 기록하고, **재현 케이스를 영속 E2E 테스트(`validate:e2e`에 묶이는 커밋 가능한 파일)로 남길 것을 권장**(자동 커밋 X — stabilize는 코드·커밋 금지, 후속 task 제안). 실패는 `Type: bugfix` task(ADR-039)로 라우팅. **보안: `browser_run_code_unsafe`류 RCE급 도구는 사용하지 않는다** — accessibility snapshot·표준 브라우저 조작만. **본 단계는 메인 세션이 직접 수행한다** — 탐색 중 임시 스크립트가 필요하면 메인이 scratch 경로에 두고 경로를 넘긴다(ADR-050#amend-2 결정 2 — 프로젝트 트리에 만들지 않는다).
3-V. **경험 게이트 — 구현 화면 vs 승인 스냅샷 대조 (ADR-072 D7, UI 확정 마일스톤 한정)**: MCP 불요 체계 감사. **실행 자체는 의무 — silent skip 금지**(미실행 사유 echo; 판정은 report-only). **본 단계도 메인 세션이 직접 수행한다** — 렌더·대조에 쓰는 임시 스크립트는 메인이 scratch 경로에 두고 경로를 넘긴다(ADR-050#amend-2 결정 2).
   - (a) `docs/20-system/prototypes/M<N>/manifest.json`을 읽는다(**이 M이 등록한 화면이 있어야 하는데** 부재면 `blocked-on-env`가 아니라 계약 결함 `P0 [Experience-contract] 매니페스트 부재`. 전 화면이 `프로토타입 면제:`이거나 이전 M 재사용이면 이 M 파일 부재가 정상이며, 그때는 feature `## 7`의 `프로토타입:` id가 가리키는 M의 매니페스트·스냅샷을 읽는다). 화면마다 두 렌더를 만든다(**매니페스트에 없는 UI 화면 — `프로토타입 면제:` feature·이전 M 승인본 재사용 — 은 ②만 만들어 (b)의 ② 경로로 대조한다, ADR-072 D7**): **① 스토리/위젯 렌더** — `validate:design -- --manifest <경로> --snapshot docs/40-validation/visual/M-N/proto/`; **② 제품 렌더** — 웹은 dev server 기동(명령은 STACK_SETUP_PLAN·`package.json` `dev`/`start`에서 회수, readiness 대기, 종료 시 kill — 재사용 규칙 기존대로) 후 매니페스트 `product_entry`(`null`이면 «제품 진입점 미기록» 사유 echo + ① 대조만)의 라우트를 프로필 뷰포트로 캡처해 `docs/40-validation/visual/M-N/app/`, Flutter는 통합 테스트 스크린샷이 가능하면 그것, 아니면 `blocked-on-env` 명시(ADR-059#amend-1 결정 4). blocker가 있어 `--snapshot` 복사에서 빠진 화면은 `design-gate-shots/`의 캡처를 ①로 쓴다.
   - (b) 각 화면에 대해 **승인 스냅샷(`snapshots/`) ↔ ① ↔ ②**를 Read(멀티모달)로 나란히 대조한다. 앵커 위계: ① 승인 스냅샷(존재 시) ② DESIGN.md §2/§7/§9/§10 파생 체크리스트(면제·부재 화면). 관점: 레이아웃·상태·카피·토큰 준수 — 픽셀 일치가 아니라 경험 계약 준수. ① vs 승인 스냅샷 불일치는 «승인 후 UI 코드 변경»이므로 같은 M 재승인 또는 다음 M `supersedes` 등재 여부를 함께 본다. 화면의 현재 기준선은 «가장 최근 M의 등록·supersedes»다(ADR-072 D5-5).
   - (c) 불일치는 QA_FINDINGS에 `P1 [Experience-drift] <screen> — <1줄> (앵커: 스냅샷|DESIGN 파생 / 렌더: proto|app)` report-only. 판독 불확실은 «판독 불확실» 명시. 시각 불일치가 봉인 AC·PX↔AC 위반을 동반하고 재현되면 그것은 별도 P0 결함(재현 줄 포함)으로 등재한다(ADR-070 D1).
   - (d) 단계 8 출력에 갤러리 경로 + «사용자 육안 확인은 `/accept-milestone <M>`이 수행한다» 1줄. 관측 modality AC가 1건이라도 있으면 사실상 필수 경로(ADR-068 D3).
   - Codex: 캡처까지 수행 + 대조는 «사용자 수동 검토» 안내로 degrade.
4. **병렬 qa verifier 팬아웃 — 고정 1개가 아니라 *필요한 만큼*** (feature / user-flow / surface 단위로 분할). 메인 세션이 본 마일스톤의 feature·핵심 시나리오·surface 목록을 회수해 *독립 점검 단위*로 쪼개고, 각 단위마다 qa agent를 1개씩 병렬 위임한다(회귀·엣지케이스 점검). qa는 보고만 한다(qa.md의 tools에 Write 없음).
   - **위임 시 ADR-046#d3 적용: finding은 cap 때문에 누락하지 말고 전수 반환 — cap은 서술/과정 설명에만.**
   - **입력에 «작업 파일을 프로젝트에 만들지 않는다 — scratch 경로: <세션 scratchpad>/stabilize-M<N>/» 한 줄(ADR-050#amend-2).**
   - **회수 분할 (ADR-075 D11 (b))**: 한 단위의 회수 문서가 **10개 이상이면** 축·범위를 더 나눠 dispatch 한다 — 한 dispatch 에 전부 싣지 않는다.
   - **입력에 ADR-070 D1 severity 정의표를 그대로 전달한다**(기준 전달 — 사전판정 아님). P0 재현 줄 형식도 함께 전달한다.
   - **축 미반환 회수 규율 (ADR-075 D13)**: qa 단위가 구조화 반환 없이 멈추면 ① 1회 재개(같은 단위·같은 형식, 이미 확립한 finding 전량 포함 명시) → ② 다른 qa에 재위임 → ③ 메인이 그 단위를 직접 감사 → ④ 그래도 불가하면 **`QA_FINDINGS.md`의 본 마일스톤 `### P0`에 `- **M<N>-audit-<K>** | P0 | [관측됨] | linked: M<N> | status: open` + 하위 줄 `- 감사 미완(unavailable): <단위> — <4단계 실패 사유>`를 등재하고**, 단계 8의 graduation을 `BLOCKED (audit incomplete: <단위>)`로 기록한다(ADR-068 D4). **qa 팬아웃은 졸업 predicate ⑤의 유일한 입력이므로, 돌지 않은 감사를 근거로 "P0 0건"을 단정하지 않는다.**
   - 다음 라운드에서 그 단위의 감사가 성공하면 본 skill이 그 `M<N>-audit-<K>` 항목의 `status: open`을 `resolved`로 갱신한다(**본 skill이 자기가 만든 감사-미완 항목에 한해 status를 닫는 유일한 예외** — 그 밖의 finding status는 `/repair-milestone`·`/repair-acceptance` 소유).
   - **Codex: 서브에이전트는 GA이나 본 저장소가 Claude persona 위임을 Codex subagent로 아직 매핑하지 않아 순차 단일 실행으로 degrade** (동일한 분할 단위를 *순차 단일 qa 호출*로 한 단위씩 처리, 결과는 동일하게 누적).
5. **병렬 reviewer verifier 팬아웃 — 필요한 만큼** (리팩토링 후보·아키텍처 부채). 각 reviewer 입력에 Clean Code 6항목 체크리스트(ADR-006) + `review surface: code` + **ADR-046#d3(finding 전수 반환 — report-only)** 를 명시 전달한다. **UI 프로젝트는 추가로 `review surface: design` reviewer를 1개 더 팬아웃** — DESIGN.md `## 9. Do's and Don'ts` 위반 의심 grep 결과를 입력으로 받아 비판적 검토. reviewer도 보고만 한다. design reviewer 입력에는 grep 결과에 더해 **렌더 증거**를 주입한다 — §3-V 갤러리 경로(`proto/`·`app/`) + **승인 스냅샷 경로(매니페스트)** + visual-qa.spec 최근 결과. reviewer는 Read로 이미지를 열람한다(ADR-073 D8). Codex: 경로 echo + 텍스트 결과만 전달로 degrade.
   - **입력에 «작업 파일을 프로젝트에 만들지 않는다 — scratch 경로: <세션 scratchpad>/stabilize-M<N>/» 한 줄(ADR-050#amend-2).**
   - **회수 분할 (ADR-075 D11 (b))**: 한 단위의 회수 문서가 **10개 이상이면** 축·범위를 더 나눠 dispatch 한다 — 한 dispatch 에 전부 싣지 않는다.
   - **Codex: 서브에이전트는 GA이나 본 저장소가 Claude persona 위임을 Codex subagent로 아직 매핑하지 않아 순차 단일 실행으로 degrade** (분할 단위를 순차 reviewer 호출로 처리).
   - **축 미반환 회수 규율**: 단계 4와 같은 4단계를 밟는다. 단 ④에 도달해도 **판정을 바꾸지 않는다** — reviewer 결과는 졸업 predicate 입력이 아니다(report-only). `IMPROVEMENT_GUIDE.md`에 `P2 [Audit-unavailable] reviewer:<단위> — 감사 미완`을 기록하고 단계 8 출력에 사유를 echo한다. 미반환을 P0로 올리면 "결과 없음"이 "결과 있음"(정상 반환한 P1 부채는 졸업을 막지 않는다)보다 강해지는 역전이 생긴다. reviewer가 정상 반환한 **결함**은 6-S가 QA_FINDINGS로 보내 졸업 입력이 된다(ADR-070 D7). 미반환 자체는 여전히 판정을 바꾸지 않는다.
6-S. **메인 세션 self-synthesis (report-only 계약 유지)**: 위 4·5의 *모든* 병렬 verifier가 반환한 보고를 메인 세션이 직접 종합한다.
   - **task report 잔여 finding도 이 종합의 입력이다 (ADR-076 D10)**: 본 마일스톤 산하 `done` task의 `docs/40-validation/reports/<task-id>.md`에서 `## 잔여 finding` 절의 줄을 4·5의 보고와 함께 받는다. 그 절이 없는 옛 report와 report가 없는 task(checkout-local)는 건너뛰고 건수만 출력한다. 출처 값은 `report-residual(<task-id>)`다. P0·P1은 아래 채택 전 검토를 똑같이 거치며 등급은 ADR-070 D1 표로 다시 판정한다(validate의 등급과 다르면 판정 근거 한 줄에 적는다). **P2는 채택 전 검토 대상이 아니다**(ADR-070 D2는 P0·P1) — 성격 라우팅만 거치고, 아래 5-D와 같은 동일성 기준으로 이미 있으면 적지 않는다. report 줄은 과거 시점의 기록이라 verifier 보고와 다른 예외가 둘 있다 — 그 task `## 8`에 같은 라벨·위치의 repair `Reject-*` 결정 줄이 있으면 task 층에서 이미 판정됐으므로 등재하지 않고, P0·P1 중 뒤 task가 이미 고쳐 현재 코드·문서에 근거가 없는 줄도 등재하지 않는다(둘 다 건수만 출력). P2는 해소 여부를 여기서 판정하지 않는다(`/repair-milestone`이 4-판정으로 닫는다).
   - **성격 기준 라우팅 (ADR-070 D7)**: 보고자와 무관하게 결함(동작·데이터·보안·계약 위반)은 `docs/40-validation/QA_FINDINGS.md`, 개선(구조·중복·명명·부채·문서 정합)은 `docs/40-validation/IMPROVEMENT_GUIDE.md`에 적는다. 항목 하위 줄 `- 출처: qa | reviewer(<surface>) | preflight | peer(<tag>) | report-residual(<task-id>)`로 보고자를 남긴다.
   - **채택 전 검토 (ADR-070 D2 — 등재 전 1회, P0·P1 전부)**: 각 항목을 `confirmed | rejected-fp | rejected-context | needs-confirmation | unsubstantiated` 중 하나로 판정해 `decision:`에 적는다. **P0는 `- 재현:` 절차를 qa 단발 sub-call(명령 1회면 메인)이 다시 실행해 관측했을 때만 `confirmed`다. 코드·문서·상태를 바꾸는 재현은 메인이 직접 돌리지 않는다 — 단계 3이 띄운 환경에서 qa로, 불가하면 `needs-confirmation`(확인 방법 = `/repair-milestone`).** P1은 보고의 재현·근거를 코드·문서로 확인하면 `confirmed`(재실행 불요). **P0인데** 재현 줄이 없으면 `[Finding-unreproduced]`를 붙여 `needs-confirmation`(하위 줄 `- 대상 / 확인 방법 / 막힌 이유` 3필드)으로 둔다(ADR-070 D1 — 이 조건은 P0 한정이다. 정적으로 확인되는 P1에 재현을 요구하지 않는다). `rejected-*`·`unsubstantiated`는 `status: resolved`로 등재한다(unsubstantiated는 `### 관찰 메모`에 한 줄). 판정 근거 한 줄을 남긴다. 이것은 사후 판정이며 verifier에게 심각도를 미리 지정하는 것이 아니다.
   - **같은 마일스톤의 2회차 이후 stabilize에서 새로 등재하는 P0**는 ADR-070 D6의 4가지 사실 줄(이전 감사 범위 / 새 근거 / 종결 항목과 동일성 / 종결을 뒤집는 증거)을 하위에 적는다. 종결 항목과 동일하면 새 ID를 만들지 않는다 — **이번 판정이 `confirmed`일 때만** 그 항목을 `status: open`으로 재개하고 재개 사유(= 종결을 뒤집는 증거)를 적는다. `rejected-*`·`unsubstantiated`로 다시 판정됐으면 **종결을 유지하고** 그 항목 하위에 `- 재보고: <날짜> — 동일 증상, 종결 유지(<decision> 근거 한 줄)`만 남긴다(ADR-070 D6 — 근거 없이 재개하면 같은 오탐이 매 라운드 졸업을 막는다).
   - **no-cap-drop (ADR-046#d3)**: 여러 verifier의 finding을 합칠 때도 cap 때문에 누락 금지 — finding은 전수 기록하고, cap은 *대화 출력의 서술/과정 요약*에만 적용한다.
   - **dedup**: 분할 단위가 겹쳐 동일 finding이 여러 verifier에서 중복 반환될 수 있다. 동일 `<라벨> <file:line> <증상>` 항목은 1건으로 병합하되, *서로 다른 단위에서 관측됨*은 근거로 보존(병합 시 관측 surface를 한 줄로 합산).
   - reviewer 결과에 구조 변경이 필요해 보이면 메인 세션에 architect 추가 호출을 텍스트로 제안.
   - **stabilize는 여전히 read-only다** — self-synthesis는 *문서 누적 기록*까지만. 코드·커밋·workitem status 변경 없음(도입부 책임 경계 정합).
5-D. **등재 전 dedup (필수 — ADR-070#amend-1 결정 2)**: 6-S 검토를 통과한 각 P0·P1 을 원장에 적기 **전에**, 같은 사실이 본 마일스톤 원장에 이미 있는지 본다. 동일성 기준은 «`<라벨> <file:line> <증상>`»(§1.0 3-1 과 같다)이며 preflight 정규식 발화처럼 file:line 이 여럿인 항목은 **경로 집합**으로 비교한다. **이미 있으면 `status` 가 `open` 이든 `resolved` 든 새 ID 를 만들지 않는다** — 대신 그 항목에 `- 재발화: <YYYY-MM-DD> (stabilize <N>회차) — 판정 유지` 한 줄만 붙인다. 경로 집합이 달라졌으면 새 항목이다. **이 규칙이 없으면 preflight 의 구조적 오탐이 매 라운드 새 ID 로 재생산된다**(dogfood Round 11 실측 — raw-hex 5건·voice 10건이 3회차 내내 동일하게 재발화).

6. 미흡한 ADR 후보 제안 — 마일스톤 중에 내려진 결정인데 ADR이 없는 것을 식별하고, **IMPROVEMENT_GUIDE 항목 스키마(필수 4필드)로 영속 기록**한다: `- **M<N>-adrc-<K>** | P2 | [관측됨] | linked: M<N> | status: open` + 하위 줄 `- [ADR-candidate] <결정 한 줄> — 회수: 다음 /plan-milestone R0` (ADR-000#amend-2 — 기록 전 _ADR_GUIDE의 ADR 대상 기준 self-check, 남발 방지. 후보 ≠ 자동 작성). ADR 후보 기준에 "layer 경계·의존성 규칙 변경"도 포함(ADR-006 정책).
   - ARCHITECTURE_OVERVIEW.md에 비해당 7-x sub-section이 *잔존*하면 IMPROVEMENT_GUIDE.md에 P2 보고 — *"조건부 sub-section 미삭제. /bootstrap-stack 재실행 또는 수동 삭제 권장."*
   - layer 경계·의존성 규칙 변경(ARCHITECTURE_OVERVIEW의 ## 3-1)이 마일스톤 중에 발생했으면 ADR 후보로 표시한다(정책: ADR-006).
   - **[Stack-drift] ADR-101 staleness 감지 (ADR-055, report-only)**: 본 마일스톤에서 순증한 dep(산하 task `## 3` install line-item / lockfile diff)을 T2 임계 카테고리(언어/런타임/프레임워크/DB·영속성/인증/배포 토폴로지/핵심 외부 의존, 또는 ARCH §7 결정·charter §7 제약을 뒤엎음 — 개별로 사소해도 cluster로 넘으면 포함)와 대조. 임계를 넘으면 `P2 [Stack-drift] ADR-101 stale — 누적 dep가 T2 임계 도달 → /bootstrap-stack --migrate 후보 또는 ADR-101 amend`를 IMPROVEMENT_GUIDE에 기록. 임계 미달 누적은 침묵(피로 방지 — ADR-101은 dep 원장이 아님). 휴리스틱 한계 echo(키워드/lockfile diff 기반 — false negative 가능).
### 6.5. DISCOVERY ↔ Charter staleness 감지 (ADR-035#amend-1)

다음 4 시그널을 점검한다 (보고만, 자동 차단 X — validator 책임 경계 정합).

1. **«Charter 마지막 커밋 이후 DISCOVERY에 Charter 공급 절의 실질 변경이 있는가»**(ADR-035#amend-4)로 판정한다. 방법: `C=$(git log -1 --format=%H -- docs/10-charter/PROJECT_CHARTER.md)`; `git diff -U0 $C -- docs/10-charter/DISCOVERY.md`(워킹트리 변경 포함)의 각 hunk를 **새 파일의 줄 범위(`@@ -a,b +c,d @@`의 c..c+d)**로 현재 DISCOVERY의 `## N.` 헤딩 줄 범위에 대응시켜 절을 정한다(hunk 헤더의 함수명 칸은 markdown에서 절 제목을 보장하지 않으므로 쓰지 않는다). **제외**: `## 14`·`## 15`·`### Repair history` 절의 hunk 전부, 그리고 `## 12` 절의 hunk 중 변경 줄이 전부 원장 상호참조 패턴(`원장 D-[0-9]{3}`·`risk-accepted`)만 담은 것. `## 12`의 그 밖의 변경(가정 추가·결과 변경)은 Charter `## 9`의 공급원이므로(ADR-069 D3 전파표) 발화한다. 제외 뒤 남는 hunk가 1개 이상이면 발화. git 이력이 없으면(fresh fork) mtime 규칙으로 degrade + 사유 echo.
2. DISCOVERY.md `## 12. Assumption Tracker` 표에서 *"미검증"* 결과 항목 수.
3. PROJECT_CHARTER.md `## 2.1 페르소나` / `## 3.1 핵심 시나리오` / `## 9 핵심 가정` 섹션 중 비어 있거나 DISCOVERY.md와 명백히 어긋난 섹션 수.
4. (ADR-035#amend-2) DISCOVERY.md `## 15. Insight Backlog`에서 `status=open`(미반영) 인사이트 수 — 있으면 *"미반영 인사이트 N건 — 다음 /plan-milestone 후보로 회수 권장"* P1 보고.

위 1~3 시그널 중 1개라도 *stale 의심* 판정 시 IMPROVEMENT_GUIDE.md에 P1 보고:
*"DISCOVERY ↔ Charter drift 의심 — 절 단위 부분 갱신이면 `/amend-ssot`, 전면 재정의면 `/bootstrap-project --apply` 권장."*
(시그널 4는 drift가 아니라 *미반영 인사이트* 신호 — 위 4번 줄에서 별도 P1 보고하므로 본 집계에 포함하지 않는다.)

7. ARCHITECTURE_OVERVIEW의 `## 3-1. 레이어 경계 + 의존성 규칙` 섹션이 비어 있고 모듈 수가 3개 이상이면 채울 것을 권장 출력한다(정책: ADR-006).

7-T. **Telemetry aggregate** ([ADR-047](../../../docs/90-decisions/boilerplate/ADR-047-code-as-agent-harness.md) D7 deep telemetry + D1 inspectability 정합). 본 마일스톤 산하 task의 *이미 수집된 데이터*를 수치 dashboard로 echo. 새 데이터 수집 X — surface만.

수집 소스:
- 본 마일스톤 산하 모든 task의 `docs/40-validation/reports/<task-id>.md` (존재 시). **부재하면 그 task `## 8`의 마지막 `- closure` 줄에서 `기계AC`·`자동화율`을 읽는다**(ADR-068 D2 — 새 체크아웃에서 telemetry가 통째로 비는 것을 막는다). 그 줄도 없으면 그 task를 «집계 불가»로 세고 출력에 건수를 남긴다.
- **검증 레벨 분포는 산하 task의 `## 6-1`에서 직접 집계한다** — 채점표에도 `- closure`에도 그 값이 없으므로(closure는 `기계AC`·`자동화율`만 담는다) 커밋된 `## 6-1`이 유일한 항구 출처다. 판정 규칙은 `/validate-workitem`과 같다(**`[자동 테스트]` AC만 레벨 대상**, 명시 `{레벨}` 태그 우선, 미기재는 테스트 경로 추론, 나머지는 `레벨 비대상`).
- 본 마일스톤 산하 feature의 `## 7-1. FAC ↔ AC 매핑표`.
- `docs/40-validation/QA_FINDINGS.md` 본 milestone 헤더(`## M-N`) 아래.
- `docs/40-validation/IMPROVEMENT_GUIDE.md`의 `## 2. 열린 항목` 안의 본 milestone sub-section (`### M-N` 그룹) — Cross-stabilize 회귀 신호 grep 대상. **`## 5. Repair decision log`는 제외** (Step 3 신설 영역, *closed records*라 *open finding 재등장* 측정 대상 아님).

집계 항목:
- Tasks: M done / N total (M/N %)
- AC↔검증 매핑: 충족 A / 전체 B — 충족률 <%> · 자동화율 <%>
- AC 검증 레벨 분포: unit N / integration M / contract K / e2e L · 레벨 비대상 P  (`[자동 테스트]` AC만 레벨 대상 — 출처: task `## 6-1`. `[산출물 검사]`·관측 2종은 «레벨 비대상»이며 자동화율 분류와는 별개다 — ADR-065 D4)
- FAC coverage: C ✅ / D total (C/D %)
- Evidence Bundle 신뢰도 분포: High K / Medium L / Low J (Step 2 도입 후 채워짐 — 미도입 마일스톤은 "해당없음" 한 줄)
- Validate exit code (가장 최근 실행): 0 / non-zero / 미설정
- Findings 분포: P0 X / P1 Y / P2 Z (본 milestone 헤더 산하)
- **Open 전체 스냅샷** — 세 수를 **정의대로** 센다(겹치지 않게 한다).
  - **N** = `QA_FINDINGS.md`의 **본 마일스톤 헤더(`## M-N`)** 아래 미해소 항목 수(P0 a / P1 b / P2 c)
  - **M** = `IMPROVEMENT_GUIDE.md`의 **본 마일스톤 그룹(`### M-N`)** 안 미해소 항목 수(P0 d / P1 e / P2 f). `## 5. Repair decision log`는 closed records라 제외.
  - **K** = **다른(이전) 마일스톤** 헤더·그룹의 미해소 P0/P1 수 = carry-over
  - **합계 = N + M + K**. 형식: `Open 전체: QA_FINDINGS N + IMPROVEMENT_GUIDE M + carry-over(P0/P1) K = (N+M+K)건` — **carry-over에 `(P0/P1)`을 붙여 출력한다**. N·M은 전 severity인데 K는 P0/P1만 세므로(다른 마일스톤 항목은 색인 스캔 대상 — `/repair-milestone` 회수 규율과 동형), 표기하지 않으면 `## 8. 회고`에 영속되는 수치를 읽는 사람이 기준을 오독한다.
  - **두 원장을 각각 읽어야만 알 수 있는 수이므로 한 줄로 합산해 남긴다**(한쪽만 읽고 남은 항목 수를 오독한 사례가 관측됨). 같은 값을 milestone `## 8. 회고`의 `open 항목 스냅샷:` 줄에도 기록한다(ADR-068 D5).
- Cross-stabilize 회귀 신호: *이전 모든 milestone들*(`## M-1` ~ `## M-(N-1)`)의 P1 라벨 finding이 본 milestone의 **QA_FINDINGS(`## M-N`)** 또는 **IMPROVEMENT_GUIDE 의 `## 2. 열린 항목` 안 `### M-N`** 두 sub-section에 *재등장*한 항목 수 (라벨 grep, 휴리스틱 한계 echo — 동의어/오타 false-negative 가능. 본 grep은 *정확한 라벨 매칭*만 잡음. `## 5. Repair decision log`는 *closed records*라 회귀 신호 대상 아님).
- **위임 예산 (ADR-074 D11)**: `턴 소진 0건 보고: N회` — 산하 task 의 report·repair 로그에서 «sub-agent 가 턴 상한에 닿았는데 보고가 0건이었다»고 적힌 건수를 센다(기록이 없으면 `0회 (미기록)`). 이 실패는 지금까지 사람이 알아채야만 보였다. **1회 이상이면 ADR-074 D14의 slice 강제 조건이 발화한다** — 단계 8 출력에 그 사실을 한 줄로 적는다.
- **수렴 (ADR-070 D8)**: `round K`(IMPROVEMENT_GUIDE `## 5` `### M-N`의 `- round:` 최대값, 없으면 0) / P0 신규 a · 해소 b · 재개 c / P0 재현 첨부율 <%> / needs-confirmation d건

본 단계는 *수치 echo만* — IMPROVEMENT_GUIDE / QA_FINDINGS에 새 항목 박지 않음. Cross-stabilize 회귀 신호가 1+ 건이면 단계 8 출력의 "P1 / P2 후속 작업"에 *patterned drift 의심* 한 줄 추가.

출력 형식 (단계 8의 최종 출력에 *Telemetry* 단락으로 포함):
```
Telemetry — M1
- Tasks: 12 / 12 (100%)
- AC↔검증 매핑: 충족 34 / 전체 36 — 충족률 94.4% · 자동화율 88.9%
- AC 검증 레벨 분포: unit 20 / integration 9 / contract 2 / e2e 1 · 레벨 비대상 4
- FAC coverage: 8 / 8 (100%)
- Evidence Bundle 신뢰도: High 9 / Medium 2 / Low 1
- Validate exit code: 0
- Findings: P0 0 / P1 3 / P2 7
- Open 전체: QA_FINDINGS 4 + IMPROVEMENT_GUIDE 6 + carry-over(P0/P1) 1 = 11건
- Cross-stabilize 회귀 신호: 0건
- 위임 예산: 턴 소진 0건 보고 0회
- 수렴: round 2 / P0 신규 1 · 해소 3 · 재개 0 / 재현 첨부율 100% / needs-confirmation 0
```

8. 최종 출력:
   - 통합 `validate` 결과 + E2E 결과 (있으면)
   - P0 / P1 / P2 후속 작업
   - QA_FINDINGS / IMPROVEMENT_GUIDE 갱신 위치
   - **변경한 tracked 파일 목록**: `QA_FINDINGS.md`·`IMPROVEMENT_GUIDE.md`·마일스톤 문서(`## 8` 회고)·`DECISION_REGISTER.md`(등재 시)
   - **커밋 안내**: 본 skill은 커밋하지 않는다 — 위 파일을 **사용자가 직접 커밋한 뒤** 다음 단계로 진행한다(commit owner는 사용자/`/finalize-workitem`). 미커밋으로 두면 후속 task의 `/finalize-workitem`이 그 파일을 task `## 4-1` 밖 변경으로 보고 `Needs Review`로 멈춘다.
   - **수용 대기 AC (item 4 미충족)**: `<task-id>:AC-N (<modality>)` 목록 / 해당없음. **`/accept-milestone <M>` 처방은 최종 판정이 `PENDING_ACCEPTANCE`일 때만 붙인다** — `NO`·`BLOCKED`면 목록만 남기고 처방은 아래 「다음 단계」 분기가 소유한다(한 출력이 두 명령을 지시하면 사용자가 어느 쪽을 칠지 알 수 없다)
   - 다음 마일스톤으로 넘기는 항목
   - (UI) 경험 게이트 결과: [Experience-drift] N건 + 스크린샷 갤러리 경로 (사용자 육안 확인 권장) — 미실행 시 사유 필수 echo (silent skip 금지)
   - architect 호출 권장 (있으면)
   - ADR 후보 (있으면): `[ADR-candidate]` 라벨 목록 — 다음 /plan-milestone R0가 회수 (ADR-000#amend-2)
   - instruction improvement 후보:
     본 마일스톤 동안 builder/validator/reviewer가 반복적으로 막힌 패턴,
     AGENTS.md 또는 agent/skill body 문구가 *비자명하거나 모호*했던 지점,
     새로 박을 만한 *self-check 항목* 후보를
     [IMPROVEMENT_GUIDE.md](../../../docs/40-validation/IMPROVEMENT_GUIDE.md)에 보고.
     각 항목에 [ADR-022](../../../docs/90-decisions/boilerplate/ADR-022-ratchet-principle.md) evidence label 부착.
     *AGENTS.md / agent / skill body는 자동 수정 X — 보고만*.
     **경험·사용 관점 교훈(제품을 실제로 써 본 결과에서 나온 것) 유무를 별도로 확인**한다 — 교훈이 검증-정교화 방향으로만 쌓이는 편향 방지([관측됨] 실사용에서 경험 축 교훈 0건).
     - DESIGN.md / ARCH 7-x cross-surface drift 가 본 마일스톤 중에 N회 이상 발견됐다면 *ADR-073 D8 적용 본문* 이 누락된 fork 인지 점검 권장.
   - **Telemetry aggregate** (단계 7-T 결과 echo — 수치만, IMPROVEMENT_GUIDE 신규 항목 X).
   - **다음 단계** ([WORKFLOW.md "스킬 종료 시 다음 단계 출력 contract"](../../../docs/00-meta/WORKFLOW.md) 양식 정합):
     - **졸업 가능 = PENDING_ACCEPTANCE** (item 4만 미충족):
       - **유일한 권장: `/accept-milestone <M>`** — 사람이 직접 실행·확인하는 수용 라운드이며(ADR-066 D1), 미발급 receipt는 그 자리에서만 발급된다(사용자 authority — ADR-065 D1). 미발급 AC 목록(`<task-id>:AC-N`)을 함께 출력한다.
       - **여기서 `/validate-workitem`·`/finalize-workitem` 재실행을 권장하지 않는다** — 그 마일스톤은 이미 폐쇄됐고(ADR-068 D1), 졸업 item 4는 task `## 8`을 직접 읽으므로 receipt 발급만으로 충족된다.
       - 수용 라운드 뒤에는 그 skill의 출력이 지시하는 순서를 따른다. 코드 변경이 있었으면 `/repair-acceptance <M>`이 그 자리에서 고치고 회귀 테스트까지 끝낸다 — **task를 재개방하지 않으므로 사용자가 돌릴 `/validate-workitem`·`/finalize-workitem`은 없다.** 사용자는 그 뒤 **본 skill을 한 번 더 실행**해 `YES`를 확정한다.
     - **졸업 가능 = YES + P0 후속 0건**:
       - **(ADR-076 D5)** IMPROVEMENT_GUIDE 본 마일스톤 그룹에 `status: open`인 `[Provisional-AC]`가 있으면 기본 권장을 `/repair-milestone <M>` — "잠정 해석 N건 사용자 확인(승인/변경)"으로 두고, 아래 `/plan-milestone`은 그 뒤 순서로 안내한다.
       - **기본 권장: `/plan-milestone`** — 새 milestone(M-(N+1)) + feature 문서 생성 → `contract-ready`. 뒤이어 `/plan-workitem M-(N+1)`(전체 계획 스냅샷, task는 `draft`) → **`/seal-milestone M-(N+1)`**(검사·승인·일괄 `ready`) 순으로 진행(ADR-057#amend-3 / ADR-060 D7)
       - **`/accept-milestone <M>`은 이 상태에서 선택이다** — `YES`는 관측 modality AC가 0건이거나 그 receipt가 이미 전부 유효하다는 뜻이므로 receipt로 막힐 것이 없다. 사용자가 경험 확인을 원하면 실행한다. **단 마일스톤 문서 `## 11`에 `- 판정: 승인`이 이미 기록돼 있고 그 뒤 코드·receipt 변경이 없으면 재권장하지 않는다** — 그 상태에서 다시 권장하면 라운드 상한 3이 무의미하게 소모된다.
       - 프롬프트 동봉 권장: 본 라운드 Telemetry 의 신뢰도 분포 + Cross-stabilize 회귀 신호 (다음 milestone 의 우선순위 조정 입력)
     - **졸업 가능 = BLOCKED** (평가 실행 불가 — ADR-068 D4). **이 분기가 아래 `NO` 분기보다 우선한다**(우선순위 `BLOCKED` > `NO`) — 감사 미완은 `M<N>-audit-<K>` P0를 등재하므로 «P0 후속 있음»에도 걸리지만, 그 P0의 처방은 repair가 아니다:
       - **감사 미완(`BLOCKED (audit incomplete: <단위>)`)**: 처방은 **그 축의 재감사**다 — 단계 4의 축 미반환 회수 규율 ①~③(1회 재개 → 다른 qa 재위임 → 메인 직접 감사)을 다시 시도하거나 본 skill을 재실행한다. **`/repair-milestone`은 처방이 아니다** — «못 재봤다»는 상태이지 코드 결함이 아니어서 4-판정할 대상이 없다. 등재된 `M<N>-audit-<K>` P0는 감사가 완료된 뒤 `status: resolved`로 닫는다.
       - **e2e blocked-on-env**: 처방은 아래 `NO` 분기의 «e2e blocked-on-env» 불릿과 같다(환경 복구 후 본 skill 재실행 — real failure가 아니므로 repair 대상이 아니다).
       - `BLOCKED`은 이전 라운드에 기록된 `YES`·`PENDING_ACCEPTANCE`를 덮어쓴다(책임 경계의 회고 기록 규칙) — 낡은 값이 남아 하류가 졸업으로 읽는 것을 막는다.
     - **졸업 가능 = NO 또는 P0 후속 있음** (분기 옵션 ≤3):
       - **수렴 실패 브리프 (ADR-070 D5)**: 7-T의 `round K`가 **3 이상**이고 `### P0`에 `status: open`이 남아 있으면, 판정은 그대로 두고 `[Convergence]` 라벨로 Decision Brief 6블록(`authority: user-choice`, `영향: M<N>`, DECISION_REGISTER 등재)을 출력한다 — 남은 P0/P1 각각의 `decision`·근거·영향·수리 범위·보류 가능 여부 + 선택지 A(계속 수리) / B(비차단 항목에 `- 수렴-보류: 회수 <시점> | 조건: …` 하위 줄을 달아 이번 라운드 대상에서 빼고 차단 항목만 수리 — `status`는 `open` 유지, finding 원장에 `deferred` 상태를 만들지 않는다) / C(`NO` 유지 + 병렬 Now 승인으로 다음 마일스톤 진행 — carry-over 표시 지속, 해소 후 `/repair-milestone M<N>`이 원본을 닫고 본 skill 재실행으로 `YES`). **남은 `### P0` open 항목이 *전부* `- 판정: Adopt — blocked:` 줄을 가지면 선택지 A·B 를 제시하지 않는다**(ADR-070#amend-1 결정 3) — 그 상태에서 A(한 라운드 더)의 기대 효과는 0 이고 B(차단 항목만 수리)의 대상도 없다. 그때 선택지는 **C** 와 **«재승인·계약 정정 경로 착수»** 둘이며, 브리프에 각 항목의 `blocked:` 경로를 그대로 옮겨 적는다. 하나라도 `blocked` 가 아니면 기존대로 셋을 낸다. **판정값 신설·`YES` 병기·P0의 P1 재분류는 하지 않는다.** 항목을 DECISION_REGISTER에 `open`으로 등재하고(정상 책임 4), 사용자가 같은 세션에서 답하면 *그 항목에 한해* `closed` + 앵커를 쓴다. **`## 5`의 `- convergence-decision:` 줄은 답변 시점과 무관하게 후속 skill이 남긴다**(A·B → `/repair-milestone` 1-R, C → `/plan-milestone` R0 — 본 skill은 `## 5`에 쓰지 않는다, ADR-070 D5). `## 5` `### M-N`에 `- convergence-decision:` 줄이 이미 있으면 새 P0 ID가 생겼거나 K − 결정 round ≥ 2일 때만 다시 낸다. **`BLOCKED` 분기에서도 같은 조건(round ≥ 3 + open P0)이면 동일 브리프를 낸다** — 감사 미완·환경 불가와 별개로 남은 P0의 진행 경로를 사용자가 정해야 한다.
       - **milestone-level P0/P1 (여러 task 교차) 또는 e2e real failure 있음: `/repair-milestone M-N` 권장** (ADR-052) — 단일 task로 격리되지 않는 회귀·교차 결함과 실제 e2e 수정은 milestone 단위 repair로 라우팅. stabilize가 read-only로 남기 위한 코드 수정 경로다.
       - `[Provisional-AC]`가 open이면 같은 `/repair-milestone M-N` 호출에서 함께 확인한다 (ADR-076 D5).
       - QA_FINDINGS 발견(P0/P1)은 단일 task 격리든 교차든 `/repair-milestone M-N` 로 회수한다 — **repair-milestone이 4-판정 후 per-task 귀속이든 cross-cutting이든 직접 수정하고**(재개방·위임 없음 — ADR-068 D1) QA_FINDINGS status를 닫는다.
       - `[Spec-gap]` finding 있음: 미커버 FAC를 분기 — (i) M-N이 *약속한* FAC의 구현 누락·버그이고 담당 task가 있으면 **현재 M-N에서 `/repair-milestone M-N`이 직접 수정**(단일 task 귀속이든 교차든 — ADR-068 D1); **담당 task 자체가 없으면**(정상적으론 plan-time `[Plan-FAC-coverage]` 100% 게이트가 막으므로 드묾) 현재 M-N의 미이행 약속으로 graduation `NO`를 유지하고 사용자에게 보고한다. 현재 M에 새 task를 자동·권장 생성하거나 FAC 취소로 거짓 통과시키지 않는다. 본 계약에 정해진 자동 해소 경로는 없으며 사용자 판단을 기다린다. (ii) *새 기능·기획 변경*(M-N 약속 아님)이면 다음 마일스톤(M-(N+1)), (iii) 계획이 근본적으로 잘못됐으면 자동 수정 없이 **사용자 중단·보고** (ADR-057#amend-3 결정 6 — F-NNN 재계획 경로 없음)
       - `[Doc-link]` / `[ADR-ref]` 등 문서 정합 P0: 사용자 직접 수정 (architect 또는 메인)
       - **e2e blocked-on-env (ENVIRONMENT failure)**: real failure가 아니므로 repair 대상 아님 — 사용자에게 환경 복구(브라우저 설치 / 앱 기동 / E2E MCP 등재·access)를 안내하고 환경 복구 후 `/stabilize-milestone M-N` 재실행 권장.
     - **공통 프롬프트 동봉 권장**:
       - 미해결 P0/P1 라벨 목록 (다음 호출의 우선 처리 대상)
       - Cross-stabilize 회귀 신호 항목 (있으면 — patterned drift 경고)
       - 본 마일스톤의 instruction improvement 후보 (있으면 — 다음 stabilize 라운드에서 회수)

책임 경계:
- 코드 수정·커밋·workitem status 변경 금지.
- 누적 문서 갱신 + milestone `## 8. 회고` 자동 채움 — **회고의 `graduation:` 줄은 §1.5의 정적 항목 값(item 1·4)과 단계 3~6의 동적 항목 값(item 2·3·5·6)을 합쳐 단계 8에서 1회만 기록한다**(ADR-068 D3·D4). **§1.5의 정적 값을 여기서 재계산하지 않는다** — 본 skill이 단계 4~6에서 QA_FINDINGS·IMPROVEMENT_GUIDE를 쓰므로 재계산하면 자기 쓰기가 판정에 섞인다. 값은 `YES|PENDING_ACCEPTANCE|NO|BLOCKED`+날짜 4종이며 우선순위는 `BLOCKED` > `NO` > `PENDING_ACCEPTANCE` > `YES`다.
  - **item 4만 미충족이고 1·2·3·5가 전부 충족이면 `PENDING_ACCEPTANCE (관측 AC 미발급: <task-id>:AC-N 목록)`** 으로 기록한다 — `NO`로 쓰지 않는다.
  - **감사 미완이 있으면 `BLOCKED (audit incomplete: <축>)`**, e2e 환경 불가면 `BLOCKED (e2e blocked-on-env: <target>)`. 이 값은 이전 라운드의 `YES`·`PENDING_ACCEPTANCE`를 덮어쓴다.
  - P0 기준은 `QA_FINDINGS.md`의 미해소 P0만 반영한다(성격 기준으로 등재된 결함 — 보고자 무관, ADR-070 D7).
  - 회고의 `open 항목 스냅샷:` 줄도 여기서 채운다(ADR-068 D5).
  - **회고의 `post-close 수정:` 줄도 여기서 채운다 (ADR-068 D5)** — `IMPROVEMENT_GUIDE.md` `## 5. Repair decision log`의 본 마일스톤 `### M-N` 그룹 항목 수를 세고 각 항목의 `scope:` 값으로 in-AC/out-of-AC를 분해한다. 그룹이 없으면 `없음`.
  - 로드맵 파일은 안 건드린다(다음 plan-milestone R0가 이 줄을 읽어 재조정).
- *상세 SSOT 는 본 skill 도입부 책임 경계 단락* — 본 단락은 단순 재확인.

E2E는 단계 3-a의 *필요성 판정*으로 결정한다 — e2e 불필요(비-UI ∧ graduation item 6 미선언) 마일스톤만 통합 `validate`만 돌리고 e2e를 skip한다(사유 출력 명시). **e2e 필요 마일스톤은 silent-skip 금지** — `validate:e2e`를 반드시 실행하고, 미통과(real) 시 졸업 hard-block, 실행 불가(env) 시 사용자 환경 복구 안내(ADR-052).

## Dependency hygiene
> 실행 시점: 단계 4~5(qa·reviewer 위임)와 함께 수행하고 결과를 단계 8 최종 출력 *전에* IMPROVEMENT_GUIDE 에 기록한다 — 본 섹션이 문서 끝에 있다고 *마지막에* 실행하는 것이 아니다.
- `npm audit` / `pip-audit` (스택별 대응) 1회 실행. **Dart/Flutter 는 audit 에 정확히 대응하는 명령이 없어 아래 셋으로 나뉜다** — 목적이 서로 달라 하나로 묶어 보고하지 않는다. **셋 다 읽기 전용 경로만 쓰고, 도구를 설치하지 않는다**(본 skill 은 파일을 고치지 않는다). 미설치 도구는 그 항목만 skip 하고 사유를 출력에 명시한다(`Doc-link check skipped` 와 동형).
  - **갱신 가능 여부**: `flutter pub outdated` — 내장이고 `pubspec.lock` 을 바꾸지 않는다.
  - **미선언·미사용 의존**: `dart pub global run dependency_validator`. 미활성이면 skip + `dep hygiene skipped: dependency_validator not activated (dart pub global activate dependency_validator — 사용자/stack-guard 소관)`.
  - **취약점**: `pubspec.lock` 을 대상으로 `osv-scanner` 실행. 미설치면 skip + 사유 명시. **`dart pub get` 의 advisory 출력을 쓰려면 반드시 `--enforce-lockfile` 을 붙인다** — 플래그 없는 `pub get` 은 해결 결과를 `pubspec.lock` 에 **쓰므로** read-only 계약을 깨뜨린다. 플래그를 못 쓰는 환경이면 이 경로를 생략하고 `osv-scanner` 결과만 쓴다.
- 결과를 IMPROVEMENT_GUIDE.md에 P1 severity로 보고.
- 6개월 unused deps는 P2로 자동 등록.

## Context 정책 (ADR-019)
`반드시 먼저 읽을 파일`은 *최소 충분*. 추가 ADR/architecture 섹션은 task 본문에서 발화 시 인용 — 사전 fork-load 금지.
fan-out 병렬 오케스트레이션 정책은 [ADR-075](../../../docs/90-decisions/boilerplate/ADR-075-main-session-orchestration-v2.md) D2 정합.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.