okstra 0.101.0 → 0.102.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.
- package/docs/kr/architecture.md +1 -1
- package/docs/project-structure-overview.md +1 -1
- package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +542 -0
- package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +568 -0
- package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +203 -0
- package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +129 -0
- package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +185 -0
- package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +121 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +1 -0
- package/runtime/prompts/lead/report-writer.md +1 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -0
- package/runtime/prompts/profiles/final-verification.md +4 -3
- package/runtime/prompts/profiles/implementation-planning.md +12 -9
- package/runtime/python/okstra_ctl/report_views.py +39 -3
- package/runtime/python/okstra_ctl/run.py +0 -1
- package/runtime/schemas/final-report-v1.0.schema.json +106 -3
- package/runtime/skills/okstra-container/SKILL.md +1 -1
- package/runtime/templates/reports/final-report.template.md +63 -2
- package/runtime/templates/reports/final-verification-input.template.md +3 -3
- package/runtime/templates/reports/i18n/en.json +28 -1
- package/runtime/templates/reports/i18n/ko.json +28 -1
- package/runtime/templates/reports/report.css +10 -0
- package/runtime/templates/reports/report.js +16 -0
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +70 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Manual User Test Section Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** implementation 리포트가 사람이 손으로 확인하는 테스트 절차 초안을 산출하고, final-verification 리포트가 그 초안을 수행·확정하도록, 양쪽 산출물에 "Manual User Test" 섹션을 신설한다.
|
|
6
|
+
|
|
7
|
+
**Architecture:** 기존 §5.7/§5.8 deliverable 섹션과 동형(data-driven Jinja 섹션 + 영어 제목 하드코딩 + i18n 라벨/빈상태 + validate-run.py substring 강제). implementation 이 `implementation.manualUserTest` 초안을, final-verification 이 `finalVerification.manualUserTest` 결과를 채운다.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Jinja 템플릿(final-report.template.md), Python validator(validate-run.py), JSON i18n(en/ko), markdown 프로파일(prompts/), pytest.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- 산출물은 한/영 양 언어로 렌더된다 — 섹션 **제목은 영어 하드코딩**(기존 §5.7.x 와 동일), 라벨/빈상태는 `t("manualUserTest.*")` i18n 키로. 영어 렌더에 한글이 들어가면 `tests/report/test_template_no_korean_glyphs.py` 가 fail.
|
|
14
|
+
- validator 강제는 **섹션 제목 substring 존재**만 본다(기존 컨벤션). 절차 내용의 적절성은 교차검증 워커/컨버전스가 판단.
|
|
15
|
+
- 범위 규칙(프로파일 지시): 사람이 **관찰 가능한 변화**가 있을 때만 절차 항목, 내부 전용이면 면제 한 줄(`applicable=false` + `exemptionReason`).
|
|
16
|
+
- container 연계는 **조건부** — `docker-compose.yml` 있으면 `okstra-container up`, 없으면 일반 실행 명령.
|
|
17
|
+
- 수정 후 `npm run build` 로 `runtime/` 동기화, 완료 게이트는 `npm run check` exit 0.
|
|
18
|
+
- `runtime/` 는 빌드 산출물 — 직접 편집 금지. 소스는 `scripts/`,`templates/`,`prompts/`,`validators/`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
### Task 1: i18n 라벨/빈상태 키 추가
|
|
23
|
+
|
|
24
|
+
**Files:**
|
|
25
|
+
- Modify: `templates/reports/i18n/en.json`
|
|
26
|
+
- Modify: `templates/reports/i18n/ko.json`
|
|
27
|
+
|
|
28
|
+
**Interfaces:**
|
|
29
|
+
- Produces: `t("manualUserTest.environmentSetup")`, `.steps`, `.expectedResult`, `.notApplicable`, `.performed`, `.result`, `.observed` — Task 2·3 템플릿이 소비.
|
|
30
|
+
|
|
31
|
+
- [ ] **Step 1:** `en.json` 의 기존 최상위 그룹(예: `emptyState`) 구조를 Read 로 확인하고, 동일 nesting 으로 `manualUserTest` 그룹 추가:
|
|
32
|
+
```json
|
|
33
|
+
"manualUserTest": {
|
|
34
|
+
"environmentSetup": "Environment",
|
|
35
|
+
"steps": "Steps",
|
|
36
|
+
"expectedResult": "Expected result",
|
|
37
|
+
"notApplicable": "Manual user test not required",
|
|
38
|
+
"performed": "Performed",
|
|
39
|
+
"result": "Result",
|
|
40
|
+
"observed": "Observed"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
- [ ] **Step 2:** `ko.json` 에 같은 키로 한국어 값 추가:
|
|
44
|
+
```json
|
|
45
|
+
"manualUserTest": {
|
|
46
|
+
"environmentSetup": "환경 기동",
|
|
47
|
+
"steps": "확인 스텝",
|
|
48
|
+
"expectedResult": "기대 결과",
|
|
49
|
+
"notApplicable": "사용자 테스트 불필요",
|
|
50
|
+
"performed": "수행",
|
|
51
|
+
"result": "결과",
|
|
52
|
+
"observed": "관찰값"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
- [ ] **Step 3:** 키 정합성 테스트 실행. Run: `python3 -m pytest tests/report/test_report_language_i18n.py -q` (en/ko 키 집합 일치 검증이 있으면 통과해야 함). Expected: PASS.
|
|
56
|
+
- [ ] **Step 4:** Commit. `git add templates/reports/i18n/en.json templates/reports/i18n/ko.json && git commit -m "feat(report): add manualUserTest i18n labels"`
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Task 2: implementation 측 — 템플릿 섹션 + validator 강제 + fixture
|
|
61
|
+
|
|
62
|
+
**Files:**
|
|
63
|
+
- Modify: `templates/reports/final-report.template.md:485` (§5.7.9 Routing → 5.7.10, 앞에 5.7.9 신설)
|
|
64
|
+
- Modify: `validators/validate-run.py:1146-1156` (`IMPLEMENTATION_REQUIRED_SECTIONS`)
|
|
65
|
+
- Modify: implementation data fixture (Task 의 Step 1 에서 `grep -rl "validationEvidence" tests/ templates/` 로 위치 확정)
|
|
66
|
+
- Test: `tests/report/test_render_final_report.py`, `tests/contract/` validator 테스트
|
|
67
|
+
|
|
68
|
+
**Interfaces:**
|
|
69
|
+
- Consumes: `t("manualUserTest.*")` (Task 1).
|
|
70
|
+
- Produces: 렌더된 본문에 `Manual User Test` substring; data 필드 `implementation.manualUserTest = {applicable: bool, exemptionReason: str|null, items: [{target, environmentSetup, steps: [str], expectedResult}]}`.
|
|
71
|
+
|
|
72
|
+
- [ ] **Step 1: 실패 테스트 — 섹션 누락 거부.** validator 테스트에 추가:
|
|
73
|
+
```python
|
|
74
|
+
def test_implementation_report_requires_manual_user_test_section():
|
|
75
|
+
# "Manual User Test" 헤딩이 없는 implementation 리포트 본문은 거부된다
|
|
76
|
+
failures = []
|
|
77
|
+
_check_required_deliverable_sections("implementation", BODY_WITHOUT_MANUAL, failures)
|
|
78
|
+
assert any("Manual User Test" in f for f in failures)
|
|
79
|
+
```
|
|
80
|
+
(실제 호출부는 validate-run.py 의 섹션 체크 함수명에 맞춤 — Step 에서 `grep -n "IMPLEMENTATION_REQUIRED_SECTIONS" validators/validate-run.py` 로 확인)
|
|
81
|
+
- [ ] **Step 2:** Run 해서 FAIL 확인(아직 "Manual User Test" 가 리스트에 없어 거부 안 됨). Expected: FAIL.
|
|
82
|
+
- [ ] **Step 3: validator 리스트에 추가.** `IMPLEMENTATION_REQUIRED_SECTIONS` 끝(`"Routing Recommendation",` 앞)에 `"Manual User Test",` 추가.
|
|
83
|
+
- [ ] **Step 4:** Run 해서 PASS.
|
|
84
|
+
- [ ] **Step 5: 템플릿 섹션 신설.** `### 5.7.9 Routing Recommendation` 을 `### 5.7.10` 으로 바꾸고, 그 앞에 삽입:
|
|
85
|
+
```jinja
|
|
86
|
+
### 5.7.9 Manual User Test (Draft)
|
|
87
|
+
|
|
88
|
+
{% if implementation.manualUserTest.applicable -%}
|
|
89
|
+
{% for item in implementation.manualUserTest.items %}
|
|
90
|
+
- **{{ item.target | mdcell }}**
|
|
91
|
+
- {{ t("manualUserTest.environmentSetup") }}: {{ item.environmentSetup }}
|
|
92
|
+
- {{ t("manualUserTest.steps") }}:
|
|
93
|
+
{% for step in item.steps %} {{ loop.index }}. {{ step }}
|
|
94
|
+
{% endfor %} - {{ t("manualUserTest.expectedResult") }}: {{ item.expectedResult }}
|
|
95
|
+
{% endfor %}
|
|
96
|
+
{%- else -%}
|
|
97
|
+
- {{ t("manualUserTest.notApplicable") }}: {{ implementation.manualUserTest.exemptionReason }}
|
|
98
|
+
{%- endif %}
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
- [ ] **Step 6: fixture 보강.** implementation 렌더 fixture data 에 `manualUserTest` 필드 추가(applicable=true 항목 1개). 누락 시 Jinja `undefined.applicable` 로 렌더 실패하므로 필수.
|
|
102
|
+
- [ ] **Step 7: 렌더 테스트.** `test_render_final_report.py` 에 implementation 렌더 결과가 `"Manual User Test (Draft)"` 와 항목 내용을 담고, 양 언어 렌더가 통과하는지 단언. Run: `python3 -m pytest tests/report/test_render_final_report.py tests/report/test_template_full_render_both_langs.py tests/report/test_template_no_korean_glyphs.py -q`. Expected: PASS.
|
|
103
|
+
- [ ] **Step 8: Commit.** `git add templates/reports/final-report.template.md validators/validate-run.py tests/ <fixture> && git commit -m "feat(report): add Manual User Test (Draft) section to implementation deliverables"`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### Task 3: implementation 프로파일 — 초안 작성 지시 + container 조건부 + report-writer 데이터 지시
|
|
108
|
+
|
|
109
|
+
**Files:**
|
|
110
|
+
- Modify: `prompts/profiles/_implementation-deliverable.md:33` (Routing recommendation 항목 앞에 새 deliverable 항목)
|
|
111
|
+
- Modify: `prompts/lead/report-writer.md` (data 필드 채우기 지시 — `grep -n "validationEvidence" prompts/lead/report-writer.md` 로 인접 위치 확정)
|
|
112
|
+
|
|
113
|
+
**Interfaces:**
|
|
114
|
+
- Consumes: Task 2 의 `implementation.manualUserTest` 데이터 형태.
|
|
115
|
+
|
|
116
|
+
- [ ] **Step 1:** `_implementation-deliverable.md` 의 `- **Validation evidence**` 와 `- **Routing recommendation ...**` 사이에 항목 추가:
|
|
117
|
+
```markdown
|
|
118
|
+
- **Manual user test draft**: 사람이 관찰 가능한 변화(UI/API/CLI/산출물 등)가 있으면 각 대상마다 `대상 / 환경 기동 / 확인 스텝 / 기대 결과` 를 §5.7.9 에 적는다. 환경 기동은 프로젝트에 `docker-compose.yml` 이 있으면 `okstra-container up <task-id>` (published port 접속), 없으면 프로젝트 실행 명령(예: `npm start`). 관찰 가능한 변화가 없으면 항목 대신 `사용자 테스트 불필요 — <사유>` 한 줄만 적는다(`applicable=false`). 절차는 승인 plan 의 `Acceptance:` 와 이 run 의 실제 diff 를 근거로 작성한다.
|
|
119
|
+
```
|
|
120
|
+
- [ ] **Step 2:** self-review 체크리스트(`_implementation-deliverable.md:38-48`)에 한 항목 추가: "Manual user test — 관찰 가능한 변화가 있는데 §5.7.9 가 면제 한 줄로 처리되지 않았는지 확인".
|
|
121
|
+
- [ ] **Step 3:** `report-writer.md` 의 deliverable 데이터 작성 지시에 `implementation.manualUserTest` 필드(applicable/exemptionReason/items) 채우는 한 줄 추가.
|
|
122
|
+
- [ ] **Step 4:** 프로파일은 코드가 아니므로 직접 테스트 없음 — `bash validators/validate-workflow.sh` 로 phase contract 깨지지 않는지 확인. Expected: PASS.
|
|
123
|
+
- [ ] **Step 5: Commit.** `git add prompts/profiles/_implementation-deliverable.md prompts/lead/report-writer.md && git commit -m "feat(report): instruct implementation lead to draft manual user test steps"`
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### Task 4: final-verification 측 — 템플릿 결과 섹션 + validator 강제 + fixture
|
|
128
|
+
|
|
129
|
+
**Files:**
|
|
130
|
+
- Modify: `templates/reports/final-report.template.md:568` (§5.8.7 Routing → 5.8.8, 앞에 5.8.7 신설)
|
|
131
|
+
- Modify: `validators/validate-run.py:1159-1167` (`FINAL_VERIFICATION_REQUIRED_SECTIONS`)
|
|
132
|
+
- Modify: final-verification data fixture
|
|
133
|
+
- Test: 위 렌더/validator 테스트
|
|
134
|
+
|
|
135
|
+
**Interfaces:**
|
|
136
|
+
- Consumes: `t("manualUserTest.*")`.
|
|
137
|
+
- Produces: 본문에 `Manual User Test` substring; `finalVerification.manualUserTest = {applicable, exemptionReaffirm: str|null, results: [{target, performed, result, observed}]}` (`result` ∈ pass|fail|blocked).
|
|
138
|
+
|
|
139
|
+
- [ ] **Step 1: 실패 테스트.** final-verification 변형으로 Task 2 Step 1 과 동일하게 "Manual User Test" 누락 거부 테스트 추가. Run → FAIL.
|
|
140
|
+
- [ ] **Step 2:** `FINAL_VERIFICATION_REQUIRED_SECTIONS` 의 `"Routing Recommendation",` 앞에 `"Manual User Test",` 추가. Run → PASS.
|
|
141
|
+
- [ ] **Step 3: 템플릿 섹션.** `### 5.8.7 Routing Recommendation` → `### 5.8.8`, 앞에 삽입:
|
|
142
|
+
```jinja
|
|
143
|
+
### 5.8.7 Manual User Test Results
|
|
144
|
+
|
|
145
|
+
{% if finalVerification.manualUserTest.applicable -%}
|
|
146
|
+
| {{ t("manualUserTest.performed") }} | {{ t("manualUserTest.result") }} | {{ t("manualUserTest.observed") }} |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
{% for row in finalVerification.manualUserTest.results -%}
|
|
149
|
+
| {{ row.target | mdcell }} — {{ row.performed | mdcell }} | `{{ row.result | mdcell }}` | {{ row.observed | mdcell }} |
|
|
150
|
+
{% endfor %}
|
|
151
|
+
{%- else -%}
|
|
152
|
+
- {{ t("manualUserTest.notApplicable") }}: {{ finalVerification.manualUserTest.exemptionReaffirm }}
|
|
153
|
+
{%- endif %}
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
- [ ] **Step 4: fixture 보강.** final-verification 렌더 fixture 에 `manualUserTest` 필드(applicable=true, results 1행).
|
|
157
|
+
- [ ] **Step 5: 렌더/양언어 테스트.** Run: `python3 -m pytest tests/report/test_render_final_report.py tests/report/test_final_report_stage_reports_render.py tests/report/test_template_full_render_both_langs.py tests/report/test_template_no_korean_glyphs.py -q`. Expected: PASS.
|
|
158
|
+
- [ ] **Step 6: Commit.** `git add templates/reports/final-report.template.md validators/validate-run.py tests/ <fixture> && git commit -m "feat(report): add Manual User Test Results section to final-verification deliverables"`
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Task 5: final-verification 프로파일 + 입력 템플릿 통합
|
|
163
|
+
|
|
164
|
+
**Files:**
|
|
165
|
+
- Modify: `prompts/profiles/final-verification.md` (deliverable/output 섹션 — `grep -n "deliverable\|Expected output\|Routing" prompts/profiles/final-verification.md` 로 위치 확정)
|
|
166
|
+
- Modify: `templates/reports/final-verification-input.template.md:58` (`Manual verification notes:`)
|
|
167
|
+
|
|
168
|
+
**Interfaces:**
|
|
169
|
+
- Consumes: implementation 의 §5.7.9 초안(Source Implementation Report 경유로 참조).
|
|
170
|
+
|
|
171
|
+
- [ ] **Step 1:** `final-verification.md` 에 지시 추가: "Source implementation report 의 §5.7.9 Manual User Test (Draft) 각 항목을 실제로 수행하고 §5.8.7 에 `결과(pass/fail/blocked) + 관찰값`을 기록한다. 초안이 면제였으면 사유 타당성만 한 줄로 재확인한다."
|
|
172
|
+
- [ ] **Step 2:** `final-verification-input.template.md:58` 를 다음으로 교체:
|
|
173
|
+
```markdown
|
|
174
|
+
- Manual verification notes (source implementation report §5.7.9 Manual User Test Draft 를 수행한 결과):
|
|
175
|
+
```
|
|
176
|
+
- [ ] **Step 3:** `bash validators/validate-workflow.sh` 통과 확인.
|
|
177
|
+
- [ ] **Step 4: Commit.** `git add prompts/profiles/final-verification.md templates/reports/final-verification-input.template.md && git commit -m "feat(report): instruct final-verification to execute manual user test draft"`
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### Task 6: okstra-container ↔ 리포트 양방향 포인터
|
|
182
|
+
|
|
183
|
+
**Files:**
|
|
184
|
+
- Modify: `skills/okstra-container/SKILL.md`
|
|
185
|
+
|
|
186
|
+
- [ ] **Step 1:** SKILL.md 의 `up` 성공 안내(published ports) 부근에, 무엇을 확인할지는 implementation 리포트 §5.7.9 Manual User Test (Draft) 를 따르라는 한 줄 추가. (단절 해소 — 환경 기동 후 절차 출처 명시)
|
|
187
|
+
- [ ] **Step 2:** Commit. `git add skills/okstra-container/SKILL.md && git commit -m "docs(container): point to report Manual User Test section for what to verify"`
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### Task 7: 빌드 + 전체 검증
|
|
192
|
+
|
|
193
|
+
- [ ] **Step 1:** `npm run build` → `runtime/` 동기화. Expected: BUILD_EXIT=0.
|
|
194
|
+
- [ ] **Step 2:** `npm run check` 전체. Expected: exit 0 (Python + JS + validators).
|
|
195
|
+
- [ ] **Step 3:** runtime 반영 확인: `grep -rl "Manual User Test" runtime/templates runtime/validators` 가 매치.
|
|
196
|
+
- [ ] **Step 4: Commit**(빌드 산출물은 gitignore 라 커밋 없음 — 소스 커밋이 이미 1~6 에서 됨). 푸시는 사용자 지시 시에만.
|
|
197
|
+
|
|
198
|
+
## Self-Review
|
|
199
|
+
|
|
200
|
+
**1. Spec coverage:** spec §3 결정 4개 → Task 2/4(위치·강제), Task 3/5(범위·초안/실행), Task 6(container 조건부 연계). spec §6 영향파일 6개 → Task 1~6 에 모두 매핑. spec §8 테스트계획 → Task 2/4 의 렌더·validator 테스트, Task 7 의 validate-workflow + npm run check. 갭 없음.
|
|
201
|
+
**2. Placeholder scan:** fixture 파일 경로·일부 프로파일 위치는 "구현 시 grep 로 확정" 으로 명시(데이터 부족 구간) — 그 외 코드/텍스트는 실제 내용 제공.
|
|
202
|
+
**3. Type consistency:** `implementation.manualUserTest`(items) ↔ `finalVerification.manualUserTest`(results) 필드명 Task 2/3/4 간 일치. i18n 키 `manualUserTest.*` Task 1 정의 ↔ Task 2/4 소비 일치.
|
|
203
|
+
**4. 설계 조정:** spec 의 "빈 스텁 거부" 는 기존 validator 컨벤션(제목 substring 강제)에 맞춰 "제목 강제 + 프로파일 내용 규칙 + self-review" 로 단순화(Global Constraints 에 명시).
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Cross-Project Dependencies — implementation-planning 선행 필수 격상 설계
|
|
2
|
+
|
|
3
|
+
- 작성일: 2026-06-24
|
|
4
|
+
- 대상 phase: `implementation-planning`
|
|
5
|
+
- 상태: 설계 승인 완료 (구현 계획 작성 대기)
|
|
6
|
+
|
|
7
|
+
## 1. 배경과 문제
|
|
8
|
+
|
|
9
|
+
`implementation-planning` 보고서는 `data.json`(SSOT) → Jinja 템플릿(`templates/reports/final-report.template.md`)으로 **결정론적 렌더**된다. report-writer 는 마크다운을 직접 쓰지 못한다([report-writer-worker.md:27](../../../agents/workers/report-writer-worker.md:27)).
|
|
10
|
+
|
|
11
|
+
이 run 이 **다른 프로젝트(다른 repo·published 패키지)** 의 작업에 의존할 때, 그 의존을 표현할 수 있는 채널이 현재 3개뿐이고 모두 부족하다:
|
|
12
|
+
|
|
13
|
+
1. **`§3 Recommended Next Steps`** (`recommendedNextSteps[]`, 자유 텍스트) — "추천"이라 강제력이 없다. 실제 사례(`dev-9795`)에서 "helpers·common-api cross-repo carry 를 별도 okstra run 으로 먼저 진행하라"가 여기에 soft 하게 들어가, 선행 필수임이 드러나지 않았다.
|
|
14
|
+
2. **`Dependency / Migration Risk`** DM 행 — `kind` enum 에 `flag-precondition`/`repo-sequencing` 이 있으나([schema:1369](../../../schemas/final-report-v1.0.schema.json)) "위험 서술"일 뿐 "선행 필수 + 구체 작업"을 강제하지 않는다. `repo-sequencing` 은 프로파일상 **repo-내부 순서**를 뜻한다([implementation-planning.md:100](../../../prompts/profiles/implementation-planning.md:100)) — cross-repo 마커가 아니다.
|
|
15
|
+
3. **프로파일이 요구하는 `## Cross-Repo Carry — <repo>` 부록**([implementation-planning.md:94](../../../prompts/profiles/implementation-planning.md:94)) — **스키마·템플릿에 렌더 슬롯이 없어 보고서에 출력되지 못하는 잠복 버그**. 게다가 방향이 "이 run 이 상위(upstream)이고 다른 repo 가 하위"로, 사용자 사례(이 run 이 **하위**, 외부 패키지가 **선행 상위**)와 반대다.
|
|
16
|
+
|
|
17
|
+
결과적으로 **"이 run 이 다른 프로젝트의 선행 작업에 의존한다"** 는 1급 개념이 없어 soft recommendation 으로 새어나가고, 거기서 필요한 **구체 작업**도 강제되지 않는다.
|
|
18
|
+
|
|
19
|
+
## 2. 목표 / 비목표
|
|
20
|
+
|
|
21
|
+
### 목표
|
|
22
|
+
- cross-project 의존을 **1급·렌더되는 구조 필드**로 승격한다.
|
|
23
|
+
- upstream(이 run 이 기다림 = 선행 필수)과 downstream(이 run 이 만들어 줌 = 기존 carry) **두 방향을 한 개념으로 통합**한다.
|
|
24
|
+
- 각 의존에 **구체적으로 필요한 작업**(`requiredWork`)을 빈말 못 하도록 스키마 레벨에서 강제한다.
|
|
25
|
+
- cross-project 의존이 선언되면 이 섹션이 비어있지 못하도록 **검증기 게이트**를 둔다.
|
|
26
|
+
- 기존 `## Cross-Repo Carry` 잠복 렌더 버그를 통합 과정에서 해소한다.
|
|
27
|
+
|
|
28
|
+
### 비목표
|
|
29
|
+
- **런타임 게이트 없음.** `implementation` run 진입 시 선행 신호를 자동 확인하거나 워커 fan-out 을 차단하지 않는다.
|
|
30
|
+
- **승인 차단 없음.** 계획 frontmatter `approved` 를 막지 않는다 — 선행 작업은 병렬 진행 가능하므로 계획 승인 자체는 막지 않는다.
|
|
31
|
+
- 다른 repo 의 트리·`.okstra/` 에 쓰지 않는다(기존 cross-repo 구조 한계 유지).
|
|
32
|
+
|
|
33
|
+
## 3. 설계
|
|
34
|
+
|
|
35
|
+
### 3.1 데이터 모델 (schema)
|
|
36
|
+
|
|
37
|
+
`schemas/final-report-v1.0.schema.json` 의 `implementationPlanning` 객체에 새 배열 `crossProjectDependencies` 를 추가한다(기본 `[]` 허용 — 단일 프로젝트 계획은 빈 배열).
|
|
38
|
+
|
|
39
|
+
새 `$defs/CrossProjectDependency`:
|
|
40
|
+
|
|
41
|
+
| 필드 | 타입/제약 | 의미 |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `id` | `^XP-\d{3,}$` | cross-project 식별자 |
|
|
44
|
+
| `direction` | enum: `upstream-precondition` \| `downstream-carry` | upstream = 이 run 이 **기다림**(선행 필수); downstream = 이 run 이 **만들어 줌**(기존 carry) |
|
|
45
|
+
| `project` | string, minLength 1 | 상대 프로젝트/repo/패키지명 (예: `@fonts-ninja-org/common-api`) |
|
|
46
|
+
| `requiredWork` | string, minLength 1 | **구체적으로 필요한 작업**. upstream: 상대 프로젝트가 만들어야 할 것; downstream: 상대가 후속으로 구현할 B-portion |
|
|
47
|
+
| `verificationSignal` | string, minLength 1 | 충족을 증명하는 관측 신호 (예: "npm common-api ≥ 1.27.46 + Font.d.ts 에 isSlanted 존재") |
|
|
48
|
+
| `linkedWork` | string, minLength 1 | upstream: 신호 충족 전 **막히는 이 계획의 stage/step**; downstream: 이 run 산출물을 소비하는 상대 작업 |
|
|
49
|
+
| `howToStart` | string, minLength 1 | 정확한 핸드오프 (`okstra-brief …(이 보고서 절대경로 Source Material)` → `okstra-run`) |
|
|
50
|
+
|
|
51
|
+
- `additionalProperties: false`, 위 7개 전부 `required`.
|
|
52
|
+
- `direction` 으로 양방향을 한 구조에 담는다. 기존 Cross-Repo Carry 의 세 서브섹션은 `downstream-carry` 행으로 흡수: `Preconditions already covered by this run` → `verificationSignal`(상대가 확인할 신호), `Work for <repo> to implement` → `requiredWork`, `How to start <repo>'s run` → `howToStart`.
|
|
53
|
+
|
|
54
|
+
### 3.2 렌더 (template + i18n)
|
|
55
|
+
|
|
56
|
+
`templates/reports/final-report.template.md` 의 §5.4 블록에서 `### Dependency / Migration Risk`([template:208](../../../templates/reports/final-report.template.md:208)) **바로 뒤**에 새 서브섹션 `### Cross-Project Dependencies` 를 추가한다.
|
|
57
|
+
|
|
58
|
+
- **엔트리별 블록** 렌더(Option Candidates 방식). 7열 표는 가독성이 떨어지므로 표를 쓰지 않는다:
|
|
59
|
+
```
|
|
60
|
+
**XP-001 — [upstream-precondition] @fonts-ninja-org/common-api**
|
|
61
|
+
- Required work: Font.d.ts 에 isSlanted 컬럼 추가 후 publish (≥ 1.27.46)
|
|
62
|
+
- Verification signal: npm view … → ≥ 1.27.46 AND isSlanted present
|
|
63
|
+
- Gated work in this plan: Stage 2 yarn install / Stage 3 compile — 신호 충족 전 진행 불가
|
|
64
|
+
- How to start: common-api repo 에서 okstra-brief … → okstra-run
|
|
65
|
+
```
|
|
66
|
+
- `crossProjectDependencies` 가 비면 단일 empty-state 라인(`- 해당 없음.` / 영어 i18n) 을 렌더한다 — 단일 프로젝트 계획은 항상 이 줄이 보인다.
|
|
67
|
+
- i18n: `templates/reports/i18n/{ko,en}.json` 에 섹션 헤딩 aside, 라벨(Required work / Verification signal / Linked work / How to start), empty-state 문자열 추가.
|
|
68
|
+
- 방향 라벨(`[upstream-precondition]` / `[downstream-carry]`)은 reader 가 선행/후속을 한눈에 구분하도록 블록 제목에 박는다.
|
|
69
|
+
|
|
70
|
+
### 3.3 강제 (validator) — 두 겹
|
|
71
|
+
|
|
72
|
+
**(a) 모양 규칙 — watertight, JSON 스키마가 강제**
|
|
73
|
+
`crossProjectDependencies` 가 비어있지 않으면 모든 행의 7개 필드가 minLength 1 을 만족해야 한다. `requiredWork`/`verificationSignal`/`howToStart` 가 비면 스키마 검증 실패 → **"구체 작업 명시"가 빈말이 될 수 없다.** `validate-run.py` 의 data.json 스키마 검증 경로([validate-run.py:1440](../../../validators/validate-run.py:1440))에서 자동 적용.
|
|
74
|
+
|
|
75
|
+
**(b) 존재 규칙 — trigger, `validate-run.py` 교차 필드 검사**
|
|
76
|
+
- DM `kind` enum 에 새 값 **`cross-project`** 추가(pre-1.0, enum 확장 자유). 의미: 다른 프로젝트/repo/패키지에 대한 의존. 기존 `repo-sequencing`(repo-내부)·`flag-precondition`(repo-내 플래그)과 명확히 구분.
|
|
77
|
+
- `validate-run.py` 에 교차 필드 규칙 신설: **data.json 에 `dependencyMigrationRisk` 행 중 `kind == cross-project` 가 하나라도 있으면 `crossProjectDependencies` 는 비어있으면 안 되고, `direction == upstream-precondition` 행이 ≥ 1 이어야 한다.** 위반 시 `contract-violated`.
|
|
78
|
+
- 이 규칙이 **"추천 → 선행 필수" 격상의 강제 지점**이다. 프로파일이 "타 repo/패키지 의존은 반드시 DM `cross-project` 행 + 매칭 XP 행으로 기록"을 지시하고, 검증기가 1:1 을 강제한다(allowlist 방식).
|
|
79
|
+
|
|
80
|
+
**(c) 섹션 헤딩 contract**
|
|
81
|
+
`implementation-planning.md` 섹션 헤딩 contract([implementation-planning.md:57](../../../prompts/profiles/implementation-planning.md:57))의 필수 substring 목록에 `Cross-Project Dependencies` 를 추가. 템플릿이 이 헤딩을 무조건 렌더하므로(empty-state 포함) substring 검사를 통과한다.
|
|
82
|
+
|
|
83
|
+
### 3.4 프로파일 prose (`prompts/profiles/implementation-planning.md`)
|
|
84
|
+
|
|
85
|
+
- 기존 Cross-Repo Carry 부록 블록(94–98)을 **새 구조 필드 참조로 재작성**하고 **양방향**(upstream-precondition / downstream-carry)을 커버하도록 바꾼다. "Recognition caveat"(상대 run 의 독립성) 문구는 섹션 하단 고정 노트(i18n)로 유지.
|
|
86
|
+
- "Required deliverable shape" 에 `crossProjectDependencies` 항목 추가: 타 프로젝트 의존은 DM `cross-project` 행 + 매칭 XP 행(구체 `requiredWork`·`verificationSignal`·`howToStart`) 으로 기록할 것.
|
|
87
|
+
- self-review 패스([implementation-planning.md:122](../../../prompts/profiles/implementation-planning.md:122))에 점검 추가: "타 repo/패키지 의존을 빠뜨리지 않았는가; DM `cross-project` ↔ XP 행 1:1 이 맞는가; `requiredWork` 가 구체적인가".
|
|
88
|
+
- §5.5.9 Plan Body Verification 의 adversarial 라운드 대상에 cross-project precondition 누락 점검을 포함.
|
|
89
|
+
- `recommendedNextSteps` 의 cross-project 항목 정책: **substance 는 새 섹션에, §3 는 포인터만**(이중 기록 방지). report-writer 가이드(`prompts/lead/report-writer.md:284` 인근)도 동기화.
|
|
90
|
+
|
|
91
|
+
### 3.5 스키마 excerpt / 빌드 흐름
|
|
92
|
+
|
|
93
|
+
- per-task-type 스키마 excerpt 빌더(`scripts/okstra_ctl/schema_excerpt.py`, `final_report_schema.py`)가 `implementationPlanning` 블록과 그 `$defs` 를 자동 포함하는지 확인한다. 새 `$defs/CrossProjectDependency` 가 implementation-planning excerpt 에 반드시 들어가야 report-writer 가 올바른 shape 로 authoring 한다.
|
|
94
|
+
- `runtime/` 은 빌드 출력이므로 직접 수정 금지 — 소스(`schemas/`, `templates/`, `prompts/`, `validators/`, `agents/`) 수정 후 `npm run build` 로 동기화.
|
|
95
|
+
|
|
96
|
+
## 4. 변경 파일 목록
|
|
97
|
+
|
|
98
|
+
| 파일 | 변경 |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `schemas/final-report-v1.0.schema.json` | `$defs/CrossProjectDependency` 신설; `implementationPlanning.crossProjectDependencies` 추가; DM `kind` enum 에 `cross-project` 추가 |
|
|
101
|
+
| `templates/reports/final-report.template.md` | §5.4 에 `### Cross-Project Dependencies` 엔트리별 블록 + empty-state |
|
|
102
|
+
| `templates/reports/i18n/ko.json`, `en.json` | 섹션 헤딩 aside·필드 라벨·empty-state·recognition-caveat 문자열 |
|
|
103
|
+
| `prompts/profiles/implementation-planning.md` | Cross-Repo Carry 재작성(양방향), deliverable shape·self-review·heading contract·recommendedNextSteps 정책 갱신 |
|
|
104
|
+
| `prompts/lead/report-writer.md` | recommendedNextSteps cross-project 포인터 정책 동기화 |
|
|
105
|
+
| `validators/validate-run.py` | DM `cross-project` ↔ `crossProjectDependencies` 교차 필드 규칙 |
|
|
106
|
+
| `agents/workers/report-writer-worker.md` | 필요 시 새 섹션 authoring 안내(스키마 excerpt 가 주도하므로 최소) |
|
|
107
|
+
| `tests/` | 아래 §6 검증 계획 |
|
|
108
|
+
|
|
109
|
+
## 5. 강제 지점 매핑 (MUST → 어디서 강제되나)
|
|
110
|
+
|
|
111
|
+
| 규칙 | 강제 지점 |
|
|
112
|
+
|---|---|
|
|
113
|
+
| XP 행의 7필드 비-빈 (구체 작업 명시) | JSON 스키마 `required` + minLength → `validate-run.py` 스키마 검증 |
|
|
114
|
+
| DM `cross-project` 있으면 XP `upstream-precondition` ≥ 1 | `validate-run.py` 신설 교차 필드 검사 |
|
|
115
|
+
| 섹션 헤딩 `Cross-Project Dependencies` 존재 | `validate-run.py` substring 검사 + 템플릿 무조건 렌더 |
|
|
116
|
+
| report-writer 가 올바른 shape authoring | implementation-planning 스키마 excerpt 에 포함 |
|
|
117
|
+
|
|
118
|
+
## 6. 검증 계획 (추가할 테스트)
|
|
119
|
+
|
|
120
|
+
- `tests/report/test_render_final_report.py`: `implementation-planning` 픽스처에 `crossProjectDependencies`(upstream·downstream 각 1행) 추가 → 렌더 결과에 블록·라벨·방향 태그가 나오는지; 빈 배열 → empty-state 라인이 나오는지.
|
|
121
|
+
- `tests/contract/` (또는 validate-run 테스트): DM `cross-project` 행이 있는데 `crossProjectDependencies` 가 비면 `contract-violated` 인지; XP 행에 `requiredWork` 빈 값이면 스키마 검증 실패인지.
|
|
122
|
+
- `tests/fixtures/final-report-data/implementation-planning-001.data.json`: 새 필드 반영(빈 배열로 최소 변경하거나 샘플 1행 추가).
|
|
123
|
+
- 완료 게이트: `npm run check` 가 그대로 exit 0.
|
|
124
|
+
|
|
125
|
+
## 7. 한계 / 미해결
|
|
126
|
+
|
|
127
|
+
- **존재 규칙의 trigger 는 planner 가 DM `cross-project` 를 찍어야 발동**한다. cross-project 의존을 DM 에 전혀 기록하지 않으면 검증기가 잡지 못한다(완전 watertight 불가). 이를 줄이기 위해 프로파일 self-review + §5.5.9 adversarial verification 이 누락을 잡도록 prose 로 보강한다(휴리스틱, 강제 아님 — 이 한계를 spec 에 명시).
|
|
128
|
+
- 자유 텍스트(`recommendedNextSteps`)에서 cross-project 신호를 토큰 매칭으로 자동 검출하지 않는다(오탐 위험). 구조 신호(DM `cross-project`)만을 강제 앵커로 쓴다.
|
|
129
|
+
- 런타임 자동 신호 확인(예: npm 버전 publish 여부)은 본 설계 범위 밖(비목표).
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Decision Drafts — implementation-planning 잠복 렌더 갭 해소 설계
|
|
2
|
+
|
|
3
|
+
- 작성일: 2026-06-24
|
|
4
|
+
- 대상 phase: `implementation-planning`
|
|
5
|
+
- 상태: 설계 승인 완료 (구현 계획 작성 대기)
|
|
6
|
+
- 선행 참조: [2026-06-24-cross-project-precondition-design.md](2026-06-24-cross-project-precondition-design.md) — 동일 종류 갭을 같은 패턴으로 해소한 직전 사례
|
|
7
|
+
|
|
8
|
+
## 1. 배경과 문제
|
|
9
|
+
|
|
10
|
+
`implementation-planning` 보고서는 `data.json`(SSOT) → Jinja 템플릿([final-report.template.md](../../../templates/reports/final-report.template.md))으로 **결정론적 렌더**된다. report-writer 는 마크다운을 직접 쓰지 못한다([report-writer-worker.md:27](../../../agents/workers/report-writer-worker.md:27)).
|
|
11
|
+
|
|
12
|
+
프로파일의 Decision-record evaluation 블록([implementation-planning.md:111-116](../../../prompts/profiles/implementation-planning.md:111))은 3기준(① 되돌리기 어려움 ② 맥락 없으면 의아함 ③ 실제 trade-off) 충족 시 보고서 부록 섹션 `Decision Drafts` 를 **의무화**한다:
|
|
13
|
+
|
|
14
|
+
- 각 draft 는 `## Context / ## Decision / ## Consequences / ## Alternatives Considered` 형태, `## Status: Proposed` 로 시작.
|
|
15
|
+
- 평가했으나 기준 미달인 후보는 `skipped adr-candidate: <topic> — reason: <criterion>` 한 줄로 같은 섹션 아래 기록.
|
|
16
|
+
|
|
17
|
+
그러나 이 부록은 **실제 보고서에 출력될 수 없다**:
|
|
18
|
+
|
|
19
|
+
1. 스키마([final-report-v1.0.schema.json](../../../schemas/final-report-v1.0.schema.json))에 `decisionDraft` 류 필드가 없다(`grep decisionDraft` → 0건).
|
|
20
|
+
2. 템플릿에 `Decision Drafts` 렌더 블록이 없다.
|
|
21
|
+
3. i18n·validator 어디에도 `Decision Drafts` 가 없다.
|
|
22
|
+
|
|
23
|
+
즉 cross-project(`## Cross-Repo Carry`)와 **동일 종류의 잠복 렌더 갭**이다.
|
|
24
|
+
|
|
25
|
+
### 부록이 load-bearing 인 이유
|
|
26
|
+
|
|
27
|
+
이 부록은 단순 장식이 아니다. [implementation-planning.md:116](../../../prompts/profiles/implementation-planning.md:116)은 승인된 계획의 stepwise execution 에 다음 step 을 의무화한다:
|
|
28
|
+
|
|
29
|
+
> `Create <PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md from the decision draft in section X`
|
|
30
|
+
|
|
31
|
+
즉 `implementation` run 이 ADR 파일을 만들 때 **"보고서의 섹션 X 에 있는 드래프트"를 출처로 가리킨다**. 부록이 렌더되지 못하면 그 step 은 존재하지 않는 섹션을 가리키게 된다.
|
|
32
|
+
|
|
33
|
+
보고서가 staging 위치로 설계된 이유:
|
|
34
|
+
- planning 은 계획 문서만 산출하고 source edit 이 금지된다([:48](../../../prompts/profiles/implementation-planning.md:48)).
|
|
35
|
+
- ADR 은 계획이 승인(frontmatter `approved: true`)되기 전에 "Accepted" 로 커밋되면 안 된다. 보고서에 `Proposed` draft 로 staging 했다가 승인+implementation 시점에 파일로 materialize 하는 것이 **승인 게이트를 지키는 흐름**이다.
|
|
36
|
+
|
|
37
|
+
하류 소비처 확인: `.okstra/decisions/<NNNN>-<slug>.md` 경로는 [_common-contract.md:87](../../../prompts/profiles/_common-contract.md:87)·[requirements-discovery.md:60](../../../prompts/profiles/requirements-discovery.md:60)·okstra-brief 가 참조하나, "Decision Drafts **보고서 섹션**"을 소비하는 것은 오직 line 116 자기참조뿐이다.
|
|
38
|
+
|
|
39
|
+
## 2. 목표 / 비목표
|
|
40
|
+
|
|
41
|
+
### 목표
|
|
42
|
+
- Decision Drafts 를 **1급·렌더되는 구조 필드**로 승격해 잠복 렌더 갭을 해소한다.
|
|
43
|
+
- draft(생성 대상)와 skipped 후보(평가 후 의도적 드롭)를 **한 섹션 아래** 구조화한다.
|
|
44
|
+
- draft 필드를 빈말 못 하도록 스키마 레벨에서 강제한다.
|
|
45
|
+
- draft 가 선언되면 line 116 의 materialization step 이 실제 존재하도록 **검증기 게이트**를 둔다.
|
|
46
|
+
|
|
47
|
+
### 비목표
|
|
48
|
+
- **런타임 게이트 없음.** `implementation` run 진입 시 ADR 파일 존재를 자동 확인하지 않는다.
|
|
49
|
+
- **승인 차단 없음.** 계획 frontmatter `approved` 를 막지 않는다.
|
|
50
|
+
- planning phase 가 `.okstra/decisions/*.md` 파일을 직접 쓰지 않는다 — 기존 "drafts are NOT written by this phase" 규칙 유지(implementation 이 materialize).
|
|
51
|
+
- brief 의 모든 `adr-candidate:*` 평가 완료를 watertight 하게 강제하지 않는다(§7 한계 참조).
|
|
52
|
+
|
|
53
|
+
## 3. 설계
|
|
54
|
+
|
|
55
|
+
### 3.1 데이터 모델 (schema)
|
|
56
|
+
|
|
57
|
+
`implementationPlanning` 객체에 배열 두 개를 추가한다(둘 다 기본 `[]` 허용 — 평가 결과가 없는 계획은 빈 배열). 둘 다 `required` 에 넣어 report-writer 가 항상 emit 하게 한다.
|
|
58
|
+
|
|
59
|
+
새 `$defs/DecisionDraft` (cross-project 의 `CrossProjectDependency` 와 동수인 7 필드, 전부 `required`, `additionalProperties: false`):
|
|
60
|
+
|
|
61
|
+
| 필드 | 타입/제약 | 의미 |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `number` | `^\d{4,}$` | 파일명 `<NNNN>-<slug>.md` 의 NNNN. `(max existing in .okstra/decisions/ + 1)` zero-pad ≥4 자리 |
|
|
64
|
+
| `slug` | `^[a-z0-9]+(?:-[a-z0-9]+)*$` | 파일명 slug. 보고서 서브섹션 헤딩 `#### <number>-<slug>` 에도 사용 |
|
|
65
|
+
| `status` | const `"Proposed"` | planning 시점은 항상 Proposed |
|
|
66
|
+
| `context` | string, minLength 1 | ADR Context |
|
|
67
|
+
| `decision` | string, minLength 1 | ADR Decision |
|
|
68
|
+
| `consequences` | string, minLength 1 | ADR Consequences |
|
|
69
|
+
| `alternativesConsidered` | string, minLength 1 | 기각된 대안과 사유 |
|
|
70
|
+
|
|
71
|
+
새 `$defs/SkippedAdrCandidate` (`additionalProperties: false`, 둘 다 `required`):
|
|
72
|
+
|
|
73
|
+
| 필드 | 타입/제약 | 의미 |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `topic` | string, minLength 1 | 평가한 adr-candidate 주제 |
|
|
76
|
+
| `reason` | string, minLength 1 | 미달한 기준 (예: "되돌리기 어렵지 않음") |
|
|
77
|
+
|
|
78
|
+
`implementationPlanning.properties` 추가:
|
|
79
|
+
- `decisionDrafts`: `array of $defs/DecisionDraft`
|
|
80
|
+
- `skippedAdrCandidates`: `array of $defs/SkippedAdrCandidate`
|
|
81
|
+
|
|
82
|
+
### 3.2 렌더 (template + i18n)
|
|
83
|
+
|
|
84
|
+
`templates/reports/final-report.template.md` §5.4 에서 `### Requirement Coverage`([:252](../../../templates/reports/final-report.template.md:252)) **뒤**, `## 5.5 Stage Map`([:260](../../../templates/reports/final-report.template.md:260)) **앞**에 `### Decision Drafts` 서브섹션을 추가한다(cross-project 와 같은 §5.4 내 위치).
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
### Decision Drafts{aside}
|
|
88
|
+
|
|
89
|
+
{% if drafts empty and skipped empty %}
|
|
90
|
+
{{ t("emptyState.decisionDrafts") }}
|
|
91
|
+
{% else %}
|
|
92
|
+
{% for d in decisionDrafts %}
|
|
93
|
+
#### {{ d.number }}-{{ d.slug }}
|
|
94
|
+
|
|
95
|
+
- **{{ t("...status") }}:** {{ d.status }}
|
|
96
|
+
- **{{ t("...context") }}:** {{ d.context }}
|
|
97
|
+
- **{{ t("...decision") }}:** {{ d.decision }}
|
|
98
|
+
- **{{ t("...consequences") }}:** {{ d.consequences }}
|
|
99
|
+
- **{{ t("...alternativesConsidered") }}:** {{ d.alternativesConsidered }}
|
|
100
|
+
{% endfor %}
|
|
101
|
+
{% for s in skippedAdrCandidates %}
|
|
102
|
+
- skipped adr-candidate: {{ s.topic }} — reason: {{ s.reason }}
|
|
103
|
+
{% endfor %}
|
|
104
|
+
{% endif %}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
설계 결정:
|
|
108
|
+
- **헤딩 레벨**: §5.4 서브섹션은 `###` 이므로 `### Decision Drafts`, 각 draft 는 `#### <number>-<slug>`. 프로파일이 말하는 draft 의 `## Context/...`(H2)는 **파일(`.okstra/decisions/*.md`)의 형태**이고, 보고서에서는 구조 필드를 라벨 불릿으로 렌더한다. implementation step 이 이 필드를 읽어 파일을 `## Status/Context/Decision/Consequences/Alternatives Considered` 형태로 materialize 한다. 보고서에 H2 를 박으면 보고서 헤딩 계층·TOC 앵커가 깨지므로 구조-필드 렌더가 정합적이다.
|
|
109
|
+
- **skipped 라인은 고정 English 토큰** (`skipped adr-candidate:` / `reason:`) — `RED:`/`GREEN:`/`Slice value:` 처럼 greppable contract token 이고 프로파일 verbatim 이라 i18n 하지 않는다(`topic`/`reason` 값은 보고서 언어를 따른다).
|
|
110
|
+
- 무조건 렌더(empty-state 포함) → 헤딩 substring 이 항상 존재 → §3.3(c) 헤딩 contract 통과.
|
|
111
|
+
- empty-state 가 기본값: 대부분의 계획은 draft·skipped 둘 다 빈 배열이라 empty-state 한 줄만 보인다.
|
|
112
|
+
|
|
113
|
+
i18n: `templates/reports/i18n/{ko,en}.json` 에 추가
|
|
114
|
+
- `sectionAside.decisionDrafts`
|
|
115
|
+
- `emptyState.decisionDrafts`
|
|
116
|
+
- `implementationPlanning.decisionDraftFields.{status, context, decision, consequences, alternativesConsidered}`
|
|
117
|
+
|
|
118
|
+
### 3.3 강제 (validator) — 세 겹
|
|
119
|
+
|
|
120
|
+
**(a) 모양 규칙 — JSON 스키마가 강제**
|
|
121
|
+
`decisionDrafts` 가 비어있지 않으면 모든 draft 의 7 필드가 `required`+`minLength 1`+`status` const 를 만족해야 한다. `skippedAdrCandidates` 행도 `topic`/`reason` 비-빈. → "구체 내용"이 빈말이 될 수 없다. `validate-run.py` 의 data.json 스키마 검증 경로에서 자동 적용.
|
|
122
|
+
|
|
123
|
+
**(b) 자기완결 trigger — `validate-run.py` 교차 필드 검사 (신설)**
|
|
124
|
+
- 새 함수 `_validate_implementation_planning_decision_drafts(data, failures)`:
|
|
125
|
+
- `implementationPlanning.decisionDrafts` 가 비어있지 않으면, **어떤 stage 의 `stepwiseExecution` step 의 `files` 또는 `action` 이 `.okstra/decisions/` 를 참조**해야 한다.
|
|
126
|
+
- 위반 시 `failures.append(...)` → `contract-violated`.
|
|
127
|
+
- 이것이 line 116 의 "approved plan's stepwise execution MUST include `Create .okstra/decisions/<NNNN>-<slug>.md ...`" 를 **실제 강제 지점으로 승격**한다. cross-project 의 trigger(planner 가 DM `cross-project` 를 수동으로 찍어야 발동)와 달리, 이 검사는 draft 존재 자체가 trigger 이므로 **self-contained·watertight** 하다.
|
|
128
|
+
- CLAUDE.md 의 "MUST/BLOCKING 은 강제 지점을 명시해야 한다" 규칙을 충족한다.
|
|
129
|
+
|
|
130
|
+
**(c) 섹션 헤딩 contract**
|
|
131
|
+
`validate-run.py` 의 `PLANNING_REQUIRED_SECTIONS`([:1132](../../../validators/validate-run.py:1132))에 `"Decision Drafts"` 를 추가. 템플릿이 이 헤딩을 무조건 렌더하므로(empty-state 포함) substring 검사를 통과한다.
|
|
132
|
+
|
|
133
|
+
### 3.4 프로파일 prose (`prompts/profiles/implementation-planning.md`)
|
|
134
|
+
|
|
135
|
+
- Decision-record evaluation 블록(111–116)의 "attach a decision draft as a report appendix section titled `Decision Drafts`" 와 "record `skipped adr-candidate: ...` one line under `Decision Drafts`" 를 **구조 필드 참조로 재작성**한다:
|
|
136
|
+
- draft 는 `decisionDrafts` 배열(필드: number/slug/status/context/decision/consequences/alternativesConsidered)로 기록 → §5.4 `### Decision Drafts` 에 렌더.
|
|
137
|
+
- skipped 후보는 `skippedAdrCandidates` 배열(topic/reason)로 기록.
|
|
138
|
+
- line 116 의 materialization step 의무는 유지하되, "from the decision draft in section X" 가 §5.4 `### Decision Drafts` 의 `#### <number>-<slug>` 서브섹션을 가리킴을 명시. 파일은 그 구조 필드를 `## Status/Context/Decision/Consequences/Alternatives Considered` 형태로 materialize.
|
|
139
|
+
- 섹션 헤딩 contract(line 57) 필수 substring 목록에 `Decision Drafts` 추가.
|
|
140
|
+
- self-review 패스([:123](../../../prompts/profiles/implementation-planning.md:123))에 점검 추가: "`decisionDrafts` 가 비어있지 않으면 매칭 materialization step(`.okstra/decisions/` 생성)이 어느 stage 의 stepwise 에 있는가 — validator (b) 가 잡지만 reviewer 도 확인".
|
|
141
|
+
|
|
142
|
+
### 3.5 report-writer 정합 (`agents/workers/report-writer-worker.md`)
|
|
143
|
+
|
|
144
|
+
- `implementation-planning` authoring 안내에 한 줄: `decisionDrafts`/`skippedAdrCandidates` 를 populate(없으면 `[]`). shape 는 스키마 excerpt 가 주도하므로 최소 안내.
|
|
145
|
+
|
|
146
|
+
### 3.6 스키마 excerpt / 빌드 흐름
|
|
147
|
+
|
|
148
|
+
- per-task-type 스키마 excerpt 빌더(`scripts/okstra_ctl/schema_excerpt.py`, `final_report_schema.py`)가 `implementationPlanning` 블록과 그 `$defs` 를 자동 포함하는지 확인한다. 새 `$defs/DecisionDraft`·`SkippedAdrCandidate` 가 `$ref` 로 도달 가능하므로 excerpt 에 자동 포함되어야 한다(`tests/report/test_schema_excerpt.py` 로 회귀 확인).
|
|
149
|
+
- `runtime/` 은 빌드 출력이므로 직접 수정 금지 — 소스 수정 후 `npm run build` 로 동기화.
|
|
150
|
+
|
|
151
|
+
## 4. 변경 파일 목록
|
|
152
|
+
|
|
153
|
+
| 파일 | 변경 |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `schemas/final-report-v1.0.schema.json` | `$defs/DecisionDraft`·`$defs/SkippedAdrCandidate` 신설; `implementationPlanning` 에 `decisionDrafts`·`skippedAdrCandidates` 추가(properties + required) |
|
|
156
|
+
| `templates/reports/final-report.template.md` | §5.4 에 `### Decision Drafts` 블록(draft 서브섹션 + skipped 라인 + empty-state) |
|
|
157
|
+
| `templates/reports/i18n/ko.json`, `en.json` | 섹션 aside·필드 라벨·empty-state 문자열 |
|
|
158
|
+
| `prompts/profiles/implementation-planning.md` | Decision-record evaluation 재작성(구조 필드 참조); heading contract·self-review 갱신 |
|
|
159
|
+
| `agents/workers/report-writer-worker.md` | decisionDrafts/skippedAdrCandidates populate 안내 1줄 |
|
|
160
|
+
| `validators/validate-run.py` | `PLANNING_REQUIRED_SECTIONS` 에 `Decision Drafts` 추가; `_validate_implementation_planning_decision_drafts` 신설 + 호출 배선 |
|
|
161
|
+
| `tests/` + `tests/fixtures/` | 아래 §6 검증 계획 |
|
|
162
|
+
|
|
163
|
+
## 5. 강제 지점 매핑 (MUST → 어디서 강제되나)
|
|
164
|
+
|
|
165
|
+
| 규칙 | 강제 지점 |
|
|
166
|
+
|---|---|
|
|
167
|
+
| draft 7 필드 비-빈 + status const | JSON 스키마 `required`+`minLength`+`const` → `validate-run.py` 스키마 검증 |
|
|
168
|
+
| skipped 행 topic/reason 비-빈 | JSON 스키마 `required`+`minLength` |
|
|
169
|
+
| draft 있으면 `.okstra/decisions/` materialization step 존재 | `validate-run.py` `_validate_implementation_planning_decision_drafts` (신설, self-contained) |
|
|
170
|
+
| 섹션 헤딩 `Decision Drafts` 존재 | `validate-run.py` `PLANNING_REQUIRED_SECTIONS` substring + 템플릿 무조건 렌더 |
|
|
171
|
+
| report-writer 가 올바른 shape authoring | implementation-planning 스키마 excerpt 에 포함 |
|
|
172
|
+
|
|
173
|
+
## 6. 검증 계획 (추가할 테스트)
|
|
174
|
+
|
|
175
|
+
- `tests/report/test_render_final_report.py`: `implementation-planning` 픽스처에 `decisionDrafts`(1행)·`skippedAdrCandidates`(1행) 추가 → 렌더 결과에 `#### <number>-<slug>` 서브섹션, Status/Context/Decision/Consequences/Alternatives Considered 라벨, `skipped adr-candidate: ... — reason: ...` 라인이 나오는지; 빈 배열 둘 → empty-state 라인이 나오는지.
|
|
176
|
+
- `tests/contract/` (또는 validate-run 테스트): `decisionDrafts` 가 비어있지 않은데 어느 stage 의 stepwise 도 `.okstra/decisions/` 를 참조하지 않으면 `contract-violated` 인지; draft 의 `context` 빈 값이면 스키마 검증 실패인지; materialization step 이 있으면 통과인지.
|
|
177
|
+
- `tests/report/test_schema_excerpt.py`: implementation-planning excerpt 에 새 `$defs` 가 포함되는지.
|
|
178
|
+
- **모든 implementation-planning 픽스처**(`tests/fixtures/final-report-data/implementation-planning-001.data.json` + 테스트 내 인라인 픽스처)에 `decisionDrafts`·`skippedAdrCandidates`(최소 `[]`) 추가 — `required` 승격으로 기존 테스트가 깨지지 않게.
|
|
179
|
+
- 완료 게이트: `npm run check` 가 그대로 exit 0.
|
|
180
|
+
|
|
181
|
+
## 7. 한계 / 미해결
|
|
182
|
+
|
|
183
|
+
- **완전성(모든 adr-candidate 평가) 강제 불가**: "brief 의 모든 `adr-candidate:*` 를 draft 또는 skipped 로 처리했는가"는 brief 외부 입력과의 대조가 필요해 data.json 자기완결 검사로 watertight 하게 잡을 수 없다. 프로파일 self-review + §5.5.9 adversarial verification 휴리스틱으로만 보강한다(강제 아님 — cross-project spec §7 과 동일 종류 한계).
|
|
184
|
+
- **materialization step 의 정확성은 검사 안 함**: validator (b) 는 `.okstra/decisions/` 참조 step 의 *존재*만 본다. 그 step 이 올바른 `<NNNN>-<slug>` 를 가리키는지·draft 개수와 step 개수가 1:1 인지까지는 강제하지 않는다(self-review 책임).
|
|
185
|
+
- **planning 이 파일을 직접 쓰지 않음 유지**: 승인 게이트 보존을 위해 draft 는 보고서 staging 에만 두고, 실제 `.okstra/decisions/*.md` 생성은 implementation run 이 한다.
|