okstra 0.127.0 → 0.129.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/docs/architecture/storage-model.md +23 -3
- package/docs/architecture.md +28 -1
- package/docs/cli.md +9 -0
- package/docs/project-structure-overview.md +17 -7
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +3 -3
- package/runtime/agents/workers/claude-worker.md +4 -4
- package/runtime/agents/workers/codex-worker.md +3 -3
- package/runtime/agents/workers/report-writer-worker.md +5 -5
- package/runtime/prompts/lead/adapters/claude-code.md +2 -1
- package/runtime/prompts/lead/adapters/codex.md +1 -0
- package/runtime/prompts/lead/adapters/external.md +1 -0
- package/runtime/prompts/lead/convergence.md +45 -83
- package/runtime/prompts/lead/okstra-lead-contract.md +12 -8
- package/runtime/prompts/lead/report-writer.md +3 -2
- package/runtime/prompts/lead/team-contract.md +19 -9
- package/runtime/prompts/profiles/_common-contract.md +1 -1
- package/runtime/prompts/profiles/error-analysis.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +10 -6
- package/runtime/prompts/profiles/implementation-planning.md +5 -0
- package/runtime/prompts/profiles/improvement-discovery.md +11 -1
- package/runtime/prompts/profiles/requirements-discovery.md +8 -1
- package/runtime/python/okstra_ctl/analysis_packet.py +14 -15
- package/runtime/python/okstra_ctl/codex_dispatch.py +51 -80
- package/runtime/python/okstra_ctl/context_cost.py +82 -7
- package/runtime/python/okstra_ctl/convergence.py +223 -0
- package/runtime/python/okstra_ctl/convergence_engine.py +1152 -0
- package/runtime/python/okstra_ctl/convergence_migration.py +184 -0
- package/runtime/python/okstra_ctl/convergence_store.py +85 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +60 -1
- package/runtime/python/okstra_ctl/improvement_assignment.py +61 -0
- package/runtime/python/okstra_ctl/log_report.py +44 -5
- package/runtime/python/okstra_ctl/path_hints.py +28 -1
- package/runtime/python/okstra_ctl/paths.py +10 -1
- package/runtime/python/okstra_ctl/render.py +78 -11
- package/runtime/python/okstra_ctl/run.py +66 -2
- package/runtime/python/okstra_ctl/wizard.py +15 -4
- package/runtime/python/okstra_ctl/work_categories.py +37 -0
- package/runtime/python/okstra_ctl/worker_prompt_body.py +107 -0
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +316 -0
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +109 -10
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +158 -0
- package/runtime/templates/implementation-worker-preamble.md +51 -0
- package/runtime/templates/operating-standard.md +4 -4
- package/runtime/templates/report-writer-prompt-preamble.md +37 -0
- package/runtime/templates/worker-error-contract.md +46 -0
- package/runtime/templates/worker-prompt-preamble.md +28 -227
- package/runtime/validators/lib/fixtures.sh +27 -12
- package/runtime/validators/validate-run.py +228 -45
- package/src/cli-registry.mjs +7 -0
- package/src/commands/execute/convergence.mjs +34 -0
- package/src/commands/inspect/log-report.mjs +5 -3
|
@@ -28,6 +28,8 @@ This contract governs **Phase 5.5 (Convergence loop)** — a *lead operating pha
|
|
|
28
28
|
|
|
29
29
|
When this contract says "queue" without qualifier, it means the *verification queue*: the set of findings that are still candidates for re-verification in subsequent rounds. The queue shrinks monotonically as findings get classified as `full-consensus`, `partial-consensus`, or `worker-unique`. Findings classified into any of these three categories MUST NOT appear in any subsequent round's reverify prompt, for any worker.
|
|
30
30
|
|
|
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
|
+
|
|
31
33
|
## When to Use
|
|
32
34
|
|
|
33
35
|
- When okstra lead Phase 5.5 (convergence loop) begins — immediately after all workers complete Phases 4 and 5
|
|
@@ -74,92 +76,48 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
|
|
|
74
76
|
- Items tagged `unknown` keep the literal `unknown` as their ticket key.
|
|
75
77
|
2. For each finding, record the summary, evidence (file path, line number, basis), the discovering worker, **the worker-internal item ID that worker assigned** (e.g. `F-001`, `1.1`, `F-3` — see `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT), and the parsed ticket set. Persist the item ID as `findings[].discoveredBy.<worker>.itemId` and each cross-worker confirmation as `findings[].sourceItems[]` (one entry per contributing `<worker>:<item-id>` pair). The final-report `## 6.1 Consensus` / `## 6.2 Differences` / `## 2.1 Primary Evidence` tables read this verbatim into their `Source items` columns; without it the synthesised `C-NNN` row loses its link back to the original worker wording.
|
|
76
78
|
3. The lead groups findings based on semantic similarity AND ticket-set equality:
|
|
77
|
-
- Same semantics + same ticket set across 2+ workers →
|
|
78
|
-
- Same semantics but disjoint ticket sets →
|
|
79
|
-
- Only one worker confirms a finding →
|
|
80
|
-
4. When grouping is ambiguous, prefer splitting over merging (avoid over-merging).
|
|
81
|
-
5.
|
|
82
|
-
6.
|
|
79
|
+
- Same semantics + same ticket set across 2+ workers → one multi-source group.
|
|
80
|
+
- Same semantics but disjoint ticket sets → separate groups (do NOT over-merge across tickets).
|
|
81
|
+
- Only one worker confirms a finding → one single-source group.
|
|
82
|
+
4. When grouping is ambiguous, prefer splitting over merging (avoid over-merging). Semantic matching, ticket-set equality, and evidence interpretation remain lead judgments; the engine does not perform fuzzy matching or decide whether evidence is credible.
|
|
83
|
+
5. Write `runs/<task-type>/state/convergence-groups-<task-type>-<seq>.json`. Each group carries its `ticketIds`, `originWorker`, `originEvidence`, `discoveredBy`, and every `<worker>:<item-id>` source in `sourceItems`. Include the resolved worker roster in order with functional `audience` values; do not derive scope from provider or model identity.
|
|
84
|
+
6. Do not write a queue or classification in this grouped-input artifact. `okstra convergence seed` deterministically marks multi-source groups `full-consensus` and puts only single-source groups in the working queue. Section 6 never enters the grouped input.
|
|
83
85
|
|
|
84
86
|
### Round 1-N: Re-verification Loop (queue-pruned)
|
|
85
87
|
|
|
86
|
-
The
|
|
88
|
+
The `ConvergenceEngine` reducer owns the working queue, classification strategy, pruning, round arithmetic, gate precedence, skip reason, final state, and classification counts. The lead owns only semantic grouping plus translation of observed worker outcomes into the structured round-results schema. Runtime adapters transport persisted batches and terminal outcomes only.
|
|
89
|
+
|
|
90
|
+
Working artifacts are stored beside the final state:
|
|
87
91
|
|
|
88
92
|
```text
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
IF roundIndex > 1 AND NOT round_gate_open(queue, roundHistory[-1].dispatches):
|
|
95
|
-
record round2SkippedReason in convergence state
|
|
96
|
-
BREAK
|
|
97
|
-
|
|
98
|
-
inputQueueSize = len(queue)
|
|
99
|
-
dispatches = []
|
|
100
|
-
skippedWorkers = []
|
|
101
|
-
|
|
102
|
-
FOR each analysis worker W (excluding report-writer-worker):
|
|
103
|
-
items_for_W = [f for f in queue if W != f.originWorker]
|
|
104
|
-
IF items_for_W is empty:
|
|
105
|
-
skippedWorkers.append({worker: W, reason: "no items to verify"})
|
|
106
|
-
CONTINUE
|
|
107
|
-
dispatch = send_reverify_request(W, items_for_W, roundIndex)
|
|
108
|
-
dispatches.append(dispatch)
|
|
109
|
-
|
|
110
|
-
IF len(dispatches) > 0 AND all dispatches in this round are terminal non-result (timeout/error/no-result-file):
|
|
111
|
-
# Per "Worker failure handling in reverify" below — do NOT treat as DISAGREE.
|
|
112
|
-
record verification-error evidence on each finding in the queue for this round
|
|
113
|
-
record round2SkippedReason = "all-reverify-non-result" for any subsequent round
|
|
114
|
-
BREAK
|
|
115
|
-
|
|
116
|
-
resolvedCount = 0
|
|
117
|
-
carriedForwardCount = 0
|
|
118
|
-
|
|
119
|
-
FOR each finding F in queue (snapshot):
|
|
120
|
-
votes = aggregate_votes(F, dispatches) # AGREE / DISAGREE / SUPPLEMENT / verification-error
|
|
121
|
-
IF all non-error votes are AGREE or SUPPLEMENT:
|
|
122
|
-
F.classification = "full-consensus"
|
|
123
|
-
queue.remove(F); resolvedCount += 1
|
|
124
|
-
ELIF majority non-error votes are AGREE or SUPPLEMENT:
|
|
125
|
-
F.classification = "partial-consensus"
|
|
126
|
-
queue.remove(F); resolvedCount += 1
|
|
127
|
-
ELIF all non-error votes are DISAGREE:
|
|
128
|
-
F.classification = "worker-unique"
|
|
129
|
-
queue.remove(F); resolvedCount += 1
|
|
130
|
-
ELSE:
|
|
131
|
-
# mixed / insufficient non-error votes, or all-error votes → carry forward
|
|
132
|
-
carriedForwardCount += 1
|
|
133
|
-
|
|
134
|
-
record roundHistory entry { round: roundIndex, inputQueueSize, resolvedCount,
|
|
135
|
-
carriedForwardCount, dispatches, skippedWorkers }
|
|
136
|
-
|
|
137
|
-
# Final classification — runs after the WHILE loop exits (queue empty OR roundIndex == effectiveMaxRounds OR Round 2 gate closed)
|
|
138
|
-
FOR each finding F still in queue:
|
|
139
|
-
IF config.adversarial AND F was carried forward by the adversarial round
|
|
140
|
-
resolution (a surviving `counter-evidence` refute, or a burden-not-met
|
|
141
|
-
majority — see §"Adversarial Verification Mode"):
|
|
142
|
-
F.classification = "contested" # one evidence-backed refute denies consensus, whatever the AGREE tally
|
|
143
|
-
ELIF majority AGREE-or-SUPPLEMENT across all executed rounds:
|
|
144
|
-
F.classification = "partial-consensus"
|
|
145
|
-
ELSE:
|
|
146
|
-
F.classification = "contested"
|
|
93
|
+
convergence-groups-<task-type>-<seq>.json
|
|
94
|
+
convergence-work-<task-type>-<seq>.json
|
|
95
|
+
convergence-round-<N>-plan-<task-type>-<seq>.json
|
|
96
|
+
convergence-round-<N>-results-<task-type>-<seq>.json
|
|
97
|
+
convergence-<task-type>-<seq>.json
|
|
147
98
|
```
|
|
148
99
|
|
|
149
|
-
|
|
100
|
+
Follow this protocol exactly:
|
|
150
101
|
|
|
151
|
-
|
|
102
|
+
1. Run `okstra convergence seed --groups <groups> --work-state <work> --final-state <final> --migration-dir <state/migrations>`. A `reuse-final` action means validate the existing final and continue to Phase 6. `create-work`, `resume-work`, and `restart-round0` continue with planning.
|
|
103
|
+
2. Run `okstra convergence plan-round --work-state <work> --plan <round-plan>`. This is read-only with respect to the working state.
|
|
104
|
+
3. When the plan action is `dispatch`, create exactly one reverify prompt for each `dispatches[]` row and dispatch it through the selected runtime adapter. Its findings are exactly that row's `findingIds`.
|
|
105
|
+
4. Convert parsed verdicts and every terminal dispatch outcome into `convergence-round-<N>-results-<task-type>-<seq>.json`; then run `okstra convergence apply-round --work-state <work> --plan <round-plan> --results <round-results>`.
|
|
106
|
+
5. Repeat `plan-round` and `apply-round` until the plan action is `finalize`.
|
|
107
|
+
6. Run `okstra convergence finalize --work-state <work> --output <final>`.
|
|
108
|
+
7. Run `okstra convergence validate --state <final> --kind final`. Only this validated final schema-v1.2 artifact is delivered to the report-writer, which does not vote.
|
|
152
109
|
|
|
153
|
-
|
|
110
|
+
The planner preserves roster and queue order, excludes that finding's origin worker, emits at most one batch per analysis worker per round, and ensures the report-writer never appears in `dispatches` or `skippedWorkers`. Queue pruning is monotonic: a finding absent from the current queue cannot reappear in a later plan.
|
|
154
111
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| `len(queue) > 0` after round 1 | true | `"queue-empty"` |
|
|
112
|
+
After `seed`, the lead MUST NOT hand-edit queue IDs, classifications, `roundHistory` arithmetic, `round2SkippedReason`, `finalState`, `totalRounds`, or `finalClassificationCounts`. The persisted plan is the assignment audit record; adapters and leads may not recalculate it. `scripts/okstra_ctl/convergence_engine.py` and `okstra convergence validate` enforce these rules.
|
|
113
|
+
|
|
114
|
+
#### Resume and legacy-state recovery (BLOCKING)
|
|
159
115
|
|
|
160
|
-
|
|
116
|
+
A valid terminal legacy final is reused unchanged. A malformed, unreadable, or partial legacy final is archived byte-for-byte under `state/migrations/` and restarted from Round 0 because its queue provenance cannot be reconstructed. A matching valid working state resumes. A malformed new-engine working state fails closed and names the explicit `--restart-from-round0` recovery flag; when supplied, every invalid existing state is archived before replacement. The final path can be replaced only when its recorded migration archive still matches the original bytes.
|
|
161
117
|
|
|
162
|
-
|
|
118
|
+
#### Engine-owned Round 2 gate
|
|
119
|
+
|
|
120
|
+
`plan-round` applies gate precedence in one place: auto-disabled, all reverify non-result, effective maximum of one, empty queue, then maximum rounds reached. `finalize` maps that internal reason to the public `round2SkippedReason` and `finalState`. The lead and adapters never reproduce this predicate.
|
|
163
121
|
|
|
164
122
|
#### Worker failure handling in reverify (BLOCKING)
|
|
165
123
|
|
|
@@ -167,17 +125,17 @@ A reverify dispatch that returns a **terminal non-result** (`timeout`, `error`,
|
|
|
167
125
|
|
|
168
126
|
Rules:
|
|
169
127
|
|
|
170
|
-
1. For each
|
|
128
|
+
1. For each failed dispatch, put its actual terminal status and duration in the round-results `dispatches[]`; do not invent a vote. `okstra convergence apply-round` appends `votes[W].verdict = "verification-error"` with the terminal reason for every affected finding.
|
|
171
129
|
2. Record one event per failed dispatch via `okstra error-log append-observed --error-type cli-failure --agent <worker> ...` (the worker wrapper does this for wrapper failures; for in-process worker timeouts the lead does it).
|
|
172
|
-
3.
|
|
173
|
-
4. If at least one dispatch was issued
|
|
130
|
+
3. `apply-round` adds the worker to the persisted round's `skippedWorkers[]` with `{worker: <W>, reason: "dispatch-non-result", terminalStatus: <timeout|error|not-run>}`.
|
|
131
|
+
4. If at least one dispatch was issued and every dispatch terminates as non-result, `apply-round` records the `all-reverify-non-result` stop state. The next `plan-round` returns `action: "finalize"`; record one `contract-violation` event per non-result dispatch.
|
|
174
132
|
5. Section 6 (Specialization Lens) of a worker output is OUT of convergence scope per "Convergence scope" above — its absence is NEVER a `verification-error`.
|
|
175
133
|
|
|
176
|
-
The
|
|
134
|
+
The engine's classifiers treat `verification-error` as "no usable vote" — it counts neither toward AGREE nor toward DISAGREE.
|
|
177
135
|
|
|
178
136
|
### Convergence Test
|
|
179
137
|
|
|
180
|
-
The
|
|
138
|
+
The executable source is `scripts/okstra_ctl/convergence_engine.py`; `okstra convergence validate --kind final` replays its persisted-state invariants. This document defines orchestration and semantic boundaries, not a second implementation of the reducer.
|
|
181
139
|
|
|
182
140
|
## Verification Mode
|
|
183
141
|
|
|
@@ -247,7 +205,9 @@ Design intent: one `counter-evidence` refute denies a claim consensus (it cannot
|
|
|
247
205
|
|
|
248
206
|
### Sponsorship Optimization
|
|
249
207
|
|
|
250
|
-
For each
|
|
208
|
+
For each persisted round plan, build exactly one prompt per `dispatches[]` row and call `redispatch_worker(assignment, prompt, reason)` once through the selected runtime adapter. The prompt contains exactly that row's `findingIds` in plan order and MUST NOT add, remove, or reorder findings. This excludes Section 6, every resolved finding, and every finding owned by the receiving origin worker because none can appear in the engine row. The assignment, model, prompt path, Result Path, worker-results path, errors paths, and `dispatchKind` come from the current run artifacts. Every reverify is a fresh one-shot session.
|
|
209
|
+
|
|
210
|
+
The persisted round plan is the audit record for batch membership. The lead and adapter do not branch on task type, provider, model identity, classification labels, or their own view of the queue. They dispatch only the engine-returned row through the selected runtime adapter.
|
|
251
211
|
|
|
252
212
|
Call `await_workers(handles)` through the same adapter and apply the shared terminal-status/completion-path contract before counting a vote. The selected adapter owns native invocation spelling and any jobs-file/CLI fields. This contract owns only the reverify payload and verdict semantics.
|
|
253
213
|
|
|
@@ -288,6 +248,8 @@ If none of the three is available, **abort the reverify dispatch for that role**
|
|
|
288
248
|
|
|
289
249
|
Reverify prompts MUST NOT inject the Phase 2 `[Required reading]` clause:
|
|
290
250
|
|
|
251
|
+
Lightweight reverify does not require the original `analysis-packet.md`, `analysis-profile.md`, `task-brief.md`, or instruction set. Its complete input is the receiving worker's current engine-planned `findingIds` batch and the evidence embedded in those findings.
|
|
252
|
+
|
|
291
253
|
- **Lightweight mode**: the clause directly contradicts the "Do NOT re-analyze the original source materials" instruction below. Including it forces workers to re-read the entire instruction-set per round per worker (3 workers × 2 rounds × 5+ files in the worst case) for no quality gain.
|
|
292
254
|
- **Full-reanalysis mode**: workers DO need to re-read source materials, but only the analysis-worker file list (no `final-report-template.md`). If lead chooses to inject a reading clause here, it MUST mirror the audience-scoped enumeration in [okstra-lead-contract](./okstra-lead-contract.md) Phase 2 (no template).
|
|
293
255
|
|
|
@@ -496,9 +458,9 @@ Schema rules:
|
|
|
496
458
|
- `roundHistory[].carriedForwardCount`: queue size at the END of this round — the single definition. In-round insertions into the queue are forbidden, so this always equals `inputQueueSize - resolvedCount`. The pseudocode's per-item `carriedForwardCount += 1` accumulator is a counting convenience that lands on the same value; persist the post-round queue length, not the loop accumulator, if the two ever diverge.
|
|
497
459
|
- `roundHistory[].dispatches[]`: one entry per worker that was actually dispatched in this round. Each entry is `{worker, status, durationMs}`. `status ∈ {completed, timeout, error, not-run}`. `durationMs` is integer milliseconds and is always present, even for terminal-non-result dispatches (use the elapsed time before the wrapper gave up).
|
|
498
460
|
- `roundHistory[].skippedWorkers[]`: per-worker `{worker, reason}` for workers with no items to verify OR with a non-result dispatch.
|
|
499
|
-
- `round2SkippedReason`: literal enum `queue-empty | max-rounds-1 | all-reverify-non-result | not-skipped | auto-disabled`. Always present
|
|
461
|
+
- `round2SkippedReason`: literal enum `queue-empty | max-rounds-1 | all-reverify-non-result | not-skipped | auto-disabled`. Always present and derived by `finalize`; the engine owns precedence so the lead never writes it manually.
|
|
500
462
|
- `finalClassificationCounts`: post-loop counts. Required field with keys `fullConsensus`, `partialConsensus`, `contested`, `workerUnique`.
|
|
501
|
-
- `finalState ∈ {converged, max-rounds-reached, aborted-non-result}`.
|
|
463
|
+
- `finalState ∈ {converged, max-rounds-reached, aborted-non-result}`. Derived by `finalize` from the validated queue, history, and stop reason; the lead does not assign it.
|
|
502
464
|
- `totalRounds`: count of rounds actually executed (not `effectiveMaxRounds`). May be `0` when Round 0 produced no queue items (all findings reached consensus during grouping).
|
|
503
465
|
|
|
504
466
|
## Coverage critic pass
|
|
@@ -571,7 +533,7 @@ Critic output lives in the run's `worker-results/` directory (`runs/final-verifi
|
|
|
571
533
|
|
|
572
534
|
Information to be passed to Phase 6 after completing this contract:
|
|
573
535
|
|
|
574
|
-
-
|
|
536
|
+
- Validated final schema-v1.2 artifact containing the four-category classification of all findings; the report-writer consumes it and does not vote
|
|
575
537
|
- Round history and votes per worker for each finding
|
|
576
538
|
- Path to the convergence state artifact
|
|
577
539
|
- Convergence summary (count per category)
|
|
@@ -47,7 +47,7 @@ Read-side inspection (`/okstra-inspect`) and scheduling (`/okstra-schedule-gen`)
|
|
|
47
47
|
| 3. Dispatch setup | Execute the selected adapter's pre-dispatch setup and record its state | selected runtime adapter + this contract |
|
|
48
48
|
| 4. Execution | Call `dispatch_worker` once per selected assignment | selected runtime adapter + `team-contract` |
|
|
49
49
|
| 5. Completion wait | Call `await_workers` and verify terminal state plus required artifacts | selected runtime adapter + `team-contract` |
|
|
50
|
-
| 5.5 Convergence |
|
|
50
|
+
| 5.5 Convergence | Semantically group findings, then drive deterministic state transitions through `ConvergenceEngine` via `okstra convergence` | `convergence` |
|
|
51
51
|
| 5.6 Critic pass | (opt-in) fresh one-shot critic pass through `redispatch_worker`: coverage gaps (discovery/error-analysis/impl-planning) or acceptance devil's-advocate (final-verification). The critic dispatch fires concurrently with the first 5.5 reverify round (its input is fixed at Round 0); gap/blocker verification (one round) completes here | `convergence` "Coverage critic pass" / "Acceptance critic pass" |
|
|
52
52
|
| 6. Synthesis | Dispatch Report writer worker, review draft. **For `implementation-planning`: then run the Phase 6 plan-body verification sub-step (see Phase 6 section below).** | `report-writer` + `plan-body-verification` (sub-step) |
|
|
53
53
|
| 7. Persist | Call `collect_usage`, update manifests, run the cleanup approval gate, then call `shutdown_workers` only on approval | selected runtime adapter + `report-writer` + this contract |
|
|
@@ -208,6 +208,10 @@ These phases are governed by [team-contract](./team-contract.md). It is the cano
|
|
|
208
208
|
- Worker output contract (sections 1–5 + optional Section 6; the Reading Confirmation block lives in the audit sidecar, never in the worker-results file — the preamble "Reading rules" section is canonical and the validator rejects violations), header standard, terminal statuses, errors-sidecar schema.
|
|
209
209
|
- Token-usage tracking conventions.
|
|
210
210
|
|
|
211
|
+
For `final-verification`, Lead persists initial analysis prompts with one shared semantic body. Any genuine run delta appears under exactly one `## Run-specific directive` heading and applies to every selected analysis worker; Lead never shards verification requirements by worker, provider, or model. If the shared directive would exceed 40 nonblank lines, Lead writes it into the instruction set and adds the same reference to `analysis-packet.md` before dispatch. Phase 7 validates the persisted initial analysis prompts through the shared prompt contract before the run can pass.
|
|
212
|
+
|
|
213
|
+
For `improvement-discovery`, Lead records `## Primary Pass Assignments` in the Phase 1.5 grilling log before worker prompt generation. Enumerate selected analyser worker instances in run-manifest `requiredWorkerRoles` order and rotate them over the resolved lenses in log order; provider and model names never determine assignment position. Every analyser still inspects every resolved lens. Phase 7 recomputes this rotation from the persisted roster and fails a missing, extra, duplicate, out-of-order, or out-of-scope assignment.
|
|
214
|
+
|
|
211
215
|
`Report writer worker` is NOT an analysis worker. Do not dispatch it in Phase 4/5 alongside analysis workers. It is invoked only in Phase 6 — see [report-writer](./report-writer.md).
|
|
212
216
|
|
|
213
217
|
### Phase 3 — Runtime adapter setup (BLOCKING)
|
|
@@ -280,15 +284,15 @@ Convergence is enabled by default. Configure via task-manifest.json:
|
|
|
280
284
|
- `convergence.verificationMode`: `"lightweight"` | `"full-reanalysis"` (default: `"lightweight"`; the adversarial phases below force `"full-reanalysis"`)
|
|
281
285
|
- `convergence.adversarial`: true/false — **phase-aware default**: `true` for `requirements-discovery` / `error-analysis` / `implementation-planning`, `false` otherwise. When `true`, Phase 5.5 runs in adversarial mode (verifiers refute findings; burden of proof on the claim). See [convergence](./convergence.md) "Adversarial Verification Mode".
|
|
282
286
|
|
|
283
|
-
When `task-manifest.json` does not set `convergence.maxRounds`, lead MUST resolve the effective value via the phase-aware default above before entering Phase 5.5
|
|
287
|
+
When `task-manifest.json` does not set `convergence.maxRounds`, lead MUST resolve the effective value via the phase-aware default above before entering Phase 5.5 and put it in the grouped input at `config.effectiveMaxRounds`.
|
|
284
288
|
|
|
285
|
-
|
|
289
|
+
The lead judges semantic similarity, ticket-set equality, and evidence. After writing the grouped input, it drives `okstra convergence seed → plan-round → apply-round → finalize → validate` and MUST NOT calculate queue membership, classification, history arithmetic, skip reasons, final state, or counts itself. `ConvergenceEngine` owns all of those deterministic transitions.
|
|
286
290
|
|
|
287
|
-
|
|
291
|
+
For every dispatch plan, create only the worker batches returned by the engine and send them through the selected adapter. Confirmed findings cannot reappear because queue pruning is engine-owned and monotonic. Reverify terminal failures are structured outcomes for `apply-round`, never lead-authored `DISAGREE` votes.
|
|
288
292
|
|
|
289
293
|
If any re-verification batch yields a `verification-error` terminal status, or a worker result fails the contract, Lead MUST record one event per violation via `okstra error-log append-observed --error-type contract-violation --agent <offending-agent> ...`. For an internally detected violation without a specific worker, use the selected adapter's lead-role event identity.
|
|
290
294
|
|
|
291
|
-
If convergence is disabled,
|
|
295
|
+
If convergence is disabled, `seed`/`finalize` produce the auto-disabled final state and Phase 6 uses the raw worker results for synthesis.
|
|
292
296
|
|
|
293
297
|
## Phase 6: Final report assembly
|
|
294
298
|
|
|
@@ -401,10 +405,10 @@ After persistence, reply briefly in the resolved Report Language with: completio
|
|
|
401
405
|
| Selecting a generic worker assignment for Report writer worker | Use the rostered `report-writer-worker` assignment; the selected adapter owns its native field mapping |
|
|
402
406
|
| Including `final-report-template.md` in analysis worker `[Required reading]` | Template belongs only in the report-writer prompt — see [team-contract](./team-contract.md) audience-scoped enumeration |
|
|
403
407
|
| Injecting `[Required reading]` into lightweight reverify prompts | Lightweight reverify forbids re-reading source materials — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression" |
|
|
404
|
-
| Letting `convergence.maxRounds` default to 2 for `requirements-discovery` | Resolve effective default to `1` for discovery and
|
|
408
|
+
| Letting `convergence.maxRounds` default to 2 for `requirements-discovery` | Resolve effective default to `1` for discovery and put it in the grouped input |
|
|
405
409
|
| Issuing serial Read calls in Phase 1 | The intake files are independent — issue all Read calls in a single message (parallel) |
|
|
406
410
|
| Flagging an adapter-shortened dispatch prompt as "incomplete" because it omits host-loaded material | The Worker Preamble pointer and core inputs remain mandatory; the selected adapter may omit duplicate host-loaded definitions |
|
|
407
411
|
| Waiting silently after `dispatch_worker` returns without a completed worker artifact | A dispatch acknowledgement is not completion — call `await_workers` and enforce the selected adapter's liveness policy |
|
|
408
|
-
| Re-sending
|
|
409
|
-
| Aggregating a `timeout`/`error` reverify dispatch as `DISAGREE` |
|
|
412
|
+
| Re-sending a finding absent from the persisted round plan | Dispatch exactly the engine-returned `findingIds`; see [convergence](./convergence.md) "Re-verification Dispatch" |
|
|
413
|
+
| Aggregating a `timeout`/`error` reverify dispatch as `DISAGREE` | Put the terminal outcome in round results; `apply-round` records `verification-error`. See [convergence](./convergence.md) "Worker failure handling in reverify" |
|
|
410
414
|
| Skipping `--substitute-data` in the Phase 7 collector run | Always pass the flag — see [report-writer](./report-writer.md) "Phase 7 token-usage collector" |
|
|
@@ -37,8 +37,9 @@ The prompt MUST include, in this order at the top:
|
|
|
37
37
|
3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.data.json` — canonical JSON SSOT. The renderer produces the sibling `.md` automatically.
|
|
38
38
|
4. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — mandatory validator-checked worker-results audit file
|
|
39
39
|
5. `Assigned worker prompt history path: <absolute-path>`
|
|
40
|
-
6. The
|
|
41
|
-
- `**Worker Preamble Path:** <absolute-path>` —
|
|
40
|
+
6. The four BLOCKING dispatch anchor headers generated from the report-writer audience (the worker cannot synthesize any of these paths):
|
|
41
|
+
- `**Worker Preamble Path:** <absolute-path>` — selects `templates/report-writer-prompt-preamble.md`.
|
|
42
|
+
- `**Worker Error Contract Path:** <absolute-path>` — selects `templates/worker-error-contract.md`.
|
|
42
43
|
- `**Errors log path:** <absolute-path>` — run-level errors JSONL (`logs/errors-<task-type>-<seq>.jsonl`).
|
|
43
44
|
- `**Errors sidecar path:** <absolute-path>` — this worker's per-run sidecar JSON (`worker-results/report-writer-worker-errors-<task-type>-<seq>.json`).
|
|
44
45
|
7. `**Model:** Report writer worker, <modelExecutionValue>` (resolved per Phase 5.5 anchor-header rules)
|
|
@@ -27,6 +27,8 @@ Okstra tasks use one lead plus the exact worker assignments selected in the prep
|
|
|
27
27
|
|
|
28
28
|
**Dispatch-prompt invariant.** Lead's dispatch prompt body for Claude / Codex / Antigravity workers MUST be byte-identical except for the role label and any wrapper-specific path headers (e.g. `**Worktree:**`, `**Errors sidecar path:**`). Lead MUST NOT bias the brief by inserting per-worker emphasis sentences ("you focus on X") into the body. Bias-by-prompt reproduces the historical failure mode where Claude commented only on assumptions, Codex only on code paths, and Antigravity only on requirements — leaving convergence with nothing to converge on.
|
|
29
29
|
|
|
30
|
+
Disjoint initial scopes are invalid triangulation. Every selected analysis worker owns the same common verification requirements; provider diversity supplies independent observations, not separate coverage slices. Do not shard the common scope by worker, provider, or model. Worker-specific depth belongs only in the non-voting Specialization Lens after the shared analysis is complete.
|
|
31
|
+
|
|
30
32
|
### Model Assignment Rules
|
|
31
33
|
|
|
32
34
|
1. `resultContract.requiredWorkerRoles` in `task-manifest.json` (and the lead model metadata) is the canonical source. There is no role-level fallback — a missing assignment is a manifest defect, not a license to invent one.
|
|
@@ -63,7 +65,15 @@ Only workers selected from `recommendedWorkers` in `task-manifest.json` and `res
|
|
|
63
65
|
|
|
64
66
|
Every worker prompt MUST start with the anchor headers rendered by `okstra_ctl.worker_prompt_headers.worker_prompt_headers()` (the generating SSOT — never hand-author or reorder them). Their meaning and extraction rules for workers are documented in the worker preamble §"Anchor headers". Phase-specific extra headers (implementation worktree, final-verification target snapshot, improvement-discovery grilling log) are listed there too.
|
|
65
67
|
|
|
66
|
-
The
|
|
68
|
+
The `**Coding preflight pack:**` anchor is emitted only for the `implementation-executor` and `implementation-verifier` audiences. An implementation report-writer never receives it. A pane display role named `verifier` during `final-verification` is still an initial analysis worker; it neither receives implementation conventions nor becomes a Phase 5.5 reverify dispatch. Reverify is identified by the `-reverify-r<N>-` prompt/result path contract in [convergence](./convergence.md).
|
|
69
|
+
|
|
70
|
+
For `improvement-discovery`, `worker_prompt_headers()` resolves and validates the Phase 1.5 grilling log before dispatch and emits its absolute path as `**Phase 1.5 Grilling Log:**`. The lead does not hand-author or guess that path.
|
|
71
|
+
|
|
72
|
+
The body must include: role name, task type, task key, assigned model, output contract, evidence handling rules, and `analysis-packet.md` as the single primary analysis input. For `final-verification`, the compact target anchors and that packet path are sufficient; do not copy the full diff stat, source/fallback path inventory, profile sections, report-output sections, or lead self-review into the initial prompt.
|
|
73
|
+
|
|
74
|
+
A `final-verification` prompt may contain exactly one optional `## Run-specific directive` section for a true run delta. It is limited to 40 nonblank lines; the nonblank prompt body excluding common/target anchors is limited to 96 lines. Larger shared material belongs in the instruction set and analysis packet. Before initial dispatch, the selected adapter validates each prompt and requires byte-identical normalized analysis bodies after removing only worker/model/role and worker-specific artifact-path metadata.
|
|
75
|
+
|
|
76
|
+
The Phase 7 run validator enforces the same cross-task rule against the persisted prompt paths recorded by the run manifest, dispatch records, and team-state. Both dispatch adapters and `validators/validate-run.py` call `okstra_ctl.worker_prompt_contract.validate_initial_prompt_records()`. The validator resolves each record through `PromptPlan`, applies audience-specific anchors, compares every equality group with at least two prompts, validates report-writer common anchors without adding it to an analysis group, and ignores `-reverify-r<N>-` prompts because they belong to the lightweight convergence protocol. A dispatch-time bypass therefore remains a run-level contract violation.
|
|
67
77
|
|
|
68
78
|
When a worker reads any project-relative path from the prompt, it MUST resolve it against `Project Root` (e.g. `<Project Root>/<Result Path>`) — never use bare relative paths that depend on cwd.
|
|
69
79
|
|
|
@@ -73,20 +83,20 @@ Persist the exact worker prompt before dispatch per Operating Rule 6; never use
|
|
|
73
83
|
|
|
74
84
|
Send byte-identical dispatch prompts to every analysis worker per the "Dispatch-prompt invariant" (Role Definitions). Specialization lives in Section 6 of the worker output, not in the dispatch prompt body.
|
|
75
85
|
|
|
76
|
-
###
|
|
86
|
+
### Audience preambles + shared error contract (SSOT)
|
|
77
87
|
|
|
78
|
-
The lead does
|
|
88
|
+
The lead does not inline reading or error blocks. It resolves `PromptPlan.audience` and injects exactly one `**Worker Preamble Path:**`: analysis → `templates/worker-prompt-preamble.md`, implementation executor/verifier → `templates/implementation-worker-preamble.md`, report-writer → `templates/report-writer-prompt-preamble.md`. Every initial worker also receives `**Worker Error Contract Path:**` pointing to `templates/worker-error-contract.md`, the sole owner of error schema and write rules. Reverify prompts use neither preamble.
|
|
79
89
|
|
|
80
90
|
What the lead MUST still do per dispatch:
|
|
81
|
-
- Inject the input file enumeration into the dispatch prompt body via an `## Inputs` section (or any heading the recipient agent expects), listing the actual project-relative primary inputs derived from the run's `instruction-set/`. For analysis workers, list `analysis-packet.md` as the
|
|
82
|
-
- Inject the absolute `**Errors log path:**` and `**Errors sidecar path:**`
|
|
91
|
+
- Inject the input file enumeration into the dispatch prompt body via an `## Inputs` section (or any heading the recipient agent expects), listing the actual project-relative primary inputs derived from the run's `instruction-set/`. For `final-verification` analysis workers, list only `analysis-packet.md` as the primary input; source files are reached on demand through that packet. Other phases may list source/fallback paths when useful. The preamble describes the rules; the lead provides the specific paths for THIS run.
|
|
92
|
+
- Inject `**Worker Error Contract Path:**` plus the absolute `**Errors log path:**` and `**Errors sidecar path:**` headers — workers cannot synthesize these paths.
|
|
83
93
|
- Omit the preamble pointer for reverify dispatches (Phase 5.5 lightweight mode) — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression".
|
|
84
94
|
|
|
85
95
|
Audience-scoped file enumeration (performance optimization — mandatory):
|
|
86
96
|
|
|
87
97
|
| Recipient | Files the lead lists under `## Inputs` |
|
|
88
98
|
|---|---|
|
|
89
|
-
| Claude / Codex / Antigravity analysis workers | `analysis-packet.md` as primary input; source/fallback
|
|
99
|
+
| Claude / Codex / Antigravity analysis workers | `analysis-packet.md` as primary input; for `final-verification`, no source/fallback list is copied into the prompt |
|
|
90
100
|
| Report writer worker (Phase 6) | task-brief, analysis-profile, analysis-material, reference-expectations, clarification-response (if carry-in), **plus** the instruction-set-local `final-report-template.md` (phase-stripped) and `final-report-schema.json` (per-task-type excerpt) — NOT the full `templates/reports/...` / `schemas/...` sources |
|
|
91
101
|
| Reverify dispatches | none — the lead provides only the items to reverify |
|
|
92
102
|
|
|
@@ -141,7 +151,7 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
|
|
|
141
151
|
|
|
142
152
|
## Worker Output Contract
|
|
143
153
|
|
|
144
|
-
The canonical worker output contract —
|
|
154
|
+
The canonical analysis-worker output contract — frontmatter, sections 1–5 plus optional Section 6, item IDs, and ticket tagging — lives in `templates/worker-prompt-preamble.md`. Implementation output behavior remains in its executor/verifier sidecars; report authoring remains in the report-writer preamble and Phase 6 contract.
|
|
145
155
|
|
|
146
156
|
Lead-facing duties that stay here:
|
|
147
157
|
|
|
@@ -215,8 +225,8 @@ without proceeding.
|
|
|
215
225
|
2. Re-verification workers follow a constrained response format (verdict + brief explanation).
|
|
216
226
|
3. Workers cannot vote on their own findings (only verify other workers’ work).
|
|
217
227
|
4. The `report writer worker` does not participate in re-verification voting. It is responsible only for generating the final report.
|
|
218
|
-
5. Division of labor: the lead performs **finding-to-finding matching** (
|
|
219
|
-
6. Batch processing is performed with one spawn per worker
|
|
228
|
+
5. Division of labor: the lead performs **finding-to-finding matching** (semantic similarity plus ticket-set equality); workers cast AGREE / DISAGREE / SUPPLEMENT verdicts; `ConvergenceEngine` owns queue membership, classifications, round arithmetic, pruning, skip reasons, and final counts. The lead does not vote or hand-edit engine state.
|
|
229
|
+
6. Batch processing is performed with one fresh spawn per persisted `plan-round` worker row (not one spawn per finding). The selected adapter transports that exact batch and terminal result without changing membership.
|
|
220
230
|
7. These rules do not apply if Convergence is disabled.
|
|
221
231
|
|
|
222
232
|
## Re-verification Terminal Statuses
|
|
@@ -75,7 +75,7 @@ profile document.
|
|
|
75
75
|
- **Worker-side item IDs (free-form but unique within the worker).** Every row item in sections 1–5 (and any optional section 6) of an analysis worker's output MUST carry an item ID that is unique within that one worker's result file. The ID convention is the worker's choice — `F-001` / `F-002` per the suggested schema, `1.1` / `1.2` / `1.3` as Codex tends to use, or any other shape — but it MUST appear as the leading column of the row (for table-form items) or as a `[<ID>]` prefix (for bullet/numbered items). Workers that emit findings without IDs make cross-worker reconciliation impossible.
|
|
76
76
|
- **Lead-side ID assignment + source preservation.** When the lead (or `report-writer-worker`) synthesises `## 6.1 Consensus` / `## 6.2 Differences` / `## 2.1 Primary Evidence` rows from worker outputs, the lead assigns a fresh `C-NNN` / `D-NNN` / `E-NNN` row ID. The `Source items` column (or, where the template still calls it `Supporting workers` / `Workers (position)` / `Source`, that same column) MUST list every contributing worker:item pair (e.g. `claude:F-001, codex:1.1, antigravity:F-3`) so a reviewer can trace the synthesised row back to each worker's original wording without re-reading every worker-results file. Bare worker names without item IDs (e.g. `claude, codex, antigravity`) are deprecated for these tables; the validator does not yet fail on them but the readability pass treats it as a contract violation.
|
|
77
77
|
- **Why this matters.** A real run had `claude=F-1..F-11`, `codex=1.1..1.8`, `antigravity=F-3..F-9` — three incompatible ID schemes. When the lead synthesised `C-1..C-8`, the link from `C-3` back to "which sentence in which worker file" was lost. Source-item preservation restores that link without forcing every worker to adopt a single ID prefix, which would over-constrain worker output style.
|
|
78
|
-
- Audit sidecar (shared): Reading Confirmation placement
|
|
78
|
+
- Audit sidecar (shared): Reading Confirmation placement follows the audience-selected preamble named by `**Worker Preamble Path:**`. Profiles do not restate it; the main worker-results body starts at section 1.
|
|
79
79
|
|
|
80
80
|
- Markdown authoring (shared — applies to markdown documents not already governed by an okstra template/schema):
|
|
81
81
|
- ad-hoc markdown documents should begin with an `Index` section. Template-governed artifacts such as final-reports, worker-results, and briefs follow their own schema first.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- read `Related Task Graph` before forming root-cause candidates. `depends-on`, `blocks` / `blocked-by`, parent/child, follow-up, and split edges define upstream/downstream boundaries for the symptom: identify whether this task's failure is caused by, blocks, or merely relates to another task before merging causes.
|
|
15
15
|
- any `intent-inference` augmentation that re-characterises the symptom (e.g. classifying a vague reporter phrase like "it sometimes doesn't work" as "intermittent failure on a specific code path") is a **hypothesis**, not a confirmed symptom. If `[CONFIRMED …]` appears on the matching `intent-check:` row, treat that confirmation as the symptom. Otherwise follow the precondition's `skipped` branch above and keep the inference labelled as a hypothesis in the root-cause analysis.
|
|
16
16
|
- `conversion-block:` rows mean the brief could not map a reporter statement to project vocabulary; never invent the missing mapping in this phase.
|
|
17
|
-
-
|
|
17
|
+
- Worker diagnosis procedure:
|
|
18
18
|
- **Symptom lock:** state the reporter's symptom verbatim, then translate it into one observable failure condition. If no observable condition can be derived from the brief, record that gap as the first blocker instead of guessing.
|
|
19
19
|
- **Reproduction status:** classify the run as `reproduced`, `not-reproduced`, or `blocked-before-repro`. Cite the command/log/file evidence used. If no command can be run safely in this phase, explain the read-only evidence path and the exact material needed next.
|
|
20
20
|
- **Falsifiable cause candidates:** every root-cause candidate must include supporting evidence, the strongest falsifying evidence checked, confidence, and the next diagnostic action that would disprove it. A candidate that cannot be falsified is too vague for this phase.
|
|
@@ -29,18 +29,22 @@
|
|
|
29
29
|
- **whole-task is a mutating phase, not a read-only one.** On entry, whole-task mode auto-merges (with `--no-ff`) the done stages not yet merged into the task branch to create an integration commit, then removes the cleanupable stage worktrees, registry stage-keys, and stage branches. If a merge conflict occurs it reports the conflicting files and aborts (the user resolves them manually and retries). A stage worktree with uncommitted changes remaining is preserved. Therefore the "fully-merged, clean target" the entry gate above refers to is the state after this auto-integration step completes, and whole-task final-verification must be treated as a mutating phase that creates the integration commit.
|
|
30
30
|
- **single-stage scope** (`--stage N`): prep verified stage N is `status:done` and its isolated stage worktree exists and is clean. Other stages' state is irrelevant. A single-stage run is a partial verification: it MUST NOT recommend plain `release-handoff`, but MAY recommend `release-handoff(stage-group)` when the verdict is `accepted` — the stage becomes PR-eligible for a stage-group handoff.
|
|
31
31
|
- the lead still captures `git status --short` from the injected worktree to confirm the analysis ran against the delivered work-tree state; an unexpected divergence (dirty tree outside `.okstra/`, missing worktree) is a `tool-failure`, not a silent proceed.
|
|
32
|
+
- Worker verification procedure:
|
|
33
|
+
- **Target confirmation:** verify the inline worktree, scope, base/head refs, target path, and digest against `verification-target.md` before analysis. Use the sidecar's stage/report mapping and complete diff stat; a missing sidecar, digest mismatch, dirty worktree outside `.okstra/`, or wrong head is a `tool-failure`, never a silent target reselection.
|
|
34
|
+
- **Evidence:** attach file:line, exact command + exit code, log excerpt, or MCP SELECT evidence to every finding. Mark a requirement as covered only when the cited artifact demonstrates it.
|
|
35
|
+
- **Tier 1 and Tier 2 read-only validation:** Tier 1 is the originating brief/approved plan `validation` set; Tier 2 is `<PROJECT_ROOT>/.okstra/project.json` `qaCommands`. Do not auto-detect commands from package manifests. A missing tier is `qa-command not configured: <category>`. Before execution, reject commands containing source/lockfile mutation tokens such as `--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, or `npm install` without `ci`; record the exact denied token.
|
|
36
|
+
- **Tier 3 stage conformance:** read `<task_root>/qa/conformance-manifest.json`. In whole-task scope, run every non-exempt `entries[].runCommand` against the merged worktree; in single-stage scope, run only the matching `stageKey`. Use `qaEnv` only with a replica/test datastore, refresh `result-<stageKey>.json`, and interpret the exit code plus the last `QA-RESULT: PASS|FAIL` marker. Missing/non-PASS evidence is an acceptance-blocker recommendation. An exemption or user waiver is not executed; record its reason, and surface a waiver as a `conditional-accept` recommendation.
|
|
37
|
+
- **Manual user test:** read only the source implementation report's `implementation.manualUserTest`. Execute reproducible steps and record `pass`, `fail`, or `blocked` with observed evidence. Human-only or environment-unavailable steps remain `blocked` with the exact reason. Reaffirm an `applicable=false` exemption; do not execute planning `designPreparation` or manual-test PREP items directly.
|
|
38
|
+
- **Design-preparation carry-in:** read only source implementation report `missingInformation` rows whose `source` starts with `design-prep:`. Recommend `ifStillOpen: block` as an acceptance blocker and `ifStillOpen: follow-up` as residual risk. This phase does not read planning PREP sidecars directly or mutate planning snapshots.
|
|
39
|
+
- **Could-not-verify honesty:** use `not-configured`, `env-unavailable`, `rejected`, `gap`, or `blocked` as appropriate. Never convert unavailable evidence into an executed/pass claim.
|
|
40
|
+
- **Source-mutation prohibition:** verification may write only assigned okstra run artifacts. Do not edit source, schema, deployment, lockfile, or configuration files; route detected defects to a later phase.
|
|
32
41
|
- Required deliverable shape (final report, in addition to the standard sections):
|
|
33
|
-
- **Source Implementation Report(s)**: the `VERIFICATION_TARGET` snapshot verbatim — verification scope, worktree path, base
|
|
42
|
+
- **Source Implementation Report(s)**: the `VERIFICATION_TARGET` snapshot verbatim — verification scope, worktree path, base/head refs, the list of stages under verification, and one row per stage citing its originating implementation final-report (`report_path` from `consumers.jsonl`; render `(report_path unrecorded)` when absent). Every analyser prompt carries the same compact target identity (`**Verification scope:** / **Worktree:** / **Verification base ref:** / **Verification head ref:** / **Verification target path:** / **Verification target digest:**`) and reads the sidecar on demand for the complete diff stat. A worker that cannot confirm its analysis ran against that worktree's delivered diff MUST record a `tool-failure`.
|
|
34
43
|
- **Verdict vocabulary**: Section 7 (`Final Verdict`) MUST include a `Verdict Token` field whose value is exactly one of `accepted`, `conditional-accept`, or `blocked`. `conditional-accept` requires an explicit, exhaustive list of conditions; ambiguous verdicts ("looks good", "mostly ready") are not allowed. Each condition MUST be recorded as a row in the **Conditional Acceptance Conditions** deliverable (`id` `CA-NNN`, `condition`, `evidenceRequired`, `blocksReleaseHandoff`). The validator enforces verdict↔deliverable consistency: `accepted` ⇒ zero acceptance blockers, `blocked` ⇒ at least one, `conditional-accept` ⇒ at least one condition, and a `release-handoff` routing recommendation is allowed only when the verdict is `accepted`. **Any Acceptance Blocker therefore forces the verdict off `accepted` (to `conditional-accept` or `blocked`); the gates below cite this rule instead of restating the arithmetic.**
|
|
35
44
|
- **Acceptance Blockers block** (under section 4): one row per blocker with `id`, `severity` (`critical` / `major` / `minor`), evidence (file path, log excerpt, or test output), and the recommended follow-up phase (`error-analysis` or `implementation-planning`). Empty block is acceptable and preferred — render the single line `- No acceptance blockers found.`
|
|
36
45
|
- **Residual Risk block** (under section 4): risks that are not blockers but should be tracked, each with mitigation owner and a trigger that would escalate them to a blocker.
|
|
37
46
|
- **Validation Evidence**: for every requirement in the originating plan or task brief, cite the artifact (commit SHA, test output, log line, MCP SELECT result) that demonstrates coverage. Paraphrased "verified" claims without an artifact are rejected.
|
|
38
47
|
- **Read-only command log**: any pre-existing test/validation command touched during this run MUST be listed with its exact command line and one honest status — `executed` (ran; carries its exit code) / `env-unavailable` (should run but cannot in this environment — missing replica DB, container, or service; carries the reason, never a faked pass) / `not-configured` (no such qa-command tier) / `rejected` (a mutating/denied token — skipped, carries the denied token). A check that could not run locally is recorded as `env-unavailable` with the reason — never silently dropped and never reported as `executed` with an invented exit code. Mutating-command prohibition is the shared read-only boundary (see Non-goals); it is not restated per row.
|
|
39
|
-
- **Two-tier command lookup (shared with `implementation`):** when this phase performs its own independent re-validation, the command source is exactly the same two tiers `implementation` verifiers use — Tier 1 is the originating task brief / approved plan's `validation` set, Tier 2 is `<PROJECT_ROOT>/.okstra/project.json` under `qaCommands`. Auto-detecting tools from manifest files is forbidden; missing tiers are recorded as `qa-command not configured: <category>` rather than guessed. The `cmd` deny-list (`--fix`, `--write`, ` -w`, ` -u`, `--snapshot-update`, `INSTA_UPDATE=<not-no>`, `cargo update`, `npm install` without `ci`, etc.) is enforced identically. NOTE: runtime fail-fast validation (`okstra_ctl.qa_commands.validate_qa_commands`) only fires at `--task-type implementation` run-prep, so this phase MUST self-check each `qaCommands` entry against the deny-list before executing it — if a denied token is present, skip the command and record it as a `Read-only command log` line `qa-command rejected (denied token: <token>): <label>`.
|
|
40
|
-
- **Tier 3 — stage conformance scripts (whole-task union):** because this phase verifies the **integrated, merged** state, it re-runs conformance against that state rather than per-stage. Read the task-level manifest `<task_root>/qa/conformance-manifest.json` (the directory is the `TASK_QA_PATH` token) and, in **whole-task scope**, run the `runCommand` of **every** `entries[]` item against the merged worktree, refreshing each `<task_root>/qa/result-<stageKey>.json` (`{ "stageKey", "overall": "PASS"|"FAIL"|"MISSING", "ranAt", "requirements" }`). In **single-stage scope**, run only the entry whose `stageKey` matches the verified stage. An entry carrying an `exemption` or user `waiver` is NOT executed — record the skip and reason; a `waiver` becomes a `conditional-accept` condition surfaced in the section 7 Verdict (conformance left unverified by user acknowledgement). Each `runCommand` runs in the worktree cwd with `qaEnv` env (replica DB DSN / app base URL / env file) — **replica / test environment only**, never shared / staging / prod, and the same source/lockfile mutation deny-list applies (a conformance script MAY mutate only its `qaEnv` replica datastore). Interpret each result from the exit code + stdout `QA-RESULT: PASS|FAIL` (last wins) and `REQ <id>: PASS|FAIL: <reason>` lines; no `QA-RESULT` marker → `MISSING`. Any entry whose result is not `PASS` (including `MISSING` or a never-run/missing sidecar) is an **Acceptance Blocker** (`major`+). This is the same gate the `validate-run.py` Tier 3 check enforces on the result sidecars.
|
|
41
|
-
- **Manual user test results**: take each item from the source implementation report's §5.7.9 Manual User Test (Draft), execute the ones reproducible in this environment (e.g. `/okstra-container-build`, which runs `okstra container up`, then the documented steps), and record `result` (`pass` / `fail` / `blocked`) + observed value in §5.8.7 (data field `finalVerification.manualUserTest`). Steps that need human-only interaction this run cannot perform are recorded as `blocked` with the reason (handed to the user), never silently skipped. A failed manual test is an Acceptance Blocker. If the draft was an exemption (`applicable=false`), reaffirm the reason in one line (`applicable=false` + `exemptionReaffirm`).
|
|
42
|
-
For manual testing, read only the source implementation report's `implementation.manualUserTest`. Do not execute planning `designPreparation` / `manual-user-test` PREP items directly. The implementation report has already reconciled the approved seed with the actual diff. Record reproducible results; human-only or unavailable environments become `result: blocked` with the exact reason.
|
|
43
|
-
- **Non-manual design-preparation handoff**: read only source implementation report `missingInformation` rows whose `source` starts with `design-prep:`. Record `ifStillOpen: block` as an acceptance blocker and `ifStillOpen: follow-up` as residual risk. This phase does not read planning PREP sidecars directly, merge their inputs, or mutate the planning snapshot.
|
|
44
48
|
- **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
|
|
45
49
|
- **Routing recommendation**: the next safe phase — one of `release-handoff`, `done`, `error-analysis`, `implementation-planning` — tied to the verdict and blocker list. `release-handoff` is allowed ONLY when the Verdict Token is `accepted`. `release-handoff` is additionally allowed ONLY when the verification scope (the `Verification scope:` line of the injected `VERIFICATION_TARGET` block, recorded as the report's `verificationScope` field) is `whole-task`; a `single-stage` accepted run routes to `release-handoff(stage-group)` (or `implementation` / `done`); plain `release-handoff` remains whole-task-only. Enforcement: `validators/validate-run.py` rejects a `single-stage` report whose routing cites plain `release-handoff`.
|
|
46
50
|
- **Verified-row recording** (single-stage scope only): when the Verdict Token is `accepted`, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper re-validates taskType/scope/verdict from data.json, so a non-accepted or whole-task report is rejected at the tool layer.
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
- Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows carry `Blocks=approval`, so the approval frontmatter stays `approved: false` until they are resolved.
|
|
14
14
|
- never plan around an unconfirmed `intent-inference` augmentation as if it were a settled requirement. Treat the inference as settled ONLY when a `[CONFIRMED …]` marker sits on the matching `intent-check:` row after the precondition runs; absent the marker it stays a `Blocks=approval` clarification item per the precondition's `skipped` branch.
|
|
15
15
|
- `conversion-block:` rows are handled by the precondition; planning around an untranslated reporter phrase is forbidden until it is resolved.
|
|
16
|
+
- Worker planning procedure:
|
|
17
|
+
- identify requirement gaps and affected interfaces with file:line evidence, resolving codebase-answerable ambiguity before returning findings
|
|
18
|
+
- compare at least two feasible options unless the brief carries a confirmed decision; record concrete trade-offs and current-pattern evidence for every option
|
|
19
|
+
- propose stages with real dependency edges, validation signals, rollback order, and change-locality evidence; do not serialize independent work
|
|
20
|
+
- surface migration, deployment, cross-project, and approval risks without drafting final-report headings or schema rows
|
|
16
21
|
- Pre-planning context exploration (mandatory before option drafting):
|
|
17
22
|
- read the task brief, related-task briefs, and any cited spec / design doc end-to-end
|
|
18
23
|
- inspect the current state of every file the task names (or the closest matching files if names are stale) — record current responsibilities, public interfaces, and known coupling points
|
|
@@ -21,8 +21,13 @@
|
|
|
21
21
|
- per-candidate evidence (path:line) and scope mapping
|
|
22
22
|
- per-candidate severity / effort / recommended-next-phase
|
|
23
23
|
- convergence classification (full / partial / contested / worker-unique) across workers
|
|
24
|
+
- Worker candidate procedure:
|
|
25
|
+
- inspect every resolved priority lens inside the resolved scan scope; the assigned primary lens changes only the first pass, never total coverage
|
|
26
|
+
- for the primary pass, return an evidence-backed candidate or a no-candidate rationale citing the highest-signal path:line inspected
|
|
27
|
+
- for every candidate, record lens, scope, severity, effort, recommended next phase, evidence, and a worker-local source item ID
|
|
28
|
+
- identify overlap with other findings or linked tasks as duplicate, broader/narrower, conflicting, blocked-by, or follow-up instead of silently merging it
|
|
24
29
|
- Worker diversity rule:
|
|
25
|
-
- every analyser inspects every priority lens
|
|
30
|
+
- every analyser inspects every resolved priority lens. The Phase 1.5 grilling log assigns only the first pass: enumerate selected analyser worker instances in `requiredWorkerRoles` order and rotate them over resolved priority lenses in log order. Provider/model names never determine the position.
|
|
26
31
|
- each worker, before broadening to the remaining lenses, must do one of: (a) produce at least one candidate from its primary pass, or (b) record a no-candidate rationale citing the highest-signal path:line evidence it inspected.
|
|
27
32
|
- two workers' candidates are the same candidate only when they cite the same underlying design/code problem and the same remediation direction. Shared evidence paths alone are not enough to merge; keep distinct failure modes distinct.
|
|
28
33
|
- when a candidate from one worker overlaps another worker's evidence, convergence must classify the relationship as one of: duplicate, broader/narrower, or conflicting. Do not collapse contested candidates just to meet the candidate cap.
|
|
@@ -33,10 +38,15 @@
|
|
|
33
38
|
- For each open question Lead asks ONE `AskUserQuestion` with a `(Recommended)` answer drawn from a codebase-first inspection. Budget: at most 12 questions in this phase.
|
|
34
39
|
- Stop conditions (OR): all questions resolved / budget exhausted / user signals proceed.
|
|
35
40
|
- Lead persists the round at `<RUN_DIR>/state/phase-1.5-grilling.md` with one section per question (question / recommended / user answer) and a closing `Resolved scope` / `Resolved lenses` block. Worker prompts use this resolved block as the authoritative scope and lens definition.
|
|
41
|
+
- The same log includes `## Primary Pass Assignments` with a `Worker ID | Primary lens` table. It contains every selected analyser exactly once in `requiredWorkerRoles` order; the lead derives it from the resolved roster and lenses rather than provider catalog order.
|
|
36
42
|
- After writing the log and before Phase 4 dispatch, the lead injects its **absolute path** into every analyser prompt as the `**Phase 1.5 Grilling Log:** <absolute-path>` anchor header (see `templates/worker-prompt-preamble.md` §"Anchor headers"). This is the improvement-discovery counterpart to the `**Worktree:**` / `**Verification …:**` anchors that implementation / final-verification inject: workers read the log from this explicit path rather than re-deriving `<RUN_DIR>`. The path is byte-identical across all analysers, so it does not break the dispatch-prompt invariant.
|
|
37
43
|
- Decision-tree walk (bounded):
|
|
38
44
|
- When candidates branch on a structural question (e.g. "is module X meant to own this responsibility?"), resolve via `Read` / `Grep` first. Only escalate to the user inside the Phase 1.5 budget.
|
|
39
45
|
- Expected output emphasis:
|
|
46
|
+
- evidence-backed candidate or explicit no-candidate result for every resolved lens
|
|
47
|
+
- worker-local candidate IDs that convergence can trace back to their source worker
|
|
48
|
+
- uncertainty and overlap relationships kept explicit for downstream consensus classification
|
|
49
|
+
- Report assembly instructions:
|
|
40
50
|
- the `## 5.9 Improvement Candidates` table populated with rows that obey the 10-column schema from `validators/validate_improvement_report.py` (Cand ID `I-NNN`, Lens from whitelist, Title, Scope ⊆ scan-scope, Severity, Effort, Consensus, Source workers `<worker>:<id>` from {claude, codex, antigravity}, Recommended next-phase ∈ {requirements-discovery, implementation-planning, error-analysis}, Evidence as path:line list)
|
|
41
51
|
- `Consensus` cells in `## 5.9 Improvement Candidates` use the table enum exactly: `full`, `partial`, `contested`, `worker-unique`. Map convergence's `full-consensus` / `partial-consensus` labels to `full` / `partial` before writing the table.
|
|
42
52
|
- `## 7. Final Verdict` Verdict Token ∈ {`candidates-ready`, `no-candidates`, `blocked`}; Direction `routing`; Next Step "ask the user to select K candidates (see the ## 5.9 table)"
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
- before deciding whether to fan out, read `Related Task Graph`. Use `depends-on`, `blocks` / `blocked-by`, parent/child, follow-up, and split edges as seed ordering constraints. Do not flatten a directed graph into unrelated tasks.
|
|
15
15
|
- `intent-inference` augmentations whose paired `intent-check:` row carries `[CONFIRMED …]` are treated as **confirmed**; trust the confirmation text in `## Reporter Confirmations` over the original inference if they differ. Unconfirmed `intent-inference` rows under `reporter-confirmations: skipped` follow the precondition's `skipped` branch above.
|
|
16
16
|
- `conversion-block:` rows are explicit "translation failed" signals — never attempt to resolve them by inference here; the precondition above already handled them.
|
|
17
|
+
- Worker discovery procedure:
|
|
18
|
+
- classify the request and cite the evidence that determines both its work category and safest next phase
|
|
19
|
+
- identify independently startable decomposition candidates without publishing or rendering fan-out artifacts; preserve every directed dependency from `Related Task Graph`
|
|
20
|
+
- resolve codebase-answerable ambiguity by inspection and record file:line evidence; return only human-owned decisions as clarification candidates with the evidence already checked
|
|
21
|
+
- state the reporter's rejection criteria, missing routing inputs, and the evidence boundary behind each recommendation
|
|
17
22
|
- Primary focus areas:
|
|
18
23
|
- classify the work as bugfix, feature, improvement, refactor, or ops
|
|
19
24
|
- determine whether `error-analysis` or `implementation-planning` is the next safe step. Direct `implementation` handoff is never a valid routing target — implementation requires an approved `implementation-planning` report
|
|
@@ -49,7 +54,9 @@
|
|
|
49
54
|
- evidence-backed routing decision
|
|
50
55
|
- uncertainty boundaries and missing inputs
|
|
51
56
|
- next recommended phase and safe resume guidance
|
|
52
|
-
- canonical-term resolution for every `terminology:*` brief item
|
|
57
|
+
- canonical-term resolution for every `terminology:*` brief item as `<term> = <definition>`, plus whether `<PROJECT_ROOT>/.okstra/glossary.md` should be updated
|
|
58
|
+
- Report assembly instructions:
|
|
59
|
+
- write canonical-term resolutions in a new `Domain Alignment` subsection of the final report; actual glossary writes happen via `okstra-brief-gen` Step 4.5 on a subsequent run
|
|
53
60
|
- Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
|
|
54
61
|
- if any blocking input is missing at the time of writing the final report, populate `## 1. Clarification Items` in `final-report-template.md` (a single unified table; `Blocks=next-phase` for items the next run cannot start without)
|
|
55
62
|
- prefer concrete questions whose answers map directly to a routing decision (`bugfix` vs `feature`, `error-analysis` vs `implementation-planning`, etc.). State each option in plain language with one sentence describing what choosing it would mean for the next phase.
|