okstra 0.49.0 → 0.51.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 (86) hide show
  1. package/README.kr.md +8 -7
  2. package/README.md +8 -7
  3. package/bin/okstra +2 -0
  4. package/docs/kr/architecture.md +23 -24
  5. package/docs/kr/cli.md +6 -6
  6. package/docs/project-structure-overview.md +13 -9
  7. package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +559 -0
  8. package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +121 -0
  9. package/docs/task-process/error-analysis.md +1 -1
  10. package/docs/task-process/final-verification.md +1 -1
  11. package/docs/task-process/release-handoff.md +1 -1
  12. package/docs/task-process/requirements-discovery.md +1 -1
  13. package/package.json +1 -1
  14. package/runtime/BUILD.json +2 -2
  15. package/runtime/agents/SKILL.md +18 -14
  16. package/runtime/agents/workers/claude-worker.md +4 -4
  17. package/runtime/agents/workers/codex-worker.md +3 -3
  18. package/runtime/agents/workers/gemini-worker.md +3 -3
  19. package/runtime/agents/workers/report-writer-worker.md +3 -3
  20. package/runtime/bin/lib/okstra/cli.sh +8 -1
  21. package/runtime/bin/lib/okstra/globals.sh +3 -0
  22. package/runtime/bin/lib/okstra/interactive.sh +14 -12
  23. package/runtime/bin/lib/okstra/usage.sh +6 -0
  24. package/runtime/bin/okstra-render-report-views.py +1 -1
  25. package/runtime/bin/okstra-team-reconcile.sh +28 -0
  26. package/runtime/bin/okstra.sh +2 -0
  27. package/runtime/prompts/launch.template.md +4 -2
  28. package/runtime/prompts/profiles/_common-contract.md +15 -15
  29. package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
  30. package/runtime/prompts/profiles/_implementation-executor.md +3 -3
  31. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  32. package/runtime/prompts/profiles/error-analysis.md +1 -1
  33. package/runtime/prompts/profiles/final-verification.md +2 -2
  34. package/runtime/prompts/profiles/implementation-planning.md +10 -9
  35. package/runtime/prompts/profiles/implementation.md +1 -1
  36. package/runtime/prompts/profiles/improvement-discovery.md +5 -5
  37. package/runtime/prompts/profiles/release-handoff.md +2 -2
  38. package/runtime/prompts/profiles/requirements-discovery.md +2 -2
  39. package/runtime/python/okstra_ctl/analysis_packet.py +259 -0
  40. package/runtime/python/okstra_ctl/clarification_items.py +11 -11
  41. package/runtime/python/okstra_ctl/context_cost.py +308 -0
  42. package/runtime/python/okstra_ctl/migrate.py +2 -12
  43. package/runtime/python/okstra_ctl/paths.py +22 -0
  44. package/runtime/python/okstra_ctl/render.py +285 -126
  45. package/runtime/python/okstra_ctl/render_final_report.py +32 -1
  46. package/runtime/python/okstra_ctl/report_views.py +12 -12
  47. package/runtime/python/okstra_ctl/run.py +510 -248
  48. package/runtime/python/okstra_ctl/sequence.py +2 -5
  49. package/runtime/python/okstra_ctl/team_reconcile.py +131 -0
  50. package/runtime/python/okstra_ctl/wizard.py +219 -136
  51. package/runtime/python/okstra_ctl/workflow.py +1 -1
  52. package/runtime/python/okstra_ctl/worktree.py +13 -5
  53. package/runtime/schemas/final-report-v1.0.schema.json +4 -0
  54. package/runtime/skills/okstra-brief/SKILL.md +1 -1
  55. package/runtime/skills/okstra-coding-preflight/SKILL.md +69 -0
  56. package/runtime/skills/okstra-coding-preflight/architecture/hexagonal.md +116 -0
  57. package/runtime/skills/okstra-coding-preflight/clean-code.md +254 -0
  58. package/runtime/skills/okstra-coding-preflight/languages/java.md +64 -0
  59. package/runtime/skills/okstra-coding-preflight/languages/javascript-typescript.md +87 -0
  60. package/runtime/skills/okstra-coding-preflight/languages/kotlin.md +69 -0
  61. package/runtime/skills/okstra-coding-preflight/languages/nodejs.md +66 -0
  62. package/runtime/skills/okstra-coding-preflight/languages/python.md +179 -0
  63. package/runtime/skills/okstra-coding-preflight/languages/rust.md +105 -0
  64. package/runtime/skills/okstra-coding-preflight/languages/sql.md +68 -0
  65. package/runtime/skills/okstra-context-loader/SKILL.md +12 -6
  66. package/runtime/skills/okstra-convergence/SKILL.md +8 -8
  67. package/runtime/skills/okstra-inspect/SKILL.md +100 -1
  68. package/runtime/skills/okstra-report-writer/SKILL.md +27 -23
  69. package/runtime/skills/okstra-run/SKILL.md +3 -1
  70. package/runtime/skills/okstra-team-contract/SKILL.md +8 -5
  71. package/runtime/templates/reports/final-report.template.md +188 -187
  72. package/runtime/templates/reports/i18n/en.json +4 -4
  73. package/runtime/templates/reports/i18n/ko.json +4 -4
  74. package/runtime/templates/reports/implementation-planning-input.template.md +1 -1
  75. package/runtime/templates/reports/release-handoff-input.template.md +1 -1
  76. package/runtime/templates/reports/user-response.template.md +1 -1
  77. package/runtime/templates/worker-prompt-preamble.md +4 -4
  78. package/runtime/validators/lib/fixtures.sh +2 -2
  79. package/runtime/validators/validate-implementation-plan-stages.py +9 -9
  80. package/runtime/validators/validate-report-views.py +10 -10
  81. package/runtime/validators/validate-run.py +36 -36
  82. package/runtime/validators/validate_improvement_report.py +8 -8
  83. package/src/_python-helper.mjs +3 -3
  84. package/src/context-cost.mjs +27 -0
  85. package/src/install.mjs +1 -0
  86. package/src/uninstall.mjs +1 -0
@@ -18,6 +18,7 @@ project-id: {{ frontmatter.projectId | yaml_scalar }}
18
18
  taskType: {{ frontmatter.taskType | yaml_scalar }}
19
19
  workerId: {{ frontmatter.workerId | yaml_scalar }}
20
20
  approved: {{ frontmatter.approved | yaml_scalar }}
21
+ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
21
22
  ---
22
23
 
23
24
  # {{ header.taskKey }} - Multi-Agent Cross Verification Final Report
@@ -42,128 +43,34 @@ approved: {{ frontmatter.approved | yaml_scalar }}
42
43
  | Approval Required? | `{% if verdictCard.approvalRequired %}yes — {{ t("verdictCard.approvalRequiredSuffix") }}{% else %}no{% endif %}` |
43
44
  | Next Step | {{ verdictCard.nextStep }} |
44
45
 
45
- {% if clarificationCarryIn and clarificationCarryIn.sourceFile %}
46
- ## 0. Clarification Response Carried In From Previous Run
47
-
48
- - Source file: `{{ clarificationCarryIn.sourceFile }}`
49
- - {{ t("sectionIntro.clarificationCarryIn") }}
50
-
51
- {% endif %}
52
- ## Summary of the Problem or Verification Target
53
-
54
- {{ t("sectionIntro.ticketCoverage") }}
46
+ ## 1. Clarification Items
55
47
 
56
- | {{ t("columns.recordMeta") }} | {{ t("columns.summary") }} |
57
- |--------|------------|
58
- {% for row in summary -%}
59
- | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>{{ t("columns.source") }}: {{ row.source }} | {{ row.summary }} |
60
- {% endfor %}
61
-
62
- {% if ticketCoverage.omit %}
63
- {# Ticket Coverage omitted entirely — release-handoff / final-verification #}
64
- {%- else %}
65
- ## Ticket Coverage
66
-
67
- {{ t("ticketCoverage.intro") }}
48
+ {{ t("sectionIntro.clarificationItems") }}
68
49
 
69
- {% if ticketCoverage.singleTicket -%}
70
- - Single ticket run: {{ ticketCoverage.singleTicket }}
50
+ {% if clarificationItems | length == 0 -%}
51
+ {{ t("emptyState.noClarification") }}
71
52
  {%- else %}
72
- | Ticket ID | {{ t("ticketCoverage.columnSections") }} | {{ t("ticketCoverage.columnRelatedIds") }} |
73
- |-----------|-----------|---------------|
74
- {% for row in ticketCoverage.rows -%}
75
- | `{{ row.ticketId }}` | `{{ row.sections }}` | `{{ row.relatedIds }}` |
76
- {% endfor %}
77
- {%- endif %}
78
-
79
- {% endif %}
80
- ## Execution Status by Agent
81
-
82
- {{ t("sectionIntro.executionStatus") }}
83
-
84
- | {{ t("columns.recordMeta") }} | Summary of Key Findings |
85
- |--------|-------------------------|
86
- {% for row in executionStatus -%}
87
- | **{{ row.agent }}**<br>Role: {{ row.role }}<br>Model: {{ row.model }}<br>Status: {{ row.status }}<br>{{ t("columns.rawTokens") }}: {{ row.totalTokens | format_int }}{% if row.cliTotalTokens %} (CLI: {{ row.cliTotalTokens | format_int }}){% endif %}<br>{{ t("columns.billableTokens") }}: {{ row.billableTokens | format_int }}<br>{{ t("columns.cost") }}: {{ row.costUsd | format_usd }}{% if row.cliCostUsd %} (+ CLI {{ row.cliCostUsd | format_usd }}){% endif %}<br>Duration: {{ row.durationMs | format_duration_ms }} | {{ row.summary }} |
88
- {% endfor %}
89
-
90
- ## {{ t("tokenSummary.heading") }}
91
-
92
- | {{ t("tokenSummary.tableHeaderItem") }} | {{ t("columns.rawTokens") }} | {{ t("columns.billableTokensInputEquiv") }} | {{ t("columns.cost") }} |
93
- |------|-----------|------------------------|------------|
94
- | {{ t("tokenSummary.rowLead") }} | `{{ tokenUsage.lead.totalTokens | format_int }}` | `{{ tokenUsage.lead.billableTokens | format_int }}` | `{{ tokenUsage.lead.costUsd | format_usd }}` |
95
- | {{ t("tokenSummary.rowWorkerTotal") }} | `{{ tokenUsage.worker.totalTokens | format_int }}` | `{{ tokenUsage.worker.billableTokens | format_int }}` | `{{ tokenUsage.worker.costUsd | format_usd }}` |
96
- | {{ t("tokenSummary.rowGrandTotal") }} | **`{{ tokenUsage.grand.totalTokens | format_int }}`** | **`{{ tokenUsage.grand.billableTokens | format_int }}`** | **`{{ tokenUsage.grand.costUsd | format_usd }}`** |
97
- {% if tokenUsage.cli and tokenUsage.cli.costUsd is not none and tokenUsage.cli.costUsd > 0 -%}
98
- | {{ t("tokenSummary.rowCliExtra") }} | | | `{{ tokenUsage.cli.costUsd | format_usd }}` |
99
- {% endif %}
100
-
101
- {# At Phase 6 numeric cells are null and render as `--`.
102
- Phase 7's okstra-token-usage.py populates tokenUsage in data.json then
103
- re-invokes this renderer to produce the final markdown. #}
104
-
105
- ## 1. Cross Verification Results
106
-
107
- {% if crossVerification.roundHistory and not crossVerification.roundHistory.disabled -%}
108
- ### 1.0 Round History
109
-
110
- {% if crossVerification.roundHistory.rounds | length > 1 -%}
111
- | Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches (worker:status:durationMs) | skippedWorkers (worker:reason) |
112
- |-------|----------------|---------------|----------------------|----------------------------------------|---------------------------------|
113
- {% for row in crossVerification.roundHistory.rounds -%}
114
- | {{ row.round }} | {{ row.inputQueueSize }} | {{ row.resolvedCount }} | {{ row.carriedForwardCount }} | {{ row.dispatches }} | {{ row.skippedWorkers }} |
115
- {% endfor %}
116
-
117
- - `round2SkippedReason`: `{{ crossVerification.roundHistory.round2SkippedReason }}` ← {{ t("roundHistory.round2SkippedReasonNote") }}
118
- {% elif crossVerification.roundHistory.rounds | length == 1 -%}
119
- {% set r = crossVerification.roundHistory.rounds[0] -%}
120
- - {{ t("roundHistory.singleRoundPrefix") }} resolved={{ r.resolvedCount }}, carriedForward={{ r.carriedForwardCount }}, round2SkippedReason=`{{ crossVerification.roundHistory.round2SkippedReason }}`
121
- {% else -%}
122
- - {{ t("roundHistory.noRoundsNote") }} round2SkippedReason=`{{ crossVerification.roundHistory.round2SkippedReason }}`
123
- {% endif %}
53
+ {{ t("clarification.fillAndRerun") }}
124
54
 
125
- {% endif %}
126
- ### 1.1 Consensus
55
+ - Claude Code: `/okstra-run resume-clarification task-key={{ header.taskKey }}`
56
+ - {{ t("clarification.separateTerminalLabel") }}: `scripts/okstra.sh --resume-clarification --task-key {{ header.taskKey }}`
127
57
 
128
- {% if crossVerification.consensus | length == 0 -%}
129
- {{ t("emptyState.consensusItems") }}
130
- {%- else %}
131
- | {{ t("columns.recordMeta") }} | Statement | Evidence (path:line / log / worker report) |
132
- |--------|-----------|---------------------------------------------|
133
- {% for row in crossVerification.consensus -%}
134
- | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Source items: {{ row.sourceItems | join(', ') }} | {{ row.statement }} | {{ row.evidence }} |
58
+ | ID | Ticket ID | Kind | Statement | Expected form | Blocks | Status | User input |
59
+ |----|-----------|------|-----------|---------------|--------|--------|-----------|
60
+ {% for row in clarificationItems -%}
61
+ | {{ row.id }} | `{{ row.ticketId }}` | `{{ row.kind }}` | {{ row.statement }} | {{ row.expectedForm }} | `{{ row.blocks }}` | {{ row.status }} | {{ row.userInput or '' }} |
135
62
  {% endfor %}
136
- {%- endif %}
137
-
138
- {{ t("sectionIntro.sourceItemsRule") }}
139
63
 
140
- ### 1.2 Differences
64
+ {{ t("clarification.columnGuide") }}
141
65
 
142
- {% if crossVerification.differences | length == 0 -%}
143
- {{ t("emptyState.differences") }}
144
- {%- else %}
145
- | {{ t("columns.recordMeta") }} | Disagreement | Evidence |
146
- |--------|--------------|----------|
147
- {% for row in crossVerification.differences -%}
148
- | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Workers: {% for w in row.workersPosition %}{{ w.worker }}:{{ w.itemId }} ({{ w.position }}){% if not loop.last %} / {% endif %}{% endfor %} | {{ row.disagreement }} | {{ row.evidence }} |
149
- {% endfor %}
66
+ - **`Kind`** `{material, decision, data-point}`.
67
+ - **`Blocks`** ∈ `{approval, next-phase, none}`.
68
+ - **`Status`** ∈ `{open, answered, resolved, obsolete}`.
150
69
  {%- endif %}
151
70
 
152
- ## 2. Final Verdict
71
+ ## 2. Evidence and Detailed Analysis
153
72
 
154
- {{ t("finalVerdict.intro") }}
155
-
156
- | {{ t("verdictCard.tableHeaderLabel") }} | {{ t("verdictCard.tableHeaderValue") }} |
157
- |------|----|
158
- | Final Conclusion | {{ finalVerdict.finalConclusion }} |
159
- | Verdict Token | `{{ finalVerdict.verdictToken }}` |
160
- | Direction | `{{ finalVerdict.direction }}` |
161
- | {{ t("verdictCard.rationaleLabel") }} | {{ finalVerdict.rationaleRowIds | join(', ') }} |
162
- | {{ t("verdictCard.nextStepLabel") }} | {{ finalVerdict.nextStep }} |
163
-
164
- ## 3. Evidence and Detailed Analysis
165
-
166
- ### 3.1 Primary Evidence
73
+ ### 2.1 Primary Evidence
167
74
 
168
75
  {% if evidence.primary | length == 0 -%}
169
76
  {{ t("emptyState.primaryEvidence") }}
@@ -177,7 +84,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
177
84
 
178
85
  {{ t("evidence.sourceItemsColumnNote") }}
179
86
 
180
- ### 3.2 Secondary Evidence or Alternate Interpretations
87
+ ### 2.2 Secondary Evidence or Alternate Interpretations
181
88
 
182
89
  {% if not evidence.secondary or evidence.secondary | length == 0 -%}
183
90
  {{ t("emptyState.secondaryEvidence") }}
@@ -189,7 +96,36 @@ approved: {{ frontmatter.approved | yaml_scalar }}
189
96
  {% endfor %}
190
97
  {%- endif %}
191
98
 
192
- ## 4. Missing Information and Risks
99
+ ## 3. Recommended Next Steps
100
+
101
+ {% if recommendedNextSteps | length == 0 -%}
102
+ - No further action required. Final verdict in section 7 stands.
103
+ {%- else %}
104
+ {% for step in recommendedNextSteps -%}
105
+ {{ loop.index }}. {{ step.text }}
106
+ {% if step.commands -%}
107
+ {% for cmd in step.commands %}
108
+ - {{ cmd.label }}:
109
+ - Claude Code: `{{ cmd.claudeCode }}`
110
+ - {{ t("clarification.separateTerminalLabel") }}: `{{ cmd.terminal }}`
111
+ {% endfor -%}
112
+ {%- endif %}
113
+ {% endfor %}
114
+ {%- endif %}
115
+
116
+ ## 4. Follow-up Tasks{% if t("followUpTasks.headingAside") != "Follow-up Tasks" %} ({{ t("followUpTasks.headingAside") }}){% endif %}
117
+
118
+ {% if followUpTasks | length == 0 -%}
119
+ {{ t("emptyState.noFollowUp") }}
120
+ {%- else %}
121
+ | {{ t("columns.recordMeta") }} | Title | Scope (files/areas) | Reason / Why deferred |
122
+ |--------|-------|---------------------|------------------------|
123
+ {% for row in followUpTasks -%}
124
+ | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Origin: `{{ row.origin }}`<br>New Task ID: `{{ row.newTaskId }}`<br>Type: `{{ row.suggestedTaskType }}`<br>Priority: `{{ row.priority }}`<br>Auto-spawn: `{{ row.autoSpawn }}` | {{ row.title }} | {{ row.scope }} | {{ row.reason }} |
125
+ {% endfor %}
126
+ {%- endif %}
127
+
128
+ ## 5. Missing Information and Risks
193
129
 
194
130
  {% if missingInformation | length == 0 -%}
195
131
  {{ t("emptyState.risks") }}
@@ -202,9 +138,9 @@ approved: {{ frontmatter.approved | yaml_scalar }}
202
138
  {%- endif %}
203
139
 
204
140
  {% if header.taskType == 'implementation-planning' %}
205
- ## 4.5 Implementation Plan Deliverables
141
+ ## 5.5 Implementation Plan Deliverables
206
142
 
207
- ### 4.5.1 Option Candidates{% if t("sectionAside.optionCandidates") != "Option Candidates" %} ({{ t("sectionAside.optionCandidates") }}){% endif %}
143
+ ### 5.5.1 Option Candidates{% if t("sectionAside.optionCandidates") != "Option Candidates" %} ({{ t("sectionAside.optionCandidates") }}){% endif %}
208
144
 
209
145
  {% for opt in implementationPlanning.optionCandidates %}
210
146
  **{{ opt.name }}**
@@ -222,7 +158,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
222
158
 
223
159
  {% endfor %}
224
160
 
225
- ### 4.5.2 Trade-off Matrix{% if t("sectionAside.tradeOffMatrix") != "Trade-off Matrix" %} ({{ t("sectionAside.tradeOffMatrix") }}){% endif %}
161
+ ### 5.5.2 Trade-off Matrix{% if t("sectionAside.tradeOffMatrix") != "Trade-off Matrix" %} ({{ t("sectionAside.tradeOffMatrix") }}){% endif %}
226
162
 
227
163
  | Option | Complexity | Risk | Reversibility | Test Coverage Cost | Rollout Cost |
228
164
  |--------|-----------|------|---------------|--------------------|--------------|
@@ -230,7 +166,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
230
166
  | {{ row.option }} | {{ row.complexity }} | {{ row.risk }} | {{ row.reversibility }} | {{ row.testCoverageCost }} | {{ row.rolloutCost }} |
231
167
  {% endfor %}
232
168
 
233
- ### 4.5.3 Recommended Option{% if t("sectionAside.recommendedOption") != "Recommended Option" %} ({{ t("sectionAside.recommendedOption") }}){% endif %}
169
+ ### 5.5.3 Recommended Option{% if t("sectionAside.recommendedOption") != "Recommended Option" %} ({{ t("sectionAside.recommendedOption") }}){% endif %}
234
170
 
235
171
  | {{ t("implementationPlanning.recommendedTableHeaderLabel") }} | {{ t("implementationPlanning.recommendedTableHeaderValue") }} |
236
172
  |------|----|
@@ -239,7 +175,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
239
175
  | {{ t("implementationPlanning.rationaleLabel") }} | {{ implementationPlanning.recommendedOption.rationale }} |
240
176
  | {{ t("implementationPlanning.rejectedSummaryLabel") }} | {{ implementationPlanning.recommendedOption.rejectedSummary }} |
241
177
 
242
- ### 4.5.4 Stepwise Execution Order{% if t("sectionAside.stepwiseExecutionOrder") != "Stepwise Execution Order" %} ({{ t("sectionAside.stepwiseExecutionOrder") }}){% endif %}
178
+ ### 5.5.4 Stepwise Execution Order{% if t("sectionAside.stepwiseExecutionOrder") != "Stepwise Execution Order" %} ({{ t("sectionAside.stepwiseExecutionOrder") }}){% endif %}
243
179
 
244
180
  | Step | Ticket ID | Action (≤ 5min) | Files | Command / Test | Expected outcome |
245
181
  |------|-----------|------------------|-------|----------------|-------------------|
@@ -247,7 +183,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
247
183
  | {{ row.step }} | `{{ row.ticketId }}` | {{ row.action }} | `{{ row.files }}` | `{{ row.commandOrTest }}` | {{ row.expectedOutcome }} |
248
184
  {% endfor %}
249
185
 
250
- ### 4.5.5 Dependency / Migration Risk{% if t("sectionAside.dependencyRisk") != "Dependency / Migration Risk" %} ({{ t("sectionAside.dependencyRisk") }}){% endif %}
186
+ ### 5.5.5 Dependency / Migration Risk{% if t("sectionAside.dependencyRisk") != "Dependency / Migration Risk" %} ({{ t("sectionAside.dependencyRisk") }}){% endif %}
251
187
 
252
188
  {% if implementationPlanning.dependencyMigrationRisk | length == 0 -%}
253
189
  {{ t("emptyState.dependencyRisk") }}
@@ -259,7 +195,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
259
195
  {% endfor %}
260
196
  {%- endif %}
261
197
 
262
- ### 4.5.6 Validation Checklist{% if t("sectionAside.validationChecklist") != "Validation Checklist" %} ({{ t("sectionAside.validationChecklist") }}){% endif %}
198
+ ### 5.5.6 Validation Checklist{% if t("sectionAside.validationChecklist") != "Validation Checklist" %} ({{ t("sectionAside.validationChecklist") }}){% endif %}
263
199
 
264
200
  | Phase | Ticket ID | Check | Command / Observation | Expected outcome |
265
201
  |-------|-----------|-------|------------------------|-------------------|
@@ -267,7 +203,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
267
203
  | {{ row.phase }} | `{{ row.ticketId }}` | {{ row.check }} | `{{ row.commandOrObservation }}` | {{ row.expectedOutcome }} |
268
204
  {% endfor %}
269
205
 
270
- ### 4.5.7 Rollback Strategy{% if t("sectionAside.rollbackStrategy") != "Rollback Strategy" %} ({{ t("sectionAside.rollbackStrategy") }}){% endif %}
206
+ ### 5.5.7 Rollback Strategy{% if t("sectionAside.rollbackStrategy") != "Rollback Strategy" %} ({{ t("sectionAside.rollbackStrategy") }}){% endif %}
271
207
 
272
208
  | ID | Step | Action | Trigger signal | {{ t("columns.checkMethod") }} |
273
209
  |----|------|--------|----------------|-----------|
@@ -275,7 +211,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
275
211
  | {{ row.id }} | {{ row.step }} | `{{ row.action }}` | {{ row.triggerSignal }} | `{{ row.verificationMethod }}` |
276
212
  {% endfor %}
277
213
 
278
- ### 4.5.9 Plan Body Verification{% if t("sectionAside.planBodyVerification") != "Plan Body Verification" %} ({{ t("sectionAside.planBodyVerification") }}){% endif %}
214
+ ### 5.5.9 Plan Body Verification{% if t("sectionAside.planBodyVerification") != "Plan Body Verification" %} ({{ t("sectionAside.planBodyVerification") }}){% endif %}
279
215
 
280
216
  {{ t("sectionIntro.planBodyVerification") }}
281
217
 
@@ -302,17 +238,17 @@ approved: {{ frontmatter.approved | yaml_scalar }}
302
238
 
303
239
  {% endif %}
304
240
  {% if header.taskType == 'release-handoff' %}
305
- ## 4.6 Release Handoff Deliverables
241
+ ## 5.6 Release Handoff Deliverables
306
242
 
307
243
  {{ t("releaseHandoff.auditNote") }}
308
244
 
309
- ### 4.6.1 Source Verification Report
245
+ ### 5.6.1 Source Verification Report
310
246
 
311
247
  - Path (project-relative): `{{ releaseHandoff.sourceVerificationReport.path }}`
312
- - Quoted `Verdict Token` row from that report's `## 2.` table:
248
+ - Quoted `Verdict Token` row from that report's `## 7.` table:
313
249
  > {{ releaseHandoff.sourceVerificationReport.verdictTokenQuote }}
314
250
 
315
- ### 4.6.2 Feature Branch & Working-Tree State{% if t("releaseHandoff.branchStateAside") != "captured at run start" %} ({{ t("releaseHandoff.branchStateAside") }}){% endif %}
251
+ ### 5.6.2 Feature Branch & Working-Tree State{% if t("releaseHandoff.branchStateAside") != "captured at run start" %} ({{ t("releaseHandoff.branchStateAside") }}){% endif %}
316
252
 
317
253
  - Feature branch: `{{ releaseHandoff.featureBranchState.branchName }}`
318
254
  - {{ t("releaseHandoff.gitStatusShortLabel") }}:
@@ -321,7 +257,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
321
257
  ```
322
258
  - {{ t("releaseHandoff.existingPrLabel") }}: `{{ releaseHandoff.featureBranchState.existingPrUrl or '(none)' }}`
323
259
 
324
- ### 4.6.3 User Selections{% if t("releaseHandoff.userSelectionsAside") != "menu response log" %} ({{ t("releaseHandoff.userSelectionsAside") }}){% endif %}
260
+ ### 5.6.3 User Selections{% if t("releaseHandoff.userSelectionsAside") != "menu response log" %} ({{ t("releaseHandoff.userSelectionsAside") }}){% endif %}
325
261
 
326
262
  | {{ t("releaseHandoff.questionsTableHeader.questionId") }} | {{ t("releaseHandoff.questionsTableHeader.questionBody") }} | {{ t("releaseHandoff.questionsTableHeader.userResponse") }} | {{ t("releaseHandoff.questionsTableHeader.allowedOptions") }} |
327
263
  |---------|-----------|--------------------|--------------------|
@@ -329,7 +265,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
329
265
  | H2 | {{ t("releaseHandoff.h2Body") }} | `{{ releaseHandoff.userSelections.h2 or t("releaseHandoff.h2DefaultLabel") }}` | {{ t("releaseHandoff.h2OptionsLabel") }} |
330
266
  | H3 | {{ t("releaseHandoff.h3Body") }} | `{{ releaseHandoff.userSelections.h3 }}` | `use as-is` / `edit then proceed` / `cancel` |
331
267
 
332
- ### 4.6.4 Executed Commands
268
+ ### 5.6.4 Executed Commands
333
269
 
334
270
  {% if releaseHandoff.executedCommands | length == 0 -%}
335
271
  - {{ t("releaseHandoff.noMutationNote") }}
@@ -341,7 +277,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
341
277
  {% endfor %}
342
278
  {%- endif %}
343
279
 
344
- ### 4.6.5 Commit List
280
+ ### 5.6.5 Commit List
345
281
 
346
282
  {% if releaseHandoff.commitList.empty -%}
347
283
  - No implementation commits found; release-handoff is blocked.
@@ -353,7 +289,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
353
289
  {% endfor %}
354
290
  {%- endif %}
355
291
 
356
- ### 4.6.6 Merge Conflict Probe
292
+ ### 5.6.6 Merge Conflict Probe
357
293
 
358
294
  {% if releaseHandoff.mergeConflictProbe.kind == 'not-run' -%}
359
295
  - Not run (user picked local only or skip).
@@ -363,7 +299,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
363
299
  - Conflicts detected against {{ releaseHandoff.mergeConflictProbe.baseBranch }} at {{ releaseHandoff.mergeConflictProbe.baseSha }}; user chose {{ releaseHandoff.mergeConflictProbe.userChoice }}. Conflicting paths: {{ releaseHandoff.mergeConflictProbe.conflictingPaths | join(', ') }}.
364
300
  {%- endif %}
365
301
 
366
- ### 4.6.7 Pull Request Outcome
302
+ ### 5.6.7 Pull Request Outcome
367
303
 
368
304
  {% if releaseHandoff.pullRequestOutcome.kind == 'no-action' -%}
369
305
  - No PR action requested.
@@ -375,15 +311,15 @@ approved: {{ frontmatter.approved | yaml_scalar }}
375
311
  - PR creation skipped: {{ releaseHandoff.pullRequestOutcome.reason }}
376
312
  {%- endif %}
377
313
 
378
- ### 4.6.8 Routing Recommendation
314
+ ### 5.6.8 Routing Recommendation
379
315
 
380
316
  {{ releaseHandoff.routingRecommendation }}
381
317
 
382
318
  {% endif %}
383
319
  {% if header.taskType == 'implementation' %}
384
- ## 4.7 Implementation Deliverables
320
+ ## 5.7 Implementation Deliverables
385
321
 
386
- ### 4.7.1 Approved Plan Reference
322
+ ### 5.7.1 Approved Plan Reference
387
323
 
388
324
  - Plan file (project-relative): `{{ implementation.approvedPlanReference.planFile }}`
389
325
  - Approval evidence:
@@ -391,7 +327,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
391
327
  - {{ t("executionMeta.runExecutorWorktreePath") }}: `{{ implementation.approvedPlanReference.executorWorktreePath }}`
392
328
  - {{ t("executionMeta.runBaseRef") }}: `{{ implementation.approvedPlanReference.baseRefSha }}`
393
329
 
394
- ### 4.7.2 Commit List
330
+ ### 5.7.2 Commit List
395
331
 
396
332
  {% if implementation.commitList | length == 0 -%}
397
333
  - No implementation commits produced; routing recommendation must be back to implementation-planning.
@@ -403,7 +339,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
403
339
  {% endfor %}
404
340
  {%- endif %}
405
341
 
406
- ### 4.7.3 Diff Summary
342
+ ### 5.7.3 Diff Summary
407
343
 
408
344
  ```
409
345
  {{ implementation.diffSummary.rawStat }}
@@ -415,7 +351,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
415
351
  | `{{ row.file }}` | {{ row.action }} | `{{ row.lines }}` | {{ row.planStep }} |
416
352
  {% endfor %}
417
353
 
418
- ### 4.7.4 Out-of-plan Edits
354
+ ### 5.7.4 Out-of-plan Edits
419
355
 
420
356
  {% if implementation.outOfPlanEdits | length == 0 -%}
421
357
  {{ t("emptyState.outOfPlanEdits") }}
@@ -427,7 +363,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
427
363
  {% endfor %}
428
364
  {%- endif %}
429
365
 
430
- ### 4.7.5 Validation Evidence
366
+ ### 5.7.5 Validation Evidence
431
367
 
432
368
  | Phase | Command | Exit code | Output tail | TDD evidence |
433
369
  |-------|---------|-----------|-------------|--------------|
@@ -435,7 +371,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
435
371
  | {{ row.phase }} | `{{ row.command }}` | `{{ row.exitCode }}` | {{ row.outputTail }} | {{ row.tddEvidence or '--' }} |
436
372
  {% endfor %}
437
373
 
438
- ### 4.7.6 Verifier Results
374
+ ### 5.7.6 Verifier Results
439
375
 
440
376
  {% for block in implementation.verifierResults %}
441
377
  - **{{ block.verifier }}** — Verdict: `{{ block.verdict }}`
@@ -446,7 +382,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
446
382
  - Discrepancy: {{ block.discrepancy or t("emptyState.discrepancy") }}
447
383
  {% endfor %}
448
384
 
449
- ### 4.7.7 Rollback Verification
385
+ ### 5.7.7 Rollback Verification
450
386
 
451
387
  | Category | Rollback command | Verification | Result |
452
388
  |----------|-------------------|---------------|--------|
@@ -454,15 +390,15 @@ approved: {{ frontmatter.approved | yaml_scalar }}
454
390
  | {{ row.category }} | `{{ row.rollbackCommand }}` | {{ row.verification }} | `{{ row.result }}` |
455
391
  {% endfor %}
456
392
 
457
- ### 4.7.8 Routing Recommendation
393
+ ### 5.7.8 Routing Recommendation
458
394
 
459
395
  {{ implementation.routingRecommendation }}
460
396
 
461
397
  {% endif %}
462
398
  {% if header.taskType == 'final-verification' %}
463
- ## 4.8 Final Verification Deliverables
399
+ ## 5.8 Final Verification Deliverables
464
400
 
465
- ### 4.8.1 Source Implementation Report
401
+ ### 5.8.1 Source Implementation Report
466
402
 
467
403
  - Path (project-relative): `{{ finalVerification.sourceImplementationReport.path }}`
468
404
  - {{ t("evidenceMeta.commitListSummary") }}:
@@ -481,7 +417,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
481
417
  {{ finalVerification.sourceImplementationReport.gitDiffStat }}
482
418
  ```
483
419
 
484
- ### 4.8.2 Acceptance Blockers
420
+ ### 5.8.2 Acceptance Blockers
485
421
 
486
422
  {% if finalVerification.acceptanceBlockers | length == 0 -%}
487
423
  - No acceptance blockers found.
@@ -493,7 +429,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
493
429
  {% endfor %}
494
430
  {%- endif %}
495
431
 
496
- ### 4.8.3 Residual Risk
432
+ ### 5.8.3 Residual Risk
497
433
 
498
434
  {% if finalVerification.residualRisk | length == 0 -%}
499
435
  {{ t("emptyState.lingeringRisks") }}
@@ -505,7 +441,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
505
441
  {% endfor %}
506
442
  {%- endif %}
507
443
 
508
- ### 4.8.4 Validation Evidence{% if t("finalVerification.validationEvidenceAside") != "requirements coverage" %} ({{ t("finalVerification.validationEvidenceAside") }}){% endif %}
444
+ ### 5.8.4 Validation Evidence{% if t("finalVerification.validationEvidenceAside") != "requirements coverage" %} ({{ t("finalVerification.validationEvidenceAside") }}){% endif %}
509
445
 
510
446
  | ID | {{ t("finalVerification.columnRequirement") }} | Artifact | Status |
511
447
  |----|--------------------------------|----------|--------|
@@ -513,7 +449,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
513
449
  | {{ row.id }} | {{ row.requirement }} | `{{ row.artifact }}` | {{ row.status }} |
514
450
  {% endfor %}
515
451
 
516
- ### 4.8.5 Read-only Command Log
452
+ ### 5.8.5 Read-only Command Log
517
453
 
518
454
  | # | Tier | Command (verbatim) | Status | Exit code | Output tail |
519
455
  |---|------|---------------------|--------|-----------|-------------|
@@ -521,7 +457,7 @@ approved: {{ frontmatter.approved | yaml_scalar }}
521
457
  | {{ row.number }} | {{ row.tier }} | `{{ row.command }}` | `{{ row.status }}` | {{ row.exitCode if row.exitCode is not none else '—' }} | {{ row.rejectionReason if row.status == 'rejected' else row.outputTail }} |
522
458
  {% endfor %}
523
459
 
524
- ### 4.8.6 Conditional Acceptance Conditions
460
+ ### 5.8.6 Conditional Acceptance Conditions
525
461
 
526
462
  {% if not finalVerdict.conditionalAcceptanceConditions -%}
527
463
  - Not applicable (verdict is not `conditional-accept`).
@@ -533,13 +469,13 @@ approved: {{ frontmatter.approved | yaml_scalar }}
533
469
  {% endfor %}
534
470
  {%- endif %}
535
471
 
536
- ### 4.8.7 Routing Recommendation
472
+ ### 5.8.7 Routing Recommendation
537
473
 
538
474
  {{ finalVerification.routingRecommendation }}
539
475
 
540
476
  {% endif %}
541
477
  {% if header.taskType == 'improvement-discovery' %}
542
- ## 4.9 Improvement Candidates
478
+ ## 5.9 Improvement Candidates
543
479
 
544
480
  > Lens whitelist and column schema enforced by `validators/validate-improvement-report.py`. Row count is bounded by the brief's `candidate-cap` (default 8, absolute max 12).
545
481
 
@@ -547,56 +483,121 @@ approved: {{ frontmatter.approved | yaml_scalar }}
547
483
  |---------|------|-------|-------|----------|--------|-----------|----------------|------------------------|----------|
548
484
 
549
485
  {% endif %}
550
- ## 5. Clarification Items
551
-
552
- {{ t("sectionIntro.clarificationItems") }}
486
+ ## 6. Cross Verification Results
553
487
 
554
- {% if clarificationItems | length == 0 -%}
555
- {{ t("emptyState.noClarification") }}
556
- {%- else %}
557
- {{ t("clarification.fillAndRerun") }}
558
-
559
- - Claude Code: `/okstra-run resume-clarification task-key={{ header.taskKey }}`
560
- - {{ t("clarification.separateTerminalLabel") }}: `scripts/okstra.sh --resume-clarification --task-key {{ header.taskKey }}`
488
+ {% if crossVerification.roundHistory and not crossVerification.roundHistory.disabled -%}
489
+ ### 6.0 Round History
561
490
 
562
- | ID | Ticket ID | Kind | Statement | Expected form | Blocks | Status | User input |
563
- |----|-----------|------|-----------|---------------|--------|--------|-----------|
564
- {% for row in clarificationItems -%}
565
- | {{ row.id }} | `{{ row.ticketId }}` | `{{ row.kind }}` | {{ row.statement }} | {{ row.expectedForm }} | `{{ row.blocks }}` | {{ row.status }} | {{ row.userInput or '' }} |
491
+ {% if crossVerification.roundHistory.rounds | length > 1 -%}
492
+ | Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches (worker:status:durationMs) | skippedWorkers (worker:reason) |
493
+ |-------|----------------|---------------|----------------------|----------------------------------------|---------------------------------|
494
+ {% for row in crossVerification.roundHistory.rounds -%}
495
+ | {{ row.round }} | {{ row.inputQueueSize }} | {{ row.resolvedCount }} | {{ row.carriedForwardCount }} | {{ row.dispatches }} | {{ row.skippedWorkers }} |
566
496
  {% endfor %}
567
497
 
568
- {{ t("clarification.columnGuide") }}
498
+ - `round2SkippedReason`: `{{ crossVerification.roundHistory.round2SkippedReason }}` ← {{ t("roundHistory.round2SkippedReasonNote") }}
499
+ {% elif crossVerification.roundHistory.rounds | length == 1 -%}
500
+ {% set r = crossVerification.roundHistory.rounds[0] -%}
501
+ - {{ t("roundHistory.singleRoundPrefix") }} resolved={{ r.resolvedCount }}, carriedForward={{ r.carriedForwardCount }}, round2SkippedReason=`{{ crossVerification.roundHistory.round2SkippedReason }}`
502
+ {% else -%}
503
+ - {{ t("roundHistory.noRoundsNote") }} round2SkippedReason=`{{ crossVerification.roundHistory.round2SkippedReason }}`
504
+ {% endif %}
569
505
 
570
- - **`Kind`** ∈ `{material, decision, data-point}`.
571
- - **`Blocks`** ∈ `{approval, next-phase, none}`.
572
- - **`Status`** ∈ `{open, answered, resolved, obsolete}`.
506
+ {% endif %}
507
+ ### 6.1 Consensus
508
+
509
+ {% if crossVerification.consensus | length == 0 -%}
510
+ {{ t("emptyState.consensusItems") }}
511
+ {%- else %}
512
+ | {{ t("columns.recordMeta") }} | Statement | Evidence (path:line / log / worker report) |
513
+ |--------|-----------|---------------------------------------------|
514
+ {% for row in crossVerification.consensus -%}
515
+ | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Source items: {{ row.sourceItems | join(', ') }} | {{ row.statement }} | {{ row.evidence }} |
516
+ {% endfor %}
573
517
  {%- endif %}
574
518
 
575
- ## 6. Recommended Next Steps
519
+ {{ t("sectionIntro.sourceItemsRule") }}
520
+
521
+ ### 6.2 Differences
576
522
 
577
- {% if recommendedNextSteps | length == 0 -%}
578
- - No further action required. Final verdict in section 2 stands.
523
+ {% if crossVerification.differences | length == 0 -%}
524
+ {{ t("emptyState.differences") }}
579
525
  {%- else %}
580
- {% for step in recommendedNextSteps -%}
581
- {{ loop.index }}. {{ step.text }}
582
- {% if step.commands -%}
583
- {% for cmd in step.commands %}
584
- - {{ cmd.label }}:
585
- - Claude Code: `{{ cmd.claudeCode }}`
586
- - {{ t("clarification.separateTerminalLabel") }}: `{{ cmd.terminal }}`
587
- {% endfor -%}
588
- {%- endif %}
526
+ | {{ t("columns.recordMeta") }} | Disagreement | Evidence |
527
+ |--------|--------------|----------|
528
+ {% for row in crossVerification.differences -%}
529
+ | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Workers: {% for w in row.workersPosition %}{{ w.worker }}:{{ w.itemId }} ({{ w.position }}){% if not loop.last %} / {% endif %}{% endfor %} | {{ row.disagreement }} | {{ row.evidence }} |
589
530
  {% endfor %}
590
531
  {%- endif %}
591
532
 
592
- ## 7. Follow-up Tasks{% if t("followUpTasks.headingAside") != "Follow-up Tasks" %} ({{ t("followUpTasks.headingAside") }}){% endif %}
533
+ ## 7. Final Verdict
593
534
 
594
- {% if followUpTasks | length == 0 -%}
595
- {{ t("emptyState.noFollowUp") }}
535
+ {{ t("finalVerdict.intro") }}
536
+
537
+ | {{ t("verdictCard.tableHeaderLabel") }} | {{ t("verdictCard.tableHeaderValue") }} |
538
+ |------|----|
539
+ | Final Conclusion | {{ finalVerdict.finalConclusion }} |
540
+ | Verdict Token | `{{ finalVerdict.verdictToken }}` |
541
+ | Direction | `{{ finalVerdict.direction }}` |
542
+ | {{ t("verdictCard.rationaleLabel") }} | {{ finalVerdict.rationaleRowIds | join(', ') }} |
543
+ | {{ t("verdictCard.nextStepLabel") }} | {{ finalVerdict.nextStep }} |
544
+
545
+ {% if clarificationCarryIn and clarificationCarryIn.sourceFile %}
546
+ ## 0. Clarification Response Carried In From Previous Run
547
+
548
+ - Source file: `{{ clarificationCarryIn.sourceFile }}`
549
+ - {{ t("sectionIntro.clarificationCarryIn") }}
550
+
551
+ {% endif %}
552
+ ## Summary of the Problem or Verification Target
553
+
554
+ {{ t("sectionIntro.ticketCoverage") }}
555
+
556
+ | {{ t("columns.recordMeta") }} | {{ t("columns.summary") }} |
557
+ |--------|------------|
558
+ {% for row in summary -%}
559
+ | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>{{ t("columns.source") }}: {{ row.source }} | {{ row.summary }} |
560
+ {% endfor %}
561
+
562
+ {% if ticketCoverage.omit %}
563
+ {# Ticket Coverage omitted entirely — release-handoff / final-verification #}
596
564
  {%- else %}
597
- | {{ t("columns.recordMeta") }} | Title | Scope (files/areas) | Reason / Why deferred |
598
- |--------|-------|---------------------|------------------------|
599
- {% for row in followUpTasks -%}
600
- | **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Origin: `{{ row.origin }}`<br>New Task ID: `{{ row.newTaskId }}`<br>Type: `{{ row.suggestedTaskType }}`<br>Priority: `{{ row.priority }}`<br>Auto-spawn: `{{ row.autoSpawn }}` | {{ row.title }} | {{ row.scope }} | {{ row.reason }} |
565
+ ## Ticket Coverage
566
+
567
+ {{ t("ticketCoverage.intro") }}
568
+
569
+ {% if ticketCoverage.singleTicket -%}
570
+ - Single ticket run: {{ ticketCoverage.singleTicket }}
571
+ {%- else %}
572
+ | Ticket ID | {{ t("ticketCoverage.columnSections") }} | {{ t("ticketCoverage.columnRelatedIds") }} |
573
+ |-----------|-----------|---------------|
574
+ {% for row in ticketCoverage.rows -%}
575
+ | `{{ row.ticketId }}` | `{{ row.sections }}` | `{{ row.relatedIds }}` |
601
576
  {% endfor %}
602
577
  {%- endif %}
578
+
579
+ {% endif %}
580
+ ## Execution Status by Agent
581
+
582
+ {{ t("sectionIntro.executionStatus") }}
583
+
584
+ | {{ t("columns.recordMeta") }} | Summary of Key Findings |
585
+ |--------|-------------------------|
586
+ {% for row in executionStatus -%}
587
+ | **{{ row.agent }}**<br>Role: {{ row.role }}<br>Model: {{ row.model }}<br>Status: {{ row.status }}<br>{{ t("columns.rawTokens") }}: {{ row.totalTokens | format_int }}{% if row.cliTotalTokens %} (CLI: {{ row.cliTotalTokens | format_int }}){% endif %}<br>{{ t("columns.billableTokens") }}: {{ row.billableTokens | format_int }}<br>{{ t("columns.cost") }}: {{ row.costUsd | format_usd }}{% if row.cliCostUsd %} (+ CLI {{ row.cliCostUsd | format_usd }}){% endif %}<br>Duration: {{ row.durationMs | format_duration_ms }} | {{ row.summary }} |
588
+ {% endfor %}
589
+
590
+ ## {{ t("tokenSummary.heading") }}
591
+
592
+ | {{ t("tokenSummary.tableHeaderItem") }} | {{ t("columns.rawTokens") }} | {{ t("columns.billableTokensInputEquiv") }} | {{ t("columns.cost") }} |
593
+ |------|-----------|------------------------|------------|
594
+ | {{ t("tokenSummary.rowLead") }} | `{{ tokenUsage.lead.totalTokens | format_int }}` | `{{ tokenUsage.lead.billableTokens | format_int }}` | `{{ tokenUsage.lead.costUsd | format_usd }}` |
595
+ | {{ t("tokenSummary.rowWorkerTotal") }} | `{{ tokenUsage.worker.totalTokens | format_int }}` | `{{ tokenUsage.worker.billableTokens | format_int }}` | `{{ tokenUsage.worker.costUsd | format_usd }}` |
596
+ | {{ t("tokenSummary.rowGrandTotal") }} | **`{{ tokenUsage.grand.totalTokens | format_int }}`** | **`{{ tokenUsage.grand.billableTokens | format_int }}`** | **`{{ tokenUsage.grand.costUsd | format_usd }}`** |
597
+ {% if tokenUsage.cli and tokenUsage.cli.costUsd is not none and tokenUsage.cli.costUsd > 0 -%}
598
+ | {{ t("tokenSummary.rowCliExtra") }} | | | `{{ tokenUsage.cli.costUsd | format_usd }}` |
599
+ {% endif %}
600
+
601
+ {# At Phase 6 numeric cells are null and render as `--`.
602
+ Phase 7's okstra-token-usage.py populates tokenUsage in data.json then
603
+ re-invokes this renderer to produce the final markdown. #}