okstra 0.122.0 → 0.123.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.
Files changed (53) hide show
  1. package/README.md +4 -2
  2. package/docs/architecture/storage-model.md +14 -0
  3. package/docs/architecture.md +34 -6
  4. package/docs/cli.md +45 -5
  5. package/docs/for-ai/README.md +2 -2
  6. package/docs/for-ai/skills/okstra-rollup.md +1 -1
  7. package/docs/for-ai/skills/{okstra-schedule.md → okstra-schedule-gen.md} +3 -3
  8. package/docs/project-structure-overview.md +3 -2
  9. package/docs/task-process/implementation-planning.md +33 -9
  10. package/docs/task-process/implementation.md +21 -2
  11. package/package.json +1 -1
  12. package/runtime/BUILD.json +2 -2
  13. package/runtime/bin/lib/okstra/usage.sh +3 -3
  14. package/runtime/prompts/launch.template.md +5 -2
  15. package/runtime/prompts/lead/convergence.md +1 -1
  16. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  17. package/runtime/prompts/lead/plan-body-verification.md +29 -0
  18. package/runtime/prompts/lead/report-writer.md +9 -3
  19. package/runtime/prompts/profiles/_common-contract.md +1 -1
  20. package/runtime/prompts/profiles/_implementation-deliverable.md +3 -1
  21. package/runtime/prompts/profiles/_implementation-executor.md +5 -0
  22. package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
  23. package/runtime/prompts/profiles/final-verification.md +2 -0
  24. package/runtime/prompts/profiles/implementation-planning.md +11 -1
  25. package/runtime/prompts/wizard/prompts.ko.json +44 -0
  26. package/runtime/python/okstra_ctl/codex_dispatch.py +23 -1
  27. package/runtime/python/okstra_ctl/design_prep.py +1462 -0
  28. package/runtime/python/okstra_ctl/design_surfaces.py +243 -0
  29. package/runtime/python/okstra_ctl/final_report_schema.py +33 -1
  30. package/runtime/python/okstra_ctl/implementation_stage.py +35 -0
  31. package/runtime/python/okstra_ctl/incremental_carry.py +294 -21
  32. package/runtime/python/okstra_ctl/incremental_scope.py +51 -5
  33. package/runtime/python/okstra_ctl/material.py +1 -1
  34. package/runtime/python/okstra_ctl/model_discovery.py +98 -0
  35. package/runtime/python/okstra_ctl/models.py +8 -3
  36. package/runtime/python/okstra_ctl/render.py +5 -0
  37. package/runtime/python/okstra_ctl/run.py +53 -5
  38. package/runtime/python/okstra_ctl/user_response.py +67 -2
  39. package/runtime/python/okstra_ctl/wizard.py +283 -3
  40. package/runtime/python/okstra_token_usage/report.py +11 -0
  41. package/runtime/schemas/final-report-v1.0.schema.json +336 -0
  42. package/runtime/skills/okstra-inspect/SKILL.md +2 -2
  43. package/runtime/skills/okstra-rollup/SKILL.md +1 -1
  44. package/runtime/skills/{okstra-schedule → okstra-schedule-gen}/SKILL.md +2 -2
  45. package/runtime/skills/okstra-user-response/SKILL.md +8 -6
  46. package/runtime/templates/reports/final-report.template.md +67 -0
  47. package/runtime/templates/reports/i18n/en.json +31 -0
  48. package/runtime/templates/reports/i18n/ko.json +31 -0
  49. package/runtime/validators/validate-run.py +426 -5
  50. package/runtime/validators/validate-schedule.py +4 -4
  51. package/src/cli-registry.mjs +7 -0
  52. package/src/commands/inspect/design-prep.mjs +23 -0
  53. package/src/lib/skill-catalog.mjs +2 -1
@@ -91,7 +91,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
91
91
 
92
92
  The **default is full re-verification**. Only narrow this re-run to the impacted stages when the deterministic `okstra incremental-scope` CLI returns `mode == "incremental"`; on any doubt, stay full. This procedure fires ONLY when this run's task-type is `implementation-planning` AND a prior final report exists for this task-key (its data.json at `runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json`, where `<prev-seq>` is the most recent prior implementation-planning run's seq). For every other task-type, ignore this block and re-verify normally. This branches on the CLI's `mode` output only — it does NOT re-implement the safety logic in the prompt.
93
93
 
94
- 1. **Resolve the impacted stage set (safety condition C2 — your discretionary judgement).** For each answered `C-*` row you reconciled in §1, decide which **Stage Map stage numbers** (from the prior plan's `## 5.5 Stage Map`) the answer touches. Rules:
94
+ 1. **Resolve the impacted stage set (safety condition C2 — your discretionary judgement).** For each answered `C-*` row you reconciled in §1, decide which **Stage Map stage numbers** (from the prior plan's `## 5.5 Stage Map`) the answer touches. Also collect the IDs of any PREP items changed by the carried response. Rules:
95
95
  - Pass ONLY stage numbers that appear in that Stage Map. Never invent or guess a stage number — a number absent from the graph must never enter `--impacted` (it would leak into `reverify_stages`).
96
96
  - If you cannot map a touched item to a real stage with confidence, leave the impacted set **EMPTY** — an empty set forces `mode == "full"`. Widening to full is always the safe choice; guessing is not.
97
97
  - If any answer overturns the selected Option, restructures the stages, or changes the recommended approach (rather than a localized detail), also leave the impacted set **EMPTY**.
@@ -104,7 +104,8 @@ The **default is full re-verification**. Only narrow this re-run to the impacted
104
104
  --prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
105
105
  --cur-base-sha {{EXECUTOR_WORKTREE_BASE_REF}} \
106
106
  --prev-base-sha <prior baseRef from step 2> \
107
- --impacted <csv of impacted stage numbers, empty for full>
107
+ --impacted <csv of impacted stage numbers, empty for full> \
108
+ --prep-items <csv of changed PREP item ids, empty when none>
108
109
  ```
109
110
  The CLI reads the plan's dependency graph from the top-level `## 5.5 Stage Map` (`implementationPlanning.stageMap`), which is authoritative for the impacted stage numbers — there is no per-option stage graph. The CLI prints JSON `{mode, reverify_stages, carry_stages, reason}`. Instruct the report-writer to record this JSON verbatim into this run's data.json as `implementationPlanning.incrementalDecision` (keys `mode`, `reverifyStages`, `carryStages`, `reason`) — the renderer turns it into the `### 0.1 Incremental Re-Verification Scope` audit block, and the validator fails an `incremental`-mode run whose Section 0 omits that block.
110
111
  4. **`mode == "full"`** → run the existing full re-verification path unchanged; ignore `reverify_stages` / `carry_stages`.
@@ -115,6 +116,8 @@ The **default is full re-verification**. Only narrow this re-run to the impacted
115
116
  --prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
116
117
  --cur-data <this run's data.json> \
117
118
  --prev-seq <prev-seq> \
119
+ --carry-stages <csv from incrementalDecision.carry_stages> \
120
+ --reverify-stages <csv from incrementalDecision.reverify_stages> \
118
121
  --out <this run's data.json>
119
122
  ```
120
123
  A non-zero exit (`CarryError` — schema drift between the two runs) means the carry is unsafe: fall back to **full** — discard the incremental result and re-verify every stage. Note: `verdictCard` / `finalVerdict` are NEVER carried — this run re-computes them from the re-verified plus carried plan items.
@@ -277,7 +277,7 @@ Assigned worker prompt history path: <Project Root>/<Prompt History Path>
277
277
  2. `team-state-<task-type>-<seq>.json` → `workers[].usage.cliModel` for that role (initial run's actual execution value)
278
278
  3. The `**Model:**` line of the initial Phase 4 prompt for that role (read from its persisted prompt-history file)
279
279
 
280
- If none of the three is available, **abort the reverify dispatch for that role** and record a `contract-violation` event via `okstra error-log append-observed`. Do NOT guess or fall back to a runtime default. The selected adapter receives the exact value through the assignment and owns how it reaches the worker runtime. The current Codex catalog default is `gpt-5.6`, but that reference value never replaces the manifest assignment.
280
+ If none of the three is available, **abort the reverify dispatch for that role** and record a `contract-violation` event via `okstra error-log append-observed`. Do NOT guess or fall back to a runtime default. The selected adapter receives the exact value through the assignment and owns how it reaches the worker runtime. The current Codex catalog default is `gpt-5.6-sol`, but that reference value never replaces the manifest assignment.
281
281
 
282
282
  ### Reverify prompt: required-reading suppression
283
283
 
@@ -34,7 +34,7 @@ This document is the operating contract and phase index. Detailed procedures liv
34
34
  | [plan-body-verification](./plan-body-verification.md) | Phase 6 plan-body verification sub-step (implementation-planning only) — plan-item extraction, verdict semantics, gate resolution, state schema. Read only at that sub-step |
35
35
  | [report-writer](./report-writer.md) | Phase 6 final-report authorship, dispatch template, resume-safe dispatch, shared-graph integrity check, Phase 7 token-usage collector |
36
36
 
37
- Read-side inspection (`/okstra-inspect`) and scheduling (`/okstra-schedule`) are user-invoked skills, not lead support contracts — the lead does not consult them during a run.
37
+ Read-side inspection (`/okstra-inspect`) and scheduling (`/okstra-schedule-gen`) are user-invoked skills, not lead support contracts — the lead does not consult them during a run.
38
38
 
39
39
  ## Quick Reference
40
40
 
@@ -126,7 +126,7 @@ The table below documents those prep-time seed values **for reference only** —
126
126
  | Lead role | opus | -- | runtime-specific role label; orchestration + convergence supervision + final-report review/approval |
127
127
  | Report writer worker | opus | report-writer-worker | `agents/workers/report-writer-worker.md` |
128
128
  | Claude worker | opus | claude-worker | `agents/workers/claude-worker.md` |
129
- | Codex worker | gpt-5.6 | codex-worker | generated from `agents/workers/_cli-wrapper-template.md` + `codex-worker.params.json` |
129
+ | Codex worker | gpt-5.6-sol | codex-worker | generated from `agents/workers/_cli-wrapper-template.md` + `codex-worker.params.json` |
130
130
  | Antigravity worker | auto | antigravity-worker | generated from `agents/workers/_cli-wrapper-template.md` + `antigravity-worker.params.json` |
131
131
 
132
132
  All three analysis workers use dedicated agent definitions; Codex/Antigravity wrappers handle external CLI invocation internally; Claude worker runs as an in-process subagent with explicitly registered MCP tools so it does not fall back to `claude --mcp-cli` Bash invocations.
@@ -60,11 +60,14 @@ From the report-writer's draft of `## 5.4 Implementation Plan Deliverables`, lea
60
60
  | `P-Val-<N>` | `4.5.6 Validation Checklist` | one checklist item |
61
61
  | `P-Rb-<N>` | `4.5.7 Rollback Strategy` | one rollback path |
62
62
  | `P-Req-<N>` | `4.5.8 Requirement Coverage` | one requirement coverage row |
63
+ | `P-Prep-S<stage>-<kind>` | Stage `designSurfaceCoverage` + `5.5.10 Implementation Design Preparation` | exactly one detector-produced `(stage, kind)` |
63
64
 
64
65
  `4.5.2 Trade-off Matrix` and `4.5.3 Recommended Option` are NOT extracted as standalone plan items — the trade-off matrix is evaluated implicitly through each option's `P-Opt-*` verification, and the recommended option is one of those `P-Opt-*` rows.
65
66
 
66
67
  Each plan item inherits the `[TICKETID: ...]` tag of its source section (per the standard ticket-tagging contract).
67
68
 
69
+ For every detector-produced `(stage, kind)`, extract exactly one plan item named `P-Prep-S<stage>-<kind>`. The V1 detector in `scripts/okstra_ctl/design_surfaces.py` owns the set: extraction consumes its output and never reruns a free-form requirements or keyword analysis. The worker receives the stage trigger evidence and its single `designSurfaceCoverage` row, plus only the referenced `designPreparation` PREP items needed to judge that row. `validators/validate-run.py` `_validate_expected_prep_plan_items` enforces the exact ID set and `_validate_detector_coverage` enforces exactly-once coverage/evidence.
70
+
68
71
  When extracting each item, lead also captures a **`subject`** — a plain one-line label (≤12 words) describing *what that item is* in the reader's terms, e.g. `P-Opt-1` → "Option A: upload v2 를 신규 모듈로 분리", `P-Step-1.1` → "Stage 1 Step 2: `npm run test:v2` 로 회귀 검증". This is a label-capture, not new analysis. The `subject` is what §5.5.9 renders as the per-item heading so the reader knows *what* each AGREE/DISAGREE is about without cross-referencing §4.5; a bare `P-*` ID with no subject is a contract violation. **Enforced:** `validators/validate-run.py` `_validate_plan_item_subject_substance` fails a subject that is a placeholder — under 3 chars, equal to the item id, or shaped like a bare `P-*` id.
69
72
 
70
73
  ## Plan-body verdict semantics
@@ -85,6 +88,15 @@ The verdict tokens `AGREE` / `DISAGREE` / `SUPPLEMENT` are reused, but their mea
85
88
  - `needs-user-input` — 교정에 열린 사용자 clarification(인프라·계약 결정) 또는 외부 정보가 필요하다.
86
89
  기준 한 줄: "지금 가진 코드 + 계획 + brief 만으로 이 결함을 고칠 수 있는가?" — 그렇다면 `planner-fixable`. **Enforced:** `validators/validate-run.py` `_validate_disagree_has_fixability` 는 verification round 가 돈(`roundCount >= 1`) run 에서 `fixability` 가 없거나 허용값(`planner-fixable` / `needs-user-input`)이 아닌 `DISAGREE` verdict 를 실패시킨다 — 그래야 `_validate_self_fix_before_clarification` 가 mislabel 로 planner-fixable 결함을 self-fix 없이 승격시키지 못한다.
87
90
 
91
+ `P-Prep-S<stage>-<kind>` applies the same verdict tokens and adds these disposition checks:
92
+
93
+ - `inline-contract`: AGREE only when the contract contains the kind-specific fields needed to implement the stage; a label or generic prose is insufficient.
94
+ - `prep-item`: AGREE only when every referenced PREP item has a concrete `aiProposal`, correct `stageRefs`/`kind`, and state-specific safeguards required by `schemas/final-report-v1.0.schema.json`.
95
+ - `not-applicable`: AGREE only when the rationale is consistent with the stage action; otherwise DISAGREE with `fixability` (`planner-fixable` when the plan can supply the missing contract, `needs-user-input` only for genuinely external facts).
96
+ - A declared `blocked` item is not itself a plan-body failure. Missing or duplicate coverage, an empty proposal, a mismatched reference, or an unjustified disposition is a failure and receives `DISAGREE(<kind>)` with `fixability`.
97
+
98
+ The semantic checks above are the plan-body enforcement layer for the schema-valid structures; `validators/validate-run.py` enforces detector coverage and references, while this worker verdict decides whether the content is implementable.
99
+
88
100
  Worker non-result handling (`timeout`, `error`, no result file, wrapper `cli-failure`) is identical to finding convergence: do NOT aggregate as DISAGREE, record `contract-violation`, and apply the round-level abort rule below.
89
101
 
90
102
  ## Mode constraint
@@ -123,6 +135,7 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
123
135
  6. Lead writes `runs/<task-type>/state/plan-body-verification-<task-type>-<seq>.json` (schema below) and populates `### 5.5.9 Plan Body Verification` in the final report's data.json (`implementationPlanning.planBodyVerification`, schema `schemas/final-report-v1.0.schema.json`; template at `templates/reports/final-report.template.md`). The §5.5.9 body is **grouped by plan item**: `planItems[]`, each carrying its `id`, its plain-language `subject` (rendered as the item heading), an optional `sourceSection`, an optional `clarificationId` (the `C-<N>` this item blocks on when `majority-disagree`), and a `verdicts[]` list (`worker / verdict / breakageKind / note`) — one verdict row per worker under that item. The renderer prints three fixed legends (gate values, verdict tokens, breakage kinds a–f) so the reader can decode every cell without opening this spec. The older flat `#### Verdict details` table (`Plan item / Worker / …`, one row per plan-item × worker pair) is superseded by the grouped layout — it hid *what* each vote was about behind a bare `P-*` ID; the subject heading is the fix. The validator's `Plan Body Verification` + `Gate result:` substring checks still gate this section.
124
136
  7. **Self-fix round (최대 1회, planner-fixable 결함 대상).** aggregation 후 `majority-disagree` 항목 중 그 `DISAGREE` verdict 의 다수가 `fixability == planner-fixable` 인 항목이 하나 이상이면, lead 는 사용자에게 승격하기 **전에** 자가수정을 1회 시도한다:
125
137
  - lead 가 report-writer 에게 그 planner-fixable 항목들만 교정 재작성을 지시한다(전체 draft 재생성 아님 — 해당 `P-*` 가 가리키는 계획 섹션만 patch; 절차는 [report-writer](./report-writer.md) §"Self-fix rewrite").
138
+ - missing or weak `P-Prep-*` contracts are repaired by adding kind-specific inline detail or an AI-prepared PREP item with a concrete proposal. Facts that require user or external authority remain `blocked` and keep their request material; never invent those facts during self-fix.
126
139
  - lead 가 plan-body 검증을 1회 재실행한다(교정된 항목 + 재작성이 건드린 인접 항목 중심). 재검증 후 verdict 로 `planItems[].verdicts` 를 덮어쓴다.
127
140
  - self-fix 로 `majority-disagree` 가 해소된 항목은 `planItems[].selfFixNote` 에 `self-fixed in round <N>: <무엇을 고쳤는지>` 를 기록한다. 해소된 항목은 clarification 을 만들지 않는다.
128
141
  - 이 라운드는 **최대 1회**다(무한루프 상한). self-fix 라운드를 시도했으면 `planBodyVerification.selfFixRoundApplied = true` 로 기록한다.
@@ -217,6 +230,11 @@ against the cited plan item(s). Do not open the original brief, but do reject
217
230
  coverage rows that cite no concrete option/stage/step or cite a plan item that
218
231
  does not satisfy the row's own requirement.
219
232
 
233
+ For each `P-Prep-S<stage>-<kind>` item, use only the supplied detector trigger
234
+ evidence, its single `designSurfaceCoverage` row, and referenced PREP items.
235
+ Apply the disposition-specific AGREE/DISAGREE rules in this contract; do not
236
+ rerun a free-form requirements analysis. Every DISAGREE includes Fixability.
237
+
220
238
  ## Plan items to verify
221
239
 
222
240
  ### P-Step-3 [TICKETID: <id>]: <one-line summary>
@@ -232,6 +250,12 @@ does not satisfy the row's own requirement.
232
250
  ### P-Opt-2 [TICKETID: <id>]: <one-line summary>
233
251
  ...
234
252
 
253
+ ### P-Prep-S2-external-interface [TICKETID: <id>]: <one-line summary>
254
+ **From section**: Stage 2 designSurfaceCoverage + 5.5.10 Implementation Design Preparation
255
+ **Trigger evidence**: <detector-produced evidence rows>
256
+ **Coverage row**: <the single designSurfaceCoverage row>
257
+ **Referenced PREP items**: <verbatim referenced items, or none>
258
+
235
259
  ## Response format
236
260
 
237
261
  ### P-Step-3
@@ -241,6 +265,11 @@ does not satisfy the row's own requirement.
241
265
 
242
266
  ### P-Opt-2
243
267
  ...
268
+
269
+ ### P-Prep-S2-external-interface
270
+ **Verdict**: AGREE | DISAGREE(<a|b|c|d|e|f>) | SUPPLEMENT
271
+ **Fixability** (DISAGREE only): planner-fixable | needs-user-input
272
+ **Explanation**: <2-3 sentences applying the disposition-specific rule>
244
273
  ```
245
274
 
246
275
  When `config.adversarial == true`, the lead prepends the adversarial framing from §"Adversarial plan-body posture" to the `## Instructions` block: the burden of proof is on the plan, the verifier opens and confirms every cited path / command, and an item whose cited references cannot be confirmed is answered `DISAGREE(<kind>)` rather than `AGREE`. The verdict tokens, breakage kinds (a–f), classification, and the majority gate threshold are unchanged. This prepended framing supersedes the template's "Judge solely from plan internal consistency" instruction for the adversarial round.
@@ -51,7 +51,7 @@ The prompt MUST include, in this order at the top:
51
51
  has been resolved by the lead from project.json / global config
52
52
  before the dispatch is constructed. The worker copies this verbatim
53
53
  into `data.json.meta.reportLanguage`.
54
- 12. For implementation-planning runs: a literal block listing the 8 required English section headings the validator scans for (`Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`). The writer must use these exact substrings as section headings (Korean translation in parentheses is allowed).
54
+ 12. For implementation-planning runs: a literal block listing the 10 required English section headings (`Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`, `Plan Body Verification`, `Implementation Design Preparation`). The writer uses these exact substrings as section headings (Korean translation in parentheses is allowed), and the `Plan Body Verification` section carries its required `Gate result:` line.
55
55
  13. An explicit instruction: `You are the author of TWO files: (a) the final-report data.json at <Result Path>, (b) the worker-results audit file at <Worker Result Path>. After writing the data.json, invoke "okstra render-final-report <Result Path>" through the available execution interface so the markdown sibling is rendered before you return. Do not return the report inline. The validator fails the run when (a)'s schema validation fails, when the rendered markdown is absent, or when (b) is missing.`
56
56
 
57
57
  **Completion detection after dispatch (BLOCKING).** A dispatch acknowledgement is NOT completion — detect completion via the SSOT protocol in [team-contract](./team-contract.md) "Worker-completion detection", with a one-entry pending set covering the data.json (Result Path) and the worker-results file (Worker Result Path). Do NOT end the turn with a prose "waiting for the report" statement.
@@ -75,6 +75,8 @@ Speculative reasons such as "session resume constraint", "runtime state is unava
75
75
 
76
76
  Phase 6 first produces the final-report data.json at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` and its rendered markdown sibling. Token Usage cells are `null` at this point, and Section 3 does not yet include auto-spawned follow-ups.
77
77
 
78
+ For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v1.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
79
+
78
80
  The four Phase 7 steps below MUST execute in this exact order. Reordering them is the recurring root cause of reports shipping with `--` token cells, Section 3 missing follow-up entries, or Section 4 rows never spawning.
79
81
 
80
82
  1. **Collect usage.** Call `collect_usage` through the selected adapter with substitution enabled by the existing `okstra token-usage` workflow. One invocation aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state, populates `tokenUsage` and the execution-status usage fields in data.json, and re-invokes the renderer so the markdown carries real numbers.
@@ -87,6 +89,8 @@ The four Phase 7 steps below MUST execute in this exact order. Reordering them i
87
89
  ```
88
90
 
89
91
  The data.json paths populated: `tokenUsage.lead.{totalTokens,billableTokens,costUsd}`, the `worker` / `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` for rows whose role matches a team-state worker. The data.json MUST already exist (Phase 6 output).
92
+
93
+ For implementation-planning, this Phase 7 canonical render calls `materialize_design_prep_requests()` after token substitution and creates deterministic request files only for `provisional` / `blocked` items. Later answers are append-only user-input sidecars; request generation and user input never rewrite the assessment fields, so the source report remains immutable as the design-input snapshot after this render. `validators/validate-run.py` `_validate_design_prep_requests` enforces request existence, canonical path, content, and assessment fingerprint.
90
94
  2. **Validate and render the report artifacts.** Always invoke the report-view renderer after the substituted data.json passes its schema/run checks; the renderer decides whether an html sibling is warranted:
91
95
 
92
96
  ```bash
@@ -199,7 +203,7 @@ Token Summary Generation Rules:
199
203
 
200
204
  ### Implementation-planning section heading contract (BLOCKING)
201
205
 
202
- When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the 9 literal English substrings below**. The validator (`validators/validate-run.py`) does plain substring matching on the report text — missing headings was a real, repeatedly observed failure mode caused by translating the headings to Korean.
206
+ When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the 10 literal English substrings below**. The validator (`validators/validate-run.py`) does plain substring matching on the report text and validates the design-preparation data contract — missing headings was a real, repeatedly observed failure mode caused by translating the headings to Korean.
203
207
 
204
208
  | # | Required substring | Recommended heading form |
205
209
  |---|--------------------|--------------------------|
@@ -212,6 +216,7 @@ When the run's `task-type` is `implementation-planning`, the final report MUST c
212
216
  | 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
213
217
  | 8 | `User Approval Request` | Satisfied by the top-of-report `## User Approval Request (사용자 승인 게이트)` block. Do NOT recreate a `### 5.5.8 User Approval Request` body stub — the validator now fails reports that contain one. |
214
218
  | 9 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (계획 본문 검증)` containing a `Gate result:` line — copy `templates/reports/final-report.template.md §5.5.9` verbatim. Validator checks both substrings. |
219
+ | 10 | `Implementation Design Preparation` | `### Implementation Design Preparation (구현 설계 준비)` — rendered from `implementationPlanning.designPreparation` by `templates/reports/final-report.template.md §5.5.10`. |
215
220
 
216
221
  The Korean translation in parentheses is optional but the English keyword is mandatory. The body of each section is written in the Report Language per the writing rules below. For non-`implementation-planning` runs, omit this entire block — these headings are NOT validator-checked for other task-types.
217
222
 
@@ -225,6 +230,7 @@ lead 가 self-fix 라운드를 지시하면(대상 `P-*` 목록 + 각 결함 사
225
230
  - prose command → 작업 디렉터리·인자·task-type 이 포함된 실행 가능한 명령 시퀀스로 구체화.
226
231
  - placeholder(`stage-<N>` 등) → 구체 파일명·재생성 계획으로 교체.
227
232
  - requirement-coverage 매핑 오류 → 실재하는 option/stage/step 또는 XP 행으로 재매핑.
233
+ - missing/weak design-prep contract → kind-specific inline detail 또는 concrete `aiProposal` 을 가진 AI-prepared PREP item 으로 교정. 사용자·외부 권한 사실은 만들어내지 않고 `blocked` + request material 로 유지한다.
228
234
 
229
235
  교정 후 해당 `planItems[].selfFixNote` 에 `self-fixed in round <N>: <무엇을 고쳤는지>` 를 남기고, `planBodyVerification.selfFixRoundApplied = true` 로 표시한다. `needs-user-input` 항목은 절대 교정 대상이 아니다 — 그대로 clarification 으로 승격된다.
230
236
 
@@ -280,7 +286,7 @@ Every field MUST anchor its claim with at least one evidence reference — a `pa
280
286
 
281
287
  **Reader-facing prose MUST NOT cite a bare brief/worker-internal ID that this report never surfaces** — `RC-*` (reporter confirmations, defined in the brief), `RF-*` / `F-*` (findings, defined in worker-results) have no anchor in the final report, so a reader hits an opaque token with nothing to click. Either expand it inline (`the confirmed version target 1.27.47→1.27.48`) or, for an audit trail, namespace it (`claude:F-005`). **Enforced:** `_validate_no_opaque_id_references` fails a bare `RC-*` / `RF-*` / non-namespaced `F-*` appearing in `verdictCard` / `finalVerdict` / `rationale` / `clarificationItems[].statement`. (The renderer anchors + links in-report IDs of any digit width, so a surfaced `RC-4`-style id does resolve.) Do NOT restate the Verdict Card or the §5.4 trade-off matrix verbatim — this section is the *why*, in connected prose, that those tables compress.
282
288
 
283
- 0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub. When the lead ran `okstra incremental-scope` for this re-run, record its JSON verbatim into `implementationPlanning.incrementalDecision` (`mode`, `reverifyStages`, `carryStages`, `reason`); the renderer emits the `### 0.1 Incremental Re-Verification Scope` audit block from it, and the validator fails an `incremental`-mode run whose Section 0 omits that block. In `incremental` mode this run's `planItems` MUST carry every plan-item id from the re-verified stages forward with its updated verdict; if re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is not local — do not drop it here, tell the lead to abandon incremental and re-route to a FULL re-verification, because the carry merge only adds prior items and would resurrect the removed item's stale verdict.
289
+ 0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub. The lead calls `okstra incremental-scope` exactly once, combining answered-clarification stage impacts (`--impacted`) and changed PREP IDs (`--prep-items`); selected-option, Stage Map, or recommended-approach changes pass both CSVs empty to force full mode. Record that single decision JSON verbatim into `implementationPlanning.incrementalDecision` (`mode`, `reverifyStages`, `carryStages`, `reason`); the renderer emits the `### 0.1 Incremental Re-Verification Scope` audit block from it, and the validator fails an `incremental`-mode run whose Section 0 omits that block. In `incremental` mode this run's `planItems` MUST carry every plan-item id from the re-verified stages forward with its updated verdict; if re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is not local — do not drop it here, tell the lead to abandon incremental and re-route to a FULL re-verification, because the carry merge only adds prior items and would resurrect the removed item's stale verdict. After authoring the current data.json, call `okstra incremental-carry`, passing the decision's `carryStages` CSV to `--carry-stages` and its `reverifyStages` CSV to `--reverify-stages`. A `CarryError` means the stage/PREP ownership contract is unsafe: discard the partial merged output and route the run through full re-verification; never publish a partially merged report.
284
290
  1. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- 합의 미달 항목 없음.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
285
291
  2. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
286
292
  3. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
@@ -8,7 +8,7 @@ profile document.
8
8
  - Team contract (shared):
9
9
  - `Claude lead` is synthesis-only and stays distinct from `Claude worker` (or, in `implementation`, the `Executor` and verifiers).
10
10
  - `Report writer worker` is the **author** of the final-report file; `Claude lead` reviews and approves the produced draft and does NOT write the file itself (see `team-contract` and `report-writer` for the authoritative contract).
11
- - default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6`, `Antigravity worker`=`auto`. Phase-specific overrides (e.g. `implementation`'s executor binding) live in the per-profile document.
11
+ - default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6-sol`, `Antigravity 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
14
  - Worker interaction model (shared — read before inferring behaviour from the roster):
@@ -30,7 +30,8 @@ are collected and convergence finished. Phase 1-5 do not need it.
30
30
  - **Pure code changes** (no persisted state, no infra mutation): a reachable revert SHA is sufficient. Record the exact `git revert <SHA>` command that would undo the change, and confirm `git rev-parse <SHA>` resolves.
31
31
  - **Feature-flag-gated changes**: confirm the off-switch path was exercised in this run's validation evidence (i.e. one of the validation commands ran with the flag off and succeeded). A plan that ships a flag without exercising the off-path does NOT satisfy this requirement.
32
32
  - **Schema migrations, config-format changes, or any change with persisted state**: a **dry-run of the rollback step is mandatory**, not preferred. Record the exact rollback command and its captured exit code / stdout. If the migration tool offers no dry-run mode (`--dry-run`, `--plan`, equivalent), the executor MUST refuse to claim rollback verification and instead end the run with a routing recommendation back to `implementation-planning` for a safer rollback strategy. Skipping this step on a stateful change is treated as a `contract-violated` outcome by `final-verification`.
33
- - **Manual user test draft**: when this run produces a user-observable change (UI / API / CLI / artifact), write `target / environment / steps / expected result` per change into §5.7.9 (data field `implementation.manualUserTest`, `applicable=true` with `items`). Environment line: if the project has a `docker-compose.yml`, use `/okstra-container-build` (which runs `okstra container up <task-id>`) then connect to the published port; otherwise the project's run command (e.g. `npm start`). When there is no user-observable change, set `applicable=false` and give a one-line `exemptionReason` instead of items. Base the steps on the approved plan's `Acceptance:` and this run's actual diff — these are the steps a human (or `final-verification`) re-runs by hand, NOT the automated validation commands in `Validation evidence`.
33
+ - **Manual user test draft**: when this run produces a user-observable change (UI / API / CLI / artifact), write `target / environment / steps / expected result` per change into §5.7.9 (data field `implementation.manualUserTest`, `applicable=true` with `items`). Treat effective `manual-user-test` PREP content only as a seed: reconcile it with the approved plan's `Acceptance:` and this run's actual diff before writing the final steps. Environment line: if the project has a `docker-compose.yml`, use `/okstra-container-build` (which runs `okstra container up <task-id>`) then connect to the published port; otherwise the project's run command (e.g. `npm start`). When there is no user-observable change, set `applicable=false` and give a one-line `exemptionReason` instead of items. These are the steps a human (or `final-verification`) re-runs by hand, NOT the automated validation commands in `Validation evidence`; planning PREP is never a second final-verification manual-test source.
34
+ - **Design preparation handoff**: `implementation.manualUserTest` remains the only manual-test handoff to final-verification. For each effective non-`manual-user-test` item whose `reviewAt.phase` is `final-verification` and whose question remains unresolved after inspecting the actual diff, add one common `missingInformation` row. Set `source` to `design-prep:<PREP-ID>:<assessment-fingerprint>`, put `ifStillOpen` and the unresolved question in `item`, and put the guardrails plus risk in `risk`. Do not introduce an implementation-only PREP schema.
34
35
  - **Routing recommendation for `final-verification`**: brief note on whether the changes are ready for final-verification phase or need a new error-analysis / planning loop first.
35
36
  - **Follow-up tasks (Section 4 of the final report)**: every item discovered during this run that was *not* delivered MUST appear in the final report's `## 4. Follow-up Tasks (후속 작업)` table with a concrete `Origin`, `New Task ID`, `Suggested task-type`, `Scope`, and `Reason / Why deferred`. Sources include: out-of-scope discoveries that the executor consciously chose not to fold into this run, verifier concerns the executor declined to fix in-place, scope-boundary items from the approved plan that turned out to need their own ticket, and any unresolved `## 1. Clarification Items` row carried over from the approved plan (`Status` ∈ `{open, answered}` at approval time). An empty section is acceptable but only when expressed as the single line `- 후속 작업 없음.` — silence is treated as a contract violation. Rows with `Auto-spawn? = yes` will be materialised by `scripts/okstra-spawn-followups.py` in Phase 7; rows with `Auto-spawn? = no` MUST also appear in `Section 3. Recommended Next Steps` so the user knows to act manually.
36
37
 
@@ -52,6 +53,7 @@ are collected and convergence finished. Phase 1-5 do not need it.
52
53
  ## Lead post-stage persistence (BLOCKING — runs after the Executor emits `### Stage Carry Evidence`)
53
54
 
54
55
  - 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`.
56
+ - The `### Stage Carry Evidence` JSON may include `designPrepEvidence[]`. Emit a row only when this stage produced concrete evidence that refines an effective PREP item: `itemId`, the injected `assessmentFingerprint`, `resolution`, and non-empty `evidence[]` are required; `overrides` is optional and only records observed, non-authoritative refinements. Carry evidence never represents user approval. Downstream resolution accepts it only from transitive dependency stages with the matching fingerprint.
55
57
  - 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).
56
58
  - 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. Append it with `okstra_ctl.consumers.append_consumer` (NOT a raw filesystem write) — that call honours the consumers lock AND releases this stage's worktree-registry occupancy, so later runs stop seeing a finished stage as a concurrent run. `report_path` lets `final-verification` cite each stage's originating report when assembling its Source Implementation Report list.
57
59
  - The verifier round, Phase 5.5 convergence, and this Phase 6 report run **once per run** over this stage's diff — NOT per step.
@@ -40,6 +40,11 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
40
40
  - load every `runs/<plan-key>/carry/stage-<i>.json` for `i ∈ depends-on(this stage)` and inject them into the executor's working context as "runtime carry-in". For a `depends-on (none)` stage, no sidecar load — task-brief only.
41
41
  - this stage's `depends-on` are all already `status:done`. Its file list, step order, Stage Validation commands, Stage Exit Contract, and rollback path are the authoritative scope.
42
42
  - **Clarification answers carried in (read before the first edit):** when `instruction-set/clarification-response.md` exists, it carries the user's answers to the approved plan's `## 1. Clarification Items` rows (the planning HTML form's `# Attached User Responses`). Treat each answer as an authoritative refinement of the plan's scope for the matching row; an answer that contradicts or expands the approved scope beyond the plan is a re-plan trigger (route to a new `implementation-planning` run), not a silent in-run change. **CLI executor (codex/antigravity):** that file sits outside the CLI sandbox, so the lead MUST transcribe its body into the dispatched executor prompt at dispatch time (same rule as the preflight / stage-discipline transcription above) — a path reference never reaches the CLI process.
43
+ - **Effective design preparation (runtime-resolved after stage selection):**
44
+
45
+ {{DESIGN_PREP_CONTEXT}}
46
+
47
+ Within the approved stage, effective user overrides are authoritative. AI proposals remain working assumptions, not user decisions. Obey every injected guardrail and `reviewAt` point. A conflict with approved scope, the selected option, or Stage Map structure stops execution and routes to a new `implementation-planning` run. Do not reread planning PREP sidecars or independently merge stale or duplicate inputs; the injected context is the stage-scoped decision.
43
48
  - inspect the current state of every file the plan names; if any file has changed materially since the plan was written, stop and route to a new `implementation-planning` run instead of editing speculatively
44
49
  - "materially changed" means: the function, class, section, or behaviour the plan targets has been edited, renamed, moved, removed, or otherwise altered in a way that invalidates the plan's reasoning. Cosmetic edits (whitespace, comment-only changes, unrelated function modifications elsewhere in the same file) do NOT trigger a re-plan; cite the diff (`git log --oneline <plan-created-at>..HEAD -- <file>`) in the final report and proceed.
45
50
  - distinguish the two file-scope rules (they are not in conflict):
@@ -12,7 +12,7 @@ at Phase 5, BEFORE constructing the verifier worker dispatch prompts.
12
12
  - **Verifier dispatch labelling.** The core functional role label is `<provider>-verifier` (here, and identically in `final-verification`). Provider, role, and model identity are owned by `prompts/lead/okstra-lead-contract.md` "Model assignments"; the selected runtime adapter owns provider-native dispatch-label mapping (including any `name` / `**Pane role:**` fields) and token-attribution wiring under its "Semantic operation mapping".
13
13
  - The verifier slots are `Claude verifier` and `Codex verifier`, plus `Antigravity verifier` **only when `antigravity` is in the resolved `--workers` roster**. Every verifier in the resolved roster is dispatched regardless of which provider holds the executor role; the executor's own provider is run *separately* as a verifier (a fresh CLI session with no shared context) so that no verdict is produced from the same session that wrote the diff. Verifiers MUST NOT call Edit, Write, or any Bash command that mutates files outside the run's artifact directories. If a verifier wants a fix, it records the recommendation in its worker result; it does not apply the fix itself.
14
14
  - Session isolation — not model-variant divergence — is the primary self-review safeguard: each verifier is a separate CLI invocation with its own context window, so reusing the same model variant for executor and same-provider verifier is acceptable. Different model variants (e.g. executor=opus / Claude verifier=sonnet) remain recommended when available.
15
- - Phase-specific model defaults override the shared defaults: `Claude verifier`=`opus`, `Codex verifier`=`gpt-5.6`, `Antigravity verifier`=`auto` (only when present in the roster). The `Executor`'s model is taken from the provider-specific worker model corresponding to `--executor`: claude→`--claude-model` (default `opus`), codex→`--codex-model` (default `gpt-5.6`), antigravity→`--antigravity-model` (default `auto`).
15
+ - Phase-specific model defaults override the shared defaults: `Claude verifier`=`opus`, `Codex verifier`=`gpt-5.6-sol`, `Antigravity verifier`=`auto` (only when present in the roster). The `Executor`'s model is taken from the provider-specific worker model corresponding to `--executor`: claude→`--claude-model` (default `opus`), codex→`--codex-model` (default `gpt-5.6-sol`), antigravity→`--antigravity-model` (default `auto`).
16
16
  - Verifiers read from the SAME working tree path the Executor used so they observe the exact diff the Executor produced. Verifiers remain strictly read-only there.
17
17
 
18
18
  ## Verifier QA duties (independent re-run mandate)
@@ -39,6 +39,8 @@
39
39
  - **Two-tier command lookup (shared with `implementation`):** when this phase performs its own independent re-validation, the command source is exactly the same two tiers `implementation` verifiers use — Tier 1 is the originating task brief / approved plan's `validation` set, Tier 2 is `<PROJECT_ROOT>/.okstra/project.json` under `qaCommands`. Auto-detecting tools from manifest files is forbidden; missing tiers are recorded as `qa-command not configured: <category>` rather than guessed. The `cmd` deny-list (`--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, `npm install` without `ci`, etc.) is enforced identically. NOTE: runtime fail-fast validation (`okstra_ctl.qa_commands.validate_qa_commands`) only fires at `--task-type implementation` run-prep, so this phase MUST self-check each `qaCommands` entry against the deny-list before executing it — if a denied token is present, skip the command and record it as a `Read-only command log` line `qa-command rejected (denied token: <token>): <label>`.
40
40
  - **Tier 3 — stage conformance scripts (whole-task union):** because this phase verifies the **integrated, merged** state, it re-runs conformance against that state rather than per-stage. Read the task-level manifest `<task_root>/qa/conformance-manifest.json` (the directory is the `TASK_QA_PATH` token) and, in **whole-task scope**, run the `runCommand` of **every** `entries[]` item against the merged worktree, refreshing each `<task_root>/qa/result-<stageKey>.json` (`{ "stageKey", "overall": "PASS"|"FAIL"|"MISSING", "ranAt", "requirements" }`). In **single-stage scope**, run only the entry whose `stageKey` matches the verified stage. An entry carrying an `exemption` or user `waiver` is NOT executed — record the skip and reason; a `waiver` becomes a `conditional-accept` condition surfaced in the section 7 Verdict (conformance left unverified by user acknowledgement). Each `runCommand` runs in the worktree cwd with `qaEnv` env (replica DB DSN / app base URL / env file) — **replica / test environment only**, never shared / staging / prod, and the same source/lockfile mutation deny-list applies (a conformance script MAY mutate only its `qaEnv` replica datastore). Interpret each result from the exit code + stdout `QA-RESULT: PASS|FAIL` (last wins) and `REQ <id>: PASS|FAIL: <reason>` lines; no `QA-RESULT` marker → `MISSING`. Any entry whose result is not `PASS` (including `MISSING` or a never-run/missing sidecar) is an **Acceptance Blocker** (`major`+). This is the same gate the `validate-run.py` Tier 3 check enforces on the result sidecars.
41
41
  - **Manual user test results**: take each item from the source implementation report's §5.7.9 Manual User Test (Draft), execute the ones reproducible in this environment (e.g. `/okstra-container-build`, which runs `okstra container up`, then the documented steps), and record `result` (`pass` / `fail` / `blocked`) + observed value in §5.8.7 (data field `finalVerification.manualUserTest`). Steps that need human-only interaction this run cannot perform are recorded as `blocked` with the reason (handed to the user), never silently skipped. A failed manual test is an Acceptance Blocker. If the draft was an exemption (`applicable=false`), reaffirm the reason in one line (`applicable=false` + `exemptionReaffirm`).
42
+ For manual testing, read only the source implementation report's `implementation.manualUserTest`. Do not execute planning `designPreparation` / `manual-user-test` PREP items directly. The implementation report has already reconciled the approved seed with the actual diff. Record reproducible results; human-only or unavailable environments become `result: blocked` with the exact reason.
43
+ - **Non-manual design-preparation handoff**: read only source implementation report `missingInformation` rows whose `source` starts with `design-prep:`. Record `ifStillOpen: block` as an acceptance blocker and `ifStillOpen: follow-up` as residual risk. This phase does not read planning PREP sidecars directly, merge their inputs, or mutate the planning snapshot.
42
44
  - **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
43
45
  - **Routing recommendation**: the next safe phase — one of `release-handoff`, `done`, `error-analysis`, `implementation-planning` — tied to the verdict and blocker list. `release-handoff` is allowed ONLY when the Verdict Token is `accepted`. `release-handoff` is additionally allowed ONLY when the verification scope (the `Verification scope:` line of the injected `VERIFICATION_TARGET` block, recorded as the report's `verificationScope` field) is `whole-task`; a `single-stage` accepted run routes to `release-handoff(stage-group)` (or `implementation` / `done`); plain `release-handoff` remains whole-task-only. Enforcement: `validators/validate-run.py` rejects a `single-stage` report whose routing cites plain `release-handoff`.
44
46
  - **Verified-row recording** (single-stage scope only): when the Verdict Token is `accepted`, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper re-validates taskType/scope/verdict from data.json, so a non-accepted or whole-task report is rejected at the tool layer.
@@ -38,12 +38,22 @@
38
38
  - feasible plan options
39
39
  - dependency and risk visibility
40
40
  - recommended execution order
41
+ - Implementation Design Preparation (`implementation-design-prep-v1`, BLOCKING):
42
+ - **Detector SSOT:** the planner MUST run the V1 detector defined by `scripts/okstra_ctl/design_surfaces.py` (`detect_design_surfaces()` over the detector's `RULES`) and MUST NOT invent or copy a second keyword list into the plan or prompt. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` reruns that detector and compares every `(stage, kind)` plus its trigger evidence.
43
+ - **Exactly-once coverage:** for every detector-produced `(stage, kind)`, the planner MUST write exactly one `designSurfaceCoverage` row on that stage. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` rejects missing, duplicate, extra-detector-kind, or evidence-mismatched rows; `schemas/final-report-v1.0.schema.json` `$defs.DesignSurfaceCoverage` enforces the row shape.
44
+ - **Disposition:** a row MUST use `inline-contract` only when the stage already states the kind-specific minimum implementation contract; otherwise it MUST use `prep-item` and reference one or more `designPreparation.items`. `not-applicable` is legal only with a concrete rationale consistent with the stage action. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignSurfaceCoverage` enforces the disposition-specific fields, and `prompts/lead/plan-body-verification.md` `P-Prep-S<stage>-<kind>` verifies semantic sufficiency.
45
+ - **AI-prepared proposal:** every referenced PREP item MUST record `kind`, `stageRefs`, `need`, evidence-cited `knownFacts`, `openQuestions`, a concrete evidence-backed `aiProposal` (`summary`, `details`, `assumptions`, `evidence`, `confidence`), `humanConfirmation`, explicit `status`, and the safest reversible default available. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPrepItem` / `$defs.DesignPrepProposal` enforce required fields, `validators/validate-run.py` `_validate_prep_references` enforces the bidirectional stage/kind link, and `prompts/lead/plan-body-verification.md` rejects empty or non-implementable proposals.
46
+ - **Status choice:** prefer `provisional` with a `workingAssumption`, concrete `guardrails`, `reviewAt`, `ifStillOpen`, and canonical `requestPath`; use `blocked` only for business policy, external authority, a destructive migration decision, or the absence of any safe reversible assumption. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPrepItem` enforces state-specific fields, `validators/validate-run.py` `_validate_design_prep_states` enforces confirmation/request invariants, and `prompts/lead/plan-body-verification.md` judges whether the disposition is justified. A declared `blocked` status does not by itself fail plan-body verification.
47
+ - **Planner-only test surface:** add `manual-user-test` only when a test prerequisite changes the implementation interface or acceptance contract; the V1 detector never emits it. **Enforced:** `validators/validate-run.py` `_validate_detector_coverage` rejects detector-produced `manual-user-test`, `schemas/final-report-v1.0.schema.json` permits its planner-authored shape, and `prompts/lead/plan-body-verification.md` verifies the stage-action rationale.
48
+ - **Trivial task:** when the detector returns no surfaces and no interface/acceptance-changing manual test input exists, `designPreparation` MUST use `mode: no-design-inputs`, an empty `items` array, and a concrete reason tied to the plan. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.DesignPreparation` requires the reason and empty array for that mode; `validators/validate-run.py` `_validate_design_prep_contract` validates the marked V1 payload.
41
49
  - Approval gate (phase-specific addendum to shared authority rule):
42
50
  - The YAML frontmatter `approved: true|false` field is the only authorised approval gate. report-writer always emits `approved: false`. The user clears it either by (a) editing the frontmatter line to `approved: true` directly, or (b) invoking the next phase with `--approve` so the CLI flips the frontmatter on the user's behalf. `okstra_ctl.run._validate_approved_plan` reads this field and refuses entry until it is `true`.
43
51
  - Cross-verification mode:
44
52
  - Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / option) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode".
45
53
  - §5.5.9 plan-body verification runs with an **adversarial posture** (`prompts/lead/plan-body-verification.md` §"Adversarial plan-body posture"): verifiers open and confirm every cited path / command and put the burden of proof on the plan. The gate threshold is majority-based for kinds `b`/`c`/`e`, but a single `DISAGREE` blocks on its own for the concrete, safety-critical kinds `a` (path/symbol mismatch) / `d` (rollback order) — and `f` on `P-Req-*` items. A majority also needs ≥2 participating votes, so a lone dissent whose peer returned a non-result does not block on a majority-gated kind (see that contract's §"Adversarial plan-body posture").
46
54
  - **Incremental re-verification scope (clarification re-runs):** when the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), workers re-analyze ONLY the stages listed in `reverify_stages` (the downstream closure of the impacted stages). Workers MUST NOT re-open, re-score, or re-judge any stage in `carry_stages` — those stages' prior plan-item verdicts are carried forward verbatim, and a worker never overwrites a carried verdict with its own judgement. When the decision is `mode == "full"` (the default), every stage is re-analyzed as usual.
55
+ - **Single incremental-scope decision:** the lead calls `okstra incremental-scope` exactly once for the re-run, passing answered-clarification stage impacts through `--impacted` and changed design-preparation IDs through `--prep-items`; the CLI unions their `stageRefs` before applying the existing dependency closure and cutoff. An answer that changes the selected option, Stage Map, or recommended approach is not a local impact: pass both CSVs empty so the same call returns `mode == "full"`. Unknown PREP IDs or invalid `stageRefs` also return an explicit full decision instead of being guessed.
56
+ - **Stage-aware carry:** for an incremental decision, pass its `carry_stages` and `reverify_stages` CSVs unchanged to `okstra incremental-carry`. The helper carries the prior whole stage rows and their owned PREP / `P-Prep-*` artifacts; overlap, cross-scope ownership, scope leaks, or canonical conflicts return `CarryError`. On that error, discard the partial merge and run full re-verification.
47
57
  {{INCLUDE:_coverage-critic.md}}
48
58
  - Non-goals:
49
59
  - code-level micro-optimization unless it changes the implementation approach
@@ -56,7 +66,7 @@
56
66
  {{INCLUDE:_clarification-recommendation.md}}
57
67
  - **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only a human can answer this" (reporter intent, business priority, organisational decision). A row with `none` that *could* have been answered by the codebase is a defect of this phase, restated from the pre-planning rule above.
58
68
  - Section heading contract (BLOCKING — validator scans for these literal English substrings):
59
- - 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`, `Cross-Project Dependencies`, `Decision Drafts`, `Validation Checklist`, `Rollback`, `Requirement Coverage`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.)
69
+ - 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`, `Cross-Project Dependencies`, `Decision Drafts`, `Validation Checklist`, `Rollback`, `Requirement Coverage`, `Implementation Design Preparation`. (Approval is no longer a body section — it is the YAML frontmatter `approved` field.) `validators/validate-run.py` enforces the planning headings it scans, while `schemas/final-report-v1.0.schema.json` plus `templates/reports/final-report.template.md` enforce and render the design-preparation heading from its required data block.
60
70
  - Korean translations are allowed in parentheses (e.g. `### Recommended Option (권장 옵션)`), but the English keyword must be present verbatim in the heading line.
61
71
  - The shape and ordering follow `final-report-template.md` sections 5.4 (`Implementation Plan Deliverables`) + 5.5 (`Stage Map`). `validators/validate-run.py` substring-matches the raw report text, so a Korean-only heading fails the gate — the cause of repeated observed failures.
62
72
  - 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 — not deferred to the `implementation` entry gate. It enforces: 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 (≤8), the `depends-on` DAG, and the per-stage vertical-slice contract (S10). S10 scans for the literal in-section strings `Slice value:`, `Acceptance:`, the three `Test case (success):` / `Test case (boundary):` / `Test case (failure):` lines (S10d), and the Stepwise `action`-cell prefixes `RED:` / `GREEN:` (or a `TDD exemption:` line, which waives both the test-case lines and the RED/GREEN check) — keep these tokens verbatim for the same reason as the heading keywords above.
@@ -233,6 +233,50 @@
233
233
  "unknown_option": "보고서에서 내보낸 승인 기록의 옵션 `{option}` 이 plan 의 Option Candidates 에 없습니다. 유효 후보: {candidates}. 보고서에서 다시 내보내거나 '예 — 승인만' 을 선택하세요."
234
234
  }
235
235
  },
236
+ "design_prep_decision": {
237
+ "label": "설계 준비 항목 {item_id} — {title}\n대상 stage: {stage_refs}\n\nAI 초안\n- 요약: {proposal_summary}\n- 상세: {details}\n- 가정: {assumptions}\n- 가드레일: {guardrails}\n- 요청 문서: {request_path}\n\n이 초안을 어떻게 처리할까요?",
238
+ "echo_template": "design-prep decision: {value}",
239
+ "options": {
240
+ "accept-draft": "AI 초안 수락",
241
+ "modify-draft": "AI 초안 수정",
242
+ "reject-draft": "AI 초안 거절",
243
+ "later": "나중에 결정"
244
+ },
245
+ "echo_variants": {
246
+ "later": "design-prep {item_id}: 나중에 결정 — 입력 파일을 만들지 않음"
247
+ },
248
+ "errors": {
249
+ "invalid_decision": "설계 준비 결정은 accept-draft, modify-draft, reject-draft, later 중 하나여야 합니다."
250
+ }
251
+ },
252
+ "design_prep_overrides": {
253
+ "label": "설계 준비 항목 {item_id}의 {decision} 내용을 입력하세요. modify-draft는 JSON 객체, reject-draft는 거절 사유를 입력합니다.",
254
+ "echo_template": "design-prep details: {value}",
255
+ "echo_variants": {
256
+ "overrides": "design-prep overrides: JSON 객체 확인됨",
257
+ "note": "design-prep rejection note: 확인됨"
258
+ },
259
+ "errors": {
260
+ "invalid_json": "수정 내용이 올바른 JSON이 아닙니다: {error}",
261
+ "object_required": "수정 내용은 JSON 객체여야 합니다.",
262
+ "note_required": "reject-draft에는 비어 있지 않은 note가 필요합니다."
263
+ }
264
+ },
265
+ "design_prep_confirm": {
266
+ "label": "설계 준비 입력을 저장하기 전 의미 내용을 확인하세요.\n\nitem: {item_id}\ndecision: {decision}\noverrides: {overrides}\nnotes: {notes}\n\n승인된 스냅샷의 모든 의미 필드:\n{item_snapshot}\n\nrevision / input-id / created-at은 확정 후 원자적으로 할당됩니다.",
267
+ "echo_template": "design-prep confirm: {value}",
268
+ "options": {
269
+ "yes": "예 — 이 의미 내용으로 입력 파일 생성",
270
+ "no": "아니오 — 결정 화면으로 돌아가기"
271
+ },
272
+ "echo_variants": {
273
+ "revise": "design-prep {item_id}: 저장하지 않고 결정 화면으로 돌아감",
274
+ "written": "design-prep {item_id}: revision {revision}, input-id {input_id}, path {path}"
275
+ },
276
+ "errors": {
277
+ "confirmation_required": "설계 준비 입력 저장은 yes 또는 no로 확인해야 합니다."
278
+ }
279
+ },
236
280
  "stage_pick": {
237
281
  "label": "진행할 stage 를 선택하세요(여러 개 선택 가능). '전체' 는 남은 미완료 stage 를 모두, 개별 선택 시 의존하는 미완료 stage 가 자동 포함됩니다.",
238
282
  "label_final_verification": "검증할 implementation stage 를 선택하세요.",
@@ -452,7 +452,11 @@ def _render_missing_analysis_worker_prompt(
452
452
  lines.extend(_worktree_headers(manifest, active_context, role))
453
453
  lines.extend(_analysis_prompt_body(manifest, active_context, worker_id, model, role))
454
454
  executor_tail = _implementation_executor_tail(
455
- manifest, workspace_root, role
455
+ manifest,
456
+ active_context,
457
+ project_root,
458
+ workspace_root,
459
+ role,
456
460
  )
457
461
  if executor_tail:
458
462
  lines.extend(["", executor_tail.rstrip()])
@@ -806,6 +810,8 @@ def _worktree_headers(
806
810
 
807
811
  def _implementation_executor_tail(
808
812
  manifest: Mapping[str, Any],
813
+ active_context: Mapping[str, Any],
814
+ project_root: Path,
809
815
  workspace_root: Path,
810
816
  role: str,
811
817
  ) -> str:
@@ -813,6 +819,22 @@ def _implementation_executor_tail(
813
819
  return ""
814
820
  profiles = workspace_root / "prompts" / "profiles"
815
821
  parts: list[str] = []
822
+ analysis_profile = _instruction_path(
823
+ manifest,
824
+ active_context,
825
+ "analysisProfilePath",
826
+ )
827
+ if not analysis_profile:
828
+ raise DispatchError("implementation executor profile path is missing")
829
+ executor_profile = (
830
+ _resolve_project_path(project_root, analysis_profile).parent
831
+ / "implementation-executor.md"
832
+ )
833
+ if not executor_profile.is_file():
834
+ raise DispatchError(
835
+ f"resolved implementation executor profile not found: {executor_profile}"
836
+ )
837
+ parts.append(executor_profile.read_text(encoding="utf-8"))
816
838
  preflight_path = profiles / "_coding-conventions-preflight.md"
817
839
  if preflight_path.is_file():
818
840
  parts.append(preflight_path.read_text(encoding="utf-8"))