@henry1981/nondev-harness-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,380 @@
1
+ ---
2
+ name: plan-nondev
3
+ description: Use when proceeding from clarify-nondev PRD 8-element output to a Plan 6-element schema for non-developer deliverables — SOP/QMS/compliance, audit/legal, rule·skill·harness revision, wiki filing/reference curation. Generates Plan with 지식 식별·부수 변화·도구·workflow·분기·앵커 라인. Triggers on "plan-nondev", "비개발자 plan", "Plan 6 항목", "plan 작성", "plan 단계 진입", "clarify 후속". Skip for programming tasks (use superpowers:writing-plans), single-unit tasks (한 줄 수정·파일 1개 cp·메모리 항목 추가 등), or unresolved hb_judgment_required·open_questions (clarify-nondev로 회귀). PRD Lite cutoff 통과 케이스는 skip이 아니라 plan-nondev에 진입해 Plan Lite로 축약 산출한다.
4
+ ---
5
+
6
+ # Plan-nondev — 비개발자 작업 Plan 6 항목 schema 생성기
7
+
8
+ clarify-nondev §Output Format PRD 8 항목 markdown 본문을 입력으로 받아 PRD v2.4 §7 §단계 2 Plan 결정 6 항목 schema를 산출한다. 본 스킬은 PRD v2.4 §5 §단계 2 Plan = `plan-nondev` (재작성, 명칭 보존) 매핑 영역의 Plan 생성기 역할이다.
9
+
10
+ ## 언제 사용하는가
11
+
12
+ clarify-nondev 통과 직후 + 다음 4 조건 모두 충족 시:
13
+
14
+ - PRD 8 항목 (또는 PRD Lite 4 항목) 산출 완료
15
+ - PRD §9 신호등 5 항목 self-check 전 항목 녹
16
+ - clarify-nondev hb_judgment_required 영역 모두 closure
17
+ - HB 명시 신호 ("이제 plan 가자" 또는 자동 진입 default)
18
+
19
+ ## 언제 사용 금지
20
+
21
+ - 프로그래밍 작업 (코드 구현·bug fix·리팩토링) → `superpowers:writing-plans`
22
+ - 단건 작업 (검증 단위 1개) → 직접 진행, plan 불필요
23
+ - clarify-nondev hb_judgment_required·open_questions 잔존 → clarify-nondev로 회귀
24
+ - 의료기기 인허가 도메인 진입 → `medical-device-ra-qa-frame`이 Plan 영역도 흡수
25
+
26
+ ## 전제·의존성
27
+
28
+ 본 스킬 성립 전제 4종. 위반 시 §Step 1 진입 차단 또는 §Step 3 review_gate metadata 작성 실패.
29
+
30
+ 1. **clarify-nondev PRD 8 항목 선행**: 입력 계약은 clarify-nondev §Output Format PRD 8 항목 markdown 본문 (또는 PRD Lite 4 항목). 입력 누락 시 §Step 1 진입 차단 + clarify-nondev 회귀 안내
31
+ 2. **PRD v2 본문 실존**: `docs/superpowers/specs/2026-05-14-nondev-harness-prd-v2.md` §7 §단계 2 Plan 결정 6 항목 line 122~133 영역 본문 보존 (v2.4 ship 시점 실측 기준)
32
+ 3. **deliverable-review 스킬 실존**: Plan artifact 생성 후 execute 진입 전 `/deliverable-review target={plan} subtype=plan` 게이트 호출 의무
33
+ 4. **skill-creator 경유 개정**: 본 스킬 수정 시 반드시 `skill-creator` 경유 (rules/workflow.md §스킬 수정)
34
+
35
+ ---
36
+
37
+ ## Workflow — 6 Step
38
+
39
+ 각 Step은 §Question Quality Pre-Self-Check 3 체크를 선행 통과해야 질문 출력. 전체 라운드 상한 3 (Step 1 진입 차단·Step 3 분기 결정·Step 5 review_gate 결정 합계).
40
+
41
+ ### Step 1 — 진입 판정
42
+
43
+ clarify-nondev PRD 8 항목 산출물 read. mismatch 3 case 점검:
44
+
45
+ | case | trigger | 처리 |
46
+ |---|---|---|
47
+ | 1 | PRD §9 신호등 황 1+ | 진입 차단. clarify-nondev §Step 5 영역 회귀 안내 |
48
+ | 2 | PRD §9 신호등 적 1+ | 진입 차단. PRD 미완성 — clarify-nondev §Step 4 회귀 또는 HB 명시 신호 대기 |
49
+ | 3 | PRD §4 GT 자산 경로 0건 | 경고 후 진입 (HB 수동 보강 신호 — 본 plan에서 §workflow read-only refs 누락 가능성) |
50
+
51
+ case 1·2면 회귀 후 종료. case 3는 §Step 3에서 workflow read-only refs 영역에 HB 보강 의무 명시.
52
+
53
+ ### Step 2 — Plan 결정 6 항목 채우기 source 확보
54
+
55
+ clarify-nondev PRD 8 항목 영역에서 Plan 6 항목 채우기 source 추출:
56
+
57
+ | Plan 항목 | PRD source | 추출 방법 |
58
+ |---|---|---|
59
+ | 지식 식별·리서치 계획 | PRD §4 지식 요구사항 (GT + 참조) | GT 경로 → 구체 자산. 부족 영역은 본 Step에서 조달 |
60
+ | 부수 변화 문서 식별 | PRD §6 산출물 ↔ 참조 연계 역할 | 본문 직접 인용 / 구조 틀 / 검증 기준 3 역할 영역의 영향 문서 하이라키 |
61
+ | 도구 영역 | PRD §5 산출물 형태 | 산출물 형태에 맞는 도구 — 예: "docx 생성", "Notion MCP", "Edit·Write", "humanize-monolith" |
62
+ | workflow | PRD §7 스킬 (계획-구현-검증 흐름) | 순서·step 시퀀스 + 의존성. 하위 필수 항목 — 실행 boundary 7건 (Step 3) |
63
+ | 분기 | PRD §8 제약 | 외부 입력·partial 수령·변형 대응. 시간 압박 trade-off 3-layer (PRD §3) 포함 |
64
+ | 앵커 라인 | PRD §2 작업 목표 + §5 산출물 | 다음 한 동작 (cold-start 진입점) |
65
+
66
+ ### Step 3 — Plan 결정 6 항목 채우기 (실행 boundary 명시)
67
+
68
+ 6 항목 순차 채우기. 본 cycle 핵심 산출 영역.
69
+
70
+ #### 3-1. 지식 식별·리서치 계획
71
+
72
+ - PRD §4 GT 자산 경로 → 구체 라인·섹션·코드 수준까지 specify
73
+ - 부족 영역 — Plan 진행 중 추가 조달 계획 명시 (예: "RWE SOP DP1101 §5.3.2 영역 추가 read")
74
+
75
+ #### 3-2. 부수 변화 문서 식별
76
+
77
+ - 본 산출물이 영향 주는 문서 하이라키 명시
78
+ - 예: SOP 개정 시 → SOP 본문 + changelog + index + 하위 절차서 정합 영역
79
+
80
+ #### 3-3. 도구 영역
81
+
82
+ - 산출물 형태에 맞는 도구 *영역*만 명시 (구체 함수·라이브러리는 execute-nondev 자율 영역)
83
+ - 예: "docx 생성", "Notion MCP 본문 patch", "Edit·Write tool"
84
+
85
+ #### 3-4. workflow — 실행 boundary 7건 의무
86
+
87
+ 순서·step 시퀀스 + 의존성. **하위 필수 항목 7건** (PRD §7 §단계 2 정합 + execute-nondev 자율 영역 cap):
88
+
89
+ | # | 항목 | 정의 |
90
+ |---|---|---|
91
+ | (a) | **cwd** | 작업 디렉토리 (예: `/Users/hb/Project/KHC`) |
92
+ | (b) | **write scope** | 수정 대상 파일·디렉토리 명시 (예: `rwe-vendor-audit/sop/DP1101.md` + changelog) |
93
+ | (c) | **read-only refs** | 읽기 전용 참조 영역 (GT 자산·rules·prior cycle artifact) |
94
+ | (d) | **branch/worktree policy** | 현 branch 직접 작업 vs worktree 신설 (Cross-platform rule 영역 — `rules/workflow.md` §Worktree Setup 정합) |
95
+ | (e) | **commit grouping** | commit 단위 — step별 1 commit / Task별 1 commit / 일괄 1 commit |
96
+ | (f) | **no-touch paths** | 건드리지 말아야 할 경로 (security·legacy·read-only refs 영역) |
97
+ | (g) | **external visibility** | 외부 발신 영역 — 본 산출물이 외부 수신자(스폰서·규제·계약·법률·audit·벤더)에게 보내지는지 |
98
+
99
+ 7건 모두 명시 의무. execute-nondev *도구 자율 허용*이 branch·commit·파일 범위 자율화로 확장되지 않도록 cap.
100
+
101
+ #### 3-5. 분기
102
+
103
+ - 외부 입력·partial 수령·변형 대응 영역 명시
104
+ - 시간 압박 trade-off 3-layer (PRD §3 line 41~45 영역 인용) — Never sacrifice / Can compress first / Escalate to HB when
105
+ - 외부 입력 도착 시 인터럽트 처리 영역 (PRD §7 §단계 3 정합)
106
+
107
+ #### 3-6. 앵커 라인
108
+
109
+ - 다음 한 동작 명시 (cold-start 진입점)
110
+ - 예: "rwe-vendor-audit/sop/DP1101.md §5.3.2 영역 patch 진입"
111
+
112
+ ### Step 4 — Plan artifact 산출
113
+
114
+ §Output Format Plan 6 항목 markdown 본문 산출. frontmatter + 6 항목 본문 + 변경 이력.
115
+
116
+ **Plan artifact 생성 직후 execute 진입 X — Step 5 review_gate 게이트 의무 영역**.
117
+
118
+ ### Step 5 — Plan artifact review gate + review_gate metadata 기록
119
+
120
+ Plan artifact 생성 후 execute 진입 전 의무:
121
+
122
+ `/deliverable-review target={plan path} subtype=plan` 게이트 호출.
123
+
124
+ **review_gate metadata schema 의무** (codex r7 P1.1 + r9 P1.1 + r10 P1.2 + r11 P1.2 정합):
125
+
126
+ ```yaml
127
+ review_gate:
128
+ status: pending | pass | revise-minor | revise-major | block
129
+ reviewed_at: YYYY-MM-DD
130
+ reviewer: deliverable-review
131
+ review_target: path/to/plan.md
132
+ review_evidence: path/to/review.md 또는 "inline: §Review Gate"
133
+ closure_note: "" # revise-minor 시 closure 영역 명시 의무
134
+ reviewed_revision: "§변경 이력 row id 또는 version" # codex r9 P1.1 freshness anchor (primary, required)
135
+ plan_fingerprint: "sha256:<canonical-plan-hash>" # codex r10 P1.2 — optional diagnostic
136
+ ```
137
+
138
+ **`plan_fingerprint` canonical hash 정의** (codex r10 P1.2 — self-invalidating 차단):
139
+
140
+ - canonical body = Plan 본문 *전체*에서 다음 volatile 영역을 *제외*한 영역의 sha256:
141
+ - `review_gate` metadata block 전체 (status·reviewed_at·review_evidence·closure_note·reviewed_revision·plan_fingerprint 모두)
142
+ - generated review report path 영역 (Step 5에서 생성된 review.md 경로)
143
+ - frontmatter `updated` timestamp + Revision History row의 자동 갱신 timestamp 영역
144
+ - 기타 volatile review bookkeeping 영역
145
+ - 본 정의로 `plan_fingerprint` 기록이 자기 자신을 무효화하지 X (review_gate 영역이 hash 대상에서 제외)
146
+ - fallback `lines:<N>+modified_at:<ISO8601>` 영역도 동일 canonical body 영역 기준
147
+
148
+ **primary freshness key는 `reviewed_revision`** — hash 산식 재현 어려운 환경에서는 reviewed_revision만으로 freshness 검증 가능. plan_fingerprint는 optional diagnostic.
149
+
150
+ **review 결과별 분기**:
151
+
152
+ | Recommendation | Signal | review_gate.status | 처리 |
153
+ |---|---|---|---|
154
+ | ship | green | pass | execute-nondev 진입 |
155
+ | revise-minor | yellow | revise-minor | closure_note 채움 + Plan patch + 재게이트 또는 closure_note 명시 후 execute 진입 |
156
+ | revise-major | red (default) | revise-major | reviewer 본문에 *"Plan-only yellow downgrade 가능"* 근거 명시 시 Plan patch + 재게이트, 그 외 HB/PRD 회귀 |
157
+ | block | red | block | HB/PRD 회귀 (Plan 수정만으로 진입 X) |
158
+
159
+ **`pass` 영역 조건** (codex r8 P1.2 + P2.3 정합): `Signal=green` AND `Recommendation=ship` 시만 `review_gate.status: pass` 기록.
160
+
161
+ **무조건 red 영역** (recommendation과 무관):
162
+ - source_fidelity FAIL — 인용 정확성·원문 대조 실패
163
+ - regulatory correctness FAIL — 법규·SOP·고시 정합 실패
164
+ - explicit HB judgment boundary 침범 — HB 결정 영역 자율 처리
165
+
166
+ ### Step 6 — 다음 흐름 진입 (execute-nondev)
167
+
168
+ Step 5 review_gate `status: pass` (또는 `revise-minor` + closure_note 채움) 영역 진입 후 execute-nondev 호출.
169
+
170
+ `Skill execute-nondev plan={Plan artifact 경로}`.
171
+
172
+ unreviewed Plan으로 execute 진입 X — execute-nondev §1 입력 조건이 Plan frontmatter `review_gate` metadata catch + freshness 검증.
173
+
174
+ ---
175
+
176
+ ## Output Format — Plan 6 항목 markdown 본문
177
+
178
+ Step 4 산출. PRD `docs/superpowers/specs/2026-05-14-nondev-harness-prd-v2.md` §7 §단계 2 본문 형식 답습.
179
+
180
+ ````markdown
181
+ ---
182
+ title: {Topic} Plan
183
+ type: plan
184
+ status: active
185
+ created: YYYY-MM-DD
186
+ updated: YYYY-MM-DD
187
+ prd: docs/.../YYYY-MM-DD-{topic}-prd.md
188
+ input_prd_version: v{x.y}
189
+ related_paths:
190
+ - {PRD 경로}
191
+ - {GT 자산 경로 1}
192
+ - {GT 자산 경로 2}
193
+ review_gate:
194
+ status: pending # Step 5 게이트 후 갱신
195
+ reviewed_at: ""
196
+ reviewer: deliverable-review
197
+ review_target: ""
198
+ review_evidence: ""
199
+ closure_note: ""
200
+ reviewed_revision: ""
201
+ plan_fingerprint: "" # optional diagnostic — value 존재 시만 비교, 부재만으로는 fail-closed X
202
+ ---
203
+
204
+ # {Topic} Plan
205
+
206
+ ## 1. 지식 식별·리서치 계획
207
+
208
+ - GT 자산: {경로 1} (라인 영역 X~Y)
209
+ - GT 자산: {경로 2}
210
+ - 참조: {경로 3}
211
+ - 부족 영역 조달: {Plan 진행 중 추가 조달 계획}
212
+
213
+ ## 2. 부수 변화 문서 식별
214
+
215
+ - {본 산출물}이 영향 주는 문서 하이라키:
216
+ - 직접 인용 영역: {문서 1}
217
+ - 구조 틀 영역: {문서 2}
218
+ - 검증 기준 영역: {문서 3}
219
+
220
+ ## 3. 도구 영역
221
+
222
+ - {도구 영역 1 — 예: "docx 생성"}
223
+ - {도구 영역 2 — 예: "Notion MCP 본문 patch"}
224
+
225
+ ## 4. Workflow
226
+
227
+ **실행 boundary 7건** (PRD §7 §단계 2 정합):
228
+ - **cwd**: `{작업 디렉토리}`
229
+ - **write scope**: `{수정 대상 1}`, `{수정 대상 2}`
230
+ - **read-only refs**: `{참조 1}`, `{참조 2}`
231
+ - **branch/worktree policy**: `{현 branch | worktree 신설}`
232
+ - **commit grouping**: `{step별 1 commit | Task별 1 commit | 일괄 1 commit}`
233
+ - **no-touch paths**: `{건드리지 말아야 할 경로}`
234
+ - **external visibility**: `{외부 발신 X | {수신자 명시}}`
235
+
236
+ **Step 시퀀스**:
237
+ 1. {Step 1 — 작업 내용}
238
+ 2. {Step 2 — 작업 내용}
239
+ 3. {Step 3 — 작업 내용}
240
+ 4. {Step 4 — deliverable-review 게이트 (subtype 명시)}
241
+ 5. {Step 5 — commit}
242
+
243
+ **의존성**:
244
+ - Step 2 → Step 3 (출력 영역 의존)
245
+ - Step 4 → Step 5 (review PASS 후 commit)
246
+
247
+ ## 5. 분기
248
+
249
+ - {외부 입력 대응 1}: {처리 방향}
250
+ - {partial 수령 대응 1}: {처리 방향}
251
+ - **시간 압박 trade-off 3-layer** (PRD §3 정합):
252
+ - Never sacrifice: source fidelity·regulatory correctness·HB judgment boundaries
253
+ - Can compress first: optional polish·nonessential automation·broad research·secondary docs
254
+ - Escalate to HB when: Never sacrifice 영역 흔들림 시점
255
+
256
+ ## 6. 앵커 라인
257
+
258
+ **다음 한 동작**: {cold-start 진입점 — 구체 파일·구체 동작}
259
+
260
+ ## 7. 변경 이력
261
+
262
+ | 버전 | 일자 | 변경 요지 | 사유 |
263
+ |---|---|---|---|
264
+ | v1.0 | YYYY-MM-DD | 신규 작성 (plan-nondev 산출) | {사유} |
265
+ ````
266
+
267
+ ---
268
+
269
+ ## 산출물 위치
270
+
271
+ Plan 산출물 위치는 PRD 산출물 위치 영역과 정합:
272
+
273
+ - **PRD가 RWE Vendor Audit·SOP·compliance 도메인** → `{project}/plans/YYYY-MM-DD-{topic}-plan.md`
274
+ - **PRD가 비개발자 하네스·rules·skill 영역** → `docs/superpowers/plans/YYYY-MM-DD-{topic}-plan.md`
275
+ - **PRD가 drafts 영역** → `drafts/{topic}/plans/YYYY-MM-DD-{topic}-plan.md`
276
+
277
+ frontmatter `related_paths`에 PRD 경로 + GT 자산 경로 + 후속 handoff 경로 등록 의무.
278
+
279
+ ---
280
+
281
+ ## 다음 흐름 진입
282
+
283
+ Step 5 review_gate PASS 후 다음 흐름 — **execute-nondev 진입 default**.
284
+
285
+ unreviewed Plan으로 execute 진입 X — execute-nondev §1 입력 조건이 Plan frontmatter `review_gate.status: pass` (또는 `revise-minor` + closure_note 채움) + `reviewed_revision` freshness 검증 catch.
286
+
287
+ *직접 작업* 영역은 다음 5 조건 모두 충족 시에만 허용 (clarify-nondev §다음 흐름 진입 영역 정합):
288
+ 1. repo 변경 X
289
+ 2. 외부 발신 X
290
+ 3. 산출물 생성 X
291
+ 4. 기존 문서 조회·단순 답변 영역
292
+ 5. HB 명시 승인
293
+
294
+ 5 조건 중 1건이라도 X면 execute-nondev 강제 흐름 의무.
295
+
296
+ ---
297
+
298
+ ## Plan Lite (cutoff 통과 영역)
299
+
300
+ clarify-nondev Step 3에서 PRD Lite cutoff 4 조건 모두 충족 영역 시 Plan Lite 축약본 산출.
301
+
302
+ Plan Lite 항목 — Plan 6 항목 중 핵심 3 항목:
303
+ 1. **workflow** (실행 boundary 7건은 의무 — write scope·external visibility·commit grouping은 strict)
304
+ 2. **분기** (단순 분기 영역만)
305
+ 3. **앵커 라인** (다음 한 동작)
306
+
307
+ 지식 식별·부수 변화·도구 영역은 PRD Lite 4 항목에서 inline 흡수.
308
+
309
+ **Plan Lite도 review_gate metadata는 의무** (면제되는 것은 full 8-field 정식 작성뿐): cutoff 4 조건 모두 충족 시 review_gate metadata는 simplified schema로 기록 — `status: pass` + `reviewed_revision: v1.0` + `closure_note: "Plan Lite — cutoff 4 조건 통과"`를 명시하고 나머지 필드는 기본값으로 채운다 (`reviewed_at` = 작성일 · `reviewer: deliverable-review` · `review_target` = Plan 경로 · `review_evidence: ""` · `plan_fingerprint: ""`). metadata block 자체를 생략하지 않는다 — execute-nondev §Step 1 입력 조건이 review_gate를 catch하기 때문이다.
310
+
311
+ **Plan artifact review gate 대체**: Plan Lite 경로에서는 §Step 5의 `/deliverable-review subtype=plan` 명시 호출(또는 plan 호출자가 명시한 Plan review gate — 예: PRD 구현 plan의 Task별 Plan review step)이 위 simplified review_gate 기록으로 대체된다. cutoff 4 조건 충족이 이미 검증 부담 축약을 정당화하므로, Plan Lite는 deliverable-review 실제 dispatch 없이 simplified `status: pass`로 execute 진입한다. 단 execute-nondev §Step 6의 *산출물* deliverable-review 게이트는 Plan Lite 여부와 무관하게 그대로 의무다 — 본 대체는 *Plan artifact* review gate에만 적용된다.
312
+
313
+ ---
314
+
315
+ ## Escape Hatches
316
+
317
+ 4종. 라운드 상한 도달 이전이어도 조건 만족 시 바로 발동.
318
+
319
+ - **명확하면 스킵**: clarify-nondev PRD 8 항목 + GT + 모든 결정 closure → Step 1·2 자동 통과, Step 3·4·5 진행
320
+ - **라운드 상한 도달 (3라운드)**: "현재까지 채워진 Plan 6 항목으로 진행할까요, 아니면 추가 라운드 필요할까요?" HB 1줄 선택
321
+ - **HB 통찰로 boundary 재정의 요청**: HB가 "write scope 다시 보자" / "branch 영역 재검토" 등 신호 감지 시 → 즉시 현재 항목 중단 + boundary 재검토 진입
322
+ - **HB 스킵 신호**: "그냥 바로 execute 가" 신호 → Step 5 review_gate 게이트만 진행 + Plan 본문 simplified
323
+
324
+ ---
325
+
326
+ ## Question Quality Pre-Self-Check
327
+
328
+ **매 질문 출력 전** LLM 자가 체크 3종. 3 체크 모두 통과해야 질문 출력. 하나라도 fail이면 질문 출력 중단 + fail 대응 절차 실행.
329
+
330
+ ### 체크 1 — 본질 관련성
331
+
332
+ - 이 질문이 (a) Plan 진입 판정 / (b) Plan 6 항목 채우기 / (c) review_gate metadata 결정 중 하나에 직접 영향을 주는가?
333
+ - 아니면 본질무관질문 → **출력 금지**. 해당 정보가 진짜 필요하면 LLM이 직접 탐색(Read·Glob·Grep·wiki query)으로 보완
334
+
335
+ ### 체크 2 — 로컬 탐색 선행
336
+
337
+ - 이 질문의 답을 Read·Glob·Grep·wiki query로 LLM이 직접 확인 가능한가?
338
+ - 가능하면 **먼저 탐색** → 탐색 결과 바탕으로 질문 재평가 → 여전히 HB 판단 필요 시에만 질문 출력
339
+ - "로컬 탐색 없이 추정 질문"은 HB 명시 안티패턴
340
+
341
+ ### 체크 3 — 1라운드 1질문 원칙
342
+
343
+ - 이 응답에 출력할 질문이 2개 이상인가?
344
+ - 2개 이상이면 가장 의존도 높은(앞 답이 뒷 옵션 바꿀) 1건만 선택. 나머지는 다음 라운드로
345
+
346
+ ---
347
+
348
+ ## Red Flags — STOP and run Pre-Self-Check
349
+
350
+ 질문 출력 직전 다음 생각이 들면 **STOP**. 세 체크 전부 다시 돌려라.
351
+
352
+ | 합리화 | 실제 |
353
+ |---|---|
354
+ | "Plan 6 항목 중 1~2개 생략해도 된다" | execute-nondev 입력 계약 위반. 해당 없으면 명시적 "해당 없음" 표기 |
355
+ | "실행 boundary 7건 중 5건만 명시해도 된다" | 7건 모두 의무. execute-nondev 자율 영역 cap 차단 |
356
+ | "review_gate metadata는 commit 후 적용" | review_gate는 *execute 진입 전* 의무. metadata 부재 시 fail-closed |
357
+ | "Plan-only yellow downgrade는 자유롭게 가능" | reviewer 본문에 *명시 근거* 명시 후에만 가능. 그 외 revise-major → HB/PRD 회귀 |
358
+ | "여러 가능성 다 물어보자" | 체크 3 위반. 1라운드 1질문 원칙 |
359
+
360
+ ---
361
+
362
+ ## Rationalization Counters
363
+
364
+ | 합리화 | 반박 |
365
+ |---|---|
366
+ | "Plan 본문 작성 후 execute 바로 진입" | review_gate Step 5 의무. unreviewed Plan execute 진입 X |
367
+ | "review_gate metadata schema 일부 필드 생략" | 8 필드 모두 의무 (status·reviewed_at·reviewer·review_target·review_evidence·closure_note·reviewed_revision·plan_fingerprint) — plan_fingerprint만 optional diagnostic |
368
+ | "실행 boundary write scope 광범위하게 명시" | write scope는 *수정 대상 파일·디렉토리 명시* — 범위 모호 시 execute-nondev 자율 확장 risk. 구체 path까지 명시 |
369
+ | "외부 발신 visibility는 외부 발신 시만 명시" | external visibility 항목은 *외부 발신 X 영역도 명시 의무* — "외부 발신 X" 명시. 빈 영역 X |
370
+ | "분기 영역 빠뜨려도 execute에서 catch" | 분기 명시 X 시 yellow state machine 발동 — Plan 갱신 round 추가. 사전 명시가 비용 절약 |
371
+ | "Plan Lite는 review_gate도 생략" | Plan Lite도 review_gate metadata 기록은 의무 — simplified schema 적용 (deliverable-review 실제 dispatch는 면제되나 metadata block 자체 기록은 의무). PRD Lite cutoff 4 조건 통과 시만 |
372
+
373
+ ---
374
+
375
+ ## Notes
376
+
377
+ - **PRD v2.4 매핑**: 본 스킬은 PRD `docs/superpowers/specs/2026-05-14-nondev-harness-prd-v2.md` §5 §단계 2 Plan = `plan-nondev` (재작성, 명칭 보존) 매핑 영역. PRD §7 §단계 2 Plan 결정 6 항목 line 122~133 정의 + §단계 3 Execute 통제 강도 line 135~145 정의를 본 스킬 출력에 직접 흡수
378
+ - **이전 본문 차이**: 이전 본문 (Direction Layer adapter 영역의 5요소 schema → thin issue) 폐기. 신규 본문은 PRD §단계 2 Plan 결정 6 항목 schema 직접 생성기 영역
379
+ - **dogfood 영역**: 본 스킬 첫 dogfood는 본 cycle Task 4 (execute-nondev 신규 작성) plan 또는 Task 5 (deliverable-review 개정) plan 영역. plan v1.2 (drafts/nondev-harness/plans/2026-05-14-prd-v2-self-application-plan.md, *Plan 작성 스킬 부재* evidence pack)와 신규 plan-nondev 산출물 비교 영역은 별도 dogfood cycle로 carry-forward
380
+ - **개정 규율**: 본 스킬 수정 시 반드시 `skill-creator` 경유 (rules/workflow.md §스킬 수정)
@@ -0,0 +1,50 @@
1
+ # PRD Formatter MVP
2
+
3
+ PRD v2.4 §5 §보조 산출물 영역 — frontmatter·history·source·related_paths·8 영역 자동 검증.
4
+
5
+ ## Scope
6
+
7
+ - (a) frontmatter version·updated·supersedes 검증
8
+ - (b) §10 revision history row 영역 검증
9
+ - (c) source_session·related_paths 실제 path 존재 영역 확인
10
+ - (d) PRD 8 영역 (§1~§8) 누락 여부 체크
11
+ - (e) **문장 rewriting·품질 판단 영역 X** (humanize-monolith·deliverable-review 영역)
12
+
13
+ ## Usage
14
+
15
+ ```python
16
+ from prd_formatter import (
17
+ check_frontmatter, check_revision_history, check_source_session,
18
+ check_related_paths, check_eight_sections,
19
+ )
20
+ from pathlib import Path
21
+
22
+ # tools/prd-formatter cwd 기준 — repo root는 부모×2
23
+ repo_root = Path("../..").resolve()
24
+ target = repo_root / "docs/superpowers/specs/2026-05-14-nondev-harness-prd-v2.md"
25
+ content = target.read_text()
26
+
27
+ print(check_frontmatter(content).passed)
28
+ print(check_revision_history(content, "v2.4").passed)
29
+ print(check_source_session(content, base_path=repo_root).passed)
30
+ print(check_related_paths(content, base_path=repo_root).passed)
31
+ print(check_eight_sections(content).passed)
32
+ ```
33
+
34
+ ## Dependencies
35
+
36
+ PEP 668 환경(macOS Homebrew Python 등)에서는 venv 사용을 권장한다.
37
+
38
+ ```bash
39
+ python3 -m venv .venv
40
+ .venv/bin/pip install -r requirements.txt
41
+ # 또는 직접: .venv/bin/pip install PyYAML pytest
42
+ ```
43
+
44
+ ## Test
45
+
46
+ ```bash
47
+ .venv/bin/python -m pytest test_prd_formatter.py -v
48
+ ```
49
+
50
+ Expected: 8 passed.
@@ -0,0 +1,118 @@
1
+ """PRD formatter MVP — PRD v2.4 §5 §보조 산출물 영역.
2
+
3
+ Scope cap (PRD v2.4 §5 정합):
4
+ - (a) frontmatter version·updated·supersedes 검증
5
+ - (b) §10 revision history row 추가 또는 검증
6
+ - (c) source_session·related_paths 존재 영역 확인
7
+ - (d) PRD 8 영역 누락 여부 체크
8
+ - (e) 문장 rewriting·품질 판단은 formatter 범위 밖
9
+ """
10
+ from dataclasses import dataclass, field
11
+ from pathlib import Path
12
+ from typing import Optional
13
+ import re
14
+ import yaml
15
+
16
+
17
+ @dataclass
18
+ class PRDFormatterResult:
19
+ passed: bool
20
+ findings: list[str] = field(default_factory=list)
21
+
22
+
23
+ def _parse_frontmatter(content: str) -> Optional[dict]:
24
+ """YAML frontmatter 영역 parse."""
25
+ match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
26
+ if not match:
27
+ return None
28
+ try:
29
+ return yaml.safe_load(match.group(1))
30
+ except yaml.YAMLError:
31
+ return None
32
+
33
+
34
+ def check_frontmatter(content: str) -> PRDFormatterResult:
35
+ """frontmatter version·updated·supersedes 영역 검증."""
36
+ fm = _parse_frontmatter(content)
37
+ if fm is None:
38
+ return PRDFormatterResult(passed=False, findings=["frontmatter parse 실패"])
39
+
40
+ findings = []
41
+ for required in ["version", "updated", "supersedes"]:
42
+ if required not in fm:
43
+ findings.append(f"frontmatter {required} 누락")
44
+
45
+ return PRDFormatterResult(passed=len(findings) == 0, findings=findings)
46
+
47
+
48
+ def check_revision_history(content: str, expected_version: str) -> PRDFormatterResult:
49
+ """§10 revision history 영역에 expected_version row 영역 검증."""
50
+ history_match = re.search(
51
+ r"##\s+10\.\s+본\s+PRD\s+변경\s+이력.*?(?=^##|\Z)",
52
+ content,
53
+ re.DOTALL | re.MULTILINE,
54
+ )
55
+ if not history_match:
56
+ return PRDFormatterResult(passed=False, findings=["§10 변경 이력 section 미발견"])
57
+
58
+ history_body = history_match.group(0)
59
+ if expected_version not in history_body:
60
+ return PRDFormatterResult(
61
+ passed=False,
62
+ findings=[f"§10에 {expected_version} row 누락"],
63
+ )
64
+
65
+ return PRDFormatterResult(passed=True)
66
+
67
+
68
+ def check_source_session(content: str, base_path: Path) -> PRDFormatterResult:
69
+ """source_session 영역 실제 path 존재 검증."""
70
+ fm = _parse_frontmatter(content)
71
+ if fm is None or "source_session" not in fm:
72
+ return PRDFormatterResult(passed=False, findings=["source_session 누락"])
73
+
74
+ source = fm["source_session"]
75
+ sources = source if isinstance(source, list) else [source]
76
+
77
+ findings = []
78
+ for src in sources:
79
+ path = Path(src) if Path(src).is_absolute() else base_path / src
80
+ if not path.exists():
81
+ findings.append(f"source_session path 미존재: {src}")
82
+
83
+ return PRDFormatterResult(passed=len(findings) == 0, findings=findings)
84
+
85
+
86
+ def check_related_paths(content: str, base_path: Path) -> PRDFormatterResult:
87
+ """related_paths 영역 모든 path 실제 존재 검증 (PRD D6 영역)."""
88
+ fm = _parse_frontmatter(content)
89
+ if fm is None or "related_paths" not in fm:
90
+ return PRDFormatterResult(passed=False, findings=["related_paths 누락"])
91
+
92
+ paths = fm["related_paths"]
93
+ if not isinstance(paths, list):
94
+ return PRDFormatterResult(
95
+ passed=False,
96
+ findings=["related_paths 영역 list 아님"],
97
+ )
98
+
99
+ findings = []
100
+ for p in paths:
101
+ path = Path(p) if Path(p).is_absolute() else base_path / p
102
+ if not path.exists():
103
+ findings.append(f"related_paths path 미존재: {p}")
104
+
105
+ return PRDFormatterResult(passed=len(findings) == 0, findings=findings)
106
+
107
+
108
+ def check_eight_sections(content: str) -> PRDFormatterResult:
109
+ """PRD 8 영역 (§1~§8) 영역 검증."""
110
+ expected = ["1.", "2.", "3.", "4.", "5.", "6.", "7.", "8."]
111
+ findings = []
112
+
113
+ for num in expected:
114
+ pattern = rf"^##\s+{re.escape(num)}\s"
115
+ if not re.search(pattern, content, re.MULTILINE):
116
+ findings.append(f"§{num} section 누락")
117
+
118
+ return PRDFormatterResult(passed=len(findings) == 0, findings=findings)
@@ -0,0 +1,2 @@
1
+ PyYAML>=6.0
2
+ pytest>=7.0
@@ -0,0 +1,123 @@
1
+ import pytest
2
+ from pathlib import Path
3
+ from prd_formatter import (
4
+ check_frontmatter,
5
+ check_revision_history,
6
+ check_source_session,
7
+ check_related_paths,
8
+ check_eight_sections,
9
+ PRDFormatterResult,
10
+ )
11
+
12
+
13
+ def test_check_frontmatter_valid():
14
+ """Valid frontmatter — version·updated·supersedes 모두 present."""
15
+ content = """---
16
+ prd: test
17
+ version: v2.4
18
+ updated: 2026-05-14
19
+ supersedes: path/to/old.md
20
+ ---
21
+ # Test PRD
22
+ """
23
+ result = check_frontmatter(content)
24
+ assert result.passed
25
+ assert result.findings == []
26
+
27
+
28
+ def test_check_frontmatter_missing_version():
29
+ """frontmatter version 누락 영역."""
30
+ content = """---
31
+ prd: test
32
+ updated: 2026-05-14
33
+ ---
34
+ """
35
+ result = check_frontmatter(content)
36
+ assert not result.passed
37
+ assert any("version" in f for f in result.findings)
38
+
39
+
40
+ def test_check_revision_history_row_present():
41
+ """§10 revision history v2.4 row 영역."""
42
+ content = """## 10. 본 PRD 변경 이력
43
+
44
+ | 버전 | 일자 | 변경 요지 | 사유 |
45
+ |---|---|---|---|
46
+ | v2.0 | 2026-05-14 | 신규 | sample |
47
+ | v2.4 | 2026-05-14 | closure | test |
48
+ """
49
+ result = check_revision_history(content, expected_version="v2.4")
50
+ assert result.passed
51
+
52
+
53
+ def test_check_source_session_path_exists(tmp_path):
54
+ """source_session 영역 실제 존재 path 검증."""
55
+ sample_session = tmp_path / "sample.md"
56
+ sample_session.touch()
57
+ content = f"""---
58
+ source_session: {sample_session}
59
+ ---
60
+ """
61
+ result = check_source_session(content, base_path=tmp_path)
62
+ assert result.passed
63
+
64
+
65
+ def test_check_related_paths_all_exist(tmp_path):
66
+ """related_paths 영역 모든 path 실제 존재 검증."""
67
+ p1 = tmp_path / "spec.md"
68
+ p2 = tmp_path / "handoff.md"
69
+ p1.touch()
70
+ p2.touch()
71
+ content = f"""---
72
+ related_paths:
73
+ - {p1}
74
+ - {p2}
75
+ ---
76
+ """
77
+ result = check_related_paths(content, base_path=tmp_path)
78
+ assert result.passed
79
+
80
+
81
+ def test_check_related_paths_missing(tmp_path):
82
+ """related_paths 영역 일부 path 미존재 영역."""
83
+ p1 = tmp_path / "spec.md"
84
+ p1.touch()
85
+ content = f"""---
86
+ related_paths:
87
+ - {p1}
88
+ - {tmp_path}/does_not_exist.md
89
+ ---
90
+ """
91
+ result = check_related_paths(content, base_path=tmp_path)
92
+ assert not result.passed
93
+ assert any("does_not_exist" in f for f in result.findings)
94
+
95
+
96
+ def test_check_eight_sections_all_present():
97
+ """PRD 8 영역 (§1~§8) 모두 present."""
98
+ content = """## 1. 작업 유형
99
+ ## 2. 작업 목표
100
+ ## 3. 성공 판단 기준
101
+ ## 4. 지식 요구사항
102
+ ## 5. 산출물
103
+ ## 6. 산출물 ↔ 참조 연계 역할
104
+ ## 7. 비개발자 작업 4단계 흐름
105
+ ## 8. 제약
106
+ """
107
+ result = check_eight_sections(content)
108
+ assert result.passed
109
+
110
+
111
+ def test_check_eight_sections_missing():
112
+ """PRD 8 영역 중 §4 누락 영역."""
113
+ content = """## 1. 작업 유형
114
+ ## 2. 작업 목표
115
+ ## 3. 성공 판단 기준
116
+ ## 5. 산출물
117
+ ## 6. 연계 역할
118
+ ## 7. 흐름
119
+ ## 8. 제약
120
+ """
121
+ result = check_eight_sections(content)
122
+ assert not result.passed
123
+ assert any("§4" in f or "4." in f for f in result.findings)