okstra 0.27.0 → 0.29.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 (28) hide show
  1. package/bin/okstra +1 -0
  2. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +167 -0
  3. package/package.json +1 -1
  4. package/runtime/BUILD.json +2 -2
  5. package/runtime/agents/workers/claude-worker.md +6 -5
  6. package/runtime/agents/workers/codex-worker.md +5 -4
  7. package/runtime/agents/workers/gemini-worker.md +5 -4
  8. package/runtime/agents/workers/report-writer-worker.md +10 -3
  9. package/runtime/bin/okstra-render-report-views.py +129 -0
  10. package/runtime/prompts/launch.template.md +1 -1
  11. package/runtime/prompts/profiles/_common-contract.md +12 -4
  12. package/runtime/prompts/profiles/implementation-planning.md +1 -1
  13. package/runtime/python/okstra_ctl/report_views.py +701 -0
  14. package/runtime/python/okstra_token_usage/cli.py +9 -2
  15. package/runtime/python/okstra_token_usage/report.py +32 -3
  16. package/runtime/skills/okstra-convergence/SKILL.md +2 -2
  17. package/runtime/skills/okstra-report-writer/SKILL.md +25 -8
  18. package/runtime/skills/okstra-team-contract/SKILL.md +16 -15
  19. package/runtime/templates/reports/final-report.template.md +398 -211
  20. package/runtime/templates/reports/report.css +151 -0
  21. package/runtime/templates/reports/report.js +163 -0
  22. package/runtime/templates/reports/user-response.template.md +69 -0
  23. package/runtime/validators/lib/fixtures.sh +76 -2
  24. package/runtime/validators/validate-report-views.py +283 -0
  25. package/runtime/validators/validate-run.py +564 -4
  26. package/runtime/validators/validate-workflow.sh +4 -0
  27. package/src/install.mjs +1 -0
  28. package/src/render-views.mjs +67 -0
@@ -6,7 +6,7 @@ import json
6
6
  import sys
7
7
  from pathlib import Path
8
8
  from .collect import collect
9
- from .report import substitute_final_report
9
+ from .report import SubstituteRefusedError, substitute_final_report
10
10
 
11
11
 
12
12
  def main() -> int:
@@ -60,7 +60,14 @@ def main() -> int:
60
60
  print(f"sessions={s.get('sessionsFound', 0)} team={s.get('teamName', '')}", file=sys.stderr)
61
61
 
62
62
  if args.substitute_final_report is not None:
63
- replaced = substitute_final_report(args.substitute_final_report, updated)
63
+ try:
64
+ replaced = substitute_final_report(args.substitute_final_report, updated)
65
+ except SubstituteRefusedError as exc:
66
+ print(
67
+ f"final-report substitution REFUSED: {exc}",
68
+ file=sys.stderr,
69
+ )
70
+ return 2
64
71
  if replaced < 0:
65
72
  print(
66
73
  f"final-report substitution skipped: file not found at {args.substitute_final_report}",
@@ -18,19 +18,48 @@ def _format_usd(v) -> str:
18
18
  return "$0.00"
19
19
 
20
20
 
21
+ class SubstituteRefusedError(RuntimeError):
22
+ """Raised when substitution would write a zero-only Token Usage Summary.
23
+
24
+ Shipping `0` / `$0.00` in the Lead / Worker / Grand rows is the
25
+ observed silent-failure mode where the collector ran but every
26
+ session jsonl was empty (or the writer fabricated zeros). The
27
+ validator catches it post-hoc, but raising here at the substitution
28
+ boundary surfaces the failure at the exact step where it can still
29
+ be retried with a re-collection.
30
+ """
31
+
32
+
21
33
  def substitute_final_report(report_path: Path, state: dict) -> int:
22
34
  """Replace token-usage placeholders in the final report file with concrete
23
35
  values from the freshly computed usageSummary.
24
36
 
25
37
  Returns the number of placeholder occurrences replaced. If the report file
26
- does not exist, returns -1 without raising. If any required placeholder is
27
- still present after substitution attempts (e.g. usageSummary missing), the
28
- function still writes what it can and returns the count.
38
+ does not exist, returns -1 without raising.
39
+
40
+ Raises ``SubstituteRefusedError`` when ``usageSummary.grandTotalTokens``
41
+ is zero — substituting zeros into the report bakes in the most common
42
+ silent failure mode (collector ran but found nothing). Callers that
43
+ want to suppress the refusal (e.g. unit-test fixtures) can pass a
44
+ summary with ``grandTotalTokens`` > 0 or remove the summary entirely
45
+ so substitution is skipped.
29
46
  """
30
47
  if not report_path.is_file():
31
48
  return -1
32
49
 
33
50
  summary = state.get("usageSummary") or {}
51
+ grand_total = summary.get("grandTotalTokens", 0)
52
+ if isinstance(grand_total, (int, float)) and grand_total == 0 and summary:
53
+ raise SubstituteRefusedError(
54
+ "Refusing to substitute zero-only usageSummary into the final "
55
+ f"report at {report_path}. grandTotalTokens=0 means the "
56
+ "collector ran but every session jsonl was empty (or absent). "
57
+ "Re-run `python3 scripts/okstra-token-usage.py <team-state> "
58
+ "--write --summary --substitute-final-report <report-path>` "
59
+ "after locating the missing session jsonls. To intentionally "
60
+ "ship zeros (test fixtures only), omit `usageSummary` from the "
61
+ "team-state JSON before calling substitute_final_report."
62
+ )
34
63
  cost = summary.get("estimatedCostUsd") or {}
35
64
  lead_cost = cost.get("lead") or 0
36
65
  worker_cost = cost.get("claudeWorkers") or 0
@@ -73,7 +73,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
73
73
  - For bullet/numbered findings, parse `[TICKETID: <id>]` from the item title.
74
74
  - Items with multiple tickets (e.g. `TICKET-123, TICKET-456`) expand to a set of ticket keys.
75
75
  - Items tagged `unknown` keep the literal `unknown` as their ticket key.
76
- 2. For each finding, record the summary, evidence (file path, line number, basis), the worker who identified it, and the parsed ticket set.
76
+ 2. For each finding, record the summary, evidence (file path, line number, basis), the worker who identified it, **the worker-internal item ID assigned by that worker** (e.g. `F-001`, `1.1`, `F-3` — see `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT), and the parsed ticket set. The item ID is persisted on the finding record as `findings[].discoveredBy.<worker>.itemId` and on each cross-worker confirmation as `findings[].sourceItems[]` (one entry per contributing `<worker>:<item-id>` pair). The final-report's `## 1.1 Consensus` / `## 1.2 Differences` / `## 3.1 Primary Evidence` tables read this list verbatim into their `Source items` columns — without this, the synthesised `C-NNN` row has no traceable link back to the original worker wording.
77
77
  3. Claude Lead groups findings based on semantic similarity AND ticket-set equality:
78
78
  - Same semantics + same ticket set across 2+ workers → immediately reach `full consensus`.
79
79
  - Same semantics but disjoint ticket sets → keep as separate groups (do NOT over-merge across tickets).
@@ -521,7 +521,7 @@ Plan-body verification only supports **lightweight mode** (defined in §"Verific
521
521
  - all dispatches non-result → `aborted-non-result`
522
522
  - any `partial-consensus` / `dissent-isolated` present, no `majority-disagree` → `passed-with-dissent`
523
523
  - all items `full-consensus` → `passed`
524
- 6. Lead writes `runs/<task-type>/state/plan-body-verification-<task-type>-<seq>.json` (schema below) and populates `### 4.5.9 Plan Body Verification` in the final report (template at `templates/reports/final-report.template.md`).
524
+ 6. Lead writes `runs/<task-type>/state/plan-body-verification-<task-type>-<seq>.json` (schema below) and populates `### 4.5.9 Plan Body Verification` in the final report (template at `templates/reports/final-report.template.md`). The §4.5.9 body in the template is split into two tables: a narrow `#### Verdict summary` (`Plan item / Ticket ID / Section / Classification` only — one row per plan item) and a tall `#### Verdict details` (`Plan item / Worker / Verdict / Breakage kind / Note` — one row per plan-item × worker pair). The older wide `| Plan item | <worker1> | <worker2> | … | Classification |` matrix is removed — it scaled horizontally with the worker count and lost readability past 3 workers. Lead MUST emit both tables (the validator's `Plan Body Verification` + `Gate result:` substring checks still pass either layout, but reviewers depend on the split form).
525
525
  7. For every `majority-disagree` item, lead adds a row to `## 5. Clarification Items` with:
526
526
  - new `C-<N>` ID (numbering continues from any existing rows)
527
527
  - `Statement` summarising the disagreement and the worker breakage `<kind>`
@@ -83,7 +83,19 @@ The four steps below MUST execute in this exact order. Reordering them is the re
83
83
  ```
84
84
 
85
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 2Follow-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.
86
+ 3. **Phase 7 step 1.5Render report views** (BLOCKING). Produces two derived artifacts from the now-substituted final-report MD:
87
+
88
+ ```bash
89
+ python3 scripts/okstra-render-report-views.py \
90
+ <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
91
+ ```
92
+
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.
96
+
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
+ 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.
87
99
 
88
100
  ```bash
89
101
  python3 scripts/okstra-spawn-followups.py \
@@ -98,7 +110,7 @@ The four steps below MUST execute in this exact order. Reordering them is the re
98
110
  - Rows with `Auto-spawn? != yes` are reported as `skipped` and never written; surface them in Section 6 if manual action is still needed.
99
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.
100
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.
101
- 4. **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:
113
+ 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:
102
114
 
103
115
  ```
104
116
  - Follow-up: `<task-group>/<new-task-id>` — Claude Code 세션 안 `/okstra-run task-key=<task-group>/<new-task-id> task-type=<suggested>` / 별도 터미널 `scripts/okstra.sh --task-key <task-group>/<new-task-id> --task-type <suggested>`
@@ -117,7 +129,8 @@ The final report follows the structure below. If `instruction-set/final-report-t
117
129
  - Date: <ISO 8601 timestamp>
118
130
  - Task Key: <task-key>
119
131
  - Task Type: <task-type>
120
- - Author: `<Report writer worker if in roster, else Claude lead>`
132
+ - Report Owner: `Claude lead`
133
+ - Report Author: `<Report writer worker if in roster, else Claude lead (release-handoff or recorded-fallback only)>`
121
134
  - Lead model: `<lead-model>`
122
135
  - Preparation Method: Final report authored by Report writer worker (or lead-authored fallback — record the documented dispatch failure reason here when applicable)
123
136
  ```
@@ -185,8 +198,8 @@ When the run's `task-type` is `implementation-planning`, the final report MUST c
185
198
  | 5 | `Dependency` | `### Dependency / Migration Risk (의존성·마이그레이션 위험)` |
186
199
  | 6 | `Validation Checklist` | `### Validation Checklist (검증 체크리스트)` |
187
200
  | 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
188
- | 8 | `User Approval Request` | `### User Approval Request (사용자 승인 요청)` |
189
- | 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 (`validators/validate-run.py` lines 531, 548) checks both substrings. |
201
+ | 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. |
190
203
 
191
204
  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.
192
205
 
@@ -208,7 +221,7 @@ The final-report template `okstra-final-report.template.md` Section 2 already en
208
221
 
209
222
  ### Release-handoff section contract (release-handoff runs only)
210
223
 
211
- When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 4.6 Release Handoff Deliverables` with all seven sub-sections (`4.6.1` Source Verification Report, `4.6.2` Feature Branch & Working-Tree State, `4.6.3` User Selections, `4.6.4` Executed Commands, `4.6.5` Commit List, `4.6.6` Pull Request Outcome, `4.6.7` Routing Recommendation). Every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. H1 choices are `local only`, `push + PR`, or `skip`; release-handoff records existing implementation commits and MUST NOT create new commits. If the user picked `skip` (H1) or `cancel` (H3), keep 4.6.3 populated but leave 4.6.4–4.6.6 explicitly empty per the template's empty-state lines.
224
+ When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 4.6 Release Handoff Deliverables` with all eight sub-sections (`4.6.1` Source Verification Report, `4.6.2` Feature Branch & Working-Tree State, `4.6.3` User Selections, `4.6.4` Executed Commands, `4.6.5` Commit List, `4.6.6` Merge Conflict Probe, `4.6.7` Pull Request Outcome, `4.6.8` Routing Recommendation). Every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. H1 choices are `local only`, `push + PR`, or `skip`; release-handoff records existing implementation commits and MUST NOT create new commits. If the user picked `skip` (H1) or `cancel` (H3), keep 4.6.3 populated but leave 4.6.4–4.6.6 explicitly empty per the template's empty-state lines.
212
225
 
213
226
  **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`).
214
227
 
@@ -232,12 +245,14 @@ Skipping this file because "the real report is in `reports/`" is wrong. Both fil
232
245
 
233
246
  Section numbering follows `templates/reports/final-report.template.md` exactly — that file is the single source of truth. Below is a one-line summary of each section's writer obligation; consult the template for full body structure.
234
247
 
235
- 0. **Clarification Response Carried In** if `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty, walk every `C-*` row of the prior report's `## 5. Clarification Items` table, reconcile each one against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. Legacy `4.5.9 / 5.1 / 5.2` carry-in mapping is documented in the template's Section 0.
248
+ **Verdict Card (top-of-report, mandatory).** Render `## Verdict Card` between the report header and the (conditional) Approval block. Its `Verdict Token` / `Direction` / `Next Step` cells MUST byte-match the corresponding cells in `## 2. Final Verdict` and the first item of `## 6.`. Divergence is `contract-violated`.
249
+
250
+ 0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 5. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub.
236
251
  1. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `okstra-convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- 합의 미달 항목 없음.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
237
252
  2. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
238
253
  3. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
239
254
  4. **Missing Information and Risks** — uncertain / "I don't know" items. `implementation-planning` adds §4.5 (see heading contract below); `release-handoff` adds §4.6.
240
- 5. **Clarification Items** — single unified `C-*` table; column schema, ID convention, and rerun behaviour are owned by `_common-contract.md §Clarification request policy` (8-column SSOT). Never recreate the deprecated `4.5.9 Open Questions` / `5.1` / `5.2` sub-sections.
255
+ 5. **Clarification Items** — single unified `C-*` table; column schema, ID convention, and rerun behaviour are owned by `_common-contract.md §Clarification request policy` (8-column SSOT). The deprecated `4.5.9 Open Questions` / `5.1 추가 자료 요청` / `5.2 사용자 확인 질문` sub-sections are removed; the validator fails reports that reintroduce them.
241
256
  6. **Recommended Next Steps** — prioritized actions. After Phase 7's follow-up spawner runs, append a row per newly created task-key (see "Phase 6 → Phase 7 execution sequence" above).
242
257
  7. **Follow-up Tasks** — auto-spawn-eligible table. Each row drives `okstra-spawn-followups.py`; see template §7 for the row schema.
243
258
 
@@ -276,6 +291,8 @@ Persistence steps that must be performed in Phase 7:
276
291
  - [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
277
292
  - [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
278
293
  - [ ] 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)
279
296
 
280
297
  ### Response after Persistence
281
298
 
@@ -132,19 +132,23 @@ Reading rules:
132
132
  large for one read; if you must page, you MUST cover the entire file
133
133
  before moving on, and you MUST state the page boundaries you used in your
134
134
  Findings section.
135
- - For the carry-in clarification response, read sub-section 0 and every
136
- row of `## 5. Clarification Items` (`C-001`, `C-002`, ...) in full,
135
+ - For the carry-in clarification response, read the conditional
136
+ `## 0. Clarification Response Carried In From Previous Run` section
137
+ (rendered only when carry-in is non-empty) and every row of
138
+ `## 5. Clarification Items` (`C-001`, `C-002`, ...) in full,
137
139
  including rows whose `User input` cell is blank. The fact that you
138
140
  will write your output into a file with a structurally similar
139
141
  section 5 is NOT an excuse to skim — the prior `C-*` rows carry
140
- context you cannot reconstruct from the new run alone. If the prior
141
- report uses the deprecated `4.5.9 Open Questions` / `5.1` / `5.2`
142
- layout with `OQ-*` / `A*` / `Q*` IDs, walk all three blocks the
143
- same way (legacy carry-in transitional rule).
144
- - Before writing any Findings, state in one sentence per file that you
145
- read it end-to-end. Example: "Read task-brief.md end-to-end (147 lines)."
146
- If you cannot truthfully say this for a file, do not produce Findings
147
- record a `tool-failure` in the errors sidecar instead.
142
+ context you cannot reconstruct from the new run alone.
143
+ - Write the Reading Confirmation block to your **audit sidecar** at
144
+ `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md`
145
+ (sibling to the main worker-results file). One short line per input
146
+ file confirming end-to-end reading, e.g. "Read task-brief.md
147
+ end-to-end (147 lines)." Do NOT include a `## 0. Reading Confirmation`
148
+ heading in the main worker-results file the validator now fails
149
+ worker-results that contain one. If you cannot truthfully confirm a
150
+ file end-to-end, record a `tool-failure` in the errors sidecar
151
+ instead of fabricating Findings.
148
152
  - Do not collapse multiple input files into a single mental summary before
149
153
  reading them all individually. Each file has its own canonical role
150
154
  (brief = the user's request, profile = the lead's rules for this phase,
@@ -209,7 +213,7 @@ Terminal statuses that can be recorded for a worker:
209
213
 
210
214
  **Authoritative source.** If other documents (SKILL.md, worker agent definitions) disagree with this section, this section wins.
211
215
 
212
- ### Result Frontmatter (mandatory, precedes Section 0)
216
+ ### Result Frontmatter (mandatory, precedes Section 1)
213
217
 
214
218
  Every worker result file MUST begin with a YAML frontmatter block. The values are sourced from the corresponding fields of the input files' frontmatter (e.g. `analysis-material.md`, `task-brief.md`) — copy them verbatim; do NOT regenerate them. Only `workerId` and `title` are worker-specific.
215
219
 
@@ -256,11 +260,8 @@ The same frontmatter contract applies to the `Report writer worker`'s final-repo
256
260
 
257
261
  A successful worker result must include the following sections in this exact order, beneath the frontmatter block:
258
262
 
259
- 0. **Reading Confirmation** one short line per input file stating that the worker read it end-to-end. Each line takes the form `- Read <file-name> end-to-end (<line-count> lines).`. The enumerated files are audience-scoped they MUST match the recipient's row in the "Audience-scoped enumeration" table above:
260
- - **Claude / Codex / Gemini analysis workers**: `task-brief.md`, `analysis-profile.md`, `analysis-material.md` (if present), `reference-expectations.md`, `clarification-response.md` (if a carry-in was provided). Analysis workers MUST NOT include `final-report-template.md` — it is not in their `[Required reading]` block.
261
- - **Report writer worker (Phase 6)**: all of the above **plus** `final-report-template.md`.
263
+ > **Reading Confirmation lives in the audit sidecar, NOT in the main worker result.** Section 0 is intentionally absent from the main file. The worker writes Reading Confirmation to `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md` per the dispatch-prompt clause above; the validator FAILS any main worker-result file that contains a `## 0. Reading Confirmation` heading. If a file was skipped or only partially read, the worker MUST NOT produce sections 1–5 — instead it records a `tool-failure` in the errors sidecar and stops.
262
264
 
263
- If a file was skipped or only partially read, the worker MUST NOT produce sections 1–5; instead it records a `tool-failure` in the errors sidecar and stops. This section exists specifically to counteract the common failure mode where workers skim long inputs because they share structure with the file the run will eventually write into.
264
265
  1. Findings
265
266
  2. Missing Information or Assumptions
266
267
  3. Safe or Reasonable Areas