okstra 0.31.0 → 0.32.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 (51) hide show
  1. package/package.json +1 -1
  2. package/runtime/BUILD.json +2 -2
  3. package/runtime/agents/SKILL.md +3 -3
  4. package/runtime/agents/workers/report-writer-worker.md +45 -67
  5. package/runtime/bin/okstra-render-final-report.py +101 -0
  6. package/runtime/bin/okstra-render-report-views.py +17 -10
  7. package/runtime/bin/okstra-token-usage.py +3 -1
  8. package/runtime/python/okstra_ctl/final_report_schema.py +253 -0
  9. package/runtime/python/okstra_ctl/render_final_report.py +201 -0
  10. package/runtime/python/okstra_ctl/report_views.py +108 -305
  11. package/runtime/python/okstra_token_usage/__init__.py +5 -1
  12. package/runtime/python/okstra_token_usage/cli.py +66 -36
  13. package/runtime/python/okstra_token_usage/report.py +148 -65
  14. package/runtime/python/okstra_vendor/__init__.py +37 -0
  15. package/runtime/python/okstra_vendor/jinja2/__init__.py +38 -0
  16. package/runtime/python/okstra_vendor/jinja2/_identifier.py +6 -0
  17. package/runtime/python/okstra_vendor/jinja2/async_utils.py +99 -0
  18. package/runtime/python/okstra_vendor/jinja2/bccache.py +408 -0
  19. package/runtime/python/okstra_vendor/jinja2/compiler.py +1998 -0
  20. package/runtime/python/okstra_vendor/jinja2/constants.py +20 -0
  21. package/runtime/python/okstra_vendor/jinja2/debug.py +191 -0
  22. package/runtime/python/okstra_vendor/jinja2/defaults.py +48 -0
  23. package/runtime/python/okstra_vendor/jinja2/environment.py +1672 -0
  24. package/runtime/python/okstra_vendor/jinja2/exceptions.py +166 -0
  25. package/runtime/python/okstra_vendor/jinja2/ext.py +870 -0
  26. package/runtime/python/okstra_vendor/jinja2/filters.py +1873 -0
  27. package/runtime/python/okstra_vendor/jinja2/idtracking.py +318 -0
  28. package/runtime/python/okstra_vendor/jinja2/lexer.py +868 -0
  29. package/runtime/python/okstra_vendor/jinja2/loaders.py +693 -0
  30. package/runtime/python/okstra_vendor/jinja2/meta.py +112 -0
  31. package/runtime/python/okstra_vendor/jinja2/nativetypes.py +130 -0
  32. package/runtime/python/okstra_vendor/jinja2/nodes.py +1206 -0
  33. package/runtime/python/okstra_vendor/jinja2/optimizer.py +48 -0
  34. package/runtime/python/okstra_vendor/jinja2/parser.py +1049 -0
  35. package/runtime/python/okstra_vendor/jinja2/py.typed +0 -0
  36. package/runtime/python/okstra_vendor/jinja2/runtime.py +1062 -0
  37. package/runtime/python/okstra_vendor/jinja2/sandbox.py +436 -0
  38. package/runtime/python/okstra_vendor/jinja2/tests.py +256 -0
  39. package/runtime/python/okstra_vendor/jinja2/utils.py +766 -0
  40. package/runtime/python/okstra_vendor/jinja2/visitor.py +92 -0
  41. package/runtime/python/okstra_vendor/markupsafe/__init__.py +396 -0
  42. package/runtime/python/okstra_vendor/markupsafe/_native.py +8 -0
  43. package/runtime/python/okstra_vendor/markupsafe/py.typed +0 -0
  44. package/runtime/schemas/final-report-v1.0.schema.json +1391 -0
  45. package/runtime/skills/okstra-report-writer/SKILL.md +29 -28
  46. package/runtime/templates/reports/final-report.template.md +370 -411
  47. package/runtime/templates/reports/report.css +12 -6
  48. package/runtime/validators/lib/fixtures.sh +7 -7
  49. package/runtime/validators/validate-report-views.py +24 -153
  50. package/runtime/validators/validate-run.py +102 -19
  51. package/src/install.mjs +20 -1
@@ -8,11 +8,13 @@ user-invocable: false
8
8
 
9
9
  ## File-author ownership (BLOCKING)
10
10
 
11
- The final-report file at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md` is authored by the `Report writer worker` subagent when that worker is in the run's roster. Claude lead reviews the file but does NOT write it itself in that case. Lead-authored fallback is permitted only after a real Report writer worker dispatch attempt with a recorded non-`completed` terminal status (`error` / `timeout` / `not-run`) and a logged reason (`okstra-error-log.py`). **Except for `release-handoff`**, which has no worker roster — the Claude lead authors the final-report directly by design (see "Release-handoff section contract" below), and the fallback rules in this section do not apply.
11
+ The final-report **data.json** (JSON SSOT) at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` is authored by the `Report writer worker` subagent when that worker is in the run's roster. The user-facing **markdown** at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md` is then produced by `scripts/okstra-render-final-report.py` from the data.json — the worker invokes the renderer as part of its own turn so both files land on disk before it returns. Claude lead reviews both files but does NOT write them itself in that case. Lead-authored fallback is permitted only after a real Report writer worker dispatch attempt with a recorded non-`completed` terminal status (`error` / `timeout` / `not-run`) and a logged reason (`okstra-error-log.py`). **Except for `release-handoff`**, which has no worker roster — the Claude lead authors the data.json directly by design (see "Release-handoff section contract" below), and the fallback rules in this section do not apply.
12
12
 
13
- If you are reading this skill **as the report-writer-worker subagent**, YOU are the one calling the `Write` tool against the result path. Do not return the report inline the file on disk is the canonical artifact.
13
+ 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.
14
14
 
15
- If you are reading this skill **as Claude lead**, your job in Phase 6 is to (a) prepare the report-writer prompt, (b) dispatch the Report writer worker per the Phase 6 dispatch template in SKILL.md, (c) review the produced file in Phase 7. Do not call `Write` against the final-report path yourself when Report writer worker is in the roster.
15
+ If you are reading this skill **as the report-writer-worker subagent**, YOU are the one calling the `Write` tool against the data.json path AND invoking the renderer via `Bash`. Do not return either artifact inline the files on disk are the canonical record.
16
+
17
+ If you are reading this skill **as Claude lead**, your job in Phase 6 is to (a) prepare the report-writer prompt, (b) dispatch the Report writer worker per the Phase 6 dispatch template in SKILL.md, (c) review both files in Phase 7. Do not call `Write` against either path yourself when Report writer worker is in the roster.
16
18
 
17
19
  ## When to Use
18
20
 
@@ -40,15 +42,15 @@ The prompt MUST include, in this order at the top:
40
42
 
41
43
  1. `**Project Root:** <absolute-path>`
42
44
  2. `**Prompt History Path:** <project-relative-path>` (under current run `prompts/`)
43
- 3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.md` — canonical final-report file (user-facing)
45
+ 3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` — canonical JSON SSOT. The renderer produces the sibling `.md` automatically.
44
46
  4. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — mandatory validator-checked worker-results audit file
45
47
  5. `Assigned worker prompt history path: <absolute-path>`
46
48
  6. `**Model:** Report writer worker, <modelExecutionValue>` (resolved per Phase 5.5 anchor-header rules)
47
- 7. The full `[Required reading]` clause (see [okstra-team-contract](../okstra-team-contract/SKILL.md)) including `final-report-template.md`.
49
+ 7. The full `[Required reading]` clause (see [okstra-team-contract](../okstra-team-contract/SKILL.md)) including `schemas/final-report-v1.0.schema.json` and `templates/reports/final-report.template.md` (template is read-only — the worker writes the data.json that drives it).
48
50
  8. The verbatim `## Available MCP Servers` block from the task brief, if present.
49
51
  9. The convergence classifications (Full/Partial/Contested/Worker-Unique), the round history table (`roundHistory[]`), the `round2SkippedReason` value, and pointers to all worker result files under `worker-results/`. The report-writer worker must reproduce a Round History sub-table in Section 1 of the final report so the reader can see which rounds executed, queue sizes, and why Round 2 was (or was not) skipped.
50
52
  10. For implementation-planning runs: a literal block listing the 8 required English section headings the validator scans for (`Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`). The writer must use these exact substrings as section headings (Korean translation in parentheses is allowed).
51
- 11. An explicit instruction: `You are the author of TWO files: (a) the final-report file at <Result Path>, (b) the worker-results file at <Worker Result Path>. Write both directly using your Write tool. Do not return the report inline. The validator fails the run when (b) is missing.`
53
+ 11. An explicit instruction: `You are the author of TWO files: (a) the final-report data.json at <Result Path>, (b) the worker-results audit file at <Worker Result Path>. After writing the data.json, invoke "python3 scripts/okstra-render-final-report.py <Result Path>" via Bash so the markdown sibling is rendered before you return. Do not return the report inline. The validator fails the run when (a)'s schema validation fails, when the rendered markdown is absent, or when (b) is missing.`
52
54
 
53
55
  ### Resume-safe dispatch
54
56
 
@@ -70,36 +72,35 @@ Speculative reasons such as "session resume constraint", "team object no longer
70
72
 
71
73
  ## Phase 6 → Phase 7 execution sequence (BLOCKING order)
72
74
 
73
- The four steps below MUST execute in this exact order. Reordering them is the recurring root cause of reports shipping with unsubstituted `{{LEAD_TOTAL_TOKENS}}` placeholders, Section 6 missing the follow-up entries, or Section 7 rows never spawning.
75
+ The four steps below MUST execute in this exact order. Reordering them is the recurring root cause of reports shipping with `--` token cells (Phase 7 not run yet), Section 6 missing follow-up entries, or Section 7 rows never spawning.
74
76
 
75
- 1. **Phase 6 — Report writer worker drafts the final-report file** at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md`. Token placeholders are left verbatim; Section 6 lists prioritized actions but does NOT yet include auto-spawned follow-ups (they don't exist yet).
76
- 2. **Phase 7 step 1 — Token-usage collector with `--substitute-final-report`** (BLOCKING). One invocation aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state AND substitutes the 10 placeholders in the final-report file. Skipping the flag ships literal `{{...}}` in the Token Usage Summary table.
77
+ 1. **Phase 6 — Report writer worker drafts the final-report data.json** at `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`, then invokes `scripts/okstra-render-final-report.py` to produce the sibling markdown. Token Usage cells in the data.json are `null` at this point (renderer emits `--` for nulls); Section 6 lists prioritized actions but does NOT yet include auto-spawned follow-ups (they don't exist yet).
78
+ 2. **Phase 7 step 1 — Token-usage collector with `--substitute-data`** (BLOCKING). One invocation aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state AND populates `tokenUsage` + `executionStatus[].totalTokens` etc. in the data.json AND re-invokes the renderer so the sibling markdown carries the real numbers. Skipping the flag ships a markdown full of `--` cells.
77
79
 
78
80
  ```bash
79
81
  python3 scripts/okstra-token-usage.py \
80
82
  <runDirectoryPath>/state/team-state-<task-type>-<seq>.json \
81
83
  --write --summary \
82
- --substitute-final-report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
84
+ --substitute-data <runDirectoryPath>/reports/final-report-<task-type>-<seq>.data.json
83
85
  ```
84
86
 
85
- The 10 substituted placeholders: `{{LEAD_TOTAL_TOKENS}}`, `{{LEAD_BILLABLE_TOKENS}}`, `{{LEAD_COST_USD}}`, `{{WORKER_TOTAL_TOKENS}}`, `{{WORKER_BILLABLE_TOKENS}}`, `{{WORKER_COST_USD}}`, `{{GRAND_TOTAL_TOKENS}}`, `{{GRAND_BILLABLE_TOKENS}}`, `{{GRAND_COST_USD}}`, `{{CLI_COST_USD}}`. The final-report file MUST already exist (Phase 6 output).
86
- 3. **Phase 7 step 1.5 — Render report views** (BLOCKING). Produces two derived artifacts from the now-substituted final-report MD:
87
+ 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).
88
+ 3. **Phase 7 step 1.5 — Render report views** (BLOCKING). Produces the self-contained HTML view from the now-substituted final-report MD:
87
89
 
88
90
  ```bash
89
91
  python3 scripts/okstra-render-report-views.py \
90
92
  <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
91
93
  ```
92
94
 
93
- Outputs (idempotent — re-running overwrites):
94
- - `runs/<task-type>/reports/final-report-<task-type>-<seq>.slim.md` token-saving AI-consumption copy.
95
- - `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view. Section 5 `C-*` clarification rows with `Status` ∈ {`open`, `answered`} embed `<textarea>` controls; 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)) that the user pastes to `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md`. The original final-report MD is **never** mutated by user input — the sidecar is the single write target.
95
+ Output (idempotent — re-running overwrites):
96
+ - `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view. Section 5 `C-*` 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)) that the user pastes to `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md`. The original final-report MD is **never** mutated by user input — the sidecar is the single write target.
96
97
 
97
- Must run AFTER step 1 (so token placeholders are substituted in both derived views) and BEFORE step 2 (so the slim/html artifacts exist for any validator step that checks them).
98
+ Must run AFTER step 1 (so token placeholders are substituted in the rendered html) and BEFORE step 2 (so the html artifact exists for any validator step that checks it).
98
99
  4. **Phase 7 step 2 — Follow-up task spawner** (BLOCKING when Section 7 is non-empty). Turns the report's `## 7. Follow-up Tasks (후속 작업)` rows into `tasks/<task-group>/<new-task-id>/` stubs.
99
100
 
100
101
  ```bash
101
102
  python3 scripts/okstra-spawn-followups.py \
102
- <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md \
103
+ <runDirectoryPath>/reports/final-report-<task-type>-<seq>.data.json \
103
104
  --project-root <project_root> \
104
105
  --task-group <task-group> \
105
106
  --parent-task-key <task-key>
@@ -107,9 +108,10 @@ The four steps below MUST execute in this exact order. Reordering them is the re
107
108
 
108
109
  Behaviour contract:
109
110
  - Idempotent: rows whose target dir exists are reported as `existing` and skipped. Reruns of the same parent task are safe.
110
- - Rows with `Auto-spawn? != yes` are reported as `skipped` and never written; surface them in Section 6 if manual action is still needed.
111
- - An invalid `Origin`, `Suggested task-type`, missing `Title`, or missing `Reason / Why deferred` exits `1`. The report-writer MUST refuse to ship a Section 7 with such rows.
112
- - **Canonical spawn rule (single source of truth):** the spawner runs when `task-type` {`implementation`, `final-verification`, `release-handoff`}, OR when Section 7 is non-empty for any other task-type. For the listed task-types Section 7 must be present in the report; an empty section renders as `- 후속 작업 없음.`. Missing / empty sections are no-ops (exit `0`). All other references to this rule (including the Persistence Checklist) defer to this statement.
111
+ - Rows with `autoSpawn != "yes"` are reported as `skipped` and never written; surface them in Section 6 if manual action is still needed.
112
+ - Rows whose `origin` is `phase-continuation` are reported as `skipped (no new task dir)` and never spawn they advance the same task-key via `/okstra-run` instead.
113
+ - An invalid `origin`, `suggestedTaskType`, missing `title`, missing `reason`, or missing `newTaskId` exits `1`. (Schema validation in Phase 6 catches most of these before the spawner runs.)
114
+ - **Canonical spawn rule (single source of truth):** the spawner runs when `task-type` ∈ {`implementation`, `final-verification`, `release-handoff`}, OR when `followUpTasks` is non-empty for any other task-type. For the listed task-types `followUpTasks` must be present (schema enforces the phase-continuation row for non-terminal task-types); an empty array is permitted only for `release-handoff`. Missing arrays are no-ops (exit `0`). All other references to this rule (including the Persistence Checklist) defer to this statement.
113
115
  5. **Phase 7 step 3 — Update Section 6** after the spawner. The report-writer MUST append one row per newly spawned task-key with its entry command:
114
116
 
115
117
  ```
@@ -120,7 +122,7 @@ The status file is written after step 3 completes.
120
122
 
121
123
  ## Final Report Structure
122
124
 
123
- The final report follows the structure below. If `instruction-set/final-report-template.md` exists, that format takes precedence.
125
+ The final report follows the structure encoded in `schemas/final-report-v1.0.schema.json`. The schema is 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.
124
126
 
125
127
  ### Report Header
126
128
 
@@ -175,7 +177,7 @@ Place this section immediately after the execution status table.
175
177
  ```
176
178
 
177
179
  Token Summary Generation Rules:
178
- - **You author this section in Phase 6, BEFORE Phase 7 runs the collector.** Therefore you MUST leave the 10 placeholders (`{{LEAD_TOTAL_TOKENS}}`, `{{LEAD_BILLABLE_TOKENS}}`, `{{LEAD_COST_USD}}`, `{{WORKER_TOTAL_TOKENS}}`, `{{WORKER_BILLABLE_TOKENS}}`, `{{WORKER_COST_USD}}`, `{{GRAND_TOTAL_TOKENS}}`, `{{GRAND_BILLABLE_TOKENS}}`, `{{GRAND_COST_USD}}`, `{{CLI_COST_USD}}`) verbatim in the table cells `okstra-token-usage.py --substitute-final-report` will fill them in Phase 7. Never replace any of these cells with a literal number, `not-collected`, `N/A`, `--`, `0`, or any other sentinel: that erases the substitution target, and the report ships with no token numbers. Also do not insert a note like "Phase 7 has not run yet" — the report is read AFTER Phase 7, so that statement is wrong on arrival.
180
+ - **You populate the data.json in Phase 6, BEFORE Phase 7 runs the collector.** Set `tokenUsage.lead.totalTokens` / `.billableTokens` / `.costUsd`, the `worker` and `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` to JSON `null`. The renderer emits `--` for nulls; `okstra-token-usage.py --substitute-data` populates them in Phase 7 and re-renders the markdown. Never set these cells to `0`, `"not-collected"`, `"--"`, `"N/A"`, or any other sentinel: nulls are the only valid placeholder, and the substitution step depends on them being null when it runs.
179
181
  - All values come from `usageSummary` (populated by `scripts/okstra-token-usage.py` at the start of Phase 7). Do not estimate or invent.
180
182
  - **Lead** row: `usageSummary.leadTotalTokens` / `usageSummary.leadBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.lead`.
181
183
  - **Worker 합계** row: `usageSummary.workerTotalTokens` / `usageSummary.workerBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.claudeWorkers`.
@@ -199,11 +201,11 @@ When the run's `task-type` is `implementation-planning`, the final report MUST c
199
201
  | 6 | `Validation Checklist` | `### Validation Checklist (검증 체크리스트)` |
200
202
  | 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
201
203
  | 8 | `User Approval Request` | Satisfied by the top-of-report `## User Approval Request (사용자 승인 게이트)` block. Do NOT recreate a `### 4.5.8 User Approval Request` body stub — the validator now fails reports that contain one. |
202
- | 9 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (계획 본문 검증)` containing a `Gate result:` line — copy `okstra-final-report.template.md §4.5.9` verbatim. Validator checks both substrings. |
204
+ | 9 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (계획 본문 검증)` containing a `Gate result:` line — copy `templates/reports/final-report.template.md §4.5.9` verbatim. Validator checks both substrings. |
203
205
 
204
206
  The Korean translation in parentheses is optional but the English keyword is mandatory. The body of each section is written in Korean per the writing rules below. For non-`implementation-planning` runs, omit this entire block — these headings are NOT validator-checked for other task-types.
205
207
 
206
- The final-report template `okstra-final-report.template.md` Section 4.5 already encodes this contract — copy that block verbatim and fill in.
208
+ The final-report template `templates/reports/final-report.template.md` Section 4.5 already encodes this contract — copy that block verbatim and fill in.
207
209
 
208
210
  ### Final-verification verdict token contract (BLOCKING)
209
211
 
@@ -217,7 +219,7 @@ When the run's `task-type` is `final-verification`, the report's `## 2. Final Ve
217
219
 
218
220
  For every other task-type, set the `Verdict Token` cell to `not-applicable`. Do NOT omit the row — the template renders it for all task-types and downstream tooling expects the field to exist.
219
221
 
220
- The final-report template `okstra-final-report.template.md` Section 2 already encodes this contract — copy that block verbatim and fill in.
222
+ The final-report template `templates/reports/final-report.template.md` Section 2 already encodes this contract — copy that block verbatim and fill in.
221
223
 
222
224
  ### Release-handoff section contract (release-handoff runs only)
223
225
 
@@ -225,7 +227,7 @@ When the run's `task-type` is `release-handoff`, the final report MUST include S
225
227
 
226
228
  **Single-lead authorship (release-handoff only):** release-handoff has no worker roster (no `Report writer worker`, no `Claude worker` drafter). The Claude lead authors the final-report file directly — there is no `Report writer worker` dispatch to perform in Phase 6, no resume-safe dispatch concern, and no mandatory worker-results file for a report-writer role. The rest of this skill's dispatch / resume / fallback machinery applies ONLY when `Report writer worker` is in the roster (i.e. every task-type other than `release-handoff`).
227
229
 
228
- The final-report template `okstra-final-report.template.md` Section 4.6 already encodes this contract — copy that block verbatim and fill in. For non-`release-handoff` runs, omit Section 4.6 entirely.
230
+ The final-report template `templates/reports/final-report.template.md` Section 4.6 already encodes this contract — copy that block verbatim and fill in. For non-`release-handoff` runs, omit Section 4.6 entirely.
229
231
 
230
232
  ### Mandatory worker-results file (BLOCKING)
231
233
 
@@ -291,8 +293,7 @@ Persistence steps that must be performed in Phase 7:
291
293
  - [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
292
294
  - [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
293
295
  - [ ] 8. **Spawn follow-up task stubs**: run `scripts/okstra-spawn-followups.py` against the final-report per the canonical spawn rule defined in "Phase 7 follow-up task spawner" above. Do not restate the trigger condition here — that section is the single source of truth. The script is idempotent across reruns.
294
- - [ ] 9. **Slim AI report**: `runs/<task-type>/reports/final-report-<task-type>-<seq>.slim.md` (produced by Phase 7 step 1.5 — see "Phase 6 Phase 7 execution sequence" above)
295
- - [ ] 10. **Human HTML report**: `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` (same step 1.5; self-contained, embeds `Export user response` button)
296
+ - [ ] 9. **Human HTML report**: `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` (produced by Phase 7 step 1.5 — self-contained, embeds `Export user response` button)
296
297
 
297
298
  ### Response after Persistence
298
299