okstra 0.202.0 → 0.204.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 (258) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-registry.mjs +7 -7
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/install.mjs +50 -124
  5. package/dist/commands/lifecycle/install.mjs.map +1 -1
  6. package/dist/commands/memory/memory.mjs +41 -8
  7. package/dist/commands/memory/memory.mjs.map +1 -1
  8. package/dist/lib/install-assets.mjs +3 -0
  9. package/dist/lib/install-assets.mjs.map +1 -1
  10. package/dist/lib/runtime-manifest.mjs +2 -1
  11. package/dist/lib/runtime-manifest.mjs.map +1 -1
  12. package/dist/lib/types.d.mts +2 -1
  13. package/docs/architecture/storage-model.md +14 -11
  14. package/docs/architecture.md +25 -19
  15. package/docs/cli.md +15 -12
  16. package/docs/contributor-change-matrix.md +3 -2
  17. package/docs/performance-improvement-plan-v2.md +2 -3
  18. package/docs/project-structure-overview.md +35 -9
  19. package/docs/task-process/README.md +1 -1
  20. package/docs/task-process/common-flow.md +1 -1
  21. package/docs/task-process/final-verification.md +3 -1
  22. package/docs/task-process/implementation.md +1 -1
  23. package/docs/task-process/release-handoff.md +36 -39
  24. package/package.json +1 -2
  25. package/runtime/BUILD.json +2 -2
  26. package/runtime/agents/common.json +28 -0
  27. package/runtime/agents/operations/code-review.json +6 -0
  28. package/runtime/agents/operations/report-translation.json +6 -0
  29. package/runtime/agents/operations/schedule-verification.json +6 -0
  30. package/runtime/agents/roles/analyser.json +18 -0
  31. package/runtime/agents/roles/critic.json +18 -0
  32. package/runtime/agents/roles/designer.json +18 -0
  33. package/runtime/agents/roles/implementer.json +20 -0
  34. package/runtime/agents/roles/leader.json +20 -0
  35. package/runtime/agents/roles/planner.json +18 -0
  36. package/runtime/agents/roles/report-writer.json +19 -0
  37. package/runtime/agents/roles/translator.json +19 -0
  38. package/runtime/agents/roles/verifier.json +18 -0
  39. package/runtime/bin/lib/okstra/usage.sh +5 -5
  40. package/runtime/prompts/duties/acceptance-critic.json +32 -0
  41. package/runtime/prompts/duties/acceptance-verifier.json +32 -0
  42. package/runtime/prompts/duties/analysis-worker.json +32 -0
  43. package/runtime/prompts/duties/code-reviewer.json +32 -0
  44. package/runtime/prompts/duties/diagnosis-worker.json +32 -0
  45. package/runtime/prompts/duties/direction-selection-worker.json +32 -0
  46. package/runtime/prompts/duties/discovery-worker.json +32 -0
  47. package/runtime/prompts/duties/implementation-executor.json +32 -0
  48. package/runtime/prompts/duties/implementation-verifier.json +32 -0
  49. package/runtime/prompts/duties/lead.json +32 -0
  50. package/runtime/prompts/duties/planning-worker.json +36 -0
  51. package/runtime/prompts/duties/report-writer.json +32 -0
  52. package/runtime/prompts/duties/reverification-worker.json +32 -0
  53. package/runtime/prompts/duties/schedule-verifier.json +32 -0
  54. package/runtime/prompts/duties/scope-critic.json +32 -0
  55. package/runtime/prompts/duties/technical-verification-worker.json +32 -0
  56. package/runtime/prompts/duties/translator.json +32 -0
  57. package/runtime/prompts/launch.template.md +2 -1
  58. package/runtime/prompts/lead/adapters/cmux.md +1 -1
  59. package/runtime/prompts/lead/convergence.md +4 -4
  60. package/runtime/prompts/lead/okstra-lead-contract.md +113 -4
  61. package/runtime/prompts/lead/plan-body-verification.md +6 -6
  62. package/runtime/prompts/lead/report-writer.md +3 -3
  63. package/runtime/prompts/profiles/_common-contract.md +2 -2
  64. package/runtime/prompts/profiles/_implementation-executor.md +4 -1
  65. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  66. package/runtime/prompts/profiles/change-impact-analysis.json +31 -0
  67. package/runtime/prompts/profiles/change-impact-analysis.md +0 -20
  68. package/runtime/prompts/profiles/error-analysis.json +39 -0
  69. package/runtime/prompts/profiles/error-analysis.md +0 -25
  70. package/runtime/prompts/profiles/feature-analysis.json +31 -0
  71. package/runtime/prompts/profiles/feature-analysis.md +0 -20
  72. package/runtime/prompts/profiles/final-verification.json +30 -0
  73. package/runtime/prompts/profiles/final-verification.md +3 -22
  74. package/runtime/prompts/profiles/forbidden-actions.json +4 -3
  75. package/runtime/prompts/profiles/implementation-option-selection.json +31 -0
  76. package/runtime/prompts/profiles/implementation-option-selection.md +0 -20
  77. package/runtime/prompts/profiles/implementation-planning.json +40 -0
  78. package/runtime/prompts/profiles/implementation-planning.md +4 -29
  79. package/runtime/prompts/profiles/implementation.json +30 -0
  80. package/runtime/prompts/profiles/implementation.md +1 -20
  81. package/runtime/prompts/profiles/improvement-discovery.json +31 -0
  82. package/runtime/prompts/profiles/improvement-discovery.md +0 -20
  83. package/runtime/prompts/profiles/project-analysis.json +31 -0
  84. package/runtime/prompts/profiles/project-analysis.md +0 -20
  85. package/runtime/prompts/profiles/release-handoff.json +5 -0
  86. package/runtime/prompts/profiles/release-handoff.md +71 -73
  87. package/runtime/prompts/profiles/requirements-discovery.json +39 -0
  88. package/runtime/prompts/profiles/requirements-discovery.md +0 -25
  89. package/runtime/prompts/profiles/technical-verification.json +39 -0
  90. package/runtime/prompts/profiles/technical-verification.md +0 -25
  91. package/runtime/prompts/wizard/prompts.ko.json +12 -17
  92. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -0
  93. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +3 -0
  94. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -1
  95. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -3
  96. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/worker-session.md +108 -0
  97. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -0
  98. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -0
  99. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -0
  100. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +8 -1
  101. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +8 -0
  102. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +23 -6
  103. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +6 -2
  104. package/runtime/python/okstra_ctl/agent/invocation.py +168 -113
  105. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +120 -0
  106. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +107 -2
  107. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -49
  108. package/runtime/python/okstra_ctl/analysis_packet.py +4 -1
  109. package/runtime/python/okstra_ctl/application/open_worker.py +6 -1
  110. package/runtime/python/okstra_ctl/assignment_resolver.py +16 -5
  111. package/runtime/python/okstra_ctl/cmux.py +69 -20
  112. package/runtime/python/okstra_ctl/code_review_target.py +16 -8
  113. package/runtime/python/okstra_ctl/conformance.py +43 -0
  114. package/runtime/python/okstra_ctl/consumers.py +6 -3
  115. package/runtime/python/okstra_ctl/container.py +31 -8
  116. package/runtime/python/okstra_ctl/context_cost.py +11 -15
  117. package/runtime/python/okstra_ctl/contract_refreeze.py +156 -0
  118. package/runtime/python/okstra_ctl/convergence_provenance.py +7 -1
  119. package/runtime/python/okstra_ctl/design_prep.py +34 -1
  120. package/runtime/python/okstra_ctl/dispatch_core.py +53 -27
  121. package/runtime/python/okstra_ctl/domain/host.py +5 -0
  122. package/runtime/python/okstra_ctl/domain/worker_runtime.py +10 -0
  123. package/runtime/python/okstra_ctl/error_report.py +4 -3
  124. package/runtime/python/okstra_ctl/execution_manifest.py +71 -18
  125. package/runtime/python/okstra_ctl/handoff.py +167 -277
  126. package/runtime/python/okstra_ctl/implementation_stage.py +9 -0
  127. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +113 -0
  128. package/runtime/python/okstra_ctl/lead_progress.py +1 -1
  129. package/runtime/python/okstra_ctl/legacy_model_selection.py +2 -2
  130. package/runtime/python/okstra_ctl/manager_cli.py +92 -4
  131. package/runtime/python/okstra_ctl/manager_launch.py +1 -1
  132. package/runtime/python/okstra_ctl/manager_paths.py +14 -3
  133. package/runtime/python/okstra_ctl/manager_store.py +210 -3
  134. package/runtime/python/okstra_ctl/manager_sync.py +4 -1
  135. package/runtime/python/okstra_ctl/manager_view.py +2 -1
  136. package/runtime/python/okstra_ctl/model_discovery.py +30 -0
  137. package/runtime/python/okstra_ctl/model_io/lines.py +14 -1
  138. package/runtime/python/okstra_ctl/model_io/renderers.py +4 -3
  139. package/runtime/python/okstra_ctl/models.py +1 -1
  140. package/runtime/python/okstra_ctl/next_phase.py +16 -6
  141. package/runtime/python/okstra_ctl/operation_invocation.py +86 -0
  142. package/runtime/python/okstra_ctl/option_comparison.py +168 -0
  143. package/runtime/python/okstra_ctl/path_hints.py +9 -0
  144. package/runtime/python/okstra_ctl/paths.py +3 -0
  145. package/runtime/python/okstra_ctl/profile_show.py +42 -1
  146. package/runtime/python/okstra_ctl/registry/host_discovery.py +20 -12
  147. package/runtime/python/okstra_ctl/registry/host_registry.py +11 -0
  148. package/runtime/python/okstra_ctl/render.py +50 -0
  149. package/runtime/python/okstra_ctl/report_contract.py +1 -1
  150. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +21 -3
  151. package/runtime/python/okstra_ctl/report_synthesis_packet.py +177 -17
  152. package/runtime/python/okstra_ctl/report_translation.py +2 -1
  153. package/runtime/python/okstra_ctl/report_translation_dispatch.py +69 -9
  154. package/runtime/python/okstra_ctl/role_requirements.py +142 -129
  155. package/runtime/python/okstra_ctl/rollup.py +3 -1
  156. package/runtime/python/okstra_ctl/run.py +76 -29
  157. package/runtime/python/okstra_ctl/schedule_semantics.py +17 -6
  158. package/runtime/python/okstra_ctl/stage_fix_carry.py +23 -4
  159. package/runtime/python/okstra_ctl/stage_integrate.py +178 -18
  160. package/runtime/python/okstra_ctl/stage_map.py +16 -2
  161. package/runtime/python/okstra_ctl/stage_targets.py +209 -43
  162. package/runtime/python/okstra_ctl/team.py +22 -13
  163. package/runtime/python/okstra_ctl/time_report.py +2 -1
  164. package/runtime/python/okstra_ctl/usage_report.py +3 -1
  165. package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -9
  166. package/runtime/python/okstra_ctl/wizard/ids.py +1 -1
  167. package/runtime/python/okstra_ctl/wizard/registry.py +1 -1
  168. package/runtime/python/okstra_ctl/wizard/state.py +3 -5
  169. package/runtime/python/okstra_ctl/wizard/steps_plan.py +3 -23
  170. package/runtime/python/okstra_ctl/worker_prompt_contract.py +5 -1
  171. package/runtime/python/okstra_ctl/worker_prompt_headers.py +35 -7
  172. package/runtime/python/okstra_ctl/worker_prompt_policy.py +66 -48
  173. package/runtime/python/okstra_ctl/workflow.py +1 -1
  174. package/runtime/python/okstra_ctl/worktree/__init__.py +3 -1
  175. package/runtime/python/okstra_ctl/worktree/naming.py +9 -0
  176. package/runtime/python/okstra_ctl/worktree_registry.py +38 -9
  177. package/runtime/python/okstra_token_usage/pricing.py +6 -4
  178. package/runtime/schemas/agent-common-v1.schema.json +34 -0
  179. package/runtime/schemas/agent-duty-v1.schema.json +38 -0
  180. package/runtime/schemas/agent-operation-v1.schema.json +11 -0
  181. package/runtime/schemas/agent-profile-v1.schema.json +46 -0
  182. package/runtime/schemas/agent-role-v1.schema.json +29 -0
  183. package/runtime/schemas/final-report-v2.0.schema.json +118 -97
  184. package/runtime/schemas/final-report-v3.0.schema.json +118 -97
  185. package/runtime/skills/okstra-brief-gen/SKILL.md +84 -4
  186. package/runtime/skills/okstra-chat/SKILL.md +2 -2
  187. package/runtime/skills/okstra-code-review/SKILL.md +23 -9
  188. package/runtime/skills/okstra-container-build/SKILL.md +10 -10
  189. package/runtime/skills/okstra-inspect/SKILL.md +1 -1
  190. package/runtime/skills/okstra-inspect/facets/cost.md +1 -1
  191. package/runtime/skills/okstra-inspect/facets/error-zip.md +9 -9
  192. package/runtime/skills/okstra-inspect/facets/errors.md +16 -16
  193. package/runtime/skills/okstra-inspect/facets/logs.md +7 -7
  194. package/runtime/skills/okstra-inspect/facets/recap.md +2 -2
  195. package/runtime/skills/okstra-inspect/facets/report.md +1 -1
  196. package/runtime/skills/okstra-inspect/facets/status.md +4 -3
  197. package/runtime/skills/okstra-inspect/facets/time.md +11 -10
  198. package/runtime/skills/okstra-manager/SKILL.md +18 -2
  199. package/runtime/skills/okstra-pr-gen/SKILL.md +6 -5
  200. package/runtime/skills/okstra-rollup/SKILL.md +5 -5
  201. package/runtime/skills/okstra-run/SKILL.md +31 -12
  202. package/runtime/skills/okstra-schedule-gen/SKILL.md +19 -14
  203. package/runtime/skills/okstra-setup/SKILL.md +12 -10
  204. package/runtime/skills/okstra-setup/references/project-config.md +7 -6
  205. package/runtime/skills/okstra-usage/SKILL.md +1 -1
  206. package/runtime/skills/okstra-user-response/SKILL.md +1 -1
  207. package/runtime/templates/manager/view.template.html +1 -0
  208. package/runtime/templates/report-writer-prompt-preamble.md +8 -0
  209. package/runtime/templates/reports/brief.template.md +14 -4
  210. package/runtime/templates/reports/html/i18n/en.json +5 -4
  211. package/runtime/templates/reports/html/i18n/ko.json +5 -4
  212. package/runtime/templates/reports/html/tasks/release-handoff.template.html +8 -5
  213. package/runtime/templates/reports/i18n/en.json +1 -1
  214. package/runtime/templates/reports/md/tasks/release-handoff.template.md +1 -1
  215. package/runtime/templates/reports/release-handoff-input.template.md +6 -4
  216. package/runtime/templates/translator-prompt-preamble.md +36 -0
  217. package/runtime/validators/checks/validate-assets-01.py +7 -8
  218. package/runtime/validators/validate-brief.py +70 -0
  219. package/runtime/validators/validate-implementation-plan-stages.py +2 -1
  220. package/runtime/validators/validate-run.py +59 -9
  221. package/runtime/validators/validate-schedule.py +9 -0
  222. package/docs/for-ai/README.md +0 -68
  223. package/docs/for-ai/skills/okstra-brief-gen.md +0 -262
  224. package/docs/for-ai/skills/okstra-chat.md +0 -34
  225. package/docs/for-ai/skills/okstra-code-review.md +0 -57
  226. package/docs/for-ai/skills/okstra-container-build.md +0 -129
  227. package/docs/for-ai/skills/okstra-inspect.md +0 -262
  228. package/docs/for-ai/skills/okstra-manager.md +0 -86
  229. package/docs/for-ai/skills/okstra-memory.md +0 -126
  230. package/docs/for-ai/skills/okstra-pr-gen.md +0 -49
  231. package/docs/for-ai/skills/okstra-rollup.md +0 -114
  232. package/docs/for-ai/skills/okstra-run.md +0 -250
  233. package/docs/for-ai/skills/okstra-schedule-gen.md +0 -240
  234. package/docs/for-ai/skills/okstra-setup.md +0 -167
  235. package/docs/for-ai/skills/okstra-usage.md +0 -29
  236. package/docs/for-ai/skills/okstra-user-response.md +0 -72
  237. package/runtime/agents/workers/claude-worker.md +0 -128
  238. package/runtime/agents/workers/report-writer-worker.md +0 -37
  239. package/runtime/agents/workers/translator-worker.md +0 -63
  240. package/runtime/prompts/duties/acceptance-critic.md +0 -44
  241. package/runtime/prompts/duties/acceptance-verifier.md +0 -44
  242. package/runtime/prompts/duties/analysis-worker.md +0 -44
  243. package/runtime/prompts/duties/code-reviewer.md +0 -44
  244. package/runtime/prompts/duties/common.md +0 -39
  245. package/runtime/prompts/duties/diagnosis-worker.md +0 -44
  246. package/runtime/prompts/duties/direction-selection-worker.md +0 -44
  247. package/runtime/prompts/duties/discovery-worker.md +0 -44
  248. package/runtime/prompts/duties/implementation-executor.md +0 -44
  249. package/runtime/prompts/duties/implementation-verifier.md +0 -44
  250. package/runtime/prompts/duties/lead.md +0 -44
  251. package/runtime/prompts/duties/planning-worker.md +0 -52
  252. package/runtime/prompts/duties/report-writer.md +0 -44
  253. package/runtime/prompts/duties/reverification-worker.md +0 -44
  254. package/runtime/prompts/duties/schedule-verifier.md +0 -44
  255. package/runtime/prompts/duties/scope-critic.md +0 -44
  256. package/runtime/prompts/duties/technical-verification-worker.md +0 -44
  257. package/runtime/prompts/duties/translator.md +0 -44
  258. package/runtime/python/okstra_ctl/pane_title.py +0 -154
@@ -6,31 +6,6 @@ Validation commands are executable inputs: preserve their newlines, quotes, and
6
6
 
7
7
  Plan for the actual worktree layout before approval. Shared documentation directories can be links to the main checkout. Choose a build command compatible with those links (for example, an installed Next.js version may provide `next build --webpack`); verify the available option rather than assuming it. Do not plan for a verifier to move links or repair its environment. Compare negative-case assertions with the brief and the script body: a requirement to cache existing assets does not establish that missing assets should be cached. Record any changed expectation in a new plan revision; preserve the earlier approved plan.
8
8
 
9
- ```yaml
10
- roles:
11
- - role: planner
12
- min: 2
13
- recommended: 2
14
- max: 5
15
- duty: planning-worker
16
- - role: critic
17
- min: 0
18
- recommended: 1
19
- max: 1
20
- duty: scope-critic
21
- - role: report-writer
22
- min: 1
23
- recommended: 1
24
- max: 1
25
- duty: report-writer
26
- - role: verifier
27
- min: 0
28
- recommended: 0
29
- max: 0
30
- duty: reverification-worker
31
- dynamic: true
32
- ```
33
-
34
9
  - Purpose: turn an upstream-selected direction into an executable plan; legacy reruns may retain candidate comparison
35
10
  - Required workers:
36
11
  - claude
@@ -71,8 +46,8 @@ roles:
71
46
  - flag any requirement that is ambiguous, contradictory, or missing success criteria — register each one as a row in the report's `## 1. Clarification Items` table with `Blocks=approval` instead of guessing
72
47
  - read `<PROJECT_ROOT>/.okstra/glossary.md` and `<PROJECT_ROOT>/.okstra/decisions/` titles if present. Absent okstra memory files are the normal state — do not error. Treat the brief's `terminology:*` resolutions from `requirements-discovery` (if any) as authoritative; if missing, resolve any remaining fuzzy term as a `Blocks=approval` clarification row.
73
48
  - **Stage Ledger (read before drafting the Stage Map):** when this task already has a plan on disk, the analysis packet carries a `## Stage Ledger` JSON block listing every stage with its `status` (`done` / `active` / `ready` / `blocked`), `dependsOn`, and done commit. It states what exists, not what to plan. Two rules follow from it:
74
- - A stage whose `status` is `done` is already implemented and will not be executed again. Carry its plan body forward as written; do not rewrite its steps, and do not fold its work into a new stage.
75
- - Every stage number in the ledger is taken. A new stage takes the next number after the highest one listed; numbers are never reused or reordered. **Not yet machine-enforced** — the validator for this rule lands with the plan-amendment feature.
49
+ - A stage whose `status` is `done` is already implemented and will not be executed again. Declare it in this report's `stages[]` and `stageMap[]` with its plan body copied forward as written; do not rewrite its steps, and do not fold its work into a new stage. Its plan items are `observed`, not `in-scope` (`okstra_ctl.plan_items.stage_scope_bucket`), so re-declaring it adds no verification load. A carried body is also not re-judged: the planning conformance gate skips a stage the consumer ledger records as `done`, and report assembly issues no design-prep request for one (`okstra_ctl.design_prep.materialize_design_prep_requests`). A rule that widened since that stage shipped cannot be satisfied by a body you are forbidden to rewrite.
50
+ - Every stage number in the ledger is taken. This report declares every one of them — rows run `1..N` with no gap — and a new stage takes the next number after the highest one listed; numbers are never reused or reordered. A report that declares only its new stages satisfies neither rule and is refused twice over. **Enforced:** `okstra_ctl.stage_map._validate_stage_numbers` rejects the gap in every published plan it parses, so `okstra prepare` refuses the implementation run (`okstra_ctl.run._parse_stage_map_into_ctx`) and the Stage Ledger of every later run reads as `unreadable`; `validators/validate-implementation-plan-stages.py` check **S2** reports the same defect at authoring time. Cancelling a stage you no longer want is not yet expressible — that lands with the plan-amendment feature — so an unstarted stage you drop still keeps its number and body here.
76
51
  - The ledger answers two questions from two sources, and the block names both. `sourcePlan` is the plan the completed stages were actually built against; `latestPlan` is the plan the `stages` list came from and is therefore the numbering authority. When they differ, the completed work followed the former and the highest taken number comes from the latter.
77
52
  - A `planDivergence` entry means one of two things: the two plans disagree about a stage that is already `done` — the same number naming different work, or a completed stage the latest plan no longer declares — or the plan the completed stages were built against could not be read at all, so that comparison never ran. Both block the same way: do not pick one of the two plans yourself; register it as a `Blocks=approval` clarification row and assign no new stage number until it is resolved. Completed stages built against an *earlier* plan are not a divergence — that is the normal shape of an amended plan and the ledger folds it silently.
78
53
  - The block is absent ONLY on a task's first planning run. Its absence then means there is no prior plan, not that no stage is done. When the ledger could not be read, the packet names the source and reason. Continue planning to repair unambiguous dependency notation in the new report, retaining every stage number and title and every completed stage body. Record the original and corrected values with their source. Do not overwrite the prior report or select an older plan. Assign no new stage number until the corrected Stage Map validates; unresolved dependency meaning remains a blocker. The preparation behavior is covered by `tests/run/test_stage_ledger_prepare.py`; preservation of author intent remains a review guideline.
@@ -112,7 +87,7 @@ roles:
112
87
  - Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / plan item) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode".
113
88
  - §5.5.9 plan-body verification runs with an **adversarial posture** (`prompts/lead/plan-body-verification.md` §"Adversarial plan-body posture"): verifiers open and confirm every cited path / command and put the burden of proof on the plan. The gate threshold is majority-based for kinds `b`/`c`/`e`, but a single `DISAGREE` blocks on its own for the concrete, safety-critical kind `a` (path/symbol mismatch) — and `f` on `P-Req-*` items. `P-Var-*` items are excepted from the kind-`a` exception: a variation-point defect takes a majority. Rollback ordering (`d`) is advisory and never blocks the gate — a rollback is executed by a human, not by okstra's workers or verifiers. A majority also needs ≥2 participating votes, so a lone dissent whose peer returned a non-result does not block on a majority-gated kind (see that contract's §"Adversarial plan-body posture").
114
89
  - **Incremental re-verification scope (clarification re-runs):** when the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), workers re-analyze ONLY the stages listed in `reverify_stages` (the downstream closure of the impacted stages). Workers MUST NOT re-open, re-score, or re-judge any stage in `carry_stages` — those stages' prior plan-item verdicts are carried forward verbatim, and a worker never overwrites a carried verdict with its own judgement. When the decision is `mode == "full"` (the default), every stage is re-analyzed as usual.
115
- - **Single incremental-scope decision:** the lead calls `okstra incremental-scope` once the inputs are complete, passing the answered `C-NNN` ids through `--answered-clarifications`, changed design-preparation IDs through `--prep-items`, and any lead-resolved stage numbers through `--impacted`; the CLI unions all three before applying the existing dependency closure and cutoff. The clarification ids are resolved to stages by the CLI from the prior report's own `planItems[].clarificationId` and `blocked C-NNN` coverage links — the lead does not map answers to stage numbers. An answer that changes the selected planning payload, Stage Map, or execution approach is not a local impact: pass `--full-reason`, which is the only structural path that still forces `mode == "full"`. A clarification id that traces to no stage returns `mode == "unresolved"` — ask the user for stage numbers and call again with `--impacted`; do not treat it as full and do not silently drop the id. **When this run only ADDS stages** — every prior stage is `done` and none of them is being re-opened — there are no stage numbers to give: pass `--carry-all-reason` instead. Pinning any prior stage as impacted makes `incremental-carry` demand it from the current snapshot, which no longer holds it (a `done` stage is not in this run's narrative), so that path has no answer that works. `--carry-all-reason` still applies the base-ref check: if the branch moved, the decision degrades to `full` because the prior stages are no longer "as written". Unknown PREP IDs or invalid `stageRefs` still return an explicit full decision instead of being guessed. When the wizard pin is `auto` and the CLI returns `mode == "incremental"`, keep it — do not upgrade to full. When the user pinned a scope at the wizard (`REVERIFY_SCOPE_MODE` / `REVERIFY_SCOPE_STAGES` in `prompts/launch.template.md` §"Clarification Response Carried In" step 0), that pin is an input to this same call — `full` supplies the `--full-reason`, `carry-all` supplies the `--carry-all-reason`, and pinned stage numbers join `--impacted` — never a bypass of the CLI's closure and cutoff.
90
+ - **Single incremental-scope decision:** the lead calls `okstra incremental-scope` once the inputs are complete, passing the answered `C-NNN` ids through `--answered-clarifications`, changed design-preparation IDs through `--prep-items`, and any lead-resolved stage numbers through `--impacted`; the CLI unions all three before applying the existing dependency closure and cutoff. The clarification ids are resolved to stages by the CLI from the prior report's own `planItems[].clarificationId` and `blocked C-NNN` coverage links — the lead does not map answers to stage numbers. An answer that changes the selected planning payload, Stage Map, or execution approach is not a local impact: pass `--full-reason`, which is the only structural path that still forces `mode == "full"`. A clarification id that traces to no stage returns `mode == "unresolved"` — ask the user for stage numbers and call again with `--impacted`; do not treat it as full and do not silently drop the id. **When this run only ADDS stages** — every prior stage is `done` and none of them is being re-opened — there are no stage numbers to give: pass `--carry-all-reason` instead. Pinning any prior stage as impacted makes `incremental-carry` demand plan-item verdicts from the current snapshot, which no longer holds them (a `done` stage's plan items are `observed`, so they are never dispatched or scored in this run), so that path has no answer that works. The stage's own row is still declared in the narrative — that is the numbering rule above, not a re-verification. `--carry-all-reason` still applies the base-ref check: if the branch moved, the decision degrades to `full` because the prior stages are no longer "as written". Unknown PREP IDs or invalid `stageRefs` still return an explicit full decision instead of being guessed. When the wizard pin is `auto` and the CLI returns `mode == "incremental"`, keep it — do not upgrade to full. When the user pinned a scope at the wizard (`REVERIFY_SCOPE_MODE` / `REVERIFY_SCOPE_STAGES` in `prompts/launch.template.md` §"Clarification Response Carried In" step 0), that pin is an input to this same call — `full` supplies the `--full-reason`, `carry-all` supplies the `--carry-all-reason`, and pinned stage numbers join `--impacted` — never a bypass of the CLI's closure and cutoff.
116
91
  - **Stage-aware carry:** for an incremental decision, `okstra incremental-scope` writes the decision to the record this run's manifest names in `incrementalDecisionPath`. The report writer's duty to copy each `carry_stages` stage row unchanged is not stated here — it is generated into that writer's own authoring contract from the same record, with this run's stage numbers in it (`okstra_ctl.report_synthesis_packet.ReportSynthesisPacket._carry_instructions`). After plan-item seeding, run `okstra incremental-carry --cur-narrative ... --state ... --out-state ...` against that record. The helper rejects a changed or missing carried stage and copies prior `P-Step-*` / `P-Prep-*` verdicts for `carry_stages`, plus unchanged `P-Val-*` / `P-Req-*` / `P-Rb-*` rows whose extract `contentHash` still matches. It rewrites `dispatchQueue` and the sibling `plan-items-*.json` so the next prompt does not re-score a carried checklist row. Overlap, omissions, and canonical conflicts return `CarryError`. On that error, discard the partial state and run full re-verification.
117
92
  {{INCLUDE:_coverage-critic.md}}
118
93
  - Non-goals:
@@ -180,7 +155,7 @@ roles:
180
155
  - **Clean-tree assertions use `okstra worktree-status --check-clean`.** A bare `git status --porcelain` is never empty there, so an assertion built on one fails on okstra's scaffolding rather than on the stage's work. The okstra command asks the same question over source paths only and exits 1 when dirty, so it stands alone as a step's assertion: `okstra worktree-status --check-clean`. Validator S13 rejects the bare form. Do not add a `git tag stage-<N>-exit` to the step. Stage completion records the commit in the consumer ledger without creating or moving git tags.
181
156
  - **Never read an `.okstra/` artifact back out of a git object.** `.okstra/**` is gitignored and never committed — the executor aborts a commit that stages an ignored path and the verifier reports a committed `.okstra` path as a branch defect — so `git cat-file -e <tag>:.okstra/…`, `git show <tag>:.okstra/…`, and every variant of that read can never resolve, at any tag, in any stage. A later stage that needs a QA artifact reads it from the working tree or receives it through the carry sidecar / verifier result; do not design a stage contract around one being reachable from a tag. Validator S12 rejects the read.
182
157
  - **Per-stage conformance declaration (mandatory one line, in the stage section — same placement freedom as `TDD exemption:`):** the stage MUST carry exactly one of:
183
- - `Conformance tests: stage-<N> — <task_root>/qa/scripts/stage-<N>.<ext> (requires=[db|io|http|external,...])` — declare that a Tier3 verification script will prove this stage's upstream requirements (brief / requirements-discovery / error-analysis / improvement-discovery → this stage's `Acceptance`) hold against **real** DB rows, real endpoints, or the real external API — NOT mocks. This phase emits the line and the `requires` set only. Do NOT write `<task_root>/qa/scripts/stage-<N>.*` and do NOT add a `runCommand` or `conformance-manifest.json` entry here — the matching `implementation` stage run creates the script file and the manifest `runCommand`. A plan that declares tests with no script file on disk is valid at this gate. The data.json `conformanceTests` value carries only the remainder after the `Conformance tests: stage-<N> — ` prefix — never the `stage-<N> — ` label itself (report assembly strips a leftover label at publication, and the implementation entry gate rejects one).
158
+ - `Conformance tests: stage-<N> — <task_root>/qa/scripts/stage-<N>.<ext> (requires=[db|io|http|external,...])` — declare that a Tier3 verification script will prove this stage's upstream requirements (brief / requirements-discovery / error-analysis / improvement-discovery → this stage's `Acceptance`) hold against **real** DB rows, real endpoints, or the real external API — NOT mocks. This phase emits the line and the `requires` set only. Do NOT write `<task_root>/qa/scripts/stage-<N>.*` and do NOT add a `runCommand` or `conformance-manifest.json` entry here — the matching `implementation` stage run creates the script file and the manifest `runCommand`. A plan that declares tests with no script file on disk is valid at this gate. The data.json `conformanceTests` value carries only the remainder after the `Conformance tests: stage-<N> — ` prefix — never the `stage-<N> — ` label itself (report assembly strips a leftover label at publication, and the implementation entry gate rejects one). The `requires` set MUST cover every surface the stage's own `stepwiseExecution[].plannedPaths` touch — a controller is `http`, a repository or query is `db` — because the implementation run's diff-surface check demands them after the work is done, when the approved plan can no longer change (2026-09-22, dev-10860: `requires=[io]` over a planned `catalog.controller.ts`). **Enforced at planning:** `validators/validate-run.py` `_validate_planning_conformance_declared` runs the implementation gate's surface patterns over those paths (`okstra_ctl.conformance.declared_stage_surface_gaps`) and fails the planning run on a missing surface. A stage the consumer ledger records as `done` is skipped — its body is carried, not authored, and cannot be corrected here.
184
159
  - `Conformance exemption: <reason>` — only for stages that touch no db/io/http/external surface, or where unit tests fully cover the increment. Exemption stays a planning declaration; do not move it to implementation. (If the eventual `implementation` diff actually touches one of those surfaces, `validate-run.py`'s diff-surface cross-check is BLOCKING — an exemption cannot hide a real db/io/http/external change.) **Enforced at planning:** `validators/validate-run.py` `_validate_planning_conformance_declared` runs the same surface patterns over the exempted stage's `stepwiseExecution[].plannedPaths` (`okstra_ctl.conformance.exempt_stage_surface_conflicts`) and fails the planning run — a plan that exempts a stage while planning a `*repository*` / `*.controller.*` / `*migration*` path is corrected here, where the plan is still editable, not after the implementation is done (observed 2026-09-09, dev-10784 Stage 2).
185
160
  - **External QA outcome guideline:** after satisfying the S11 declaration above, a line whose `requires` contains
186
161
  `db`, `http`, or `external` should name those capabilities here so the later `runCommand` can be written against them.
@@ -0,0 +1,30 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "implementation",
4
+ "roles": [
5
+ {
6
+ "mode": "static",
7
+ "roleId": "implementer",
8
+ "dutyId": "implementation-executor",
9
+ "min": 1,
10
+ "recommended": 1,
11
+ "max": 1
12
+ },
13
+ {
14
+ "mode": "static",
15
+ "roleId": "verifier",
16
+ "dutyId": "implementation-verifier",
17
+ "min": 2,
18
+ "recommended": 2,
19
+ "max": 3
20
+ },
21
+ {
22
+ "mode": "static",
23
+ "roleId": "report-writer",
24
+ "dutyId": "report-writer",
25
+ "min": 1,
26
+ "recommended": 1,
27
+ "max": 1
28
+ }
29
+ ]
30
+ }
@@ -1,24 +1,5 @@
1
1
  # Implementation Profile
2
2
 
3
- ```yaml
4
- roles:
5
- - role: implementer
6
- min: 1
7
- recommended: 1
8
- max: 1
9
- duty: implementation-executor
10
- - role: verifier
11
- min: 2
12
- recommended: 2
13
- max: 3
14
- duty: implementation-verifier
15
- - role: report-writer
16
- min: 1
17
- recommended: 1
18
- max: 1
19
- duty: report-writer
20
- ```
21
-
22
3
  - Purpose: realise the approved `implementation-planning` deliverable as actual source changes, with cross-model verification, while keeping the run reversible
23
4
  - **Run-level fixed cost:** the verifier set, Phase 5.5 convergence, and the Phase 6 report-writer run exactly once per implementation run, over this run's single stage diff — never once per step.
24
5
  - **Fix run (profile carries a "Fix-Run Carry" block):** the executor's scope is the carried blocking findings plus the previous routing recommendation — it MUST NOT re-execute plan steps the previous run completed. Verifiers apply the "Fix-run incremental scope" section of `_implementation-verifier.md`; the report writer applies "Fix-run incremental authoring" in `report-writer.md`. The full validation-command re-run is NOT reduced.
@@ -53,7 +34,7 @@ roles:
53
34
  - Base ref: `{{EXECUTOR_WORKTREE_BASE_REF}}` — canonical `<base>` for every `git diff` / `git log` in this run. Independent stages start from the common anchor (the task-key worktree HEAD, fixed once at first stage entry); dependent stages start from the predecessor done commit or the verified merged task worktree head.
54
35
  - Provisioning note: `{{EXECUTOR_WORKTREE_NOTE}}`
55
36
  - Treat the working-tree path as `project_root` for the duration of this run. Do NOT mutate the caller's original checkout. cwd-sensitive Bash commands MUST be prefixed `cd {{EXECUTOR_WORKTREE_PATH}} && ` in the same Bash invocation (never `bash -lc "..."` wrappers — see executor sidecar for full rules).
56
- - Lifecycle: kept after the run completes as this stage's evidence worktree. Later stages get their own stage worktrees. Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` → drop the stage-key registry entry (`<task-key>#stage-<N>`). Exception: whole-task `final-verification` auto-merges every done stage and removes its worktree directory (`stage_integrate.integrate_stages`, `teardown=True`) — do not promise the user the worktree survives past that point. The stage BRANCH does survive: it is kept so the stack stays reviewable and `okstra handoff local-checkout --stage <N>` still has a target.
37
+ - Lifecycle: kept after the run completes as this stage's evidence worktree. Later stages get their own stage worktrees. Manual cleanup: `git worktree remove <path>` → `git branch -D <branch>` → drop the stage-key registry entry (`<task-key>#stage-<N>`). Exception: whole-task `final-verification` removes the stage worktree directory after its verdict clears the work for release (`stage_integrate.integrate_stages`, `teardown=True`; it also merges the done stages into the task branch, unless one stage branch already contains them all) — do not promise the user the worktree survives past that point. The stage BRANCH does survive: it is kept so the stack stays reviewable and `okstra handoff local-checkout --stage <N>` still has a target.
57
38
  - Approval gate (phase-specific addendum to shared authority rule):
58
39
  - the pre-implementation gate's recorded user approval marker is the only authorised approval gate at this phase — proceed once it is satisfied without further external coordination.
59
40
  - Forbidden actions — universal (any occurrence → terminal status `contract-violated`):
@@ -0,0 +1,31 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "improvement-discovery",
4
+ "roles": [
5
+ {
6
+ "mode": "static",
7
+ "roleId": "analyser",
8
+ "dutyId": "discovery-worker",
9
+ "min": 3,
10
+ "recommended": 3,
11
+ "max": 5
12
+ },
13
+ {
14
+ "mode": "static",
15
+ "roleId": "report-writer",
16
+ "dutyId": "report-writer",
17
+ "min": 1,
18
+ "recommended": 1,
19
+ "max": 1
20
+ },
21
+ {
22
+ "mode": "dynamic",
23
+ "roleId": "verifier",
24
+ "dutyId": "reverification-worker",
25
+ "sourceRoleIds": [
26
+ "analyser"
27
+ ],
28
+ "activation": "per-selected-source"
29
+ }
30
+ ]
31
+ }
@@ -1,25 +1,5 @@
1
1
  # Improvement Discovery Profile
2
2
 
3
- ```yaml
4
- roles:
5
- - role: analyser
6
- min: 3
7
- recommended: 3
8
- max: 5
9
- duty: discovery-worker
10
- - role: report-writer
11
- min: 1
12
- recommended: 1
13
- max: 1
14
- duty: report-writer
15
- - role: verifier
16
- min: 0
17
- recommended: 0
18
- max: 0
19
- duty: reverification-worker
20
- dynamic: true
21
- ```
22
-
23
3
  - Purpose: scan a codebase scope through a fixed lens whitelist and surface ranked improvement candidates with multi-worker consensus classification
24
4
  - Required workers:
25
5
  - claude
@@ -0,0 +1,31 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "project-analysis",
4
+ "roles": [
5
+ {
6
+ "mode": "static",
7
+ "roleId": "analyser",
8
+ "dutyId": "analysis-worker",
9
+ "min": 2,
10
+ "recommended": 3,
11
+ "max": 5
12
+ },
13
+ {
14
+ "mode": "static",
15
+ "roleId": "report-writer",
16
+ "dutyId": "report-writer",
17
+ "min": 1,
18
+ "recommended": 1,
19
+ "max": 1
20
+ },
21
+ {
22
+ "mode": "dynamic",
23
+ "roleId": "verifier",
24
+ "dutyId": "reverification-worker",
25
+ "sourceRoleIds": [
26
+ "analyser"
27
+ ],
28
+ "activation": "per-selected-source"
29
+ }
30
+ ]
31
+ }
@@ -1,25 +1,5 @@
1
1
  # Project Analysis Profile
2
2
 
3
- ```yaml
4
- roles:
5
- - role: analyser
6
- min: 2
7
- recommended: 3
8
- max: 5
9
- duty: analysis-worker
10
- - role: report-writer
11
- min: 1
12
- recommended: 1
13
- max: 1
14
- duty: report-writer
15
- - role: verifier
16
- min: 0
17
- recommended: 0
18
- max: 0
19
- duty: reverification-worker
20
- dynamic: true
21
- ```
22
-
23
3
  - Purpose: map a bounded project area so later work can navigate components, dependencies, entry points, repositories, and external integrations without changing the source
24
4
  - Required workers:
25
5
  - claude
@@ -0,0 +1,5 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "release-handoff",
4
+ "roles": []
5
+ }
@@ -1,115 +1,113 @@
1
1
  # Release Handoff Profile
2
2
 
3
- ```yaml
4
- roles: []
5
- ```
6
-
7
- - Record the handoff shape in `releaseHandoff.handoffScope`: `mode` always, plus `stages`
8
- and `collectorBranch` in stage-group mode. The report is the only place a reader learns
9
- which stages shipped — the collector branch name does not say.
10
- - Purpose: take an `accepted` final-verification verdict for an already-committed implementation branch and turn it into a delivered push and/or pull request, with explicit user selection at every mutating step. Two modes: **whole-task** (default — the verified task branch becomes one PR) and **stage-group** (a user-selected subset of verified stages is merged into a collector branch and becomes one PR).
3
+ - Record the handoff shape in `releaseHandoff.handoffScope`: the `stages` this run delivered and
4
+ the `releaseBase` the user picked. The report is the only place a reader learns which stages
5
+ shipped and in what order their PRs must be merged — the branch names do not say.
6
+ - Purpose: take a release-ready single-stage final-verification verdict for each already-committed implementation stage and turn it into a delivered push and/or pull request, with explicit user selection at every mutating step. **One stage is one PR.** The PR head is that stage's stack branch (`<prefix>-<task-id>-s<N>`); nothing is squashed, rebased, or collected into a bundle branch.
11
7
  - **Execution model: single-lead, no worker dispatch.** This phase is a thin orchestrator over `git` / `gh`; it does NOT dispatch teammates, does NOT dispatch analysis or drafter sub-agents, and does NOT run convergence. The host-native Okstra lead performs every step inline (drafting PR text, asking the user, running git / gh, writing the final report) — see "Lead-only contract" below.
12
8
  - Worker roster: none — this profile intentionally has no `- Required workers:` block; the run is executed entirely by the Okstra lead.
13
9
  - Lead-only contract (replaces the shared team contract for this phase):
14
10
  - The host-native Okstra lead is the sole agent for this run. No worker dispatch, no teammates, no parallel sub-agents, no convergence loop.
15
- - The lead drafts the PR title and PR body **inline** by reading the run brief, the cited final-verification report, `git log --oneline <base>..HEAD`, and `git diff <base>..HEAD --stat`. No drafter worker is dispatched.
11
+ - The lead drafts each stage's PR title and PR body **inline** by reading the run brief, that stage's cited final-verification report, `git log --oneline <stage base>..<stage head>`, and `git diff <stage base>..<stage head> --stat`. No drafter worker is dispatched.
16
12
  - The lead authors the final-report file directly (no `Report writer worker` dispatch). The report still conforms to the standard `templates/reports/final-report-v2.template.md` structure, including the `## 5.6 Release Handoff Deliverables` section.
17
13
  - The shared anti-escalation rule from the common contract still applies: do not start any other lifecycle phase from inside this run.
18
14
  - The shared "authority & permissions assumption" rule from the common contract still applies: assume the user holds every permission needed; do not block on hypothetical approvals.
19
15
  - Pre-handoff entry gate (mandatory — refuse to start if any item fails):
20
- - the run's input document (`release-handoff-input.md`, generated by prepare in place of a task brief — briefs belong to entry phases only) carries a `## Source Verification Report` section with `Mode`, `Stages`, and one table row per cited `final-verification` final-report. The run context exposes the same selection as `HANDOFF_MODE` (`whole-task` | `stage-group`) and `HANDOFF_STAGES` (csv, empty for whole-task).
21
- - **whole-task mode** (`HANDOFF_MODE=whole-task`): the lead opens the cited report and confirms its `verificationScope` is `whole-task` and its verdict is release-ready — `Verdict Token` exactly `accepted`, or exactly `conditional-accept` with every **Conditional Acceptance Condition** row declaring `blocksReleaseHandoff: false`. The rule lives in `okstra_ctl.release_gate.release_handoff_allowed`; the lead reads the report against it and does not invent a third case.
22
- - **stage-group mode** (`HANDOFF_MODE=stage-group`): the lead opens each cited single-stage report and confirms every verdict is release-ready by the same rule as whole-task mode. Eligibility was already enforced at prepare time (`okstra_ctl.handoff.compute_eligibility`) and is re-enforced by `okstra handoff assemble` — the lead never hand-computes it.
23
- - if the verdict is `blocked`, a `conditional-accept` carrying any condition that blocks release, or any other token (including ambiguous phrasing like "looks good"), the run MUST end immediately with status `blocked` and a routing recommendation back to `error-analysis` or `implementation-planning`. Do NOT prompt the user; Do NOT run any git command.
24
- - when the cited verdict is `conditional-accept`, the lead MUST carry every **Conditional Acceptance Condition** row into the PR body under a heading naming them as unresolved — id, condition, and the evidence the reviewer would need. These conditions are the whole reason a non-`accepted` verdict was allowed through; a PR body that drops them turns a recorded condition into a silent one.
16
+ - the run's input document (`release-handoff-input.md`, generated by prepare in place of a task brief — briefs belong to entry phases only) carries a `## Source Verification Report` section with `Stages` and one table row per cited `final-verification` final-report. The run context exposes the same selection as `HANDOFF_STAGES` (csv, never empty — prepare defaults it to every eligible stage).
17
+ - the lead opens each cited single-stage report and confirms its `verificationScope` is `single-stage` and its verdict is release-ready — `Verdict Token` exactly `accepted`, or exactly `conditional-accept` with every **Conditional Acceptance Condition** row declaring `blocksReleaseHandoff: false`. The rule lives in `okstra_ctl.release_gate.release_handoff_allowed`; the lead reads the reports against it and does not invent a third case. Eligibility was already enforced at prepare time (`okstra_ctl.handoff.compute_eligibility`) and is re-enforced by `okstra handoff pr-plan` — the lead never hand-computes it.
18
+ - if any cited verdict is `blocked`, a `conditional-accept` carrying a condition that blocks release, or any other token (including ambiguous phrasing like "looks good"), the run MUST end immediately with status `blocked` and a routing recommendation back to `error-analysis` or `implementation-planning`. Do NOT prompt the user; Do NOT run any git command.
19
+ - when a cited verdict is `conditional-accept`, the lead MUST carry that stage's **Conditional Acceptance Condition** rows into **that stage's** PR body under a heading naming them as unresolved — id, condition, and the evidence the reviewer would need. These conditions are the whole reason a non-`accepted` verdict was allowed through; a PR body that drops them turns a recorded condition into a silent one.
25
20
  - the lead MUST capture `git status --short` and confirm the working tree is clean. Dirty state aborts the run; release-handoff packages the commits produced by `implementation`, it does not stage or commit changes.
26
- - the lead MUST capture `git rev-parse --abbrev-ref HEAD` and record it as the **feature branch**. If the current branch is itself `main`, `master`, `prod`, `preprod`, `staging`, or `dev`, the run MUST end immediately — release-handoff never operates on a base branch.
27
- - the lead MUST confirm `git log --oneline <base>..HEAD` contains at least one implementation commit. If it is empty, the run MUST end with status `blocked` and route back to `implementation`.
28
- - In whole-task mode, compare `git rev-parse <handoff-branch>` with `finalVerification.sourceImplementationReport.capturedHeadSha` in the cited latest verification report, both at entry and immediately before pushing. Any mismatch stops delivery and requires final-verification again. In stage-group mode, run `okstra handoff eligible` again before pushing and confirm each selected stage is still eligible; assemble already checks the recorded verified commits. Record the compared commits and eligibility output in Executed Commands. These pre-push comparisons are lead instructions; the automated entry and assembly checks are enforced by `okstra_ctl.handoff_verification` and the handoff tests.
21
+ - the lead MUST capture `git rev-parse --abbrev-ref HEAD` and record it as the run's current branch. It is evidence, not a PR head: every PR head comes from `okstra handoff pr-plan`. If the current branch is `main`, `master`, `prod`, `preprod`, `staging`, or `dev`, record it and do not push it — release-handoff never pushes a base branch.
22
+ - before pushing, run `okstra handoff pr-plan` again if anything mutated since entry, and confirm each selected stage is still present in its output. `pr-plan` re-checks eligibility and each stage's recorded verified commit. Record the pr-plan output in Executed Commands. These pre-push comparisons are lead instructions; the automated entry checks are enforced by `okstra_ctl.handoff_verification` and the handoff tests.
23
+ - **Commit history is preserved — structurally, not as a preference.** These PRs are a stack: stage N's PR base is stage N-1's branch. Squash-merging a PR in the stack replaces its commits with a new one, so the next PR's base points at commits that no longer exist on the target branch and its diff re-shows the predecessor's changes. Therefore: okstra never rebases, squashes, amends, or cherry-picks a stage branch, and every PR body states the merge policy — **merge commit or rebase-merge, never squash, and merge in ascending stage order**.
29
24
  - User interaction protocol (Okstra lead — performed in order, using the selected runtime adapter's interactive prompt):
30
25
  1. **Action selection** — present three choices and capture exactly one:
31
- - `local checkout` — bring a verified branch into the MAIN worktree for local testing (no push, no PR). Two targets: the whole-task branch (whole-task mode only), or a single stage's stack branch (`--stage N`, available in both modes since stage branches survive verification). See step 1c. When `HANDOFF_MODE` is `stage-group`, offer only the per-stage target.
32
- - `push + PR` — push the feature branch, then open or reuse a pull request.
26
+ - `local checkout` — bring one stage's branch into the MAIN worktree for local testing (no push, no PR). See step 1c.
27
+ - `push + PR` — push the selected stage branches and open or reuse one pull request per stage.
33
28
  - `skip` — cancel delivery actions for now: record that release-handoff was intentionally skipped and end the run without any git command.
34
29
  If the user picks `skip`, route directly to the final-report self-review pass.
35
- 1c. **Local checkout execution** (only when the user picked `local checkout`) — first ask which target — when `HANDOFF_MODE` is `whole-task`, offer both the whole-task branch and one stage's stack branch; when it is `stage-group`, offer only the per-stage target — listing the selectable stage numbers (from the approved plan's Stage Map, since the run input document carries no Stage Map). Then confirm with the user that okstra will remove the corresponding okstra worktree (when it still exists) and `git checkout <branch>` in the MAIN worktree, and that the base branch is never modified. On confirmation run:
36
- `okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t>` — append `--stage <N>` for the per-stage target.
37
- Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, another run of this task still `in-progress`, the target branch already deleted, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra worktree for that target no longer exists — if the lead's cwd was inside it, EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
38
- - **stage-group mode step order** (overrides the default Q1→Q3 sequence): after Q1 picks `push + PR`, run (1) base-branch selection first — identical to Q2 below, because the dependency-closure check needs `origin/<base>`; (2) G2 stage confirmation (step 1g); (3) assemble (step 2g); then Q2b and Q3 as usual, with the collector branch as the PR head.
39
- 1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR target stage: <csv> — proceeding`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
40
- 2g. **assemble**: run `okstra handoff assemble --plan-run-root <...> --approved-plan <...> --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --work-category <c> --stages <csv> --base <chosen-base>`. Exit 2 means a stage-vs-stage merge conflict: show the `conflicts` paths and stop (route: reshape the group or resolve manually). Exit 1 means an eligibility/closure violation: show the error verbatim and re-ask G2. On success the returned `branch` is the PR head branch for every subsequent step.
41
- 2. **PR base branch** (only when the user picked `push + PR`) — present four options and capture exactly one:
30
+ 1c. **Local checkout execution** (only when the user picked `local checkout`) — first ask which stage, listing the stage numbers from `HANDOFF_STAGES` (a stage outside that list is still checkoutable; offer the approved plan's Stage Map numbers when the user asks for one, since the run input document carries no Stage Map). Then confirm with the user that okstra will remove that stage's okstra worktree (when it still exists) and `git checkout <branch>` in the MAIN worktree, and that no base branch is modified. On confirmation run:
31
+ `okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --stage <N>`
32
+ Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, a run still holds the stage, the target branch already deleted, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra worktree for that stage no longer exists — if the lead's cwd was inside it, EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
33
+ 2. **Release base branch** (only when the user picked `push + PR`) — present these options and capture exactly one:
42
34
  - `preprod`
43
35
  - `main`
44
36
  - `direct input` (free-form branch name; lead validates the name exists on origin via `git ls-remote --heads origin <name>` and re-asks on failure)
45
- The chosen base MUST NOT equal the feature branch. If it does, re-ask.
46
- 2b. **Pre-merge conflict probe** (only when the user picked `push + PR`) — before the push/PR step, the lead MUST refresh the base ref and probe for merge conflicts against it:
47
- - run `git fetch origin <chosen-base>` (read-only on the local working tree).
48
- - run `git merge-tree --write-tree <handoff-branch> origin/<chosen-base>`. Use the verified task branch in whole-task mode or the branch returned by assemble in stage-group mode, regardless of the current directory's HEAD. Exit 0 means clean. Exit 1 with a result-tree object ID on the first stdout line means a merge conflict. A missing result tree, or any other exit code, is an execution error: stop and report it, without offering permission to proceed as if it were a content conflict. An invalid ref can also return exit 1, so the exit code alone is insufficient.
49
- - If no conflict is detected, proceed silently to Q3 (do NOT add a confirmation prompt — keep the happy path frictionless).
50
- - If a conflict IS detected, present the conflicting paths (parsed from the `merge-tree` output) and capture exactly one:
51
- - `proceed anyway` — continue to Q3; the PR will be opened with conflicts and the final report MUST flag this in `Merge Conflict Probe`.
52
- - `change base branch` — return to Q2 and re-ask the base selection.
37
+ This is the release base for the run, not necessarily each PR's base: a stage that sits on another stage targets that stage's branch. The chosen base MUST NOT be one of the stage branches. If it is, re-ask.
38
+ 2p. **PR plan** (only when the user picked `push + PR`) — run
39
+ `okstra handoff pr-plan --plan-run-root <...> --approved-plan <...> --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --work-category <c> --stages <HANDOFF_STAGES> --base <chosen-base>`.
40
+ It returns one row per stage with `head_branch`, `head_commit`, `base_kind` (`release-base` | `stage` | `merge-base`), `base_branch` and `base_commit`. Exit 2 means the predecessors of a multi-dependency stage conflict with each other: show the `conflicts` paths and stop (route: resolve manually, then retry). Exit 1 means an eligibility or dependency violation — most often a stage whose predecessor is neither in this run nor already PR'd nor merged into the release base: show the error verbatim and re-ask the action selection. On success these rows are authoritative for every subsequent step; the lead does not recompute a base by hand.
41
+ A `merge-base` row means `pr-plan` created a branch merging that stage's predecessors. That branch is a PR base only — it is never a PR head — and it MUST be pushed before the PR that targets it.
42
+ 2b. **Pre-merge conflict probe** (only when the user picked `push + PR`) — before pushing, for each planned stage in ascending order:
43
+ - run `git fetch origin <chosen-base>` once (read-only on the local working tree).
44
+ - run `git merge-tree --write-tree <head_branch> <base_branch>` for that stage, using the `base_branch` from the pr-plan row (`origin/<chosen-base>` for a `release-base` row). Exit 0 means clean. Exit 1 with a result-tree object ID on the first stdout line means a merge conflict. A missing result tree, or any other exit code, is an execution error: stop and report it, without offering permission to proceed as if it were a content conflict. An invalid ref can also return exit 1, so the exit code alone is insufficient.
45
+ - If no stage conflicts, proceed silently to Q3 (do NOT add a confirmation prompt — keep the happy path frictionless).
46
+ - If any stage conflicts, present the conflicting stage(s) and their paths (parsed from the `merge-tree` output) and capture exactly one:
47
+ - `proceed anyway` — continue to Q3; the affected PRs will be opened with conflicts and the final report MUST flag this in `Merge Conflict Probe`.
48
+ - `change base branch` — return to Q2 and re-ask the base selection (and re-run pr-plan).
53
49
  - `cancel` — end the run without push or PR; record the cancellation in the final report.
54
50
  - The probe is read-only. It MUST NOT run `git merge`, `git rebase`, `git pull`, or any command that mutates the working tree or local refs.
55
- 3. **PR title + PR body confirmation** — show the lead's inline draft verbatim, together with the filled-body self-check result (either `body self-check: clean` or the list of hits with their lines, per the drafting rules below), and capture one of:
56
- - `use as-is` — proceed with the drafted text.
57
- - `edit then proceed` — accept inline edits from the user, then proceed with the edited text.
51
+ 3. **PR title + PR body confirmation** — draft every selected stage's title and body first, then show all of them verbatim in ONE question, each with the filled-body self-check result (either `body self-check: clean` or the list of hits with their lines, per the drafting rules below), and capture one of:
52
+ - `use as-is` — proceed with the drafted text for every stage.
53
+ - `edit then proceed` — accept inline edits from the user (the user may edit any subset), then proceed with the edited text.
58
54
  - `cancel` — end the run without executing push or PR commands; record the cancellation in the final report.
59
- - Inline drafting rules (Okstra lead):
60
- - read the run brief, the cited final-verification report, `git log --oneline <base>..HEAD`, and `git diff <base>..HEAD --stat` to ground the drafted text in actual committed changes. In stage-group mode the draft is grounded on `git log <implementation_base_commit>..<collector HEAD>` / `git diff <implementation_base_commit>..<collector HEAD> --stat`, with source material = each selected stage's implementation report + its single-stage verification report.
55
+ - Inline drafting rules (Okstra lead) — applied once per stage:
56
+ - read the run brief, that stage's cited final-verification report and its implementation report, `git log --oneline <base_commit>..<head_commit>`, and `git diff <base_commit>..<head_commit> --stat` (both from the stage's pr-plan row) to ground the drafted text in the commits that PR actually carries. A stacked PR's diff is that stage alone — do not describe a predecessor's work in it.
61
57
  - **PR body template** — the run context exposes `PR_TEMPLATE_PATH` and `PR_TEMPLATE_SOURCE`. The path MUST be an okstra-owned project artifact under `<PROJECT_ROOT>/.okstra/**`, or a file the prepare step already materialised into this run's artifact directory. If the resolved file is missing or outside that boundary at draft time, abort with a clear error — do NOT invent a structure. Otherwise the lead MUST `Read` it verbatim, strip HTML comments, and fill in the placeholders, treating the template (never a hard-coded section list) as the source of truth for the structure.
62
- - produce **two artifacts** before showing them to the user:
63
- 1. **PR title** — by default the subject of the most recent implementation commit, or a concise Conventional Commits-style summary of the committed range.
64
- 2. **PR body** — markdown filled from `PR_TEMPLATE_PATH`. The user-confirmation step's diff (Q3 `edit then proceed`) is computed against the filled template, not against the raw template file.
65
- - **Filled-body self-check (runs on the drafted body, before Q3 shows it).** "Fill in the placeholders" is only observable if someone checks that they were filled, so scan the drafted body for these and carry the result into Q3: a residual HTML comment or template marker (`<!-- … -->`, `_Describe your changes…_`, a bare `TODO` / `FIXME` the diff did not introduce), an unchecked `- [ ]` box with no inline N/A justification, a section heading whose body is empty, and a whole body short enough to carry no substance. Each hit is reported to the user with its line — never silently left in, and never auto-filled with invented content. The user remains free to accept it; the point is that they see it before choosing `use as-is`.
58
+ - produce **two artifacts per stage** before showing them to the user:
59
+ 1. **PR title** — by default the subject of that stage's most recent implementation commit, or a concise Conventional Commits-style summary of the stage's committed range.
60
+ 2. **PR body** — markdown filled from `PR_TEMPLATE_PATH`, plus a **merge policy** line naming the base branch, the required merge style (merge commit or rebase-merge, never squash), and the stage's position in the stack (`merge after PR for stage <N-1>`). The user-confirmation step's diff (Q3 `edit then proceed`) is computed against the filled template, not against the raw template file.
61
+ - **Filled-body self-check (runs on each drafted body, before Q3 shows it).** "Fill in the placeholders" is only observable if someone checks that they were filled, so scan the drafted body for these and carry the result into Q3: a residual HTML comment or template marker (`<!-- … -->`, `_Describe your changes…_`, a bare `TODO` / `FIXME` the diff did not introduce), an unchecked `- [ ]` box with no inline N/A justification, a section heading whose body is empty, and a whole body short enough to carry no substance. Each hit is reported to the user with its line — never silently left in, and never auto-filled with invented content. The user remains free to accept it; the point is that they see it before choosing `use as-is`.
66
62
  - Allowed actions during the run (Okstra lead only):
67
63
  - read-only inspection: `git status`, `git status --short`, `git diff`, `git log`, `git rev-parse`, `git ls-remote --heads origin <name>`, `gh pr list --head <branch>`, `gh pr view <url>`.
68
- - merge-conflict probe (only when the user picked `push + PR`): `git fetch origin <chosen-base>` and the exact `git merge-tree` command from step 2b. Both preserve the working tree and branch tips.
69
- - feature-branch push (only when the user picked `push + PR`): `git push -u origin <current-branch>`. The pushed ref MUST be the feature branch — never the chosen base branch. (stage-group mode: the collector branch returned by assemble)
70
- - PR creation (only when the user picked `push + PR` AND no PR with the same head already exists on origin): `gh pr create --base <chosen-base> --head <current-branch> --title "<title>" --body "<body>"`. The title and body are the user-confirmed PR draft.
71
- - PR reuse: if `gh pr list --head <branch> --state open --json url --jq '.[0].url'` returns a URL, treat that PR as already existing — record the URL in the final report and SKIP `gh pr create`.
72
- - after `gh pr create` succeeds (or an existing PR is reused), the lead MUST run `okstra handoff record-pr --plan-run-root <...> --stages <csv> --branch <head branch> --url <pr url>` and quote the command + exit code in the final report. This applies to BOTH modes — whole-task runs record `--stages` as the full Stage Map list — so duplicate-PR prevention for both modes converges on a single consumers ledger.
73
- - stage-group helpers: `okstra handoff eligible`, `okstra handoff assemble`, `okstra handoff record-pr`. The assemble step is the ONLY path that may create commits (merge commits on the collector branch) in this phase.
64
+ - merge-conflict probe (only when the user picked `push + PR`): `git fetch origin <chosen-base>` and the exact `git merge-tree` commands from step 2b. Both preserve the working tree and branch tips.
65
+ - branch push (only when the user picked `push + PR`), in ascending stage order, `git push -u origin <branch>` for: each `merge-base` branch from the pr-plan rows (before the PR that targets it), then each stage's `head_branch`. The pushed ref MUST come from a pr-plan row — never the release base branch.
66
+ - PR creation, one per stage (only when the user picked `push + PR` AND no PR with the same head already exists on origin): `gh pr create --base <row base_branch> --head <row head_branch> --title "<title>" --body "<body>"`. The title and body are the user-confirmed PR draft for that stage. Open them in ascending stage order so each base branch already exists on origin.
67
+ - PR reuse: if `gh pr list --head <branch> --state open --json url --jq '.[0].url'` returns a URL, treat that PR as already existing — record the URL in the final report and SKIP `gh pr create` for that stage.
68
+ - after each `gh pr create` succeeds (or an existing PR is reused), the lead MUST run `okstra handoff record-pr --plan-run-root <...> --stage <N> --branch <head branch> --base <base branch> --url <pr url>` and quote the command + exit code in the final report. One record-pr call per stage — the consumers ledger is what stops the same stage being PR'd twice.
69
+ - stage helpers: `okstra handoff eligible`, `okstra handoff pr-plan`, `okstra handoff record-pr`, `okstra handoff local-checkout`. `pr-plan` is the ONLY path that may create commits in this phase (merge commits on a `merge-base` branch, and only for a multi-dependency stage).
74
70
  - Forbidden actions (any occurrence → terminal status `contract-violated`):
75
71
  {{PHASE_FORBIDDEN_ACTIONS}}
76
72
  - Required deliverable shape (final report, in addition to the standard sections):
77
- - **Source Verification Report**: relative path of the originating `final-verification` final-report file plus the literal quoted `Verdict Token` row, and — when that token is `conditional-accept` — every Conditional Acceptance Condition row quoted with its `blocksReleaseHandoff` value.
78
- - **Feature Branch & Working-Tree State**: branch name from `git rev-parse --abbrev-ref HEAD`, output of `git status --short` at run start.
73
+ - **Source Verification Reports**: one row per selected stage — relative path of that stage's originating `final-verification` final-report plus the literal quoted `Verdict Token` row, and — when that token is `conditional-accept` — every Conditional Acceptance Condition row quoted with its `blocksReleaseHandoff` value.
74
+ - **Feature Branch & Working-Tree State**: the branch from `git rev-parse --abbrev-ref HEAD` at run start and the output of `git status --short` at run start.
75
+ - **Stage PR Plan**: the pr-plan rows — stage, head branch, head commit, base kind, base branch, base commit — plus, for every `merge-base` row, which predecessor stages it merges and the merge commits it created. This is the table a reader uses to merge the stack in the right order.
79
76
  - **User Selections**: a block recording each prompt and the user's verbatim answer.
80
77
  - Q1 action: `local checkout` | `push + PR` | `skip`.
81
- - Q1c checkout target (only when Q1 is `local checkout`): `whole-task branch` | `stage <N> stack branch`, plus the `--stage <N>` value this answer produced (or `no --stage` for the whole-task branch). Record it in the `User Selections` row `H1c` (`userSelections.h1c`); omit the row entirely when Q1 was not `local checkout`.
82
- - Q2 PR base (if applicable): the chosen branch and how it was selected (menu pick vs free-form input).
83
- - Q2b merge-conflict probe (if applicable): `not-run` | `clean` (no conflict, no prompt shown) | `proceed anyway` | `change base branch` | `cancel`. Record it in both the `User Selections` row `H2b` and the `Merge Conflict Probe` deliverable. When a conflict was detected, list the conflicting paths.
78
+ - Q1c checkout stage (only when Q1 is `local checkout`): the `--stage <N>` value this answer produced. Record it in the `User Selections` row `H1c` (`userSelections.h1c`); omit the row entirely when Q1 was not `local checkout`.
79
+ - Q2 release base (if applicable): the chosen branch and how it was selected (menu pick vs free-form input).
80
+ - Q2b merge-conflict probe (if applicable): `not-run` | `clean` (no conflict, no prompt shown) | `proceed anyway` | `change base branch` | `cancel`. Record it in both the `User Selections` row `H2b` and the `Merge Conflict Probe` deliverable. When a conflict was detected, list the conflicting stages and paths.
84
81
  - Q3 title/body: `use as-is` | `edit then proceed` (with a diff between the lead's draft and the final text) | `cancel`.
85
82
  - **Executed Commands**: every git / gh command the lead actually ran, with its exit code and a one-line stdout/stderr summary. Read-only inspection commands MAY be summarised; mutating commands MUST be listed verbatim.
86
- - **Commit List**: each existing implementation commit in `git log <base>..HEAD`, with short/full SHA, subject line, and touched files. Release-handoff MUST NOT create new commits.
83
+ - **Commit List**: per stage, each implementation commit in `git log <base_commit>..<head_commit>`, with short/full SHA, subject line, and touched files. Release-handoff MUST NOT create new commits other than a `merge-base` branch's merge commits.
87
84
  - **Merge Conflict Probe**: one of
88
85
  - `- Not run (user picked local checkout or skip).`
89
- - `- Clean — no conflicts against <base> at <origin/base SHA>.`
90
- - `- Conflicts detected against <base> at <origin/base SHA>; user chose <proceed anyway | change base branch | cancel>. Conflicting paths: <list>.`
91
- - **Pull Request Outcome**: one of
86
+ - `- Clean — every stage merges cleanly into its PR base at <origin/base SHA>.`
87
+ - `- Conflicts detected for stage(s) <list> against <base> at <origin/base SHA>; user chose <proceed anyway | change base branch | cancel>. Conflicting paths: <list>.`
88
+ - **Pull Request Outcomes**: one row per selected stage, each one of
92
89
  - `- No PR action requested.` (user picked `local checkout` or `skip`)
93
- - `- PR created: <url>` with title and base branch
94
- - `- PR reused: <url>` when an existing PR was found via `gh pr list`
95
- - `- PR creation skipped: <reason>` for any user-driven cancellation
90
+ - `- Stage <N> PR created: <url>` with title and base branch
91
+ - `- Stage <N> PR reused: <url>` when an existing PR was found via `gh pr list`
92
+ - `- Stage <N> PR creation skipped: <reason>` for any user-driven cancellation
96
93
  - **Local Checkout Outcome**: one of
97
94
  - `- Not run (user picked push + PR or skip).`
98
- - `- Checked out <branch> into <main worktree path>; okstra worktree <path> removed. Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
99
- - `- Checked out <branch> into <main worktree path>; no okstra worktree removed (already torn down — the branch survived). Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
95
+ - `- Checked out <branch> (stage <N>) into <main worktree path>; okstra worktree <path> removed. Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
96
+ - `- Checked out <branch> (stage <N>) into <main worktree path>; no okstra worktree removed (already torn down — the branch survived). Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
100
97
  - Pick between the two `Checked out` variants by the command's `removedWorktree` field: a non-empty path takes the first, an empty string takes the second. Never write a removal that did not happen.
101
- - **Stage Group** (stage-group mode only): selected stages, each stage's single-stage verification report path + quoted `Verdict Token` row, collector branch name, merge commit SHAs from assemble, and the dependency-closure verdict (from the assemble output / error).
102
- - **Routing recommendation**: explicit `done` token, since release-handoff is the terminal lifecycle phase. If the run ended in `skip` or `cancel`, the recommendation MUST also state whether re-entry into release-handoff is appropriate.
98
+ - **Routing recommendation**: explicit `done` token, since release-handoff is the terminal lifecycle phase. If the run ended in `skip` or `cancel`, or delivered only some of the selected stages, the recommendation MUST state which stages still need a PR and that re-entry into release-handoff is appropriate.
103
99
  - Self-review pass before finalising the report (the Okstra lead runs this):
104
- 1. **Entry-gate audit** — section 2 cites the originating final-verification report path and the literal `Verdict Token` row with a release-ready value. If either is missing, or a `conditional-accept` run's PR body omits the conditions, the run is invalid and MUST be re-routed to `final-verification`.
100
+ 1. **Entry-gate audit** — the report cites, for every stage it delivered, that stage's final-verification report path and the literal `Verdict Token` row with a release-ready value. If any is missing, or a `conditional-accept` stage's PR body omits its conditions, the run is invalid and MUST be re-routed to `final-verification`.
105
101
  2. **User-selection traceability** — every executed mutating command maps to a user selection captured in the report. Any mutating command without a corresponding user answer is a contract violation.
106
102
  3. **Forbidden-action audit** — scan the run's session transcripts (`git`, `gh` invocations) for every entry in the Forbidden actions list above. Any occurrence means the run has crossed into unsafe territory and MUST be flagged as `contract-violated`.
107
- 4. **Push-target audit** — for every `git push` recorded, confirm the refspec resolves to the feature branch, not the base branch.
108
- 5. **Idempotency check** — if a PR with the same head already existed at run start, confirm the report records `PR reused` rather than a fresh `gh pr create` invocation.
109
- 6. **Merge-conflict probe audit** — for any `push + PR` run, confirm the report's `Merge Conflict Probe` section is present and either records `Clean` or records `Conflicts detected` with the user's verbatim choice. A missing or unparseable probe entry on a `push + PR` run is a contract violation.
103
+ 4. **Push-target audit** — for every `git push` recorded, confirm the refspec resolves to a branch that appears in the pr-plan output, not to the release base branch.
104
+ 5. **Stack-integrity audit** — for every PR opened, confirm its base is the `base_branch` of that stage's pr-plan row, that the base branch was pushed first, and that the PR body carries the no-squash merge policy. A stacked PR opened against the release base instead of its predecessor ships the predecessor's diff twice.
105
+ 6. **Idempotency check** — for every stage whose PR already existed at run start, confirm the report records `PR reused` rather than a fresh `gh pr create` invocation.
106
+ 7. **Merge-conflict probe audit** — for any `push + PR` run, confirm the report's `Merge Conflict Probe` section is present and either records `Clean` or records `Conflicts detected` with the user's verbatim choice. A missing or unparseable probe entry on a `push + PR` run is a contract violation.
110
107
  - Non-goals:
111
- - re-litigating the final-verification verdict — release-handoff trusts the cited release-ready verdict and does not reopen acceptance checks. Carrying a conditional-accept's conditions into the PR body is transcription, not verification: the lead does not check whether a condition has been satisfied.
112
- - creating, amending, squashing, or rewriting commits. Commit production belongs to `implementation`.
113
- - opening additional PRs, releases, or deployments beyond the single PR the user chose to create.
114
- - merging the PR. Merging is a separate, manual step performed by the user (or by repo automation) after release-handoff ends; the lead MUST NOT call `gh pr merge`.
108
+ - re-litigating a final-verification verdict — release-handoff trusts the cited release-ready verdicts and does not reopen acceptance checks. Carrying a conditional-accept's conditions into the PR body is transcription, not verification: the lead does not check whether a condition has been satisfied.
109
+ - creating, amending, squashing, rebasing, or rewriting commits. Commit production belongs to `implementation`; the only commits this phase may create are the merge commits `okstra handoff pr-plan` makes on a `merge-base` branch.
110
+ - bundling several stages into one PR, or building a branch that collects every stage. One stage is one PR.
111
+ - opening releases or deployments beyond the per-stage PRs the user chose to create.
112
+ - merging the PRs. Merging is a separate, manual step performed by the user (or by repo automation) after release-handoff ends; the lead MUST NOT call `gh pr merge`.
115
113
  - escalating beyond the menu choices on user phrasing — every mutating action requires an explicit menu selection.
@@ -0,0 +1,39 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "requirements-discovery",
4
+ "roles": [
5
+ {
6
+ "mode": "static",
7
+ "roleId": "analyser",
8
+ "dutyId": "discovery-worker",
9
+ "min": 2,
10
+ "recommended": 3,
11
+ "max": 5
12
+ },
13
+ {
14
+ "mode": "static",
15
+ "roleId": "critic",
16
+ "dutyId": "scope-critic",
17
+ "min": 0,
18
+ "recommended": 1,
19
+ "max": 1
20
+ },
21
+ {
22
+ "mode": "static",
23
+ "roleId": "report-writer",
24
+ "dutyId": "report-writer",
25
+ "min": 1,
26
+ "recommended": 1,
27
+ "max": 1
28
+ },
29
+ {
30
+ "mode": "dynamic",
31
+ "roleId": "verifier",
32
+ "dutyId": "reverification-worker",
33
+ "sourceRoleIds": [
34
+ "analyser"
35
+ ],
36
+ "activation": "per-selected-source"
37
+ }
38
+ ]
39
+ }