okstra 0.179.2 → 0.180.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.
- package/README.md +1 -1
- package/dist/cli-registry.mjs +14 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/incremental-carry.mjs +9 -8
- package/dist/commands/execute/incremental-carry.mjs.map +1 -1
- package/dist/commands/execute/plan-verify.mjs +3 -1
- package/dist/commands/execute/plan-verify.mjs.map +1 -1
- package/dist/commands/report/approval-decision.d.mts +1 -0
- package/dist/commands/report/approval-decision.mjs +21 -0
- package/dist/commands/report/approval-decision.mjs.map +1 -0
- package/dist/commands/report/design-snapshot.d.mts +1 -0
- package/dist/commands/report/design-snapshot.mjs +19 -0
- package/dist/commands/report/design-snapshot.mjs.map +1 -0
- package/docs/architecture/storage-model.md +1 -1
- package/docs/architecture.md +10 -10
- package/docs/cli.md +11 -8
- package/docs/project-structure-overview.md +15 -6
- package/docs/task-process/implementation-planning.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +15 -164
- package/runtime/prompts/launch.template.md +6 -5
- package/runtime/prompts/lead/adapters/cmux.md +1 -1
- package/runtime/prompts/lead/convergence.md +2 -2
- package/runtime/prompts/lead/okstra-lead-contract.md +19 -18
- package/runtime/prompts/lead/plan-body-verification.md +39 -18
- package/runtime/prompts/lead/report-writer.md +64 -423
- package/runtime/prompts/lead/team-contract.md +1 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +5 -4
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_implementation-deliverable.md +1 -1
- package/runtime/prompts/profiles/change-impact-analysis.md +1 -1
- package/runtime/prompts/profiles/error-analysis.md +1 -1
- package/runtime/prompts/profiles/feature-analysis.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +13 -11
- package/runtime/prompts/profiles/improvement-discovery.md +1 -1
- package/runtime/prompts/profiles/project-analysis.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +2 -1
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +1 -1
- package/runtime/python/okstra_ctl/agent_activity.py +23 -3
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +6 -6
- package/runtime/python/okstra_ctl/analysis_packet.py +43 -2
- package/runtime/python/okstra_ctl/approval_decisions.py +327 -0
- package/runtime/python/okstra_ctl/design_snapshot.py +134 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +62 -4
- package/runtime/python/okstra_ctl/dispatch_state.py +29 -4
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +6 -2
- package/runtime/python/okstra_ctl/final_report_schema.py +24 -15
- package/runtime/python/okstra_ctl/incremental_carry.py +128 -16
- package/runtime/python/okstra_ctl/incremental_scope.py +4 -1
- package/runtime/python/okstra_ctl/path_hints.py +12 -0
- package/runtime/python/okstra_ctl/paths.py +12 -0
- package/runtime/python/okstra_ctl/plan_items_cli.py +113 -16
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +2 -1
- package/runtime/python/okstra_ctl/render.py +48 -1
- package/runtime/python/okstra_ctl/render_final_report.py +7 -6
- package/runtime/python/okstra_ctl/report_assembly.py +354 -0
- package/runtime/python/okstra_ctl/report_contract.py +2 -1
- package/runtime/python/okstra_ctl/report_finalize.py +60 -22
- package/runtime/python/okstra_ctl/report_inputs.py +72 -0
- package/runtime/python/okstra_ctl/report_markdown.py +69 -8
- package/runtime/python/okstra_ctl/report_narrative.py +319 -0
- package/runtime/python/okstra_ctl/report_projections.py +265 -0
- package/runtime/python/okstra_ctl/run.py +25 -9
- package/runtime/python/okstra_ctl/schema_excerpt.py +11 -6
- package/runtime/python/okstra_ctl/stage_fix_carry.py +4 -4
- package/runtime/python/okstra_ctl/stage_ledger.py +132 -18
- package/runtime/python/okstra_ctl/stage_map.py +70 -22
- package/runtime/python/okstra_ctl/team.py +1 -1
- package/runtime/python/okstra_ctl/worker_dispatch.py +5 -2
- package/runtime/python/okstra_ctl/worker_prompt_body.py +35 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +31 -3
- package/runtime/schemas/final-report-v3.0.schema.json +10210 -0
- package/runtime/schemas/report-narrative-v3.0.schema.json +30 -0
- package/runtime/templates/report-writer-prompt-preamble.md +15 -21
- package/runtime/templates/reports/html/macros/forms.html +6 -4
- package/runtime/validators/validate-run.py +258 -10
|
@@ -1,180 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: report-writer-worker
|
|
3
|
-
description:
|
|
4
|
-
Use this agent
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Context: okstra has completed Phase 5.5 convergence and is entering Phase 6 with `Report writer worker` in the roster.
|
|
8
|
-
user: "okstra this task bundle"
|
|
9
|
-
assistant: "Phase 6 — dispatching report-writer-worker to author the final report."
|
|
10
|
-
<commentary>The okstra skill dispatches this agent in Phase 6 to write the final-report file.</commentary>
|
|
11
|
-
</example>
|
|
12
|
-
color: purple
|
|
13
|
-
model: inherit
|
|
14
|
-
tools: ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "TodoWrite", "WebFetch", "WebSearch"]
|
|
3
|
+
description: >
|
|
4
|
+
Use this agent in Phase 6 to synthesize the report narrative Markdown from
|
|
5
|
+
settled worker results. It is not an analysis worker and does not publish
|
|
6
|
+
the final report record.
|
|
15
7
|
---
|
|
16
8
|
|
|
17
|
-
|
|
18
|
-
The final prompt's `report-writer` duty contract owns the role boundary,
|
|
19
|
-
required responsibility, and prohibited actions. This file owns only how that
|
|
20
|
-
contract is executed with Claude host tools. Refuse a dispatch whose prompt has
|
|
21
|
-
no adjacent verified invocation metadata. Consume the stored `executionLabel`.
|
|
22
|
-
The final-report `executionRoles[]` set must equal the execution-manifest
|
|
23
|
-
`roleExecutions[]` set.
|
|
24
|
-
|
|
25
|
-
- The `**Report Language:**` header in your dispatch prompt is already
|
|
26
|
-
resolved to `en` or `ko` by the lead. Copy it verbatim into
|
|
27
|
-
`data.json.meta.reportLanguage`. Never write `auto` here.
|
|
28
|
-
- **That header is not the language you write in — you always write English.**
|
|
29
|
-
It names the language the human HTML renders in, and Phase 7 reads it to
|
|
30
|
-
decide whether to dispatch a translator. The data.json is the SSOT every
|
|
31
|
-
later phase, validator and agent reads, so authoring it in anything but
|
|
32
|
-
English splits the record. **Enforced:** `okstra report-finalize` runs
|
|
33
|
-
`report-translate check-source` as its first Phase 7 step and fails the run
|
|
34
|
-
when the data.json's authored prose is not English. You can run that check
|
|
35
|
-
yourself before returning.
|
|
36
|
-
|
|
37
|
-
## Host file procedure
|
|
38
|
-
|
|
39
|
-
Use the assigned `runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json`
|
|
40
|
-
path. Do not invoke the full reading copy renderer.
|
|
41
|
-
|
|
42
|
-
The data.json is the **single source of truth** for two audiences. Phase 7 produces the human HTML (`final-report-<task-type>-<seq>.html`) through the task-specific HTML renderer. The full reading copy is rendered on demand with `okstra render-final-report <data.json>`. HTML is rendered directly from the data.json; it is not a presentation of the Markdown. You do NOT hand-write either derived artifact.
|
|
43
|
-
|
|
44
|
-
If you find yourself thinking "I'll just write the markdown directly" — stop. Write the data.json with your `Write` tool. The full reading copy is rendered on demand.
|
|
45
|
-
|
|
46
|
-
## Worker Result File (MANDATORY)
|
|
47
|
-
|
|
48
|
-
Write the required worker-result record at the lead-registered `**Worker Result Path:**`. Both dispatch adapters include it in `WorkerJob.completion_paths` and refuse `completed` while it is absent. Schema: short YAML frontmatter (`workerId: "report-writer"`, plus the canonical fields copied verbatim from `analysis-material.md` per `team-contract`) followed by:
|
|
49
|
-
|
|
50
|
-
1. The canonical data.json path you wrote (project-relative).
|
|
51
|
-
2. The convergence-state input path from the prompt (project-relative).
|
|
52
|
-
|
|
53
|
-
Keep the data.json contents and analysis-worker result list out of this file: the data.json is the canonical artifact and the analysis results remain prompt inputs. This file is the dispatch-required two-path pointer record.
|
|
54
|
-
|
|
55
|
-
## Heartbeat (BLOCKING)
|
|
56
|
-
|
|
57
|
-
Write the audit sidecar at `**Audit sidecar path:**` before required reading, then append `- PROGRESS: <stage> <ISO-8601-UTC>` at a cadence no longer than five minutes. Use only: `started`, `required-reading-complete`, `synthesis-start`, `data-json-write-start`, `render-start`, and `write-result-start`. When a stage runs longer than that, append `- PROGRESS: in-stage:<stage> <ISO-8601-UTC>` with the same stage names. The Phase 7 validator enforces the first stage, timestamps, cadence, and this allowlist.
|
|
58
|
-
|
|
59
|
-
`data-json-write-start`, `render-start` and `write-result-start` open a stretch whose work is one uninterruptible tool call, so no `in-stage:` line can be appended while it runs. Those three carry a 20-minute budget instead of five. `required-reading-complete` and `synthesis-start` open the tool-free reading and synthesis stretches — the worker cannot append an `in-stage:` line mid-synthesis either — and carry a 15-minute budget. Every other stage keeps the five-minute cadence.
|
|
60
|
-
|
|
61
|
-
## Execution Rules
|
|
62
|
-
|
|
63
|
-
1. Extract the absolute `Project Root` from the lead prompt (look for a line starting with `**Project Root:**` or `Project Root:`). If missing, return:
|
|
64
|
-
`REPORT_WRITER_PROJECT_ROOT_MISSING: absolute Project Root was not provided in the lead prompt`
|
|
65
|
-
|
|
66
|
-
2. Extract the assigned worker prompt history path (`Assigned worker prompt history path:`). If missing, return:
|
|
67
|
-
`REPORT_WRITER_PROMPT_PATH_MISSING: assigned worker prompt history path was not provided`
|
|
68
|
-
- Resolve relative paths against `Project Root` to get an absolute path.
|
|
69
|
-
|
|
70
|
-
3. Extract the assigned `Result Path` (the final-report file path). If missing, return:
|
|
71
|
-
`REPORT_WRITER_RESULT_PATH_MISSING: assigned final-report Result Path was not provided`
|
|
72
|
-
- Resolve relative paths against `Project Root` to get an absolute path.
|
|
73
|
-
|
|
74
|
-
4. Persist the exact worker prompt to the absolute prompt history path before producing any output. Prefer a Bash heredoc (`cat > <path> <<'EOF'`) — on a redispatch the prompt history file already exists, and the `Write` tool then refuses with "File has not been read yet"; the heredoc has no read-before-write constraint. Never use `/tmp/*prompt*.txt` as canonical storage. Create parent directories if missing.
|
|
75
|
-
|
|
76
|
-
5. Anchor all file operations to the absolute `Project Root`. Use absolute paths everywhere — do not rely on inherited cwd, do not `cd`.
|
|
9
|
+
# Report Writer Worker
|
|
77
10
|
|
|
78
|
-
|
|
11
|
+
The final prompt's `report-writer` duty contract and the selected report-writer preamble are authoritative.
|
|
79
12
|
|
|
80
|
-
|
|
13
|
+
Write only the report narrative Markdown at `**Result Path:**`, the pointer at `**Worker Result Path:**`, and the audit sidecar. You must not write or patch `final-report-*.data.json`, the approval decision ledger, activity ledger, team state, convergence state, or design-preparation input.
|
|
81
14
|
|
|
82
|
-
|
|
15
|
+
Read every dispatched input end-to-end. Full context is available to write the plan and explanation; reading an artifact does not grant authority to reproduce or repair its machine metadata.
|
|
83
16
|
|
|
84
|
-
|
|
85
|
-
2. Read every input file the lead enumerated under `## Inputs` (or equivalent heading) end-to-end (single `Read` call with no `offset`/`limit`; page explicitly only when required).
|
|
17
|
+
The analysis packet is the only MCP authority. If its MCP section is absent or says none, do not infer an MCP server from the task brief or another input.
|
|
86
18
|
|
|
87
|
-
|
|
19
|
+
The narrative must not contain `designPreparation`, `designSurfaceCoverage`, `executionStatus`, `executionRoles`, `tokenUsage`, `crossVerification`, `approvalContext`, `clarificationItems`, `agentActivity`, or `planBodyVerification`. Do not invent a future round, gate result, activity identifier, resolution, or usage value.
|
|
88
20
|
|
|
89
|
-
-
|
|
90
|
-
- `<instruction-set>/final-report-template.md` — the full reading copy template. Read it to understand which IDs, routing fields, evidence, task deliverable, and audit blocks appear in the AI artifact; do NOT edit it, and do NOT use it as the human presentation contract.
|
|
91
|
-
- `templates/reports/i18n/en.json` and `templates/reports/i18n/ko.json`.
|
|
92
|
-
- Every analysis worker's result file under `worker-results/`.
|
|
93
|
-
- `state/convergence-<task-type>-<seq>.json` (if present). When present, reproduce its `roundHistory[]`, `round2SkippedReason`, and `finalClassificationCounts` verbatim into the final report's Section 6 Round History sub-table — do not recompute from worker results.
|
|
94
|
-
- `<instruction-set>/task-brief.md` — the brief this run was prepared from. The lead already lists it under `## Inputs`; what it is FOR is the `## Expected Behavior` / `## Preserved Behavior` / `## Expected Outcome` items, whose `EB-NNN` / `PB-NNN` / `EO-NNN` ids are exactly what `endStateCoverage` maps. Read the instruction-set copy, NOT the project's `.okstra/briefs/...` path from the task manifest — that path is not resolvable here, same as the full schema source. A report that omits an id the brief pinned is rejected by the run validator.
|
|
21
|
+
**Implementation-planning direction branch.** A selected-direction narrative carries `selectedDirectionRef` and `directionRealization`; `P-Dir-1` checks that realization against the selected core mechanism, architecture boundaries, planning invariants, and any hidden direction change. A legacy candidate-comparison narrative retains `P-Opt-*` option comparison semantics.
|
|
95
22
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Write a Reading Confirmation block to `**Audit sidecar path:**`, per the selected report-writer preamble's `Required reading` section (the main final-report and worker-results files carry no Section 0 heading). If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating the report.
|
|
99
|
-
|
|
100
|
-
## Authoring Contract
|
|
101
|
-
|
|
102
|
-
You author the final-report data.json (the JSON SSOT). You author it against the `<instruction-set>/final-report-schema.json` excerpt — its `$defs` enumerate every row shape, enum value, and cross-field constraint that applies to this run's task-type. The validator and renderers both consume the **full** `schemas/final-report-v2.0.schema.json` (the excerpt is a faithful task-type-scoped subset of it), so a data.json that satisfies the excerpt can independently produce both audience artifacts.
|
|
103
|
-
|
|
104
|
-
The full reading copy is an agent-facing ledger: verdict, routing, clarification decisions, evidence, one structured task deliverable, and execution audits. The human HTML is the reader-facing explanation: `humanSummary` plus the selected task block's `userNarrative` and structured facts. Populate both human fields in data.json even though the Markdown intentionally omits their full prose. Worker discussion, convergence mechanics, and token usage belong to audit data and must not be copied into the HTML human main body.
|
|
105
|
-
|
|
106
|
-
### Implementation-planning frontmatter contract
|
|
107
|
-
|
|
108
|
-
#### Selected-direction
|
|
109
|
-
|
|
110
|
-
Emit `frontmatter.approved` as `false` and copy `implementationPlanning.selectedDirectionRef.snapshotPath` into `frontmatter.selectedDirectionRef`. You MUST omit `frontmatter.implementationOption`; the direction was selected upstream and cannot be selected again in planning. `schemas/final-report-v2.0.schema.json` enforces the required selected-direction reference and rejects an `implementationOption` property for this branch.
|
|
111
|
-
|
|
112
|
-
#### Legacy candidate-comparison
|
|
113
|
-
|
|
114
|
-
Emit `frontmatter.approved` as `false` and `frontmatter.implementationOption` as the empty string `""`. The user later flips `approved` to `true` and fills `implementationOption` with the chosen Option Candidate name to authorise and scope the next `implementation` run. Every other report type follows the same empty `implementationOption` default; the schema's non-selected-direction branch requires that field and rejects a selected-direction reference.
|
|
115
|
-
|
|
116
|
-
### General authoring rules
|
|
117
|
-
|
|
118
|
-
Rules (the schema enforces most of these — they are listed here so you know *what* to populate, not *how* to validate):
|
|
119
|
-
|
|
120
|
-
- Read the exact permitted header values from the task bundle schema excerpt. In the current v2 contract, `header.reportOwner` is `"Okstra lead"` and `header.reportAuthor` is `"Report writer worker"`. Set author to `"Okstra lead"` only for `release-handoff` runs (single-lead by design) or a recorded report-writer dispatch failure fallback. A legacy v1 excerpt may retain its historical compatibility values; follow that excerpt rather than inferring ownership from the provider.
|
|
121
|
-
- **Source items (worker:item) preservation.** Every `consensus[].sourceItems`, `differences[].workersPosition[].itemId`, and `evidence.primary[].sourceItems` entry MUST carry the worker:item-id pair (e.g. `claude:F-001`, `codex:1.1`, `antigravity:F-3`, or `lead:mcp-1` for lead-only evidence). The schema enforces this via the `SourceItem` regex; bare worker-name lists no longer parse.
|
|
122
|
-
- **Verdict Card consistency.** The Card has no `verdictToken` field: the verdict token is authored once, in `finalVerdict.verdictToken`. `verdictCard.direction` MUST byte-match `finalVerdict.direction`; `validators/validate-run.py` diffs it and fails the run on divergence. `verdictCard.nextStep` names the same action as `finalVerdict.nextStep` and `recommendedNextSteps[0].text` but is written as the actionable command the reader runs (e.g. `/okstra-run task-key=… task-type=release-handoff`) where the other two are prose — it is deliberately not a byte copy.
|
|
123
|
-
- **Error-analysis diagnosis and routing.** When `header.taskType` is `error-analysis`, populate the required `errorAnalysis` object. Copy `errorAnalysis.symptomVerbatim` byte-for-byte from the symptom stated in the brief's `Source Material`; do not paraphrase it. Every `causeCandidates[]` row includes the full `supportingEvidence`, `falsifyingEvidenceChecked`, `confidence`, and `disproveWith` fields. When a candidate is a step in a propagation chain rather than a competing explanation — the analysis calls it a downstream step, a second stage, or a consequence of another candidate — set its `downstreamOf` to the ids of the candidates immediately upstream of it; leave the field absent for a candidate that stands on its own. Every id listed MUST be another candidate in the same report, no row may name itself, and the links MUST NOT form a cycle; `validators/validate-run.py::_validate_cause_chain` rejects all three. This is the only place the chain is machine-readable — prose calling a candidate "the second step of the chain" while `downstreamOf` is absent leaves the report's figure claiming the candidates are alternatives. Route `errorAnalysis.routing.nextTaskType=implementation-option-selection` with `direction=begin-option-selection`, or route `errorAnalysis.routing.nextTaskType=error-analysis` with `direction=continue-investigation`; no other pairing is valid. `verdictCard.nextStep`, `finalVerdict.nextStep`, the first `recommendedNextSteps` action and command, and the unique `followUpTasks` row whose `origin` is `phase-continuation` MUST all point to the same `errorAnalysis.routing.nextTaskType` target. The schema enforces only the presence of a `phase-continuation` row; `validators/validate-run.py::_validate_error_analysis_consistency` enforces exact target agreement and uniqueness.
|
|
124
|
-
- **Implementation-option-selection comparison.** When `header.taskType` is `implementation-option-selection`, populate `implementationOptionSelection` from the converged direction-selection findings. Preserve every merged or rejected raw candidate in `candidateAudit`, and put at most three selectable candidates in `rankedOptions`. Each displayed candidate carries its requirement coverage, scope commitments, criterion scores, feasibility votes, safety blockers, unresolved feasibility facts, planning invariants, and exact coverage summary. In each displayed candidate, `expectedChangeAreas` names direction-level change surfaces, never exact file paths or an exact file list. `expectedVerification` names direction-level verification signals, never a stage list or executable test commands. `schemas/final-report-v2.0.schema.json` enforces the displayed-summary constants and the three-option cap; semantic recalculation belongs to `validators/validate-run.py`.
|
|
125
|
-
- **Implementation-planning direction branch.** For `planningContract: selected-direction`, read `selectedDirectionRef` and its snapshot, then preserve their core mechanism, architecture boundaries, and planning invariants in `directionRealization`. Materialize files, interfaces, stages, validation, rollback, and bidirectional original-requirement links without candidate generation, scoring, recommendation, or user candidate selection. Author exactly one `P-Dir-1` whose payload is the complete `directionRealization`; its verifier checks those preserved properties and any hidden direction change. If the direction must change, author `direction-invalidated` and no execution queue. Legacy candidate-comparison reruns retain Option Candidates, trade-offs, Recommended Option, and `P-Opt-*` semantics.
|
|
23
|
+
**Implementation-option-selection comparison.** Candidate details remain direction-level and must not claim planning precision:
|
|
126
24
|
|
|
127
25
|
```json
|
|
128
|
-
{
|
|
129
|
-
"candidateDetailBoundary": {
|
|
130
|
-
"expectedChangeAreas": "direction-level-only",
|
|
131
|
-
"expectedVerification": "direction-level-signals-only",
|
|
132
|
-
"forbidden": ["exact-file-lists", "stage-lists", "test-commands"]
|
|
133
|
-
}
|
|
134
|
-
}
|
|
26
|
+
{"candidateDetailBoundary":{"expectedChangeAreas":"direction-level-only","expectedVerification":"direction-level-signals-only","forbidden":["exact-file-lists","stage-lists","test-commands"]}}
|
|
135
27
|
```
|
|
136
|
-
- **Human narrative.** Populate required `humanSummary` and the selected task block's `userNarrative`. Human-visible analysis facts must not exist only in Markdown; HTML is derived independently and can use only data.json. Keep worker discussion and audit details in `crossVerification`, `executionStatus`, and `tokenUsage`, outside the human narrative fields.
|
|
137
|
-
- **External QA advisory.** A Tier 3 entry requiring `db`, `http`, or
|
|
138
|
-
`external` may be non-PASS without changing approval or final verdict. Render
|
|
139
|
-
its command log row as `tier: 3`, `status: advisory`, keep the observed and
|
|
140
|
-
expected result in `statusReason`, add a `Residual Risk` row owned by `user`,
|
|
141
|
-
and add the exact rerun command to `recommendedNextSteps`. Never turn this
|
|
142
|
-
advisory alone into a clarification, Acceptance Blocker, conditional
|
|
143
|
-
acceptance condition, or blocked routing.
|
|
144
|
-
- **§7 phase-continuation row (mandatory for non-terminal task-types).** When `header.taskType` is one of `requirements-discovery` / `implementation-option-selection` / `implementation-planning` / `error-analysis` / `implementation` / `final-verification`, `followUpTasks` MUST contain at least one row whose `origin` is `phase-continuation`, `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. The schema `allOf` / `contains` clause enforces row presence, not exact route-target agreement or uniqueness; phase validation must enforce those error-analysis semantics as specified above.
|
|
145
|
-
- **No deprecated sections.** The schema has no `4.5.8 User Approval Request` body field, no `4.5.9 Open Questions`, no `5.1 Additional Material Request`, no `5.2 User Confirmation Questions` — clarifications go under the unified `clarificationItems[]` array.
|
|
146
|
-
- **Optional Section 0.** Include `clarificationCarryIn` ONLY when the lead's prompt provides a non-empty carry-in path. Omit the key entirely otherwise (do NOT set it to `null` or an empty object).
|
|
147
|
-
- **Reading Confirmation** goes at `**Audit sidecar path:**` per the selected report-writer preamble's `Required reading` section — never in the data.json or the main worker-results file.
|
|
148
|
-
- Include all four convergence categories. The schema's `crossVerification.consensus` / `.differences` arrays carry full / partial / contested / worker-unique items; do not omit any.
|
|
149
|
-
- Convergence round history goes in `crossVerification.roundHistory.rounds[]` with `round2SkippedReason`. When convergence is disabled, set `crossVerification.roundHistory` to `{"disabled": true}`. Values come verbatim from `state/convergence-<task-type>-<seq>.json` — do not recompute.
|
|
150
|
-
- `verification-error` votes are their own verdict (`planItems[].verdicts[].verdict` enum); they are NOT folded into AGREE / DISAGREE counts.
|
|
151
|
-
- **Token Usage cells are `null` in Phase 6.** Leave `tokenUsage.lead.totalTokens` / `.billableTokens` / `.costUsd` (and the worker / grand rows, and per-row `executionStatus[].totalTokens` etc.) as JSON `null`. The renderer emits `--` for nulls. Phase 7's `okstra-token-usage.py --substitute-data` populates them and re-renders. **Never** write `0`, `"not-collected"`, `"--"`, or any sentinel value — those are how zeros sneak into the report.
|
|
152
|
-
- If only one analysis worker produced usable output, perform a reduced-confidence write-up and say so explicitly (e.g. note in `executionStatus[].summary`).
|
|
153
|
-
- If evidence is missing, write `"I don't know"` in the relevant statement field rather than fabricating confidence.
|
|
154
|
-
- Cite file paths and line numbers in every `evidence.primary[].source` / `consensus[].evidence` cell.
|
|
155
|
-
- Preserve every analysis worker's ticket tagging — every row's `ticketId` field carries the ticket key or the task-fallback. For single-ticket runs, set `ticketCoverage` to `{"singleTicket": "<ticket>"}`. For runs that do not require ticket tagging (`release-handoff`, `final-verification`), set `ticketCoverage` to `{"omit": true}`.
|
|
156
|
-
- For `requirements-discovery`, `error-analysis`, and `implementation-planning`, populate the top-level `endStateCoverage` with exactly one row per end-state id the brief declares — no more, no fewer. `disposition` is one of `addressed` / `deferred` / `not-applicable` / `blocked`. `addressed` requires a `coveredBy` anchor in THIS phase's own deliverable (requirements-discovery: the routing decision, the fan-out unit id, or the `C-NNN` clarification; error-analysis: the root-cause candidate or the next diagnostic; implementation-planning: the `R-NNN` row); every other disposition requires a `rationale`. Do not author a goal of your own here and do not restate the brief — this table records only how this phase accounted for what the reporter already pinned. When the brief declares no end-state ids (a brief authored before those sections existed), omit the field entirely. **Enforced:** `validators/validate-run.py` `_validate_end_state_coverage`.
|
|
157
|
-
- For selected-direction `implementation-planning`, preserve each original requirement ID and populate its `stageRefs`, `stepRefs`, `validationRefs`, and `fileRefs`; `validate_selected_direction_plan` enforces forward and reverse exact coverage. For legacy candidate-comparison `implementation-planning`, populate `implementationPlanning.requirementCoverage` with one row per concrete requirement from the brief / packet, using IDs `R-001`, `R-002`, ... in source order. A `covered` row's `coveredBy` MUST name the specific Option Candidate plus Stage/Step that satisfies the requirement. Use `status: "covered"` only when the report's plan actually covers it; use `documented-deviation` only when `coveredBy` states the concrete alternative and the row records non-empty unique `decisionRefs` plus `approvalDisposition`. Each `C-NNN` ref must name a clarification in this report; each `D-NNNN` ref must name a `decisionDrafts[].number`. `approvalDisposition: "accepted"` requires a referenced clarification with `status: answered|resolved` and non-empty `userInput`; `approvalDisposition: "blocked C-NNN"` requires that same-report clarification to be `status: open, blocks: approval`. Otherwise use `gap` or `blocked C-NNN` and ensure the corresponding `Clarification Items` row blocks approval. Do not collapse this into `ticketCoverage`; ticket coverage is not requirement coverage. **Enforced:** `schemas/final-report-v2.0.schema.json` `$defs.ImplementationRequirementCoverageRow` and `validators/validate-run.py` `_validate_requirement_deviations`.
|
|
158
|
-
- For legacy candidate-comparison `implementation-planning`, each `requirementCoverage` row's `source` is a graded cell, not prose — free text like `"carry-in from requirements-discovery C-001"` is rejected. Write exactly one of: `brief:EB-001` / `brief:PB-001` / `brief:EO-001`, an end-state id the brief declares — when the brief pins ids, citing a heading instead is rejected, because every brief carries the same generic headings and a heading cannot say WHICH reporter line the requirement came from (only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it); `derived:R-NNN — <one-line reason>`, whose chain must terminate at a `brief:` or `contract:` row of the same table without cycling; or `contract:<rule>`, for artifacts okstra's own phase contract mandates, whose allowlist is exactly the two tokens `decision-record-step` (the §5.4 Decision Drafts materialization step) and `glossary-step` (the glossary proposal step) — any other rule name is rejected, so never invent one. (Maintainer SSOT for that allowlist: `scripts/okstra_ctl/scope_provenance.py` in the okstra repo.) A requirement you cannot source this way does not belong in the table: put it in `clarificationItems[]` with `Blocks=approval`. **Enforced:** `validators/validate-run.py` `_validate_requirement_provenance`. In the same table, anchor every stage number in `coveredBy` to a `Stage` / `Stages` word (`Stage 2`, `Stages 1-3`) — `_validate_stage_has_requirement` reads that cell as prose and fails the plan when a Stage Map stage is cited by no row.
|
|
159
|
-
- For legacy candidate-comparison `implementation-planning`, also populate `implementationPlanning.decisionDrafts` (one row per decision meeting all three decision-record criteria; `[]` otherwise) and `implementationPlanning.skippedAdrCandidates` (evaluated-but-dropped adr-candidates; `[]` otherwise). The schema excerpt enumerates the row shape; the renderer emits §5.4 `### Decision Drafts`. When `decisionDrafts` is non-empty, the plan's stages MUST carry a stepwise step that creates `.okstra/decisions/<NNNN>-<slug>.md` (validate-run gates this).
|
|
160
|
-
- For `implementation-planning`, populate `implementationPlanning.variationPointAnalysis` — a `hasMultipleImplementations` judgement synthesized from the analysis workers' output, not a field filled in last. When it is `true`, write one `points[]` row per varying behavior carrying `behavior`, the two or more `implementations` that serve it, `evidence` (a `path:line`, or the sibling task / stage that already implements that behavior), and an `extractionDecision` of `extract` / `interfaceKind` / `coveredBy` (the Stage Map stage that builds the interface) / `rationale`; when it is `false`, write a non-empty `noVariationRationale` and leave `points` empty (the two branches are mutually exclusive). Do NOT pass a boilerplate rationale. Populate test seams under `implementationPlanning.directionRealization.testSeams` for selected-direction plans and under `implementationPlanning.recommendedOption.testSeams` for legacy candidate-comparison plans. An empty list is a conscious "no seam needed" claim, never a default for a field nobody filled. Every point becomes a `P-Var-*` plan item judged in §5.5.9.
|
|
161
|
-
- When the `Task Type` is `improvement-discovery`, populate `improvementDiscovery.candidates[]`, `improvementDiscovery.lensCoverage[]`, `improvementDiscovery.selectionLimit`, and `improvementDiscovery.userNarrative`. Each candidate carries the 11 logical fields enforced by `validators/validate_improvement_report.py`; each lens-coverage row records candidate IDs or an evidence-backed no-candidate rationale. Source IDs, lens names, and worker prefixes from `scripts/okstra_ctl/improvement_lenses.py`. The standard renderer derives the full reading copy; never author a free-form improvement report.
|
|
162
|
-
|
|
163
|
-
Write the report record, the Worker Result Path pointer, and the separate audit sidecar with your `Write` tool — that is the canonical authoring path. A Bash heredoc is acceptable ONLY when a specific `Write` call is genuinely rejected by the host environment, and it MUST produce byte-identical content — do not reach for it pre-emptively. Do not invoke `okstra render-final-report`; the full reading copy is on-demand. Confirm data.json, the pointer, and the audit sidecar exist before responding with a short status line prefixed by your model identity, per the preamble §"Return message to the lead". **Enforced:** dispatch `completionPaths` requires the record and the pointer; `validators/validate_session_conformance.py` validates the audit sidecar.
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
**Model:** Report writer worker, <modelExecutionValue>
|
|
167
|
-
data.json written to <abs path>. Sections populated: <count>.
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Error reporting
|
|
171
|
-
|
|
172
|
-
Record tool failures through the file selected by `**Worker Error Contract Path:**`. If `**Errors sidecar path:**` is absent, return `REPORT_WRITER_ERRORS_PATH_MISSING` and stop; otherwise use the shared schema and append protocol exactly. This worker has no external CLI.
|
|
173
28
|
|
|
174
|
-
|
|
29
|
+
Use `# OKSTRA Report Narrative`, nested `- **Field**` rows, `- Item N` array entries, and `> value` scalar lines. Do not write JSON, YAML, JSON Pointer, or fenced JSON.
|
|
175
30
|
|
|
176
|
-
|
|
177
|
-
- You do NOT produce independent analysis findings — your input is the analysis workers' results plus convergence output.
|
|
178
|
-
- Do NOT modify analysis worker result files. They are read-only inputs to you.
|
|
179
|
-
- If the analysis workers disagree and convergence ended with `Contested` items, surface them in the final report verbatim — do not silently pick a side.
|
|
180
|
-
- `Contested` is a final-only classification. If you see findings labeled `Contested` in the convergence state, the lead has already exhausted re-verification — do not invent a synthesizing answer; surface each worker's position verbatim.
|
|
31
|
+
Report assembly validates every owner input and publishes the final record once. An assembly error naming another owner must be returned to that owner, not repaired in the narrative.
|
|
@@ -126,19 +126,20 @@ The **default is full re-verification**. Only narrow this re-run to the impacted
|
|
|
126
126
|
--answered-clarifications <csv of answered C-NNN ids, empty when none> \
|
|
127
127
|
--full-reason "<empty, or what structural change forces full>"
|
|
128
128
|
```
|
|
129
|
-
The CLI reads the plan's dependency graph from the
|
|
129
|
+
The CLI reads the plan's dependency graph from the prior `implementationPlanning.stageMap`, which is authoritative for the impacted stage numbers. The CLI prints JSON `{mode, reverify_stages, carry_stages, reason}`. Instruct the report writer to record this decision in its narrative as `implementationPlanning.incrementalDecision`, using camel-case array keys `reverifyStages` and `carryStages`. Final report assembly preserves that writer-owned decision.
|
|
130
130
|
4. **`mode == "full"`** → run the existing full re-verification path unchanged; ignore `reverify_stages` / `carry_stages`.
|
|
131
131
|
5. **`mode == "incremental"`** → scope every worker dispatch prompt to `reverify_stages` only (the downstream closure of the impacted stages). Do NOT re-analyze `carry_stages` — their prior plan-item verdicts are carried forward verbatim (see `prompts/profiles/implementation-planning.md` "Cross-verification mode" and `prompts/lead/convergence.md` "Convergence scope").
|
|
132
|
-
6. **Merge carried-forward verdicts.** In `incremental` mode,
|
|
132
|
+
6. **Merge carried-forward verdicts.** In `incremental` mode, the report writer includes every `carry_stages` stage row unchanged in its narrative. After `okstra plan-items seed --narrative ... --state ...`, the lead runs:
|
|
133
133
|
```
|
|
134
134
|
okstra incremental-carry \
|
|
135
135
|
--prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
|
|
136
|
-
--cur-
|
|
136
|
+
--cur-narrative <this run's report-writer narrative> \
|
|
137
|
+
--state <this run's plan-body-verification state> \
|
|
137
138
|
--prev-seq <prev-seq> \
|
|
138
139
|
--carry-stages <csv from incrementalDecision.carry_stages> \
|
|
139
140
|
--reverify-stages <csv from incrementalDecision.reverify_stages> \
|
|
140
|
-
--out <this run's
|
|
141
|
+
--out-state <this run's plan-body-verification state>
|
|
141
142
|
```
|
|
142
|
-
A non-zero exit
|
|
143
|
+
A non-zero exit means the writer changed or omitted a carried stage, the item set drifted, or the stage scopes conflict. Fall back to **full** and re-verify every stage. The command writes only the convergence-owned plan state. It never patches the writer narrative or final `data.json`. `verdictCard` / `finalVerdict` are never carried.
|
|
143
144
|
|
|
144
145
|
**Carry completeness (BLOCKING).** In incremental mode, this run's `planItems` MUST contain every plan-item id from the re-verified stages, each carried forward with its updated verdict. If re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is NOT local — abandon incremental and re-route to a FULL re-verification. The carry merge only ever ADDS prior items whose id is absent from this run; it cannot distinguish a legitimate deletion from an untouched carry, so it would resurrect a stale verdict.
|
|
@@ -64,7 +64,7 @@ Use the screen to tell "still working" from "stuck", and to see at a glance whic
|
|
|
64
64
|
- **v1 entry**: carries `workerId`, `provider`, `promptPath`, and `workerResultPath`, and must carry none of the v2 identity fields.
|
|
65
65
|
- `resultPath` and `completionPaths` are advisory in both: dispatch derives them from the same rules the roster path uses, so a jobs file cannot disagree with a roster dispatch about which artifact is the result.
|
|
66
66
|
- `workerResultPath` must carry the canonical `-worker-` token (`<role>-worker-<task-type>-<seq>.md`); the audit sidecar name is derived from it by inserting `-audit-` after that token, so a reverify name like `<role>-reverify-r1-<task-type>-<seq>.md` is refused with `worker result path has no canonical -worker- token`. The round belongs in `dispatchKind` and `invocationRef`, not in the artifact name.
|
|
67
|
-
- `role` names the role execution's own role — `verifier` for reverify, `report-writer` for the report writer. It is not a per-round label: `dispatch_state.py` requires the entry's `role` to equal both the role execution's `role` and the duty's role, so a value like `worker-reverify-r<N>` is refused as `jobs file v2 identity does not match role execution authority`. The round lives in `dispatchKind` and in `invocationRef`. The report-writer completion paths include
|
|
67
|
+
- `role` names the role execution's own role — `verifier` for reverify, `report-writer` for the report writer. It is not a per-round label: `dispatch_state.py` requires the entry's `role` to equal both the role execution's `role` and the duty's role, so a value like `worker-reverify-r<N>` is refused as `jobs file v2 identity does not match role execution authority`. The round lives in `dispatchKind` and in `invocationRef`. The report-writer completion paths include its narrative Markdown, worker-result pointer, and audit sidecar; they do not include the Phase 7 report record.
|
|
68
68
|
- After either dispatch, run `okstra team await --project-root <root> --run-manifest <path>` before evaluating terminal status or completion paths.
|
|
69
69
|
|
|
70
70
|
## Completion, cleanup, and resume
|
|
@@ -30,7 +30,7 @@ When this contract says "queue" without qualifier, it means the *verification qu
|
|
|
30
30
|
|
|
31
31
|
An initial pane role `verifier` is still a Phase 4/5 analysis worker; it does not mean Phase 5.5 reverify. Only a queue-scoped dispatch whose prompt/result path carries `-reverify-r<N>-` performs the reverify step described by this contract.
|
|
32
32
|
|
|
33
|
-
The end-to-end artifact lifecycle is worker results → Round 0 grouping → reducer-owned queue → analyser-instance re-verification → optional `okstra convergence apply-critic-gaps` transition → validated terminal state (newly finalized v1.3, or unchanged historical v1.0–v1.2 from `reuse-final`) → report-writer
|
|
33
|
+
The end-to-end artifact lifecycle is worker results → Round 0 grouping → reducer-owned queue → analyser-instance re-verification → optional `okstra convergence apply-critic-gaps` transition → validated terminal state (newly finalized v1.3, or unchanged historical v1.0–v1.2 from `reuse-final`) → report-writer narrative → deterministic report assembly. Cross-verification is queue-scoped: it does not mean that one worker reviews another worker's complete result. The reducer asks independent analyser instances to vote only on non-consensus findings selected by the persisted plan; the report writer never votes.
|
|
34
34
|
|
|
35
35
|
Initial and reverify worker prompts carry `**Audit sidecar path:**`. Initial workers write their reading confirmation there; reverify workers use their own canonical sidecar for the reverify session without reopening the initial worker's full reading packet.
|
|
36
36
|
|
|
@@ -71,7 +71,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
|
|
|
71
71
|
|
|
72
72
|
**Convergence scope.** Convergence operates on sections 1–5 of the worker output (the common core, see the worker preamble §"Worker output sections"). Section 6 ("Specialization Lens") is additive worker-specific depth and MUST NOT be fed into the consensus grouping, the verification queue, or the round-N reverify prompts. Carry Section 6 forward into the final report verbatim through the report-writer worker — do not let it inflate `unique` counts or trigger spurious `verification-error` statuses.
|
|
73
73
|
|
|
74
|
-
**Incremental re-verification scope (implementation-planning clarification re-runs).** When the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), only findings the lead attributes to a stage in `reverify_stages` enter the verification queue. Findings and plan-item verdicts carried forward for `carry_stages` are NOT re-queued
|
|
74
|
+
**Incremental re-verification scope (implementation-planning clarification re-runs).** When the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), only findings the lead attributes to a stage in `reverify_stages` enter the verification queue. Findings and plan-item verdicts carried forward for `carry_stages` are NOT re-queued. The report writer preserves those stage rows in its narrative, and `okstra incremental-carry` verifies that they are unchanged before copying their prior verdicts into the convergence-owned plan state. When the decision is `mode == "full"` (the default), every finding enters the queue as usual.
|
|
75
75
|
|
|
76
76
|
1. In the "Findings" section of each worker's results, identify individual items by number (F-001, F-002, ...) and parse the ticket identifier attached to each item:
|
|
77
77
|
- For table-form findings, read the `Ticket ID` column.
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The lead orchestrates the selected AI workers against a prepared task bundle, collects their independent outputs, supervises convergence, and ensures the final report is produced. When `Report writer worker` is in the selected roster, that worker authors the
|
|
5
|
+
The lead orchestrates the selected AI workers against a prepared task bundle, collects their independent outputs, supervises convergence, and ensures the final report is produced. When `Report writer worker` is in the selected roster, that worker authors the report narrative Markdown; report assembly publishes the final record from role-owned inputs. The lead never substitutes its own reasoning for a worker result and never bypasses a rostered report writer.
|
|
6
|
+
|
|
7
|
+
The lead owns the approval decision ledger and writes it only through `okstra approval-decision`. The activity recorder owns the activity ledger. Runtime adapters own team state and usage. The convergence engine owns convergence state and the completed plan-body result. The design-surface detector owns the design-preparation snapshot. Report assembly validates these inputs and publishes `final-report-*.data.json` once; a failure is returned to the owner named in its diagnostic.
|
|
6
8
|
|
|
7
9
|
## When to Use
|
|
8
10
|
|
|
@@ -44,10 +46,10 @@ Read-side inspection (`/okstra-inspect`) and scheduling (`/okstra-schedule-gen`)
|
|
|
44
46
|
|
|
45
47
|
## Core operating contract
|
|
46
48
|
|
|
47
|
-
- The `leader` owns orchestration, convergence supervision, and final-report review
|
|
49
|
+
- The `leader` owns orchestration, convergence supervision, and final-report review. It does not author the report narrative or assembled record when `Report writer worker` is in the roster. `lead` is a compatibility alias for `leader` and must not be written on new artifacts.
|
|
48
50
|
- Dispatch consumes stored role executions, not provider-named worker IDs. Canonical roles are `leader`, `analyser`, `critic`, `designer`, `planner`, `implementer`, `verifier`, `report-writer`, and `translator`. `executor` is a compatibility alias for `implementer`.
|
|
49
51
|
- Pane titles and operational rows use the stored `executionLabel`. Do not rebuild that label from a provider name or model string.
|
|
50
|
-
- `report-writer`, when in the roster, is the
|
|
52
|
+
- `report-writer`, when in the roster, is the sole author of the report narrative. Lead reviews the draft and may request a revision through a follow-up dispatch, but MUST NOT edit that narrative or the assembled `data.json`. Contract v3 has no lead-authored fallback; a failed writer dispatch is retried or leaves the run blocked. Historical v2 reports may still carry `header.leadAuthoredFallback`, but no new run writes it.
|
|
51
53
|
- "Session resume", "team is no longer alive", and similar are NOT valid reasons to skip Report writer worker dispatch — see [report-writer](./report-writer.md) "Resume-safe dispatch".
|
|
52
54
|
- A shell command the lead runs must not be able to ask a question. The lead's shell is the user's own, where `cp`, `mv`, and `rm` are commonly aliased to their `-i` form; the confirmation that alias raises has nobody to answer it, so the call hangs until it is killed — observed as a `cp` over an existing state file stalling a whole self-fix round. Invoke these as `command cp` / `command mv` / `command rm`, which skips alias expansion and leaves the tool's own behaviour untouched. `-f` is not a substitute: it changes what the tool does on failure (`rm -f` reports success on a path that never existed).
|
|
53
55
|
- If the brief is incomplete, continue with explicit uncertainty markers rather than fabricating confidence.
|
|
@@ -136,7 +138,7 @@ The sequence is fixed:
|
|
|
136
138
|
3. On an answer — record the raw text in the row's `userInput`, set `status: answered` and `userConfirmation: asked-and-answered`, and apply the selected disposition in this run.
|
|
137
139
|
4. Only when asking fails does the row stay open: `asked-awaiting` when the user has not answered, `deferred-no-interactive-session` when this run has no user to ask.
|
|
138
140
|
|
|
139
|
-
For
|
|
141
|
+
For report contract v3 `implementation-planning`, record active approval decisions only through `okstra approval-decision`; report assembly derives each report row's status, resolution, and backtraces from that lead-owned ledger plus the activity ledger. Classify a user-owned selection as `user-decision`, a surviving non-correctness majority disagreement as `noncritical-dissent`, and a cited path/symbol mismatch, `P-Req-*` coverage mismatch, or independent Requirement Coverage blocker as `correctness-critical`. `select` is limited to `user-decision`, `accept-risk` is limited to `noncritical-dissent`, and `request-revision` / `reject` are available to all three classifications. `correctness-critical` never offers or records `accept-risk`. Contract v2 remains read-only compatible; do not create a new v2 report. **Enforced:** `scripts/okstra_ctl/approval_decisions.py` rejects invalid option/disposition combinations, and `validators/validate-run.py` `_validate_v3_approval_context` recomputes report backtraces.
|
|
140
142
|
|
|
141
143
|
The approval state transitions are fixed:
|
|
142
144
|
|
|
@@ -147,7 +149,7 @@ The approval state transitions are fixed:
|
|
|
147
149
|
|
|
148
150
|
`open` and `answered` continue to block approval; only `resolved` and `obsolete` are non-blocking. `user-decision` resolves after the choice is applied and structure / extraction / Requirement Coverage checks pass. `noncritical-dissent` resolves only after an explicit `accept-risk` with non-empty user text and activity-backed checks. `correctness-critical` resolves only after the correction's targeted re-verification records `AGREE` or an acceptable `SUPPLEMENT` for every linked item and no independent coverage blocker remains. A user-directed correction does not consume the automatic self-fix limit, and a verification failure after that correction does not restart the automatic loop.
|
|
149
151
|
|
|
150
|
-
When a terminal row preserves a pre-correction dissent classification, keep
|
|
152
|
+
When a terminal row preserves a pre-correction dissent classification, keep superseded votes in `state/plan-body-verification-implementation-planning-<seq>.json`. Activities that implement or check the decision record the exact `C-NNN` in `clarificationRefs` and the affected `P-*` identifiers in `planItemIds`. Report assembly verifies that every resolution `checkRefs` value names an existing activity and derives each plan item's `clarificationRefs`; the lead never copies those references into `approvalContext`. A corrected coverage-only blocker keeps its `C-NNN` in the non-blocking Requirement Coverage row's `decisionRefs`. An `obsolete` row is invalid while its disagreement or coverage blocker remains active in the current plan. **Enforced:** `scripts/okstra_ctl/report_assembly.py` `_clarification_row` / `_attach_plan_backlinks` and `validators/validate-run.py` `_validate_v3_approval_context`.
|
|
151
153
|
|
|
152
154
|
**Predicting the blocker is not the same as raising it.** A lead that says "this will likely become an approval blocker; I will ask at that point" has already reached the moment — ask then, in that message. One run announced exactly that, never asked, wrote the row anyway, and then spent its entire self-fix budget on a gate no round could clear, because the user had already answered the question before the run started.
|
|
153
155
|
|
|
@@ -346,11 +348,11 @@ If convergence is disabled, `seed`/`finalize` produce the auto-disabled final st
|
|
|
346
348
|
|
|
347
349
|
## Phase 6: Final report assembly
|
|
348
350
|
|
|
349
|
-
**REQUIRED RESOURCE:** Read [report-writer](./report-writer.md) for report
|
|
351
|
+
**REQUIRED RESOURCE:** Read [report-writer](./report-writer.md) for report ownership, dispatch, assembly, and Phase 7 rules.
|
|
350
352
|
|
|
351
353
|
### Authoring ownership (BLOCKING)
|
|
352
354
|
|
|
353
|
-
If `Report writer worker` is in the selected roster (`recommendedWorkers` / `resultContract.requiredWorkerRoles`),
|
|
355
|
+
If `Report writer worker` is in the selected roster (`recommendedWorkers` / `resultContract.requiredWorkerRoles`), Lead dispatches it to author only `report-writer-narrative-<task-type>-<seq>.md`, its worker-result pointer, and its audit sidecar. The worker may read the complete run context but cannot write `final-report-*.data.json` or another role's ledger. After every required input exists, Phase 7 runs report assembly, which validates the role-owned inputs and atomically publishes the report record once. Phase 7 then renders the human HTML from that record. Contract v2 artifacts remain readable but no new run writes them. **Enforced:** report-writer dispatch completion paths in `scripts/okstra_ctl/dispatch_state.py`, granted artifacts in `scripts/okstra_ctl/dispatch_core.py`, and `scripts/okstra_ctl/report_assembly.py` `assemble_report`.
|
|
354
356
|
|
|
355
357
|
Before constructing the dispatch prompt, the lead MUST:
|
|
356
358
|
|
|
@@ -360,7 +362,8 @@ Before constructing the dispatch prompt, the lead MUST:
|
|
|
360
362
|
based on its main prose language (default `en` when the brief is
|
|
361
363
|
mostly code/identifiers). Pass the final `en` or `ko` value as
|
|
362
364
|
`**Report Language:**` in the report-writer dispatch prompt, and ensure
|
|
363
|
-
|
|
365
|
+
report assembly writes the same value into `data.json.meta.reportLanguage`
|
|
366
|
+
from the immutable run manifest.
|
|
364
367
|
|
|
365
368
|
The convergence output provides four finding categories:
|
|
366
369
|
|
|
@@ -375,7 +378,7 @@ If only one worker result is usable: reduced-confidence synthesis. If evidence i
|
|
|
375
378
|
|
|
376
379
|
### Phase 6 sub-step: Plan-body verification (implementation-planning only, BLOCKING)
|
|
377
380
|
|
|
378
|
-
After the Report writer worker
|
|
381
|
+
After the Report writer worker narrative is reviewed, **if** `task_type == "implementation-planning"` **and** `task-manifest.json` `convergence.planBodyVerification.enabled == true` (default), the lead MUST run the plan-body verification sequence on the consolidated plan body before declaring Phase 6 complete and entering Phase 7.
|
|
379
382
|
|
|
380
383
|
This is a Phase 6 sub-step — it does NOT introduce a new top-level lifecycle phase; the lead operating-phase model (Phase 1 Intake → Phase 7 Persist, labels in the "Quick Reference" table above as the single source of truth) is preserved. The round's outcome is read from the final report's `### 5.5.9 Plan Body Verification` section and `implementationPlanning.planBodyVerification` in its data.json — it is not a separate lifecycle phase identifier.
|
|
381
384
|
|
|
@@ -391,7 +394,7 @@ Lead's responsibilities in this sub-step (in order):
|
|
|
391
394
|
|
|
392
395
|
For a new `implementation-planning` run, the fixed order is initial verification → one planner self-fix → targeted re-verification → user gate. The initial verification is round 1 and the targeted re-verification is round 2. A second automatic self-fix is a contract violation.
|
|
393
396
|
|
|
394
|
-
1. Build the queue with `okstra plan-items extract --
|
|
397
|
+
1. Build the queue with `okstra plan-items extract --narrative <report-writer-narrative.md> --output <state>/plan-items-....json`, place the persisted `items[]` verbatim in every verifier prompt, then run `okstra plan-items validate --narrative <report-writer-narrative.md> --items <state>/plan-items-....json`. The lead MUST NOT summarise, select, omit, reorder, or renumber the queue. Each prompt uses the compact `subject` plus the lossless `payload`, and asks every item:
|
|
395
398
|
|
|
396
399
|
```text
|
|
397
400
|
What concrete false-positive input, failure ordering, or omitted dependency
|
|
@@ -401,23 +404,21 @@ For a new `implementation-planning` run, the fixed order is initial verification
|
|
|
401
404
|
An `AGREE` response records the considered counterexample and exclusion reason in its note; unverified external material is `verification-error`, not `DISAGREE`.
|
|
402
405
|
2. Dispatch a single plan-body reverify round to every analyser worker in the roster (`claude`, `codex`, and `antigravity` when opted in). `Report writer worker` is NOT a participant in this round.
|
|
403
406
|
3. Aggregate verdicts and resolve the gate result to one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`.
|
|
404
|
-
4. Write `runs/<task-type>/state/plan-body-verification
|
|
405
|
-
5.
|
|
406
|
-
6.
|
|
407
|
+
4. Write `runs/<task-type>/state/plan-body-verification-<task-type>-<seq>.json`, appending each round to `roundHistory[]` and updating its nested `planBodyVerification` final projection. This state belongs to convergence and is the only plan-verification input report assembly reads.
|
|
408
|
+
5. Record every surviving `majority-disagree` decision through `okstra approval-decision`; record its plan and clarification links only on activities. Do not append `clarificationItems[]` directly.
|
|
409
|
+
6. Run report assembly after the final plan-body state, approval ledger, design snapshot, activity ledger, and team state are complete. Assembly writes `implementationPlanning.planBodyVerification` and derived clarification rows while publishing `data.json` once.
|
|
407
410
|
7. Publish the report record `frontmatter.approved` field as `false`. There is no in-body `- [ ] Approved` marker line — approval lives only in the record (see [plan-body-verification](./plan-body-verification.md) §"Round protocol" step 9). The user may set it to `true` (via `--approve` or the in-session wizard) only when the gate is `passed` or `passed-with-dissent`. **Enforced:** `validators/validate-run.py` `validate_phase_boundary` fails a report shipping `approved: true` under `blocked-by-disagreement` / `aborted-non-result`, and run-prep (`scripts/okstra_ctl/run.py` `_validate_approved_plan`) fail-closes the same case. Manually flipping a blocked gate to passing is a contract violation.
|
|
408
411
|
|
|
409
412
|
If `convergence.planBodyVerification.enabled == false` (set by `--no-plan-verification` or by `okstra config set plan-verification off`), the entire sub-step is skipped and the top-of-report Approval marker is rendered unconditionally (legacy behaviour). This opt-out is intended for fast iteration only and is not recommended for handoff-ready plans.
|
|
410
413
|
|
|
411
414
|
## Phase 7: Artifact persistence and validator handoff
|
|
412
415
|
|
|
413
|
-
The detailed persistence
|
|
416
|
+
The detailed persistence sequence lives in [report-writer](./report-writer.md). Drive it through `okstra report-finalize`; do not patch any final-report field manually.
|
|
414
417
|
|
|
415
418
|
Order of operations:
|
|
416
419
|
|
|
417
|
-
1. Run `okstra
|
|
418
|
-
2.
|
|
419
|
-
3. When `meta.reportLanguage` is not `en`, dispatch the translator worker. The worker builds its work list with `okstra report-translate extract`, writes `final-report-<task-type>-<seq>.i18n.<lang>.json`, and gates it with `okstra report-translate check`.
|
|
420
|
-
4. Run `okstra report-finalize ...`. This command owns token substitution, view rendering, follow-up persistence, and validation in their contractual order.
|
|
420
|
+
1. Run `okstra report-finalize ...`. Contract v3 collects usage, assembles the role-owned inputs into `data.json` once, checks the source, renders views, persists follow-ups, validates the run, and performs eligible teardown in order.
|
|
421
|
+
2. When `meta.reportLanguage` is not `en`, first run only `token-usage`, `project-activity`, and `check-source`. Dispatch the translator against that assembled record, then resume with only `render-views`, `spawn-followups`, `validate-run`, and `teardown-stages` so assembly is not repeated.
|
|
421
422
|
|
|
422
423
|
Keep the assigned worker prompt history paths stable in `team-state`, `run-manifest`, and `task-manifest`. Do not rewrite prompt artifacts to `/tmp` or omit prompt metadata for attempted workers.
|
|
423
424
|
|