okstra 0.128.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 +15 -2
- package/docs/architecture.md +19 -3
- package/docs/cli.md +8 -0
- package/docs/project-structure-overview.md +14 -5
- 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 +42 -84
- package/runtime/prompts/lead/okstra-lead-contract.md +10 -8
- package/runtime/prompts/lead/report-writer.md +3 -2
- package/runtime/prompts/lead/team-contract.md +11 -9
- 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 +42 -97
- 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/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 +7 -0
- package/src/commands/execute/convergence.mjs +34 -0
|
@@ -105,6 +105,8 @@ By contrast, `sessions/claude-resume-<task-type>-<seq>.sh` is an interruption-re
|
|
|
105
105
|
|
|
106
106
|
The resolved run directory collects execution history. It divides its contents into type-specific subdirectories such as `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, and `worker-results/`, then distinguishes each run-level artifact and result file with a `-<task-type>-<seq>` suffix (a three-digit, zero-padded per-category counter, such as `001` or `002`).
|
|
107
107
|
Worker prompt history is retained not under `/tmp`, but always as a canonical artifact under `prompts/` for the current run.
|
|
108
|
+
|
|
109
|
+
The persisted prompt's `**Worker Preamble Path:**` records the selected functional audience contract: analysis uses `templates/worker-prompt-preamble.md`, implementation executor/verifier uses `templates/implementation-worker-preamble.md`, and report writing uses `templates/report-writer-prompt-preamble.md`. Every initial prompt also persists `**Worker Error Contract Path:** templates/worker-error-contract.md`. Active-run and run-context runtime resources expose the same audience map plus the shared error-contract path, so dispatch replay and context-cost accounting do not infer an audience from a provider/model name.
|
|
108
110
|
Unlike before, `analysis-profile.md`, `analysis-material.md`, `reference-expectations.md`, `task-brief.md`, skill copies, and `final-report-template.md` are not duplicated for every run.
|
|
109
111
|
These materials retain canonical copies in `instruction-set/` under the stable task root.
|
|
110
112
|
For `final-verification`, `verification-target.md` is also stable-task instruction-set state. Prepare owns the snapshot and stores its project-relative path plus SHA-256 digest in task/run manifests and active-run context. Initial analysis prompts carry the compact worktree/scope/base/head/path/digest identity and read this sidecar on demand instead of copying its diff stat.
|
|
@@ -309,12 +311,23 @@ After `okstra` runs, Claude should follow this default sequence when reading the
|
|
|
309
311
|
8. Consult `history/timeline.json` and previous run results if necessary.
|
|
310
312
|
9. As `Claude lead`, organize roles according to the current run's worker roster (`Claude worker`, `Codex worker`, and `Report writer worker` by default; `Antigravity worker` only when explicitly included).
|
|
311
313
|
10. Save each selected worker prompt under the current run's `prompts/` directory at the assigned worker prompt history path before dispatching the worker.
|
|
312
|
-
Every selected
|
|
313
|
-
11. In convergence Round 0,
|
|
314
|
+
Every selected initial analyser receives the same full-core semantic body for its task, including final-verification. Dispatch and Phase 7 validate the same normalized equality policy; implementation executor, report-writer, and `-reverify-r<N>-` prompts are separate audiences.
|
|
315
|
+
11. In convergence Round 0, the lead groups findings by semantic meaning and ticket set, then writes `state/convergence-groups-<task-type>-<seq>.json`. The deterministic engine seeds the working queue and generates each roster-aware reverify plan; lightweight reverify reads only that persisted batch and its embedded evidence.
|
|
314
316
|
12. Collect a result or terminal status for each required worker.
|
|
315
317
|
13. Unless the brief requires a more specific format, write the final Markdown report using the `final-report-template.md` structure.
|
|
316
318
|
14. Save the result directly to `reports/final-report-<task-type>-<seq>.md` for the current run and, if necessary, update `status/final-<task-type>-<seq>.status`, `manifests/run-manifest-<task-type>-<seq>.json`, `task-manifest.json`, and `task-index.md` to match the current state.
|
|
317
319
|
|
|
320
|
+
Convergence keeps its decision trail under the run's `state/` directory:
|
|
321
|
+
|
|
322
|
+
- `state/convergence-groups-<task-type>-<seq>.json` — lead-authored semantic groups and resolved analyser roster.
|
|
323
|
+
- `state/convergence-work-<task-type>-<seq>.json` — engine-owned queue, finding state, and round history.
|
|
324
|
+
- `state/convergence-round-<N>-plan-<task-type>-<seq>.json` — immutable roster-aware dispatch plan for one round.
|
|
325
|
+
- `state/convergence-round-<N>-results-<task-type>-<seq>.json` — adapter outcomes and parsed votes supplied to the reducer.
|
|
326
|
+
- `state/convergence-<task-type>-<seq>.json` — validated terminal schema v1.2 state consumed by reporting and Phase 7.
|
|
327
|
+
- `state/migrations/` — byte-for-byte archives of invalid or partial legacy state replaced during an explicit Round 0 restart.
|
|
328
|
+
|
|
329
|
+
A valid terminal legacy final is reused unchanged, and a matching valid working state resumes. Invalid new-engine working state fails closed unless seeding receives `--restart-from-round0`; an existing final can be replaced only when its migration archive still matches its original bytes.
|
|
330
|
+
|
|
318
331
|
Recommended worker status values:
|
|
319
332
|
|
|
320
333
|
- `completed`
|
package/docs/architecture.md
CHANGED
|
@@ -304,15 +304,31 @@ The standard `okstra` workflow applies the following team contract consistently
|
|
|
304
304
|
- Every attempted worker (`completed`, `timeout`, `error`) must have an assigned worker prompt history file under the current run's `prompts/` directory.
|
|
305
305
|
- An unnamed generic parallel worker is not accepted as a substitute for a required role.
|
|
306
306
|
|
|
307
|
-
###
|
|
307
|
+
### Cross-task worker prompt policy and final-verification boundaries
|
|
308
|
+
|
|
309
|
+
`PromptPlan` is the generating SSOT for functional prompt audience, equality group, packet-only input, coding-preflight eligibility, required headers, and size limits. It resolves only from task type, worker ID, the manifest's executor worker ID, and dispatch kind; provider and model identity never assign scope. The resolved analyser order used for improvement primary-pass rotation is a separate roster operation and is not a `PromptPlan` input.
|
|
310
|
+
|
|
311
|
+
The same analysis-core rule applies to `requirements-discovery`, `error-analysis`, `implementation-planning`, `improvement-discovery`, and `final-verification`: every selected initial analyser receives the same normalized semantic body and independently covers the whole common scope. In `implementation`, the implementation executor is excluded from verifier equality; all selected implementation verifiers form their own equality group. If the roster contains one verifier, individual header rules still apply, while one verifier makes normalized equality a deliberate no-op. Report-writer and reverify prompts are excluded from analysis equality groups because they author or adjudicate existing findings instead of producing an initial independent analysis.
|
|
312
|
+
|
|
313
|
+
The policy selects one audience preamble: analysis uses `templates/worker-prompt-preamble.md`; executor and verifier use `templates/implementation-worker-preamble.md`; report writing uses `templates/report-writer-prompt-preamble.md`. Every initial audience also reads the shared `templates/worker-error-contract.md`. Only implementation executor/verifier prompts receive `**Coding preflight pack:**`; a report writer never loads implementation coding instructions.
|
|
314
|
+
|
|
315
|
+
`dispatch_core.py`, `codex_dispatch.py`, and Phase 7 `validators/validate-run.py` all call `worker_prompt_contract.validate_initial_prompt_records()` so launch-time and persisted-artifact validation use the same `PromptPlan`. Report-writer prompts still receive individual common-anchor validation, while `-reverify-r<N>-` prompts keep their separate lightweight convergence contract.
|
|
308
316
|
|
|
309
317
|
Final-verification uses one shared full-core responsibility for every selected initial analysis worker. Provider/model diversity supplies independent observations of the same requirements; it does not split acceptance criteria into disjoint worker scopes. `analysis-packet.md` carries the worker-facing verification procedure, while report-only deliverable and self-review guidance stays with the report writer.
|
|
310
318
|
|
|
311
319
|
At final-verification entry, `prepare_task_bundle()` snapshots the resolved worktree, verification scope, base ref, head ref, implementation/stage report mapping, and diff stat into `instruction-set/verification-target.md`. It records the sidecar's project-relative path and `sha256:<hex>` digest in the task/run manifest and active-run context. Initial prompts carry only six compact target identity headers plus one `analysis-packet.md` path; workers open the target sidecar on demand. The coding-preflight anchor remains implementation-only, regardless of whether an initial pane is displayed with the role `verifier`.
|
|
312
320
|
|
|
313
|
-
All selected initial prompt bodies must normalize to the same semantic content. One optional shared `## Run-specific directive` is bounded to 40 nonblank lines, and larger material is placed in the instruction set.
|
|
321
|
+
All selected initial prompt bodies must normalize to the same semantic content. One optional shared `## Run-specific directive` is bounded to 40 nonblank lines, and larger material is placed in the instruction set. Final-verification adds compact target identity and size limits to the common cross-task policy.
|
|
322
|
+
|
|
323
|
+
### Deterministic convergence engine
|
|
324
|
+
|
|
325
|
+
`ConvergenceEngine` owns deterministic state transitions after Round 0 grouping: queue membership, roster-aware dispatch plans, vote reduction, classification, round history and limits, skip reasons, final state, and classification counts. The lead retains semantic grouping and evidence interpretation because those operations require judgment. Runtime adapters are transport-only: they dispatch the persisted batch and return structured terminal outcomes without recalculating engine state.
|
|
326
|
+
|
|
327
|
+
The lead writes the grouped input, then advances it through `okstra convergence seed`, `plan-round`, `apply-round`, `finalize`, and `validate`. For worker W, each generated dispatch excludes findings originating from W; resolved findings leave the queue permanently. Lightweight reverify receives only its current persisted batch and embedded evidence, not the original analysis packet, profile, brief, or instruction set. Terminal worker non-results become `verification-error`; the engine never fabricates a `DISAGREE` vote. The report writer does not vote and may consume only a validated terminal v1.2 final state.
|
|
328
|
+
|
|
329
|
+
Coverage critic and plan-body verification remain separate from finding convergence. The critic audits the integrated Round 0 analysis, while implementation-planning's plan-body gate validates the later report draft through its own `P-*` queue and state file. Neither path changes the engine's `F-*` queue.
|
|
314
330
|
|
|
315
|
-
|
|
331
|
+
Seeding provides the migration boundary for in-progress runs. A valid terminal legacy final is reused unchanged. A matching valid working state resumes. A malformed or partial legacy state is archived byte-for-byte under `state/migrations/` before an explicit Round 0 restart; an invalid new-engine working state fails closed until `--restart-from-round0` is supplied. Replacement of an existing final is allowed only while its recorded archive still matches the original bytes.
|
|
316
332
|
|
|
317
333
|
## Stable task identity
|
|
318
334
|
|
package/docs/cli.md
CHANGED
|
@@ -128,6 +128,7 @@ For standard values and phase-specific responsibilities, see [Task type](#--task
|
|
|
128
128
|
- Verdict Token: `candidates-ready` / `no-candidates` / `blocked`.
|
|
129
129
|
- Routing: there is no automatic spin-off. The user selects candidates and starts each under a new task ID with `requirements-discovery`, `implementation-planning`, or `error-analysis`.
|
|
130
130
|
- Workers: claude + codex + antigravity + report-writer are all required.
|
|
131
|
+
- Primary-pass assignment: selected analyser instances are enumerated in `requiredWorkerRoles` order, then the lead rotates the primary pass across the resolved priority lenses. Provider/model names do not affect the order, and every analyser still covers every resolved lens after its primary pass.
|
|
131
132
|
- Two bidirectional grilling points: an enhanced Step 4 in `okstra-brief-gen` with a budget of 8, and the lead's Phase 1.5 reflect-back with a budget of 12.
|
|
132
133
|
- Validator: `validators/validate_improvement_report.py` enforces the 11-part contract for an `improvement-discovery` final report.
|
|
133
134
|
- Because an `improvement-discovery` run is not in `PHASE_SEQUENCE`, the `--task-key` short form does not automatically populate `nextRecommendedPhase` for it.
|
|
@@ -634,6 +635,11 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
634
635
|
| `okstra setup --project-id <id>` | Create or update `.okstra/project.json` in the current project |
|
|
635
636
|
| `okstra check-project [--json]` | Verify that the current project is registered |
|
|
636
637
|
| `okstra preflight [--runtime <name>] [--cwd <dir>] [--json]` | Single skill-preflight call combining `ensure-installed`, with silent reinstall when stale, and `check-project` into one JSON response. Step 0 of every project-scoped skill converges on this command |
|
|
638
|
+
| `okstra convergence seed --groups <path> --work-state <path> --final-state <path> --migration-dir <dir> [--restart-from-round0]` | Create, resume, reuse, or explicitly recover deterministic convergence state |
|
|
639
|
+
| `okstra convergence plan-round --work-state <path> --plan <path>` | Persist the next roster-aware dispatch plan without mutating working state |
|
|
640
|
+
| `okstra convergence apply-round --work-state <path> --plan <path> --results <path>` | Validate one complete structured result set and atomically reduce it into working state |
|
|
641
|
+
| `okstra convergence finalize --work-state <path> --output <path>` | Materialize the terminal schema v1.2 convergence state |
|
|
642
|
+
| `okstra convergence validate --state <path> --kind <working\|final>` | Validate replayable working state or a terminal final state |
|
|
637
643
|
| `okstra config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | Manage persistent settings such as `pr-template-path` with atomic JSON writes |
|
|
638
644
|
| `okstra memory <add\|list\|search\|show\|archive>` | Manage global conversation memory in `~/.okstra/memory-book`, a user-home store separate from project `.okstra/` and the CLI basis of the `save this in okstra` natural-language skill |
|
|
639
645
|
| `okstra manager <init\|discover-projects\|new\|task>` | Public CLI for grouping cross-project okstra tasks into manager-owned context. `new project`, `new task-group`, and `new task` create manager plans; `task assign`, `task note`, `task sync`, `task status`, and `task run` manage per-project assignments and snapshots. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. Public documentation uses the full `project-id:task-group:task-id` child task key; when child task IDs differ within the same manager task, select the exact child with `--child-task-id`. `task run` does not execute the child lead directly; it returns `prepared` launch metadata/event and a child launch-context packet as JSON |
|
|
@@ -661,6 +667,8 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
661
667
|
| `okstra wizard <init\|step\|render-args\|confirmation\|outcome> --state-file <path>` | Interactive input state machine for okstra-run, implemented by `okstra_ctl.wizard`. Seed a state file with `init`, then repeatedly call `step --answer <val>` to receive the next `Prompt` JSON. `--answer` is **required**; use `--no-submit` to peek at the next prompt without submitting a response. `render-args` returns the final `render-bundle` argument map, and `confirmation` returns the user echo block. On a completed wizard, `outcome` returns `renderArgs`, `persistActions`, and `confirmationText` together; project/global release-handoff PR-template persistence appears as `persistActions[].command == "config.set"`. For an `implementation` task type, `stage_pick` follows `approved_plan_pick` and selects the stage before `executor_pick`. The brief step appears only for entry task types—requirements-discovery, error-analysis, and improvement-discovery. Downstream phases automatically carry the manifest brief, with a three-option `brief_carry` fallback when none is registered; `release-handoff` has no brief and enters multi-select `handoff_stage_pick` for eligible stage groups or the whole task |
|
|
662
668
|
| `okstra token-usage ...` | Wrap the installed `okstra-token-usage.py` to collect and substitute run token usage. Session JSONL is incrementally scanned by default through a byte-cursor cache at `$OKSTRA_HOME/cache/token-usage/`; `--no-cache` bypasses the cache and forces a full rescan as an accuracy fallback |
|
|
663
669
|
|
|
670
|
+
`okstra convergence` is an internal admin CLI used by the lead protocol, not a user-facing skill. The former `okstra-convergence` skill remains obsolete; the installed `prompts/lead/convergence.md` contract tells the lead when to invoke these operations.
|
|
671
|
+
|
|
664
672
|
> Every subcommand is wired to `PYTHONPATH` and `~/.okstra/lib/python` by the Python helper (`src/lib/python-helper.mjs`) spawned by `bin/okstra`. When invoking `python3 -m okstra_ctl.*` directly, you must configure `PYTHONPATH` yourself.
|
|
665
673
|
|
|
666
674
|
#### `okstra design-prep`
|
|
@@ -268,9 +268,9 @@ Important modules:
|
|
|
268
268
|
| `manager_store.py` | Manager-owned state mutation — project membership, task planning, assignment, directives, event append |
|
|
269
269
|
| `manager_sync.py` | One-way child project `.okstra` snapshot reader; corrupt child state becomes row-level `error` so other children continue |
|
|
270
270
|
| `manager_launch.py` | Child launch packet and manager child context renderer; records `prepared` launch metadata/events without changing project-local task state |
|
|
271
|
-
| `dispatch_core.py` | Backend-neutral worker dispatch core — worker execution/collection logic shared by any lead runtime (Claude/Codex/external); gates selected
|
|
272
|
-
| `codex_dispatch.py` | Codex lead CLI-worker dispatcher — the `okstra codex-dispatch` backend. Reads the run manifest to run the Codex-side supported worker subset, applies the same
|
|
273
|
-
| `analysis_packet.py` | assembles the compact analysis-worker input packet for a task run
|
|
271
|
+
| `dispatch_core.py` | Backend-neutral worker dispatch core — worker execution/collection logic shared by any lead runtime (Claude/Codex/external); gates selected initial prompts through the shared cross-task contract before launch |
|
|
272
|
+
| `codex_dispatch.py` | Codex lead CLI-worker dispatcher — the `okstra codex-dispatch` backend. Reads the run manifest to run the Codex-side supported worker subset, applies the same cross-task initial-prompt gate, and performs token-usage substitution, view render, follow-up, and validation |
|
|
273
|
+
| `analysis_packet.py` | assembles the compact analysis-worker input packet for a task run from worker-owned profile sections; report/lead procedure stays outside the packet |
|
|
274
274
|
| `context_cost.py` | read-side context-cost estimator for a prepared okstra task bundle (the `okstra context-cost` backend) |
|
|
275
275
|
| `schema_excerpt.py` | generates a task-type-scoped excerpt of the final-report schema — a schema reduction to inject into the worker/lead prompt |
|
|
276
276
|
| `work_categories.py` | requirements-discovery work-category (domain) **SSOT** (`is_valid_category`) — the work-category allowlist is defined only here |
|
|
@@ -279,7 +279,12 @@ Important modules:
|
|
|
279
279
|
| `lead_events.py` | structured JSONL events emitted by non-Claude lead runtimes |
|
|
280
280
|
| `team_reconcile.py` | stale team-member reconciliation at run-end teardown |
|
|
281
281
|
| `worker_prompt_headers.py` | shared rendering of phase-aware worker prompt anchors (`worker_prompt_headers`): coding-preflight only for implementation and compact target identity for final-verification |
|
|
282
|
-
| `
|
|
282
|
+
| `worker_prompt_body.py` | provider-neutral initial analysis body/input renderer shared by Codex and external/team dispatch paths |
|
|
283
|
+
| `worker_prompt_policy.py` | `PromptPlan` generating SSOT — resolves functional audience, equality group, packet-only input, coding-preflight eligibility, required headers, and size limits without consulting provider/model identity |
|
|
284
|
+
| `worker_prompt_contract.py` | deterministic cross-task initial-prompt validator and normalized cross-worker equality SSOT, reused by dispatch adapters and the Phase 7 persisted-artifact validator |
|
|
285
|
+
| `convergence_engine.py` | pure `ConvergenceEngine` reducer — seeds Round 0 working state, plans roster-aware rounds, applies structured outcomes, finalizes schema v1.2, and validates replayable state without dispatch or filesystem ownership |
|
|
286
|
+
| `convergence_store.py`, `convergence_migration.py` | atomic JSON persistence plus legacy/new-engine seed decisions; valid terminal finals are reused, while invalid state requires byte-preserving archival before restart |
|
|
287
|
+
| `convergence.py` | `okstra convergence` internal CLI orchestration for `seed`, `plan-round`, `apply-round`, `finalize`, and `validate`; it composes the reducer, store, and migration policy without duplicating their decisions |
|
|
283
288
|
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar written by `okstra-wrapper-status.py` (the heartbeat writer) |
|
|
284
289
|
| `task_target.py` | shared helper resolving `task-key → (task_root, project_root)` (`resolve_task_root`) |
|
|
285
290
|
| `graphify_cmd.py` | scope wrapper for the okstra-graphify skill — `resolve_scope` + `assemble` + `okstra graphify` subcommand dispatch. Forces the corpus to `.okstra` and outputs to `.okstra/graph/` |
|
|
@@ -321,6 +326,10 @@ Token/cost accounting:
|
|
|
321
326
|
| `templates/reports/report.css`, `report.js` | Inline assets for self-contained HTML report view |
|
|
322
327
|
| `templates/reports/*.template.md` | Inputs, schedule, user-response, settings templates |
|
|
323
328
|
| `templates/project-docs/task-index.template.md` | Project task index template |
|
|
329
|
+
| `templates/worker-prompt-preamble.md` | Initial analysis audience procedure and output contract |
|
|
330
|
+
| `templates/implementation-worker-preamble.md` | Shared implementation executor/verifier procedure, including coding-preflight and worktree rules |
|
|
331
|
+
| `templates/report-writer-prompt-preamble.md` | Report-writer input and authoring procedure without analysis or implementation instructions |
|
|
332
|
+
| `templates/worker-error-contract.md` | Audience-neutral error-path, sidecar schema, and write protocol shared by every initial worker |
|
|
324
333
|
|
|
325
334
|
### 4.8 `schemas/`
|
|
326
335
|
|
|
@@ -430,7 +439,7 @@ Single-stage `final-verification --stage <N>` reuses the matching implementation
|
|
|
430
439
|
Current report pipeline:
|
|
431
440
|
|
|
432
441
|
1. Analysis workers write worker result files.
|
|
433
|
-
2.
|
|
442
|
+
2. The lead writes semantic groups; the convergence engine persists working state, per-round plans/results, and then a validated `state/convergence-<task-type>-<seq>.json` v1.2 terminal state.
|
|
434
443
|
3. Report-writer worker writes `reports/final-report-<task-type>-<seq>.data.json`.
|
|
435
444
|
4. `scripts/okstra-render-final-report.py` renders Markdown.
|
|
436
445
|
5. Token usage substitution fills usage/cost cells.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -149,14 +149,14 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Ant
|
|
|
149
149
|
|
|
150
150
|
Before invoking the Antigravity CLI, you MUST:
|
|
151
151
|
|
|
152
|
-
1. Extract
|
|
152
|
+
1. Extract `**Worker Preamble Path:**` and `**Worker Error Contract Path:**` and verify the CLI run will Read both selected files end-to-end. The first owns audience procedure; the second owns sidecar schema and write rules. Persist and forward both anchors unchanged; never substitute the analysis preamble for an implementation audience. **Exception — `-reverify-r<N>-` dispatches**: a Phase 5.5 re-verification prompt deliberately omits both reading contracts and uses its lightweight prompt contract; do NOT return a sentinel for those two omitted reading anchors. The `**Errors log path:**` / `**Errors sidecar path:**` gate still applies.
|
|
153
153
|
2. Verify the lead's prompt body lists the per-run primary input files under `## Inputs` (normally `analysis-packet.md` for analysis workers). The source files named inside that packet are fallback/evidence paths to open when needed. Analysis workers do NOT read `final-report-template.md` — that file is for the report writer only.
|
|
154
154
|
|
|
155
|
-
The CLI writes a Reading Confirmation block to the **audit sidecar** at `runs/<task-type>/worker-results/antigravity-worker-audit-<task-type>-<seq>.md`. The sidecar's body begins with `# Antigravity Worker Audit — <task-key>` followed by one short line per input file confirming end-to-end reading.
|
|
155
|
+
The CLI writes a Reading Confirmation block to the **audit sidecar** at `runs/<task-type>/worker-results/antigravity-worker-audit-<task-type>-<seq>.md`. The sidecar's body begins with `# Antigravity Worker Audit — <task-key>` followed by one short line per input file confirming end-to-end reading. Placement follows the selected audience preamble's `Required reading` section. If any file was skipped, record a `tool-failure` in the errors sidecar instead of fabricating Findings.
|
|
156
156
|
|
|
157
157
|
## Worker Output Structure
|
|
158
158
|
|
|
159
|
-
The Antigravity CLI — not this wrapper — produces the worker result.
|
|
159
|
+
The Antigravity CLI — not this wrapper — produces the worker result. It follows the audience-selected preamble and, for implementation, the executor/verifier role sidecar. Analysis output uses sections 1–5 plus optional Section 6; implementation output follows its sidecar. This wrapper forwards output unmodified except for the single `**Model:**` line (step 8d).
|
|
160
160
|
|
|
161
161
|
## Error reporting
|
|
162
162
|
|
|
@@ -58,8 +58,8 @@ Unlike the Codex / Antigravity workers, you are an in-process Claude subagent
|
|
|
58
58
|
|
|
59
59
|
Before producing any output, you MUST:
|
|
60
60
|
|
|
61
|
-
1. Extract
|
|
62
|
-
2. Read every primary input file the lead enumerated under `## Inputs` (or equivalent heading)
|
|
61
|
+
1. Extract `**Worker Preamble Path:**` and `**Worker Error Contract Path:**` from the lead prompt and Read both selected files end-to-end with one full-file `Read` each. The preamble owns audience procedure; the error contract owns sidecar schema and write rules. Never replace the selected path with a hard-coded analysis preamble.
|
|
62
|
+
2. Read every primary input file the lead enumerated under `## Inputs` (or equivalent heading) end-to-end, following the selected preamble. Analysis workers normally receive `analysis-packet.md`; implementation workers receive their role sidecar and approved deliverable inputs.
|
|
63
63
|
|
|
64
64
|
**Heartbeat — write the audit sidecar EARLY and APPEND per stage (BLOCKING).** This worker runs as an in-process Agent or a fresh-session tmux pane, so the lead has no `BashOutput`-style liveness signal while it waits for your return — the audit sidecar is the only signal that survives a silent hang.
|
|
65
65
|
|
|
@@ -71,7 +71,7 @@ Before producing any output, you MUST:
|
|
|
71
71
|
|
|
72
72
|
## Worker Output Structure
|
|
73
73
|
|
|
74
|
-
Follow the
|
|
74
|
+
Follow the output contract selected for your audience. Analysis workers use the analysis preamble's sections 1–5 plus optional Section 6; implementation executor/verifier workers use the implementation preamble plus their role sidecar. Set `workerId: "claude"`.
|
|
75
75
|
|
|
76
76
|
## Stop Condition (BLOCKING)
|
|
77
77
|
|
|
@@ -93,7 +93,7 @@ If you find yourself thinking "let me double-check section 3" or "I should read
|
|
|
93
93
|
|
|
94
94
|
## Error reporting
|
|
95
95
|
|
|
96
|
-
Record your own tool failures per the
|
|
96
|
+
Record your own tool failures per the file selected by `**Worker Error Contract Path:**`: extract `**Errors sidecar path:**` from the dispatch prompt (return `CLAUDE_WORKER_ERRORS_PATH_MISSING` without proceeding if absent), then append `tool-failure` entries exactly as that shared contract requires. This worker has no external CLI, so MCP and Bash failures use the same sidecar protocol.
|
|
97
97
|
|
|
98
98
|
## Notes
|
|
99
99
|
|
|
@@ -149,14 +149,14 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Cod
|
|
|
149
149
|
|
|
150
150
|
Before invoking the Codex CLI, you MUST:
|
|
151
151
|
|
|
152
|
-
1. Extract
|
|
152
|
+
1. Extract `**Worker Preamble Path:**` and `**Worker Error Contract Path:**` and verify the CLI run will Read both selected files end-to-end. The first owns audience procedure; the second owns sidecar schema and write rules. Persist and forward both anchors unchanged; never substitute the analysis preamble for an implementation audience. **Exception — `-reverify-r<N>-` dispatches**: a Phase 5.5 re-verification prompt deliberately omits both reading contracts and uses its lightweight prompt contract; do NOT return a sentinel for those two omitted reading anchors. The `**Errors log path:**` / `**Errors sidecar path:**` gate still applies.
|
|
153
153
|
2. Verify the lead's prompt body lists the per-run primary input files under `## Inputs` (normally `analysis-packet.md` for analysis workers). The source files named inside that packet are fallback/evidence paths to open when needed. Analysis workers do NOT read `final-report-template.md` — that file is for the report writer only.
|
|
154
154
|
|
|
155
|
-
The CLI writes a Reading Confirmation block to the **audit sidecar** at `runs/<task-type>/worker-results/codex-worker-audit-<task-type>-<seq>.md`. The sidecar's body begins with `# Codex Worker Audit — <task-key>` followed by one short line per input file confirming end-to-end reading.
|
|
155
|
+
The CLI writes a Reading Confirmation block to the **audit sidecar** at `runs/<task-type>/worker-results/codex-worker-audit-<task-type>-<seq>.md`. The sidecar's body begins with `# Codex Worker Audit — <task-key>` followed by one short line per input file confirming end-to-end reading. Placement follows the selected audience preamble's `Required reading` section. If any file was skipped, record a `tool-failure` in the errors sidecar instead of fabricating Findings.
|
|
156
156
|
|
|
157
157
|
## Worker Output Structure
|
|
158
158
|
|
|
159
|
-
The Codex CLI — not this wrapper — produces the worker result.
|
|
159
|
+
The Codex CLI — not this wrapper — produces the worker result. It follows the audience-selected preamble and, for implementation, the executor/verifier role sidecar. Analysis output uses sections 1–5 plus optional Section 6; implementation output follows its sidecar. This wrapper forwards output unmodified except for the single `**Model:**` line (step 8d).
|
|
160
160
|
|
|
161
161
|
## Error reporting
|
|
162
162
|
|
|
@@ -62,8 +62,8 @@ Do NOT duplicate the data.json contents here — the data.json is the canonical
|
|
|
62
62
|
|
|
63
63
|
Before writing the data.json, you MUST:
|
|
64
64
|
|
|
65
|
-
1. Extract
|
|
66
|
-
2. Read every input file the lead enumerated under `## Inputs` (or equivalent heading)
|
|
65
|
+
1. Extract `**Worker Preamble Path:**` and `**Worker Error Contract Path:**`; Read the selected report-writer preamble and shared error contract end-to-end. Do not substitute the analysis or implementation preamble.
|
|
66
|
+
2. Read every input file the lead enumerated under `## Inputs` (or equivalent heading) end-to-end (single `Read` call with no `offset`/`limit`; page explicitly only when required).
|
|
67
67
|
|
|
68
68
|
For the report writer specifically, the `## Inputs` list always includes:
|
|
69
69
|
|
|
@@ -75,7 +75,7 @@ For the report writer specifically, the `## Inputs` list always includes:
|
|
|
75
75
|
|
|
76
76
|
For the carry-in `clarification-response.md` (if present), walk every row of `## 1. Clarification Items` including rows whose `User input` cell is blank — a blank cell with `Status=open` is a signal you must surface in the conditional `## 0. Clarification Response Carried In From Previous Run` section (the template's `RENDER_IF` guard activates it when the carry-in path is non-empty). When no carry-in path was provided, OMIT the `## 0.` heading entirely — do NOT write an empty-state stub.
|
|
77
77
|
|
|
78
|
-
Write a Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md`, per the
|
|
78
|
+
Write a Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/report-writer-worker-audit-<task-type>-<seq>.md`, per the selected report-writer preamble's `Required reading` section (the main final-report and worker-results files carry no Section 0 heading). If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating the report.
|
|
79
79
|
|
|
80
80
|
## Authoring Contract
|
|
81
81
|
|
|
@@ -92,7 +92,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
|
|
|
92
92
|
- **§7 phase-continuation row (mandatory for non-terminal task-types).** When `header.taskType` is one of `requirements-discovery` / `implementation-planning` / `error-analysis` / `implementation` / `final-verification`, `followUpTasks` MUST contain at least one row whose `origin` is `phase-continuation`, `suggestedTaskType` equals the next phase (byte-identical to `finalVerdict.nextStep`'s referenced phase), `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. Schema `allOf` clause enforces this via `contains`.
|
|
93
93
|
- **No deprecated sections.** The schema has no `4.5.8 User Approval Request` body field, no `4.5.9 Open Questions`, no `5.1 Additional Material Request`, no `5.2 User Confirmation Questions` — clarifications go under the unified `clarificationItems[]` array.
|
|
94
94
|
- **Optional Section 0.** Include `clarificationCarryIn` ONLY when the lead's prompt provides a non-empty carry-in path. Omit the key entirely otherwise (do NOT set it to `null` or an empty object).
|
|
95
|
-
- **Reading Confirmation** goes in the audit sidecar per the preamble
|
|
95
|
+
- **Reading Confirmation** goes in the audit sidecar per the selected report-writer preamble's `Required reading` section — never in the data.json or the main worker-results file.
|
|
96
96
|
- Include all four convergence categories. The schema's `crossVerification.consensus` / `.differences` arrays carry full / partial / contested / worker-unique items; do not omit any.
|
|
97
97
|
- Convergence round history goes in `crossVerification.roundHistory.rounds[]` with `round2SkippedReason`. When convergence is disabled, set `crossVerification.roundHistory` to `{"disabled": true}`. Values come verbatim from `state/convergence-<task-type>-<seq>.json` — do not recompute.
|
|
98
98
|
- `verification-error` votes are their own verdict (`planItems[].verdicts[].verdict` enum); they are NOT folded into AGREE / DISAGREE counts.
|
|
@@ -114,7 +114,7 @@ data.json written to <abs path>; markdown rendered to <abs path>. Sections popul
|
|
|
114
114
|
|
|
115
115
|
## Error reporting
|
|
116
116
|
|
|
117
|
-
Record tool failures
|
|
117
|
+
Record tool failures through the file selected by `**Worker Error Contract Path:**`. If `**Errors sidecar path:**` is absent, return `REPORT_WRITER_ERRORS_PATH_MISSING` and stop; otherwise use the shared schema and append protocol exactly. This worker has no external CLI.
|
|
118
118
|
|
|
119
119
|
## Notes
|
|
120
120
|
|
|
@@ -46,12 +46,13 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
|
|
|
46
46
|
- Missing or unsupported family-token mapping is a pre-dispatch contract failure. Never inherit the lead model, choose a nearby alias, or switch provider silently.
|
|
47
47
|
- Every analysis dispatch sets `name: "<workerId>-worker"`; convergence retries append `-reverify-r<N>`, implementation uses the functional `-executor` / `-verifier` suffix, and report writing uses `report-writer`. These values are retained as `agentName` in session JSONL for usage attribution.
|
|
48
48
|
- Every Codex / Antigravity prompt includes `**Pane role:** <functional-role>` so the wrapper's optional fifth argument names both its caller pane and trace pane.
|
|
49
|
-
- The Agent SDK
|
|
49
|
+
- The Agent SDK may supply transport metadata through the in-process worker definition, but the persisted semantic prompt body and primary analysis-packet input remain identical to the CLI-wrapper workers after permitted identity/path normalization.
|
|
50
50
|
- A retry keeps the same Agent `name`. When logging a twice-failed CLI-wrapper attempt, reference both attempts' `bash_ids` and prompt-history paths.
|
|
51
51
|
- An internally detected contract violation without a specific worker uses `--agent "claude-lead"` in the error-log event.
|
|
52
52
|
|
|
53
53
|
### Reverify, critic, and report-writer assignments
|
|
54
54
|
|
|
55
|
+
- For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
|
|
55
56
|
- Reverify dispatch uses a fresh one-shot `Agent(...)` call named `<workerId>-worker-reverify-r<N>`. Preserve the initial worker's definition and map an in-process Claude assignment's `modelExecutionValue` to its exact family token; CLI-wrapper assignments remain `inherit` at the Agent layer and apply the exact model in their wrapper.
|
|
56
57
|
- Critic dispatch uses `name: "<provider>-worker-critic"`, `dispatchKind: "critic"`, and the exact mapped model from `config.critic.modelExecutionValue`. If that value cannot be mapped, record `critic-skipped: model-unresolved` and do not dispatch.
|
|
57
58
|
- Report-writer dispatch uses `name: "report-writer"` and maps the roster assignment's `modelExecutionValue` to the supported family token. The prompt's `**Model:**` header must carry the same execution value.
|
|
@@ -33,6 +33,7 @@ This adapter maps the neutral Okstra lead operations to the Codex artifact-first
|
|
|
33
33
|
|
|
34
34
|
## Codex dispatch details
|
|
35
35
|
|
|
36
|
+
- For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
|
|
36
37
|
- Do not invoke Claude Code team or subagent tools.
|
|
37
38
|
- The prepared run manifest and team-state are the dispatch authority. Unsupported explicitly requested workers fail; an adapter must not silently change the roster.
|
|
38
39
|
- Report-writer execution keeps the existing explicit opt-in policy in this milestone: dispatch requires `--enable-codex-report-writer` and an explicit `--report-writer-codex-model` value.
|
|
@@ -33,6 +33,7 @@ This adapter maps the neutral Okstra lead operations to a generic host using Oks
|
|
|
33
33
|
|
|
34
34
|
## External dispatch details
|
|
35
35
|
|
|
36
|
+
- For convergence reverify, consume the persisted round plan exactly. This adapter may map and transport each returned batch, but it cannot change batch membership and does not classify findings or branch on task type, provider, or model identity.
|
|
36
37
|
- Do not invoke Claude Code team tools or `okstra codex-dispatch`.
|
|
37
38
|
- Worker completion is valid only from `workerDispatches[]`, terminal status sidecars, and required Result Paths. Pane creation alone is not completion.
|
|
38
39
|
- Reverify uses a fresh jobs file at `runs/<task-type>/state/reverify-jobs-r<N>-<task-type>-<seq>.json`, sets `dispatchKind: "reverify-r<N>"`, and dispatches with `okstra team dispatch --project-root <root> --run-manifest <path> --dispatch-kind reverify-r<N> --jobs-file <jobs-file>`.
|
|
@@ -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)
|