okstra 0.172.0 → 0.173.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 (83) hide show
  1. package/README.md +8 -6
  2. package/docs/architecture/storage-model.md +11 -0
  3. package/docs/architecture.md +16 -14
  4. package/docs/cli.md +36 -5
  5. package/docs/performance-improvement-plan-v2.md +6 -5
  6. package/docs/project-structure-overview.md +21 -13
  7. package/docs/task-process/README.md +5 -3
  8. package/docs/task-process/error-analysis.md +2 -2
  9. package/docs/task-process/final-verification.md +2 -2
  10. package/docs/task-process/implementation-option-selection.md +70 -0
  11. package/docs/task-process/implementation-planning.md +23 -15
  12. package/docs/task-process/requirements-discovery.md +2 -2
  13. package/package.json +1 -1
  14. package/runtime/BUILD.json +2 -2
  15. package/runtime/agents/workers/report-writer-worker.md +30 -6
  16. package/runtime/bin/lib/okstra/cli.sh +5 -1
  17. package/runtime/bin/lib/okstra/globals.sh +1 -0
  18. package/runtime/bin/lib/okstra/usage.sh +3 -0
  19. package/runtime/bin/okstra.sh +2 -0
  20. package/runtime/prompts/duties/direction-selection-worker.md +44 -0
  21. package/runtime/prompts/duties/planning-worker.md +12 -4
  22. package/runtime/prompts/lead/context-loader.md +1 -1
  23. package/runtime/prompts/lead/convergence.md +5 -5
  24. package/runtime/prompts/lead/okstra-lead-contract.md +6 -5
  25. package/runtime/prompts/lead/plan-body-verification.md +20 -3
  26. package/runtime/prompts/lead/report-writer.md +27 -5
  27. package/runtime/prompts/profiles/_common-contract.md +1 -1
  28. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
  29. package/runtime/prompts/profiles/error-analysis.md +3 -3
  30. package/runtime/prompts/profiles/final-verification.md +3 -3
  31. package/runtime/prompts/profiles/forbidden-actions.json +7 -0
  32. package/runtime/prompts/profiles/implementation-option-selection.md +35 -0
  33. package/runtime/prompts/profiles/implementation-planning.md +50 -38
  34. package/runtime/prompts/profiles/implementation.md +2 -1
  35. package/runtime/prompts/profiles/improvement-discovery.md +1 -1
  36. package/runtime/prompts/profiles/requirements-discovery.md +3 -3
  37. package/runtime/prompts/wizard/prompts.ko.json +9 -1
  38. package/runtime/python/okstra_ctl/agent_invocation.py +1 -0
  39. package/runtime/python/okstra_ctl/analysis_packet.py +6 -0
  40. package/runtime/python/okstra_ctl/exact_coverage.py +128 -0
  41. package/runtime/python/okstra_ctl/fix_cycles.py +3 -1
  42. package/runtime/python/okstra_ctl/implementation_direction.py +836 -0
  43. package/runtime/python/okstra_ctl/implementation_options.py +479 -0
  44. package/runtime/python/okstra_ctl/plan_items.py +51 -3
  45. package/runtime/python/okstra_ctl/render.py +1 -0
  46. package/runtime/python/okstra_ctl/render_final_report.py +1 -0
  47. package/runtime/python/okstra_ctl/report_contract.py +45 -13
  48. package/runtime/python/okstra_ctl/report_html/render.py +4 -2
  49. package/runtime/python/okstra_ctl/report_html/router.py +4 -0
  50. package/runtime/python/okstra_ctl/report_html/view_models/implementation_option_selection.py +32 -0
  51. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +25 -10
  52. package/runtime/python/okstra_ctl/report_views.py +148 -12
  53. package/runtime/python/okstra_ctl/run.py +350 -2
  54. package/runtime/python/okstra_ctl/scope_provenance.py +15 -9
  55. package/runtime/python/okstra_ctl/user_response.py +75 -0
  56. package/runtime/python/okstra_ctl/wizard.py +144 -0
  57. package/runtime/python/okstra_ctl/worker_prompt_policy.py +2 -0
  58. package/runtime/python/okstra_ctl/workflow.py +29 -7
  59. package/runtime/schemas/final-report-v2.0.schema.json +1428 -137
  60. package/runtime/templates/reports/final-report-v2.template.md +4 -0
  61. package/runtime/templates/reports/final-verification-input.template.md +1 -1
  62. package/runtime/templates/reports/html/base.template.html +3 -2
  63. package/runtime/templates/reports/html/i18n/en.json +21 -1
  64. package/runtime/templates/reports/html/i18n/ko.json +21 -1
  65. package/runtime/templates/reports/html/macros/forms.html +21 -2
  66. package/runtime/templates/reports/html/tasks/implementation-option-selection.template.html +49 -0
  67. package/runtime/templates/reports/html/tasks/implementation-planning.template.html +36 -2
  68. package/runtime/templates/reports/i18n/en.json +13 -0
  69. package/runtime/templates/reports/implementation-input.template.md +4 -2
  70. package/runtime/templates/reports/implementation-planning-input.template.md +18 -4
  71. package/runtime/templates/reports/improvement-discovery-input.template.md +1 -1
  72. package/runtime/templates/reports/md/tasks/implementation-option-selection.template.md +13 -0
  73. package/runtime/templates/reports/md/tasks/implementation-planning.template.md +17 -0
  74. package/runtime/templates/reports/report.js +111 -4
  75. package/runtime/templates/reports/task-brief.template.md +9 -3
  76. package/runtime/templates/reports/user-response.template.md +25 -4
  77. package/runtime/templates/worker-prompt-preamble.md +8 -0
  78. package/runtime/validators/validate-implementation-plan-stages.py +106 -1
  79. package/runtime/validators/validate-report-views.py +2 -2
  80. package/runtime/validators/validate-run.py +135 -25
  81. package/runtime/validators/validate_improvement_report.py +5 -1
  82. package/src/commands/execute/codex-run.mjs +1 -0
  83. package/src/commands/execute/render-bundle.mjs +1 -0
@@ -0,0 +1,70 @@
1
+ # implementation-option-selection process
2
+
3
+ ## Index
4
+
5
+ - [1. Purpose](#1-purpose)
6
+ - [2. Execution modes](#2-execution-modes)
7
+ - [3. Prepare gates](#3-prepare-gates)
8
+ - [4. Candidate validation and ranking](#4-candidate-validation-and-ranking)
9
+ - [5. Direction confirmation and planning handoff](#5-direction-confirmation-and-planning-handoff)
10
+ - [6. Forbidden actions](#6-forbidden-actions)
11
+ - [7. Verified code](#7-verified-code)
12
+
13
+ ## 1. Purpose
14
+
15
+ `implementation-option-selection` is the read-only lifecycle phase between cause analysis and detailed planning. It decides which implementation mechanism and architecture boundary planning may realize. It does not name the exact file list, split stages, or prescribe test commands.
16
+
17
+ Direction confirmation and detailed plan approval are independent user decisions. Confirming a direction permits planning to begin. It does not approve the plan or permit implementation.
18
+
19
+ ## 2. Execution modes
20
+
21
+ | Mode | Input | Output |
22
+ |---|---|---|
23
+ | `candidate-comparison` | Requirement ledger, cause evidence, code evidence, independently proposed raw candidates | At most three ranked valid directions and a separate user selection |
24
+ | `preselected-validation` | A direction already fixed by upstream evidence or an explicit user instruction | One normalized and validated direction, or `blocked`; no alternative is generated |
25
+
26
+ The normal analyser roster contains at least three analyser workers plus the report writer. Each analyser may propose at most three raw candidates. All analysers reassess the merged candidate set before ranking.
27
+
28
+ ## 3. Prepare gates
29
+
30
+ Prepare rejects the phase when the brief has no stable `EB-NNN`, `PB-NNN`, or `EO-NNN` requirement IDs. External Gates are not part of that denominator. Prepare also rejects a roster with fewer than three analysers.
31
+
32
+ The phase reuses the task-key worktree and may inspect the code and prior task artifacts. It does not obtain a writable implementation-stage worktree.
33
+
34
+ ## 4. Candidate validation and ranking
35
+
36
+ Every displayed candidate has all of the following properties:
37
+
38
+ - `coveragePercent == 100`
39
+ - `scopePrecisionPercent == 100`
40
+ - `coverageVerdict == exact`
41
+ - no `unmappedCommitments`
42
+ - no `contradictedRequirements`
43
+ - supporting code or upstream evidence
44
+ - at least two feasibility votes
45
+ - no safety blocker or unresolved implementation-critical external fact
46
+
47
+ The final report can display one, two, or three valid candidates. Rejected candidates remain in `candidateAudit` with their rejection reasons and cannot be selected. If no candidate is valid, the report uses `blocked` and planning cannot start.
48
+
49
+ Ranking uses eight fixed criteria with per-run weights: requirement fit, architecture fit, change locality, implementation complexity, correctness risk, reversibility, verification cost, and rollout cost. Safety and exact-coverage failures override the weighted score.
50
+
51
+ ## 5. Direction confirmation and planning handoff
52
+
53
+ Comparison mode exports a `DIRECTION SELECTION` block in the user-response sidecar. Prepare validates the selected ID against the displayed candidates and binds the response to the report's sibling data JSON through its SHA-256 digest.
54
+
55
+ A new planning run receives the selection report through `--selected-direction`. Prepare normalizes the validated choice into `instruction-set/selected-direction.json`. Planning cites that snapshot through `selectedDirectionRef` and writes `approved: false` until the user separately approves the detailed plan.
56
+
57
+ If planning proves that the mechanism or architecture boundary cannot satisfy exact coverage, it emits `direction-invalidated` and routes back to `implementation-option-selection`. It never picks the next ranked direction automatically.
58
+
59
+ ## 6. Forbidden actions
60
+
61
+ This phase does not edit source code, run builds or tests, execute migrations, deploy, or call a write API. Candidate details do not contain exact file lists, stage maps, or test commands. Those details belong to `implementation-planning` after direction confirmation.
62
+
63
+ ## 7. Verified code
64
+
65
+ - [`prompts/profiles/implementation-option-selection.md`](../../prompts/profiles/implementation-option-selection.md)
66
+ - [`prompts/duties/direction-selection-worker.md`](../../prompts/duties/direction-selection-worker.md)
67
+ - [`scripts/okstra_ctl/implementation_options.py`](../../scripts/okstra_ctl/implementation_options.py)
68
+ - [`scripts/okstra_ctl/implementation_direction.py`](../../scripts/okstra_ctl/implementation_direction.py)
69
+ - [`scripts/okstra_ctl/exact_coverage.py`](../../scripts/okstra_ctl/exact_coverage.py)
70
+ - [`validators/validate-run.py`](../../validators/validate-run.py)
@@ -12,7 +12,9 @@
12
12
 
13
13
  ## 1. Purpose
14
14
 
15
- `implementation-planning` is the phase that decides the implementation direction before coding. It produces at least two implementation options, trade-offs, a recommended option, a stepwise execution order, a validation checklist, and a rollback strategy, and it places a user approval gate.
15
+ `implementation-planning` realizes one direction that was already confirmed by `implementation-option-selection`. It turns that mechanism and architecture boundary into a file-level Stage Map, validation checklist, rollback strategy, and exact requirement-coverage map. The resulting detailed plan has its own approval gate; direction confirmation does not approve it.
16
+
17
+ An existing plan without `planningContract: selected-direction` remains on the legacy candidate-plan contract for compatibility. A new planning run uses the selected-direction contract and does not generate or rank alternatives.
16
18
 
17
19
  ## 2. okstra-run wizard flow
18
20
 
@@ -20,7 +22,11 @@
20
22
  flowchart TD
21
23
  Start[/okstra-run/] --> Common[common task identity flow]
22
24
  Common --> Type[task-type = implementation-planning]
23
- Type --> Worktree{active task worktree?}
25
+ Type --> Input{new plan or planning rerun?}
26
+ Input -->|new| Direction[selected-direction report pick]
27
+ Input -->|rerun| Prior[prior planning report via clarification-response]
28
+ Direction --> Worktree{active task worktree?}
29
+ Prior --> Worktree
24
30
  Worktree -->|yes| Defaults[Use defaults / Customize]
25
31
  Worktree -->|no| BaseRef[base-ref pick/text]
26
32
  BaseRef --> Defaults
@@ -33,7 +39,7 @@ flowchart TD
33
39
  Confirm --> Render[render-bundle]
34
40
  ```
35
41
 
36
- The wizard currently does not ask about `--no-plan-verification`. On the okstra-run path, plan-body verification is prepared as enabled by default. The shell/CLI path has a `--no-plan-verification` flag.
42
+ For a new plan, the wizard asks for a validated option-selection report and passes it as `--selected-direction`. A planning clarification rerun passes its own prior report through `--clarification-response`. The wizard currently does not ask about `--no-plan-verification`; on the okstra-run path, plan-body verification is prepared as enabled by default.
37
43
 
38
44
  ## 3. prepare_task_bundle handling
39
45
 
@@ -44,8 +50,10 @@ sequenceDiagram
44
50
  participant R as render.py
45
51
  participant M as manifests
46
52
 
47
- W->>P: task-type=implementation-planning
53
+ W->>P: task-type=implementation-planning + selected-direction or prior planning report
48
54
  P->>P: validate profile/brief/base-ref
55
+ P->>P: validate selection report, data digest, response, and selected option
56
+ P->>M: write instruction-set/selected-direction.json
49
57
  P->>P: resolve profile workers + optional override
50
58
  P->>P: resolve model metadata
51
59
  P->>P: provision/reuse task worktree
@@ -55,7 +63,7 @@ sequenceDiagram
55
63
  P-->>W: prepared lead prompt
56
64
  ```
57
65
 
58
- The runtime prepare stage does not block source edits itself; instead it "bakes the current phase boundary into the lead prompt and manifest." The actual no-edit/no-build rules must be honored by the lead and workers reading the profile.
66
+ Prepare rejects a new plan without a selected-direction report. Comparison mode requires a valid `DIRECTION SELECTION` sidecar, while preselected-validation mode uses the confirmed upstream direction without one. The normalized snapshot binds the source report, source-data digest, option ID, direction body, requirements, and invariants.
59
67
 
60
68
  ## 4. lead execution flow
61
69
 
@@ -72,8 +80,8 @@ flowchart TD
72
80
  RW --> Extract[Deterministic plan-item extraction]
73
81
  Extract --> PBV[Phase 6 sub-step<br/>Plan-body verifier round]
74
82
  PBV --> Gate{gate result}
75
- Gate -->|passed / passed-with-dissent| Approval[render top Approval checkbox]
76
- Gate -->|blocked-by-disagreement / aborted-non-result| NoApproval[render block without checkbox]
83
+ Gate -->|passed / passed-with-dissent| Approval[render plan decision approval control]
84
+ Gate -->|blocked-by-disagreement / aborted-non-result| NoApproval[render blocked plan decision]
77
85
  Approval --> P7[Phase 7 persistence/finalization<br/>canonical Markdown render<br/>HTML render + validate-run<br/>via okstra report-finalize]
78
86
  NoApproval --> P7
79
87
  ```
@@ -118,9 +126,8 @@ Plan approval and design-preparation status are independent gates. If plan-body
118
126
 
119
127
  ```mermaid
120
128
  flowchart LR
121
- Options[Option Candidates] --> Matrix[Trade-off Matrix]
122
- Matrix --> Rec[Recommended Option]
123
- Rec --> Stages[Stage Map + Stage Exit/Validation]
129
+ Direction[Selected Direction Snapshot] --> Realize[Direction Realization]
130
+ Realize --> Stages[Stage Map + Stage Exit/Validation]
124
131
  Stages --> Prep[Implementation Design Preparation]
125
132
  Prep --> Dep[Dependency / Migration Risk]
126
133
  Dep --> Val[Validation Checklist]
@@ -130,11 +137,10 @@ flowchart LR
130
137
  Approval --> Impl[Next run: implementation]
131
138
  ```
132
139
 
133
- Because the validator searches for the English substring of the section heading, the following strings must remain verbatim on the heading line.
140
+ The selected-direction branch verifies `P-Dir-1` before its stage, dependency, validation, rollback, requirement, preparation, and variation items. `P-Dir-1` proves that the plan preserves the selected mechanism, architecture boundary, invariants, and user constraints. The legacy branch continues to extract `P-Opt-*` from its option candidates.
141
+
142
+ The detailed selected-direction plan retains these deliverable surfaces:
134
143
 
135
- - `Option Candidates`
136
- - `Trade-off`
137
- - `Recommended Option`
138
144
  - `Stage Map`
139
145
  - `Stage Exit Contract`
140
146
  - `Stage Validation`
@@ -146,7 +152,9 @@ Because the validator searches for the English substring of the section heading,
146
152
  - `Requirement Coverage`
147
153
  - `Implementation Design Preparation`
148
154
 
149
- Approval is recorded with `approved: true` in the YAML frontmatter and the chosen `implementation-option`. If a `Blocks=approval` clarification row is unresolved, the implementation prepare rejects it even when the frontmatter is in an approved state. The `blocked` status of design-preparation is not the same as `Blocks=approval`, and it operates only at that stage's implementation preflight.
155
+ Approval is recorded with `approved: true` in YAML frontmatter. A selected-direction plan has no `implementation-option:` field and rejects `--implementation-option` before any approval-file mutation. If a `Blocks=approval` clarification row is unresolved, implementation prepare rejects the plan even when frontmatter is approved. Existing candidate plans keep their legacy option field and execution behavior.
156
+
157
+ `plan-ready` requires 100% requirement coverage, 100% scope precision, and no unmapped stage or file change. If the selected mechanism or boundary cannot meet those conditions, planning emits `direction-invalidated` without an executable Stage Map and routes back to `implementation-option-selection`. It does not choose another direction automatically.
150
158
 
151
159
  ## 6. Forbidden actions
152
160
 
@@ -11,7 +11,7 @@
11
11
 
12
12
  ## 1. Purpose
13
13
 
14
- `requirements-discovery` classifies the request before implementation. It determines which of bugfix, feature, improvement, refactor, or ops it is, and chooses whether the next safe phase is `error-analysis` or `implementation-planning`. Going directly to `implementation` is not valid per the profile. Implementation can only start once an approved `implementation-planning` report exists.
14
+ `requirements-discovery` classifies the request before implementation. It determines which of bugfix, feature, improvement, refactor, or ops it is, and chooses whether the next safe phase is `error-analysis` or `implementation-option-selection`. Going directly to planning or implementation is not valid for a new direction. Implementation can only start once a selected direction has been expanded into a separately approved `implementation-planning` report.
15
15
 
16
16
  ## 2. okstra-run wizard flow
17
17
 
@@ -90,7 +90,7 @@ flowchart LR
90
90
  RD --> Domain[Domain Alignment<br/>terminology resolution]
91
91
  RD --> Route{next safe phase}
92
92
  Route --> EA[error-analysis]
93
- Route --> IP[implementation-planning]
93
+ Route --> IOS[implementation-option-selection]
94
94
  Route -. invalid .-> Impl[implementation<br/>not allowed directly]
95
95
  ```
96
96
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.172.0",
3
+ "version": "0.173.0",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.172.0",
3
- "builtAt": "2026-08-15T19:49:27.306Z",
2
+ "package": "0.173.0",
3
+ "builtAt": "2026-08-16T04:09:59.317Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -102,12 +102,36 @@ You author the final-report data.json (the JSON SSOT). You author it against the
102
102
 
103
103
  The AI handoff Markdown is an agent-facing ledger: verdict, routing, clarification decisions, evidence, one structured task deliverable, and execution audits. The human HTML is the reader-facing explanation: `humanSummary` plus the selected task block's `userNarrative` and structured facts. Populate both human fields in data.json even though the Markdown intentionally omits their full prose. Worker discussion, convergence mechanics, and token usage belong to audit data and must not be copied into the HTML human main body.
104
104
 
105
+ ### Implementation-planning frontmatter contract
106
+
107
+ #### Selected-direction
108
+
109
+ Emit `frontmatter.approved` as `false` and copy `implementationPlanning.selectedDirectionRef.snapshotPath` into `frontmatter.selectedDirectionRef`. You MUST omit `frontmatter.implementationOption`; the direction was selected upstream and cannot be selected again in planning. `schemas/final-report-v2.0.schema.json` enforces the required selected-direction reference and rejects an `implementationOption` property for this branch.
110
+
111
+ #### Legacy candidate-comparison
112
+
113
+ Emit `frontmatter.approved` as `false` and `frontmatter.implementationOption` as the empty string `""`. The user later flips `approved` to `true` and fills `implementationOption` with the chosen Option Candidate name to authorise and scope the next `implementation` run. Every other report type follows the same empty `implementationOption` default; the schema's non-selected-direction branch requires that field and rejects a selected-direction reference.
114
+
115
+ ### General authoring rules
116
+
105
117
  Rules (the schema enforces most of these — they are listed here so you know *what* to populate, not *how* to validate):
106
118
 
107
119
  - Read the exact permitted header values from the task bundle schema excerpt. In the current v2 contract, `header.reportOwner` is `"Okstra lead"` and `header.reportAuthor` is `"Report writer worker"`. Set author to `"Okstra lead"` only for `release-handoff` runs (single-lead by design) or a recorded report-writer dispatch failure fallback. A legacy v1 excerpt may retain its historical compatibility values; follow that excerpt rather than inferring ownership from the provider.
108
120
  - **Source items (worker:item) preservation.** Every `consensus[].sourceItems`, `differences[].workersPosition[].itemId`, and `evidence.primary[].sourceItems` entry MUST carry the worker:item-id pair (e.g. `claude:F-001`, `codex:1.1`, `antigravity:F-3`, or `lead:mcp-1` for lead-only evidence). The schema enforces this via the `SourceItem` regex; bare worker-name lists no longer parse.
109
121
  - **Verdict Card consistency.** `verdictCard.verdictToken` and `verdictCard.direction` MUST byte-match `finalVerdict.verdictToken` / `.direction`; `validators/validate-run.py` diffs both and fails the run on divergence. `verdictCard.nextStep` names the same action as `finalVerdict.nextStep` and `recommendedNextSteps[0].text` but is written as the actionable command the reader runs (e.g. `/okstra-run task-key=… task-type=release-handoff`) where the other two are prose — it is deliberately not a byte copy. Duplicating the compared values across `verdictCard` and `finalVerdict` is intentional so the validator can diff them.
110
- - **Error-analysis diagnosis and routing.** When `header.taskType` is `error-analysis`, populate the required `errorAnalysis` object. Copy `errorAnalysis.symptomVerbatim` byte-for-byte from the symptom stated in the brief's `Source Material`; do not paraphrase it. Every `causeCandidates[]` row includes the full `supportingEvidence`, `falsifyingEvidenceChecked`, `confidence`, and `disproveWith` fields. When a candidate is a step in a propagation chain rather than a competing explanation — the analysis calls it a downstream step, a second stage, or a consequence of another candidate — set its `downstreamOf` to the ids of the candidates immediately upstream of it; leave the field absent for a candidate that stands on its own. Every id listed MUST be another candidate in the same report, no row may name itself, and the links MUST NOT form a cycle; `validators/validate-run.py::_validate_cause_chain` rejects all three. This is the only place the chain is machine-readable — prose calling a candidate "the second step of the chain" while `downstreamOf` is absent leaves the report's figure claiming the candidates are alternatives. Route `errorAnalysis.routing.nextTaskType=implementation-planning` with `direction=begin-planning`, or route `errorAnalysis.routing.nextTaskType=error-analysis` with `direction=continue-investigation`; no other pairing is valid. `verdictCard.nextStep`, `finalVerdict.nextStep`, the first `recommendedNextSteps` action and command, and the unique `followUpTasks` row whose `origin` is `phase-continuation` MUST all point to the same `errorAnalysis.routing.nextTaskType` target. The schema enforces only the presence of a `phase-continuation` row. Phase validation MUST enforce exact target agreement and uniqueness through `validators/validate-run.py::_validate_error_analysis_consistency`; until that check is implemented and executed, those semantics are contract requirements rather than enforced guarantees.
122
+ - **Error-analysis diagnosis and routing.** When `header.taskType` is `error-analysis`, populate the required `errorAnalysis` object. Copy `errorAnalysis.symptomVerbatim` byte-for-byte from the symptom stated in the brief's `Source Material`; do not paraphrase it. Every `causeCandidates[]` row includes the full `supportingEvidence`, `falsifyingEvidenceChecked`, `confidence`, and `disproveWith` fields. When a candidate is a step in a propagation chain rather than a competing explanation — the analysis calls it a downstream step, a second stage, or a consequence of another candidate — set its `downstreamOf` to the ids of the candidates immediately upstream of it; leave the field absent for a candidate that stands on its own. Every id listed MUST be another candidate in the same report, no row may name itself, and the links MUST NOT form a cycle; `validators/validate-run.py::_validate_cause_chain` rejects all three. This is the only place the chain is machine-readable — prose calling a candidate "the second step of the chain" while `downstreamOf` is absent leaves the report's figure claiming the candidates are alternatives. Route `errorAnalysis.routing.nextTaskType=implementation-option-selection` with `direction=begin-option-selection`, or route `errorAnalysis.routing.nextTaskType=error-analysis` with `direction=continue-investigation`; no other pairing is valid. `verdictCard.nextStep`, `finalVerdict.nextStep`, the first `recommendedNextSteps` action and command, and the unique `followUpTasks` row whose `origin` is `phase-continuation` MUST all point to the same `errorAnalysis.routing.nextTaskType` target. The schema enforces only the presence of a `phase-continuation` row; `validators/validate-run.py::_validate_error_analysis_consistency` enforces exact target agreement and uniqueness.
123
+ - **Implementation-option-selection comparison.** When `header.taskType` is `implementation-option-selection`, populate `implementationOptionSelection` from the converged direction-selection findings. Preserve every merged or rejected raw candidate in `candidateAudit`, and put at most three selectable candidates in `rankedOptions`. Each displayed candidate carries its requirement coverage, scope commitments, criterion scores, feasibility votes, safety blockers, unresolved feasibility facts, planning invariants, and exact coverage summary. In each displayed candidate, `expectedChangeAreas` names direction-level change surfaces, never exact file paths or an exact file list. `expectedVerification` names direction-level verification signals, never a stage list or executable test commands. `schemas/final-report-v2.0.schema.json` enforces the displayed-summary constants and the three-option cap; semantic recalculation belongs to `validators/validate-run.py`.
124
+ - **Implementation-planning direction branch.** For `planningContract: selected-direction`, read `selectedDirectionRef` and its snapshot, then preserve their core mechanism, architecture boundaries, and planning invariants in `directionRealization`. Materialize files, interfaces, stages, validation, rollback, and bidirectional original-requirement links without candidate generation, scoring, recommendation, or user candidate selection. Author exactly one `P-Dir-1` whose payload is the complete `directionRealization`; its verifier checks those preserved properties and any hidden direction change. If the direction must change, author `direction-invalidated` and no execution queue. Legacy candidate-comparison reruns retain Option Candidates, trade-offs, Recommended Option, and `P-Opt-*` semantics.
125
+
126
+ ```json
127
+ {
128
+ "candidateDetailBoundary": {
129
+ "expectedChangeAreas": "direction-level-only",
130
+ "expectedVerification": "direction-level-signals-only",
131
+ "forbidden": ["exact-file-lists", "stage-lists", "test-commands"]
132
+ }
133
+ }
134
+ ```
111
135
  - **Human narrative.** Populate required `humanSummary` and the selected task block's `userNarrative`. Human-visible analysis facts must not exist only in Markdown; HTML is derived independently and can use only data.json. Keep worker discussion and audit details in `crossVerification`, `executionStatus`, and `tokenUsage`, outside the human narrative fields.
112
136
  - **External QA advisory.** A Tier 3 entry requiring `db`, `http`, or
113
137
  `external` may be non-PASS without changing approval or final verdict. Render
@@ -116,7 +140,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
116
140
  and add the exact rerun command to `recommendedNextSteps`. Never turn this
117
141
  advisory alone into a clarification, Acceptance Blocker, conditional
118
142
  acceptance condition, or blocked routing.
119
- - **§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`, `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. The schema `allOf` / `contains` clause enforces row presence, not exact route-target agreement or uniqueness; phase validation must enforce those error-analysis semantics as specified above.
143
+ - **§7 phase-continuation row (mandatory for non-terminal task-types).** When `header.taskType` is one of `requirements-discovery` / `implementation-option-selection` / `implementation-planning` / `error-analysis` / `implementation` / `final-verification`, `followUpTasks` MUST contain at least one row whose `origin` is `phase-continuation`, `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. The schema `allOf` / `contains` clause enforces row presence, not exact route-target agreement or uniqueness; phase validation must enforce those error-analysis semantics as specified above.
120
144
  - **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.
121
145
  - **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).
122
146
  - **Reading Confirmation** goes at `**Audit sidecar path:**` per the selected report-writer preamble's `Required reading` section — never in the data.json or the main worker-results file.
@@ -129,10 +153,10 @@ Rules (the schema enforces most of these — they are listed here so you know *w
129
153
  - Cite file paths and line numbers in every `evidence.primary[].source` / `consensus[].evidence` cell.
130
154
  - Preserve every analysis worker's ticket tagging — every row's `ticketId` field carries the ticket key or the task-fallback. For single-ticket runs, set `ticketCoverage` to `{"singleTicket": "<ticket>"}`. For runs that do not require ticket tagging (`release-handoff`, `final-verification`), set `ticketCoverage` to `{"omit": true}`.
131
155
  - For `requirements-discovery`, `error-analysis`, and `implementation-planning`, populate the top-level `endStateCoverage` with exactly one row per end-state id the brief declares — no more, no fewer. `disposition` is one of `addressed` / `deferred` / `not-applicable` / `blocked`. `addressed` requires a `coveredBy` anchor in THIS phase's own deliverable (requirements-discovery: the routing decision, the fan-out unit id, or the `C-NNN` clarification; error-analysis: the root-cause candidate or the next diagnostic; implementation-planning: the `R-NNN` row); every other disposition requires a `rationale`. Do not author a goal of your own here and do not restate the brief — this table records only how this phase accounted for what the reporter already pinned. When the brief declares no end-state ids (a brief authored before those sections existed), omit the field entirely. **Enforced:** `validators/validate-run.py` `_validate_end_state_coverage`.
132
- - For `implementation-planning`, populate `implementationPlanning.requirementCoverage` with one row per concrete requirement from the brief / packet, using IDs `R-001`, `R-002`, ... in source order. A `covered` row's `coveredBy` MUST name the specific Option Candidate plus Stage/Step that satisfies the requirement. Use `status: "covered"` only when the report's plan actually covers it; use `documented-deviation` only when `coveredBy` states the concrete alternative and the row records non-empty unique `decisionRefs` plus `approvalDisposition`. Each `C-NNN` ref must name a clarification in this report; each `D-NNNN` ref must name a `decisionDrafts[].number`. `approvalDisposition: "accepted"` requires a referenced clarification with `status: answered|resolved` and non-empty `userInput`; `approvalDisposition: "blocked C-NNN"` requires that same-report clarification to be `status: open, blocks: approval`. Otherwise use `gap` or `blocked C-NNN` and ensure the corresponding `Clarification Items` row blocks approval. Do not collapse this into `ticketCoverage`; ticket coverage is not requirement coverage. **Enforced:** `schemas/final-report-v2.0.schema.json` `$defs.ImplementationRequirementCoverageRow` and `validators/validate-run.py` `_validate_requirement_deviations`.
133
- - For `implementation-planning`, each `requirementCoverage` row's `source` is a graded cell, not prose — free text like `"carry-in from requirements-discovery C-001"` is rejected. Write exactly one of: `brief:EB-001` / `brief:PB-001` / `brief:EO-001`, an end-state id the brief declares — when the brief pins ids, citing a heading instead is rejected, because every brief carries the same generic headings and a heading cannot say WHICH reporter line the requirement came from (only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it); `derived:R-NNN — <one-line reason>`, whose chain must terminate at a `brief:` or `contract:` row of the same table without cycling; or `contract:<rule>`, for artifacts okstra's own phase contract mandates, whose allowlist is exactly the two tokens `decision-record-step` (the §5.4 Decision Drafts materialization step) and `glossary-step` (the glossary proposal step) — any other rule name is rejected, so never invent one. (Maintainer SSOT for that allowlist: `scripts/okstra_ctl/scope_provenance.py` in the okstra repo.) A requirement you cannot source this way does not belong in the table: put it in `clarificationItems[]` with `Blocks=approval`. **Enforced:** `validators/validate-run.py` `_validate_requirement_provenance`. In the same table, anchor every stage number in `coveredBy` to a `Stage` / `Stages` word (`Stage 2`, `Stages 1-3`) — `_validate_stage_has_requirement` reads that cell as prose and fails the plan when a Stage Map stage is cited by no row.
134
- - 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).
135
- - For `implementation-planning`, populate `implementationPlanning.variationPointAnalysis` — a `hasMultipleImplementations` judgement synthesized from the analysis workers' output, not a field filled in last. When it is `true`, write one `points[]` row per varying behavior carrying `behavior`, the two or more `implementations` that serve it, `evidence` (a `path:line`, or the sibling task / stage that already implements that behavior), and an `extractionDecision` of `extract` / `interfaceKind` / `coveredBy` (the Stage Map stage that builds the interface) / `rationale`; when it is `false`, write a non-empty `noVariationRationale` and leave `points` empty (the two branches are mutually exclusive). Do NOT pass a boilerplate rationale — `false` is the cheaper field to fill, and a `false` declaration the brief or the sibling code in the workers' evidence contradicts is a `P-Var` DISAGREE, not a saving. Also populate `implementationPlanning.recommendedOption.testSeams`: one row per boundary a test injects at and replaces, each carrying `boundary` / `injectedAs` / `replacedInTest`. An empty list is a conscious "no seam needed" claim, never a default for a field nobody filled. The schema excerpt enumerates both row shapes — author against it. (Maintainer SSOT for these two rules: the `Required deliverable shape` bullet in `prompts/profiles/implementation-planning.md` in the okstra repo; that path is not resolvable here, so it is provenance, not a file to open.) **Enforced:** `schemas/final-report-v2.0.schema.json` `$defs.VariationPointAnalysis` / `$defs.VariationPoint` (the block is in `implementationPlanning.required`) plus `testSeams` in `$defs.RecommendedOption`'s `required`; `validators/validate-run.py` `_validate_variation_point_analysis` rejects a rationale-less `false`, a `false` carrying points, a `true` with no point, an `extract: true` decision leaving `interfaceKind` or `coveredBy` empty, and a hexagonal project extracting as anything but a port; and every point becomes a `P-Var-*` plan item judged in §5.5.9.
156
+ - For selected-direction `implementation-planning`, preserve each original requirement ID and populate its `stageRefs`, `stepRefs`, `validationRefs`, and `fileRefs`; `validate_selected_direction_plan` enforces forward and reverse exact coverage. For legacy candidate-comparison `implementation-planning`, populate `implementationPlanning.requirementCoverage` with one row per concrete requirement from the brief / packet, using IDs `R-001`, `R-002`, ... in source order. A `covered` row's `coveredBy` MUST name the specific Option Candidate plus Stage/Step that satisfies the requirement. Use `status: "covered"` only when the report's plan actually covers it; use `documented-deviation` only when `coveredBy` states the concrete alternative and the row records non-empty unique `decisionRefs` plus `approvalDisposition`. Each `C-NNN` ref must name a clarification in this report; each `D-NNNN` ref must name a `decisionDrafts[].number`. `approvalDisposition: "accepted"` requires a referenced clarification with `status: answered|resolved` and non-empty `userInput`; `approvalDisposition: "blocked C-NNN"` requires that same-report clarification to be `status: open, blocks: approval`. Otherwise use `gap` or `blocked C-NNN` and ensure the corresponding `Clarification Items` row blocks approval. Do not collapse this into `ticketCoverage`; ticket coverage is not requirement coverage. **Enforced:** `schemas/final-report-v2.0.schema.json` `$defs.ImplementationRequirementCoverageRow` and `validators/validate-run.py` `_validate_requirement_deviations`.
157
+ - For legacy candidate-comparison `implementation-planning`, each `requirementCoverage` row's `source` is a graded cell, not prose — free text like `"carry-in from requirements-discovery C-001"` is rejected. Write exactly one of: `brief:EB-001` / `brief:PB-001` / `brief:EO-001`, an end-state id the brief declares — when the brief pins ids, citing a heading instead is rejected, because every brief carries the same generic headings and a heading cannot say WHICH reporter line the requirement came from (only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it); `derived:R-NNN — <one-line reason>`, whose chain must terminate at a `brief:` or `contract:` row of the same table without cycling; or `contract:<rule>`, for artifacts okstra's own phase contract mandates, whose allowlist is exactly the two tokens `decision-record-step` (the §5.4 Decision Drafts materialization step) and `glossary-step` (the glossary proposal step) — any other rule name is rejected, so never invent one. (Maintainer SSOT for that allowlist: `scripts/okstra_ctl/scope_provenance.py` in the okstra repo.) A requirement you cannot source this way does not belong in the table: put it in `clarificationItems[]` with `Blocks=approval`. **Enforced:** `validators/validate-run.py` `_validate_requirement_provenance`. In the same table, anchor every stage number in `coveredBy` to a `Stage` / `Stages` word (`Stage 2`, `Stages 1-3`) — `_validate_stage_has_requirement` reads that cell as prose and fails the plan when a Stage Map stage is cited by no row.
158
+ - For legacy candidate-comparison `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).
159
+ - For `implementation-planning`, populate `implementationPlanning.variationPointAnalysis` — a `hasMultipleImplementations` judgement synthesized from the analysis workers' output, not a field filled in last. When it is `true`, write one `points[]` row per varying behavior carrying `behavior`, the two or more `implementations` that serve it, `evidence` (a `path:line`, or the sibling task / stage that already implements that behavior), and an `extractionDecision` of `extract` / `interfaceKind` / `coveredBy` (the Stage Map stage that builds the interface) / `rationale`; when it is `false`, write a non-empty `noVariationRationale` and leave `points` empty (the two branches are mutually exclusive). Do NOT pass a boilerplate rationale. Populate test seams under `implementationPlanning.directionRealization.testSeams` for selected-direction plans and under `implementationPlanning.recommendedOption.testSeams` for legacy candidate-comparison plans. An empty list is a conscious "no seam needed" claim, never a default for a field nobody filled. Every point becomes a `P-Var-*` plan item judged in §5.5.9.
136
160
  - When the `Task Type` is `improvement-discovery`, populate `improvementDiscovery.candidates[]`, `improvementDiscovery.lensCoverage[]`, `improvementDiscovery.selectionLimit`, and `improvementDiscovery.userNarrative`. Each candidate carries the 11 logical fields enforced by `validators/validate_improvement_report.py`; each lens-coverage row records candidate IDs or an evidence-backed no-candidate rationale. Source IDs, lens names, and worker prefixes from `scripts/okstra_ctl/improvement_lenses.py`. The standard renderer derives the AI handoff Markdown; never author a free-form improvement report.
137
161
 
138
162
  Write the three completion artifacts and the separate audit sidecar with your `Write` tool — that is the canonical authoring path, and okstra ships no hook that blocks `.md` writes (its seeded settings carry no `PreToolUse` entry at all — only the session/subagent lifecycle hooks `SessionStart` compact-reminder, `SessionEnd` trace-cleanup, and `SubagentStop` / `TaskCompleted` pane reclaim, none of which can intercept a tool call). 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. After writing data.json, invoke the renderer (`Bash`): `okstra render-final-report <data.json path>`, then write the Worker Result Path pointer. Confirm data.json, rendered Markdown, the pointer, and the audit sidecar exist before responding with a short status line prefixed by your model identity, per the preamble §"Return message to the lead". **Enforced:** dispatch `completionPaths` requires the first three files and `validators/validate_session_conformance.py` validates the audit sidecar.
@@ -175,6 +175,10 @@ while [[ $# -gt 0 ]]; do
175
175
  CLARIFICATION_RESPONSE_PATH="$(require_option_value --clarification-response "${2-}")"
176
176
  shift 2
177
177
  ;;
178
+ --selected-direction)
179
+ SELECTED_DIRECTION_PATH="$(require_option_value --selected-direction "${2-}")"
180
+ shift 2
181
+ ;;
178
182
  --task-key)
179
183
  TASK_KEY_INPUT="$(require_option_value --task-key "${2-}")"
180
184
  shift 2
@@ -233,7 +237,7 @@ while [[ $# -gt 0 ]]; do
233
237
  printf ' hint: did you mean --task-id?\n' >&2
234
238
  ;;
235
239
  esac
236
- printf ' valid options: --render-only --resume-clarification --yes --workers --lead-provider --lead-model --claude-model --codex-model --antigravity-model --worker-model --report-writer-provider --report-writer-model --lead-runtime --executor --critic --related-tasks --work-category --task-type --project-id --project-root --task-group --task-id --task-brief --directive --base-ref --fix-cycle --clarification-response --task-key --approved-plan --approve --implementation-option --stage --stages --qa-waiver --no-plan-verification -h|--help\n' >&2
240
+ printf ' valid options: --render-only --resume-clarification --yes --workers --lead-provider --lead-model --claude-model --codex-model --antigravity-model --worker-model --report-writer-provider --report-writer-model --lead-runtime --executor --critic --related-tasks --work-category --task-type --project-id --project-root --task-group --task-id --task-brief --directive --base-ref --fix-cycle --clarification-response --selected-direction --task-key --approved-plan --approve --implementation-option --stage --stages --qa-waiver --no-plan-verification -h|--help\n' >&2
237
241
  usage
238
242
  exit 1
239
243
  ;;
@@ -44,6 +44,7 @@ ANALYSIS_PROFILE=""
44
44
  DIRECTIVE=""
45
45
  FIX_CYCLE=""
46
46
  CLARIFICATION_RESPONSE_PATH=""
47
+ SELECTED_DIRECTION_PATH=""
47
48
  APPROVED_PLAN_PATH=""
48
49
  APPROVE_PLAN_ACK="false"
49
50
  # implementation 전용: 유저가 고른 Option Candidate 이름. 빈 값이면 implementation
@@ -43,6 +43,9 @@ optional arguments:
43
43
  input so the lead can reconcile each prior Q*. Use this for scripted or
44
44
  CI runs where the answer file is already prepared. Interactive users
45
45
  should prefer --resume-clarification, which wraps this flag.
46
+ --selected-direction Path to a validated implementation-option-selection final report.
47
+ Required for a new implementation-planning run. Existing planning
48
+ reruns continue to use --clarification-response with their prior report.
46
49
  --approved-plan Path to the approved final-report.md from a prior implementation-planning run.
47
50
  Required when --task-type=implementation; the file MUST contain a recorded user approval marker.
48
51
  --approve Treat the user's CLI invocation itself as the plan-approval signal. Only meaningful
@@ -187,6 +187,7 @@ okstra execution summary:
187
187
  task brief: ${BRIEF_PATH}
188
188
  directive: ${DIRECTIVE:-None}
189
189
  clarification response: ${CLARIFICATION_RESPONSE_PATH:-None}
190
+ selected direction: ${SELECTED_DIRECTION_PATH:-None}
190
191
  workers override: ${WORKERS_OVERRIDE:-None}
191
192
  executor (implementation only): ${EXECUTOR_OVERRIDE:-default(claude)}
192
193
  approved plan: ${APPROVED_PLAN_PATH:-None}
@@ -237,6 +238,7 @@ PY_ARGS=(
237
238
  [[ "$APPROVE_PLAN_ACK" == "true" ]] && PY_ARGS+=(--approve)
238
239
  [[ -n "${IMPLEMENTATION_OPTION-}" ]] && PY_ARGS+=(--implementation-option "$IMPLEMENTATION_OPTION")
239
240
  [[ -n "${CLARIFICATION_RESPONSE_PATH-}" ]] && PY_ARGS+=(--clarification-response "$CLARIFICATION_RESPONSE_PATH")
241
+ [[ -n "${SELECTED_DIRECTION_PATH-}" ]] && PY_ARGS+=(--selected-direction "$SELECTED_DIRECTION_PATH")
240
242
  [[ -n "${WORK_CATEGORY-}" ]] && PY_ARGS+=(--work-category "$WORK_CATEGORY")
241
243
  [[ -n "${BASE_REF-}" ]] && PY_ARGS+=(--base-ref "$BASE_REF")
242
244
  [[ -n "${STAGE-}" ]] && PY_ARGS+=(--stage "$STAGE")
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: direction-selection-worker
3
+ version: 1
4
+ kind: role
5
+ appliesTo: direction-selection-worker
6
+ ---
7
+
8
+ # Direction Selection Worker Duty Contract
9
+
10
+ ## Responsibility
11
+
12
+ Compare feasible directions before planning in `candidate-comparison` mode, or validate one preselected direction in `preselected-validation` mode.
13
+
14
+ ## Required conduct
15
+
16
+ In `candidate-comparison` mode, inspect the evidence needed to distinguish candidates, submit no more than three candidates, state the strongest counterevidence for each one, and map every candidate to the stable brief end-state IDs it satisfies, preserves, or leaves unresolved. In `preselected-validation` mode, validate the one preselected direction against that evidence and mapping; the worker must not generate new candidates.
17
+
18
+ ## Decision principles
19
+
20
+ Score candidates against the same stated criteria. Prefer evidence-backed feasibility over familiarity, and preserve a rejected candidate when its evidence or trade-off could affect the later planning decision.
21
+
22
+ ## Authority and boundaries
23
+
24
+ Select directions only. Do not edit project state, author detailed file lists, create stage maps, prescribe execution commands, or approve an implementation plan.
25
+
26
+ ## Evidence standard
27
+
28
+ Each candidate, score, counterexample, and requirement mapping cites inspected evidence. State uncertainty when the code or brief cannot establish a criterion.
29
+
30
+ ## Collaboration contract
31
+
32
+ Reason independently from other workers. Do not collapse overlapping candidates or seek agreement before convergence; provide the evidence that lets the lead merge and re-evaluate them.
33
+
34
+ ## Completion criteria
35
+
36
+ In `candidate-comparison` mode, every submitted candidate has a criterion score, counterevidence, and stable requirement mapping. In `preselected-validation` mode, the one preselected direction has a validation result, counterevidence, and stable requirement mapping. Rejected candidates retain their audit reason and evidence.
37
+
38
+ ## Forbidden conduct
39
+
40
+ Do not turn a candidate into a detailed implementation plan, invent a requirement ID, omit contrary evidence, present a selection as user approval, or generate a new candidate in `preselected-validation` mode.
41
+
42
+ ## Blocked-state reporting
43
+
44
+ Name the missing evidence or unresolved requirement that prevents a candidate comparison, the inspection attempted, and the criterion it leaves unscored.
@@ -9,11 +9,19 @@ appliesTo: planning-worker
9
9
 
10
10
  ## Responsibility
11
11
 
12
- Produce an implementation direction a person can approve: feasible options with their trade-offs, one recommendation, and stages that carry the requirement to a verifiable end — all without writing the implementation.
12
+ Produce an executable implementation plan without writing the implementation.
13
+
14
+ ### Selected-direction responsibility
15
+
16
+ When `selected-direction.json` is present, read it and the requirements ledger first. Preserve the selected direction's core mechanism, architecture boundaries, user constraints, and planning invariants. Concretize only its files, interfaces, stages, validation, and rollback. Link every file and stage back to original requirements, and link every original requirement forward to its files, stages, and checks. If current code evidence requires changing the direction, return `direction-invalidated` with evidence and stop. Direction selection remains upstream of this branch.
17
+
18
+ ### Legacy candidate-comparison compatibility
19
+
20
+ For a legacy rerun without `selected-direction.json`, retain Option Candidates, trade-offs, the Recommended Option, and `P-Opt-*` verification semantics. Only this compatibility branch compares alternatives or chooses a recommendation.
13
21
 
14
22
  ## Required conduct
15
23
 
16
- Read the current state of the code the work touches before drafting options; compare at least two feasible options on evidence from that code unless the decision is already settled upstream; tie the recommendation to the trade-off that decides it; split the work into stages along real dependencies with each stage's validation signal and rollback; and connect every requirement to the stage that satisfies it.
24
+ Read the current state of the code the work touches before planning. Split work into stages along real dependencies with each stage's validation signal and rollback. Connect every requirement to the stage that satisfies it. In the selected-direction branch, verify direction preservation before adding plan detail. In the legacy branch, compare options on current-code evidence.
17
25
 
18
26
  ## Decision principles
19
27
 
@@ -29,11 +37,11 @@ Every cited path, symbol, and command must exist as written and be executable in
29
37
 
30
38
  ## Collaboration contract
31
39
 
32
- Draft independently of the other planners rather than converging on the first option proposed. Leave the choice between competing plans and the resolution of contested items to convergence and the lead, and hand the executor a plan complete enough to follow without re-deriving the decisions behind it.
40
+ Draft independently of the other planners. Leave contested plan details to convergence and the lead, and hand the executor a plan complete enough to follow without re-deriving the selected direction.
33
41
 
34
42
  ## Completion criteria
35
43
 
36
- Options, trade-offs, the recommendation, the stages with their dependencies, validation and rollback, and requirement coverage are all present and mutually consistent; every unresolved decision is recorded as such rather than assumed; and no stage depends on work the plan never places.
44
+ For selected-direction planning, the snapshot and requirements ledger are preserved; files, interfaces, stages, validation, rollback, and requirements links are mutually consistent; planning invariants have evidence; and no hidden direction change is present. For legacy candidate-comparison compatibility, Option Candidates, trade-offs, the Recommended Option, and `P-Opt-*` semantics remain present. Every unresolved decision is recorded rather than assumed, and no stage depends on work the plan never places.
37
45
 
38
46
  ## Forbidden conduct
39
47
 
@@ -37,7 +37,7 @@
37
37
  | `projectId` | Project ID |
38
38
  | `taskGroup` | Task group |
39
39
  | `taskId` | Task ID |
40
- | `taskType` | Analysis type (requirements-discovery, error-analysis, implementation-planning, implementation, final-verification, release-handoff, plus the sidetrack improvement-discovery) |
40
+ | `taskType` | Analysis type (requirements-discovery, error-analysis, implementation-option-selection, implementation-planning, implementation, final-verification, release-handoff, plus the sidetrack improvement-discovery) |
41
41
  | `workCategory` | bugfix / feature / improvement / refactor / ops / unknown |
42
42
  | `recommendedWorkers` | List of selected workers |
43
43
  | `currentStatus` | Current task status |
@@ -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. 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.
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 7 task-type lifecycle phases (`requirements-discovery` → `error-analysis` → `implementation-option-selection` → `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
 
@@ -48,7 +48,7 @@ Configure this in the `convergence` block of `task-manifest.json`. If the block
48
48
  | `enabled` | `true` | If `false`, skip the convergence loop and use the existing consensus/divergence method |
49
49
  | `maxRounds` | phase-aware: `1` for `requirements-discovery`, `2` otherwise (range 1–3) | Maximum number of re-verification rounds. Discovery's routing/missing-input outputs gain little from a second round; other phases (especially `error-analysis`) keep `2`. Lead resolves the effective value when the manifest omits the key and records it in `config.effectiveMaxRounds` of the convergence state artifact. |
50
50
  | `verificationMode` | `"lightweight"` | `"lightweight"` or `"full-reanalysis"` |
51
- | `adversarial` | phase-aware: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise | When `true`, Phase 5.5 runs in **adversarial mode** (see §"Adversarial Verification Mode"): verifiers actively try to refute each finding, the burden of proof sits on the claim, and `verificationMode` is forced to `"full-reanalysis"` scoped to the finding's cited evidence. Resolved by `scripts/okstra_ctl/render.py` `_build_convergence_block` and recorded in `config.adversarial` of the convergence state artifact. |
51
+ | `adversarial` | phase-aware: `true` for `requirements-discovery` / `error-analysis` / `implementation-option-selection` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise | When `true`, Phase 5.5 runs in **adversarial mode** (see §"Adversarial Verification Mode"): verifiers actively try to refute each finding, the burden of proof sits on the claim, and `verificationMode` is forced to `"full-reanalysis"` scoped to the finding's cited evidence. Resolved by `scripts/okstra_ctl/render.py` `_build_convergence_block` and recorded in `config.adversarial` of the convergence state artifact. |
52
52
 
53
53
  **Auto-disable rule (BLOCKING).** Convergence requires ≥2 analyser workers to produce a meaningful consensus tally. When the active profile's `Required workers:` block (see `prompts/profiles/*.md`) resolves to fewer than 2 analyser workers — e.g. `release-handoff` (zero analyser workers, lead-only) — the lead MUST treat `convergence.enabled` as `false` for that run regardless of manifest configuration, skip Phases 5.5 and the plan-body verification round ([plan-body-verification](./plan-body-verification.md)), and record `finalState: "converged"` with `totalRounds: 0`, `round2SkippedReason: "auto-disabled"`, an empty `roundHistory`, and an explanatory note in `config` (e.g. `"autoDisabled": "fewer-than-two-analysers"`). The plan-body round inherits the same rule via its `gating=false` advisory path.
54
54
 
@@ -160,7 +160,7 @@ Use each finding as a guide but reanalyze the original code/data yourself. High
160
160
 
161
161
  ## Adversarial Verification Mode
162
162
 
163
- Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, `implementation-planning`, `project-analysis`, `feature-analysis`, and `change-impact-analysis`; 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.
163
+ Active only when `config.adversarial == true` (default for `requirements-discovery`, `error-analysis`, `implementation-option-selection`, `implementation-planning`, `project-analysis`, `feature-analysis`, and `change-impact-analysis`; 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.
164
164
 
165
165
  ### Read-only analysis task contract
166
166
 
@@ -361,7 +361,7 @@ Lightweight reverify does not require the original `analysis-packet.md`, `analys
361
361
  - **Lightweight mode**: the clause directly contradicts the "Do NOT re-analyze the original source materials" instruction below. Including it forces workers to re-read the entire instruction-set per round per worker (3 workers × 2 rounds × 5+ files in the worst case) for no quality gain.
362
362
  - **Full-reanalysis mode**: workers DO need to re-read source materials, but only the analysis-worker file list (no `final-report-template.md`). If lead chooses to inject a reading clause here, it MUST mirror the audience-scoped enumeration in [okstra-lead-contract](./okstra-lead-contract.md) Phase 2 (no template).
363
363
 
364
- This is the single largest avoidable cost in `requirements-discovery`, `error-analysis`, and `implementation-planning` runs. Treat as mandatory.
364
+ This is the single largest avoidable cost in `requirements-discovery`, `error-analysis`, `implementation-option-selection`, and `implementation-planning` runs. Treat as mandatory.
365
365
 
366
366
  ### Lightweight Re-verification Prompt
367
367
 
@@ -565,7 +565,7 @@ Save it to `runs/<task-type>/state/convergence-<task-type>-<seq>.json`.
565
565
  Schema rules:
566
566
 
567
567
  - `schemaVersion`: literal string `"1.3"` for all new runs — both adversarial and collaborative. Historical readers accept `"1.0"` / `"1.1"` / `"1.2"` unchanged and never rewrite those artifacts during validation. v1.3 adds the strict coverage-critic ledger and rejects unknown top-level fields; work-state remains v1.0.
568
- - `config.adversarial`: boolean. `true` when this run used adversarial verification (default for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`). When `true`, `config.verificationMode` is `"full-reanalysis"` (scoped) and every `disagree` vote carries a non-null `disagreeBasis`.
568
+ - `config.adversarial`: boolean. `true` when this run used adversarial verification (default for `requirements-discovery` / `error-analysis` / `implementation-option-selection` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`). When `true`, `config.verificationMode` is `"full-reanalysis"` (scoped) and every `disagree` vote carries a non-null `disagreeBasis`.
569
569
  - `config.effectiveMaxRounds`: the integer the lead actually used after resolving the phase-aware default (`1` for `requirements-discovery`, `2` otherwise). MUST equal `config.maxRounds` when the manifest explicitly set it.
570
570
  - `findings[].ticketIds`: array of ticket keys from Phase 4 grouping (parsed per the Round 0 step 5 rule). It is empty when the phase does not require ticket tagging; `"unknown"` is not a ticket key and must not be synthesized.
571
571
  - `findings[].rounds[].votes.<worker>.verdict`: enum, one of `agree | disagree | supplement | verification-error`. Lower-case tokens; map upper-case AGREE/DISAGREE/SUPPLEMENT verdicts emitted by workers to their lower-case form and map the input alias `unverifiable` to persisted `verification-error`. The latter represents either a terminal non-result dispatch or a completed dispatch that could not verify a particular finding (§"Worker failure handling in reverify"). Every vote has a non-empty `explanation`.
@@ -39,7 +39,7 @@ Read-side inspection (`/okstra-inspect`) and scheduling (`/okstra-schedule-gen`)
39
39
  | 5. Completion wait | Call `await_workers` and verify terminal state plus required artifacts | selected runtime adapter + `team-contract` |
40
40
  | 5.5 Convergence | Semantically group findings, then drive deterministic state transitions through `ConvergenceEngine` via `okstra convergence` | `convergence` |
41
41
  | 5.6 Critic pass | (opt-in) fresh one-shot critic pass through `redispatch_worker`: coverage gaps (discovery/error-analysis/impl-planning) or acceptance devil's-advocate (final-verification). The critic dispatch fires concurrently with the first 5.5 reverify round (its input is fixed at Round 0); gap/blocker verification (one round) completes here | `convergence` "Coverage critic pass" / "Acceptance critic pass" |
42
- | 6. Synthesis | Dispatch Report writer worker, review draft. **For `implementation-planning`: then run the Phase 6 plan-body verification sub-step (see Phase 6 section below).** | `report-writer` + `plan-body-verification` (sub-step) |
42
+ | 6. Synthesis | Dispatch Report writer worker, review draft. **For `implementation-planning`: then run the Phase 6 plan-body verification sub-step (see Phase 6 section below). Selected-direction plans verify `P-Dir-1`; legacy plans retain `P-Opt-*`.** | `report-writer` + `plan-body-verification` (sub-step) |
43
43
  | 7. Persist | Call `collect_usage`, update manifests, run the cleanup approval gate, then call `shutdown_workers` only on approval | selected runtime adapter + `report-writer` + this contract |
44
44
 
45
45
  ## Core operating contract
@@ -60,6 +60,7 @@ A single okstra run executes **exactly one** lifecycle phase. The phase is given
60
60
  |-----------------|-----------------|-------------------|
61
61
  | `requirements-discovery` | classification, routing decision, missing-input list, next-phase recommendation | code edits, plan documents, build/test execution that mutates state |
62
62
  | `error-analysis` | evidence, root-cause hypotheses, reproduction gaps, validation paths | code edits, implementation design, build/migration/deploy execution |
63
+ | `implementation-option-selection` | candidate comparison, counterevidence, criterion scores, requirement mappings, rejected-candidate audit | code edits, tests/builds, detailed file lists, stage maps, execution commands, plan approval |
63
64
  | `implementation-planning` | option matrix, trade-offs, dependencies, recommended order, validation/rollback strategy, Tier3 conformance scripts + manifest under the task-root `qa/` tree, **explicit user-approval request** | source code edits, file writes outside the run's `reports/`, `prompts/`, `state/`, `manifests/`, `worker-results/`, `status/`, `sessions/` directories and the task-root `qa/` tree, build/migration/deploy execution |
64
65
  | `implementation` | code edits authorised by an approved plan, accompanying tests | starting work without an approved `implementation-planning` final report carried in via `--clarification-response` or referenced in the brief |
65
66
  | `final-verification` | acceptance verdict, residual risk, regression notes; read-only execution of existing test/validation commands, run-artifact writes (qa result sidecars, `okstra handoff record-verified` on acceptance), and qaEnv-replica-only conformance runs are permitted | source code edits, refactors, scope expansion, mutations of the project or shared environments |
@@ -188,7 +189,7 @@ Executor is chosen at run-prep time via `--executor <claude|codex|antigravity>`
188
189
 
189
190
  `okstra-ctl` provisions dedicated `git worktree`s at run-prep time. Lead, the Executor, and every verifier MUST treat the provisioned worktree as the canonical working directory regardless of task-type.
190
191
 
191
- - **Task-key worktree (non-`implementation` phases):** `requirements-discovery`, `error-analysis`, and `implementation-planning` share one worktree per task-key so phase N inherits the working-tree state phase N-1 left behind. Location: `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (override `OKSTRA_HOME` only for tests). All segments are sanitised — `/`, `:`, and other special chars collapse to `-`.
192
+ - **Task-key worktree (non-`implementation` phases):** `requirements-discovery`, `error-analysis`, `implementation-option-selection`, and `implementation-planning` share one worktree per task-key so phase N inherits the working-tree state phase N-1 left behind. Location: `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (override `OKSTRA_HOME` only for tests). All segments are sanitised — `/`, `:`, and other special chars collapse to `-`.
192
193
  - **Stage worktree (`implementation`):** stage-isolated — one run = one stage, each in its own worktree at `.../<task-id-segment>/stage-<N>/` on its own branch. Single-stage `final-verification` (`--stage <N>`) reuses that stage worktree read-only; whole-task `final-verification` operates on the task-key worktree.
193
194
  - Branch: `<work-category-namespace>/<task-id-segment>` (e.g. `feature/dev-9436`, `fix/dev-7311`); a stage worktree appends `-s<N>` (e.g. `feature/dev-9436-s2`). The task-key worktree is branched from the user-chosen `--base-ref` (default: `HEAD` of the repo's **main** worktree) at the first phase's prep time; a stage worktree's base is resolved from its `depends-on` anchors at prep time. The resolved base SHA is recorded in `EXECUTOR_WORKTREE_BASE_REF`.
194
195
  - A global registry at `~/.okstra/worktrees/registry.json` (flock-guarded) reserves both task-keys and stage-keys (`<task-key>#stage-<N>`), mapping each to its path + branch, and prevents concurrent runs from colliding. Branch names are globally unique on this machine.
@@ -232,7 +233,7 @@ The `implementation` profile's thin core (`prompts/profiles/implementation.md`)
232
233
 
233
234
  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.
234
235
 
235
- 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.
236
+ This pattern is implementation-only. Other profiles (`requirements-discovery`, `error-analysis`, `implementation-option-selection`, `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.
236
237
 
237
238
  Extract from the compact intake files: task key, task type, work category, workflow lifecycle snapshot, selected worker roster, assigned models, worker result paths, worker prompt history paths, current run prompt directory, final report path, final status path, validator path, resume helper path, config-file references, deployment-manifest references, and their expected values or invariants.
238
239
 
@@ -330,7 +331,7 @@ Convergence is enabled by default. Configure via task-manifest.json:
330
331
  - `convergence.enabled`: true/false (default: true)
331
332
  - `convergence.maxRounds`: 1–3 — **phase-aware default**: `1` for `requirements-discovery`, `2` for all other task types
332
333
  - `convergence.verificationMode`: `"lightweight"` | `"full-reanalysis"` (default: `"lightweight"`; the adversarial phases below force `"full-reanalysis"`)
333
- - `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise. When `true`, Phase 5.5 runs in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
334
+ - `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-option-selection` / `implementation-planning` / `project-analysis` / `feature-analysis` / `change-impact-analysis`, `false` otherwise. When `true`, Phase 5.5 runs in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
334
335
 
335
336
  When `task-manifest.json` does not set `convergence.maxRounds`, lead MUST resolve the effective value via the phase-aware default above before entering Phase 5.5 and put it in the grouped input at `config.effectiveMaxRounds`.
336
337
 
@@ -377,7 +378,7 @@ After the Report writer worker draft is reviewed (or after the lead-authored fal
377
378
 
378
379
  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. The round's outcome is read from the final report's `### 5.5.9 Plan Body Verification` section and `implementationPlanning.planBodyVerification` in its data.json — it is not a separate lifecycle phase identifier.
379
380
 
380
- **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-*` / `P-Req-*` / `P-Prep-*`), verdict semantics (`AGREE` / `DISAGREE(a-f)` / `SUPPLEMENT`), classification rules, gate-result resolution, and the state-file schema at `runs/<task-type>/state/plan-body-verification.json`.
381
+ **REQUIRED RESOURCE:** Read [plan-body-verification](./plan-body-verification.md) for the round protocol, plan-item ID scheme (`P-Dir-1` for selected-direction; `P-Opt-*` for legacy candidate comparison; then `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*` / `P-Req-*` / `P-Prep-*`), verdict semantics (`AGREE` / `DISAGREE(a-f)` / `SUPPLEMENT`), classification rules, gate-result resolution, and the state-file schema at `runs/<task-type>/state/plan-body-verification.json`. For `P-Dir-1`, compare `directionRealization` with `selectedDirectionRef` and its snapshot: verify the core mechanism, architecture boundaries, planning invariants, and any hidden direction change.
381
382
 
382
383
  Distinct from Phase 5.5 finding convergence:
383
384