okstra 0.128.0 → 0.129.1
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 +15 -2
- package/docs/architecture.md +21 -5
- package/docs/cli.md +13 -2
- package/docs/project-structure-overview.md +22 -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 +6 -6
- 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 +42 -84
- package/runtime/prompts/lead/okstra-lead-contract.md +10 -8
- package/runtime/prompts/lead/report-writer.md +22 -28
- package/runtime/prompts/lead/team-contract.md +28 -11
- package/runtime/prompts/profiles/_common-contract.md +1 -1
- package/runtime/prompts/profiles/error-analysis.md +1 -1
- 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 +7 -13
- package/runtime/python/okstra_ctl/codex_dispatch.py +70 -319
- 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 +53 -14
- package/runtime/python/okstra_ctl/improvement_assignment.py +61 -0
- package/runtime/python/okstra_ctl/path_hints.py +23 -1
- package/runtime/python/okstra_ctl/paths.py +10 -1
- package/runtime/python/okstra_ctl/render.py +56 -11
- package/runtime/python/okstra_ctl/report_finalize.py +394 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +6 -2
- package/runtime/python/okstra_ctl/worker_prompt_body.py +107 -0
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +102 -9
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +79 -9
- 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 -234
- package/runtime/validators/lib/fixtures.sh +27 -12
- package/runtime/validators/validate-run.py +201 -72
- package/src/cli-registry.mjs +18 -0
- package/src/commands/execute/convergence.mjs +34 -0
- package/src/commands/report/finalize.mjs +65 -0
|
@@ -76,92 +76,48 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
|
|
|
76
76
|
- Items tagged `unknown` keep the literal `unknown` as their ticket key.
|
|
77
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.
|
|
78
78
|
3. The lead groups findings based on semantic similarity AND ticket-set equality:
|
|
79
|
-
- Same semantics + same ticket set across 2+ workers →
|
|
80
|
-
- Same semantics but disjoint ticket sets →
|
|
81
|
-
- Only one worker confirms a finding →
|
|
82
|
-
4. When grouping is ambiguous, prefer splitting over merging (avoid over-merging).
|
|
83
|
-
5.
|
|
84
|
-
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.
|
|
85
85
|
|
|
86
86
|
### Round 1-N: Re-verification Loop (queue-pruned)
|
|
87
87
|
|
|
88
|
-
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:
|
|
89
91
|
|
|
90
92
|
```text
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
IF roundIndex > 1 AND NOT round_gate_open(queue, roundHistory[-1].dispatches):
|
|
97
|
-
record round2SkippedReason in convergence state
|
|
98
|
-
BREAK
|
|
99
|
-
|
|
100
|
-
inputQueueSize = len(queue)
|
|
101
|
-
dispatches = []
|
|
102
|
-
skippedWorkers = []
|
|
103
|
-
|
|
104
|
-
FOR each analysis worker W (excluding report-writer-worker):
|
|
105
|
-
items_for_W = [f for f in queue if W != f.originWorker]
|
|
106
|
-
IF items_for_W is empty:
|
|
107
|
-
skippedWorkers.append({worker: W, reason: "no items to verify"})
|
|
108
|
-
CONTINUE
|
|
109
|
-
dispatch = send_reverify_request(W, items_for_W, roundIndex)
|
|
110
|
-
dispatches.append(dispatch)
|
|
111
|
-
|
|
112
|
-
IF len(dispatches) > 0 AND all dispatches in this round are terminal non-result (timeout/error/no-result-file):
|
|
113
|
-
# Per "Worker failure handling in reverify" below — do NOT treat as DISAGREE.
|
|
114
|
-
record verification-error evidence on each finding in the queue for this round
|
|
115
|
-
record round2SkippedReason = "all-reverify-non-result" for any subsequent round
|
|
116
|
-
BREAK
|
|
117
|
-
|
|
118
|
-
resolvedCount = 0
|
|
119
|
-
carriedForwardCount = 0
|
|
120
|
-
|
|
121
|
-
FOR each finding F in queue (snapshot):
|
|
122
|
-
votes = aggregate_votes(F, dispatches) # AGREE / DISAGREE / SUPPLEMENT / verification-error
|
|
123
|
-
IF all non-error votes are AGREE or SUPPLEMENT:
|
|
124
|
-
F.classification = "full-consensus"
|
|
125
|
-
queue.remove(F); resolvedCount += 1
|
|
126
|
-
ELIF majority non-error votes are AGREE or SUPPLEMENT:
|
|
127
|
-
F.classification = "partial-consensus"
|
|
128
|
-
queue.remove(F); resolvedCount += 1
|
|
129
|
-
ELIF all non-error votes are DISAGREE:
|
|
130
|
-
F.classification = "worker-unique"
|
|
131
|
-
queue.remove(F); resolvedCount += 1
|
|
132
|
-
ELSE:
|
|
133
|
-
# mixed / insufficient non-error votes, or all-error votes → carry forward
|
|
134
|
-
carriedForwardCount += 1
|
|
135
|
-
|
|
136
|
-
record roundHistory entry { round: roundIndex, inputQueueSize, resolvedCount,
|
|
137
|
-
carriedForwardCount, dispatches, skippedWorkers }
|
|
138
|
-
|
|
139
|
-
# Final classification — runs after the WHILE loop exits (queue empty OR roundIndex == effectiveMaxRounds OR Round 2 gate closed)
|
|
140
|
-
FOR each finding F still in queue:
|
|
141
|
-
IF config.adversarial AND F was carried forward by the adversarial round
|
|
142
|
-
resolution (a surviving `counter-evidence` refute, or a burden-not-met
|
|
143
|
-
majority — see §"Adversarial Verification Mode"):
|
|
144
|
-
F.classification = "contested" # one evidence-backed refute denies consensus, whatever the AGREE tally
|
|
145
|
-
ELIF majority AGREE-or-SUPPLEMENT across all executed rounds:
|
|
146
|
-
F.classification = "partial-consensus"
|
|
147
|
-
ELSE:
|
|
148
|
-
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
|
|
149
98
|
```
|
|
150
99
|
|
|
151
|
-
|
|
100
|
+
Follow this protocol exactly:
|
|
152
101
|
|
|
153
|
-
|
|
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.
|
|
154
109
|
|
|
155
|
-
|
|
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.
|
|
156
111
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
| `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)
|
|
161
115
|
|
|
162
|
-
|
|
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.
|
|
163
117
|
|
|
164
|
-
|
|
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.
|
|
165
121
|
|
|
166
122
|
#### Worker failure handling in reverify (BLOCKING)
|
|
167
123
|
|
|
@@ -169,17 +125,17 @@ A reverify dispatch that returns a **terminal non-result** (`timeout`, `error`,
|
|
|
169
125
|
|
|
170
126
|
Rules:
|
|
171
127
|
|
|
172
|
-
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.
|
|
173
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).
|
|
174
|
-
3.
|
|
175
|
-
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.
|
|
176
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`.
|
|
177
133
|
|
|
178
|
-
The
|
|
134
|
+
The engine's classifiers treat `verification-error` as "no usable vote" — it counts neither toward AGREE nor toward DISAGREE.
|
|
179
135
|
|
|
180
136
|
### Convergence Test
|
|
181
137
|
|
|
182
|
-
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.
|
|
183
139
|
|
|
184
140
|
## Verification Mode
|
|
185
141
|
|
|
@@ -249,7 +205,9 @@ Design intent: one `counter-evidence` refute denies a claim consensus (it cannot
|
|
|
249
205
|
|
|
250
206
|
### Sponsorship Optimization
|
|
251
207
|
|
|
252
|
-
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.
|
|
253
211
|
|
|
254
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.
|
|
255
213
|
|
|
@@ -290,7 +248,7 @@ If none of the three is available, **abort the reverify dispatch for that role**
|
|
|
290
248
|
|
|
291
249
|
Reverify prompts MUST NOT inject the Phase 2 `[Required reading]` clause:
|
|
292
250
|
|
|
293
|
-
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 `
|
|
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.
|
|
294
252
|
|
|
295
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.
|
|
296
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).
|
|
@@ -500,9 +458,9 @@ Schema rules:
|
|
|
500
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.
|
|
501
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).
|
|
502
460
|
- `roundHistory[].skippedWorkers[]`: per-worker `{worker, reason}` for workers with no items to verify OR with a non-result dispatch.
|
|
503
|
-
- `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.
|
|
504
462
|
- `finalClassificationCounts`: post-loop counts. Required field with keys `fullConsensus`, `partialConsensus`, `contested`, `workerUnique`.
|
|
505
|
-
- `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.
|
|
506
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).
|
|
507
465
|
|
|
508
466
|
## Coverage critic pass
|
|
@@ -575,7 +533,7 @@ Critic output lives in the run's `worker-results/` directory (`runs/final-verifi
|
|
|
575
533
|
|
|
576
534
|
Information to be passed to Phase 6 after completing this contract:
|
|
577
535
|
|
|
578
|
-
-
|
|
536
|
+
- Validated final schema-v1.2 artifact containing the four-category classification of all findings; the report-writer consumes it and does not vote
|
|
579
537
|
- Round history and votes per worker for each finding
|
|
580
538
|
- Path to the convergence state artifact
|
|
581
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 |
|
|
@@ -210,6 +210,8 @@ These phases are governed by [team-contract](./team-contract.md). It is the cano
|
|
|
210
210
|
|
|
211
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
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
|
+
|
|
213
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).
|
|
214
216
|
|
|
215
217
|
### Phase 3 — Runtime adapter setup (BLOCKING)
|
|
@@ -282,15 +284,15 @@ Convergence is enabled by default. Configure via task-manifest.json:
|
|
|
282
284
|
- `convergence.verificationMode`: `"lightweight"` | `"full-reanalysis"` (default: `"lightweight"`; the adversarial phases below force `"full-reanalysis"`)
|
|
283
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".
|
|
284
286
|
|
|
285
|
-
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`.
|
|
286
288
|
|
|
287
|
-
|
|
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.
|
|
288
290
|
|
|
289
|
-
|
|
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.
|
|
290
292
|
|
|
291
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.
|
|
292
294
|
|
|
293
|
-
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.
|
|
294
296
|
|
|
295
297
|
## Phase 6: Final report assembly
|
|
296
298
|
|
|
@@ -403,10 +405,10 @@ After persistence, reply briefly in the resolved Report Language with: completio
|
|
|
403
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 |
|
|
404
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 |
|
|
405
407
|
| Injecting `[Required reading]` into lightweight reverify prompts | Lightweight reverify forbids re-reading source materials — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression" |
|
|
406
|
-
| 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 |
|
|
407
409
|
| Issuing serial Read calls in Phase 1 | The intake files are independent — issue all Read calls in a single message (parallel) |
|
|
408
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 |
|
|
409
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 |
|
|
410
|
-
| Re-sending
|
|
411
|
-
| 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" |
|
|
412
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)
|
|
@@ -80,42 +81,33 @@ Phase 6 first produces the final-report data.json at `runs/<task-type>/reports/f
|
|
|
80
81
|
|
|
81
82
|
For an implementation-planning run, the Report writer worker owns the Phase 6 design assessment snapshot: it writes `designPreparation` and every stage's `designSurfaceCoverage` into data.json from the detector output and consolidated plan. It does not create user inputs, consume a user answer as if it were part of that snapshot, or materialize `design-prep-requests/`; `schemas/final-report-v1.0.schema.json` and `validators/validate-run.py` `_validate_design_prep_contract` enforce the snapshot shape, detector coverage, and references.
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
Phase 7 post-processing is **one command**. `okstra report-finalize` owns the ordered sequence — it is the same code path the Codex lead adapter runs automatically, so a Claude-led run and a Codex-led run finalize identically:
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
```bash
|
|
87
|
+
okstra report-finalize \
|
|
88
|
+
--project-root <project_root> \
|
|
89
|
+
--run-manifest <runDirectoryPath>/manifests/run-manifest-<task-type>-<seq>.json \
|
|
90
|
+
--report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
|
|
91
|
+
```
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
+
Do NOT run the four steps below by hand. Hand-running them is the recurring root cause of reports shipping with `--` token cells, a missing html sibling, Section 3 missing follow-up entries, or Section 4 rows never spawning — the order is load-bearing and a skipped step surfaces only later, as a validator `contract-violated`. Every step is idempotent, so after fixing a reported failure just re-run the same command.
|
|
94
|
+
|
|
95
|
+
The steps it executes, in this contractual order, and the contract each one carries:
|
|
96
|
+
|
|
97
|
+
1. **`token-usage` — collect usage.** Aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state, populates `tokenUsage` and the execution-status usage fields in data.json, and re-invokes the renderer so the markdown carries real numbers.
|
|
93
98
|
|
|
94
99
|
The data.json paths populated: `tokenUsage.lead.{totalTokens,billableTokens,costUsd}`, the `worker` / `grand` rows, `tokenUsage.cli.costUsd`, and each `executionStatus[].{totalTokens,billableTokens,costUsd,durationMs,cliTotalTokens,cliCostUsd}` for rows whose role matches a team-state worker. The data.json MUST already exist (Phase 6 output).
|
|
95
100
|
|
|
96
101
|
For implementation-planning, this Phase 7 canonical render calls `materialize_design_prep_requests()` after token substitution and creates deterministic request files only for `provisional` / `blocked` items. Later answers are append-only user-input sidecars; request generation and user input never rewrite the assessment fields, so the source report remains immutable as the design-input snapshot after this render. `validators/validate-run.py` `_validate_design_prep_requests` enforces request existence, canonical path, content, and assessment fingerprint.
|
|
97
|
-
2.
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
okstra render-views \
|
|
101
|
-
<runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
|
|
102
|
-
```
|
|
102
|
+
2. **`render-views` — render the human report artifact.** Runs against the substituted markdown; the renderer itself decides whether an html sibling is warranted.
|
|
103
103
|
|
|
104
104
|
Output (idempotent — re-running overwrites):
|
|
105
105
|
- `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — single-file self-contained human view, **generated when the report has at least one §1 `C-*` clarification row OR an implementation-planning Plan Approval widget target** (a sibling `final-report-*.data.json` carrying `implementationPlanning.optionCandidates`). Clarification rows with `Status` ∈ {`open`, `answered`} embed form widgets (`<select>` for enum-style decisions, `<input>` for material / data-point kinds, `<textarea>` fallback); an `Export user response` button serialises form values to a markdown sidecar (schema in [`templates/reports/user-response.template.md`](../../templates/reports/user-response.template.md)) and downloads it as `user-response-<task-type>-<seq>.md`; the user saves it to `runs/<task-type>/user-responses/` (the renderer pre-creates that directory), and `--resume-clarification` auto-appends every sidecar found there to the next run's `clarification-response.md` (`clarification_items.clarification_response_with_sidecars`). The original final-report MD is **never** mutated by user input — the sidecar is the single write target.
|
|
106
106
|
- the implementation-planning report renders a **Plan Approval** section at the end of the body (implementation-option `<select>` + an approval checkbox) — disabled while any §1 `Blocks: approval` row is unresolved. Checking approval and exporting embeds a `## APPROVAL` block in the sidecar body, and the implementation-start wizard's approve-confirm step detects it and, after user confirmation, applies it through the existing `--approve` / `--implementation-option` path.
|
|
107
107
|
- When the report has **no** `C-*` clarification rows and is **not** a Plan Approval widget target, the html carries no interactive forms (it would only duplicate the MD), so the renderer prints `html: skipped (...)` and writes nothing. This is the expected state for such runs — `validators/validate-report-views.py` treats "no C-* rows + no approval target + no html" as a pass, not a missing artifact.
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
3.
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
okstra spawn-followups \
|
|
114
|
-
<runDirectoryPath>/reports/final-report-<task-type>-<seq>.data.json \
|
|
115
|
-
--project-root <project_root> \
|
|
116
|
-
--task-group <task-group> \
|
|
117
|
-
--parent-task-key <task-key>
|
|
118
|
-
```
|
|
109
|
+
It runs after usage collection so token placeholders are substituted in any rendered html, and before routing persistence so the html artifact, when generated, exists for the validator step that checks it.
|
|
110
|
+
3. **`spawn-followups` — routing and follow-up persistence.** Turns the report's `## 4. Follow-up Tasks` rows into `tasks/<task-group>/<new-task-id>/` stubs.
|
|
119
111
|
|
|
120
112
|
Behaviour contract:
|
|
121
113
|
- Idempotent: rows whose target dir exists are reported as `existing` and skipped. Reruns of the same parent task are safe.
|
|
@@ -130,7 +122,9 @@ The four Phase 7 steps below MUST execute in this exact order. Reordering them i
|
|
|
130
122
|
```
|
|
131
123
|
|
|
132
124
|
The status file is written after routing and follow-up persistence completes.
|
|
133
|
-
4.
|
|
125
|
+
4. **`validate-run` — validate the finished run.** Checks the completed artifact set, including the report-views contract that catches a missing or stale html sibling. A failure here names the specific contract; fix it and re-run `okstra report-finalize`.
|
|
126
|
+
|
|
127
|
+
After `okstra report-finalize` reports `"ok": true`, **execute the run-scoped cleanup gate.** Call `shutdown_workers` only after that success, all persistence work, and explicit user approval under [okstra-lead-contract](./okstra-lead-contract.md) "Run-scoped worker-resource lifecycle". If the user keeps resources, leave the selected adapter's resources intact and surface its manual cleanup guidance.
|
|
134
128
|
|
|
135
129
|
## Final Report Structure
|
|
136
130
|
|
|
@@ -356,7 +350,7 @@ Persistence steps that must be performed in Phase 7:
|
|
|
356
350
|
- [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
|
|
357
351
|
- [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
|
|
358
352
|
- [ ] 8. **Spawn follow-up task stubs**: run `okstra spawn-followups` against the final-report per the canonical spawn rule defined in "Phase 7 follow-up task spawner" above. Do not restate the trigger condition here — that section is the single source of truth. The script is idempotent across reruns.
|
|
359
|
-
- [ ] 9. **Human HTML report** (conditional): `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — produced by Phase 7 step
|
|
353
|
+
- [ ] 9. **Human HTML report** (conditional): `runs/<task-type>/reports/final-report-<task-type>-<seq>.html` — produced by the Phase 7 `render-views` step per its generation predicate (≥1 §1 `C-*` clarification row OR an implementation-planning Plan Approval widget target; that step is the single source for the exact condition). Reports matching neither condition legitimately have no html sibling; do not treat its absence as a missing artifact.
|
|
360
354
|
|
|
361
355
|
### Response after Persistence
|
|
362
356
|
|
|
@@ -65,13 +65,15 @@ Only workers selected from `recommendedWorkers` in `task-manifest.json` and `res
|
|
|
65
65
|
|
|
66
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.
|
|
67
67
|
|
|
68
|
-
The `**Coding preflight pack:**` anchor is emitted only
|
|
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.
|
|
69
71
|
|
|
70
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.
|
|
71
73
|
|
|
72
|
-
A `final-verification` prompt may contain 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.
|
|
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.
|
|
73
75
|
|
|
74
|
-
The Phase 7 run validator enforces the same rule against the persisted prompt paths recorded by the run manifest and team-state. `validators/validate-run.py`
|
|
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.
|
|
75
77
|
|
|
76
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.
|
|
77
79
|
|
|
@@ -81,13 +83,13 @@ Persist the exact worker prompt before dispatch per Operating Rule 6; never use
|
|
|
81
83
|
|
|
82
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.
|
|
83
85
|
|
|
84
|
-
###
|
|
86
|
+
### Audience preambles + shared error contract (SSOT)
|
|
85
87
|
|
|
86
|
-
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.
|
|
87
89
|
|
|
88
90
|
What the lead MUST still do per dispatch:
|
|
89
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.
|
|
90
|
-
- Inject the absolute `**Errors log path:**` and `**Errors sidecar path:**`
|
|
92
|
+
- Inject `**Worker Error Contract Path:**` plus the absolute `**Errors log path:**` and `**Errors sidecar path:**` headers — workers cannot synthesize these paths.
|
|
91
93
|
- Omit the preamble pointer for reverify dispatches (Phase 5.5 lightweight mode) — see [convergence](./convergence.md) "Reverify prompt: required-reading suppression".
|
|
92
94
|
|
|
93
95
|
Audience-scoped file enumeration (performance optimization — mandatory):
|
|
@@ -117,6 +119,21 @@ Terminal statuses that can be recorded for a worker:
|
|
|
117
119
|
4. A process exit, spawn acknowledgement, pane creation, or Result Path alone is insufficient when the backend contract requires additional status/audit artifacts.
|
|
118
120
|
5. Apply the single shared retry budget through `redispatch_worker`; after the second failure, record the terminal status and proceed with reduced confidence.
|
|
119
121
|
|
|
122
|
+
### Mid-run liveness probes
|
|
123
|
+
|
|
124
|
+
Between wakes, `okstra worker-liveness` is the **only** sanctioned way to ask whether a pending worker is still alive. Do NOT hand-roll a polling script, an `ls` / `stat` loop, or any ad-hoc file-existence check: a lead that writes its own probe owns that probe's bugs, and those bugs surface as *worker* failures — a shell quoting slip silently turns the probe into a no-op that reports health it never measured.
|
|
125
|
+
|
|
126
|
+
Each probe matches exactly one dispatch backend, and passing a worker to the wrong flag returns a confident wrong answer:
|
|
127
|
+
|
|
128
|
+
| Worker | Backend | Flag | What it reads |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| `claude-worker` | in-process subagent | `--audit` | its audit sidecar's newest `- PROGRESS:` heartbeat |
|
|
131
|
+
| `codex-worker` / `antigravity-worker` | CLI wrapper | `--prompt` | `<prompt>.log` / `<prompt>.status.json` |
|
|
132
|
+
|
|
133
|
+
The mismatch is not intermittent, it is guaranteed: only the `okstra-*-exec.sh` wrappers ever write `<prompt>.log` / `<prompt>.status.json`, so an in-process worker produces neither by construction. Probing a `claude-worker` with `--prompt` therefore reports `did-not-launch` for a worker that is running normally, every time, as soon as the 60s launch grace passes. Probe in-process workers with `--audit`.
|
|
134
|
+
|
|
135
|
+
Branch on the exit code, not the JSON: `0` = every probe healthy, `1` = at least one `stalled` / `did-not-launch`. The probe reports; it never kills or re-dispatches. Acting on an unhealthy verdict means spending the existing one-retry budget below.
|
|
136
|
+
|
|
120
137
|
## Lead Redispatch Policy on Result-Missing
|
|
121
138
|
|
|
122
139
|
After each worker subagent returns (regardless of role), Lead MUST verify the canonical result file exists at the absolute path resolved from the `**Result Path:**` anchor header (against `**Project Root:**`). The check is identical for in-process workers (claude-worker) and CLI-wrapper workers (codex-worker / antigravity-worker).
|
|
@@ -126,8 +143,8 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
|
|
|
126
143
|
- The wrapper subagent returned an explicit `*_RESULT_MISSING` sentinel (codex-worker / antigravity-worker step 8c — `CODEX_RESULT_MISSING` / `ANTIGRAVITY_RESULT_MISSING`).
|
|
127
144
|
- The result file is absent at the resolved absolute path even though the worker returned without a `*_RESULT_MISSING` sentinel — for example, claude-worker returned its final assistant message but never persisted the artifact, or the wrapper exited 0 and the codex/antigravity sub-agent forwarded raw stdout despite the contract.
|
|
128
145
|
- The result file exists but cannot be parsed (frontmatter unreadable, sections 1–5 entirely missing). A truncated file in the middle of section 5 is NOT covered here — it goes to the validator's regular `error` path, not the retry path.
|
|
129
|
-
- `okstra worker-liveness` reports
|
|
130
|
-
- `okstra worker-liveness` reports
|
|
146
|
+
- `okstra worker-liveness --prompt` reports a **CLI-wrapper** worker (`codex` / `antigravity`) `did-not-launch` — neither `<prompt-path>.log` nor `<prompt-path>.status.json` exists past the launch grace (default 60s). The wrapper writes its status sidecar before invoking the CLI and hard-fails loudly with a distinct exit code on every argument check before that, so the absence of BOTH artifacts means the dispatch itself never reached the script. Without this trigger the only evidence was a lead noticing two missing files by eye, and the run paid the full polling cap for a worker that never started.
|
|
147
|
+
- `okstra worker-liveness --audit` reports an **in-process** worker (`claude-worker`) `stalled` — its audit sidecar's newest `- PROGRESS:` heartbeat is older than the cadence budget, or the sidecar carries no heartbeat at all. This is the in-process equivalent of the CLI wrappers' idle watchdog: the wrapper reaps a silent CLI itself, but nothing reaped a silent `claude-worker` until its deadline.
|
|
131
148
|
- The result file exists but its audit sidecar does not, at `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md`. Workers write both in the same step, so a result without a sidecar means the Reading Confirmation block — the only evidence the worker read its inputs — was never produced. `validate-run.py` fails the run on this at Phase 7 either way (`validate_worker_results_audit`); checking it here spends the existing one-retry budget while the role can still be re-dispatched, instead of surfacing hours later when the worker session is gone.
|
|
132
149
|
|
|
133
150
|
**One-retry policy:**
|
|
@@ -149,7 +166,7 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
|
|
|
149
166
|
|
|
150
167
|
## Worker Output Contract
|
|
151
168
|
|
|
152
|
-
The canonical worker output contract —
|
|
169
|
+
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.
|
|
153
170
|
|
|
154
171
|
Lead-facing duties that stay here:
|
|
155
172
|
|
|
@@ -223,8 +240,8 @@ without proceeding.
|
|
|
223
240
|
2. Re-verification workers follow a constrained response format (verdict + brief explanation).
|
|
224
241
|
3. Workers cannot vote on their own findings (only verify other workers’ work).
|
|
225
242
|
4. The `report writer worker` does not participate in re-verification voting. It is responsible only for generating the final report.
|
|
226
|
-
5. Division of labor: the lead performs **finding-to-finding matching** (
|
|
227
|
-
6. Batch processing is performed with one spawn per worker
|
|
243
|
+
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.
|
|
244
|
+
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.
|
|
228
245
|
7. These rules do not apply if Convergence is disabled.
|
|
229
246
|
|
|
230
247
|
## 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.
|
|
@@ -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)"
|