okstra 0.122.0 → 0.124.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 (108) hide show
  1. package/README.md +5 -2
  2. package/docs/architecture/storage-model.md +15 -1
  3. package/docs/architecture.md +45 -7
  4. package/docs/cli.md +47 -5
  5. package/docs/for-ai/README.md +42 -36
  6. package/docs/for-ai/skills/okstra-brief-gen.md +105 -105
  7. package/docs/for-ai/skills/okstra-container-build.md +61 -61
  8. package/docs/for-ai/skills/okstra-graphify.md +64 -0
  9. package/docs/for-ai/skills/okstra-inspect.md +86 -86
  10. package/docs/for-ai/skills/okstra-manager.md +32 -32
  11. package/docs/for-ai/skills/okstra-memory.md +49 -50
  12. package/docs/for-ai/skills/okstra-pr-gen.md +48 -0
  13. package/docs/for-ai/skills/okstra-rollup.md +58 -58
  14. package/docs/for-ai/skills/okstra-run.md +95 -95
  15. package/docs/for-ai/skills/okstra-schedule-gen.md +320 -0
  16. package/docs/for-ai/skills/okstra-setup.md +63 -64
  17. package/docs/for-ai/skills/okstra-user-response.md +48 -0
  18. package/docs/performance-improvement-plan-v2.md +4 -4
  19. package/docs/pr-template-usage.md +34 -34
  20. package/docs/project-structure-overview.md +92 -70
  21. package/docs/task-process/README.md +33 -33
  22. package/docs/task-process/common-flow.md +26 -26
  23. package/docs/task-process/error-analysis.md +20 -21
  24. package/docs/task-process/final-verification.md +41 -41
  25. package/docs/task-process/implementation-planning.md +52 -28
  26. package/docs/task-process/implementation.md +51 -32
  27. package/docs/task-process/release-handoff.md +46 -46
  28. package/docs/task-process/requirements-discovery.md +22 -23
  29. package/package.json +1 -1
  30. package/runtime/BUILD.json +2 -2
  31. package/runtime/agents/workers/antigravity-worker.md +4 -4
  32. package/runtime/agents/workers/claude-worker.md +2 -2
  33. package/runtime/agents/workers/codex-worker.md +4 -4
  34. package/runtime/agents/workers/report-writer-worker.md +4 -4
  35. package/runtime/bin/lib/okstra/usage.sh +3 -3
  36. package/runtime/prompts/coding-preflight/frameworks/node-server.md +1 -1
  37. package/runtime/prompts/launch.template.md +6 -3
  38. package/runtime/prompts/lead/convergence.md +11 -21
  39. package/runtime/prompts/lead/okstra-lead-contract.md +16 -18
  40. package/runtime/prompts/lead/plan-body-verification.md +47 -18
  41. package/runtime/prompts/lead/report-writer.md +50 -45
  42. package/runtime/prompts/lead/team-contract.md +11 -122
  43. package/runtime/prompts/profiles/_common-contract.md +15 -22
  44. package/runtime/prompts/profiles/_implementation-deliverable.md +4 -2
  45. package/runtime/prompts/profiles/_implementation-executor.md +6 -1
  46. package/runtime/prompts/profiles/_implementation-verifier.md +3 -3
  47. package/runtime/prompts/profiles/error-analysis.md +2 -2
  48. package/runtime/prompts/profiles/final-verification.md +3 -1
  49. package/runtime/prompts/profiles/implementation-planning.md +24 -14
  50. package/runtime/prompts/profiles/implementation.md +1 -1
  51. package/runtime/prompts/profiles/improvement-discovery.md +1 -1
  52. package/runtime/prompts/profiles/release-handoff.md +3 -3
  53. package/runtime/prompts/profiles/requirements-discovery.md +18 -18
  54. package/runtime/prompts/wizard/prompts.ko.json +44 -0
  55. package/runtime/python/okstra_ctl/codex_dispatch.py +23 -1
  56. package/runtime/python/okstra_ctl/design_prep.py +1462 -0
  57. package/runtime/python/okstra_ctl/design_surfaces.py +243 -0
  58. package/runtime/python/okstra_ctl/final_report_schema.py +33 -1
  59. package/runtime/python/okstra_ctl/implementation_stage.py +35 -0
  60. package/runtime/python/okstra_ctl/incremental_carry.py +294 -21
  61. package/runtime/python/okstra_ctl/incremental_scope.py +51 -5
  62. package/runtime/python/okstra_ctl/material.py +1 -1
  63. package/runtime/python/okstra_ctl/model_discovery.py +98 -0
  64. package/runtime/python/okstra_ctl/models.py +8 -3
  65. package/runtime/python/okstra_ctl/render.py +5 -0
  66. package/runtime/python/okstra_ctl/run.py +53 -5
  67. package/runtime/python/okstra_ctl/user_response.py +67 -2
  68. package/runtime/python/okstra_ctl/wizard.py +283 -3
  69. package/runtime/python/okstra_token_usage/report.py +11 -0
  70. package/runtime/schemas/final-report-v1.0.schema.json +336 -0
  71. package/runtime/skills/_fragments/bash-invocation-rule.md +1 -0
  72. package/runtime/skills/_fragments/preflight-outdated-cli.md +1 -0
  73. package/runtime/skills/_fragments/python-bootstrap-note.md +1 -0
  74. package/runtime/skills/okstra-brief-gen/SKILL.md +117 -122
  75. package/runtime/skills/okstra-container-build/SKILL.md +24 -14
  76. package/runtime/skills/okstra-graphify/SKILL.md +12 -4
  77. package/runtime/skills/okstra-inspect/SKILL.md +105 -99
  78. package/runtime/skills/okstra-manager/SKILL.md +1 -1
  79. package/runtime/skills/okstra-memory/SKILL.md +3 -3
  80. package/runtime/skills/okstra-rollup/SKILL.md +12 -6
  81. package/runtime/skills/okstra-run/SKILL.md +49 -88
  82. package/runtime/skills/{okstra-schedule → okstra-schedule-gen}/SKILL.md +38 -32
  83. package/runtime/skills/okstra-setup/SKILL.md +1 -1
  84. package/runtime/skills/okstra-setup/references/project-config.md +17 -16
  85. package/runtime/skills/okstra-usage/SKILL.md +5 -2
  86. package/runtime/skills/okstra-user-response/SKILL.md +23 -9
  87. package/runtime/templates/prd/brief.template.md +92 -92
  88. package/runtime/templates/reports/error-analysis-input.template.md +1 -1
  89. package/runtime/templates/reports/fan-out-unit.template.md +6 -6
  90. package/runtime/templates/reports/final-report.template.md +67 -0
  91. package/runtime/templates/reports/final-verification-input.template.md +6 -6
  92. package/runtime/templates/reports/i18n/en.json +31 -0
  93. package/runtime/templates/reports/i18n/ko.json +31 -0
  94. package/runtime/templates/reports/implementation-input.template.md +1 -1
  95. package/runtime/templates/reports/implementation-planning-input.template.md +1 -1
  96. package/runtime/templates/reports/improvement-discovery-input.template.md +1 -1
  97. package/runtime/templates/reports/quick-input.template.md +1 -1
  98. package/runtime/templates/reports/release-handoff-input.template.md +1 -1
  99. package/runtime/templates/reports/schedule.template.md +22 -22
  100. package/runtime/templates/reports/task-brief.template.md +3 -3
  101. package/runtime/templates/reports/user-response.template.md +20 -20
  102. package/runtime/templates/worker-prompt-preamble.md +111 -13
  103. package/runtime/validators/validate-run.py +426 -5
  104. package/runtime/validators/validate-schedule.py +5 -5
  105. package/src/cli-registry.mjs +7 -0
  106. package/src/commands/inspect/design-prep.mjs +23 -0
  107. package/src/lib/skill-catalog.mjs +2 -1
  108. package/docs/for-ai/skills/okstra-schedule.md +0 -320
@@ -75,7 +75,7 @@ For the report writer specifically, the `## Inputs` list always includes:
75
75
 
76
76
  For the carry-in `clarification-response.md` (if present), walk every row of `## 1. Clarification Items` including rows whose `User input` cell is blank — a blank cell with `Status=open` is a signal you must surface in the conditional `## 0. Clarification Response Carried In From Previous Run` section (the template's `RENDER_IF` guard activates it when the carry-in path is non-empty). When no carry-in path was provided, OMIT the `## 0.` heading entirely — do NOT write an empty-state stub.
77
77
 
78
- Write a Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md`. The main final-report and the main worker-results file MUST NOT contain a `## 0. Reading Confirmation` heading. If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating the report.
78
+ Write a Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md`, per the worker preamble §"Reading rules" (canonical — the main final-report and worker-results files carry no Section 0 heading). If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating the report.
79
79
 
80
80
  ## Authoring Contract
81
81
 
@@ -90,9 +90,9 @@ Rules (the schema enforces most of these — they are listed here so you know *w
90
90
  - **Verdict Card consistency.** `verdictCard.verdictToken` / `.direction` / `.nextStep` MUST byte-match `finalVerdict.verdictToken` / `.direction` / `.nextStep` and `recommendedNextSteps[0].text`. The renderer pulls both from the same data structure — duplicating values across `verdictCard` and `finalVerdict` is intentional so the validator can diff them.
91
91
  - **Reader Summary.** Populate `readerSummary` when the schema excerpt exposes it. It is the human-first entrypoint for both Markdown and HTML: one sentence for the decision, one for the human action required, one for blockers, one for audit sections safe to skip on first read, and one runnable recommended command. Do not duplicate raw evidence tables here.
92
92
  - **§7 phase-continuation row (mandatory for non-terminal task-types).** When `header.taskType` is one of `requirements-discovery` / `implementation-planning` / `error-analysis` / `implementation` / `final-verification`, `followUpTasks` MUST contain at least one row whose `origin` is `phase-continuation`, `suggestedTaskType` equals the next phase (byte-identical to `finalVerdict.nextStep`'s referenced phase), `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. Schema `allOf` clause enforces this via `contains`.
93
- - **No deprecated sections.** The schema has no `4.5.8 User Approval Request` body field, no `4.5.9 Open Questions`, no `5.1 추가 자료 요청`, no `5.2 사용자 확인 질문` — clarifications go under the unified `clarificationItems[]` array.
93
+ - **No deprecated sections.** The schema has no `4.5.8 User Approval Request` body field, no `4.5.9 Open Questions`, no `5.1 Additional Material Request`, no `5.2 User Confirmation Questions` — clarifications go under the unified `clarificationItems[]` array.
94
94
  - **Optional Section 0.** Include `clarificationCarryIn` ONLY when the lead's prompt provides a non-empty carry-in path. Omit the key entirely otherwise (do NOT set it to `null` or an empty object).
95
- - **Reading Confirmation** lives in the audit sidecar (`runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md`), never in the data.json or the main worker-results file.
95
+ - **Reading Confirmation** goes in the audit sidecar per the preamble §"Reading rules" — never in the data.json or the main worker-results file.
96
96
  - Include all four convergence categories. The schema's `crossVerification.consensus` / `.differences` arrays carry full / partial / contested / worker-unique items; do not omit any.
97
97
  - Convergence round history goes in `crossVerification.roundHistory.rounds[]` with `round2SkippedReason`. When convergence is disabled, set `crossVerification.roundHistory` to `{"disabled": true}`. Values come verbatim from `state/convergence-<task-type>-<seq>.json` — do not recompute.
98
98
  - `verification-error` votes are their own verdict (`planItems[].verdicts[].verdict` enum); they are NOT folded into AGREE / DISAGREE counts.
@@ -105,7 +105,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
105
105
  - For `implementation-planning`, also populate `implementationPlanning.decisionDrafts` (one row per decision meeting all three decision-record criteria; `[]` otherwise) and `implementationPlanning.skippedAdrCandidates` (evaluated-but-dropped adr-candidates; `[]` otherwise). The schema excerpt enumerates the row shape; the renderer emits §5.4 `### Decision Drafts`. When `decisionDrafts` is non-empty, the plan's stages MUST carry a stepwise step that creates `.okstra/decisions/<NNNN>-<slug>.md` (validate-run gates this).
106
106
  - When the `Task Type` is `improvement-discovery`, populate `## 5.9 Improvement Candidates` with the 10-column schema enforced by `validators/validate_improvement_report.py`. Source the row IDs (`I-NNN`), lens whitelist, and Source workers patterns from `scripts/okstra_ctl/improvement_lenses.py` — do NOT introduce new lens names or worker prefixes. `improvement-discovery` is NOT in the data.json schema enum, so author its markdown directly (not via `okstra-render-final-report.py`). Immediately after writing the markdown, run (`Bash`): `okstra inject-report-index <markdown path> --report-language <en|ko>`. That adds the top-of-report Index plus `I-NNN` / `C-NNN` scroll anchors; the run validator fails the report when the Index anchor is absent.
107
107
 
108
- Write the data.json (and the audit sidecar `.md`) with your `Write` tool — that is the canonical authoring path, and okstra ships no hook that blocks `.md` writes (its only settings hook is the `SessionEnd` trace-cleanup; the coding-preflight hook emits reminders but never blocks). A Bash heredoc is acceptable ONLY when a specific `Write` call is genuinely rejected by the host environment, and it MUST produce byte-identical content — do not reach for it pre-emptively. Then invoke the renderer (`Bash`): `okstra render-final-report <data.json path>`. Confirm both files exist and respond with a short status line prefixed by your model identity, copied verbatim from the `**Model:** Report writer worker, <modelExecutionValue>` line in your dispatch prompt (per Worker Preamble → "Return message to the lead"):
108
+ Write the data.json (and the audit sidecar `.md`) with your `Write` tool — that is the canonical authoring path, and okstra ships no hook that blocks `.md` writes (its only settings hook is the `SessionEnd` trace-cleanup; the coding-preflight hook emits reminders but never blocks). A Bash heredoc is acceptable ONLY when a specific `Write` call is genuinely rejected by the host environment, and it MUST produce byte-identical content — do not reach for it pre-emptively. Then invoke the renderer (`Bash`): `okstra render-final-report <data.json path>`. Confirm both files exist and respond with a short status line prefixed by your model identity, per the preamble §"Return message to the lead":
109
109
 
110
110
  ```
111
111
  **Model:** Report writer worker, <modelExecutionValue>
@@ -29,7 +29,7 @@ optional arguments:
29
29
  (1) ancestor of cwd that contains .okstra/project.json,
30
30
  (2) \`git rev-parse --show-toplevel\` from cwd. Errors out if neither resolves.
31
31
  --directive Free-form user-supplied directive carried into the run as a "## Directive" section
32
- inside instruction-set/analysis-material.md. Lead, workers, and skills (e.g. okstra-schedule)
32
+ inside instruction-set/analysis-material.md. Lead, workers, and skills (e.g. okstra-schedule-gen)
33
33
  may treat this as a hard hint that overrides default heuristics. Use to express intent
34
34
  like "render a Gantt even with single XL task" or "emphasize rollout risk".
35
35
  --fix-cycle <yes|no> When re-entering an entry phase (requirements-discovery / error-analysis /
@@ -90,7 +90,7 @@ options:
90
90
  (Antigravity worker is optional; add \`antigravity\` explicitly, e.g. --workers claude,codex,antigravity,report-writer)
91
91
  --lead-model Model for Claude lead. Default: OKSTRA_DEFAULT_LEAD_MODEL or opus
92
92
  --claude-model Model for Claude worker. Default: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
93
- --codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6
93
+ --codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6-sol
94
94
  --antigravity-model Model for Antigravity worker. Default: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
95
95
  --report-writer-model
96
96
  Model for report writer worker. Default: OKSTRA_DEFAULT_REPORT_WRITER_MODEL or lead model default
@@ -124,7 +124,7 @@ model defaults:
124
124
  Claude lead: OKSTRA_DEFAULT_LEAD_MODEL or opus
125
125
  Report writer worker: OKSTRA_DEFAULT_REPORT_WRITER_MODEL or Claude lead default
126
126
  Claude worker: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
127
- Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6
127
+ Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6-sol
128
128
  Antigravity worker: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
129
129
  Implementation executor: OKSTRA_DEFAULT_EXECUTOR or claude (one of: claude | codex | antigravity)
130
130
 
@@ -1,6 +1,6 @@
1
1
  # Node.js Conventions (server-side)
2
2
 
3
- Load this **in addition to** [javascript-typescript.md](javascript-typescript.md). JS / TS rules still apply; this file adds the server-specific layer.
3
+ Load this **in addition to** [javascript-typescript.md](../languages/javascript-typescript.md). JS / TS rules still apply; this file adds the server-specific layer.
4
4
 
5
5
  ## Architecture
6
6
 
@@ -14,7 +14,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
14
14
  {{PHASE_ALLOWED_OUTPUTS}}
15
15
  - Forbidden actions in this phase:
16
16
  {{PHASE_FORBIDDEN_ACTIONS}}
17
- - This run executes `{{WORKFLOW_CURRENT_PHASE}}` only. Do not start `{{WORKFLOW_NEXT_RECOMMENDED_PHASE}}` or any later phase inside this run, even if the user says "다음 단계 진행해" or similar.
17
+ - This run executes `{{WORKFLOW_CURRENT_PHASE}}` only. Do not start `{{WORKFLOW_NEXT_RECOMMENDED_PHASE}}` or any later phase inside this run, even if the user says "proceed to the next step" or similar.
18
18
  {{STAGE_BATCH_DIRECTIVE}}
19
19
  {{VERIFICATION_TARGET}}
20
20
  {{STAGE_INTEGRATION}}
@@ -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.
@@ -22,7 +22,7 @@
22
22
 
23
23
  ## Scope and Terminology (BLOCKING)
24
24
 
25
- This contract governs **Phase 5.5 (Convergence loop)** — a *lead operating phase* inside a single okstra run, not a task-type lifecycle phase. The 6 task-type lifecycle phases (`requirements-discovery` → `error-analysis` → `implementation-planning` → `implementation` → `final-verification` → `release-handoff`, see [okstra-lead-contract](./okstra-lead-contract.md) "Lifecycle Phase Boundaries") are unchanged by this contract. The lead operating phases (Phase 1 Intake → Phase 7 Persist, see [okstra-lead-contract](./okstra-lead-contract.md) "Quick Reference") describe how the lead drives a *single* task-type run.
25
+ This contract governs **Phase 5.5 (Convergence loop)** — a *lead operating phase* inside a single okstra run, not a task-type lifecycle phase. It leaves the 6 task-type lifecycle phases (`requirements-discovery` → `error-analysis` → `implementation-planning` → `implementation` → `final-verification` → `release-handoff`, see [okstra-lead-contract](./okstra-lead-contract.md) "Lifecycle Phase Boundaries") unchanged; the lead operating phases (Phase 1 Intake → Phase 7 Persist, see [okstra-lead-contract](./okstra-lead-contract.md) "Quick Reference") drive a *single* task-type run.
26
26
 
27
27
  **`contested` is a final classification only.** It is NEVER an intermediate queue label. The verification queue carries findings that are *unique to a single worker* (entered in Round 0) or *mixed/unresolved after a re-verification round* (carried forward). The `contested` label is assigned only when the **last executed round** completes and the queue is still non-empty.
28
28
 
@@ -30,9 +30,8 @@ When this contract says "queue" without qualifier, it means the *verification qu
30
30
 
31
31
  ## When to Use
32
32
 
33
- - When okstra lead Phase 5.5 (convergence loop) begins
34
- - Immediately after all workers have completed Phases 4 and 5
35
- - When findings need to be systematically classified by consensus level
33
+ - When okstra lead Phase 5.5 (convergence loop) begins — immediately after all workers complete Phases 4 and 5
34
+ - When findings need systematic classification by consensus level
36
35
 
37
36
  ## Configuration
38
37
 
@@ -64,7 +63,7 @@ Configure this in the `convergence` block of `task-manifest.json`. If the block
64
63
 
65
64
  Read the worker result files generated in Phase 4/5 and extract individual findings.
66
65
 
67
- **Convergence scope.** Convergence operates on sections 1–5 of the worker output (the common core, see `team-contract` "Worker Output Contract"). Section 6 ("Specialization Lens") is additive worker-specific depth and MUST NOT be fed into the consensus grouping, the verification queue, or the round-N reverify prompts. Carry Section 6 forward into the final report verbatim through the report-writer worker — do not let it inflate `unique` counts or trigger spurious `verification-error` statuses.
66
+ **Convergence scope.** Convergence operates on sections 1–5 of the worker output (the common core, see the worker preamble §"Worker output sections"). Section 6 ("Specialization Lens") is additive worker-specific depth and MUST NOT be fed into the consensus grouping, the verification queue, or the round-N reverify prompts. Carry Section 6 forward into the final report verbatim through the report-writer worker — do not let it inflate `unique` counts or trigger spurious `verification-error` statuses.
68
67
 
69
68
  **Incremental re-verification scope (implementation-planning clarification re-runs).** When the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), only findings the lead attributes to a stage in `reverify_stages` enter the verification queue. Findings and plan-item verdicts carried forward for `carry_stages` are NOT re-queued — they skip the re-verification rounds entirely and are merged verbatim into this run's data.json via `okstra incremental-carry`. When the decision is `mode == "full"` (the default), every finding enters the queue as usual.
70
69
 
@@ -73,7 +72,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
73
72
  - For bullet/numbered findings, parse `[TICKETID: <id>]` from the item title.
74
73
  - Items with multiple tickets (e.g. `TICKET-123, TICKET-456`) expand to a set of ticket keys.
75
74
  - Items tagged `unknown` keep the literal `unknown` as their ticket key.
76
- 2. For each finding, record the summary, evidence (file path, line number, basis), the worker who identified it, **the worker-internal item ID assigned by that worker** (e.g. `F-001`, `1.1`, `F-3` — see `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT), and the parsed ticket set. The item ID is persisted on the finding record as `findings[].discoveredBy.<worker>.itemId` and on each cross-worker confirmation as `findings[].sourceItems[]` (one entry per contributing `<worker>:<item-id>` pair). The final-report's `## 6.1 Consensus` / `## 6.2 Differences` / `## 2.1 Primary Evidence` tables read this list verbatim into their `Source items` columns — without this, the synthesised `C-NNN` row has no traceable link back to the original worker wording.
75
+ 2. For each finding, record the summary, evidence (file path, line number, basis), the discovering worker, **the worker-internal item ID that worker assigned** (e.g. `F-001`, `1.1`, `F-3` — see `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT), and the parsed ticket set. Persist the item ID as `findings[].discoveredBy.<worker>.itemId` and each cross-worker confirmation as `findings[].sourceItems[]` (one entry per contributing `<worker>:<item-id>` pair). The final-report `## 6.1 Consensus` / `## 6.2 Differences` / `## 2.1 Primary Evidence` tables read this verbatim into their `Source items` columns; without it the synthesised `C-NNN` row loses its link back to the original worker wording.
77
76
  3. The lead groups findings based on semantic similarity AND ticket-set equality:
78
77
  - Same semantics + same ticket set across 2+ workers → immediately reach `full consensus`.
79
78
  - Same semantics but disjoint ticket sets → keep as separate groups (do NOT over-merge across tickets).
@@ -180,23 +179,15 @@ The exit conditions and final-classification rules are defined by the §"Converg
180
179
 
181
180
  ### Lightweight (Default)
182
181
 
183
- Decisions are made based solely on the findings and evidence presented by other reviewers. The original code or data is not reanalyzed.
184
-
185
- Advantages: Fast and cost-effective
186
- Disadvantages: Accuracy decreases if evidence is insufficient
182
+ Decide solely on the findings and evidence other reviewers present; do not reanalyze the original code or data. Fast and cost-effective, but accuracy drops when evidence is insufficient.
187
183
 
188
184
  ### Full Re-analysis (opt-in)
189
185
 
190
- Use the findings as a guide, but reanalyze the original code/data yourself.
191
-
192
- Advantages: High accuracy
193
- Disadvantages: 2–3 times the cost, increased time
186
+ Use each finding as a guide but reanalyze the original code/data yourself. High accuracy at 2–3× the cost and time.
194
187
 
195
188
  ## Adversarial Verification Mode
196
189
 
197
- Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, and `implementation-planning`; see §"Configuration"). When `false`, every rule in this section is inert and the collaborative behaviour documented elsewhere in this contract applies unchanged.
198
-
199
- In adversarial mode the verifier's job inverts: instead of confirming a peer's finding, the verifier **tries to break it**, and the burden of proof sits on the claim — a finding survives only if refutation attempts fail.
190
+ Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, and `implementation-planning`; see §"Configuration"); when `false`, every rule in this section is inert and the collaborative behaviour elsewhere in this contract applies unchanged. In adversarial mode the verifier's job inverts: instead of confirming a peer's finding, the verifier **tries to break it**, and the burden of proof sits on the claim — a finding survives only if refutation attempts fail.
200
191
 
201
192
  ### Scoped full-reanalysis
202
193
 
@@ -246,7 +237,7 @@ ELSE:
246
237
 
247
238
  `contested` remains a **final classification only** (per §"Scope and Terminology"): a disputed finding is carried forward through intermediate rounds and labelled `contested` only at the last executed round. For `requirements-discovery` (`effectiveMaxRounds = 1`) the single round IS the last round, so a split-with-hard-refute finding is labelled `contested` in that one round. The final-classifier block of §"Convergence Algorithm" is unchanged; this section only changes how each round's verdicts resolve into queue actions.
248
239
 
249
- Design intent: one `counter-evidence` refute is enough to deny a claim consensus (it cannot rise above `contested` no matter how many others AGREE), while a single `burden-not-met` doubt does not by itself sink an otherwise-surviving claim — only a majority of burden-not-met doubts does. When every non-discoverer refutes (all_others_disagree), the finding is worker-unique regardless of whether those refutes were counter-evidence or burden-not-met — only the discoverer still holds it. A SUPPLEMENT/caveat with zero disagrees lands partial-consensus rather than full-consensus, because a caveat means the claim does not pass cleanly (this differs from the collaborative classifier, where SUPPLEMENT counts as full agreement).
240
+ Design intent: one `counter-evidence` refute denies a claim consensus (it cannot rise above `contested` however many others AGREE); a lone `burden-not-met` doubt does not sink an otherwise-surviving claim — only a majority of them does. When every non-discoverer refutes (all_others_disagree) the finding is worker-unique regardless of refute basis — only the discoverer still holds it. A SUPPLEMENT/caveat with zero disagrees lands partial-consensus, not full-consensus, because a caveat means the claim does not pass cleanly (unlike the collaborative classifier, where SUPPLEMENT counts as full agreement).
250
241
 
251
242
  ## Re-verification Dispatch
252
243
 
@@ -256,7 +247,6 @@ For each analysis worker with a non-empty current round's `items_for_W` batch, b
256
247
 
257
248
  Call `await_workers(handles)` through the same adapter and apply the shared terminal-status/completion-path contract before counting a vote. The selected adapter owns native invocation spelling and any jobs-file/CLI fields. This contract owns only the reverify payload and verdict semantics.
258
249
 
259
-
260
250
  **Completion detection per round (BLOCKING).** A dispatch acknowledgement is NOT completion — detect each round's completion via the SSOT protocol in [team-contract](./team-contract.md) "Worker-completion detection", with the pending set reconstructed from that round's dispatched workers' Result Paths. Do NOT end the turn with a prose "waiting" statement.
261
251
 
262
252
  ### Required reverify-prompt anchor headers (BLOCKING)
@@ -277,7 +267,7 @@ Assigned worker prompt history path: <Project Root>/<Prompt History Path>
277
267
  2. `team-state-<task-type>-<seq>.json` → `workers[].usage.cliModel` for that role (initial run's actual execution value)
278
268
  3. The `**Model:**` line of the initial Phase 4 prompt for that role (read from its persisted prompt-history file)
279
269
 
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.
270
+ 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
271
 
282
272
  ### Reverify prompt: required-reading suppression
283
273
 
@@ -475,7 +465,7 @@ Save it to `runs/<task-type>/state/convergence-<task-type>-<seq>.json`.
475
465
  }
476
466
  ```
477
467
 
478
- > The example above shows an abbreviated artifact: the `findings[]` array contains only `F-001` even though `finalClassificationCounts` totals 7 — a real artifact has one `findings[]` entry per finding. The example uses a clean one-round queue-drained run for clarity; runs that hit Round 2 add a second `roundHistory[]` entry with the same shape.
468
+ > Abbreviated example: `findings[]` shows only `F-001` though `finalClassificationCounts` totals 7 — a real artifact has one `findings[]` entry per finding. This is a clean one-round queue-drained run; a Round 2 run adds a second `roundHistory[]` entry of the same shape.
479
469
 
480
470
  Schema rules:
481
471
 
@@ -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
 
@@ -82,13 +82,13 @@ Phase-transition checklist (lead, end of run):
82
82
 
83
83
  User-utterance interpretation rule:
84
84
 
85
- - "다음 단계 진행해" / "proceed to the next step" / equivalent phrases are scoped to **the current phase only**. Interpret them as "produce the remaining outputs of the current phase," never as "start the next lifecycle phase."
85
+ - "proceed to the next step" / "move on to the next step" / equivalent phrases are scoped to **the current phase only**. Interpret them as "produce the remaining outputs of the current phase," never as "start the next lifecycle phase."
86
86
  - If the current phase's outputs are already complete and the user clearly wants to advance, reply with the phase-transition checklist above and the exact next-run command. Wait for explicit user confirmation before any action that belongs to the next phase.
87
87
  - If `nextRecommendedPhase` is `implementation-planning`, the next run produces a **plan**, not code. The next run after that is `implementation`.
88
88
 
89
89
  ## Progress reporting (BLOCKING)
90
90
 
91
- A single okstra run frequently spans 30–120 minutes of wall-clock time with multi-minute silent windows while workers run. Without explicit progress signals the user cannot distinguish "still working" from "hung", so Lead MUST emit a single short progress line at each of the checkpoints below — as plain user-facing text in a separate brief message (not buried inside a tool call). One line per checkpoint, format: `PROGRESS: <phase-id> <verb-phrase>`. Emit the line raw — the literal `PROGRESS:` token must begin the line. Do NOT wrap it in inline-code backticks (`` `PROGRESS: ...` ``) or a ```` ``` ```` code fence; markdown wrapping is what the post-hoc conformance validator scrapes around, and raw emit keeps the signal unambiguous.
91
+ A single okstra run frequently spans 30–120 minutes with multi-minute silent windows while workers run; without progress signals the user cannot distinguish "still working" from "hung". Lead MUST emit a single short progress line at each checkpoint below — plain user-facing text in a separate brief message (not buried inside a tool call), one line per checkpoint, format: `PROGRESS: <phase-id> <verb-phrase>`. Emit the line raw — the literal `PROGRESS:` token must begin the line. Do NOT wrap it in inline-code backticks (`` `PROGRESS: ...` ``) or a ```` ``` ```` code fence; markdown wrapping is what the post-hoc conformance validator scrapes around, and raw emit keeps the signal unambiguous.
92
92
 
93
93
  Required checkpoints:
94
94
 
@@ -101,15 +101,15 @@ Required checkpoints:
101
101
  - `PROGRESS: phase-5-collect worker=<role> status=<terminal-status>` — once per worker, immediately after the result file is verified.
102
102
  - `PROGRESS: phase-5.5-convergence round=<N> queue=<count>` — at the start of each convergence round (Phase 5.5).
103
103
  - `PROGRESS: phase-5.6-critic provider=<provider> gaps=<n>` — after the critic result is collected (Phase 5.6, opt-in; the critic dispatch itself fires concurrently with the first 5.5 reverify round). Omitted when `convergence.critic.enabled == false`.
104
- - `PROGRESS: phase-batch-cleanup panes=<n> teammates=<m>` — 이전 배치 pane·완료 teammate 를 정리한 직후, 각 배치 경계에서(① 첫 `phase-5.5-convergence` round 직전 ② `phase-6-synthesis` report-writer dispatch 직전). 카운트만 노출하고 `%NNN`/lead-pane.id/raw worker handle 은 절대 노출하지 않는다. 첫 배치(분석 워커 dispatch) 직전엔 치울 게 없어 no-op 이며 마커도 생략.
104
+ - `PROGRESS: phase-batch-cleanup panes=<n> teammates=<m>` — immediately after cleaning up the previous batch's panes and completed teammates, at each batch boundary (① just before the first `phase-5.5-convergence` round ② just before the `phase-6-synthesis` report-writer dispatch). Expose only the counts and NEVER expose `%NNN`/lead-pane.id/raw worker handles. Just before the first batch (analysis-worker dispatch) there is nothing to clean up, so it is a no-op and the marker is omitted.
105
105
  - `PROGRESS: phase-6-synthesis dispatching report-writer-worker` — at the start of Phase 6.
106
106
  - `PROGRESS: phase-7-persist updating manifests` — at the start of Phase 7.
107
107
  - `PROGRESS: phase-7-teardown shutting-down-workers` — only after usage collection and user approval, immediately before `shutdown_workers`; omitted when no cleanup resource exists or the user keeps it.
108
108
  - `PROGRESS: complete final-report=<relative-path>` — final summary line, after all persistence.
109
109
 
110
- These lines are the only structured signal the user has during a long run. Do NOT replace them with prose ("Now I'm starting Phase 2..."), do NOT skip a checkpoint because "the previous message already said that", and do NOT batch multiple checkpoints into one. Each line stands alone so the user (or any operator scraping stdout) can timestamp it externally.
110
+ Do NOT replace them with prose ("Now I'm starting Phase 2..."), do NOT skip a checkpoint because "the previous message already said that", and do NOT batch multiple checkpoints into one. Each line stands alone so the user (or any operator scraping stdout) can timestamp it externally.
111
111
 
112
- `okstra-run` surfaces these lines to the user directly; other launch paths persist them in the selected adapter's declared conformance evidence/event source for post-hoc retrieval. No path requires additional formatting from Lead — emit the literal `PROGRESS:` prefix and the rest of the line as plain text.
112
+ `okstra-run` surfaces these lines to the user directly; other launch paths persist them in the selected adapter's declared conformance evidence/event source for post-hoc retrieval.
113
113
 
114
114
  **Enforcement:** the Phase 7 validator (`validators/validate-run.py` → `validate_session_conformance.py`) reads the selected adapter's declared conformance evidence/event source within the run window and fails the run as `contract-violated` when a required checkpoint is missing — including the per-worker `phase-4-dispatch` / `phase-5-collect` lines (which must name each worker's role) and the `phase-batch-cleanup` lines that MUST precede the first `phase-5.5-convergence` round and the `phase-6-synthesis` report-writer dispatch. `phase-7-teardown` and `complete` fire after validation and are not checked.
115
115
 
@@ -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.
@@ -138,7 +138,7 @@ For `--task-type implementation` runs, the task bundle additionally pins one of
138
138
  - `instruction-set/analysis-profile.md` — top "Executor binding" block (provider, displayName, workerAgent, model)
139
139
  - `runs/implementation/manifests/run-manifest-*.json` — `teamContract.executor` object (same fields plus `appliesTo: "implementation"`)
140
140
 
141
- Lead MUST dispatch Edit/Write-bearing work only through the `workerAgent` declared there. The other two providers still run as read-only verifiers in the same run; the executor's own provider is *also* dispatched separately as a verifier (a fresh CLI session) so the diff is reviewed by a context-isolated session. Session isolation is the primary self-review safeguard — same-model executor and same-provider verifier is acceptable when running in distinct sessions. Selecting a different model variant (e.g. executor=opus / Claude verifier=sonnet) is recommended but no longer mandatory.
141
+ Lead MUST dispatch Edit/Write-bearing work only through the `workerAgent` declared there. The other two providers still run as read-only verifiers in the same run; the executor's own provider is *also* dispatched separately as a verifier in a fresh CLI session, so the diff is reviewed context-isolated. Session isolation is the primary self-review safeguard — same-model executor and same-provider verifier is acceptable in distinct sessions. A different model variant (e.g. executor=opus / Claude verifier=sonnet) is recommended but not mandatory.
142
142
 
143
143
  Executor is chosen at run-prep time via `--executor <claude|codex|antigravity>` (or `OKSTRA_DEFAULT_EXECUTOR`, fallback `claude`); the model used by the executor is taken from the corresponding worker model flag (`--claude-model` / `--codex-model` / `--antigravity-model`). For CLI-backed executors, the underlying file mutation happens inside the executor CLI's own auto-edit mode (e.g. `codex exec --sandbox workspace-write`), not through the lead runtime's `write_artifact` operation.
144
144
 
@@ -164,7 +164,7 @@ Executor is chosen at run-prep time via `--executor <claude|codex|antigravity>`
164
164
 
165
165
  Treat cross verify input as a task bundle, not as a single file. If the user did not specify an explicit task key or task path, use `.okstra/discovery/latest-task.json` as the current-task convenience pointer. If task browsing, task-id disambiguation, or project-level task inventory is needed, inspect `.okstra/discovery/task-catalog.json` first.
166
166
 
167
- After context-loader completes, read **only the compact intake files below** in a single parallel-Read message at the start of Phase 1. The other instruction-set files are loaded lazily at the phase that actually needs them — see "Lazy reading discipline" below. This split exists because re-absorbing the full instruction-set baseline at every phase entry was the dominant observed source of lead-token bloat — most of that baseline is files only one downstream phase ever uses.
167
+ After context-loader completes, read **only the compact intake files below** in a single parallel-Read message at the start of Phase 1. The other instruction-set files are loaded lazily at the phase that actually needs them — see "Lazy reading discipline" below. This split exists because re-absorbing the full instruction-set baseline at every phase entry is the dominant source of lead-token bloat — most of it is files only one downstream phase uses.
168
168
 
169
169
  **Mandatory at Phase 1 start (parallel Read, one message):**
170
170
 
@@ -184,11 +184,11 @@ After context-loader completes, read **only the compact intake files below** in
184
184
 
185
185
  **Implementation profile lazy reading discipline (BLOCKING — applies only when `task_type == "implementation"`):**
186
186
 
187
- The `implementation` profile's thin core (`prompts/profiles/implementation.md`) is intentionally minimal so the Phase 1 baseline stays small. Three sidecar files carry the bulk of the rules and MUST be read at the listed phase — do NOT pre-load them at Phase 1. The sidecar list and each one's `Read at` phase live in the profile's "Lazy section pointers" table (`prompts/profiles/implementation.md`) — the profile arrives in the Phase 1 intake via `analysis-profile.md`, so that table is already in context whenever this discipline applies.
187
+ The `implementation` profile's thin core (`prompts/profiles/implementation.md`) is intentionally minimal so the Phase 1 baseline stays small. Three sidecar files carry the bulk of the rules and MUST be read at the listed phase — do NOT pre-load them at Phase 1. The sidecar list and each one's `Read at` phase live in that profile's "Lazy section pointers" table, which arrives in the Phase 1 intake via `analysis-profile.md`, so it is already in context whenever this discipline applies.
188
188
 
189
- **Entry guard (BLOCKING).** Before transitioning into Phase 5 or Phase 6 for an `implementation` run, lead MUST emit a single Read tool call for the sidecar(s) whose `Read at` (per that table) matches the entering phase. If lead enters the phase without that Read recorded in the selected adapter's conformance evidence/event source, phase 진입 거부 — lead writes a `contract-violation` to the run-level errors log with `--message "implementation-sidecar-not-loaded"` and stops. Re-entry requires the sidecar Read first. **Enforcement:** the Phase 7 validator (`validate_session_conformance.py`) verifies post-hoc that all three sidecar Reads exist in the selected adapter's declared source within this run's window, and that they precede the `phase-6-synthesis` / `phase-7-persist` checkpoints respectively.
189
+ **Entry guard (BLOCKING).** Before transitioning into Phase 5 or Phase 6 for an `implementation` run, lead MUST emit a single Read tool call for the sidecar(s) whose `Read at` (per that table) matches the entering phase. If lead enters the phase without that Read recorded in the selected adapter's conformance evidence/event source, phase entry is refused — lead writes a `contract-violation` to the run-level errors log with `--message "implementation-sidecar-not-loaded"` and stops. Re-entry requires the sidecar Read first. **Enforcement:** the Phase 7 validator (`validate_session_conformance.py`) verifies post-hoc that all three sidecar Reads exist in the selected adapter's declared source within this run's window, and that they precede the `phase-6-synthesis` / `phase-7-persist` checkpoints respectively.
190
190
 
191
- The guard is not satisfied by remembering content from a prior run — each implementation run reads the sidecar fresh, because the sidecars are part of the runtime shipped via `okstra install` and may have been updated between runs.
191
+ The guard is not satisfied by memory from a prior run — each implementation run re-reads the sidecar fresh, since `okstra install` may have updated it between runs.
192
192
 
193
193
  This pattern is implementation-only. Other profiles (`requirements-discovery`, `error-analysis`, `implementation-planning`, `final-verification`, `release-handoff`) load their whole profile body at Phase 1 as before — they are short enough not to benefit from a split.
194
194
 
@@ -229,7 +229,7 @@ The launch prompt's `## Run Logs (error-log wiring)` section gives Lead the reso
229
229
  - `**Errors log path:** <absolute run-level errors log path from launch prompt>`
230
230
  - `**Errors sidecar path:** <absolute per-worker sidecar path matching the dispatched worker>`
231
231
 
232
- Workers are contractually required to extract these two lines and abort with `<WORKER>_ERRORS_PATH_MISSING` if either is absent (see each worker definition's "Path extraction (BLOCKING)" block). Omitting these headers reproduces the historical bug class where every run's `errors-<task-type>-<seq>.jsonl` stayed empty because workers had only template placeholders to work from.
232
+ Workers are contractually required to extract these two lines and abort with `<WORKER>_ERRORS_PATH_MISSING` if either is absent (see each worker definition's "Path extraction (BLOCKING)" block). Omitting these headers reproduces the historical bug where every run's `errors-<task-type>-<seq>.jsonl` stayed empty (workers had only template placeholders).
233
233
 
234
234
  After each worker terminates, BEFORE classifying its terminal status, verify the canonical result file exists at the absolute path resolved from the `**Result Path:**` header. If it is absent — or the wrapper sub-agent returned `CODEX_RESULT_MISSING` / `ANTIGRAVITY_RESULT_MISSING` — re-dispatch the SAME worker once with the byte-identical prompt. Only after the second attempt also misses may the role be classified `error` with `--message "result-missing after 1 retry"`. Full rules: [team-contract](./team-contract.md) "Lead Redispatch Policy on Result-Missing".
235
235
 
@@ -283,7 +283,7 @@ Before constructing the dispatch prompt, the lead MUST:
283
283
  `**Report Language:**` in the report-writer dispatch prompt, and ensure
284
284
  the worker writes the same value into `data.json.meta.reportLanguage`.
285
285
 
286
- Do not write the final verdict until every analysis worker role has either a saved result or a terminal status entry. The convergence output provides four finding categories:
286
+ The convergence output provides four finding categories:
287
287
 
288
288
  1. Full Consensus
289
289
  2. Partial Consensus
@@ -298,7 +298,7 @@ If only one worker result is usable: reduced-confidence synthesis. If evidence i
298
298
 
299
299
  After the Report writer worker draft is reviewed (or after the lead-authored fallback completes), **if** `task_type == "implementation-planning"` **and** `task-manifest.json` `convergence.planBodyVerification.enabled == true` (default), the lead MUST run one additional verification round on the consolidated plan body before declaring Phase 6 complete and entering Phase 7.
300
300
 
301
- This is a Phase 6 sub-step — it does NOT introduce a new top-level lifecycle phase. The lead operating-phase model (Phase 1 Intake → Phase 7 Persist, with the labels in the "Quick Reference" table above as the single source of truth) is preserved.
301
+ This is a Phase 6 sub-step — it does NOT introduce a new top-level lifecycle phase; the lead operating-phase model (Phase 1 Intake → Phase 7 Persist, labels in the "Quick Reference" table above as the single source of truth) is preserved. `okstra-inspect status` exposes it as a `planVerification` sub-field of the implementation-planning phase, not a separate lifecycle phase identifier.
302
302
 
303
303
  **REQUIRED RESOURCE:** Read [plan-body-verification](./plan-body-verification.md) for the round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics (`AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`), classification rules, gate-result resolution, and the state-file schema at `runs/<task-type>/state/plan-body-verification.json`.
304
304
 
@@ -320,8 +320,6 @@ Lead's responsibilities in this sub-step (in order):
320
320
 
321
321
  If `convergence.planBodyVerification.enabled == false` (set by `--no-plan-verification` or by `okstra config set plan-verification off`), the entire sub-step is skipped and the top-of-report Approval marker is rendered unconditionally (legacy behaviour). This opt-out is intended for fast iteration only and is not recommended for handoff-ready plans.
322
322
 
323
- The `okstra-inspect status` sub-command exposes the sub-step's state as a `planVerification` sub-field of the implementation-planning phase, not as a separate lifecycle phase identifier.
324
-
325
323
  ## Phase 7: Artifact persistence and validator handoff
326
324
 
327
325
  The detailed persistence checklist and the BLOCKING token-usage collector invocation live in [report-writer](./report-writer.md). Persist the run yourself — do not assume okstra saves the final artifacts for you.
@@ -350,7 +348,7 @@ jq -s 'group_by(.errorType) | map({type: .[0].errorType, count: length})' <runDi
350
348
 
351
349
  The errors log is informational. Its presence/absence does not affect the final verdict. Do not block report writing on it.
352
350
 
353
- After persistence, reply briefly in the resolved Report Language with: completion status, final report path, team-state path, validator result, resume command path, any remaining blocker. **Lead this reply with the run's task identity** — state `<task-group>/<task-id>` (or the full `taskKey`) first, so the reader knows which task the reply is about. **Every run-artifact path in this reply MUST be task-qualified** — report the final report as `.okstra/tasks/<task-group>/<task-id>/runs/<task-type>/reports/final-report-<task-type>-<seq>.md` (the full path rooted at the task bundle), NOT the bare `runs/<task-type>/reports/...` form. The bare `runs/...` prefix is byte-for-byte identical across every task-group / task-id of the same task-type, so it cannot tell one task's report from another's — always emit the `.okstra/tasks/<task-group>/<task-id>/` prefix. The same task-qualified rule applies to the team-state path, resume command path, and any other run-artifact path this reply cites.
351
+ After persistence, reply briefly in the resolved Report Language with: completion status, final report path, team-state path, validator result, resume command path, any remaining blocker. **Lead this reply with the run's task identity** — state `<task-group>/<task-id>` (or the full `taskKey`) first, so the reader knows which task the reply is about. **Every run-artifact path in this reply MUST be task-qualified** — report the final report as `.okstra/tasks/<task-group>/<task-id>/runs/<task-type>/reports/final-report-<task-type>-<seq>.md` rooted at the task bundle, NOT the bare `runs/<task-type>/reports/...` form (byte-for-byte identical across every task of the same task-type, so it cannot identify the task). The same task-qualified rule applies to the team-state path, resume command path, and any other run-artifact path this reply cites.
354
352
 
355
353
  ## Run-scoped worker-resource lifecycle
356
354
 
@@ -60,12 +60,15 @@ 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
 
68
- 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
+ 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
+
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: split upload v2 into a new module", `P-Step-1.1` → "Stage 1 Step 2: regression-check with `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
71
74
 
@@ -80,10 +83,19 @@ The verdict tokens `AGREE` / `DISAGREE` / `SUPPLEMENT` are reused, but their mea
80
83
  - `e` — item contradicts the trade-off matrix
81
84
  - `f` — requirement coverage row cites no concrete option / stage / step, cites a non-existent option / stage / step, or marks a requirement `covered` while the cited plan item does not satisfy the row's stated requirement. A row that cites an existing option / stage / step is concrete for this purpose even if that option's File Structure paths are abbreviated — path imprecision inside the cited option is kind `b` on that option's own item, not `f` on the coverage row.
82
85
  - **SUPPLEMENT**: the item is sound but is missing a dependency / edge case / precondition.
83
- - **fixability** (DISAGREE 전용, 필수): 각 `DISAGREE(<kind>)` 는 결함을 지금 가진 코드 + 이 계획 draft + brief 만으로 고칠 수 있는지 판정한다.
84
- - `planner-fixable` — 외부 정보 없이 계획 자체를 교정하면 해소된다(경로 축약, prose command, placeholder, requirement-coverage 재매핑, 존재하지 않는 stage 인용 등).
85
- - `needs-user-input` — 교정에 열린 사용자 clarification(인프라·계약 결정) 또는 외부 정보가 필요하다.
86
- 기준 한 줄: "지금 가진 코드 + 계획 + 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 없이 승격시키지 못한다.
86
+ - **fixability** (DISAGREE-only, required): each `DISAGREE(<kind>)` judges whether the defect can be fixed using only the code you have now + this plan draft + the brief.
87
+ - `planner-fixable` — resolved by correcting the plan itself without external information (abbreviated paths, prose commands, placeholders, requirement-coverage remapping, citing a non-existent stage, etc.).
88
+ - `needs-user-input` — the fix requires an open user clarification (infrastructure / contract decision) or external information.
89
+ One-line criterion: "Can this defect be fixed using only the code I have now + the plan + the brief?" — if so, `planner-fixable`. **Enforced:** `validators/validate-run.py` `_validate_disagree_has_fixability` fails, on a run where the verification round ran (`roundCount >= 1`), any `DISAGREE` verdict whose `fixability` is missing or not one of the allowed values (`planner-fixable` / `needs-user-input`) — so that `_validate_self_fix_before_clarification` cannot let a mislabelled planner-fixable defect be promoted without a self-fix.
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.
87
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
 
@@ -121,19 +133,20 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
121
133
  - any `partial-consensus` / `dissent-isolated` present, no `majority-disagree` → `passed-with-dissent`
122
134
  - all items `full-consensus` → `passed`
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
- 7. **Self-fix round (최대 1회, planner-fixable 결함 대상).** aggregation 후 `majority-disagree` 항목 중 그 `DISAGREE` verdict 의 다수가 `fixability == planner-fixable` 인 항목이 하나 이상이면, lead 는 사용자에게 승격하기 **전에** 자가수정을 1회 시도한다:
125
- - lead 가 report-writer 에게 그 planner-fixable 항목들만 교정 재작성을 지시한다(전체 draft 재생성 아님 — 해당 `P-*` 가 가리키는 계획 섹션만 patch; 절차는 [report-writer](./report-writer.md) §"Self-fix rewrite").
126
- - lead 가 plan-body 검증을 1회 재실행한다(교정된 항목 + 재작성이 건드린 인접 항목 중심). 재검증 후 verdict 로 `planItems[].verdicts` 를 덮어쓴다.
127
- - self-fix 로 `majority-disagree` 가 해소된 항목은 `planItems[].selfFixNote` 에 `self-fixed in round <N>: <무엇을 고쳤는지>` 를 기록한다. 해소된 항목은 clarification 을 만들지 않는다.
128
- - 이 라운드는 **최대 1회**다(무한루프 상한). self-fix 라운드를 시도했으면 `planBodyVerification.selfFixRoundApplied = true` 로 기록한다.
129
- - `needs-user-input` 다수인 `majority-disagree` 항목은 self-fix 대상이 아니다 — 곧바로 다음 step 의 clarification 승격으로 간다.
130
- 8. For every `majority-disagree` item **that remains after the self-fix round** (self-fix 로 해소되지 않았거나 처음부터 `needs-user-input` 다수인 항목), lead adds a row to `## 1. Clarification Items` with:
136
+ 7. **Self-fix round (at most once, targeting planner-fixable defects).** After aggregation, if at least one `majority-disagree` item has a majority of its `DISAGREE` verdicts at `fixability == planner-fixable`, lead attempts one self-fix **before** promoting it to the user:
137
+ - lead instructs report-writer to rewrite only those planner-fixable items for correction (NOT a full draft regeneration — patch only the plan section each `P-*` points to; procedure in [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.
139
+ - lead re-runs plan-body verification once (focused on the corrected items + adjacent items the rewrite touched). After re-verification, overwrite `planItems[].verdicts` with the new verdicts.
140
+ - for an item whose `majority-disagree` was resolved by self-fix, record `self-fixed in round <N>: <what was fixed>` in `planItems[].selfFixNote`. A resolved item does not create a clarification.
141
+ - this round runs **at most once** (infinite-loop cap). If a self-fix round was attempted, record `planBodyVerification.selfFixRoundApplied = true`.
142
+ - a `majority-disagree` item with a majority of `needs-user-input` is NOT a self-fix target — it goes straight to the next step's clarification promotion.
143
+ 8. For every `majority-disagree` item **that remains after the self-fix round** (items not resolved by self-fix, or with a `needs-user-input` majority from the start), lead adds a row to `## 1. Clarification Items` with:
131
144
  - new `C-<N>` ID (numbering continues from any existing rows)
132
145
  - `Statement` summarising the disagreement and the worker breakage `<kind>`
133
146
  - `Kind` chosen per the standard policy (usually `decision` for option-level conflicts, `data-point` for path/symbol mismatches)
134
147
  - `Blocks=approval`
135
148
  - the item's `planItems[].clarificationId` set to that `C-<N>` (1:1 link). `validators/validate-run.py` `_validate_plan_body_clarification_matching` recomputes each item's class and fails when a majority-disagree item's `clarificationId` is missing, dangling, or points at a non-`approval` row.
136
- - self-fix 라운드를 거치고도 남은 `planner-fixable` 항목은 승격하되 `Statement` 에 "planner self-fix 시도했으나 미해소" 를 명시한다(상한 때문에 재작성을 반복하지 않는다). `validators/validate-run.py` `_validate_self_fix_before_clarification` 는 `selfFixRoundApplied != true` 인데 planner-fixable 다수 항목이 승격되면 실패시킨다.
149
+ - a `planner-fixable` item that survives the self-fix round is still promoted, but its `Statement` MUST state "planner self-fix attempted but unresolved" (the cap prevents repeating the rewrite). `validators/validate-run.py` `_validate_self_fix_before_clarification` fails when `selfFixRoundApplied != true` yet a planner-fixable majority item is promoted.
137
150
  9. The top-of-report `- [ ] Approved` marker line is rendered if and only if the Gate result is `passed` or `passed-with-dissent`. `validators/validate-run.py` `validate_phase_boundary` enforces this correspondence; manually adding the marker line when the gate did not pass is a contract violation.
138
151
 
139
152
  ## `plan-body-verification-<task-type>-<seq>.json` schema
@@ -151,7 +164,7 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
151
164
  "planItems": [
152
165
  {
153
166
  "id": "P-Opt-1",
154
- "subject": "Option A: upload v2 를 신규 모듈로 분리",
167
+ "subject": "Option A: split upload v2 into a new module",
155
168
  "sourceSection": "4.5.1",
156
169
  "ticketId": "<id-or-unknown>",
157
170
  "votes": {"claude-worker": "AGREE", "codex-worker": "AGREE"},
@@ -160,7 +173,7 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
160
173
  },
161
174
  {
162
175
  "id": "P-Step-3",
163
- "subject": "Stage 2 Step 3: 마이그레이션 실행 후 회귀 테스트",
176
+ "subject": "Stage 2 Step 3: run migration then regression test",
164
177
  "sourceSection": "4.5.4",
165
178
  "ticketId": "TICKET-123",
166
179
  "votes": {"claude-worker": "DISAGREE(a)", "codex-worker": "DISAGREE(a)"},
@@ -180,7 +193,7 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
180
193
 
181
194
  `planItems[].votes.<worker>` is the verbatim verdict token emitted by the worker — `AGREE | DISAGREE(<a|b|c|d|e|f>) | SUPPLEMENT` — or `verification-error` for terminal non-result dispatches. The `DISAGREE` token retains its `<kind>` suffix so the breakage class is recoverable from the state file alone.
182
195
 
183
- `planBodyVerification.selfFixRoundApplied` (bool, 기본 false): self-fix 라운드를 1회라도 시도했는지. `planItems[].verdicts[].fixability` 는 각 `DISAGREE` 의 `planner-fixable | needs-user-input` 판정으로, 최종 data.json(`§5.5.9`)에 기록된다.
196
+ `planBodyVerification.selfFixRoundApplied` (bool, default false): whether a self-fix round was attempted at least once. `planItems[].verdicts[].fixability` is each `DISAGREE`'s `planner-fixable | needs-user-input` judgement, recorded in the final data.json (`§5.5.9`).
184
197
 
185
198
  ## Plan-body reverify prompt
186
199
 
@@ -204,7 +217,7 @@ verdict:
204
217
  (d) rollback violates commit / dependency order,
205
218
  (e) item contradicts the trade-off matrix,
206
219
  (f) requirement coverage row does not map the stated requirement to a concrete satisfying option / stage / step — citing an existing option counts as concrete even if that option's paths are abbreviated (that is (b) on the option's item, not (f)).
207
- DISAGREE 를 낼 때는 **Fixability** 도 함께 답하라 — 이 결함을 코드 + 이 계획 draft + brief 만으로 고칠 수 있으면 `planner-fixable`, 열린 사용자 clarification / 외부 정보가 필요하면 `needs-user-input`.
220
+ When you give a DISAGREE, also answer **Fixability** — `planner-fixable` if this defect can be fixed using only the code + this plan draft + the brief, `needs-user-input` if an open user clarification / external information is required.
208
221
  - **SUPPLEMENT**: The item is sound but a dependency / edge case / precondition
209
222
  is missing.
210
223
 
@@ -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,15 +250,26 @@ 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
238
262
  **Verdict**: AGREE | DISAGREE(<a|b|c|d|e|f>) | SUPPLEMENT
239
- **Fixability** (DISAGREE 일 때만): planner-fixable | needs-user-input — "코드 + 이 계획 + brief 만으로 고칠 수 있으면 planner-fixable"
263
+ **Fixability** (only when DISAGREE): planner-fixable | needs-user-input — "planner-fixable if it can be fixed using only the code + this plan + the brief"
240
264
  **Explanation**: <2-3 sentences>
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.