okstra 0.25.0 → 0.26.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/README.kr.md CHANGED
@@ -169,6 +169,7 @@ Claude Code 세션 밖에서 task 를 시작하려면:
169
169
  - **`release-handoff` lifecycle phase** — `final-verification` 이 `verdict=accepted` 를 반환한 직후에 실행되는 신규 phase. lead 가 Claude worker (drafter) 를 통해 commit message · PR body 후보를 만들고, `AskUserQuestion` 으로 사용자에게 (1) action (`commit only` / `commit + PR` / `skip`), (2) PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / 직접 입력), (3) message handling (`use as-is` / `edit then proceed` / `cancel`) 세 가지를 순서대로 묻습니다. 사용자가 메뉴로 선택한 git / gh 명령만 실행되고, force-push, base 브랜치 직접 push, hook bypass (`--no-verify`), release publish (`gh release`, `npm publish`, ...) 는 금지됩니다. 이 phase 에서는 소스 코드를 수정하지 않습니다. profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
170
170
  - **PR 본문 템플릿 설정** (release-handoff) — PR 본문은 마크다운 템플릿에서 채워집니다. 해석 우선순위: 1회성 override (`--pr-template-path` 또는 okstra-run Step 6 prompt) → `<project_root>/.project-docs/okstra/project.json` 의 `prTemplatePath` → `~/.okstra/config.json` 의 `prTemplatePath` → 스킬 디폴트 `~/.claude/skills/okstra-run/templates/pr-body.template.md`. 템플릿 등록 명령: `okstra config set pr-template-path <path> [--scope project|global]` (project 스코프는 project root 기준 상대경로 허용, global 스코프는 절대경로 또는 `~/` 시작 경로만 허용). 현재 설정 확인: `okstra config get pr-template-path --scope all` 은 각 스코프 값 + 실제로 우승하는 경로(effective) 까지 보여줍니다. 디폴트 템플릿은 `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` 4 섹션 + HTML 주석으로 lead 작성 가이드를 포함하며, PR 생성 직전에 lead 가 주석을 제거합니다.
171
171
  - **프로파일 워커 로스터 검증** — `--workers <csv>` 와 okstra-run Step 6 의 워커 prompt 는 해당 프로파일의 `Required workers:` 블록에 선언된 워커 ID 만 허용합니다. 프로파일에 없는 워커 (예: `release-handoff` 에서 `codex` / `gemini`) 를 요청하면 명확한 에러로 거절되고, 인터랙티브 prompt 도 프로파일이 실제로 받는 워커만 보여줍니다.
172
+ - **Phase 6 plan-body verification (implementation-planning 전용)** — Report writer worker 가 final-report draft 를 작성한 직후, User Approval gate 직전에 lead 가 1 라운드의 사후 검증을 추가로 돌립니다. 합성된 `## 4.5` plan 본문에서 `P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` plan-item 을 추출해 모든 analyser 워커에게 `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT` 평결을 요청합니다. 집계된 gate 결과는 `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result` 중 하나. 앞 둘은 final-report 상단의 `- [ ] Approved` 마커를 렌더하고, 뒤 둘은 `majority-disagree` 항목을 `## 5. Clarification Items` 의 `Blocks=approval` row 로 변환합니다. 빠른 반복용 opt-out: `--no-plan-verification` (기본값: 활성). 자세한 라운드 프로토콜은 [`skills/okstra-convergence/SKILL.md`](skills/okstra-convergence/SKILL.md) 의 "Plan-body verification mode" 섹션과 [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
172
173
 
173
174
  ### 3.5 운영 명령
174
175
 
package/README.md CHANGED
@@ -168,6 +168,7 @@ Recent workflow additions (post-0.8.0, on `main`):
168
168
  - **`release-handoff` lifecycle phase** — runs after `final-verification` returns `verdict=accepted`. The lead drafts a commit message and PR body via a Claude worker, then prompts the user with `AskUserQuestion` for three choices: action (`commit only` / `commit + PR` / `skip`), PR base branch (`staging` / `preprod` / `prod` / `main` / `dev` / free-form), and message handling (`use as-is` / `edit then proceed` / `cancel`). Only user-selected mutating git/gh commands run. Force-push, base-branch direct push, hook bypass (`--no-verify`), and release publishing (`gh release`, `npm publish`, ...) are forbidden. Source code is not edited in this phase. Profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
169
169
  - **Configurable PR body template** (release-handoff) — the PR body is filled from a markdown template chosen in priority order: per-run override (`--pr-template-path` or the okstra-run Step 6 prompt) → `<project_root>/.project-docs/okstra/project.json` `prTemplatePath` → `~/.okstra/config.json` `prTemplatePath` → bundled skill default at `~/.claude/skills/okstra-run/templates/pr-body.template.md`. Register a template with `okstra config set pr-template-path <path> [--scope project|global]` (project scope accepts paths relative to the project root; global scope requires absolute or `~/`-prefixed). `okstra config get pr-template-path --scope all` reports every scope plus the effective winner. The bundled default ships `## Summary` / `## Changes` / `## Test plan` / `## Linked issues` with HTML comment guidance that the lead strips before opening the PR.
170
170
  - **Profile-roster worker validation** — `--workers <csv>` (and the okstra-run Step 6 worker prompt) are now restricted to the worker IDs declared by the chosen profile's `Required workers:` block. Asking for `codex` / `gemini` on a profile that does not list them (e.g. `release-handoff`) is rejected with a clear error, and the interactive prompt only offers workers the profile actually accepts.
171
+ - **Phase 6 plan-body verification (implementation-planning only)** — after the Report writer worker authors the final-report draft and before the User Approval gate, the lead now runs one additional verification round: it extracts `P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` items from the consolidated `## 4.5` plan body and dispatches them to every analyser worker as `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`. The aggregated gate result is one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`; only the first two render the top-of-report `- [ ] Approved` marker, the other two convert `majority-disagree` items into `## 5. Clarification Items` rows with `Blocks=approval`. Disable for fast iteration with `--no-plan-verification` (default: enabled). Details: [`skills/okstra-convergence/SKILL.md`](skills/okstra-convergence/SKILL.md) "Plan-body verification mode" and [`docs/kr/cli.md#--no-plan-verification`](docs/kr/cli.md#--no-plan-verification).
171
172
 
172
173
  ### 3.5 Ops commands
173
174
 
@@ -326,7 +326,7 @@ Claude launch prompt 본문은 항상 `prompts/launch.template.md` 템플릿에
326
326
  |---|---|---|---|---|
327
327
  | `requirements-discovery` | 요청을 bugfix/feature/refactor/ops/improvement 중 하나로 분류하고 안전한 다음 phase로 라우팅 | work category, routing decision, missing-input list, clarification requests | `pending-routing-decision` (사용자 답변 후 결정) | 금지 |
328
328
  | `error-analysis` | 보고된 에러/사고의 증상·원인·재현 갭을 증거 기반으로 분석 | symptom/trigger 정리, root-cause 가설, reproduction gap, validation 경로 | `implementation-planning` | 금지 |
329
- | `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, 단계별 실행 순서, validation/rollback, **User Approval Request** 블록 | `implementation` (사용자 승인 후) | 금지 |
329
+ | `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, 단계별 실행 순서, validation/rollback, **User Approval Request** 블록, **§4.5.9 Plan Body Verification** (Phase 6 워커 사후 검증 라운드 — 합성된 plan 의 내적 일관성을 워커가 `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT` 로 cross-verify; gate 결과가 `passed` / `passed-with-dissent` 일 때만 Approval 마커 렌더, `blocked-by-disagreement` / `aborted-non-result` 일 때는 majority DISAGREE 항목이 `## 5. Clarification Items` 의 `Blocks=approval` row 로 변환됨) | `implementation` (사용자 승인 후) | 금지 |
330
330
  | `implementation` | 승인된 `implementation-planning` final report의 단계대로 소스 코드를 수정 | commit list, diff summary, out-of-plan edits 블록, validation/TDD evidence, rollback 검증, verifier 결과(Gemini/Codex/Claude) | `final-verification` | 허용 (승인된 plan의 파일 목록 한정, `git push`/publish/deploy/실제 migration 금지) |
331
331
  | `final-verification` | 완료된 작업의 잔존 결함·회귀 위험을 점검하고 release 판단 | acceptance verdict, residual risk, follow-up 라우팅(`error-analysis`/`implementation-planning`/`release-handoff`) | `pending-release-handoff` (verdict 가 `accepted` 일 때만 `release-handoff` 로 진입; 그 외에는 `error-analysis` 또는 `implementation-planning` 으로 리라우팅) | 금지 (read-only 테스트만 허용) |
332
332
  | `release-handoff` | `accepted` 받은 변경을 사용자가 선택한 방식대로 커밋·푸시·PR 로 전달 | 사용자 메뉴 응답(H1 action / H2 PR base / H3 message handling) 기록, 실행한 git/gh 명령 로그, commit SHA 목록, PR URL | `done-or-follow-up` | 허용 — 단 **사용자가 메뉴로 선택한 mutating 명령만** 실행. `git push --force*`, base 브랜치 직접 push, `--no-verify`, `gh release`, publish/deploy 는 금지. source code 자체는 수정 금지(이전 `implementation` 의 diff 를 그대로 패키징). |
package/docs/kr/cli.md CHANGED
@@ -9,7 +9,7 @@
9
9
  기본 명령(첫 진입 / full args):
10
10
 
11
11
  ```bash
12
- scripts/okstra.sh [--render-only] [--yes] [--refresh-assets] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--executor claude|codex|gemini] [--related-tasks taskA,taskB] [--work-category bugfix|feature|refactor|ops|improvement|unknown] [--clarification-response <previous-final-report>] [--approved-plan <plan-path>] [--approve] --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>]
12
+ scripts/okstra.sh [--render-only] [--yes] [--refresh-assets] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--executor claude|codex|gemini] [--related-tasks taskA,taskB] [--work-category bugfix|feature|refactor|ops|improvement|unknown] [--clarification-response <previous-final-report>] [--approved-plan <plan-path>] [--approve] --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>]
13
13
  ```
14
14
 
15
15
  후속 phase 단축 형식(기존 task-manifest.json이 존재할 때):
@@ -399,6 +399,15 @@ scripts/okstra.sh --task-type error-analysis --related-tasks scanner-regression,
399
399
  project-local `.claude/skills/`와 `.claude/agents/` 아래의 okstra mapped asset을 workspace source 기준으로 다시 생성합니다.
400
400
  기본 rerun에서는 기존 project-local asset을 유지합니다.
401
401
 
402
+ ### `--no-plan-verification`
403
+
404
+ `implementation-planning` task-type 의 Phase 6 plan-body verification 라운드를 끕니다. 기본값은 활성. 다른 task-type 에서는 무시됩니다.
405
+
406
+ - **활성 (default)**: Phase 6 에서 Report writer worker 가 final-report draft 를 작성한 직후, lead 가 합성된 plan 의 §4.5 본문 (Option Candidates / Stepwise Execution Order / Dependency / Validation Checklist / Rollback) 을 `P-*` plan-item 단위로 쪼개 모든 analyser 워커 (`claude`, `codex`, 그리고 옵트인된 `gemini`) 에게 reverify dispatch 합니다. 워커의 평결 (`AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`) 을 집계해 4 가지 gate result (`passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`) 중 하나를 산출하고, `passed` / `passed-with-dissent` 일 때만 final-report 상단의 `- [ ] Approved` 마커가 렌더됩니다. majority DISAGREE 항목은 `## 5. Clarification Items` 의 `Blocks=approval` row 로 변환됩니다 (자동 revise 없음 — 사용자가 답변 후 같은 phase 를 resume 해야 함).
407
+ - **비활성 (`--no-plan-verification` 전달 시)**: Phase 6 sub-step 전체가 skip 되고 final-report 상단의 Approval 마커가 무조건 렌더됩니다 (legacy 동작). 빠른 반복용 opt-out — handoff-ready plan 에는 권장하지 않습니다.
408
+ - 본 flag 는 manifest 의 `convergence.planBodyVerification.enabled` 를 `false` 로 기록합니다. resume 명령에서도 같은 flag 를 명시해야 같은 동작이 유지됩니다 (`_canonical_argv` 가 resume fidelity emit 을 보장).
409
+ - 자세한 라운드 프로토콜 / verdict semantics / state 파일 스키마는 `skills/okstra-convergence/SKILL.md` 의 "Plan-body verification mode (implementation-planning only)" 섹션 참고.
410
+
402
411
 
403
412
  ## Interactive input flow
404
413
 
@@ -0,0 +1,254 @@
1
+ # Implementation Plan Body Verification — Design
2
+
3
+ - Date: 2026-05-15
4
+ - Scope: okstra phase `implementation-planning` only
5
+ - Status: Designed (pending implementation)
6
+ - Implementation plan: `docs/superpowers/plans/2026-05-15-implementation-plan-verification.md` (to be written)
7
+
8
+ ## 1. 목적
9
+
10
+ `implementation-planning` phase는 현재 다음 흐름을 따른다.
11
+
12
+ ```
13
+ Phase 4 (워커 독립 분석)
14
+ → Phase 5.5 (워커 finding 상호 검증 — convergence)
15
+ → Phase 6 (report-writer가 통합 plan draft 작성)
16
+ → User Approval gate
17
+ → implementation phase
18
+ ```
19
+
20
+ Phase 5.5의 convergence는 **워커의 finding (section 1~5)** 만 cross-verify한다. 그 뒤 report-writer가 합성한 **통합 plan body (section 4.5: Option Candidates / Trade-off / Recommended Option / Stepwise Execution Order / Dependency / Validation Checklist / Rollback)** 에 대해서는 워커의 재검증이 없다. lead의 self-review pass만 거치고 User Approval로 직행한다.
21
+
22
+ 본 변경은 Phase 6 직후, User Approval 직전에 **합성 결과물 자체를 워커가 peer-review하는 라운드**를 끼워 넣는다. 통합 plan의 내적 일관성 / 실행 가능성 / 누락된 step / 깨진 file path 등을 워커들이 잡아내고, majority disagreement는 `## 5. Clarification Items`에 `Blocks=approval` row로 변환해 사용자에게 던진다.
23
+
24
+ ## 2. 결정된 분기 (대화에서 확정)
25
+
26
+ | ID | 결정 |
27
+ |----|-----|
28
+ | Q1 | **gating**. majority DISAGREE는 User Approval 체크박스를 막고 clarification 변환 경로로 보낸다. `contested` 와 `partial-consensus` 는 보고서에 기록만 하고 통과. |
29
+ | Q2 | **lifecycle 내부 step**. 외부 6-phase 계약 유지. `/okstra-status` 에는 implementation-planning 내부의 `plan-verification` sub-state로만 노출. |
30
+ | Q3 | **maxRounds = 1**. plan body 검증은 사실 검증이 아닌 일관성·완전성 검증이며 추가 라운드 이득이 작음. manifest로 override 가능. |
31
+ | Q4 | **자동 revise 안 함**. majority DISAGREE 항목은 lead가 직접 `## 5. Clarification Items` 표의 `Blocks=approval` row로 변환. report-writer 재호출 없음. |
32
+
33
+ ## 3. Plan Item 분리 규칙
34
+
35
+ report-writer가 draft한 final-report의 `## 4.5 Implementation Plan Deliverables` 본문을 lead가 파싱해 다음 형식의 plan-item으로 쪼갠다.
36
+
37
+ | Prefix | 출처 섹션 | 1 row의 정의 |
38
+ |--------|----------|--------------|
39
+ | `P-Opt-<N>` | `4.5 Option Candidates` | Option 1개 전체 (File Structure / 인터페이스 / blast radius 묶음) |
40
+ | `P-Step-<N>` | `Stepwise Execution Order` | step 1개 (file path + command + 성공 신호) |
41
+ | `P-Dep-<N>` | `Dependency` | dependency row 1개 |
42
+ | `P-Val-<N>` | `Validation Checklist` | checklist item 1개 |
43
+ | `P-Rb-<N>` | `Rollback` | rollback path 1개 (보통 1행) |
44
+
45
+ `Trade-off matrix`, `Recommended Option`은 별도 plan-item으로 만들지 않는다 (각 Option 자체가 P-Opt-* 로 평가되므로 중복).
46
+
47
+ Ticket ID 표기는 기존 규칙 그대로 (`[TICKETID: ...]`) plan-item 라인에 강제.
48
+
49
+ ## 4. 평결 스키마 (재사용)
50
+
51
+ 기존 convergence의 `AGREE` / `DISAGREE` / `SUPPLEMENT` 스키마와 워커 실패 처리 규칙을 그대로 재사용. plan-body 모드에서의 각 평결 의미는 다음과 같다.
52
+
53
+ | 평결 | plan-body 모드 의미 |
54
+ |------|--------------------|
55
+ | `AGREE` | 항목이 실행 가능하고 다른 항목과 내적으로 일관됨 |
56
+ | `DISAGREE` | 항목이 깨짐 — 다음 중 하나 이상: (a) 참조된 file path / symbol 이 다른 step·option과 불일치, (b) command가 실행 불가하거나 ambiguity, (c) validation step이 관측 불가, (d) rollback이 commit 순서·dependency 위반, (e) 명시된 trade-off와 모순 |
57
+ | `SUPPLEMENT` | 항목 자체는 OK이나 누락된 dependency / edge case / 사전조건 보강이 필요함 |
58
+
59
+ 워커 non-result(`timeout`/`error`/no result file) 처리는 finding convergence와 동일 — DISAGREE로 집계하지 않고 `contract-violation` 이벤트만 기록.
60
+
61
+ ## 5. 최종 분류 → Gate 매핑
62
+
63
+ `effectiveMaxRounds = 1` 이므로 단일 라운드 결과로 결정.
64
+
65
+ | 항목 분류 | Gate 동작 |
66
+ |----------|----------|
67
+ | `full-consensus AGREE` | 통과. 보고서에 기록. |
68
+ | `partial-consensus` (majority AGREE, 일부 DISAGREE) | 통과(`passed-with-dissent`). 반대 의견은 보고서 4.5.9 섹션에 기록. |
69
+ | `majority DISAGREE` | **gate 차단**. clarification row 변환. User Approval 체크박스 라인 자체를 렌더하지 않음. |
70
+ | `worker-unique DISAGREE` (1명만 반대) | 통과. 보고서 기록만. |
71
+ | `contested` (round 1 종료 시 큐 잔류 — maxRounds=1에서는 partial-consensus 와 동일 취급) | partial-consensus 로 fold-in. |
72
+ | 모든 워커 non-result | 라운드 전체 실패. `aborted-non-result` 기록 + User Approval 체크박스 라인 렌더하지 않음 + clarification에 "plan-body verification could not run" row 추가. |
73
+
74
+ ## 6. 변경 파일
75
+
76
+ ### 6.1 `prompts/profiles/implementation-planning.md`
77
+ - `Required deliverable shape` 끝에 새 bullet: "the final report MUST include a `## 4.5.9 Plan Body Verification` section populated by the post-synthesis worker verification round (see `okstra-convergence` "Plan-body verification mode")."
78
+ - `Approval gate` 항목 보강: User Approval 체크박스 라인은 **plan-body verification gate가 `passed` 또는 `passed-with-dissent`일 때만 렌더된다**. `blocked-by-disagreement` / `aborted-non-result` 면 라인 자체를 생략하고 clarification 표로 사용자에게 던진다.
79
+ - `Self-review pass` 끝에 6번 항목 신설: "If plan-body verification produced `DISAGREE` majority on any P-* item, convert each into a row of `## 5. Clarification Items` with `Blocks=approval`. Do NOT create a parallel `Open Questions` block."
80
+
81
+ ### 6.2 `skills/okstra-convergence/SKILL.md`
82
+ - 신규 섹션 추가: "Plan-body verification mode (implementation-planning only)"
83
+ - 본문 내용:
84
+ - **선행 흐름**: Phase 5.5 finding convergence → Phase 6 report-writer → plan-body verification round → User Approval
85
+ - finding 큐와 plan-item 큐는 **서로 독립**. 같은 워커, 같은 평결 스키마, 같은 wrapper 인프라를 재사용하되 state file은 별도(`plan-body-verification.json`).
86
+ - **MUTUAL EXCLUSION (BLOCKING)**: finding convergence 의 reverify prompt에 P-* item을 끼워 넣거나, plan-body 라운드의 reverify prompt에 F-* finding을 끼워 넣지 말 것.
87
+ - plan-body 라운드 전용 reverify prompt 본문 템플릿 (§7 참고).
88
+ - prompt anchor 5종은 finding convergence와 동일하게 유지.
89
+
90
+ ### 6.3 `templates/reports/final-report.template.md`
91
+ - 신규 sub-section `### 4.5.9 Plan Body Verification` 추가. 위치: 기존 `### 4.5.8 User Approval Request` 직후, `## 4.6 Release Handoff Deliverables` 직전 (implementation-planning 4.5 블록의 마지막 sub-section).
92
+ - 필드:
93
+
94
+ ```
95
+ ## 4.5.9 Plan Body Verification
96
+
97
+ - Round count: <N>
98
+ - Gate result: <passed | passed-with-dissent | blocked-by-disagreement | aborted-non-result>
99
+ - Verdict table:
100
+
101
+ | Plan item | Ticket ID | Section | <worker1> | <worker2> | ... | Classification |
102
+ |-----------|-----------|---------|-----------|-----------|-----|----------------|
103
+ | P-Opt-1 | ... | 4.5.1 | AGREE | AGREE | ... | full-consensus |
104
+ | P-Step-3 | ... | 4.5.4 | DISAGREE | DISAGREE | ... | majority-disagree → C-7 |
105
+
106
+ - Dissent log: (partial-consensus / worker-unique 인 항목의 반대 의견 본문)
107
+ ```
108
+
109
+ ### 6.4 `validators/validate-run.py`
110
+ - `implementation-planning` phase 일 때 final-report에서 다음 substring을 필수로 검사:
111
+ - `Plan Body Verification`
112
+ - Approval gate 라인 검사 로직 보강: gate 결과가 `passed` / `passed-with-dissent` 이면 `- [ ] Approved` / `- [x] Approved` 라인이 반드시 존재해야 하고, `blocked-by-disagreement` / `aborted-non-result` 이면 해당 라인이 **존재하지 않아야** 한다.
113
+
114
+ ### 6.5 `scripts/okstra_ctl/render.py` (task-manifest payload)
115
+ 현재 codebase 에는 task-manifest 를 위한 Python dataclass 가 없다 (`models.py` 는 model alias 전용). manifest payload 는 `render_task_manifest()` 안에서 dict literal 로 직접 구성된다. 기존 `convergence` 블록은 아직 manifest 에 출력되지 않으며, skill 문서에만 "있으면 읽고 없으면 default" 로 기술돼 있다. 따라서:
116
+
117
+ - `render_task_manifest()` payload 에 신규 `convergence` 블록을 명시적으로 출력한다:
118
+
119
+ ```json
120
+ "convergence": {
121
+ "enabled": true,
122
+ "maxRounds": <phase-aware default>,
123
+ "verificationMode": "lightweight",
124
+ "planBodyVerification": {
125
+ "enabled": true,
126
+ "maxRounds": 1,
127
+ "gating": true
128
+ }
129
+ }
130
+ ```
131
+
132
+ - `maxRounds`: `requirements-discovery` 면 1, 그 외 phase 면 2 (기존 skill 문서의 default 그대로).
133
+ - `planBodyVerification.enabled`: task-type 이 `implementation-planning` 일 때만 의미를 가진다. 다른 phase 에서는 무시되어도 안전한 dead-letter 필드 (스키마 일관성을 위해 항상 출력).
134
+ - ctx 입력 키 (CLI / wizard / interactive 입력 → ctx env 로 합류):
135
+ - `OKSTRA_PLAN_VERIFICATION` ∈ `{"true","false",""}` — 빈 값이면 default(true). 명령행 `--no-plan-verification` 가 `"false"` 로 set.
136
+ - 추후 `OKSTRA_PLAN_VERIFICATION_MAX_ROUNDS` 같은 추가 knob 가능하지만 본 spec 범위에서는 1 고정.
137
+ - 기존 manifest 와의 호환: render 마다 payload 가 매 회 다시 쓰이므로 (`render_task_manifest` 의 `existing` 머지 대상은 `workflow` 일부와 `createdAt`/`latestRunPath` 같은 lifecycle 키뿐) `convergence` 블록은 매 render 마다 새로 작성된다. legacy task-key 의 resume 시 ctx 가 default(true) 면 자동으로 enabled 가 set 된다 (§8 마이그레이션 항목 그대로).
138
+
139
+ ### 6.6 `agents/SKILL.md` (lead orchestration skill — markdown only, no Python)
140
+
141
+ **아키텍처 정정**: okstra 의 orchestration 패턴은 conversational-only 다. Python 코드(`scripts/okstra_ctl/`)는 task bundle 준비 / 템플릿 렌더링 / validation 만 담당하고, Phase 4 (워커 dispatch), Phase 5.5 (convergence), Phase 6 (report-writer dispatch) 등 **모든 phase 실행은 lead 가 SKILL.md 명세를 따라 inline 으로 Agent() 호출**로 수행한다. `render.py:1133` 의 rendered prompt 문구 ("convergence loop. The Claude lead performs every step inline") 와 run.py 에 convergence 관련 dispatch 함수가 존재하지 않는 점이 이 패턴을 확인해 준다.
142
+
143
+ 따라서 plan-body verification 도 별도 Python 함수 추가 없이, lead skill 의 Phase 6 섹션 확장만으로 wiring 한다.
144
+
145
+ - `agents/SKILL.md` 의 "Phase 6: Final report assembly" 섹션 끝에 새 sub-step 추가:
146
+ - report-writer draft 검토 후 → `task_type == "implementation-planning"` 이고 manifest 의 `convergence.planBodyVerification.enabled == true` 면 → `okstra-convergence` "Plan-body verification mode" sub-skill invoke (이 명세는 §6.2 Phase D 에서 추가됨).
147
+ - 라운드 결과(`gateResult`) 에 따라 §6.3 양식의 `### 4.5.9 Plan Body Verification` 섹션을 final-report 에 직접 채우고, `majority-disagree` 항목은 `## 5. Clarification Items` 의 `Blocks=approval` row 로 변환. (이 변환 로직은 §6.1 Phase C 의 self-review step 6 가 lead 에게 BLOCKING 으로 명령.)
148
+ - 변환 완료 후, Gate result 에 따라 top-of-report Approval marker 의 렌더 / 비렌더 결정 (이 룰은 §6.1 Phase C 의 Approval gate bullet 이 BLOCKING 으로 명령, §6.4 Phase B 의 validator 가 실행 후 검사).
149
+ - `agents/SKILL.md` 상단 "Lifecycle / Skill index" 표(line 28 근처)에 plan-body verification 이 Phase 6 의 sub-step 임을 한 줄 명시 — 별도 phase 식별자는 부여하지 **않는다** (spec §2 Q2 = lifecycle 내부 step).
150
+
151
+ **Single-reference-point invariant**: Python dispatch 함수가 존재하지 않으므로 분기 가능성 자체가 없다. 모든 entry point (CLI / skill / interactive) 가 동일한 `task-manifest.json` 의 `convergence.planBodyVerification` 블록을 읽고, 동일한 `okstra-convergence` SKILL.md "Plan-body verification mode" 명세를 따라 lead 가 수행한다. 메모리상의 `prepare_task_bundle` 수렴 invariant 는 manifest 생성 시점에서만 의미를 가지며, 이는 §6.5 Phase B 에서 이미 완료됨.
152
+
153
+ ### 6.7 CLI 진입점 (single reference point 준수)
154
+ 세 진입점 모두 동일한 manifest write 경로(`prepare_task_bundle`)로 수렴해야 한다.
155
+
156
+ - `scripts/okstra.sh` — `--no-plan-verification` 플래그 추가 (boolean off)
157
+ - `scripts/lib/okstra-ctl/` Bash 라우팅 — flag → CLI args 통과만 (business logic 없음)
158
+ - `bin/okstra` (Node CLI) — `setup` / `config set` 경로에서 `plan-verification` 키 지원
159
+ - `okstra config set plan-verification <on|off> [--scope project|global]` 명령 추가 (기존 `pr-template-path` 패턴 답습)
160
+
161
+ flag 우선순위: 명령행 `--no-plan-verification` > 프로젝트 config (`project.json` `planVerification`) > 글로벌 config (`~/.okstra/config.json` `planVerification`) > 기본값 ON.
162
+
163
+ ### 6.8 인터랙티브 skill 진입점
164
+ `skills/okstra-run/SKILL.md` 의 Step 6 (worker / option 선택) 에 다음 질문 추가:
165
+
166
+ > "implementation-planning 의 plan-body 검증 라운드를 활성화할까요? (default: yes — 합성된 plan을 워커가 peer-review)"
167
+
168
+ `AskUserQuestion` 의 옵션은 yes / no 단일 선택. 사용자 선택은 manifest의 `plan_body_verification.enabled` 로 기록.
169
+
170
+ ## 7. plan-body 모드 reverify prompt 템플릿 (lightweight 만 지원)
171
+
172
+ `full-reanalysis` 모드는 plan-body에 대해서는 의미가 약함(원본은 워커 자신의 분석 + lead 합성 결과이므로 "원본 재검토"의 정의가 모호). 따라서 plan-body 모드는 lightweight만 지원하고 manifest의 `verificationMode` 와는 독립적으로 동작한다.
173
+
174
+ ```
175
+ You are <worker-role> performing plan-body verification for <task-key> (round 1).
176
+
177
+ ## Instructions
178
+
179
+ Review the following items extracted from the consolidated implementation plan
180
+ authored after your initial analysis. For EACH item, respond with exactly one verdict:
181
+
182
+ - **AGREE**: The item is executable as written and internally consistent with
183
+ other items in the plan.
184
+ - **DISAGREE**: The item is broken. Cite which kind of breakage:
185
+ (a) referenced file path / symbol mismatches another step or option,
186
+ (b) command is not executable or is ambiguous,
187
+ (c) validation signal is not observable,
188
+ (d) rollback violates commit / dependency order,
189
+ (e) item contradicts the trade-off matrix.
190
+ - **SUPPLEMENT**: The item is sound but a dependency / edge case / precondition
191
+ is missing.
192
+
193
+ Do NOT re-analyze the original requirements. Judge solely from plan internal
194
+ consistency and stated commands / paths.
195
+
196
+ ## Plan items to verify
197
+
198
+ ### P-Step-3 [TICKETID: <id>]: <one-line summary>
199
+ **From section**: 4.5.4 Stepwise Execution Order
200
+ **Original text**:
201
+ > <verbatim quote of the step>
202
+
203
+ **Check**:
204
+ - Are referenced file paths consistent with the option's File Structure list?
205
+ - Is the named command executable as written?
206
+ - Does the success criterion produce an observable signal?
207
+
208
+ ### P-Opt-2 [TICKETID: <id>]: <one-line summary>
209
+ ...
210
+
211
+ ## Response format
212
+
213
+ ### P-Step-3
214
+ **Verdict**: AGREE | DISAGREE(<a|b|c|d|e>) | SUPPLEMENT
215
+ **Explanation**: <2-3 sentences>
216
+
217
+ ### P-Opt-2
218
+ ...
219
+ ```
220
+
221
+ ## 8. 마이그레이션 / 호환성
222
+
223
+ - **신규 task-key**: manifest에 plan_body_verification 기본값 ON으로 기록. 정상 동작.
224
+ - **legacy task-key** (이미 implementation-planning을 한 번 돌렸으나 implementation으로 넘어가지 않은 task-key): manifest에 `plan_body_verification` 키 없음.
225
+ - resume 시 lead가 기본값 ON으로 채워 1라운드 dispatch를 추가 실행한다.
226
+ - **사용자 영향**: 기존 IP 산출물이 있어도 resume 시 한 라운드가 추가됨. 원치 않는 경우 resume 명령에 `--no-plan-verification`을 명시하거나 project config로 영구 off.
227
+ - 이 동작은 `CHANGES.md` 의 `사용자 영향:` 라인에 명시한다.
228
+
229
+ ## 9. 검증 가능성 / 테스트 포인트
230
+
231
+ 1. **manifest 기본값 / override**: `plan_body_verification` 키 누락 시 기본값 주입, `--no-plan-verification` 명령행 옵션 우선순위 (unit).
232
+ 2. **plan-item 파서**: §3 분리 규칙대로 P-Opt / P-Step / P-Dep / P-Val / P-Rb 가 추출되는지, Ticket ID 태그 보존 (unit).
233
+ 3. **verdict aggregation**: §5 매핑 4가지 케이스 모두 (unit).
234
+ 4. **majority DISAGREE → clarification row 변환** round-trip: P-* item → `## 5. Clarification Items` row(`Blocks=approval`) → `--resume-clarification` 흐름에서 사용자 응답이 다음 run에 carry-in (unit + e2e).
235
+ 5. **Approval 체크박스 라인 조건부 렌더**: gate 결과 4가지에 따라 라인 존재/부재 (unit + validator).
236
+ 6. **e2e 시나리오**: 의도적으로 깨진 plan(예: step의 file path가 option의 File Structure와 불일치)을 inject한 task를 돌려, DISAGREE 발생 → clarification 자동 추가 → resume 후 통과까지의 full happy path (e2e).
237
+ 7. **워커 non-result**: 모든 워커가 timeout / error 일 때 `aborted-non-result` 분류 + Approval 라인 부재 + clarification에 "could not run" row (unit).
238
+
239
+ ## 10. 위험 / 미해결 항목
240
+
241
+ 1. **report-writer 재호출 안 함** (Q4=b) 으로 인해, majority DISAGREE → clarification 변환 누락이 발생하면 사용자에게 dead-end(Approval 라인은 사라졌는데 무엇을 고쳐야 하는지 안 보이는 상태) 가 노출된다. 변환 round-trip 단위 테스트를 BLOCKING으로 잠근다.
242
+
243
+ 2. **convergence 스킬 안에 mode 두 개 공존** (finding / plan-body). 본문 첫 줄에 MUTUAL EXCLUSION 박스를 두고 future Claude 가 두 큐를 섞지 않도록 명시.
244
+
245
+ 3. **maxRounds=1의 `contested` 정의**: 기존 finding convergence의 `contested`는 maxRounds 도달 시점의 잔류 큐에 부여되는 라벨. plan-body 모드에서 maxRounds=1 인 경우 round 1 종료 직후의 partial-consensus와 사실상 구별 불가. §5 표에서 `contested → partial-consensus 로 fold-in` 으로 명시했지만, 사용자가 manifest 에서 maxRounds=2,3 으로 override 한 경우엔 finding 모드와 동일한 정의가 살아남는다는 점을 스킬 본문에 명시 필요.
246
+
247
+ 4. **plan-item 파서의 robustness**: report-writer 가 markdown 구조를 약간 다르게 작성할 가능성(예: option 헤더 들여쓰기 깊이). 파서는 `## 4.5`, `### 4.5.x` 헤더 + `Stepwise Execution Order` substring 같은 anchored 검색을 사용하고, 추출 실패 시 `aborted-non-result` 와 동등하게 처리한다.
248
+
249
+ 5. **CLI flag 단일 진입점**: 메모리상의 invariant(`prepare_task_bundle` 단일 수렴) 를 유지해야 함. flag → manifest 의 변환은 Python 측 한 곳에서만 수행되도록 분기 막기.
250
+
251
+ ## 11. 후속 작업 (out of scope)
252
+
253
+ - error-analysis 결과물 (cause analysis 통합본) 에도 유사한 검증 라운드를 추가할지 여부 — 본 spec 범위 밖. plan-body 검증이 안정화된 후 별도 spec으로 검토.
254
+ - requirements-discovery 의 routing decision 자체에 대한 검증 라운드 — 동일하게 후속 검토 대상.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.25.0",
3
- "builtAt": "2026-05-15T07:26:25.848Z",
2
+ "package": "0.26.0",
3
+ "builtAt": "2026-05-15T14:37:59.243Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -25,7 +25,7 @@ This SKILL.md is the operating contract and phase index. Detailed procedures liv
25
25
  |-------|-------|
26
26
  | [okstra-context-loader](./skills/okstra-context-loader/SKILL.md) | Phase 1 task-bundle discovery, manifest fields, run-directory layout |
27
27
  | [okstra-team-contract](./skills/okstra-team-contract/SKILL.md) | Phase 2–5 worker roster, model assignment rules, prompt composition (anchor headers, `[Required reading]`, `[Error reporting]`), worker output contract, terminal statuses, usage tracking |
28
- | [okstra-convergence](./skills/okstra-convergence/SKILL.md) | Phase 5.5 convergence loop, finding categories, reverify dispatch (anchor headers, required-reading suppression), convergence state schema |
28
+ | [okstra-convergence](./skills/okstra-convergence/SKILL.md) | Phase 5.5 finding convergence loop, finding categories, reverify dispatch (anchor headers, required-reading suppression), convergence state schema, **plus Phase 6 plan-body verification mode (implementation-planning only)** |
29
29
  | [okstra-report-writer](./skills/okstra-report-writer/SKILL.md) | Phase 6 final-report authorship, dispatch template, resume-safe dispatch, shared-graph integrity check, Phase 7 token-usage collector |
30
30
  | [okstra-status](./skills/okstra-status/SKILL.md) | Project/task status views and `workStatus` updates |
31
31
  | [okstra-history](./skills/okstra-history/SKILL.md) | Past-run history, re-run command assembly, resume helper |
@@ -45,7 +45,7 @@ This SKILL.md is the operating contract and phase index. Detailed procedures liv
45
45
  | 4. Execution | Spawn analysis workers (Teams preferred) | `okstra-team-contract` |
46
46
  | 5. Fallback | Sequential/background dispatch when Teams unavailable | `okstra-team-contract` |
47
47
  | 5.5 Convergence | Cross-verify findings across workers | `okstra-convergence` |
48
- | 6. Synthesis | Dispatch Report writer worker, review draft | `okstra-report-writer` |
48
+ | 6. Synthesis | Dispatch Report writer worker, review draft. **For `implementation-planning`: then run the Phase 6 plan-body verification sub-step (see Phase 6 section below).** | `okstra-report-writer` + `okstra-convergence` (sub-step) |
49
49
  | 7. Persist | Run token-usage collector, update manifests | `okstra-report-writer` |
50
50
 
51
51
  ## Core operating contract
@@ -234,6 +234,34 @@ All categories must appear in the final synthesis. Do not omit contested or work
234
234
 
235
235
  If only one worker result is usable: reduced-confidence synthesis. If evidence is missing: say `I don't know`. If no meaningful worker differences: say so explicitly.
236
236
 
237
+ ### Phase 6 sub-step: Plan-body verification (implementation-planning only, BLOCKING)
238
+
239
+ After the Report writer worker draft is reviewed (or after the lead-authored fallback completes), **if** `task_type == "implementation-planning"` **and** `task-manifest.json` `convergence.planBodyVerification.enabled == true` (default), the lead MUST run one additional verification round on the consolidated plan body before declaring Phase 6 complete and entering Phase 7.
240
+
241
+ This is a Phase 6 sub-step — it does NOT introduce a new top-level lifecycle phase. The 6-phase model (1 Intake → 2 Render → 3 Team → 4 Workers → 5 Synthesis prep → 5.5 Convergence → 6 Synthesis → 7 Persist) is preserved.
242
+
243
+ **REQUIRED SUB-SKILL:** Invoke [okstra-convergence](./skills/okstra-convergence/SKILL.md) "Plan-body verification mode (implementation-planning only)" for the round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics (`AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`), classification rules, gate-result resolution, and the state-file schema at `runs/<task-type>/state/plan-body-verification.json`.
244
+
245
+ Distinct from Phase 5.5 finding convergence:
246
+
247
+ - Phase 5.5 reconciles worker **findings** (F-*) from independent analysis.
248
+ - This sub-step reconciles the **consolidated plan body** (P-*) authored by the Report writer worker.
249
+ - The two rounds use disjoint queues and separate state files — see [okstra-convergence](./skills/okstra-convergence/SKILL.md) "MUTUAL EXCLUSION (BLOCKING)".
250
+
251
+ Lead's responsibilities in this sub-step (in order):
252
+
253
+ 1. Extract `P-*` plan items from the draft report's `## 4.5 Implementation Plan Deliverables` per the prefix → source-section mapping in the convergence skill.
254
+ 2. Dispatch a single plan-body reverify round to every analyser worker in the roster (`claude`, `codex`, and `gemini` when opted in). `Report writer worker` is NOT a participant in this round.
255
+ 3. Aggregate verdicts and resolve the gate result to one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`.
256
+ 4. Write `runs/<task-type>/state/plan-body-verification.json` (schema in the convergence skill).
257
+ 5. Populate `### 4.5.9 Plan Body Verification` in the final-report file (template at `templates/reports/final-report.template.md` §4.5.9 — Round count, Gate result, Verdict table, Dissent log).
258
+ 6. For every `majority-disagree` plan item, append a row to `## 5. Clarification Items` with `Blocks=approval` and the 1:1 ID match in the verdict table's `Classification` column (`majority-disagree → C-<N>`). Do NOT create a parallel `Open Questions` block — see `prompts/profiles/implementation-planning.md` self-review step 6 for the orphan-on-either-side contract.
259
+ 7. Conditionally render the top-of-report `- [ ] Approved` marker line: present iff gate ∈ {passed, passed-with-dissent}, absent iff gate ∈ {blocked-by-disagreement, aborted-non-result}. `validators/validate-run.py` `validate_phase_boundary` enforces this correspondence. Manually flipping a blocked gate to passing in order to render the marker is a contract violation.
260
+
261
+ If `convergence.planBodyVerification.enabled == false` (set by `--no-plan-verification` or by `okstra config set plan-verification off`), the entire sub-step is skipped and the top-of-report Approval marker is rendered unconditionally (legacy behaviour). This opt-out is intended for fast iteration only and is not recommended for handoff-ready plans.
262
+
263
+ `/okstra-status` exposes the sub-step's state as a `planVerification` sub-field of the implementation-planning phase, not as a separate lifecycle phase identifier.
264
+
237
265
  ## Phase 7: Artifact persistence and validator handoff
238
266
 
239
267
  The detailed persistence checklist and the BLOCKING token-usage collector invocation live in [okstra-report-writer](./skills/okstra-report-writer/SKILL.md). Persist the run yourself — do not assume okstra saves the final artifacts for you.
@@ -122,6 +122,7 @@ PY_ARGS=(
122
122
  [[ -n "${BASE_REF-}" ]] && PY_ARGS+=(--base-ref "$BASE_REF")
123
123
  [[ "$RENDER_ONLY" == "true" ]] && PY_ARGS+=(--render-only)
124
124
  [[ "$REFRESH_OKSTRA_ASSETS" == "true" ]] && PY_ARGS+=(--refresh-assets)
125
+ [[ "$PLAN_VERIFICATION_ENABLED" == "false" ]] && PY_ARGS+=(--no-plan-verification)
125
126
 
126
127
  if [[ "$RENDER_ONLY" == "true" ]]; then
127
128
  okstra_py -m okstra_ctl.run "${PY_ARGS[@]}"
@@ -11,6 +11,11 @@ profile document.
11
11
  - default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`sonnet`, `Codex worker`=`gpt-5.5`, `Gemini worker`=`auto`. Phase-specific overrides (e.g. `implementation`'s executor binding) live in the per-profile document.
12
12
  - every required worker listed in the per-profile `Required workers:` block must be attempted; the final verdict waits until each has either a result or an explicit terminal status (`timeout`, `error`, `not-run`).
13
13
  - unnamed generic parallel workers must not replace the required role roster, and no additional sub-agent dispatch is allowed beyond this roster.
14
+ - Worker interaction model (shared — read before inferring behaviour from the roster):
15
+ - the per-profile `Required workers:` block is a **roster**, not a behaviour contract. Each role's interaction mode changes across operating phases of the same run.
16
+ - **Phase 4 / 5 (independent analysis)**: analyser workers (`claude`, `codex`, `gemini` when opted in) produce findings independently and have no access to one another's outputs. `report-writer` does not analyse.
17
+ - **Phase 5.5 (convergence — peer review by workers)**: the lead replays each analyser's findings to the *other* analysers and collects `AGREE` / `DISAGREE` / `SUPPLEMENT` verdicts across up to `effectiveMaxRounds` rounds. Workers act as peer reviewers of each other's findings in this phase; the lead mediates but does not vote. See `skills/okstra-convergence/SKILL.md` for the round protocol, queue invariants, and final classification (`full-consensus` / `partial-consensus` / `contested` / `worker-unique`).
18
+ - Do NOT conclude "no peer review happens" from the roster alone — every profile that lists ≥2 analyser workers runs convergence by default (`convergence.enabled=true` in `task-manifest.json`).
14
19
  - Tooling — read-only MCP availability (shared):
15
20
  - the read-only MCP servers declared in the task brief's `## Available MCP Servers` section may be queried as a read-only cross-check; that section is the canonical source of which servers and tools exist for this run, and any MCP-derived finding MUST cite server, table, and the SELECT used. MCP MUST NEVER be used as a write path — schema/data mutations go through repository migration files reviewed by humans.
16
21
  - Authority & permissions assumption (HARD RULE — applies to every okstra task-type):
@@ -57,7 +57,9 @@
57
57
  - validation checklist (pre / mid / post) — each item is an exact command or observable outcome
58
58
  - rollback strategy — exact revert path (commits, flags, migrations) and the signal that triggers rollback
59
59
  - explicit `User Approval Request (사용자 승인 게이트)` block placed at the **top of the report** with a single canonical checkbox marker `- [ ] Approved` (user toggles to `- [x] Approved` to authorise the next `implementation` run). Section `4.5.8` is retained only as a back-pointer to this top block for validator/key-substring compatibility — it must NOT carry an independent marker.
60
+ - **the marker line is rendered only when the plan-body verification gate (§4.5.9) returns `passed` or `passed-with-dissent`.** When the gate returns `blocked-by-disagreement` or `aborted-non-result`, the top-of-report Approval block is rendered **without** the canonical `- [ ] Approved` bullet (the rest of the block — title, summary, audit lines — stays). The `validators/validate-run.py` `validate_phase_boundary` function enforces this exact correspondence between gate result and marker line presence.
60
61
  - every ambiguity flagged during pre-planning that the user must resolve before approval registered as a `Blocks=approval` row in the `## 5. Clarification Items` table (do NOT create a separate `Open Questions` block under `4.5.x` — the unified table is the single home)
62
+ - **§4.5.9 Plan Body Verification (BLOCKING).** After report-writer finishes the draft, the lead MUST run a worker peer-review round on the consolidated plan body (sections 4.5.1 – 4.5.7) and populate `### 4.5.9 Plan Body Verification` in the final report. The round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics, gate-result classification, and dissent log format are defined in `skills/okstra-convergence/SKILL.md` "Plan-body verification mode". The four gate-result values are `passed`, `passed-with-dissent`, `blocked-by-disagreement`, `aborted-non-result`. When the gate would have been `blocked-by-disagreement` or `aborted-non-result`, the lead MUST NOT silently flip it to one of the passing values to "unblock" the run — that is a contract violation.
61
63
  - No-placeholder rule (plan failures — reject any option or step that contains these):
62
64
  - "TBD", "TODO", "implement later", "fill in details", "add appropriate error handling", "handle edge cases", "write tests for the above" without actual test code
63
65
  - "similar to Option/Task N" without repeating the concrete content (readers may consume sections out of order)
@@ -69,3 +71,4 @@
69
71
  3. **Internal consistency** — option file lists, trade-off matrix, and recommended step list must agree on file paths, names, and signatures. A symbol called `clearLayers()` in the matrix and `clearFullLayers()` in the steps is a bug.
70
72
  4. **Ambiguity check** — any requirement that could be read two ways must be made explicit or moved to the `## 5. Clarification Items` table as a `Blocks=approval` row.
71
73
  5. **Scope check** — if the recommended plan now spans multiple independent subsystems, recommend splitting into separate planning runs rather than shipping an oversized plan.
74
+ 6. **Plan-body verification reconciliation (BLOCKING for implementation-planning).** Inspect the `### 4.5.9 Plan Body Verification` verdict table. For every plan-item row classified as `majority-disagree → C-<N>`, the corresponding `C-<N>` row MUST exist in `## 5. Clarification Items` with `Kind` chosen per the standard policy and `Blocks=approval`. Do NOT create a parallel `### 4.5.x Open Questions` block — the unified table is the single home. Conversely, the `Classification` column's `C-<N>` reference and the `## 5. Clarification Items` `ID` column MUST match 1:1; an orphan on either side is a contract violation. For `partial-consensus` and `worker-unique` plan-items, the dissenting opinion lives in §4.5.9 `Dissent log` and is NOT promoted to §5.
@@ -195,6 +195,13 @@ while [[ $# -gt 0 ]]; do
195
195
  APPROVE_PLAN_ACK="true"
196
196
  shift
197
197
  ;;
198
+ --no-plan-verification)
199
+ # implementation-planning 의 Phase 6 plan-body verification 라운드를
200
+ # 끈다. 기본값은 활성화. 비활성 시 final-report 상단의 User Approval
201
+ # 체크박스는 무조건 렌더된다 (legacy 동작). 빠른 반복용 opt-out.
202
+ PLAN_VERIFICATION_ENABLED="false"
203
+ shift
204
+ ;;
198
205
  -h|--help)
199
206
  usage
200
207
  exit 0
@@ -224,7 +231,7 @@ while [[ $# -gt 0 ]]; do
224
231
  printf ' hint: did you mean --task-id?\n' >&2
225
232
  ;;
226
233
  esac
227
- printf ' valid options: --render-only --resume-clarification --yes --refresh-assets --workers --lead-model --claude-model --codex-model --gemini-model --report-writer-model --related-tasks --task-type --project-id --project-root --task-group --task-id --task-brief --directive --clarification-response --approved-plan --approve -h|--help\n' >&2
234
+ printf ' valid options: --render-only --resume-clarification --yes --refresh-assets --workers --lead-model --claude-model --codex-model --gemini-model --report-writer-model --related-tasks --task-type --project-id --project-root --task-group --task-id --task-brief --directive --clarification-response --approved-plan --approve --no-plan-verification -h|--help\n' >&2
228
235
  usage
229
236
  exit 1
230
237
  ;;
@@ -40,6 +40,9 @@ DIRECTIVE=""
40
40
  CLARIFICATION_RESPONSE_PATH=""
41
41
  APPROVED_PLAN_PATH=""
42
42
  APPROVE_PLAN_ACK="false"
43
+ # Phase 6 plan-body verification toggle. Default "true" (round runs).
44
+ # Flipped to "false" by --no-plan-verification on the CLI.
45
+ PLAN_VERIFICATION_ENABLED="true"
43
46
  CLARIFICATION_RESPONSE_FILE=""
44
47
  CLARIFICATION_RESPONSE_RELATIVE_PATH=""
45
48
  PROJECT_ROOT=""
@@ -3,7 +3,7 @@
3
3
  usage() {
4
4
  cat >&2 <<USAGE_EOF
5
5
  usage:
6
- $DISPLAY_COMMAND_NAME [--render-only] [--yes] [--refresh-assets] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--executor claude|codex|gemini] [--related-tasks taskA,taskB] --project-id <project-id> [--project-root <path>] --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>]
6
+ $DISPLAY_COMMAND_NAME [--render-only] [--yes] [--refresh-assets] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--gemini-model <model>] [--report-writer-model <model>] [--executor claude|codex|gemini] [--related-tasks taskA,taskB] --project-id <project-id> [--project-root <path>] --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>]
7
7
 
8
8
  summary:
9
9
  $DISPLAY_TOOL_NAME prepares a task-keyed instruction bundle for Claude Code and launches an interactive Claude session by default.
@@ -45,6 +45,13 @@ optional arguments:
45
45
  \`- [ ] Approved\` to \`- [x] Approved\` and appends an approval audit line
46
46
  (timestamp + "CLI --approve"). Use this for scripted/CI flows or when you want a
47
47
  single command to both approve and launch the next phase.
48
+ --no-plan-verification
49
+ Disable the Phase 6 plan-body verification round that runs after the report-writer
50
+ authors the implementation-planning draft. Default: enabled. Only meaningful with
51
+ --task-type=implementation-planning; ignored for other task types. When disabled the
52
+ top-of-report \`User Approval Request\` checkbox renders unconditionally (legacy
53
+ behaviour). Use this for fast iteration; the default is recommended for handoff-ready
54
+ plans.
48
55
  --task-key <project-id:task-group:task-id>
49
56
  Shorthand for --project-id/--task-group/--task-id. When the matching task-manifest.json
50
57
  exists, brief-path and task-type are auto-filled from it (taskBriefPath and
@@ -586,6 +586,7 @@ def render_task_manifest(manifest_path: str, ctx: dict) -> None:
586
586
  latest_report_relative = current_report_relative or existing.get("latestReportPath", "")
587
587
  latest_team_state_relative = ctx.get("TEAM_STATE_RELATIVE_PATH", "")
588
588
  latest_resume_command_relative = ctx.get("CLAUDE_RESUME_COMMAND_RELATIVE_PATH", "") or existing.get("latestResumeCommandPath", "")
589
+ convergence_block = _build_convergence_block(ctx)
589
590
  payload = {
590
591
  "schemaVersion": "1.0",
591
592
  "projectId": ctx.get("PROJECT_ID", ""),
@@ -695,12 +696,43 @@ def render_task_manifest(manifest_path: str, ctx: dict) -> None:
695
696
  "sessionId": ctx.get("CLAUDE_SESSION_ID", ""),
696
697
  "resumeCommandPath": ctx.get("CLAUDE_RESUME_COMMAND_RELATIVE_PATH", ""),
697
698
  },
699
+ "convergence": convergence_block,
698
700
  "createdAt": existing.get("createdAt") or ctx.get("RUN_TIMESTAMP_ISO", ""),
699
701
  "updatedAt": ctx.get("RUN_TIMESTAMP_ISO", ""),
700
702
  }
701
703
  _write_json(path, payload)
702
704
 
703
705
 
706
+ def _build_convergence_block(ctx: dict) -> dict:
707
+ """Resolve the `convergence` sub-tree written into task-manifest.json.
708
+
709
+ Defaults follow `skills/okstra-convergence/SKILL.md`:
710
+ - `enabled` default True
711
+ - `maxRounds` default 1 for `requirements-discovery`, 2 otherwise
712
+ - `verificationMode` default "lightweight"
713
+ - `planBodyVerification` is implementation-planning specific; the key is
714
+ always emitted (dead-letter on other phases) so the schema stays stable.
715
+
716
+ ctx knobs honoured:
717
+ - `OKSTRA_PLAN_VERIFICATION`: "true" | "false" | "" (empty → default True).
718
+ Wired from CLI `--no-plan-verification` (sets "false").
719
+ """
720
+ task_type = ctx.get("ANALYSIS_TYPE", "")
721
+ default_max_rounds = 1 if task_type == "requirements-discovery" else 2
722
+ raw_plan_verify = (ctx.get("OKSTRA_PLAN_VERIFICATION", "") or "").strip().lower()
723
+ plan_verify_enabled = raw_plan_verify != "false"
724
+ return {
725
+ "enabled": True,
726
+ "maxRounds": default_max_rounds,
727
+ "verificationMode": "lightweight",
728
+ "planBodyVerification": {
729
+ "enabled": plan_verify_enabled,
730
+ "maxRounds": 1,
731
+ "gating": True,
732
+ },
733
+ }
734
+
735
+
704
736
  def render_run_manifest(run_manifest_path: str, ctx: dict) -> None:
705
737
  task_manifest_path = Path(ctx.get("TASK_MANIFEST_FILE", ""))
706
738
  task_manifest = {}
@@ -115,6 +115,11 @@ class PrepareInputs:
115
115
  render_only: bool = False
116
116
  refresh_assets: bool = False
117
117
  approve_plan_ack: bool = False
118
+ # Phase 6 plan-body verification opt-out. Default True (round runs after
119
+ # report-writer draft). Flipped to False by CLI `--no-plan-verification`.
120
+ # Only meaningful for `--task-type implementation-planning`; the manifest
121
+ # records the value for other phases too to keep the schema stable.
122
+ plan_verification_enabled: bool = True
118
123
 
119
124
 
120
125
  @dataclass
@@ -382,6 +387,8 @@ def _canonical_argv(inp: PrepareInputs, ctx: dict) -> list[str]:
382
387
  argv.append("--render-only")
383
388
  if inp.refresh_assets:
384
389
  argv.append("--refresh-assets")
390
+ if not inp.plan_verification_enabled:
391
+ argv.append("--no-plan-verification")
385
392
  argv.append("--yes")
386
393
  return argv
387
394
 
@@ -632,6 +639,13 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
632
639
  "EXECUTOR_WORKTREE_BASE_REF": worktree.base_ref,
633
640
  "EXECUTOR_WORKTREE_STATUS": worktree.status,
634
641
  "EXECUTOR_WORKTREE_NOTE": worktree.note,
642
+ # Phase 6 plan-body verification toggle, read by
643
+ # `render._build_convergence_block` when emitting the manifest's
644
+ # `convergence.planBodyVerification.enabled` field. Default ("")
645
+ # is treated as enabled.
646
+ "OKSTRA_PLAN_VERIFICATION": (
647
+ "false" if not inp.plan_verification_enabled else ""
648
+ ),
635
649
  })
636
650
 
637
651
  if inp.render_only:
@@ -910,6 +924,18 @@ def main(argv: list[str]) -> int:
910
924
  )
911
925
  p.add_argument("--render-only", action="store_true", dest="render_only")
912
926
  p.add_argument("--refresh-assets", action="store_true", dest="refresh_assets")
927
+ p.add_argument(
928
+ "--no-plan-verification",
929
+ action="store_false",
930
+ dest="plan_verification_enabled",
931
+ default=True,
932
+ help=(
933
+ "Disable the Phase 6 plan-body verification round for "
934
+ "`--task-type implementation-planning`. Default: enabled. "
935
+ "When disabled, the top-of-report `User Approval Request` "
936
+ "marker line is rendered unconditionally (legacy behaviour)."
937
+ ),
938
+ )
913
939
  p.add_argument(
914
940
  "--work-category",
915
941
  default="",
@@ -976,6 +1002,7 @@ def main(argv: list[str]) -> int:
976
1002
  render_only=args.render_only,
977
1003
  refresh_assets=args.refresh_assets,
978
1004
  approve_plan_ack=args.approve_plan_ack,
1005
+ plan_verification_enabled=args.plan_verification_enabled,
979
1006
  )
980
1007
  try:
981
1008
  out = prepare_task_bundle(inputs)