okstra 0.146.1 → 0.148.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 (137) hide show
  1. package/README.md +23 -9
  2. package/docs/architecture/storage-model.md +39 -65
  3. package/docs/architecture.md +68 -60
  4. package/docs/cli.md +40 -23
  5. package/docs/for-ai/skills/okstra-run.md +13 -34
  6. package/docs/performance-improvement-plan-v2.md +2 -2
  7. package/docs/pr-template-usage.md +1 -1
  8. package/docs/project-structure-overview.md +26 -22
  9. package/docs/task-process/README.md +4 -4
  10. package/docs/task-process/common-flow.md +12 -12
  11. package/docs/task-process/final-verification.md +2 -2
  12. package/docs/task-process/implementation.md +1 -1
  13. package/docs/task-process/release-handoff.md +1 -1
  14. package/package.json +2 -2
  15. package/runtime/BUILD.json +2 -2
  16. package/runtime/agents/workers/antigravity-worker.md +2 -2
  17. package/runtime/agents/workers/claude-worker.md +1 -1
  18. package/runtime/agents/workers/codex-worker.md +2 -2
  19. package/runtime/agents/workers/grok-worker.md +256 -0
  20. package/runtime/agents/workers/kimi-worker.md +256 -0
  21. package/runtime/agents/workers/report-writer-worker.md +12 -12
  22. package/runtime/bin/lib/okstra/cli.sh +13 -1
  23. package/runtime/bin/lib/okstra/globals.sh +3 -0
  24. package/runtime/bin/lib/okstra/usage.sh +17 -12
  25. package/runtime/bin/okstra-grok-exec.sh +5 -0
  26. package/runtime/bin/okstra-kimi-exec.sh +5 -0
  27. package/runtime/bin/okstra-provider-exec.py +235 -0
  28. package/runtime/bin/okstra-render-final-report.py +4 -4
  29. package/runtime/bin/okstra-render-report-views.py +100 -12
  30. package/runtime/bin/okstra.sh +3 -0
  31. package/runtime/prompts/lead/adapters/antigravity.md +48 -0
  32. package/runtime/prompts/lead/adapters/claude-code.md +13 -11
  33. package/runtime/prompts/lead/adapters/codex.md +7 -7
  34. package/runtime/prompts/lead/okstra-lead-contract.md +5 -5
  35. package/runtime/prompts/lead/report-writer.md +16 -12
  36. package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
  37. package/runtime/prompts/profiles/_common-contract.md +16 -10
  38. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
  39. package/runtime/prompts/profiles/_implementation-diff-review.md +1 -1
  40. package/runtime/prompts/profiles/_implementation-executor.md +12 -12
  41. package/runtime/prompts/profiles/_implementation-self-check.md +4 -4
  42. package/runtime/prompts/profiles/_implementation-verifier.md +3 -3
  43. package/runtime/prompts/profiles/change-impact-analysis.md +2 -0
  44. package/runtime/prompts/profiles/error-analysis.md +2 -0
  45. package/runtime/prompts/profiles/feature-analysis.md +2 -0
  46. package/runtime/prompts/profiles/final-verification.md +3 -1
  47. package/runtime/prompts/profiles/forbidden-actions.json +4 -4
  48. package/runtime/prompts/profiles/implementation-planning.md +3 -1
  49. package/runtime/prompts/profiles/implementation.md +2 -2
  50. package/runtime/prompts/profiles/improvement-discovery.md +6 -2
  51. package/runtime/prompts/profiles/project-analysis.md +2 -0
  52. package/runtime/prompts/profiles/release-handoff.md +7 -7
  53. package/runtime/prompts/profiles/requirements-discovery.md +2 -0
  54. package/runtime/prompts/wizard/prompts.ko.json +9 -1
  55. package/runtime/python/okstra_ctl/codex_dispatch.py +68 -87
  56. package/runtime/python/okstra_ctl/dispatch_core.py +4 -22
  57. package/runtime/python/okstra_ctl/final_report_schema.py +37 -12
  58. package/runtime/python/okstra_ctl/lead_events.py +1 -1
  59. package/runtime/python/okstra_ctl/lead_runtime.py +13 -2
  60. package/runtime/python/okstra_ctl/models.py +156 -8
  61. package/runtime/python/okstra_ctl/path_hints.py +9 -25
  62. package/runtime/python/okstra_ctl/paths.py +1 -1
  63. package/runtime/python/okstra_ctl/render.py +172 -74
  64. package/runtime/python/okstra_ctl/render_final_report.py +136 -28
  65. package/runtime/python/okstra_ctl/report_contract.py +124 -0
  66. package/runtime/python/okstra_ctl/report_finalize.py +1 -1
  67. package/runtime/python/okstra_ctl/report_html/__init__.py +10 -0
  68. package/runtime/python/okstra_ctl/report_html/common.py +86 -0
  69. package/runtime/python/okstra_ctl/report_html/filters.py +104 -0
  70. package/runtime/python/okstra_ctl/report_html/models.py +59 -0
  71. package/runtime/python/okstra_ctl/report_html/render.py +76 -0
  72. package/runtime/python/okstra_ctl/report_html/router.py +40 -0
  73. package/runtime/python/okstra_ctl/report_html/view_models/__init__.py +1 -0
  74. package/runtime/python/okstra_ctl/report_html/view_models/change_impact_analysis.py +39 -0
  75. package/runtime/python/okstra_ctl/report_html/view_models/error_analysis.py +49 -0
  76. package/runtime/python/okstra_ctl/report_html/view_models/feature_analysis.py +39 -0
  77. package/runtime/python/okstra_ctl/report_html/view_models/final_verification.py +47 -0
  78. package/runtime/python/okstra_ctl/report_html/view_models/implementation.py +47 -0
  79. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +103 -0
  80. package/runtime/python/okstra_ctl/report_html/view_models/improvement_discovery.py +43 -0
  81. package/runtime/python/okstra_ctl/report_html/view_models/project_analysis.py +54 -0
  82. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +54 -0
  83. package/runtime/python/okstra_ctl/report_html/view_models/requirements_discovery.py +55 -0
  84. package/runtime/python/okstra_ctl/report_html/visualizations.py +139 -0
  85. package/runtime/python/okstra_ctl/report_view_artifacts.py +4 -1
  86. package/runtime/python/okstra_ctl/report_views.py +15 -43
  87. package/runtime/python/okstra_ctl/run.py +276 -51
  88. package/runtime/python/okstra_ctl/runner_resolution.py +103 -0
  89. package/runtime/python/okstra_ctl/schema_excerpt.py +7 -17
  90. package/runtime/python/okstra_ctl/team.py +2 -7
  91. package/runtime/python/okstra_ctl/wizard.py +194 -21
  92. package/runtime/python/okstra_ctl/worker_artifacts.py +46 -0
  93. package/runtime/python/okstra_ctl/workers.py +3 -1
  94. package/runtime/python/okstra_ctl/workflow.py +4 -2
  95. package/runtime/python/okstra_token_usage/__init__.py +1 -0
  96. package/runtime/python/okstra_token_usage/collect.py +32 -23
  97. package/runtime/python/okstra_token_usage/pricing.py +35 -3
  98. package/runtime/schemas/final-report-v2.0.schema.json +3923 -0
  99. package/runtime/skills/okstra-run/SKILL.md +31 -42
  100. package/runtime/templates/prd/pr-body.template.md +1 -1
  101. package/runtime/templates/reports/final-report-v2.template.md +66 -0
  102. package/runtime/templates/reports/html/assets/base.css +41 -0
  103. package/runtime/templates/reports/html/assets/base.js +5 -0
  104. package/runtime/templates/reports/html/base.template.html +79 -0
  105. package/runtime/templates/reports/html/macros/forms.html +47 -0
  106. package/runtime/templates/reports/html/macros/layout.html +19 -0
  107. package/runtime/templates/reports/html/macros/visualizations.html +27 -0
  108. package/runtime/templates/reports/html/tasks/change-impact-analysis.template.html +40 -0
  109. package/runtime/templates/reports/html/tasks/error-analysis.template.html +40 -0
  110. package/runtime/templates/reports/html/tasks/feature-analysis.template.html +40 -0
  111. package/runtime/templates/reports/html/tasks/final-verification.template.html +39 -0
  112. package/runtime/templates/reports/html/tasks/implementation-planning.template.html +47 -0
  113. package/runtime/templates/reports/html/tasks/implementation.template.html +40 -0
  114. package/runtime/templates/reports/html/tasks/improvement-discovery.template.html +29 -0
  115. package/runtime/templates/reports/html/tasks/project-analysis.template.html +57 -0
  116. package/runtime/templates/reports/html/tasks/release-handoff.template.html +36 -0
  117. package/runtime/templates/reports/html/tasks/requirements-discovery.template.html +37 -0
  118. package/runtime/templates/reports/report.js +21 -4
  119. package/runtime/templates/reports/settings.template.json +4 -0
  120. package/runtime/templates/reports/task-brief.template.md +7 -7
  121. package/runtime/validators/validate-report-views.py +86 -4
  122. package/runtime/validators/validate-run.py +73 -15
  123. package/runtime/validators/validate_improvement_report.py +55 -0
  124. package/runtime/validators/validate_session_conformance.py +2 -1
  125. package/src/cli-registry.mjs +4 -4
  126. package/src/commands/execute/codex-dispatch.mjs +7 -10
  127. package/src/commands/execute/render-bundle.mjs +3 -3
  128. package/src/commands/execute/run.mjs +17 -52
  129. package/src/commands/execute/wizard.mjs +4 -1
  130. package/src/commands/lifecycle/doctor.mjs +6 -3
  131. package/src/commands/lifecycle/install.mjs +49 -21
  132. package/src/commands/report/finalize.mjs +2 -3
  133. package/src/commands/report/render-final-report.mjs +4 -2
  134. package/src/commands/report/render-views.mjs +8 -8
  135. package/src/lib/runtime-manifest.mjs +1 -1
  136. package/src/lib/runtime-resolver.mjs +2 -2
  137. package/src/lib/worker-agent-render.mjs +50 -0
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env python3
2
- """CLI entrypoint for Phase 7 step 1.5 — render the self-contained HTML
3
- view of an okstra final-report markdown.
2
+ """CLI entrypoint for Phase 7 step 1.5 — render a final-report HTML view.
4
3
 
5
4
  Usage:
6
- okstra-render-report-views.py <path-to-final-report.md>
5
+ okstra-render-report-views.py <path-to-final-report.data.json|final-report.md>
7
6
  [--task-key <task-group/task-id>]
8
7
  [--task-type <profile>]
9
8
  [--seq <NNN>]
10
9
  [--source-report <relative-path>]
11
10
 
12
- When the optional flags are omitted, the script infers what it can from
13
- the report path (``runs/<task-type>/reports/final-report-<task-type>-<seq>.md``)
14
- and the report's frontmatter / ``- Task Key:`` / ``- Task Type:`` lines.
11
+ Schema-v2 ``.data.json`` input is rendered directly into the dedicated task
12
+ HTML template and always produces an HTML sibling. Markdown input resolves its
13
+ data sibling first; schema-v1 and quick reports keep the legacy conditional
14
+ Markdown renderer.
15
15
 
16
16
  Output (idempotent — overwrites):
17
17
  - <stem>.html — single-file self-contained HTML view
@@ -22,13 +22,19 @@ This script is the canonical single-reference-point. The Node CLI
22
22
  from __future__ import annotations
23
23
 
24
24
  import argparse
25
+ import json
25
26
  import os
27
+ import re
26
28
  import sys
27
29
  from pathlib import Path
28
30
 
29
31
  REPO_ROOT = Path(__file__).resolve().parents[1]
30
32
  SCRIPTS_DIR = REPO_ROOT / "scripts"
31
- HOME_LIB = Path(os.environ.get("OKSTRA_HOME", str(Path.home() / ".okstra"))) / "lib" / "python"
33
+ HOME_LIB = (
34
+ Path(os.environ.get("OKSTRA_HOME", str(Path.home() / ".okstra")))
35
+ / "lib"
36
+ / "python"
37
+ )
32
38
 
33
39
  # Prefer dev sources when present, fall back to install. Without this
34
40
  # order, a stale install (~/.okstra/lib/python/okstra_ctl) without the
@@ -43,6 +49,10 @@ elif HOME_LIB.is_dir() and str(HOME_LIB) not in sys.path:
43
49
  sys.path.insert(0, str(HOME_LIB))
44
50
 
45
51
  from okstra_ctl.report_views import infer_run_meta, render_html_view # noqa: E402
52
+ from okstra_ctl.final_report_paths import ( # noqa: E402
53
+ final_report_data_path,
54
+ final_report_markdown_path,
55
+ )
46
56
 
47
57
 
48
58
  _OKSTRA_HOME = Path(os.environ.get("OKSTRA_HOME", str(Path.home() / ".okstra")))
@@ -77,6 +87,60 @@ def _load_assets() -> tuple[str, str]:
77
87
  return css_text, js_text
78
88
 
79
89
 
90
+ def _templates_root() -> Path:
91
+ for directory in _TEMPLATES_DIRS:
92
+ if (directory / "html" / "base.template.html").is_file():
93
+ return directory
94
+ raise SystemExit(
95
+ "schema-v2 HTML templates not found. Looked under: "
96
+ + ", ".join(str(directory) for directory in _TEMPLATES_DIRS)
97
+ )
98
+
99
+
100
+ def _report_pair(report_path: Path) -> tuple[Path, Path]:
101
+ if report_path.name.endswith(".data.json"):
102
+ return report_path, final_report_markdown_path(report_path)
103
+ return final_report_data_path(report_path), report_path
104
+
105
+
106
+ def _load_data_if_present(data_path: Path) -> dict | None:
107
+ if not data_path.is_file():
108
+ return None
109
+ try:
110
+ data = json.loads(data_path.read_text(encoding="utf-8"))
111
+ except json.JSONDecodeError as exc:
112
+ raise SystemExit(
113
+ f"final-report data is not valid JSON: {data_path} ({exc})"
114
+ ) from exc
115
+ if not isinstance(data, dict):
116
+ raise SystemExit(f"final-report data must be a JSON object: {data_path}")
117
+ return data
118
+
119
+
120
+ def _v2_run_meta(data: dict, markdown_path: Path, args: argparse.Namespace):
121
+ from okstra_ctl.report_html.models import HtmlRunMeta
122
+
123
+ header = data.get("header", {})
124
+ task_key = args.task_key or header.get("taskKey")
125
+ task_type = args.task_type or header.get("taskType")
126
+ match = re.search(r"-(\d+)\.md$", markdown_path.name)
127
+ seq = (
128
+ args.seq
129
+ or data.get("analysisCommon", {}).get("runSeq")
130
+ or (match.group(1) if match else None)
131
+ )
132
+ if not all(
133
+ isinstance(value, str) and value for value in (task_key, task_type, seq)
134
+ ):
135
+ raise SystemExit("schema-v2 report metadata requires task-key, task-type, and seq")
136
+ return HtmlRunMeta(
137
+ task_key,
138
+ task_type,
139
+ seq,
140
+ args.source_report or markdown_path.name,
141
+ )
142
+
143
+
80
144
  def main(argv: list[str] | None = None) -> int:
81
145
  parser = argparse.ArgumentParser(
82
146
  description="Render the self-contained HTML view of an okstra final-report."
@@ -88,18 +152,42 @@ def main(argv: list[str] | None = None) -> int:
88
152
  parser.add_argument("--source-report", default=None)
89
153
  args = parser.parse_args(argv)
90
154
 
91
- report_path: Path = args.report_path.resolve()
155
+ report_path = args.report_path.resolve()
92
156
  if not report_path.is_file():
93
157
  parser.error(f"final-report not found: {report_path}")
158
+ data_path, markdown_path = _report_pair(report_path)
159
+ data = _load_data_if_present(data_path)
160
+
161
+ if data is not None and data.get("schemaVersion") == "2.0":
162
+ if not markdown_path.is_file():
163
+ parser.error(f"schema-v2 markdown sibling not found: {markdown_path}")
164
+ from okstra_ctl.report_html.render import render_v2_html_view
165
+
166
+ html_path = render_v2_html_view(
167
+ data_path,
168
+ markdown_path,
169
+ run_meta=_v2_run_meta(data, markdown_path, args),
170
+ templates_root=_templates_root(),
171
+ )
172
+ print(f"html: {html_path}")
173
+ return 0
94
174
 
175
+ if not markdown_path.is_file():
176
+ parser.error(f"legacy markdown sibling not found: {markdown_path}")
95
177
  meta = infer_run_meta(
96
- report_path, task_key=args.task_key, task_type=args.task_type,
97
- seq=args.seq, source_report=args.source_report,
178
+ markdown_path,
179
+ task_key=args.task_key,
180
+ task_type=args.task_type,
181
+ seq=args.seq,
182
+ source_report=args.source_report,
98
183
  )
99
184
  css, js = _load_assets()
100
- html_path = render_html_view(report_path, run_meta=meta, css=css, js=js)
185
+ html_path = render_html_view(markdown_path, run_meta=meta, css=css, js=js)
101
186
  if html_path is None:
102
- print("html: skipped (no §1 clarification rows — html view carries no interactive forms for this report)")
187
+ print(
188
+ "html: skipped (no §1 clarification rows — html view carries no "
189
+ "interactive forms for this report)"
190
+ )
103
191
  else:
104
192
  print(f"html: {html_path}")
105
193
  return 0
@@ -110,10 +110,13 @@ PY_ARGS=(
110
110
  [[ -n "${DIRECTIVE-}" ]] && PY_ARGS+=(--directive "$DIRECTIVE")
111
111
  [[ -n "${FIX_CYCLE-}" ]] && PY_ARGS+=(--fix-cycle "$FIX_CYCLE")
112
112
  [[ -n "${WORKERS_OVERRIDE-}" ]] && PY_ARGS+=(--workers "$WORKERS_OVERRIDE")
113
+ [[ -n "${LEAD_PROVIDER_OVERRIDE-}" ]] && PY_ARGS+=(--lead-provider "$LEAD_PROVIDER_OVERRIDE")
113
114
  [[ -n "${LEAD_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--lead-model "$LEAD_MODEL_OVERRIDE")
114
115
  [[ -n "${CLAUDE_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--claude-model "$CLAUDE_MODEL_OVERRIDE")
115
116
  [[ -n "${CODEX_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--codex-model "$CODEX_MODEL_OVERRIDE")
116
117
  [[ -n "${ANTIGRAVITY_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--antigravity-model "$ANTIGRAVITY_MODEL_OVERRIDE")
118
+ [[ -n "${WORKER_MODELS_OVERRIDE-}" ]] && PY_ARGS+=(--worker-model "$WORKER_MODELS_OVERRIDE")
119
+ [[ -n "${REPORT_WRITER_PROVIDER_OVERRIDE-}" ]] && PY_ARGS+=(--report-writer-provider "$REPORT_WRITER_PROVIDER_OVERRIDE")
117
120
  [[ -n "${REPORT_WRITER_MODEL_OVERRIDE-}" ]] && PY_ARGS+=(--report-writer-model "$REPORT_WRITER_MODEL_OVERRIDE")
118
121
  [[ -n "${LEAD_RUNTIME-}" ]] && PY_ARGS+=(--lead-runtime "$LEAD_RUNTIME")
119
122
  [[ -n "${EXECUTOR_OVERRIDE-}" ]] && PY_ARGS+=(--executor "$EXECUTOR_OVERRIDE")
@@ -0,0 +1,48 @@
1
+ # Antigravity Lead Runtime Adapter
2
+
3
+ ## Scope
4
+
5
+ This adapter maps the neutral Okstra lead operations to the current Antigravity CLI host. Read it only when the rendered launch prompt selects `leadRuntime=antigravity`.
6
+
7
+ ## Capability declaration
8
+
9
+ | Field | Value |
10
+ |---|---|
11
+ | `runtime` | `antigravity` |
12
+ | `leadRoleLabel` | `Antigravity lead` |
13
+ | `userPromptMode` | `host-text` |
14
+ | `workerDispatchBackend` | `mixed` |
15
+ | `initialPromptDeliveryMode` | `eager-include` |
16
+ | `sessionAccounting` | `artifact-only` |
17
+ | `resumeMode` | `artifact-checkpoint` |
18
+ | `teardownMode` | `process-cleanup` |
19
+ | `leadEventSource` | `lead-events-jsonl` |
20
+
21
+ ## Semantic operation mapping
22
+
23
+ | Operation | Mapping |
24
+ |---|---|
25
+ | `read_artifacts` | Read the manifest-provided paths through the current Antigravity host file interface. |
26
+ | `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
27
+ | `prompt_user` | Ask through the current host text/question interface and stop at approval gates until an explicit answer arrives. |
28
+ | `dispatch_worker` | Dispatch every `runner=native-session` Antigravity assignment through the current host. Dispatch every `runner=cli-wrapper` assignment through its registered provider wrapper. |
29
+ | `await_workers` | Await native host workers through the host primitive and CLI workers through their status sidecars, then verify terminal state and Result Paths. |
30
+ | `redispatch_worker` | Start a fresh native worker or CLI wrapper attempt according to the persisted assignment and record the supplied dispatch kind. |
31
+ | `shutdown_workers` | Perform host or process cleanup only for resources owned by this run. |
32
+ | `record_lead_event` | Append the required structured event to the manifest-provided `leadEventsPath`; emit the matching user-facing `PROGRESS:` line. |
33
+ | `collect_usage` | Collect host- or artifact-backed usage through the existing Okstra token-usage path; do not substitute another runtime's session log. |
34
+
35
+ ## Antigravity dispatch details
36
+
37
+ - For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
38
+ - The current Antigravity session is the lead. Never launch another provider as a replacement lead.
39
+ - The prepared run manifest and team-state are the assignment authority. Keep `runner=native-session` assignments in the current host and route `runner=cli-wrapper` assignments through the registered wrapper.
40
+ - Do not infer the current host from an installed `agy` binary. The `antigravity` runtime must come from the active host skill or an explicit runtime flag.
41
+ - Unsupported workers or unavailable models fail before dispatch; do not change the provider, model, or runner silently.
42
+ - Reverify and critic retries use fresh attempts and persist the core-supplied `dispatchKind`.
43
+ - Report-writer completion requires both the data Result Path and the worker-results audit path.
44
+
45
+ ## Completion, cleanup, and resume
46
+
47
+ - A native host completion or successful wrapper return alone is insufficient. Verify terminal state, every required completion path, and the corresponding dispatch audit record.
48
+ - Resume from run artifacts and lead-event checkpoints. Do not invent Claude or Codex session identifiers.
@@ -11,7 +11,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
11
11
  | `runtime` | `claude-code` |
12
12
  | `leadRoleLabel` | `Claude lead` |
13
13
  | `userPromptMode` | `native-question` |
14
- | `workerDispatchBackend` | `team` |
14
+ | `workerDispatchBackend` | `mixed` |
15
15
  | `initialPromptDeliveryMode` | `lazy-path-reference` |
16
16
  | `sessionAccounting` | `claude-jsonl` |
17
17
  | `resumeMode` | `session-id` |
@@ -25,10 +25,10 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
25
25
  | `read_artifacts` | Use the host file-read primitive and preserve the core contract's read order. |
26
26
  | `write_artifact` | Use the host file-write primitive only for paths authorized by the active lifecycle phase. |
27
27
  | `prompt_user` | Use the native question tool for approvals and clarifications; do not infer an answer from silence. |
28
- | `dispatch_worker` | Dispatch `Agent(name: "<role>", run_in_background: true)` without `team_name`; apply the assigned model as specified below. |
28
+ | `dispatch_worker` | Dispatch each assignment through `Agent(name: "<role>", run_in_background: true)` without `team_name`; use an in-process worker for `runner=native-session` and the assigned provider's wrapper worker for `runner=cli-wrapper`. |
29
29
  | `await_workers` | Arm one background shell poll for the pending Result Paths; the spawn acknowledgement is not completion. |
30
30
  | `redispatch_worker` | Dispatch a fresh `Agent(...)` session with the same prompt plus the core reverify/retry reason. |
31
- | `shutdown_workers` | Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` only to confirmed-complete teammates selected for cleanup. |
31
+ | `shutdown_workers` | For each confirmed-complete worker selected for cleanup, send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to idle the roster member **and** call `TaskStop(task_id: "<name>")` to stop its background task. Both are required; neither subsumes the other. |
32
32
  | `record_lead_event` | Emit the required `PROGRESS:` line as assistant text and persist core-required state/artifact updates. |
33
33
  | `collect_usage` | Run `okstra token-usage` against the team-state; it reads the run-scoped `~/.claude/projects` session JSONL evidence. |
34
34
 
@@ -36,14 +36,14 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
36
36
 
37
37
  - The session owns one implicit team. `TeamCreate` and `TeamDelete` are absent on current Claude Code builds; never probe for them and never pass `team_name`.
38
38
  - Set `name` to the core-assigned functional role label so token attribution can match `agentName`.
39
- - Map the core assignment key to the native `subagent_type` field: `claude-worker`, `codex-worker`, `antigravity-worker`, or `report-writer-worker`. Never substitute `general-purpose` for a rostered Report writer worker.
40
- - For in-process Claude and report-writer roles, map `modelExecutionValue` to the supported family token and pass it as the `model` argument. CLI-wrapper roles apply their model in the wrapper and remain `inherit` at the Agent layer.
39
+ - Map a `runner=native-session` Claude assignment to `claude-worker`. Map a `runner=cli-wrapper` assignment to `<provider>-worker`; the registered providers currently resolve to `claude-worker`, `codex-worker`, `antigravity-worker`, `grok-worker`, or `kimi-worker`. The functional `report-writer` worker ID does not override its provider assignment. Never substitute `general-purpose` for a rostered worker.
40
+ - For `runner=native-session`, map `modelExecutionValue` to the supported Claude family token and pass it as the `model` argument. CLI-wrapper roles apply their exact model in the provider wrapper and remain `inherit` at the Agent layer.
41
41
  - A resumed lead can dispatch a fresh worker; resume is not a valid reason to omit a rostered role.
42
42
 
43
43
  ### Dispatch-time model enforcement
44
44
 
45
- - `Claude worker` and `Report writer worker` definitions declare `model: inherit`; the lead MUST override that default by passing the assigned family token (`fable`, `opus`, `sonnet`, or `haiku`) as the `Agent(...)` `model` argument.
46
- - Codex and Antigravity wrapper agents remain `inherit` at the Agent layer because their exact `modelExecutionValue` is applied by the wrapper CLI's own model argument.
45
+ - A native Claude worker definition declares `model: inherit`; the lead MUST override that default by passing the assigned family token (`fable`, `opus`, `sonnet`, or `haiku`) as the `Agent(...)` `model` argument.
46
+ - Every CLI-wrapper agent remains `inherit` at the Agent layer because its exact `modelExecutionValue` is applied by `okstra-claude-exec.sh`, `okstra-codex-exec.sh`, `okstra-antigravity-exec.sh`, `okstra-grok-exec.sh`, or `okstra-kimi-exec.sh` according to the assignment provider.
47
47
  - Missing or unsupported family-token mapping is a pre-dispatch contract failure. Never inherit the lead model, choose a nearby alias, or switch provider silently.
48
48
  - Every analysis dispatch sets `name: "<workerId>-worker"`; convergence retries append `-reverify-r<N>`, implementation uses the functional `-executor` / `-verifier` suffix, and report writing uses `report-writer`. These values are retained as `agentName` in session JSONL for usage attribution.
49
49
  - Every Codex / Antigravity prompt includes `**Pane role:** <functional-role>` so the wrapper's optional fifth argument names both its caller pane and trace pane.
@@ -56,7 +56,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
56
56
  - For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
57
57
  - Reverify dispatch uses a fresh one-shot `Agent(...)` call named `<workerId>-worker-reverify-r<N>`. Preserve the initial worker's definition and map an in-process Claude assignment's `modelExecutionValue` to its exact family token; CLI-wrapper assignments remain `inherit` at the Agent layer and apply the exact model in their wrapper.
58
58
  - Critic dispatch uses `name: "<provider>-worker-critic"`, `dispatchKind: "critic"`, and the exact mapped model from `config.critic.modelExecutionValue`. If that value cannot be mapped, record `critic-skipped: model-unresolved` and do not dispatch.
59
- - Report-writer dispatch uses `name: "report-writer"` and maps the roster assignment's `modelExecutionValue` to the supported family token. The prompt's `**Model:**` header must carry the same execution value.
59
+ - Report-writer dispatch uses `name: "report-writer"`. A native Claude assignment maps `modelExecutionValue` to the supported family token; a CLI-wrapper assignment remains `inherit` at the Agent layer and applies the exact value in its provider wrapper. The prompt's `**Model:**` header must carry the same execution value.
60
60
  - Each variant persists its prompt path, Result Path, worker-results path, error paths, and `dispatchKind` before dispatch. Completion uses the shared background Result Path poll; an Agent acknowledgement never completes the variant.
61
61
 
62
62
  ## Completion, cleanup, and resume
@@ -71,7 +71,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
71
71
 
72
72
  ### CLI-wrapper polling
73
73
 
74
- - Start `okstra-codex-exec.sh` / `okstra-antigravity-exec.sh` with `Bash(run_in_background: true)` and poll `BashOutput(bash_id)` back-to-back until terminal completion. Never add a foreground sleep.
74
+ - Start the assignment's registered wrapper (`okstra-claude-exec.sh`, `okstra-codex-exec.sh`, `okstra-antigravity-exec.sh`, `okstra-grok-exec.sh`, or `okstra-kimi-exec.sh`) with `Bash(run_in_background: true)` and poll `BashOutput(bash_id)` back-to-back until terminal completion. Never add a foreground sleep.
75
75
  - Return accumulated stdout on success. On a non-zero `exit_code`, record the real code and observed duration.
76
76
  - At the 1800-second cap, inspect the live log mtime once. Recent output grants one extension to 2100 seconds; otherwise call `KillShell(shell_id)`, record exit code 124, and return the wrapper timeout sentinel.
77
77
  - Keep the wrapper subagent alive throughout polling so its JSONL timestamp window covers the underlying CLI rollout.
@@ -81,7 +81,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
81
81
  - At the start of Phase 7, run `okstra token-usage /abs/path/to/run/state/team-state-<task-type>-<seq>.json --write --summary` with the literal team-state path.
82
82
  - Read the lead and Claude-side wrapper evidence from `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`; attribute workers by the dispatch `agentName` recorded above.
83
83
  - Resolve `teamName` from `state.teamName` or `state.team.teamName` and use the full manifest-provided value as the team needle. If it is missing, the collector's short-form fallback cannot match worker JSONLs and records those workers as `source: "unavailable"`.
84
- - Keep underlying Codex and Antigravity CLI usage separate from the Claude wrapper-session usage. Persist `leadUsage`, per-worker usage, and `usageSummary` before report substitution and cleanup.
84
+ - Keep every underlying provider CLI's usage separate from the Claude wrapper-session usage. Persist `leadUsage`, per-worker usage, and `usageSummary` before report substitution and cleanup.
85
85
 
86
86
  ## Run-scoped resource lifecycle
87
87
 
@@ -89,6 +89,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
89
89
  - Record the lead pane once with `mkdir -p "<RUN_DIR>/state" && { . "$HOME/.okstra/bin/lib/okstra/tmux-pane.sh" 2>/dev/null && okstra_resolve_caller_pane; } > "<RUN_DIR>/state/lead-pane.id" 2>/dev/null || true`. This is silent setup and must not gate cleanup; the cleanup script protects the lead pane itself.
90
90
  - Collect and persist token usage before any live-roster cleanup, including cleanup between batches and the run-end shutdown sequence.
91
91
  - Before each new worker batch (and before the next phase's render-bundle), reclaim the prior round's completed teammate panes in two passes, adding `--keep report-writer-worker` to **both** passes while the report writer is in flight. First source the count: `$HOME/.okstra/bin/okstra-trace-cleanup.sh --list --run-dir "<RUN_DIR>" [--keep report-writer-worker]` never kills and prints one `<pane_id>\t<pane_title>` line per pane it would reclaim — count those lines as `<n>`. Then perform the reclaim by running the same command **without** `--list`, and emit the neutral contract's `PROGRESS: phase-batch-cleanup panes=<n>` checkpoint with that count. Call both passes after collecting that round's results and token usage and before the next dispatch, so no in-flight worker pane is caught. This `tmux kill-pane`s the harness teammate panes; `shutdown_request` only idles the agent and never frees the pane, so it stays part of the run-end sequence for roster/token hygiene. In a non-tmux session there are no panes, both passes no-op, and `<n>` is `0` — still emit the checkpoint. The lead pane (read from `<RUN_DIR>/state/lead-pane.id`) is always preserved.
92
+ - Reclaiming a pane does not stop the worker's background task. Every `dispatch_worker` Agent runs with `run_in_background: true`, so a worker whose result is already collected stays a live background task for the rest of the session — that residue is what fills the harness's exit-time `Background work is running` list. At the same batch boundary, right after the pane reclaim, call `TaskStop(task_id: "<name>")` once per worker of the completed batch, passing the exact `name` used at dispatch (`<workerId>-worker`, `<workerId>-worker-reverify-r<N>`, `<provider>-worker-critic`, `report-writer`). Stop only workers whose results were already collected — never an in-flight worker, never the lead, and keep `report-writer` while it is in flight, matching the pane pass's `--keep report-writer-worker`. `TaskStop` on an already-finished task is a no-op; treat a failure as benign, record nothing, and continue the boundary. This runs in a non-tmux session too, where the pane passes no-op but the background tasks still exist.
92
93
  - After batch cleanup, record the current live session generation with `okstra token-usage "<TEAM_STATE_PATH>" --record-observed-session --project-root "<PROJECT_ROOT>"`. This protects usage accounting when Claude Code re-issues the session id after resume or compaction.
93
94
  - Claude Code cannot delete the implicit team or surgically remove an idle roster entry. Explain that teammates may remain visible until session end and, when needed, give the manual action `Delete team <teamName> in Teams/FleetView`.
94
95
  - The `SessionEnd` hook runs `$HOME/.okstra/bin/okstra-team-reconcile.sh --session-end` as the safety net for the current live session.
@@ -104,4 +105,5 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
104
105
  > (Yes) Close everything and clean up teammates / (No) Keep everything
105
106
  5. On `keep`, preserve every residual resource and show `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"` plus the manual Teams/FleetView action. Tell the user that `keep` holds only until the next boundary: if this session goes on to another phase/batch, that transition's round-boundary cleanup reclaims the kept **completed** panes unattended (in-flight resources and the lead pane are never touched).
106
107
  6. On approved `clean`, emit the teardown checkpoint, run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"`, then run `$HOME/.okstra/bin/okstra-team-reconcile.sh --project-root "<PROJECT_ROOT>" --fallback-team "session-<lead.sessionId-prefix>"` exactly once. The resolver reads the current live session's `~/.claude/teams/session-<live>/config.json`, falling back to the snapshot directory only when the live directory is absent, and prints `dismissible-member: <name>` records.
107
- 7. Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to each printed, confirmed-complete non-lead member. The `message` MUST be the object literal shown, NEVER a JSON string in a text field. Never target the lead or use `TaskStop`; teammates are not background tasks.
108
+ 7. Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to each printed, confirmed-complete non-lead member. The `message` MUST be the object literal shown, NEVER a JSON string in a text field. Never target the lead.
109
+ 8. Call `TaskStop(task_id: "<name>")` for every worker this run dispatched, reusing the step-7 names plus any batch worker already reclaimed earlier. `shutdown_request` only idles the roster member and the step-6 pane reclaim only closes the pane — neither ends the background task, so this step is the one that empties the harness's exit-time `Background work is running` list. Never target the lead; a `TaskStop` on an already-finished task is a benign no-op.
@@ -11,7 +11,7 @@ This adapter maps the neutral Okstra lead operations to the Codex artifact-first
11
11
  | `runtime` | `codex` |
12
12
  | `leadRoleLabel` | `Codex lead` |
13
13
  | `userPromptMode` | `host-text` |
14
- | `workerDispatchBackend` | `cli-wrapper` |
14
+ | `workerDispatchBackend` | `mixed` |
15
15
  | `initialPromptDeliveryMode` | `eager-include` |
16
16
  | `sessionAccounting` | `artifact-only` |
17
17
  | `resumeMode` | `artifact-checkpoint` |
@@ -25,9 +25,9 @@ This adapter maps the neutral Okstra lead operations to the Codex artifact-first
25
25
  | `read_artifacts` | Read the manifest-provided paths through the current host's file interface. |
26
26
  | `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
27
27
  | `prompt_user` | Ask through the host text/question interface and stop at approval gates until an explicit answer arrives. |
28
- | `dispatch_worker` | Run `okstra codex-dispatch --project-root <root> --run-manifest <path>`; use `--dry-run` first when the core requires a dispatch preview. |
29
- | `await_workers` | Treat the synchronous dispatch return plus team-state terminal records and Result Paths as completion evidence. |
30
- | `redispatch_worker` | Invoke a fresh `okstra codex-dispatch` worker attempt for the selected role and record the retry/reverify dispatch kind. |
28
+ | `dispatch_worker` | Dispatch every `runner=native-session` assignment with the current Codex host's native worker/session primitive. Pass only `runner=cli-wrapper` assignments to `okstra codex-dispatch --project-root <root> --run-manifest <path> --workers <ids>`; use `--dry-run` first when the core requires a dispatch preview. |
29
+ | `await_workers` | Await native host workers through the host primitive and CLI workers through synchronous dispatch, then verify team-state terminal records and Result Paths for both. |
30
+ | `redispatch_worker` | Start a fresh native worker or `okstra codex-dispatch` attempt according to the persisted assignment's `runner`, and record the retry/reverify dispatch kind. |
31
31
  | `shutdown_workers` | Perform process cleanup when a wrapper remains live; otherwise this operation is a no-op recorded in state. |
32
32
  | `record_lead_event` | Append the required structured event to the manifest-provided `leadEventsPath`; emit the matching user-facing `PROGRESS:` line. |
33
33
  | `collect_usage` | Collect artifact/rollout-backed usage through the existing Okstra token-usage path; never read Claude session JSONL as a substitute. |
@@ -36,12 +36,12 @@ This adapter maps the neutral Okstra lead operations to the Codex artifact-first
36
36
 
37
37
  - For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
38
38
  - Do not invoke Claude Code team or subagent tools.
39
- - The prepared run manifest and team-state are the dispatch authority. Unsupported explicitly requested workers fail; an adapter must not silently change the roster.
40
- - Report-writer execution keeps the existing explicit opt-in policy in this milestone: dispatch requires `--enable-codex-report-writer` and an explicit `--report-writer-codex-model` value.
39
+ - The prepared run manifest and team-state are the dispatch authority. A `runner=native-session` assignment stays in the current Codex host; a `runner=cli-wrapper` assignment uses the registered provider wrapper. Unsupported explicitly requested workers fail; an adapter must not silently change the roster.
40
+ - The report-writer follows its persisted provider, model, and runner assignment exactly. It has no Codex-only provider override or separate opt-in gate.
41
41
  - Reverify and critic retries invoke a fresh worker attempt and persist the core-supplied `dispatchKind` (`reverify-r<N>` or `critic`) in the dispatch record; never reuse a prior rollout as a new vote.
42
42
  - Report-writer completion requires both the data.json Result Path and the worker-results audit path, even when the synchronous dispatch command exits successfully.
43
43
 
44
44
  ## Completion, cleanup, and resume
45
45
 
46
- - A successful synchronous dispatch return alone is insufficient; verify terminal state, every required completion path, and the corresponding worker-dispatch audit record before counting the worker as complete.
46
+ - A native host completion or successful synchronous CLI return alone is insufficient; verify terminal state, every required completion path, and the corresponding worker-dispatch audit record before counting the worker as complete.
47
47
  - Resume from run artifacts and lead-events checkpoints. Do not invent a Claude session id.
@@ -202,7 +202,7 @@ If previous run reports exist, use as historical context only. If discovery meta
202
202
 
203
203
  For `project-analysis`, `feature-analysis`, and `change-impact-analysis`, Lead MUST use the run manifest's immutable pre-dispatch `analysisScopeConfirmation` snapshot as the structured reporter-confirmation evidence before Phase 4 worker dispatch. Its `status` MUST be `complete`; its `taskBriefPath` and `briefSha256` bind that status to the exact brief bytes captured when the run manifest was created. A later edit to the live brief, clarification prose, or inferred consent cannot substitute for this snapshot. `project-analysis` confirms which areas remain shallow; `feature-analysis` confirms the exact feature target and covered flows; `change-impact-analysis` confirms the proposed change, preserved behavior, and dependency boundary.
204
204
 
205
- If that snapshot is incomplete, missing, or malformed, Lead MUST follow the shared Reporter Confirmation Required / Clarification Items contract, stop before dispatch, and publish a `blocked` report. It MUST NOT silently widen the target. **Enforcement:** `scripts/okstra_ctl/render.py` records the brief path, reporter-confirmation status, and brief byte digest in the run manifest before the lead can dispatch workers; `validators/validate_analysis_report.py` validates only that immutable snapshot, rejects required-worker execution before a complete snapshot, and recomputes the analysis verdict; `validators/validate-run.py` runs that check only after schema validation succeeds.
205
+ If that snapshot is incomplete, missing, or malformed, Lead MUST follow the shared Reporter Confirmation Required / Clarification Items contract and stop before dispatch. A scope reduction must be explicitly confirmed in the brief's `## Reporter Confirmations` before a fresh bundle records `analysisScopeConfirmation.status=complete`. Do not dispatch workers and then defer a foreseeable scope conflict to a final HTML question. **Enforcement:** `scripts/okstra_ctl/render.py` records the brief path, reporter-confirmation status, and brief byte digest in the run manifest before the lead can dispatch workers; `validators/validate_analysis_report.py` validates only that immutable snapshot, rejects required-worker execution before a complete snapshot, and recomputes the analysis verdict; `validators/validate-run.py` runs that check only after schema validation succeeds.
206
206
 
207
207
  ## Phase 2 — Phase 5: Prompt preparation, teammate setup, execution, completion poll
208
208
 
@@ -308,7 +308,7 @@ If convergence is disabled, `seed`/`finalize` produce the auto-disabled final st
308
308
 
309
309
  ### Authoring ownership (BLOCKING)
310
310
 
311
- If `Report writer worker` is in the selected roster (`recommendedWorkers` / `resultContract.requiredWorkerRoles`), **Lead MUST dispatch it to author the final report**. The worker writes the JSON SSOT at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` and invokes `scripts/okstra-render-final-report.py` to produce the sibling `final-report-<task-type>-<seq>.md` — Lead writes neither file. Lead's role in this phase is: prepare the report-writer prompt (carrying convergence output, all worker results, and reference expectations), dispatch, then review the produced files. See [report-writer](./report-writer.md) "File-author ownership".
311
+ If `Report writer worker` is in the selected roster (`recommendedWorkers` / `resultContract.requiredWorkerRoles`), **Lead MUST dispatch it to author the final report data.json**. The worker writes the JSON SSOT at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` and invokes `scripts/okstra-render-final-report.py` to produce the sibling AI handoff Markdown. Phase 7 renders human HTML directly from the same data.json. Lead writes none of these files; it prepares the prompt, dispatches, and reviews both audience artifacts. See [report-writer](./report-writer.md) "File-author ownership".
312
312
 
313
313
  Before constructing the dispatch prompt, the lead MUST:
314
314
 
@@ -358,8 +358,8 @@ Lead's responsibilities in this sub-step (in order):
358
358
  2. Dispatch a single plan-body reverify round to every analyser worker in the roster (`claude`, `codex`, and `antigravity` when opted in). `Report writer worker` is NOT a participant in this round.
359
359
  3. Aggregate verdicts and resolve the gate result to one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`.
360
360
  4. Write `runs/<task-type>/state/plan-body-verification.json` (schema in the plan-body-verification contract), appending one `roundHistory[]` entry per round — including every self-fix re-verification round, since data.json keeps only the final verdicts.
361
- 5. Populate `### 5.5.9 Plan Body Verification` in the final-report file (template at `templates/reports/final-report.template.md` §5.5.9 — Round count, Gate result, per-item verdict tables grouped under each plan item's `subject`, Dissent log).
362
- 6. For every `majority-disagree` plan item, append a row to `## 1. Clarification Items` with `Blocks=approval` and the 1:1 ID match in the verdict table's `Classification` column (`majority-disagree → C-<N>`). Do NOT create a parallel `Open Questions` block — see `prompts/profiles/implementation-planning.md` self-review step 6 for the orphan-on-either-side contract.
361
+ 5. Populate `implementationPlanning.planBodyVerification` in data.json with round count, gate result, per-item verdicts, and dissent log. The AI handoff task-deliverable block carries this structure without a second prose rendering.
362
+ 6. For every `majority-disagree` plan item, append one `clarificationItems[]` row with `blocks=approval` and the 1:1 ID match in the verdict classification (`majority-disagree → C-<N>`). Do not create a parallel open-questions structure.
363
363
  7. Publish the YAML frontmatter `approved:` field as `false`. There is no in-body `- [ ] Approved` marker line — approval lives only in the frontmatter (see [plan-body-verification](./plan-body-verification.md) §"Round protocol" step 9). The user may flip it to `true` only when the gate is `passed` or `passed-with-dissent`. **Enforced:** `validators/validate-run.py` `validate_phase_boundary` fails a report shipping `approved: true` under `blocked-by-disagreement` / `aborted-non-result`, and run-prep (`scripts/okstra_ctl/run.py` `_validate_approved_plan`) fail-closes the same case. Manually flipping a blocked gate to passing is a contract violation.
364
364
 
365
365
  If `convergence.planBodyVerification.enabled == false` (set by `--no-plan-verification` or by `okstra config set plan-verification off`), the entire sub-step is skipped and the top-of-report Approval marker is rendered unconditionally (legacy behaviour). This opt-out is intended for fast iteration only and is not recommended for handoff-ready plans.
@@ -397,7 +397,7 @@ After persistence, reply briefly in the resolved Report Language with: completio
397
397
  ## Run-scoped worker-resource lifecycle
398
398
 
399
399
  - At run start, call the selected adapter's setup required to distinguish lead-owned resources from worker-owned resources.
400
- - Before every new worker batch, and between worker rounds within a phase, close the prior round's completed teammate resources before the next dispatch — never the lead and never an in-flight worker; call `record_lead_event` for the batch-cleanup checkpoint. The round-boundary teammate reclaim primitive is the selected adapter's.
400
+ - Before every new worker batch, and between worker rounds within a phase, close **every** resource the prior round's completed workers still hold — display surfaces, roster entries, and live execution handles alike — before the next dispatch; never the lead and never an in-flight worker. Call `record_lead_event` for the batch-cleanup checkpoint. Which resources exist and how each one is released is the selected adapter's mapping.
401
401
  - After Phase 7 persistence and `collect_usage`, enumerate residual adapter-owned resources. If none remain, skip the question.
402
402
  - If resources remain, call `prompt_user` once with a binary keep-or-clean choice. The answer controls the entire residual set; do not ask a second backend-specific cleanup question.
403
403
  - On keep, preserve all resources and provide the selected adapter's manual-cleanup instruction.
@@ -4,9 +4,9 @@
4
4
 
5
5
  The final-report data.json is authored by `Report writer worker` when that role is in the roster. The lead reviews both rendered artifacts but does not write them. Lead-authored fallback is legal only after a real `dispatch_worker` attempt records `error`, `timeout`, or `not-run` with a concrete reason. `release-handoff` remains the intentional single-lead exception.
6
6
 
7
- The JSON SSOT path is `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`. The user-facing markdown at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md` is produced by `scripts/okstra-render-final-report.py` from the data.json. The worker-result pointer at `**Worker Result Path:**` records those two paths and the reconciled convergence input. These three completion artifacts land on disk before the worker returns; the heartbeat audit sidecar remains a separate required audit artifact.
7
+ The JSON SSOT path is `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`. Two audience artifacts are independently derived from the data.json: `scripts/okstra-render-final-report.py` produces the AI handoff Markdown sibling, and Phase 7 produces the task-specific human HTML sibling directly from data.json. The worker-result pointer at `**Worker Result Path:**` records the data and Markdown paths plus reconciled convergence input. These three completion artifacts land on disk before the worker returns; HTML follows during finalization and the heartbeat sidecar remains a separate audit artifact.
8
8
 
9
- The data.json schema is `schemas/final-report-v1.0.schema.json`. The renderer + the run-validator both consume that schema, so a data.json that validates is guaranteed to render into a markdown that passes the contract checks.
9
+ New bundles use `schemas/final-report-v2.0.schema.json`. The Markdown keeps verdict, routing, evidence, one structured task deliverable, and audit data for the next agent. The HTML uses `humanSummary`, task `userNarrative`, and structured facts for the user. Raw worker discussion, convergence mechanics, and usage belong to audit structures and never to the HTML human main body.
10
10
 
11
11
  Two `frontmatter` approval fields are always emitted with their unset default — never pre-fill them: `frontmatter.approved` is emitted as `false`, and `frontmatter.implementationOption` is emitted as an empty string `""`. The user later flips `approved` to `true` (via `--approve` or manual edit) and fills `implementationOption` with the chosen Option Candidate name (via `--implementation-option <name>` or manual edit) to authorise and scope the next `implementation` run.
12
12
 
@@ -46,8 +46,8 @@ The prompt MUST include, in this order at the top:
46
46
  8. `**Prompt Delivery Mode:** <mode>` — the selected adapter's declared `initialPromptDeliveryMode`.
47
47
  9. `**Model:** Report writer worker, <modelExecutionValue>` (resolved per Phase 5.5 anchor-header rules)
48
48
  10. The full `[Required reading]` clause (see [team-contract](./team-contract.md)) — for Phase 6 it adds two **per-task-type, instruction-set-local** read-only files, both scoped to this run's task-type by `okstra-ctl` at prep time:
49
- - `<instruction-set>/final-report-schema.json` — a task-type excerpt of the data.json schema (the other task-types' deliverable blocks and their unreachable `$defs` are stripped; ~38% of the full schema is `$defs` alone). This is your authoring aid for the data.json shape — the installed schema, not the excerpt, is what the run is judged against. Do **NOT** pull the full `schemas/final-report-v1.0.schema.json` — it carries all task-types and its `schemas/...` path is not part of the task bundle. (Validation still runs against the full schema post-hoc via the renderer, so the excerpt never relaxes the contract.)
50
- - `<instruction-set>/final-report-template.md` — the **phase-stripped** template (every other task-type's §5.x deliverable block removed by `render.py`'s `_strip_phase_blocks`, leaving only your run's §5.x). Do **NOT** also pull the full `templates/reports/final-report.template.md` source (it re-adds ~330 lines of other phases' deliverables and is not in the task bundle).
49
+ - `<instruction-set>/final-report-schema.json` — a task-type excerpt of schema v2. This is the binding authoring shape; the installed full schema is what the run is judged against. Do **NOT** pull the full repository schema because it is outside the task bundle.
50
+ - `<instruction-set>/final-report-template.md` — the AI handoff Markdown template. It shows the agent-facing ledger shape, not the human presentation. The task-specific HTML renderer reads data.json separately.
51
51
  11. A one-line MCP pointer instead of the verbatim block (redundant — the brief is already in the report-writer's Required reading, item 10): `**MCP servers:** follow the task brief's "## Available MCP Servers" section (already in your Required reading).`
52
52
  12. `Convergence state: runs/<task-type>/state/convergence-<task-type>-<seq>.json`, followed by pointers to all analysis-worker result files under `worker-results/`. The convergence path is deterministic and is listed even before Phase 5.5 creates the file. Read its classifications (Full/Partial/Contested/Worker-Unique), `roundHistory[]`, `round2SkippedReason`, and `finalClassificationCounts`; populate `crossVerification.roundHistory` in data.json so Section 6 can show which rounds executed, queue sizes, and why Round 2 was (or was not) skipped. The renderer prints the full per-round table only when more than one round ran; single-round or zero-round histories are auto-collapsed to a one-line summary.
53
53
  13. `**Report Language:** <en|ko>` — must be either `en` or `ko`; `auto`
@@ -56,7 +56,7 @@ The prompt MUST include, in this order at the top:
56
56
  into `data.json.meta.reportLanguage`.
57
57
  14. For implementation-planning runs: a literal block listing the 12 required English section headings — `Option Candidates`, `Trade-off`, `Recommended Option`, `Stage Map`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `Requirement Coverage`, `Plan Body Verification`, `Cross-Project Dependencies`, `Decision Drafts`. This list is `PLANNING_REQUIRED_SECTIONS` in `validators/validate-run.py`; that tuple is the SSOT and this block must match it exactly. The writer uses these exact substrings as section headings (Korean translation in parentheses is allowed), and the `Plan Body Verification` section carries its required `Gate result:` line.
58
58
  15. An explicit instruction: `You are the author of THREE files: (a) the final-report data.json at <Result Path>, (b) its rendered Markdown sibling produced through "okstra render-final-report <Result Path>", and (c) the worker-result pointer at <Worker Result Path>. Maintain the separate heartbeat audit sidecar at <Audit sidecar path>. Do not return the report inline. The dispatch fails when any of the three completion artifacts is missing, and session conformance fails when the audit sidecar is missing or invalid.`
59
- 16. The prose budget (dedup contract): `verdictCard.finalConclusion` is the conclusion SSOT — at most 3 sentences. `rationale.*` fields stay within 2 sentences each and reference the verdict card / row IDs instead of restating their prose; `readerSummary` fields are one line each; `summary` stays at 3-5 rows unless the run covers multiple tickets. The schema field descriptions carry the same budgets (`tests/contract/test_report_prose_budget.py` guards both surfaces). Generation time scales with output volume, so exceeding the budget is a cost bug, not extra diligence.
59
+ 16. The prose budget (dedup contract): `verdictCard.finalConclusion` is the conclusion SSOT — at most 3 sentences. `rationale.*` fields stay within 2 sentences each; `humanSummary` entries stay concise; task `userNarrative` explains each user-facing section once with evidence references. Do not copy these narratives into the AI Markdown. `summary` stays at 3-5 rows unless the run covers multiple tickets. Generation time scales with output volume, so exceeding the budget is a cost bug, not extra diligence.
60
60
 
61
61
  **Fix-run incremental authoring (applies when the run's profile carries a "Fix-Run Carry" block).** Do not author the data.json from scratch. Start by copying the previous run's data.json (the `Previous report` path in the Fix-Run Carry block) to this run's Result Path, then update ONLY the blocks the fix run changed: `meta`/`header` (run seq, dates), `executionStatus`, `implementation.verifierResults`, `implementation.validationEvidence`, `implementation.commitList` / `diffSummary`, `crossVerification`, `verdictCard`, `finalVerdict`, and any `evidence` rows the fix touched. Deliverable prose for unchanged sections is carried forward verbatim — do not re-generate it. Then invoke the renderer exactly as in a full run. The schema validation and renderer contract are unchanged, so an incrementally-authored data.json passes the same post-hoc gates. The lead's dispatch prompt MUST include the previous data.json path when the carry block is present.
62
62
 
@@ -81,7 +81,7 @@ Speculative reasons such as "session resume constraint", "runtime state is unava
81
81
 
82
82
  Phase 6 first produces the final-report data.json at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` and its rendered markdown sibling. Token Usage cells are `null` at this point, and Section 3 does not yet include auto-spawned follow-ups.
83
83
 
84
- For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v1.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
84
+ For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v2.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
85
85
 
86
86
  Phase 7 post-processing is **one command**. `okstra report-finalize` owns the ordered sequence — it is the same code path the Codex lead adapter runs automatically, so a Claude-led run and a Codex-led run finalize identically:
87
87
 
@@ -101,12 +101,12 @@ The steps it executes, in this contractual order, and the contract each one carr
101
101
  The data.json paths populated: `tokenUsage.lead.{totalTokens,billableTokens,costUsd}`, the `worker` / `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` for rows whose role matches a team-state worker. The data.json MUST already exist (Phase 6 output).
102
102
 
103
103
  For implementation-planning, this Phase 7 canonical render calls `materialize_design_prep_requests()` after token substitution and creates deterministic request files only for `provisional` / `blocked` items. Later answers are append-only user-input sidecars; request generation and user input never rewrite the assessment fields, so the source report remains immutable as the design-input snapshot after this render. `validators/validate-run.py` `_validate_design_prep_requests` enforces request existence, canonical path, content, and assessment fingerprint.
104
- 2. **`render-views` — render the human report artifact.** Runs against the substituted markdown; the renderer itself decides whether an html sibling is warranted.
104
+ 2. **`render-views` — render the human report artifact.** Runs against the substituted v2 data.json and its Markdown sibling.
105
105
 
106
106
  Output (idempotent — re-running overwrites):
107
- - `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view, **generated when the report has at least one §1 `C-*` clarification row OR an implementation-planning Plan Approval widget target** (a sibling `final-report-*.data.json` carrying `implementationPlanning.optionCandidates`). Clarification rows with `Status` ∈ {`open`, `answered`} embed form widgets (`<select>` for enum-style decisions, `<input>` for material / data-point kinds, `<textarea>` fallback); an `Export user response` button serialises form values to a markdown sidecar (schema in [`templates/reports/user-response.template.md`](../../templates/reports/user-response.template.md)) and downloads it as `user-response-<task-type>-<seq>.md`; the user saves it to `runs/<task-type>/user-responses/` (the renderer pre-creates that directory), and `--resume-clarification` auto-appends every sidecar found there to the next run's `clarification-response.md` (`clarification_items.clarification_response_with_sidecars`). The original final-report MD is **never** mutated by user input — the sidecar is the single write target.
107
+ - `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view, always generated for schema v2 from the dedicated template registered for that task type. Clarification rows with `Status` ∈ {`open`, `answered`} embed response controls and export a `user-response-<task-type>-<seq>.md` sidecar. The original data and Markdown artifacts are never mutated by user input.
108
108
  - the implementation-planning report renders a **Plan Approval** section at the end of the body (implementation-option `<select>` + an approval checkbox) — disabled while any §1 `Blocks: approval` row is unresolved. Checking approval and exporting embeds a `## APPROVAL` block in the sidecar body, and the implementation-start wizard's approve-confirm step detects it and, after user confirmation, applies it through the existing `--approve` / `--implementation-option` path.
109
- - When the report has **no** `C-*` clarification rows and is **not** a Plan Approval widget target, the html carries no interactive forms (it would only duplicate the MD), so the renderer prints `html: skipped (...)` and writes nothing. This is the expected state for such runs — `validators/validate-report-views.py` treats "no C-* rows + no approval target + no html" as a pass, not a missing artifact.
109
+ - Schema-v1 and quick compatibility reports retain the legacy conditional HTML path; this does not change the schema-v2 always-generated contract.
110
110
 
111
111
  It runs after usage collection so token placeholders are substituted in any rendered html, and before routing persistence so the html artifact, when generated, exists for the validator step that checks it.
112
112
  3. **`spawn-followups` — routing and follow-up persistence.** Turns the report's `## 4. Follow-up Tasks` rows into `tasks/<task-group>/<new-task-id>/` stubs.
@@ -128,13 +128,17 @@ The steps it executes, in this contractual order, and the contract each one carr
128
128
 
129
129
  After `okstra report-finalize` reports `"ok": true`, **execute the run-scoped cleanup gate.** Call `shutdown_workers` only after that success, all persistence work, and explicit user approval under [okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped worker-resource lifecycle". If the user keeps resources, leave the selected adapter's resources intact and surface its manual cleanup guidance.
130
130
 
131
- ## Final Report Structure
131
+ ## Schema-v2 report data responsibilities
132
132
 
133
- The final report follows the structure encoded in `schemas/final-report-v1.0.schema.json` — the single source of truth for section names, row shapes, enum values, and task-type-conditional blocks. The Jinja2 template `templates/reports/final-report.template.md` produces the human-readable form from any data.json that validates against the schema. The structure description below is a reading guide for writers; the schema is the binding contract.
133
+ The binding authoring shape is the task bundle's `instruction-set/final-report-schema.json`. Populate both audiences in data.json: agent-facing verdict, routing, evidence, task facts, and audits; user-facing `humanSummary` and task `userNarrative`. The AI handoff template deliberately omits the full user narrative, while the task-specific HTML deliberately moves `crossVerification`, `executionStatus`, and `tokenUsage` into collapsed audit details.
134
+
135
+ ## Legacy schema-v1 Markdown structure reference
136
+
137
+ The remaining numbered-section guide exists only for rendering or diagnosing historical schema-v1 data. New report-writer runs do not author against it; their instruction-set schema and AI handoff template are authoritative.
134
138
 
135
139
  ### Report Header
136
140
 
137
- Milestone 1 keeps the final-report schema unchanged. Read the exact permitted values for `header.reportOwner` and `header.reportAuthor` from the task bundle's `instruction-set/final-report-schema.json` excerpt of `schemas/final-report-v1.0.schema.json`, then write those schema v1 compatibility values according to the actual authorship path. Do not derive either header field from the selected runtime's lead role. Runtime identity remains visible in the execution-status row and team-state audit fields.
141
+ Read the exact permitted values for `header.reportOwner` and `header.reportAuthor` from the task bundle's `instruction-set/final-report-schema.json` excerpt, then write those values according to the actual authorship path. The current v2 contract uses the provider-neutral `Okstra lead`; a legacy v1 excerpt may retain historical compatibility values. Do not derive either header field from the selected runtime's provider-specific lead label. Runtime identity remains visible in the execution-status row and team-state audit fields.
138
142
 
139
143
  ```markdown
140
144
  # <task-key> - Multi-Agent Cross Verification Final Report
@@ -2,7 +2,7 @@
2
2
  Single source for the executor's Coding-conventions preflight gate. Two delivery
3
3
  paths converge here (see _implementation-executor.md "Pre-implementation context
4
4
  exploration"):
5
- - Claude executor reads this file directly before its first Edit / Write.
5
+ - The native-session executor reads this file directly before its first edit.
6
6
  - codex / antigravity executor cannot read this path (it sits outside the CLI
7
7
  sandbox and the CLI only sees its stdin prompt), so the lead appends this
8
8
  file's body into the persisted executor prompt at dispatch time.