okstra 0.56.0 → 0.56.1

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.
@@ -343,7 +343,7 @@ okstra phase 는 PRD / issue file 을 직접 쓰지 않습니다. 동등한 결
343
343
  |---|---|---|---|---|
344
344
  | `requirements-discovery` | 요청을 bugfix/feature/refactor/ops/improvement 중 하나로 분류하고 안전한 다음 phase로 라우팅 | work category, routing decision, missing-input list, clarification requests | `pending-routing-decision` (사용자 답변 후 결정) | 금지 |
345
345
  | `error-analysis` | 보고된 에러/사고의 증상·원인·재현 갭을 증거 기반으로 분석 | symptom/trigger 정리, root-cause 가설, reproduction gap, validation 경로 | `implementation-planning` | 금지 |
346
- | `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, 단계별 실행 순서, validation/rollback, **User Approval Request** 블록, **§5.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 항목이 `## 1. Clarification Items` 의 `Blocks=approval` row 로 변환됨). **산출 구조**: 항상 `## 5.5 Stage Map` + N 개의 `## 5.5.<i> Stage <i>` 섹션. 각 stage 의 effective step ≤ 6. `depends-on (none)` 인 stage 들은 별도 `implementation` run 으로 병렬 실행 가능 | `implementation` (사용자 승인 후) | 금지 |
346
+ | `implementation-planning` | 코딩 시작 전 안전한 구현 방향과 옵션을 평가 | 최소 2개 구현 옵션, 영향 파일 목록, trade-off, validation/rollback, YAML frontmatter `approved: false` / `implementation-option:`, **§5.5.9 Plan Body Verification** (Phase 6 워커 사후 검증 라운드 — 합성된 plan 의 내적 일관성을 워커가 `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT` 로 cross-verify; gate 결과가 `passed` / `passed-with-dissent` 일 때만 사용자가 frontmatter `approved: true` 로 뒤집을 수 있고, `blocked-by-disagreement` / `aborted-non-result` 일 때는 majority DISAGREE 항목이 `## 1. Clarification Items` 의 `Blocks=approval` row 로 변환됨). **산출 구조**: 항상 `## 5.5 Stage Map` + N 개의 `## 5.5.<i> Stage <i>` 섹션. 각 stage 의 effective step ≤ 6. `depends-on (none)` 인 stage 들은 별도 `implementation` run 으로 병렬 실행 가능 | `implementation` (사용자 승인 후) | 금지 |
347
347
  | `implementation` | 승인된 `implementation-planning` final report의 단계대로 소스 코드를 수정. **한 run 에 한 stage 만 실행** (`--stage <auto\|N>` 인수로 stage 선택) | commit list, diff summary, out-of-plan edits 블록, validation/TDD evidence, rollback 검증, verifier 결과(Gemini/Codex/Claude), `carry/stage-<N>.json` evidence sidecar | `final-verification` | 허용 (승인된 plan의 파일 목록 한정, `git push`/publish/deploy/실제 migration 금지) |
348
348
  | `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 테스트만 허용) |
349
349
  | `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 를 그대로 패키징). |
@@ -355,7 +355,7 @@ okstra phase 는 PRD / issue file 을 직접 쓰지 않습니다. 동등한 결
355
355
  - **implementation stage 격리 worktree (동시 병렬)**: 위 task-key 단위 worktree 는 `requirements-discovery`~`implementation-planning` 의 모델입니다. `implementation` task 는 **stage 격리** 로 동작합니다 (spec `docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md`) — **한 run = 한 stage**, 각 run 이 `.../<task-id-segment>/stage-<N>/` (브랜치 `<prefix>-<task-id-segment>-s<N>`) 격리 worktree 를 발급받습니다. registry 가 task-key 와 **stage-key** (`<task-key>#stage-<N>`) 를 함께 flock 예약하고, `_resolve_effective_stages` 가 `consumers.jsonl` 의 `started` + registry 예약 stage 를 ready 집합에서 제외하므로(점유 SSOT = registry), 사용자가 두 `implementation` run 을 동시에 띄우면 서로 다른 독립 stage 를 충돌 없이 진행합니다. base 결정: 독립 = 공통 anchor(첫 stage 진입 HEAD 고정), 단일 의존 = 선행 done commit, 다중 의존 = 선행이 모두 ancestor 인 task worktree HEAD(`git merge-base --is-ancestor`; 미머지 시 `PrepareError`). cost-aware-design 의 ready-set batch 는 stage 마다 격리 branch 가 필요해 의미를 잃으므로(같은 branch 에 두 stage-key reserve 시 branch-uniqueness 충돌) 폐기되었고, 순차 진행은 stage done 후 다음 run, 동시 진행은 별도 run 으로 — cost 등가. `--stage <auto|N>` 또는 wizard `stage_pick` 으로 stage 를 선택합니다.
356
356
  - `implementation` 과 `release-handoff` 를 제외한 모든 phase 는 source code edit, build, migration, deployment, 그 밖의 state-mutating 명령을 금지합니다 (`final-verification` 은 read-only 테스트 명령만 허용). `implementation` 은 승인된 plan 의 파일 목록 안에서만 edit/commit 이 허용되며, `git push`·publish·deploy·실제 migration·third-party write API 는 여전히 금지됩니다. `release-handoff` 는 source code 자체는 수정하지 않고, 사용자가 메뉴로 선택한 commit / push / PR 명령만 실행합니다 (force push, base 브랜치 직접 push, hook bypass, release publish 는 여전히 금지).
357
357
  - 사용자가 "다음 단계 진행해" 같은 표현을 보내도, 그 발화만으로 다음 phase가 자동 시작되지 않습니다. 다음 phase는 새 `okstra.sh` 실행으로만 시작합니다.
358
- - **Authority & permissions assumption (모든 task-type 및 `okstra-schedule` 공통)**: 사용자(및 팀)는 예상되는 모든 작업에 대해 완전한 권한·승인 권한을 보유한다고 가정합니다. 외부 승인, 서드파티 액세스, 역할/IAM 권한, 조직적 sign-off, 법무·보안 검토, 벤더 협의, "권한 보유 여부 확인" 같은 항목을 routing 결정·missing inputs·clarification questions·risk·dependency·open questions·effort/day 추정에 포함하지 않습니다. okstra 내부 phase 핸드오프(`User Approval Request` 등)는 사용자 본인이 즉시 승인 가능한 내부 게이트이므로 영향 없으며, `implementation`의 forbidden actions(`git push`, prod deploy, shared-DB migration 등)도 권한 사유가 아닌 **안전 사유**로 계속 적용됩니다.
358
+ - **Authority & permissions assumption (모든 task-type 및 `okstra-schedule` 공통)**: 사용자(및 팀)는 예상되는 모든 작업에 대해 완전한 권한·승인 권한을 보유한다고 가정합니다. 외부 승인, 서드파티 액세스, 역할/IAM 권한, 조직적 sign-off, 법무·보안 검토, 벤더 협의, "권한 보유 여부 확인" 같은 항목을 routing 결정·missing inputs·clarification questions·risk·dependency·open questions·effort/day 추정에 포함하지 않습니다. okstra 내부 phase 핸드오프(`implementation-planning`의 `approved:` frontmatter 등)는 사용자 본인이 즉시 승인 가능한 내부 게이트이므로 영향 없으며, `implementation`의 forbidden actions(`git push`, prod deploy, shared-DB migration 등)도 권한 사유가 아닌 **안전 사유**로 계속 적용됩니다.
359
359
  - Phase별 상세 규칙은 `prompts/profiles/<task-type>.md`에 정의되어 있고, 그 본문이 그대로 `instruction-set/analysis-profile.md`로 렌더링됩니다.
360
360
 
361
361
  ### Phase 간 정보 전달
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.56.0",
3
+ "version": "0.56.1",
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.56.0",
3
- "builtAt": "2026-06-07T06:39:30.395Z",
2
+ "package": "0.56.1",
3
+ "builtAt": "2026-06-08T16:46:40.339Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -25,7 +25,7 @@ profile document.
25
25
  - Authority & permissions assumption (applies to every okstra task-type):
26
26
  - **Assume the user (and their team) holds full authority and every permission required for the anticipated, in-flight, or follow-up work.** Treat external approvals, third-party access grants, role/IAM permissions, organisational sign-off, legal/compliance review, vendor coordination, and "verify access exists" steps as already satisfied unless the task brief explicitly states otherwise.
27
27
  - Do NOT add such items to routing decisions, missing-materials lists, clarification questions, option trade-offs, dependency/migration risk, validation checklists, rollout plans, acceptance blockers, residual risks, release recommendations, the `## 1. Clarification Items` table, or any day/effort estimate. They are not legitimate sources of schedule extension.
28
- - Internal okstra phase handoffs (e.g. the `User Approval Request` block in `implementation-planning`) are unaffected — those are the user themselves approving and proceed without external coordination.
28
+ - Internal okstra phase handoffs (e.g. the `approved:` frontmatter gate in `implementation-planning`) are unaffected — those are the user themselves approving and proceed without external coordination.
29
29
  - This rule does NOT relax any phase-specific Forbidden actions list; safety rules in the per-profile document remain in force regardless of the user's authority.
30
30
  - Anti-escalation rule (shared):
31
31
  - treating "다음 단계 진행해" or equivalent user phrases as authorisation to start a *different* lifecycle phase is forbidden. The next phase begins only in a separate okstra run launched with the new `--task-type`. Per-profile documents may further restrict this within their own scope.
@@ -61,7 +61,7 @@ profile document.
61
61
  - **Reporter confirmation precondition (BLOCKING)**: the brief's frontmatter carries `reporter-confirmations: <complete | partial | pending | skipped>` set by `okstra-brief` Step 6.5. Every phase that consumes the brief MUST read this field before doing analysis. The handling matrix is:
62
62
  - `complete` → proceed normally.
63
63
  - `partial` → proceed; treat still-unmarked `intent-check:` / `conversion-block:` rows as the `skipped` branch.
64
- - `skipped` → do NOT silently infer the missing answers. Promote each unmarked `intent-check:` / `conversion-block:` row into this run's `## 1. Clarification Items` as `Kind=decision`. Use `Blocks=approval` in `implementation-planning`, where the row gates the User Approval Request; otherwise use `Blocks=next-phase`. The recommended answer is drawn from the brief's matching content and clearly labelled `보고자 직접 확인 권장`.
64
+ - `skipped` → do NOT silently infer the missing answers. Promote each unmarked `intent-check:` / `conversion-block:` row into this run's `## 1. Clarification Items` as `Kind=decision`. Use `Blocks=approval` in `implementation-planning`, where the row gates the `approved:` frontmatter flip; otherwise use `Blocks=next-phase`. The recommended answer is drawn from the brief's matching content and clearly labelled `보고자 직접 확인 권장`.
65
65
  - `pending` (or field missing) → ABORT analysis; render the Verdict Card with `Verdict Token = blocked` + `Direction = hold` and write a single `## Reporter Confirmation Required` block (no leading number) summarising which rows are pending. The `## 1. Clarification Items` table carries one row per pending item with `Blocks=approval` in `implementation-planning`, otherwise `Blocks=next-phase`. The operator must rerun `okstra-brief` Step 6.5. Do NOT emit `## 0.` for this case — Section 0 is reserved for clarification-response carry-in only.
66
66
  `[CONFIRMED <YYYY-MM-DD> → RC-N]` markers on `Open Questions` rows are the per-row signal that the reporter has answered; their answers live verbatim under `## Reporter Confirmations` in the brief.
67
67
  - `Source Material` is reporter-verbatim. Do NOT paraphrase, summarize, reorder, or restructure it. Quote it directly when needed.
@@ -81,9 +81,9 @@ profile document.
81
81
  - **Canonical column schema (SSOT — must match `templates/reports/final-report.template.md` §1 exactly):** every `## 1. Clarification Items` table has exactly these 8 columns, in this order:
82
82
  `| ID | Ticket ID | Kind | Statement | Expected form | Blocks | Status | User input |`.
83
83
  Profile-specific addenda may tighten cell content but MUST NOT add, remove, rename, or reorder columns. The `ID` cell uses `C-NNN` (3-digit zero-padded), the `Status` cell ∈ `{open, answered, resolved, obsolete}`, and the `Kind` / `Blocks` legal values are listed below.
84
- - section 1 is a **single unified table** per `final-report-template.md`. Every clarification item — whether the user must attach a file, choose between options, or supply a single number/path — is one row of that table. Do not split it into sub-sections (`1.1 추가 자료 요청` / `1.2 사용자 확인 질문` / `5.5.9 Open Questions` are removed and the validator fails reports that reintroduce them), do not create a parallel table elsewhere in the report, and do not duplicate the same item into the top-of-report `User Approval Request (사용자 승인 게이트)` block or any other section.
84
+ - section 1 is a **single unified table** per `final-report-template.md`. Every clarification item — whether the user must attach a file, choose between options, or supply a single number/path — is one row of that table. Do not split it into sub-sections (`1.1 추가 자료 요청` / `1.2 사용자 확인 질문` / `5.5.9 Open Questions` are removed and the validator fails reports that reintroduce them), do not create a parallel table elsewhere in the report, and do not duplicate the same item into an approval block or any other section.
85
85
  - each row's `Kind` column picks one of `{material, decision, data-point}`: `material` for files / snapshots / logs / screenshots the user must attach (the `User input` cell will hold a path or URL); `decision` for choices and yes/no confirmations only the user can make; `data-point` for a single number, ID, date, or short string the user can answer inline. Items that mix "yes/no + file path if yes" are one row of `Kind=material` with the combined expectation written into `Expected form`.
86
- - each row's `Blocks` column picks one of `{approval, next-phase, none}`. `approval` is reserved for items that gate an approval action, especially the `implementation-planning` User Approval Request; outside `implementation-planning`, unresolved brief reporter-confirmation rows use `next-phase` instead. `next-phase` blocks the next run from starting cleanly. `none` is informational/audit-only.
86
+ - each row's `Blocks` column picks one of `{approval, next-phase, none}`. `approval` is reserved for items that gate an approval action, especially the `implementation-planning` `approved:` frontmatter flip; outside `implementation-planning`, unresolved brief reporter-confirmation rows use `next-phase` instead. `next-phase` blocks the next run from starting cleanly. `none` is informational/audit-only.
87
87
  - write every entry in full, descriptive sentences that a non-developer can act on without further context. Avoid abbreviations and internal jargon. The `Statement` cell must state *what* is needed, *why* the answer / attachment changes the next step, and (for `material`) *where* the user can find it and *where* to place it. The `Expected form` cell must state the answer shape (예/아니오, 보기 중 하나, 숫자/날짜, 파일 경로, 짧은 서술 등); supply concrete option choices when applicable.
88
88
  - if a phase requires a recommended answer, alternatives, or an evidence-check note, encode it inside the existing 8-column schema: put evidence notes in `Statement` as `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>`, and put recommendations/options in `Expected form` as `Recommended: <answer> — <rationale>; Alternatives: <options>`. Do not add `Recommended`, `Evidence`, `Alternatives`, or `evidence-checked` columns.
89
89
  - the same `final-report.md` file is the canonical artifact carried into the next run; the user appends answers inline before rerunning. The preferred turn-around is `scripts/okstra.sh --resume-clarification --task-key <project-id>:<task-group>:<task-id>` (opens the latest report in `$EDITOR`, then auto-reruns the same phase with `--clarification-response` carry-in). The lower-level form `--clarification-response <path>` remains available for scripted runs.
@@ -48,7 +48,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
48
48
  ## Lead post-stage persistence (BLOCKING — runs after the Executor emits `### Stage Carry Evidence`)
49
49
 
50
50
  - Parse the executor's `### Stage Carry Evidence` JSON block. If absent or unparsable, end with status `contract-violated` and route to a follow-up `error-analysis`.
51
- - For EACH stage in this run's batch: write its JSON verbatim to `runs/<impl-task-key>/carry/stage-<N>.json`. Refuse to overwrite an existing file (one stage = one sidecar; re-runs are out of scope for this version).
52
- - For EACH stage in this run's batch: append a `status:"done"` row to `runs/<plan-task-key>/consumers.jsonl` with `completed_at`, `carry_path`, `report_path` (this run's final-report path relative to the run root), and the SHA of HEAD. Use the okstra runtime's `consumers_mutex` helper (NOT a raw filesystem write) to honour the lock. `report_path` lets `final-verification` cite each stage's originating report when assembling its Source Implementation Report list.
53
- - The verifier round, Phase 5.5 convergence, and this Phase 6 report run **once per run** over the batch's combined diff — NOT per stage. The single final report covers every batched stage, with a per-stage subsection.
54
- - Quote every batched stage's new contents (each sidecar JSON in full, each new consumers row by itself) in the final report's `Stage sidecar evidence` deliverable section.
51
+ - For this run's single stage: write its JSON verbatim to `runs/<impl-task-key>/carry/stage-<N>.json`. Refuse to overwrite an existing file (one stage = one sidecar; re-runs are out of scope for this version).
52
+ - For this run's single stage: append a `status:"done"` row to `runs/<plan-task-key>/consumers.jsonl` with `completed_at`, `carry_path`, `report_path` (this run's final-report path relative to the run root), and the SHA of HEAD. Use the okstra runtime's `consumers_mutex` helper (NOT a raw filesystem write) to honour the lock. `report_path` lets `final-verification` cite each stage's originating report when assembling its Source Implementation Report list.
53
+ - The verifier round, Phase 5.5 convergence, and this Phase 6 report run **once per run** over this stage's diff — NOT per step.
54
+ - Quote this stage's new contents (the sidecar JSON in full and the new consumers row by itself) in the final report's `Stage sidecar evidence` deliverable section.
@@ -48,10 +48,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
48
48
 
49
49
  - **Sidecar evidence writer (BLOCKING).** When this stage's Stage Validation `post` commands all succeed, the Executor MUST emit a JSON object matching the schema in `docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md` §3.2 and the lead MUST persist it to `runs/<impl-task-key>/carry/stage-<N>.json`. The file MUST NOT exist before the run starts (overwrite is refused — see `--force-stage` non-goal).
50
50
  - **Reverse link (BLOCKING).** The runtime already appended a `status:"started"` row for this stage before the run began. On completion, append a `status:"done"` row with `carry_path` populated for this stage number.
51
- - **One-PR-per-run.** This run creates exactly one PR titled `Stage <N>: <title>`. The PR body MUST include:
52
- - `## Stage <N>` — number, title (from Stage Map row), touched files, and validation result.
53
- - `## Carry-In summary` — depends-on list + cited identifiers/SHAs from each loaded sidecar (omit when depends-on is empty).
54
- - `## Previous run` / `## Next run` — links so a reviewer can navigate the run chain.
51
+ - **No PR / push in this phase.** This run produces local commits, carry sidecar evidence, verifier results, and the implementation final report only. Push and PR creation belong exclusively to the later `release-handoff` phase after `final-verification` returns `accepted`.
55
52
 
56
53
  ## Allowed actions during the run
57
54
 
@@ -41,7 +41,7 @@
41
41
  - Clarification request policy (phase-specific addendum — shared policy is in `_common-contract.md`):
42
42
  - populate `## 1. Clarification Items` only when a blocker hinges on information only the user can supply (deployment intent, intended target environment, business-rule interpretation); use `Blocks=next-phase` for items that gate continuing to release-handoff
43
43
  - Self-review pass before finalising the report (`Claude lead` runs this; do not delegate to a generic subagent):
44
- 1. **Verdict precision** — section 2 includes `Verdict Token` with one of the three allowed verdict tokens; `conditional-accept` lists every condition as an actionable item.
44
+ 1. **Verdict precision** — section 7 (`Final Verdict`) includes `Verdict Token` with one of the three allowed verdict tokens; `conditional-accept` lists every condition as an actionable item.
45
45
  2. **Blocker traceability** — every blocker cites a concrete artifact (file:line, log excerpt, test exit code, MCP SELECT). Blockers without evidence are demoted to residual risk or removed.
46
46
  3. **Coverage check** — every requirement in the originating plan/task brief is either marked covered (with artifact) or listed as a blocker. No silent omissions.
47
47
  4. **Verifier dissent preserved** — if workers reach different verdicts, the disagreement is visible in section 1.2; synthesis hides nothing.
@@ -9,7 +9,7 @@
9
9
  - gemini — when added to the roster it joins the analyser set; omitted by default
10
10
  {{INCLUDE:_common-contract.md}}
11
11
  - Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
12
- - Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows use `Blocks=approval`; the operator cannot toggle `User Approval Request` until those rows are resolved.
12
+ - Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows use `Blocks=approval`; the operator cannot flip the approval frontmatter to `approved: true` until those rows are resolved.
13
13
  - never plan around an unconfirmed `intent-inference` augmentation as if it were a settled requirement. After the precondition runs, a `[CONFIRMED …]` marker on the matching `intent-check:` row is the signal that the inference can be treated as settled; otherwise it remains a `Blocks=approval` clarification item per the precondition's `skipped` branch.
14
14
  - `conversion-block:` rows are handled by the precondition; planning around an untranslated reporter phrase is forbidden until it is resolved.
15
15
  - Pre-planning context exploration (mandatory before option drafting):
@@ -55,7 +55,7 @@
55
55
  - Section heading contract (BLOCKING — validator scans for these literal English substrings):
56
56
  - The final report MUST include section headings containing each of the following exact strings: `Option Candidates`, `Trade-off`, `Recommended Option`, `Stage Map`, `Stage Exit Contract`, `Stage Validation`, `Dependency`, `Validation Checklist`, `Rollback`, `Requirement Coverage`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.)
57
57
  - Korean translations are allowed in parentheses (e.g. `### Recommended Option (권장 옵션)`), but the English keyword must be present verbatim in the heading line.
58
- - The shape and ordering follow `final-report-template.md` section 4.5 (`Implementation Plan Deliverables`). Do NOT translate the heading keywords — `validators/validate-run.py` does substring matching on the raw report text and 7-of-8 missing strings is a real, repeatedly observed failure mode (root cause: writer translated the headings to Korean).
58
+ - The shape and ordering follow `final-report-template.md` section 5.5 (`Implementation Plan Deliverables` + `Stage Map`). Do NOT translate the heading keywords — `validators/validate-run.py` does substring matching on the raw report text and missing English strings are a real, repeatedly observed failure mode (root cause: writer translated the headings to Korean).
59
59
  - Beyond substring matching, when the Plan Body Verification gate result is `passed` / `passed-with-dissent`, `validators/validate-run.py` runs the **structural** Stage Map validator (`validators/validate-implementation-plan-stages.py`) at the planning boundary — the exact `## 5.5 Stage Map` heading, each `## 5.5.<i> Stage <i>:` section with its four required subsections, the per-stage effective step count (≤6), the `depends-on` DAG, and the per-stage vertical-slice contract (S10) are all enforced here, not deferred to the `implementation` entry gate. S10 scans for the literal in-section strings `Slice value:`, `Acceptance:`, and the Stepwise `action`-cell prefixes `RED:` / `GREEN:` (or a `TDD exemption:` line) — keep these tokens verbatim for the same reason as the heading keywords above.
60
60
  - Required deliverable shape (final report, in addition to the standard sections):
61
61
  - at least two implementation options. **Each option must include**:
@@ -88,8 +88,8 @@
88
88
  - the YAML frontmatter MUST include the line `approved: false` (report-writer always emits the unflipped value). The user authorises the next `implementation` run by flipping it to `approved: true` (manual edit or `--approve` CLI). Do NOT recreate any `User Approval Request` body block — the validator fails reports that contain one (see `validators/validate-run.py` deprecated patterns).
89
89
  - the YAML frontmatter MUST include the line `implementation-option:` directly under `approved:` (report-writer always emits it with an **empty value**). The user selects which Option Candidate the next `implementation` run executes by filling this line with that option's name (manual edit or `--implementation-option <name>` CLI). When left empty, the `implementation` run falls back to the `Recommended Option`.
90
90
  - **the frontmatter `approved: false` line is rendered unconditionally; if the plan-body verification gate (§5.5.9) returns `blocked-by-disagreement` or `aborted-non-result`, the writer MUST keep `approved: false` and the validator refuses any report that ships with `approved: true` under such a gate result.**
91
- - every ambiguity flagged during pre-planning that the user must resolve before approval registered as a `Blocks=approval` row in the `## 1. Clarification Items` table (do NOT create a separate `Open Questions` block under `4.5.x` — the unified table is the single home)
92
- - **§5.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 `### 5.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. When `convergence.adversarial=true` (the default for this phase), this round uses the adversarial posture — verifiers confirm cited paths/commands and the burden of proof is on the plan — but the gate threshold stays `majority-disagree` (see that skill's §"Adversarial plan-body posture").
91
+ - every ambiguity flagged during pre-planning that the user must resolve before approval registered as a `Blocks=approval` row in the `## 1. Clarification Items` table (do NOT create a separate `Open Questions` block under the implementation plan body — the unified table is the single home)
92
+ - **§5.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 (Option Candidates / Trade-off Matrix / Recommended Option / Stage Map and per-stage sections / Dependency / Validation Checklist / Rollback / Requirement Coverage) and populate `### 5.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. When `convergence.adversarial=true` (the default for this phase), this round uses the adversarial posture — verifiers confirm cited paths/commands and the burden of proof is on the plan — but the gate threshold stays `majority-disagree` (see that skill's §"Adversarial plan-body posture").
93
93
  - **Decision-record evaluation (sole owner)**: this phase is the **single owner** of decision-record evaluation in the okstra lifecycle. The brief never evaluates or drafts decision records — it only forwards `adr-candidate:*` signals. Every `adr-candidate:*` entry inherited from the brief's `Open Questions` is a mandatory evaluation target. In addition, evaluate every decision the recommended option introduces against the three criteria:
94
94
  1. **Hard to reverse** — would changing the decision later cost meaningfully more than deciding now?
95
95
  2. **Surprising without context** — would a future reader, seeing only the code, wonder "why was it built this way?"?
@@ -109,5 +109,5 @@
109
109
  4. **Ambiguity check** — any requirement that could be read two ways must be made explicit or moved to the `## 1. Clarification Items` table as a `Blocks=approval` row.
110
110
  5. **Scope check** — if the recommended plan now spans multiple independent subsystems, recommend splitting into separate planning runs rather than shipping an oversized plan.
111
111
  6. **Review-rule preflight check** — if a project review rule pack exists, map each relevant rule to the recommended option. Reject the draft if it knowingly creates a violation that the later PR reviewer would flag, unless the plan records a specific rationale and follow-up. In particular, scan for repeated helper stacks across planned files, tests that assert delegation to the same calculator/helper they exercise, public names that hide side effects, domain rules placed in repositories/adapters, and APIs made dead by this change.
112
- 7. **Plan-body verification reconciliation (BLOCKING for implementation-planning).** Inspect the `### 5.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 `## 1. Clarification Items` with `Kind` chosen per the standard policy and `Blocks=approval`. Do NOT create a parallel `### 5.5.x Open Questions` block — the unified table is the single home. Conversely, the `Classification` column's `C-<N>` reference and the `## 1. 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 §5.5.9 `Dissent log` and is NOT promoted to §5.
112
+ 7. **Plan-body verification reconciliation (BLOCKING for implementation-planning).** Inspect the `### 5.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 `## 1. Clarification Items` with `Kind` chosen per the standard policy and `Blocks=approval`. Do NOT create a parallel `Open Questions` block under the implementation plan body — the unified table is the single home. Conversely, the `Classification` column's `C-<N>` reference and the `## 1. 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 §5.5.9 `Dissent log` and is NOT promoted to §5.
113
113
  8. **Stage Map self-check** — for every stage, count the effective rows of its `Stepwise Execution Order` table by hand; reject the draft if any stage exceeds 6. Confirm each stage declares a non-empty `Slice value:` and `Acceptance:` line, and that its first step `action` starts with `RED:` with a later `GREEN:` (or carries a `TDD exemption:` line) — this is what validator S10 enforces. Walk the `depends-on` graph and confirm it is a DAG (no cycle, no self-reference). For each `depends-on` link, confirm it encodes a real data/contract dependency — do NOT add links to serialise unrelated work, and do NOT split a stage merely to create more parallel stages. **Parallel-safety:** for every pair of `depends-on (none)` stages, confirm their `Stage Exit Contract` predicted file sets are disjoint; if they share a file, merge them or add a `depends-on` link (validator S9 rejects overlap).
@@ -1,7 +1,7 @@
1
1
  # Implementation Profile
2
2
 
3
3
  - Purpose: realise the approved `implementation-planning` deliverable as actual source changes, with cross-model verification, while keeping the run reversible
4
- - **Run-level fixed cost:** the verifier set, Phase 5.5 convergence, and the Phase 6 report-writer run exactly once per run, over the combined diff of all stages in this run's batch — never once per stage.
4
+ - **Run-level fixed cost:** the verifier set, Phase 5.5 convergence, and the Phase 6 report-writer run exactly once per implementation run, over this run's single stage diff — never once per step.
5
5
  - Required workers:
6
6
  - claude
7
7
  - codex
@@ -20,14 +20,14 @@
20
20
  - that file's YAML frontmatter MUST carry `approved: true`. report-writer emits `approved: false` by default; the user flips it to `true` to authorise this run. Free-form approvals such as "lgtm" / "go ahead" / paraphrased confirmations are NOT accepted; re-edit the plan file's frontmatter to `approved: true` before invoking implementation, or pass `--approve` so the CLI flips it on the user's behalf (`okstra_ctl.run._apply_cli_approval`).
21
21
  - The `--approve` flag is meaningful ONLY with `--task-type implementation` and `--approved-plan <path>`; any other use raises `PrepareError`. Idempotent — re-running with `approved: true` already set appends an audit line but does NOT re-toggle.
22
22
  - the authoritative scope for this run is the Option Candidate named by the YAML frontmatter `implementation-option:` field. **If `implementation-option:` is empty, fall back to the plan's `Recommended Option`** (this is a soft fallback, not a hard block). The chosen option's bite-sized step list becomes the authoritative scope; deviations must be justified in the final report and routed back to a new `implementation-planning` run rather than silently expanded. If the chosen option name does not match any heading under `Option Candidates`, record it as a deviation.
23
- - Task worktree (provisioned by `okstra-ctl` at the first phase's run-prep time, reused for every subsequent phase of this task-key):
23
+ - Stage worktree (provisioned by `okstra-ctl` at this implementation run's prep time):
24
24
  - Status: `{{EXECUTOR_WORKTREE_STATUS}}` (one of: `created` | `reused` | `skipped-in-worktree` | `skipped-not-git`)
25
- - Working tree path: `{{EXECUTOR_WORKTREE_PATH}}` — when status is `created` or `reused`, this is the task's `git worktree` rooted at `~/.okstra/worktrees/<project>/<task-group>/<task-id>/`. When skipped, this is the caller's `project_root`.
26
- - Branch: `{{EXECUTOR_WORKTREE_BRANCH}}` — empty when status is `skipped-*`. Branch name = `<work-category-prefix>-<task-id-segment>`, globally unique via `~/.okstra/worktrees/registry.json`.
27
- - Base ref: `{{EXECUTOR_WORKTREE_BASE_REF}}` — canonical `<base>` for every `git diff` / `git log` in this run.
25
+ - Working tree path: `{{EXECUTOR_WORKTREE_PATH}}` — when status is `created` or `reused`, this is this run's isolated stage worktree rooted at `~/.okstra/worktrees/<project>/<task-group>/<task-id>/stage-<N>/`. When skipped, this is the caller's `project_root`.
26
+ - Branch: `{{EXECUTOR_WORKTREE_BRANCH}}` — empty when status is `skipped-*`. Branch name = `<work-category-prefix>-<task-id-segment>-s<N>`, globally unique via `~/.okstra/worktrees/registry.json`.
27
+ - Base ref: `{{EXECUTOR_WORKTREE_BASE_REF}}` — canonical `<base>` for every `git diff` / `git log` in this run. Independent stages start from the task anchor; dependent stages start from the predecessor done commit or the verified merged task worktree head.
28
28
  - Provisioning note: `{{EXECUTOR_WORKTREE_NOTE}}`
29
29
  - Treat the working-tree path as `project_root` for the duration of this run. Do NOT mutate the caller's original checkout. cwd-sensitive Bash commands MUST be prefixed `cd {{EXECUTOR_WORKTREE_PATH}} && ` in the same Bash invocation (never `bash -lc "..."` wrappers — see executor sidecar for full rules).
30
- - Lifecycle: kept after the run completes; reused by every subsequent phase of the same task-key. Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` → drop registry entry.
30
+ - Lifecycle: kept after the run completes as this stage's evidence worktree. Later stages get their own stage worktrees. Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` → drop the stage-key registry entry (`<task-key>#stage-<N>`).
31
31
  - Approval gate (phase-specific addendum to shared authority rule):
32
32
  - the pre-implementation gate's recorded user approval marker is the only authorised approval gate at this phase — proceed once it is satisfied without further external coordination.
33
33
  - Forbidden actions — universal (any occurrence → terminal status `contract-violated`):
@@ -30,6 +30,7 @@
30
30
  - When candidates branch on a structural question (e.g. "is module X meant to own this responsibility?"), resolve via `Read` / `Grep` first. Only escalate to the user inside the Phase 1.5 budget.
31
31
  - Expected output emphasis:
32
32
  - the `## 5.9 Improvement Candidates` table populated with rows that obey the 10-column schema from `validators/validate-improvement-report.py` (Cand ID `I-NNN`, Lens from whitelist, Title, Scope ⊆ scan-scope, Severity, Effort, Consensus, Source workers `<worker>:<id>` from {claude, codex, gemini}, Recommended next-phase ∈ {requirements-discovery, implementation-planning, error-analysis}, Evidence as path:line list)
33
+ - `Consensus` cells in `## 5.9 Improvement Candidates` use the table enum exactly: `full`, `partial`, `contested`, `worker-unique`. Map convergence's `full-consensus` / `partial-consensus` labels to `full` / `partial` before writing the table.
33
34
  - `## 7. Final Verdict` Verdict Token ∈ {`candidates-ready`, `no-candidates`, `blocked`}; Direction `routing`; Next Step "사용자에게 후보 K개 선택 의뢰 (## 5.9 표 참조)"
34
35
  - `## 3. Recommended Next Steps` first entry summarises per-candidate routing and proposes new task-key names of the form `<task-group>/imp-<Cand-ID>`
35
36
  - this report is authored free-form (improvement-discovery is not in the data.json schema enum); after the markdown is written, the report-writer runs `scripts/okstra-inject-report-index.py <report.md> --report-language <en|ko>` to add the top-of-report Index + `I-NNN`/`C-NNN` scroll anchors. The run validator fails the report when the Index anchor is missing.
@@ -2,11 +2,11 @@
2
2
 
3
3
  - Purpose: take an `accepted` final-verification verdict for an already-committed implementation branch and turn it into a delivered push and/or pull request, with explicit user selection at every mutating step
4
4
  - **Execution model: single-lead, no worker dispatch.** This phase is a thin orchestrator over `git` / `gh`; it does NOT run team-mode, does NOT call `TeamCreate`, does NOT dispatch analysis or drafter sub-agents, and does NOT run convergence. The Claude lead performs every step inline (drafting PR text, asking the user, running git / gh, writing the final report) — see "Lead-only contract" below.
5
- - Required workers: *(none — this profile intentionally has no `- Required workers:` block; the run is executed entirely by the Claude lead)*
5
+ - Worker roster: none — this profile intentionally has no `- Required workers:` block; the run is executed entirely by the Claude lead.
6
6
  - Lead-only contract (replaces the shared team contract for this phase):
7
7
  - The Claude lead is the sole agent for this run. No `Agent(...)` worker dispatch, no `TeamCreate`, no parallel sub-agents, no convergence loop.
8
8
  - The lead drafts the PR title and PR body **inline** by reading the run brief, the cited final-verification report, `git log --oneline <base>..HEAD`, and `git diff <base>..HEAD --stat`. No drafter worker is dispatched.
9
- - The lead authors the final-report file directly (no `Report writer worker` dispatch). The report still conforms to the standard `okstra-final-report.template.md` structure, including the `## 5.6 Release Handoff Deliverables` section.
9
+ - The lead authors the final-report file directly (no `Report writer worker` dispatch). The report still conforms to the standard `templates/reports/final-report.template.md` structure, including the `## 5.6 Release Handoff Deliverables` section.
10
10
  - The shared anti-escalation rule from the common contract still applies: do not start any other lifecycle phase from inside this run.
11
11
  - The shared "authority & permissions assumption" rule from the common contract still applies: assume the user holds every permission needed; do not block on hypothetical approvals.
12
12
  - The shared "MCP read-only" rule still applies if the brief lists MCP servers, though most release-handoff runs do not use MCP.
@@ -22,7 +22,7 @@
22
22
  - `push + PR` — push the feature branch, then open or reuse a pull request.
23
23
  - `skip` — record the verified state and end the run without any git command.
24
24
  If the user picks `skip`, route directly to the final-report self-review pass.
25
- 2. **PR base branch** (only when the user picked `push + PR`) — present six options and capture exactly one:
25
+ 2. **PR base branch** (only when the user picked `push + PR`) — present four options and capture exactly one:
26
26
  - `staging`
27
27
  - `preprod`
28
28
  - `main`
@@ -75,7 +75,7 @@
75
75
  - **User Selections**: a block recording each prompt and the user's verbatim answer.
76
76
  - Q1 action: `local only` | `push + PR` | `skip`.
77
77
  - Q2 PR base (if applicable): the chosen branch and how it was selected (menu pick vs free-form input).
78
- - Q2b merge-conflict probe (if applicable): `clean` (no conflict, no prompt shown) | `proceed anyway` | `change base branch` | `cancel`. When a conflict was detected, list the conflicting paths.
78
+ - Q2b merge-conflict probe (if applicable): `not-run` | `clean` (no conflict, no prompt shown) | `proceed anyway` | `change base branch` | `cancel`. Record it in both the `User Selections` row `H2b` and the `Merge Conflict Probe` deliverable. When a conflict was detected, list the conflicting paths.
79
79
  - Q3 title/body: `use as-is` | `edit then proceed` (with a diff between the lead's draft and the final text) | `cancel`.
80
80
  - **Executed Commands**: every git / gh command the lead actually ran, with its exit code and a one-line stdout/stderr summary. Read-only inspection commands MAY be summarised; mutating commands MUST be listed verbatim.
81
81
  - **Commit List**: each existing implementation commit in `git log <base>..HEAD`, with short/full SHA, subject line, and touched files. Release-handoff MUST NOT create new commits.
@@ -330,12 +330,13 @@
330
330
 
331
331
  "implementationPlanning": {
332
332
  "type": "object",
333
- "description": "RENDER_IF taskType == implementation-planning. §4.5 deliverables.",
333
+ "description": "RENDER_IF taskType == implementation-planning. §5.5 deliverables.",
334
334
  "required": [
335
335
  "optionCandidates",
336
336
  "tradeoffMatrix",
337
337
  "recommendedOption",
338
- "stepwiseExecution",
338
+ "stageMap",
339
+ "stages",
339
340
  "dependencyMigrationRisk",
340
341
  "validationChecklist",
341
342
  "rollbackStrategy",
@@ -355,7 +356,18 @@
355
356
  "items": { "$ref": "#/$defs/TradeoffRow" }
356
357
  },
357
358
  "recommendedOption": { "$ref": "#/$defs/RecommendedOption" },
359
+ "stageMap": {
360
+ "type": "array",
361
+ "minItems": 1,
362
+ "items": { "$ref": "#/$defs/StageMapRow" }
363
+ },
364
+ "stages": {
365
+ "type": "array",
366
+ "minItems": 1,
367
+ "items": { "$ref": "#/$defs/ImplementationPlanStage" }
368
+ },
358
369
  "stepwiseExecution": {
370
+ "description": "Legacy flat summary kept for compatibility only. New reports use stageMap/stages.",
359
371
  "type": "array",
360
372
  "minItems": 1,
361
373
  "items": { "$ref": "#/$defs/StepRow" }
@@ -385,7 +397,7 @@
385
397
 
386
398
  "releaseHandoff": {
387
399
  "type": "object",
388
- "description": "RENDER_IF taskType == release-handoff. §4.6 deliverables.",
400
+ "description": "RENDER_IF taskType == release-handoff. §5.6 deliverables.",
389
401
  "required": [
390
402
  "sourceVerificationReport",
391
403
  "featureBranchState",
@@ -419,11 +431,14 @@
419
431
  },
420
432
  "userSelections": {
421
433
  "type": "object",
422
- "required": ["h1", "h3"],
434
+ "required": ["h1", "h2b", "h3"],
423
435
  "additionalProperties": false,
424
436
  "properties": {
425
437
  "h1": { "enum": ["local only", "push + PR", "skip"] },
426
438
  "h2": { "type": "string" },
439
+ "h2b": {
440
+ "enum": ["not-run", "clean", "proceed anyway", "change base branch", "cancel"]
441
+ },
427
442
  "h3": { "enum": ["use as-is", "edit then proceed", "cancel"] }
428
443
  }
429
444
  },
@@ -482,12 +497,13 @@
482
497
 
483
498
  "implementation": {
484
499
  "type": "object",
485
- "description": "RENDER_IF taskType == implementation. §4.7 deliverables.",
500
+ "description": "RENDER_IF taskType == implementation. §5.7 deliverables.",
486
501
  "required": [
487
502
  "approvedPlanReference",
488
503
  "commitList",
489
504
  "diffSummary",
490
505
  "outOfPlanEdits",
506
+ "stageSidecarEvidence",
491
507
  "validationEvidence",
492
508
  "verifierResults",
493
509
  "rollbackVerification",
@@ -526,6 +542,7 @@
526
542
  "type": "array",
527
543
  "items": { "$ref": "#/$defs/OutOfPlanEditRow" }
528
544
  },
545
+ "stageSidecarEvidence": { "$ref": "#/$defs/StageSidecarEvidence" },
529
546
  "validationEvidence": {
530
547
  "type": "array",
531
548
  "minItems": 1,
@@ -547,7 +564,7 @@
547
564
 
548
565
  "finalVerification": {
549
566
  "type": "object",
550
- "description": "RENDER_IF taskType == final-verification. §4.8 deliverables.",
567
+ "description": "RENDER_IF taskType == final-verification. §5.8 deliverables.",
551
568
  "required": [
552
569
  "sourceImplementationReport",
553
570
  "acceptanceBlockers",
@@ -624,7 +641,7 @@
624
641
 
625
642
  "allOf": [
626
643
  {
627
- "description": "implementation-planning task-type requires §4.5 block.",
644
+ "description": "implementation-planning task-type requires §5.5 block.",
628
645
  "if": {
629
646
  "properties": { "header": { "properties": { "taskType": { "const": "implementation-planning" } } } },
630
647
  "required": ["header"]
@@ -634,7 +651,7 @@
634
651
  }
635
652
  },
636
653
  {
637
- "description": "release-handoff task-type requires §4.6 block.",
654
+ "description": "release-handoff task-type requires §5.6 block.",
638
655
  "if": {
639
656
  "properties": { "header": { "properties": { "taskType": { "const": "release-handoff" } } } },
640
657
  "required": ["header"]
@@ -644,7 +661,7 @@
644
661
  }
645
662
  },
646
663
  {
647
- "description": "implementation task-type requires §4.7 block.",
664
+ "description": "implementation task-type requires §5.7 block.",
648
665
  "if": {
649
666
  "properties": { "header": { "properties": { "taskType": { "const": "implementation" } } } },
650
667
  "required": ["header"]
@@ -654,7 +671,7 @@
654
671
  }
655
672
  },
656
673
  {
657
- "description": "final-verification task-type requires §4.8 block.",
674
+ "description": "final-verification task-type requires §5.8 block.",
658
675
  "if": {
659
676
  "properties": { "header": { "properties": { "taskType": { "const": "final-verification" } } } },
660
677
  "required": ["header"]
@@ -1066,6 +1083,90 @@
1066
1083
  }
1067
1084
  },
1068
1085
 
1086
+ "StageMapRow": {
1087
+ "type": "object",
1088
+ "required": ["stage", "title", "dependsOn", "stepCount", "exitContractSummary"],
1089
+ "additionalProperties": false,
1090
+ "properties": {
1091
+ "stage": { "type": "integer", "minimum": 1 },
1092
+ "title": { "type": "string", "minLength": 1 },
1093
+ "dependsOn": {
1094
+ "type": "string",
1095
+ "minLength": 1,
1096
+ "description": "Literal Stage Map depends-on cell: `(none)` or a comma-separated stage number list."
1097
+ },
1098
+ "stepCount": { "type": "integer", "minimum": 0, "maximum": 6 },
1099
+ "exitContractSummary": { "type": "string", "minLength": 1 }
1100
+ }
1101
+ },
1102
+
1103
+ "ImplementationPlanStage": {
1104
+ "type": "object",
1105
+ "required": [
1106
+ "stage",
1107
+ "title",
1108
+ "sliceValue",
1109
+ "acceptance",
1110
+ "carryIn",
1111
+ "stepwiseExecution",
1112
+ "exitContract",
1113
+ "stageValidation"
1114
+ ],
1115
+ "additionalProperties": false,
1116
+ "oneOf": [
1117
+ {
1118
+ "required": ["conformanceTests"],
1119
+ "not": { "required": ["conformanceExemption"] }
1120
+ },
1121
+ {
1122
+ "required": ["conformanceExemption"],
1123
+ "not": { "required": ["conformanceTests"] }
1124
+ }
1125
+ ],
1126
+ "properties": {
1127
+ "stage": { "type": "integer", "minimum": 1 },
1128
+ "title": { "type": "string", "minLength": 1 },
1129
+ "sliceValue": { "type": "string", "minLength": 1 },
1130
+ "acceptance": { "type": "string", "minLength": 1 },
1131
+ "conformanceTests": {
1132
+ "type": "string",
1133
+ "minLength": 1,
1134
+ "description": "Text after the `Conformance tests: stage-N — ...` prefix."
1135
+ },
1136
+ "conformanceExemption": {
1137
+ "type": "string",
1138
+ "minLength": 1,
1139
+ "description": "Text after the `Conformance exemption:` prefix."
1140
+ },
1141
+ "tddExemption": {
1142
+ "type": "string",
1143
+ "description": "Optional text after the `TDD exemption:` prefix."
1144
+ },
1145
+ "carryIn": { "type": "string", "minLength": 1 },
1146
+ "stepwiseExecution": {
1147
+ "type": "array",
1148
+ "minItems": 1,
1149
+ "maxItems": 6,
1150
+ "items": { "$ref": "#/$defs/StageStepRow" }
1151
+ },
1152
+ "exitContract": { "type": "string", "minLength": 1 },
1153
+ "stageValidation": { "type": "string", "minLength": 1 }
1154
+ }
1155
+ },
1156
+
1157
+ "StageStepRow": {
1158
+ "type": "object",
1159
+ "required": ["step", "action", "files", "command", "expected"],
1160
+ "additionalProperties": false,
1161
+ "properties": {
1162
+ "step": { "type": "integer", "minimum": 1 },
1163
+ "action": { "type": "string", "minLength": 1 },
1164
+ "files": { "type": "string", "minLength": 1 },
1165
+ "command": { "type": "string", "minLength": 1 },
1166
+ "expected": { "type": "string", "minLength": 1 }
1167
+ }
1168
+ },
1169
+
1069
1170
  "StepRow": {
1070
1171
  "type": "object",
1071
1172
  "required": ["step", "ticketId", "action", "files", "commandOrTest", "expectedOutcome"],
@@ -1080,6 +1181,22 @@
1080
1181
  }
1081
1182
  },
1082
1183
 
1184
+ "StageSidecarEvidence": {
1185
+ "type": "object",
1186
+ "required": ["stageNumber", "stageTitle", "carryJson", "consumerRows"],
1187
+ "additionalProperties": false,
1188
+ "properties": {
1189
+ "stageNumber": { "type": "integer", "minimum": 1 },
1190
+ "stageTitle": { "type": "string", "minLength": 1 },
1191
+ "carryJson": { "type": "string", "minLength": 1 },
1192
+ "consumerRows": {
1193
+ "type": "array",
1194
+ "minItems": 1,
1195
+ "items": { "type": "string", "minLength": 1 }
1196
+ }
1197
+ }
1198
+ },
1199
+
1083
1200
  "DependencyRow": {
1084
1201
  "type": "object",
1085
1202
  "required": ["id", "kind", "item", "impact", "mitigation"],
@@ -62,6 +62,14 @@ If you suspect an overlay applies but the layout is non-standard, ask one questi
62
62
  - [ ] Existing code searched: `grep` for the symbol / file / identifier you are about to add. Do not duplicate.
63
63
  - [ ] Project conventions checked: `.editorconfig`, `CONTRIBUTING.md`, formatter config (`.prettierrc`, `rustfmt.toml`, `ktlint`, `google-java-format`, etc.). **Project rules override this skill on conflict.**
64
64
 
65
+ ## Completion sweep (before declaring a multi-file change done)
66
+
67
+ Per-file checks miss cross-cutting issues; each commit can be individually clean while the sum violates DRY. Before saying "done":
68
+
69
+ - [ ] **Domain-literal sweep:** `grep -rn` every domain enum value / predicate you added or touched in WHERE clauses, filters, or branches. The same literal at 2+ I/O sites is a *candidate* scattered decision — ask: would these sites change together when the business rule changes? Same decision → consolidate into one named constant or query builder in the domain layer and make every site reference it. Different decisions that merely share a value → leave them separate; coupling incidental duplication is worse than the repetition. (The identifier grep above does NOT catch this — sweep *values*, not just names.)
70
+ - [ ] **Stand-alone name test for exports:** for each exported identifier, look at its siblings — can a caller pick the right one from the names alone? If a comment must explain which to use, the name fails; encode the distinguishing fact in it (e.g., the input shape: `parseRows` vs `parseRowsFromFlatItems`).
71
+ - [ ] **No documented forks:** two deliberate variants of one capability must not survive as parallel implementations with a comment explaining the delta. Re-read both bodies and check the deltas are genuinely parametric: if they reduce to a few orthogonal options, collapse into one implementation taking explicit option parameters that encode them. If encoding the delta would take more than ~3 options, or add more branching than the duplication it removes, they are two capabilities — keep two implementations with distinct honest names and delete the "variant of" framing. Either way the comment-documented fork dies. "The divergence is documented" stays a refused rationalization, and a two-capabilities verdict must come from reading the bodies, not from reluctance to refactor.
72
+
65
73
  ## Boundaries
66
74
 
67
75
  - This skill does **not** auto-format. Run the project's formatter yourself.
@@ -22,6 +22,11 @@ const sum = (arr) => arr.reduce((acc, x) => acc + x, 0);
22
22
 
23
23
  Caveat: do not extract until the duplication is real (rule of three). Premature abstraction is also a code smell.
24
24
 
25
+ Two more forms of duplication that hide from symbol-level grep:
26
+
27
+ - **Scattered domain literals** — the same enum value / predicate repeated across queries or filters *may* be one business decision duplicated. The test: would the sites change together when the rule changes? If yes, consolidate to a named constant or builder at a single reference point; if they merely share a value, leave them apart — coupling incidental duplication is worse than repetition.
28
+ - **Documented forks** — two deliberate variants of one capability kept as parallel implementations "because the delta is commented". If the delta is genuinely parametric (a few orthogonal options), collapse into one implementation with explicit option parameters; if not, split into two distinctly named capabilities. The commented fork itself is never the end state.
29
+
25
30
  ## KISS — Keep It Simple
26
31
 
27
32
  The simplest solution that meets the requirement wins. Cleverness has a maintenance cost.
@@ -104,6 +109,7 @@ The test: if the name appeared in a stacktrace, an autocomplete list, or a grep
104
109
  - Generic verbs with no information: `handle`, `process`, `execute`, `doStuff`, `manage`. If the function deletes-then-inserts, name it `replace`, not `update`.
105
110
  - Constants that will collide with siblings later: `BUCKET` → `FONTS_BUCKET`, `TIMEOUT` → `HTTP_READ_TIMEOUT_MS`, `URL` → `AUTH_SERVICE_URL`.
106
111
  - Repository / port methods named after the rule they enforce, not the data they fetch: `findValid*` / `findActive*` / `findEligible*` — the adjective encodes a business rule the caller can't inspect from the name. Prefer `findDesktopLibrariesForUser(userId)` + a domain predicate applied by the caller.
112
+ - Near-twin siblings a caller can't tell apart from the names alone (`parseRows` vs `parseRowsFromItems`): if a comment must explain which to pick, rename — encode the distinguishing fact (e.g., input shape: `parseRowsFromFlatItems`). Matching the existing sibling's style does not excuse the ambiguity.
107
113
 
108
114
  This rule applies most strongly to **names crossing module boundaries**: public methods, exported constants, port methods. Private helpers in a tight local scope get more slack.
109
115
 
@@ -17,25 +17,25 @@ okstra release-handoff 기본 PR 본문 템플릿.
17
17
  - `git log --oneline <base>..HEAD` 의 commit 범위
18
18
  - `git diff <base>..HEAD --stat` 의 변경 파일 통계
19
19
 
20
- 빈 섹션은 그대로 두지 말고 통째로 삭제합니다. HTML 주석은 PR 생성 전에
21
- 모두 제거됩니다.
22
20
  -->
23
21
 
24
- ## Summary
22
+ ## **Please check if the PR fulfills these requirements**
23
+ - [ ] Commits have a single intent
24
+ - [ ] Tests for the changes have been added (for bug fixes / features)
25
+ - [ ] I reviewed my own code
26
+ - [ ] I tested the changes (if not, explain why in the "Other information" section)
27
+ - [ ] Docs have been added / updated
25
28
 
26
- <!-- 1–3 bullets. 변경의 동기(WHY)와 결과(WHAT changed at a high level). -->
29
+ ## **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)
27
30
 
28
- ## Changes
29
31
 
30
- <!-- 영역별로 묶은 구체적 변경 목록. 파일/모듈 단위 그룹화 권장. -->
32
+ ## **What is the current behavior?** (You can also link to an open issue here)
31
33
 
32
- ## Test plan
33
34
 
34
- <!-- 리뷰어가 따라 있는 검증 절차. 자동/수동 모두 가능. -->
35
+ ## **What is the new behavior (if this is a feature change)?**
35
36
 
36
- - [ ] <검증 항목>
37
- - [ ] <검증 항목>
38
37
 
39
- ## Linked issues
38
+ ## **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?)
40
39
 
41
- <!-- `Refs: TICKET-123`, `Closes #N`, 관련 PR 링크 등. 없으면 섹션 통째로 삭제. -->
40
+
41
+ ## **Other information**:
@@ -140,7 +140,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
140
140
  {% if header.taskType == 'implementation-planning' %}
141
141
  ## 5.5 Implementation Plan Deliverables
142
142
 
143
- ### 5.5.1 Option Candidates{% if t("sectionAside.optionCandidates") != "Option Candidates" %} ({{ t("sectionAside.optionCandidates") }}){% endif %}
143
+ ### Option Candidates{% if t("sectionAside.optionCandidates") != "Option Candidates" %} ({{ t("sectionAside.optionCandidates") }}){% endif %}
144
144
 
145
145
  {% for opt in implementationPlanning.optionCandidates %}
146
146
  **{{ opt.name }}**
@@ -158,7 +158,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
158
158
 
159
159
  {% endfor %}
160
160
 
161
- ### 5.5.2 Trade-off Matrix{% if t("sectionAside.tradeOffMatrix") != "Trade-off Matrix" %} ({{ t("sectionAside.tradeOffMatrix") }}){% endif %}
161
+ ### Trade-off Matrix{% if t("sectionAside.tradeOffMatrix") != "Trade-off Matrix" %} ({{ t("sectionAside.tradeOffMatrix") }}){% endif %}
162
162
 
163
163
  | Option | Complexity | Risk | Reversibility | Test Coverage Cost | Rollout Cost |
164
164
  |--------|-----------|------|---------------|--------------------|--------------|
@@ -166,7 +166,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
166
166
  | {{ row.option }} | {{ row.complexity }} | {{ row.risk }} | {{ row.reversibility }} | {{ row.testCoverageCost }} | {{ row.rolloutCost }} |
167
167
  {% endfor %}
168
168
 
169
- ### 5.5.3 Recommended Option{% if t("sectionAside.recommendedOption") != "Recommended Option" %} ({{ t("sectionAside.recommendedOption") }}){% endif %}
169
+ ### Recommended Option{% if t("sectionAside.recommendedOption") != "Recommended Option" %} ({{ t("sectionAside.recommendedOption") }}){% endif %}
170
170
 
171
171
  | {{ t("implementationPlanning.recommendedTableHeaderLabel") }} | {{ t("implementationPlanning.recommendedTableHeaderValue") }} |
172
172
  |------|----|
@@ -175,15 +175,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
175
175
  | {{ t("implementationPlanning.rationaleLabel") }} | {{ implementationPlanning.recommendedOption.rationale }} |
176
176
  | {{ t("implementationPlanning.rejectedSummaryLabel") }} | {{ implementationPlanning.recommendedOption.rejectedSummary }} |
177
177
 
178
- ### 5.5.4 Stepwise Execution Order{% if t("sectionAside.stepwiseExecutionOrder") != "Stepwise Execution Order" %} ({{ t("sectionAside.stepwiseExecutionOrder") }}){% endif %}
179
-
180
- | Step | Ticket ID | Action (≤ 5min) | Files | Command / Test | Expected outcome |
181
- |------|-----------|------------------|-------|----------------|-------------------|
182
- {% for row in implementationPlanning.stepwiseExecution -%}
183
- | {{ row.step }} | `{{ row.ticketId }}` | {{ row.action }} | `{{ row.files }}` | `{{ row.commandOrTest }}` | {{ row.expectedOutcome }} |
184
- {% endfor %}
185
-
186
- ### 5.5.5 Dependency / Migration Risk{% if t("sectionAside.dependencyRisk") != "Dependency / Migration Risk" %} ({{ t("sectionAside.dependencyRisk") }}){% endif %}
178
+ ### Dependency / Migration Risk{% if t("sectionAside.dependencyRisk") != "Dependency / Migration Risk" %} ({{ t("sectionAside.dependencyRisk") }}){% endif %}
187
179
 
188
180
  {% if implementationPlanning.dependencyMigrationRisk | length == 0 -%}
189
181
  {{ t("emptyState.dependencyRisk") }}
@@ -195,7 +187,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
195
187
  {% endfor %}
196
188
  {%- endif %}
197
189
 
198
- ### 5.5.6 Validation Checklist{% if t("sectionAside.validationChecklist") != "Validation Checklist" %} ({{ t("sectionAside.validationChecklist") }}){% endif %}
190
+ ### Validation Checklist{% if t("sectionAside.validationChecklist") != "Validation Checklist" %} ({{ t("sectionAside.validationChecklist") }}){% endif %}
199
191
 
200
192
  | Phase | Ticket ID | Check | Command / Observation | Expected outcome |
201
193
  |-------|-----------|-------|------------------------|-------------------|
@@ -203,7 +195,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
203
195
  | {{ row.phase }} | `{{ row.ticketId }}` | {{ row.check }} | `{{ row.commandOrObservation }}` | {{ row.expectedOutcome }} |
204
196
  {% endfor %}
205
197
 
206
- ### 5.5.7 Rollback Strategy{% if t("sectionAside.rollbackStrategy") != "Rollback Strategy" %} ({{ t("sectionAside.rollbackStrategy") }}){% endif %}
198
+ ### Rollback Strategy{% if t("sectionAside.rollbackStrategy") != "Rollback Strategy" %} ({{ t("sectionAside.rollbackStrategy") }}){% endif %}
207
199
 
208
200
  | ID | Step | Action | Trigger signal | {{ t("columns.checkMethod") }} |
209
201
  |----|------|--------|----------------|-----------|
@@ -211,7 +203,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
211
203
  | {{ row.id }} | {{ row.step }} | `{{ row.action }}` | {{ row.triggerSignal }} | `{{ row.verificationMethod }}` |
212
204
  {% endfor %}
213
205
 
214
- ### 5.5.8 Requirement Coverage
206
+ ### Requirement Coverage
215
207
 
216
208
  | ID | Source | Requirement | Covered by option / stage / step | Status |
217
209
  |----|--------|-------------|-----------------------------------|--------|
@@ -219,6 +211,45 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
219
211
  | {{ row.id }} | `{{ row.source }}` | {{ row.requirement }} | {{ row.coveredBy }} | `{{ row.status }}` |
220
212
  {% endfor %}
221
213
 
214
+ ## 5.5 Stage Map
215
+
216
+ | stage | title | depends-on | step-count | exit-contract-summary |
217
+ |-------|-------|------------|------------|-----------------------|
218
+ {% for row in implementationPlanning.stageMap -%}
219
+ | {{ row.stage }} | {{ row.title }} | {{ row.dependsOn }} | {{ row.stepCount }} | {{ row.exitContractSummary }} |
220
+ {% endfor %}
221
+
222
+ {% for stage in implementationPlanning.stages %}
223
+ ## 5.5.{{ stage.stage }} Stage {{ stage.stage }}: {{ stage.title }}
224
+
225
+ Slice value: {{ stage.sliceValue }}
226
+ Acceptance: {{ stage.acceptance }}
227
+ {% if stage.conformanceTests %}Conformance tests: stage-{{ stage.stage }} — {{ stage.conformanceTests }}
228
+ {% else %}Conformance exemption: {{ stage.conformanceExemption }}
229
+ {% endif %}{% if stage.tddExemption %}TDD exemption: {{ stage.tddExemption }}
230
+ {% endif %}
231
+ ### Carry-In
232
+
233
+ {{ stage.carryIn }}
234
+
235
+ ### Stepwise Execution Order
236
+
237
+ | step | action | files | command | expected |
238
+ |------|--------|-------|---------|----------|
239
+ {% for row in stage.stepwiseExecution -%}
240
+ | {{ row.step }} | {{ row.action }} | `{{ row.files }}` | `{{ row.command }}` | {{ row.expected }} |
241
+ {% endfor %}
242
+
243
+ ### Stage Exit Contract
244
+
245
+ {{ stage.exitContract }}
246
+
247
+ ### Stage Validation
248
+
249
+ {{ stage.stageValidation }}
250
+
251
+ {% endfor %}
252
+
222
253
  ### 5.5.9 Plan Body Verification{% if t("sectionAside.planBodyVerification") != "Plan Body Verification" %} ({{ t("sectionAside.planBodyVerification") }}){% endif %}
223
254
 
224
255
  {{ t("sectionIntro.planBodyVerification") }}
@@ -271,6 +302,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
271
302
  |---------|-----------|--------------------|--------------------|
272
303
  | H1 | {{ t("releaseHandoff.h1Body") }} | `{{ releaseHandoff.userSelections.h1 }}` | `local only` / `push + PR` / `skip` |
273
304
  | H2 | {{ t("releaseHandoff.h2Body") }} | `{{ releaseHandoff.userSelections.h2 or t("releaseHandoff.h2DefaultLabel") }}` | {{ t("releaseHandoff.h2OptionsLabel") }} |
305
+ | H2b | Merge conflict probe | `{{ releaseHandoff.userSelections.h2b or releaseHandoff.mergeConflictProbe.kind }}` | `not-run` / `clean` / `proceed anyway` / `change base branch` / `cancel` |
274
306
  | H3 | {{ t("releaseHandoff.h3Body") }} | `{{ releaseHandoff.userSelections.h3 }}` | `use as-is` / `edit then proceed` / `cancel` |
275
307
 
276
308
  ### 5.6.4 Executed Commands
@@ -371,7 +403,19 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
371
403
  {% endfor %}
372
404
  {%- endif %}
373
405
 
374
- ### 5.7.5 Validation Evidence
406
+ ### 5.7.5 Stage Sidecar Evidence
407
+
408
+ - Stage: `{{ implementation.stageSidecarEvidence.stageNumber }}` — {{ implementation.stageSidecarEvidence.stageTitle }}
409
+ - Carry sidecar JSON:
410
+ ```json
411
+ {{ implementation.stageSidecarEvidence.carryJson }}
412
+ ```
413
+ - Appended `consumers.jsonl` rows:
414
+ {% for row in implementation.stageSidecarEvidence.consumerRows -%}
415
+ > {{ row }}
416
+ {% endfor %}
417
+
418
+ ### 5.7.6 Validation Evidence
375
419
 
376
420
  | Phase | Command | Exit code | Output tail | TDD evidence |
377
421
  |-------|---------|-----------|-------------|--------------|
@@ -379,7 +423,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
379
423
  | {{ row.phase }} | `{{ row.command }}` | `{{ row.exitCode }}` | {{ row.outputTail }} | {{ row.tddEvidence or '--' }} |
380
424
  {% endfor %}
381
425
 
382
- ### 5.7.6 Verifier Results
426
+ ### 5.7.7 Verifier Results
383
427
 
384
428
  {% for block in implementation.verifierResults %}
385
429
  - **{{ block.verifier }}** — Verdict: `{{ block.verdict }}`
@@ -390,7 +434,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
390
434
  - Discrepancy: {{ block.discrepancy or t("emptyState.discrepancy") }}
391
435
  {% endfor %}
392
436
 
393
- ### 5.7.7 Rollback Verification
437
+ ### 5.7.8 Rollback Verification
394
438
 
395
439
  | Category | Rollback command | Verification | Result |
396
440
  |----------|-------------------|---------------|--------|
@@ -398,7 +442,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
398
442
  | {{ row.category }} | `{{ row.rollbackCommand }}` | {{ row.verification }} | `{{ row.result }}` |
399
443
  {% endfor %}
400
444
 
401
- ### 5.7.8 Routing Recommendation
445
+ ### 5.7.9 Routing Recommendation
402
446
 
403
447
  {{ implementation.routingRecommendation }}
404
448
 
@@ -105,7 +105,7 @@
105
105
  "h2Body": "PR base branch (when H1 = `push + PR`)",
106
106
  "h3Body": "How should the PR title/body draft be handled?",
107
107
  "h2DefaultLabel": "(n/a)",
108
- "h2OptionsLabel": "staging / preprod / prod / main / dev / user input",
108
+ "h2OptionsLabel": "staging / preprod / main / user input",
109
109
  "noMutationNote": "(no mutating command — H1=`skip` or H3=`cancel`)",
110
110
  "commandsTableHeader": {
111
111
  "outputSummary": "stdout/stderr summary"
@@ -105,7 +105,7 @@
105
105
  "h2Body": "PR base 브랜치 (H1=`push + PR` 인 경우)",
106
106
  "h3Body": "PR title/body 초안 처리",
107
107
  "h2DefaultLabel": "(n/a)",
108
- "h2OptionsLabel": "staging / preprod / prod / main / dev / 사용자 입력",
108
+ "h2OptionsLabel": "staging / preprod / main / 사용자 입력",
109
109
  "noMutationNote": "(mutating 명령 미실행 — H1=`skip` 또는 H3=`cancel`)",
110
110
  "commandsTableHeader": {
111
111
  "outputSummary": "stdout/stderr 요약"
@@ -27,7 +27,7 @@ taskType: "{{FM_TASK_TYPE}}"
27
27
  ## Approved Plan Reference (mandatory)
28
28
 
29
29
  - Approved plan path: `runs/implementation-planning/<run-id>/reports/final-report.md`
30
- - Approval evidence (quoted exactly from the plan's `User Approval Request` resolution):
30
+ - Approval evidence (quoted exactly from the plan's YAML frontmatter, e.g. `approved: true`):
31
31
  - Recommended option name selected from the plan:
32
32
  - Plan's bite-sized step list (paste or reference by anchor):
33
33
 
@@ -89,12 +89,12 @@ The final report of an `implementation-planning` run MUST contain every section
89
89
  1. **Option Candidates** — at least two viable options, each with the exact list of files to create or modify and the principal change per file.
90
90
  2. **Trade-off Matrix** — comparison of the candidates across complexity, risk, reversibility, performance impact, scope, and required test surface.
91
91
  3. **Recommended Option** — selected option with explicit rationale referencing the trade-off matrix.
92
- 4. **Stepwise Execution Order** — ordered steps where each step is independently verifiable; each step lists the files it touches and the test/command that proves it works.
92
+ 4. **Stage Map** — `## 5.5 Stage Map` plus one `## 5.5.<i> Stage <i>:` section per stage. Each stage is a thin vertical slice with `Slice value:`, `Acceptance:`, `Conformance tests:` or `Conformance exemption:`, the four required subsections, and a RED/GREEN step order unless a `TDD exemption:` line applies.
93
93
  5. **Dependency and Migration Risk** — schema, data, ordering, feature-flag, and cross-service risks that the recommended option introduces.
94
94
  6. **Validation Checklist** — pre-execution, mid-execution, and post-execution checks (commands, expected outputs, observability points).
95
95
  7. **Rollback Strategy** — exact reverse procedure or compensating action for each significant step.
96
96
  8. **Scope Boundary** — an explicit list of adjacent areas, files, refactors, or quality improvements that this plan **does NOT** cover, each with a one-line reason (deferred, separate owner, separate decision, out of requirement). Any item the analysers were tempted to fold in but chose to exclude MUST appear here. An empty list is allowed only when the analysers explicitly state "no adjacent expansion was considered" — silence is not acceptable.
97
- 9. **User Approval Request** — a labelled block stating that the plan is awaiting explicit user approval. The next `implementation` run MUST NOT begin until the user has replied with explicit approval to this block.
97
+ 9. **Approval frontmatter** — the final report's YAML frontmatter MUST emit `approved: false` and `implementation-option:`. Do NOT create a `User Approval Request` body block; the next `implementation` run reads only the frontmatter gate.
98
98
 
99
99
  ## Phase Boundary
100
100
 
@@ -108,7 +108,7 @@ The final report of an `implementation-planning` run MUST contain every section
108
108
 
109
109
  ## Stage Output Shape (reference)
110
110
 
111
- This run's final report MUST emit `## 5.5 Stage Map` and `## 5.5.<i> Stage <i>` sections per the implementation-planning profile §"Required deliverable shape". Two illustrative shapes:
111
+ This run's final report MUST emit `## 5.5 Stage Map` and `## 5.5.<i> Stage <i>` sections per the implementation-planning profile §"Required deliverable shape". Two illustrative Stage Map tables:
112
112
 
113
113
  ### Shape A — single stage (small work)
114
114
  | stage | title | depends-on | step-count | exit-contract-summary |
@@ -991,6 +991,7 @@ PLANNING_REQUIRED_SECTIONS = (
991
991
  "Option Candidates",
992
992
  "Trade-off",
993
993
  "Recommended Option",
994
+ "Stage Map",
994
995
  "Stepwise Execution Order",
995
996
  "Dependency",
996
997
  "Validation Checklist",
@@ -1005,6 +1006,7 @@ IMPLEMENTATION_REQUIRED_SECTIONS = (
1005
1006
  "Commit List",
1006
1007
  "Diff Summary",
1007
1008
  "Out-of-plan Edits",
1009
+ "Stage Sidecar Evidence",
1008
1010
  "Validation Evidence",
1009
1011
  "Verifier Results",
1010
1012
  "Rollback Verification",