okstra 0.130.2 → 0.130.3
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.md +7 -1
- package/docs/cli.md +10 -2
- package/docs/project-structure-overview.md +16 -9
- package/docs/task-process/implementation-planning.md +11 -5
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +3 -1
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/agents/workers/codex-worker.md +3 -1
- package/runtime/agents/workers/report-writer-worker.md +8 -4
- package/runtime/prompts/lead/adapters/claude-code.md +2 -2
- package/runtime/prompts/lead/convergence.md +44 -21
- package/runtime/prompts/lead/okstra-lead-contract.md +9 -2
- package/runtime/prompts/lead/plan-body-verification.md +55 -12
- package/runtime/prompts/lead/report-writer.md +16 -15
- package/runtime/prompts/lead/team-contract.md +8 -6
- package/runtime/prompts/profiles/implementation-planning.md +10 -2
- package/runtime/python/okstra_ctl/codex_dispatch.py +5 -1
- package/runtime/python/okstra_ctl/convergence.py +121 -1
- package/runtime/python/okstra_ctl/convergence_engine.py +903 -13
- package/runtime/python/okstra_ctl/convergence_migration.py +9 -1
- package/runtime/python/okstra_ctl/dispatch_core.py +13 -0
- package/runtime/python/okstra_ctl/plan_items.py +203 -0
- package/runtime/python/okstra_ctl/plan_items_cli.py +81 -0
- package/runtime/python/okstra_ctl/worker_artifact_paths.py +23 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +4 -4
- package/runtime/python/okstra_ctl/worker_prompt_body.py +1 -1
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +2 -1
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +14 -0
- package/runtime/schemas/convergence-critic-results-v1.0.schema.json +57 -0
- package/runtime/schemas/convergence-groups-v1.0.schema.json +109 -0
- package/runtime/schemas/convergence-round-results-v1.0.schema.json +55 -0
- package/runtime/schemas/final-report-v1.0.schema.json +21 -2
- package/runtime/templates/report-writer-prompt-preamble.md +5 -3
- package/runtime/templates/reports/final-report.template.md +1 -1
- package/runtime/templates/worker-prompt-preamble.md +8 -7
- package/runtime/validators/validate-run.py +154 -118
- package/runtime/validators/validate_session_conformance.py +66 -23
- package/src/cli-registry.mjs +7 -0
- package/src/commands/execute/convergence.mjs +6 -1
- package/src/commands/execute/plan-items.mjs +9 -0
- package/src/commands/inspect/worker-liveness.mjs +2 -2
package/docs/architecture.md
CHANGED
|
@@ -324,10 +324,16 @@ All selected initial prompt bodies must normalize to the same semantic content.
|
|
|
324
324
|
|
|
325
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
326
|
|
|
327
|
-
The
|
|
327
|
+
The complete artifact lifecycle is: worker results → Round 0 grouping → reducer queues only non-consensus findings → analyser-instance re-verification → optional critic gap reducer transition → report-writer data.json → deterministic plan-item extraction → plan-body verifier round → final render/validation. Initial workers write their findings to the assigned Result Path and their reading confirmation to the generated `Audit sidecar path`; the sidecar is evidence of input reading, not a source of findings.
|
|
328
|
+
|
|
329
|
+
Cross-verification does not mean that worker A reviews worker B's entire result. Round 0 records multi-source agreement immediately, and the reducer asks independent analyser instances to vote only on single-source or still-unresolved findings selected in the persisted queue. The report writer is never a voter. It organizes the validated result, while the later plan-body round verifies the consolidated `P-*` plan items rather than reopening the `F-*` finding queue.
|
|
330
|
+
|
|
331
|
+
The lead writes the grouped input, then advances it through the internal admin CLI operations `okstra convergence seed`, `plan-round`, `apply-round`, optional `apply-critic-gaps`, `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 and completed per-finding `UNVERIFIABLE` responses become `verification-error`; the engine never fabricates a `DISAGREE` vote. The report writer does not vote and consumes only a validated terminal state. Newly finalized convergence output is schema v1.3; under the compatibility path, valid historical final schema versions v1.0, v1.1, or v1.2 are reused and consumed without rewrite.
|
|
328
332
|
|
|
329
333
|
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.
|
|
330
334
|
|
|
335
|
+
`okstra convergence` and `okstra plan-items` are lead-contract admin interfaces, not public skill entry points. The former `okstra-convergence` skill stays obsolete; these commands do not expand the installed public skill roster.
|
|
336
|
+
|
|
331
337
|
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.
|
|
332
338
|
|
|
333
339
|
## Stable task identity
|
package/docs/cli.md
CHANGED
|
@@ -639,8 +639,12 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
639
639
|
| `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 |
|
|
640
640
|
| `okstra convergence plan-round --work-state <path> --plan <path>` | Persist the next roster-aware dispatch plan without mutating working state |
|
|
641
641
|
| `okstra convergence apply-round --work-state <path> --plan <path> --results <path>` | Validate one complete structured result set and atomically reduce it into working state |
|
|
642
|
-
| `okstra convergence
|
|
642
|
+
| `okstra convergence apply-critic-gaps --work-state <path> --results <path>` | Apply one verified coverage-critic batch after the main queue reaches a terminal state |
|
|
643
|
+
| `okstra convergence finalize --work-state <path> --output <path>` | Materialize the terminal schema v1.3 convergence state |
|
|
643
644
|
| `okstra convergence validate --state <path> --kind <working\|final>` | Validate replayable working state or a terminal final state |
|
|
645
|
+
| `okstra convergence example --kind <groups\|round-results\|critic-results>` | Print one deterministic valid input example as JSON |
|
|
646
|
+
| `okstra plan-items extract --data <data.json> --output <items.json>` | Deterministically extract the complete implementation-planning `P-*` queue from report-writer data.json |
|
|
647
|
+
| `okstra plan-items validate --data <data.json> --items <items.json>` | Require the persisted `P-*` queue to match a fresh deterministic extraction exactly |
|
|
644
648
|
| `okstra config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | Manage persistent settings such as `pr-template-path` with atomic JSON writes |
|
|
645
649
|
| `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 |
|
|
646
650
|
| `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 |
|
|
@@ -670,7 +674,11 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
670
674
|
| `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 |
|
|
671
675
|
| `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 |
|
|
672
676
|
|
|
673
|
-
|
|
677
|
+
The convergence state lifecycle is `groups v1.0 → work v1.0 → final v1.3`; round-plan, round-results, and optional critic-results v1.0 artifacts provide the auditable transitions between those endpoints.
|
|
678
|
+
|
|
679
|
+
`okstra convergence apply-critic-gaps` is the only transition that may add verified coverage gaps to terminal main-queue state. `okstra plan-items extract` creates the complete plan queue, and `okstra plan-items validate` rejects any omission or drift before verifier dispatch.
|
|
680
|
+
|
|
681
|
+
`okstra convergence` and `okstra plan-items` are internal admin CLI families used by the lead protocol. Each is an internal admin CLI, not a user-facing skill, and their presence does not add a public skill. The former `okstra-convergence` skill remains obsolete; the installed `prompts/lead/convergence.md` and `prompts/lead/plan-body-verification.md` contracts tell the lead when to invoke these operations.
|
|
674
682
|
|
|
675
683
|
> 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.
|
|
676
684
|
|
|
@@ -107,12 +107,14 @@ So `runtime/` is not the only npm-published content. It is the install payload c
|
|
|
107
107
|
| `scripts/okstra_ctl` | `runtime/python/okstra_ctl` |
|
|
108
108
|
| `scripts/okstra_token_usage` | `runtime/python/okstra_token_usage` |
|
|
109
109
|
| `scripts/okstra_vendor` | `runtime/python/okstra_vendor` |
|
|
110
|
-
| `scripts/lib` | `runtime/
|
|
110
|
+
| `scripts/lib` | `runtime/bin/lib` |
|
|
111
111
|
| selected `scripts/okstra*.sh` / `*.py` entrypoints | `runtime/bin/` |
|
|
112
112
|
| `agents`, `prompts`, `schemas`, `templates`, `validators`, `skills` | same relative tree under `runtime/` |
|
|
113
113
|
|
|
114
114
|
`npm run build` and `prepack` both run this sync. Never hand-edit `runtime/`.
|
|
115
115
|
|
|
116
|
+
The public manuals under `docs/` are selected directly by `package.json` for npm publication; npm-published source documentation is not copied into `runtime/docs/`. The install payload receives the operating contracts it needs through the explicit `prompts/`, `templates/`, and `schemas/` sync rows above.
|
|
117
|
+
|
|
116
118
|
Runtime/install asset changes follow this checklist:
|
|
117
119
|
|
|
118
120
|
1. Add or edit the source asset under `scripts/`, `skills/`, `agents/`, `prompts/`, `schemas`, `templates`, or `validators`.
|
|
@@ -177,7 +179,8 @@ Runtime/install asset changes follow this checklist:
|
|
|
177
179
|
| `run` | `src/commands/execute/run.mjs` | Host-aware execution front door (`auto` → Claude/Codex/external path selection) |
|
|
178
180
|
| `codex-run`, `codex-dispatch` | `src/commands/execute/codex-*.mjs` | Codex lead dry-run bundle preparation and CLI-backed worker dispatch |
|
|
179
181
|
| `team` | `src/commands/execute/team.mjs` | External lead tmux-pane worker dispatch / await / teardown |
|
|
180
|
-
| `convergence` | `src/commands/execute/convergence.mjs` | Internal admin CLI for the deterministic Phase 5.5 convergence engine (`seed`/`plan-round`/`apply-round`/`finalize`/`validate`; Python: `okstra_ctl.convergence`) |
|
|
182
|
+
| `convergence` | `src/commands/execute/convergence.mjs` | Internal admin CLI for the deterministic Phase 5.5 convergence engine (`seed`/`plan-round`/`apply-round`/`apply-critic-gaps`/`finalize`/`validate`/`example`; Python: `okstra_ctl.convergence`) |
|
|
183
|
+
| `plan-items` | `src/commands/execute/plan-items.mjs` | Internal admin CLI for deterministic plan-body item extraction and exact-match validation (`extract`/`validate`; Python: `okstra_ctl.plan_items_cli`) |
|
|
181
184
|
| `report-finalize` | `src/commands/report/finalize.mjs` | Run the whole Phase 7 post-report sequence in contractual order (Python: `okstra_ctl.report_finalize`) — the single reference point shared with the Codex lead adapter |
|
|
182
185
|
| `render-views` | `src/commands/report/render-views.mjs` | Generate the self-contained HTML report view |
|
|
183
186
|
| `render-final-report`, `inject-report-index` | `src/commands/report/*.mjs` | Render final-report Markdown from data.json and inject top-of-report index anchors |
|
|
@@ -287,9 +290,10 @@ Important modules:
|
|
|
287
290
|
| `worker_prompt_body.py` | provider-neutral initial analysis body/input renderer shared by Codex and external/team dispatch paths |
|
|
288
291
|
| `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 |
|
|
289
292
|
| `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 |
|
|
290
|
-
| `convergence_engine.py` | pure `ConvergenceEngine` reducer — seeds Round 0 working state, plans roster-aware rounds, applies structured outcomes, finalizes schema v1.
|
|
293
|
+
| `convergence_engine.py` | pure `ConvergenceEngine` reducer — seeds Round 0 working state, plans roster-aware rounds, applies structured outcomes and one critic-gap batch, finalizes schema v1.3, and validates replayable state without dispatch or filesystem ownership |
|
|
291
294
|
| `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 |
|
|
292
|
-
| `convergence.py` | `okstra convergence` internal CLI orchestration for `seed`, `plan-round`, `apply-round`, `finalize`, and `
|
|
295
|
+
| `convergence.py` | `okstra convergence` internal CLI orchestration for `seed`, `plan-round`, `apply-round`, `apply-critic-gaps`, `finalize`, `validate`, and `example`; it composes the reducer, store, and migration policy without duplicating their decisions |
|
|
296
|
+
| `plan_items.py`, `plan_items_cli.py` | deterministic extraction of the report-writer data.json `P-*` plan-item queue plus the `okstra plan-items extract` / `validate` adapter |
|
|
293
297
|
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `token-usage` → `render-views` → `spawn-followups` → `validate-run` in that load-bearing order, stops at the first non-zero exit and names the failing step. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
|
|
294
298
|
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar written by `okstra-wrapper-status.py` (the heartbeat writer) |
|
|
295
299
|
| `task_target.py` | shared helper resolving `task-key → (task_root, project_root)` (`resolve_task_root`) |
|
|
@@ -341,6 +345,8 @@ Token/cost accounting:
|
|
|
341
345
|
|
|
342
346
|
`schemas/final-report-v1.0.schema.json` is the final-report data.json contract. The report-writer worker writes `final-report-<task-type>-<seq>.data.json`; the renderer produces Markdown from that JSON.
|
|
343
347
|
|
|
348
|
+
The deterministic convergence inputs are `schemas/convergence-groups-v1.0.schema.json`, `schemas/convergence-round-results-v1.0.schema.json`, and `schemas/convergence-critic-results-v1.0.schema.json`. `tools/build.mjs` syncs the entire source `schemas/` directory to `runtime/schemas/`; these JSON Schema files are runtime contracts, not Markdown publication-inventory entries.
|
|
349
|
+
|
|
344
350
|
Optional (v1.0 backward-compatible) top-level keys:
|
|
345
351
|
|
|
346
352
|
- `readerSummary` — the summary block a human reads first. When present, all five fields (`decision`, `humanActionRequired`, `blockingItems`, `safeToSkip`, `recommendedCommand`) are required. Existing data.json without it still renders as-is (the HTML dashboard falls back to `verdictCard`).
|
|
@@ -444,12 +450,13 @@ Single-stage `final-verification --stage <N>` reuses the matching implementation
|
|
|
444
450
|
|
|
445
451
|
Current report pipeline:
|
|
446
452
|
|
|
447
|
-
1. Analysis workers write worker result files
|
|
448
|
-
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
|
|
453
|
+
1. Analysis workers write worker result files and the separate audit sidecars named by `Audit sidecar path`.
|
|
454
|
+
2. The lead writes semantic groups; the convergence engine persists working state, per-round plans/results, an optional critic transition, and then a validated `state/convergence-<task-type>-<seq>.json` terminal state: schema v1.3 when newly finalized, or an unchanged historical final schema v1.0, v1.1, or v1.2 returned by `reuse-final`.
|
|
449
455
|
3. Report-writer worker writes `reports/final-report-<task-type>-<seq>.data.json`.
|
|
450
|
-
4. `
|
|
451
|
-
5.
|
|
452
|
-
6.
|
|
456
|
+
4. For implementation-planning, `okstra plan-items extract` creates the complete `P-*` queue, `validate` proves it still matches data.json, and the analyser instances run the separate plan-body verification round.
|
|
457
|
+
5. `scripts/okstra-render-final-report.py` renders Markdown.
|
|
458
|
+
6. Token usage substitution fills usage/cost cells.
|
|
459
|
+
7. `scripts/okstra-render-report-views.py` emits the self-contained `.html` view, and run validation checks the final artifacts.
|
|
453
460
|
|
|
454
461
|
The Markdown is derived, not the authoring source. The schema is the contract.
|
|
455
462
|
|
|
@@ -64,17 +64,23 @@ flowchart TD
|
|
|
64
64
|
P1[Phase 1 intake] --> P2[Phase 2 prompts]
|
|
65
65
|
P2 --> P3[Phase 3 TeamCreate]
|
|
66
66
|
P3 --> P4[Phase 4/5 analyser dispatch]
|
|
67
|
-
P4 -->
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
P4 --> A[Worker results + Audit sidecar path]
|
|
68
|
+
A --> G[Round 0 grouping]
|
|
69
|
+
G --> C[Reducer queue + analyser-instance re-verification]
|
|
70
|
+
C --> Critic[Optional critic gap reducer transition]
|
|
71
|
+
Critic --> RW[Phase 6 report-writer data.json]
|
|
72
|
+
RW --> Extract[Deterministic plan-item extraction]
|
|
73
|
+
Extract --> PBV[Phase 6 sub-step<br/>Plan-body verifier round]
|
|
70
74
|
PBV --> Gate{gate result}
|
|
71
75
|
Gate -->|passed / passed-with-dissent| Approval[render top Approval checkbox]
|
|
72
76
|
Gate -->|blocked-by-disagreement / aborted-non-result| NoApproval[render block without checkbox]
|
|
73
|
-
Approval --> P7[Phase 7
|
|
77
|
+
Approval --> P7[Phase 7 persistence/finalization<br/>canonical Markdown render<br/>HTML render + validate-run<br/>via okstra report-finalize]
|
|
74
78
|
NoApproval --> P7
|
|
75
79
|
```
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
The artifact sequence is worker results and `Audit sidecar path` → Round 0 grouping → reducer-owned finding queue → analyser-instance re-verification → optional critic transition → report-writer data.json → deterministic plan-item extraction → plan-body verifier round → Phase 7 persistence/finalization. Phase 7 calls `okstra report-finalize`; token substitution produces the canonical Markdown render, followed by HTML render, follow-up materialization, and `validate-run`. The reducer queues only non-consensus findings; it does not send every complete worker result to every other worker.
|
|
82
|
+
|
|
83
|
+
Plan-body verification uses a different queue from Phase 5.5. Phase 5.5 verifies worker findings, and the Phase 6 sub-step re-verifies the consolidated plan body produced by the report-writer at the `P-*` plan-item level. The lead must create that queue through `okstra plan-items extract` and prove it is complete with `okstra plan-items validate` before dispatch.
|
|
78
84
|
|
|
79
85
|
## 5. design preparation and final report gate
|
|
80
86
|
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -152,7 +152,9 @@ Before invoking the Antigravity CLI, you MUST:
|
|
|
152
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
|
-
|
|
155
|
+
Extract `**Audit sidecar path:** <abs-path>` verbatim from the lead's dispatch prompt and verify that the value is absolute. If the header is absent or the value is not absolute, return `ANTIGRAVITY_AUDIT_PATH_MISSING: lead prompt did not include a valid absolute **Audit sidecar path:** header` without invoking the CLI. Do NOT synthesize the audit sidecar path from the task type, worker name, or sequence.
|
|
156
|
+
|
|
157
|
+
The CLI writes a Reading Confirmation block to the absolute path extracted from the `**Audit sidecar path:**` header. 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
158
|
|
|
157
159
|
## Worker Output Structure
|
|
158
160
|
|
|
@@ -63,7 +63,7 @@ Before producing any output, you MUST:
|
|
|
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
|
|
|
66
|
-
- **Where:**
|
|
66
|
+
- **Where:** the absolute path in `**Audit sidecar path:**`.
|
|
67
67
|
- **Start (before the per-file reads):** immediately after extracting `Project Root` and the assigned paths, `Write` just the heading line (`# Claude Worker Audit — <task-key>`) plus one `- PROGRESS: started <ISO-8601-UTC>` line.
|
|
68
68
|
- **Append per stage** (`Edit` or heredoc `>>`): `read-<filename>`, `analysis-start`, `findings-draft-start`, `findings-draft-complete`, `write-result-start`.
|
|
69
69
|
- **Cadence MUST NOT exceed 5 minutes:** if a single analysis stage runs longer, emit a `- PROGRESS: in-stage:<stage> <ISO-8601-UTC>` line. A 5-minute-stale sidecar mtime is the canonical "this worker has hung" signal for the operator.
|
|
@@ -152,7 +152,9 @@ Before invoking the Codex CLI, you MUST:
|
|
|
152
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
|
-
|
|
155
|
+
Extract `**Audit sidecar path:** <abs-path>` verbatim from the lead's dispatch prompt and verify that the value is absolute. If the header is absent or the value is not absolute, return `CODEX_AUDIT_PATH_MISSING: lead prompt did not include a valid absolute **Audit sidecar path:** header` without invoking the CLI. Do NOT synthesize the audit sidecar path from the task type, worker name, or sequence.
|
|
156
|
+
|
|
157
|
+
The CLI writes a Reading Confirmation block to the absolute path extracted from the `**Audit sidecar path:**` header. 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
158
|
|
|
157
159
|
## Worker Output Structure
|
|
158
160
|
|
|
@@ -30,7 +30,7 @@ If you find yourself thinking "I'll just write the markdown directly" — stop.
|
|
|
30
30
|
|
|
31
31
|
## Worker Result File (MANDATORY)
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Write the required worker-result record at the lead-registered `**Worker Result Path:**`. The validator checks this file exists whenever the role's terminal status is `completed`. Schema: short YAML frontmatter (`workerId: "report-writer"`, plus the canonical fields copied verbatim from `analysis-material.md` per `team-contract`) followed by:
|
|
34
34
|
|
|
35
35
|
1. The canonical data.json path you wrote (project-relative).
|
|
36
36
|
2. The rendered markdown path produced by the renderer (project-relative).
|
|
@@ -39,6 +39,10 @@ You also write an audit sidecar at the path the lead registers as `**Worker Resu
|
|
|
39
39
|
|
|
40
40
|
Do NOT duplicate the data.json contents here — the data.json is the canonical artifact; this sidecar is the validator-required pointer / audit record.
|
|
41
41
|
|
|
42
|
+
## Heartbeat (BLOCKING)
|
|
43
|
+
|
|
44
|
+
Write the audit sidecar at `**Audit sidecar path:**` before required reading, then append `- PROGRESS: <stage> <ISO-8601-UTC>` at a cadence no longer than five minutes. Use only: `started`, `required-reading-complete`, `synthesis-start`, `data-json-write-start`, `render-start`, and `write-result-start`. The Phase 7 validator enforces the first stage, timestamps, cadence, and this allowlist.
|
|
45
|
+
|
|
42
46
|
## Execution Rules
|
|
43
47
|
|
|
44
48
|
1. Extract the absolute `Project Root` from the lead prompt (look for a line starting with `**Project Root:**` or `Project Root:`). If missing, return:
|
|
@@ -75,7 +79,7 @@ For the report writer specifically, the `## Inputs` list always includes:
|
|
|
75
79
|
|
|
76
80
|
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
81
|
|
|
78
|
-
Write a Reading Confirmation block to
|
|
82
|
+
Write a Reading Confirmation block to `**Audit sidecar path:**`, per the selected report-writer preamble's `Required reading` section (the main final-report and worker-results files carry no Section 0 heading). If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating the report.
|
|
79
83
|
|
|
80
84
|
## Authoring Contract
|
|
81
85
|
|
|
@@ -92,7 +96,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
|
|
|
92
96
|
- **§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
97
|
- **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
98
|
- **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
|
|
99
|
+
- **Reading Confirmation** goes at `**Audit sidecar path:**` per the selected report-writer preamble's `Required reading` section — never in the data.json or the main worker-results file.
|
|
96
100
|
- Include all four convergence categories. The schema's `crossVerification.consensus` / `.differences` arrays carry full / partial / contested / worker-unique items; do not omit any.
|
|
97
101
|
- 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
102
|
- `verification-error` votes are their own verdict (`planItems[].verdicts[].verdict` enum); they are NOT folded into AGREE / DISAGREE counts.
|
|
@@ -101,7 +105,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
|
|
|
101
105
|
- If evidence is missing, write `"I don't know"` in the relevant statement field rather than fabricating confidence.
|
|
102
106
|
- Cite file paths and line numbers in every `evidence.primary[].source` / `consensus[].evidence` cell.
|
|
103
107
|
- Preserve every analysis worker's ticket tagging — every row's `ticketId` field carries the ticket key or the task-fallback. For single-ticket runs, set `ticketCoverage` to `{"singleTicket": "<ticket>"}`. For runs that do not require ticket tagging (`release-handoff`, `final-verification`), set `ticketCoverage` to `{"omit": true}`.
|
|
104
|
-
- For `implementation-planning`, populate `implementationPlanning.requirementCoverage` with one row per concrete requirement from the brief / packet, using IDs `R-001`, `R-002`, ... in source order. `coveredBy` MUST name the specific Option Candidate plus Stage/Step that satisfies the requirement. Use `status: "covered"` only when the report's plan actually covers it;
|
|
108
|
+
- For `implementation-planning`, populate `implementationPlanning.requirementCoverage` with one row per concrete requirement from the brief / packet, using IDs `R-001`, `R-002`, ... in source order. A `covered` row's `coveredBy` MUST name the specific Option Candidate plus Stage/Step that satisfies the requirement. Use `status: "covered"` only when the report's plan actually covers it; use `documented-deviation` only when `coveredBy` states the concrete alternative and the row records non-empty unique `decisionRefs` plus `approvalDisposition`. Each `C-NNN` ref must name a clarification in this report; each `D-NNNN` ref must name a `decisionDrafts[].number`. `approvalDisposition: "accepted"` requires a referenced clarification with `status: answered|resolved` and non-empty `userInput`; `approvalDisposition: "blocked C-NNN"` requires that same-report clarification to be `status: open, blocks: approval`. Otherwise use `gap` or `blocked C-NNN` and ensure the corresponding `Clarification Items` row blocks approval. Do not collapse this into `ticketCoverage`; ticket coverage is not requirement coverage. **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.ImplementationRequirementCoverageRow` and `validators/validate-run.py` `_validate_requirement_deviations`.
|
|
105
109
|
- For `implementation-planning`, each `requirementCoverage` row's `source` is a graded cell, not prose — free text like `"carry-in from requirements-discovery C-001"` is rejected. Write exactly one of: `brief:<heading>`, where the heading literally exists in the task brief; `derived:R-NNN — <one-line reason>`, whose chain must terminate at a `brief:` or `contract:` row of the same table without cycling; or `contract:<rule>`, for artifacts okstra's own phase contract mandates, whose allowlist is exactly the two tokens `decision-record-step` (the §5.4 Decision Drafts materialization step) and `glossary-step` (the glossary proposal step) — any other rule name is rejected, so never invent one. (Maintainer SSOT for that allowlist: `scripts/okstra_ctl/scope_provenance.py` in the okstra repo.) A requirement you cannot source this way does not belong in the table: put it in `clarificationItems[]` with `Blocks=approval`. **Enforced:** `validators/validate-run.py` `_validate_requirement_provenance`. In the same table, anchor every stage number in `coveredBy` to a `Stage` / `Stages` word (`Stage 2`, `Stages 1-3`) — `_validate_stage_has_requirement` reads that cell as prose and fails the plan when a Stage Map stage is cited by no row.
|
|
106
110
|
- For `implementation-planning`, also populate `implementationPlanning.decisionDrafts` (one row per decision meeting all three decision-record criteria; `[]` otherwise) and `implementationPlanning.skippedAdrCandidates` (evaluated-but-dropped adr-candidates; `[]` otherwise). The schema excerpt enumerates the row shape; the renderer emits §5.4 `### Decision Drafts`. When `decisionDrafts` is non-empty, the plan's stages MUST carry a stepwise step that creates `.okstra/decisions/<NNNN>-<slug>.md` (validate-run gates this).
|
|
107
111
|
- When the `Task Type` is `improvement-discovery`, populate `## 5.9 Improvement Candidates` with the 10-column schema enforced by `validators/validate_improvement_report.py`. Source the row IDs (`I-NNN`), lens whitelist, and Source workers patterns from `scripts/okstra_ctl/improvement_lenses.py` — do NOT introduce new lens names or worker prefixes. `improvement-discovery` is NOT in the data.json schema enum, so author its markdown directly (not via `okstra-render-final-report.py`). Immediately after writing the markdown, run (`Bash`): `okstra inject-report-index <markdown path> --report-language <en|ko>`. That adds the top-of-report Index plus `I-NNN` / `C-NNN` scroll anchors; the run validator fails the report when the Index anchor is absent.
|
|
@@ -62,8 +62,8 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
|
|
|
62
62
|
|
|
63
63
|
- Follow the core Result Path + terminal-status completion contract. The Claude adapter's wake mechanism is one `Bash(run_in_background: true)` poll covering every pending Result Path, not foreground sleep or an idle-notification dependency. A spawn acknowledgement is never completion.
|
|
64
64
|
- The background poll uses a per-worker deadline of twice the expected duration: 20 minutes for `requirements-discovery`, 30 for `error-analysis`, 40 for `implementation-planning`, 40 for `implementation`, and 20 for `final-verification`. On timeout, record terminal status and apply the core's single shared retry budget.
|
|
65
|
-
-
|
|
66
|
-
- **The background poll checks liveness, not only Result Paths.** Result Paths change once, at the very end, so polling them alone pays the full deadline for a worker that died at minute three. Each poll iteration MUST also run, in the same background shell, one `okstra worker-liveness` call covering every pending worker — `--audit <audit-sidecar-path>` for each in-process
|
|
65
|
+
- Each in-process worker heartbeat audit sidecar must update at least every five minutes while its result is pending. A missing or stale heartbeat consumes the same one-retry budget; after the second silent hang, record `timeout`. The result file remains the authoritative completion signal.
|
|
66
|
+
- **The background poll checks liveness, not only Result Paths.** Result Paths change once, at the very end, so polling them alone pays the full deadline for a worker that died at minute three. Each poll iteration MUST also run, in the same background shell, one `okstra worker-liveness` call covering every pending worker — `--audit <audit-sidecar-path>` for each in-process worker, `--prompt <prompt-history-path>` for each CLI-wrapper worker. The dispatch record's `livenessMode` selects the flag; never infer it from provider or filename. It exits non-zero when a worker is `stalled` (heartbeat older than the cadence budget) or `did-not-launch`; either verdict ends the wait for that worker immediately and spends the core's one-retry budget, rather than waiting out the deadline. The command reports only — it never kills or re-dispatches. It shares its heartbeat budget with the Phase 7 audit (`okstra_ctl.worker_heartbeat`), so a worker the live probe passes cannot fail the post-hoc one for cadence.
|
|
67
67
|
- The Claude Code harness blocks long foreground sleeps and shorter-sleep circumvention loops. Keep the result poll in a single background shell and let wrapper agents use their documented `BashOutput` loop.
|
|
68
68
|
- On approved cleanup, reconcile the current live session roster before sending shutdown requests. Never target the lead session.
|
|
69
69
|
- Collect usage before teardown. Resume through the recorded Claude session id and keep all run artifacts authoritative.
|
|
@@ -30,6 +30,10 @@ When this contract says "queue" without qualifier, it means the *verification qu
|
|
|
30
30
|
|
|
31
31
|
An initial pane role `verifier` is still a Phase 4/5 analysis worker; it does not mean Phase 5.5 reverify. Only a queue-scoped dispatch whose prompt/result path carries `-reverify-r<N>-` performs the reverify step described by this contract.
|
|
32
32
|
|
|
33
|
+
The end-to-end artifact lifecycle is worker results → Round 0 grouping → reducer-owned queue → analyser-instance re-verification → optional `okstra convergence apply-critic-gaps` transition → validated terminal state (newly finalized v1.3, or unchanged historical v1.0–v1.2 from `reuse-final`) → report-writer data.json. Cross-verification is queue-scoped: it does not mean that one worker reviews another worker's complete result. The reducer asks independent analyser instances to vote only on non-consensus findings selected by the persisted plan; the report writer never votes.
|
|
34
|
+
|
|
35
|
+
Initial and reverify worker prompts carry `**Audit sidecar path:**`. Initial workers write their reading confirmation there; reverify workers use their own canonical sidecar for the reverify session without reopening the initial worker's full reading packet.
|
|
36
|
+
|
|
33
37
|
## When to Use
|
|
34
38
|
|
|
35
39
|
- When okstra lead Phase 5.5 (convergence loop) begins — immediately after all workers complete Phases 4 and 5
|
|
@@ -80,7 +84,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
|
|
|
80
84
|
- Same semantics but disjoint ticket sets → separate groups (do NOT over-merge across tickets).
|
|
81
85
|
- Only one worker confirms a finding → one single-source group.
|
|
82
86
|
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.
|
|
87
|
+
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`. When a live command or external read produced reproducible evidence, also include `evidenceArtifacts[]` with its `.okstra/` path, SHA-256 digest, command, and environment. The field is optional because historical or inaccessible evidence may not have a captured artifact. The lead and verifier MUST NOT infer live or external evidence from wording or keyword matching; they use the finding's explicit claim, provenance, and supplied artifacts. Include the resolved worker roster in order with functional `audience` values; do not derive scope from provider or model identity.
|
|
84
88
|
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
89
|
|
|
86
90
|
### Round 1-N: Re-verification Loop (queue-pruned)
|
|
@@ -99,13 +103,15 @@ convergence-<task-type>-<seq>.json
|
|
|
99
103
|
|
|
100
104
|
Follow this protocol exactly:
|
|
101
105
|
|
|
106
|
+
0. The machine-readable inputs are `schemas/convergence-groups-v1.0.schema.json`, `schemas/convergence-round-results-v1.0.schema.json`, and `schemas/convergence-critic-results-v1.0.schema.json`. Use `okstra convergence example --kind <groups|round-results|critic-results>` for deterministic valid examples; the command writes only JSON to stdout.
|
|
102
107
|
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
108
|
2. Run `okstra convergence plan-round --work-state <work> --plan <round-plan>`. This is read-only with respect to the working state.
|
|
104
109
|
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
110
|
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
111
|
5. Repeat `plan-round` and `apply-round` until the plan action is `finalize`.
|
|
107
|
-
6.
|
|
108
|
-
7. Run `okstra convergence
|
|
112
|
+
6. When the coverage critic is enabled, convert its verification batch to the canonical `dispatches[]` / `gaps[]` result shape and run `okstra convergence apply-critic-gaps --work-state <work> --results <critic-results>` exactly once. The reducer, not the lead, merges verified gaps.
|
|
113
|
+
7. Run `okstra convergence finalize --work-state <work> --output <final>`.
|
|
114
|
+
8. Run `okstra convergence validate --state <final> --kind final`. Newly finalized convergence output is schema v1.3. Under `reuse-final`, a valid historical final schema v1.0, v1.1, or v1.2 remains consumable by the report-writer without rewrite; do not finalize, upgrade, or otherwise rewrite that reused artifact. Deliver the validated terminal state to the report-writer, which does not vote.
|
|
109
115
|
|
|
110
116
|
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.
|
|
111
117
|
|
|
@@ -113,7 +119,7 @@ After `seed`, the lead MUST NOT hand-edit queue IDs, classifications, `roundHist
|
|
|
113
119
|
|
|
114
120
|
#### Resume and legacy-state recovery (BLOCKING)
|
|
115
121
|
|
|
116
|
-
A valid
|
|
122
|
+
A valid historical final schema v1.0, v1.1, or v1.2 is reused unchanged under `reuse-final`; it remains read-only and is not upgraded in place. 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.
|
|
117
123
|
|
|
118
124
|
#### Engine-owned Round 2 gate
|
|
119
125
|
|
|
@@ -125,13 +131,15 @@ A reverify dispatch that returns a **terminal non-result** (`timeout`, `error`,
|
|
|
125
131
|
|
|
126
132
|
Rules:
|
|
127
133
|
|
|
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.
|
|
134
|
+
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. A completed dispatch may separately return `UNVERIFIABLE` for a particular finding; the input alias is persisted as `verification-error` with its required non-empty explanation while the dispatch remains `completed`.
|
|
129
135
|
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).
|
|
130
136
|
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
137
|
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.
|
|
132
138
|
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`.
|
|
133
139
|
|
|
134
|
-
The engine's classifiers treat `verification-error` as "no usable vote" — it counts neither toward AGREE nor toward DISAGREE.
|
|
140
|
+
The engine's classifiers treat `verification-error` as "no usable vote" — it counts neither toward AGREE nor toward DISAGREE and is excluded from both numerator and denominator.
|
|
141
|
+
|
|
142
|
+
The public shorthand is `UNVERIFIABLE → verification-error`: `UNVERIFIABLE` is the worker-facing input token, while `verification-error` is the persisted state token. This mapping records unavailable evidence honestly and never turns inability to verify into a negative vote.
|
|
135
143
|
|
|
136
144
|
### Convergence Test
|
|
137
145
|
|
|
@@ -164,15 +172,16 @@ The persisted `verdict` enum is unchanged (`agree | disagree | supplement | veri
|
|
|
164
172
|
| SURVIVES | `agree` | Actively tried to refute and failed — the claim withstood the attack. |
|
|
165
173
|
| SURVIVES-WITH-CAVEAT | `supplement` | Holds, but a scope limit / extra condition / precondition was found. |
|
|
166
174
|
| REFUTED | `disagree` | The claim was broken (or failed to prove itself). MUST carry a `disagreeBasis`. |
|
|
175
|
+
| UNVERIFIABLE | `verification-error` | Capability, credential, network, or service state prevented verification of this finding. |
|
|
167
176
|
|
|
168
177
|
Each `disagree` vote records a new field `disagreeBasis`:
|
|
169
178
|
|
|
170
179
|
| `disagreeBasis` | Meaning |
|
|
171
180
|
|---|---|
|
|
172
|
-
| `counter-evidence` | The verifier cited
|
|
173
|
-
| `burden-not-met` | The verifier
|
|
181
|
+
| `counter-evidence` | The verifier opened and inspected the cited evidence and found a contradiction (`file:line` / log line) recorded in `explanation`. A **hard refute**. |
|
|
182
|
+
| `burden-not-met` | The verifier opened and inspected the cited evidence, but its contents were insufficient to establish the claim. |
|
|
174
183
|
|
|
175
|
-
A `disagree` with `disagreeBasis == null` is a contract violation in adversarial mode — every refutation must state which of the two grounds it rests on. Bare "I disagree" without re-inspection is not allowed.
|
|
184
|
+
A `disagree` with `disagreeBasis == null` is a contract violation in adversarial mode — every refutation must state which of the two grounds it rests on. Bare "I disagree" without re-inspection is not allowed. If capability, credential, network, or service state prevents that inspection, the verdict is `UNVERIFIABLE`, persisted as `verification-error`; verifier failure is never converted to `DISAGREE` or `burden-not-met`. A live/external claim without `evidenceArtifacts` remains schema-valid, but a verifier that needs the missing artifact and cannot independently access the source MUST answer `UNVERIFIABLE` with a non-empty explanation.
|
|
176
185
|
|
|
177
186
|
### Adversarial classification (replaces the §"Convergence Algorithm" per-round classifier when `adversarial == true`)
|
|
178
187
|
|
|
@@ -215,12 +224,13 @@ Call `await_workers(handles)` through the same adapter and apply the shared term
|
|
|
215
224
|
|
|
216
225
|
### Required reverify-prompt anchor headers (BLOCKING)
|
|
217
226
|
|
|
218
|
-
Every reverify prompt MUST start with these
|
|
227
|
+
Every reverify prompt MUST start with these 9 anchor headers — in this exact order, before any other content:
|
|
219
228
|
|
|
220
229
|
```
|
|
221
230
|
**Project Root:** <absolute-path>
|
|
222
231
|
**Prompt History Path:** runs/<task-type>/prompts/<role-slug>-reverify-r<N>-<task-type>-<seq>.md
|
|
223
232
|
**Result Path:** runs/<task-type>/worker-results/<role-slug>-reverify-r<N>-<task-type>-<seq>.md
|
|
233
|
+
**Audit sidecar path:** <absolute-path>
|
|
224
234
|
Assigned worker prompt history path: <Project Root>/<Prompt History Path>
|
|
225
235
|
**Model:** <role>, <modelExecutionValue>
|
|
226
236
|
**Errors log path:** <absolute-path>
|
|
@@ -230,6 +240,8 @@ Assigned worker prompt history path: <Project Root>/<Prompt History Path>
|
|
|
230
240
|
|
|
231
241
|
`**Read scope:**` is carried verbatim, not dropped: lightweight mode omits `**Worker Preamble Path:**`, so this line is the ONLY place a reverify worker receives the read allowlist — and a prompt with no `[Required reading]` block is exactly where a worker is most likely to fall back on host session instructions instead.
|
|
232
242
|
|
|
243
|
+
Before dispatch, materialize `**Audit sidecar path:**` by passing the exact reverify `**Result Path:**` through `okstra_ctl.worker_artifact_paths.audit_sidecar_rel()` and resolving that project-relative result against `**Project Root:**`. Write the resulting absolute path into the header. The lead MUST NOT construct the audit filename from a role, task type, round, or sequence independently.
|
|
244
|
+
|
|
233
245
|
The two errors paths carry the same absolute values the lead forwarded in the initial Phase 4 dispatch for that role (source: the launch prompt's `## Run Logs (error-log wiring)` section). Omitting either one makes a CLI-wrapper worker return `<WORKER>_ERRORS_PATH_MISSING` before it invokes its CLI — the path-delivery contract in [team-contract](./team-contract.md) "Error reporting" is not relaxed for reverify, because a reverify dispatch can fail the same way an initial dispatch can.
|
|
234
246
|
|
|
235
247
|
Relative to the Phase 4 anchor set rendered by `okstra_ctl.worker_prompt_headers.worker_prompt_headers()`, a reverify prompt adds `**Model:**` and drops two anchors whose targets lightweight mode never reads: `**Worker Preamble Path:**` and `**Coding preflight pack:**`.
|
|
@@ -268,6 +280,8 @@ For EACH finding, respond with exactly one verdict:
|
|
|
268
280
|
- **AGREE**: The finding is valid based on the evidence presented
|
|
269
281
|
- **DISAGREE**: The finding is incorrect or unsupported (explain briefly why)
|
|
270
282
|
- **SUPPLEMENT**: The finding is valid AND you have additional supporting evidence or context
|
|
283
|
+
- **UNVERIFIABLE**: Capability, credential, network, or service state prevents you
|
|
284
|
+
from checking this finding. Explain the unavailable capability; do not substitute DISAGREE.
|
|
271
285
|
|
|
272
286
|
Do NOT re-analyze the original source materials. Judge based on the evidence provided.
|
|
273
287
|
|
|
@@ -286,7 +300,7 @@ Do NOT re-analyze the original source materials. Judge based on the evidence pro
|
|
|
286
300
|
For each finding, respond as:
|
|
287
301
|
|
|
288
302
|
### F-001
|
|
289
|
-
**Verdict**: AGREE | DISAGREE | SUPPLEMENT
|
|
303
|
+
**Verdict**: AGREE | DISAGREE | SUPPLEMENT | UNVERIFIABLE
|
|
290
304
|
**Explanation**: <2-3 sentences>
|
|
291
305
|
|
|
292
306
|
### F-002
|
|
@@ -313,6 +327,8 @@ is wrong, overstated, or unproven. Then respond with exactly one verdict:
|
|
|
313
327
|
- **SURVIVES**: You actively tried to refute it and failed — the claim withstood the attack.
|
|
314
328
|
- **SURVIVES-WITH-CAVEAT**: It holds, but a scope limit / extra condition / missing
|
|
315
329
|
precondition exists (state it).
|
|
330
|
+
- **UNVERIFIABLE**: Capability, credential, network, or service state prevents you
|
|
331
|
+
from opening or reproducing the cited evidence. Do not use REFUTED as a substitute.
|
|
316
332
|
|
|
317
333
|
The burden of proof is on the claim. If after inspecting the cited evidence you remain
|
|
318
334
|
uncertain, your verdict is REFUTED with basis = burden-not-met.
|
|
@@ -332,7 +348,7 @@ re-read the task brief, instruction-set, or report template.
|
|
|
332
348
|
## Response format
|
|
333
349
|
|
|
334
350
|
### F-001
|
|
335
|
-
**Verdict**: REFUTED | SURVIVES | SURVIVES-WITH-CAVEAT
|
|
351
|
+
**Verdict**: REFUTED | SURVIVES | SURVIVES-WITH-CAVEAT | UNVERIFIABLE
|
|
336
352
|
**Basis** (only if REFUTED): counter-evidence | burden-not-met
|
|
337
353
|
**Explanation**: <2-3 sentences; for counter-evidence include the file:line you found>
|
|
338
354
|
|
|
@@ -340,7 +356,7 @@ re-read the task brief, instruction-set, or report template.
|
|
|
340
356
|
...
|
|
341
357
|
```
|
|
342
358
|
|
|
343
|
-
When persisting votes, map SURVIVES→`agree`, SURVIVES-WITH-CAVEAT→`supplement`, REFUTED→`disagree`, and copy the stated Basis into `votes.<worker>.disagreeBasis` (null for non-REFUTED verdicts).
|
|
359
|
+
When persisting votes, map SURVIVES→`agree`, SURVIVES-WITH-CAVEAT→`supplement`, REFUTED→`disagree`, and UNVERIFIABLE→`verification-error`; copy the stated Basis into `votes.<worker>.disagreeBasis` (null for non-REFUTED verdicts). Every vote requires a non-empty `explanation`.
|
|
344
360
|
|
|
345
361
|
### Full Re-analysis Re-verification Prompt
|
|
346
362
|
|
|
@@ -351,6 +367,10 @@ You are <worker-role> performing deep re-verification for <task-key> (round <N>)
|
|
|
351
367
|
|
|
352
368
|
Independently verify the following findings by examining the original materials.
|
|
353
369
|
Use each finding as a starting point, NOT as a confirmed conclusion.
|
|
370
|
+
If capability, credential, network, or service state prevents access to evidence
|
|
371
|
+
needed for a finding, you MUST answer UNVERIFIABLE with a non-empty explanation.
|
|
372
|
+
You MUST NOT answer DISAGREE merely because access or reproduction failed;
|
|
373
|
+
UNVERIFIABLE is persisted as `verification-error` and excluded from consensus.
|
|
354
374
|
|
|
355
375
|
## Task bundle paths
|
|
356
376
|
- Instruction set: <instruction-set path>
|
|
@@ -373,7 +393,7 @@ Use each finding as a starting point, NOT as a confirmed conclusion.
|
|
|
373
393
|
For each finding:
|
|
374
394
|
|
|
375
395
|
### F-001
|
|
376
|
-
**Verdict**: AGREE | DISAGREE | SUPPLEMENT
|
|
396
|
+
**Verdict**: AGREE | DISAGREE | SUPPLEMENT | UNVERIFIABLE
|
|
377
397
|
**Your evidence**: <your independent evidence trail with file paths and line numbers>
|
|
378
398
|
**Explanation**: <detailed analysis>
|
|
379
399
|
```
|
|
@@ -384,7 +404,7 @@ Save it to `runs/<task-type>/state/convergence-<task-type>-<seq>.json`.
|
|
|
384
404
|
|
|
385
405
|
```json
|
|
386
406
|
{
|
|
387
|
-
"schemaVersion": "1.
|
|
407
|
+
"schemaVersion": "1.3",
|
|
388
408
|
"taskKey": "<task-key>",
|
|
389
409
|
"config": {
|
|
390
410
|
"enabled": true,
|
|
@@ -446,11 +466,11 @@ Save it to `runs/<task-type>/state/convergence-<task-type>-<seq>.json`.
|
|
|
446
466
|
|
|
447
467
|
Schema rules:
|
|
448
468
|
|
|
449
|
-
- `schemaVersion`: literal string `"1.
|
|
469
|
+
- `schemaVersion`: literal string `"1.3"` for all new runs — both adversarial and collaborative. Historical readers accept `"1.0"` / `"1.1"` / `"1.2"` unchanged and never rewrite those artifacts during validation. v1.3 adds the strict coverage-critic ledger and rejects unknown top-level fields; work-state remains v1.0.
|
|
450
470
|
- `config.adversarial`: boolean. `true` when this run used adversarial verification (default for `requirements-discovery` / `error-analysis` / `implementation-planning`). When `true`, `config.verificationMode` is `"full-reanalysis"` (scoped) and every `disagree` vote carries a non-null `disagreeBasis`.
|
|
451
471
|
- `config.effectiveMaxRounds`: the integer the lead actually used after resolving the phase-aware default (`1` for `requirements-discovery`, `2` otherwise). MUST equal `config.maxRounds` when the manifest explicitly set it.
|
|
452
472
|
- `findings[].ticketIds`: array of ticket keys from Phase 4 grouping (parsed per the Round 0 step 5 rule). MAY be empty when the discovering worker tagged the finding `unknown`.
|
|
453
|
-
- `findings[].rounds[].votes.<worker>.verdict`: enum, one of `agree | disagree | supplement | verification-error`. Lower-case tokens; map upper-case AGREE/DISAGREE/SUPPLEMENT verdicts emitted by workers to their lower-case form
|
|
473
|
+
- `findings[].rounds[].votes.<worker>.verdict`: enum, one of `agree | disagree | supplement | verification-error`. Lower-case tokens; map upper-case AGREE/DISAGREE/SUPPLEMENT verdicts emitted by workers to their lower-case form and map the input alias `unverifiable` to persisted `verification-error`. The latter represents either a terminal non-result dispatch or a completed dispatch that could not verify a particular finding (§"Worker failure handling in reverify"). Every vote has a non-empty `explanation`.
|
|
454
474
|
- `findings[].rounds[].votes.<worker>.disagreeBasis`: enum `counter-evidence | burden-not-met | null`. Non-null only when `verdict == "disagree"` AND `config.adversarial == true`; `null` (or absent, treated as null) otherwise. See §"Adversarial Verification Mode".
|
|
455
475
|
- `findings[].classification`: enum, one of `full-consensus | partial-consensus | worker-unique | contested`. No other value is permitted.
|
|
456
476
|
- `roundHistory[].inputQueueSize`: queue size at the start of this round.
|
|
@@ -472,7 +492,7 @@ Runs only when `convergence.critic.enabled == true` (set by `--critic <provider>
|
|
|
472
492
|
The critic input is the Round 0 consolidated finding list. Reverify rounds only classify findings — they never add or remove them (in-round queue insertions are forbidden, see §"Convergence State Artifact" `carriedForwardCount`) — so the critic dispatch MUST NOT wait for classification to finish:
|
|
473
493
|
|
|
474
494
|
- **Dispatch**: immediately after Round 0 grouping, CONCURRENTLY with the first reverify round's dispatches. When the verification queue is empty after Round 0 (no reverify round runs), dispatch right after grouping. Concurrent dispatch to the same provider is safe — the critic result path (`<provider>-critic-...`) never collides with a reverify result path.
|
|
475
|
-
- **Gap verification + merge**: only after BOTH the finding-convergence loop has exited AND the critic result is collected, and BEFORE the Phase 6 report-writer dispatch. If the loop exited `aborted-non-result`, do NOT dispatch a gap-verification round —
|
|
495
|
+
- **Gap verification + merge**: only after BOTH the finding-convergence loop has exited AND the critic result is collected, and BEFORE the Phase 6 report-writer dispatch. If the loop exited `aborted-non-result`, do NOT dispatch a gap-verification round — record every gap in `unverifiedGaps[]` per §"Gap verification".
|
|
476
496
|
|
|
477
497
|
### Dispatch (fresh one-shot)
|
|
478
498
|
Dispatch one fresh pass to `config.critic.provider` through `redispatch_worker`, with `model = config.critic.modelExecutionValue` and `dispatchKind = "critic"`. If the model value is empty, record `critic-skipped: model-unresolved`; never dispatch without a model. Result path: `runs/<task-type>/worker-results/<provider>-critic-<task-type>-<seq>.md`. The critic prompt seeds the consolidated findings and asks ONLY for coverage gaps:
|
|
@@ -494,7 +514,9 @@ Each critic gap enters the verification queue as a finding with `originWorker =
|
|
|
494
514
|
|
|
495
515
|
### State
|
|
496
516
|
- `convergence.critic` manifest block: `{ enabled, provider, modelExecutionValue }`.
|
|
497
|
-
-
|
|
517
|
+
- The lead passes one canonical coverage batch with `{ schemaVersion, taskKey, mode, provider, modelExecutionValue, dispatches, gaps }`; each gap carries its candidate fields plus `gapId` and `votes`. `dispatches[]` contains exactly one row for every Phase 4 analyser except the critic, even when execution did not produce a result: persist `status: timeout | error | not-run` and the elapsed `durationMs` instead of omitting that analyser. `apply-critic-gaps` rejects a non-terminal main queue, duplicate or missing analysers, unknown workers, critic dispatches/votes, votes without a completed dispatch, and a second batch.
|
|
518
|
+
- Convergence state artifact: merged gaps appear in `findings[]` with `source: "critic"` and `rounds: []`. The separate `criticVerification.gaps[]` ledger retains each gap's `summary`, `category`, `ticketIds`, `originEvidence`, optional `evidenceArtifacts`, classification, merge link, and votes. Strict v1.3 validation deterministically replays each complete critic-origin finding from that ledger; a critic batch never increments `roundHistory` or `totalRounds` and never creates a fake main round.
|
|
519
|
+
- `config.critic` is `{ provider, modelExecutionValue, gapsProposed, gapsMerged, gapsRejected, gapsUnverified }`, with `gapsProposed = gapsMerged + gapsRejected + gapsUnverified`. `full-consensus` / `partial-consensus` gaps merge, `contested` / `worker-unique` gaps count as rejected, and gaps with no usable analyser vote appear in both the ledger and final `unverifiedGaps[]`.
|
|
498
520
|
|
|
499
521
|
## Acceptance critic pass (final-verification)
|
|
500
522
|
|
|
@@ -518,6 +540,7 @@ existing Acceptance Blocker. If you find none, say so explicitly.
|
|
|
518
540
|
### Verification — confirm-or-downgrade (BLOCKING)
|
|
519
541
|
|
|
520
542
|
Each candidate blocker is verified by the Phase 4 analysers (excluding the critic). Do NOT use the adversarial finding classifier's "uncertain → reject" rule here.
|
|
543
|
+
- Do NOT run `apply-critic-gaps` for this mode. That reducer implements coverage merge/drop semantics and rejects `acceptance-devils-advocate` input.
|
|
521
544
|
- **Confirmed** (an analyser reproduces it or cites supporting evidence) → promote to a `## 5.8 Acceptance Blockers` row (keep severity + recommended follow-up phase).
|
|
522
545
|
- **Not confirmed** (cannot reproduce, or evidence is weak) → **downgrade to a Residual Risk row — never drop it.** Record the escalation trigger so the user can re-judge a high-severity-but-unconfirmed candidate.
|
|
523
546
|
|
|
@@ -527,13 +550,13 @@ Promoted blockers enter `## 5.8 Acceptance Blockers`; since `accepted` requires
|
|
|
527
550
|
|
|
528
551
|
### State
|
|
529
552
|
|
|
530
|
-
Critic output lives in the run's `worker-results/` directory (`runs/final-verification/worker-results/` for whole-task verification, `runs/final-verification/stage-<N>/worker-results/` for single-stage), filename `<provider>-critic-final-verification-<seq>.md`. The convergence state `config.critic` summary
|
|
553
|
+
Critic output lives in the run's `worker-results/` directory (`runs/final-verification/worker-results/` for whole-task verification, `runs/final-verification/stage-<N>/worker-results/` for single-stage), filename `<provider>-critic-final-verification-<seq>.md`. The convergence state `config.critic` summary records `mode: "acceptance-devils-advocate"`, `candidatesProposed`, `confirmedBlockers`, `downgradedToResidual`; v1.3 enforces `candidatesProposed = confirmedBlockers + downgradedToResidual`, so no candidate can be silently dropped.
|
|
531
554
|
|
|
532
555
|
## Output
|
|
533
556
|
|
|
534
557
|
Information to be passed to Phase 6 after completing this contract:
|
|
535
558
|
|
|
536
|
-
-
|
|
559
|
+
- Newly finalized convergence output is schema v1.3. Under `reuse-final`, a valid historical final schema v1.0, v1.1, or v1.2 remains consumable by the report-writer without rewrite. Either validated terminal artifact contains the four-category classification of all findings; the report-writer consumes it and does not vote
|
|
537
560
|
- Round history and votes per worker for each finding
|
|
538
561
|
- Path to the convergence state artifact
|
|
539
562
|
- Convergence summary (count per category)
|