okstra 0.121.0 → 0.122.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.
Files changed (39) hide show
  1. package/docs/architecture.md +4 -2
  2. package/docs/project-structure-overview.md +1 -1
  3. package/package.json +1 -1
  4. package/runtime/BUILD.json +2 -2
  5. package/runtime/agents/workers/claude-worker.md +1 -1
  6. package/runtime/bin/lib/okstra/usage.sh +2 -2
  7. package/runtime/prompts/launch.template.md +4 -4
  8. package/runtime/prompts/lead/adapters/claude-code.md +104 -0
  9. package/runtime/prompts/lead/adapters/codex.md +45 -0
  10. package/runtime/prompts/lead/adapters/external.md +46 -0
  11. package/runtime/prompts/lead/context-loader.md +5 -5
  12. package/runtime/prompts/lead/convergence.md +11 -28
  13. package/runtime/prompts/lead/okstra-lead-contract.md +42 -92
  14. package/runtime/prompts/lead/plan-body-verification.md +21 -5
  15. package/runtime/prompts/lead/report-writer.md +50 -51
  16. package/runtime/prompts/lead/team-contract.md +33 -106
  17. package/runtime/prompts/profiles/_common-contract.md +2 -2
  18. package/runtime/prompts/profiles/_implementation-executor.md +1 -1
  19. package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
  20. package/runtime/prompts/profiles/implementation-planning.md +3 -3
  21. package/runtime/prompts/profiles/requirements-discovery.md +1 -1
  22. package/runtime/python/okstra_ctl/lead_runtime.py +4 -0
  23. package/runtime/python/okstra_ctl/models.py +1 -1
  24. package/runtime/python/okstra_ctl/render.py +76 -194
  25. package/runtime/python/okstra_ctl/report_views.py +22 -7
  26. package/runtime/python/okstra_ctl/team_reconcile.py +3 -1
  27. package/runtime/schemas/final-report-v1.0.schema.json +3 -0
  28. package/runtime/skills/okstra-schedule/SKILL.md +60 -18
  29. package/runtime/templates/reports/final-report.template.md +4 -4
  30. package/runtime/templates/reports/i18n/en.json +1 -1
  31. package/runtime/templates/reports/i18n/ko.json +1 -1
  32. package/runtime/validators/validate-run.py +89 -0
  33. package/runtime/validators/validate-schedule.py +7 -3
  34. package/runtime/validators/validate_session_conformance.py +58 -33
  35. package/src/cli-registry.mjs +7 -0
  36. package/src/commands/inspect/stage-map.mjs +100 -0
  37. package/src/commands/lifecycle/install.mjs +3 -0
  38. package/src/commands/lifecycle/uninstall.mjs +8 -23
  39. package/src/lib/skill-catalog.mjs +8 -0
@@ -130,7 +130,7 @@ Runtime entry points are consolidated in Python packages. Bash and skills only c
130
130
  - [`scripts/lib/okstra/{cli,globals,interactive,project-resolver,usage}.sh`](../scripts/lib/okstra/) — CLI/interactive support only; contains no artifact-generation logic.
131
131
  - [`scripts/okstra-ctl.sh`](../scripts/okstra-ctl.sh) + [`scripts/lib/okstra-ctl/`](../scripts/lib/okstra-ctl/) — central control-center CLI (list / show / open / rerun / reconcile / etc.).
132
132
 
133
- ### Claude assets (templates + skills)
133
+ ### Runtime assets (templates + lead resources)
134
134
 
135
135
  - `prompts/launch.template.md` — lead prompt template.
136
136
  - `prompts/profiles/*.md` — six task-type profiles (`requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`).
@@ -144,7 +144,9 @@ Runtime entry points are consolidated in Python packages. Bash and skills only c
144
144
 
145
145
  ### Skills (`skills/`) and lead resources (`prompts/`)
146
146
 
147
- - [`prompts/lead/okstra-lead-contract.md`](../prompts/lead/okstra-lead-contract.md) main okstra lead contract. It is a runtime resource (`~/.okstra/prompts/lead/`), not an agent skill.
147
+ - [`prompts/lead/okstra-lead-contract.md`](../prompts/lead/okstra-lead-contract.md) is the runtime-neutral lifecycle core: phase boundaries, artifacts, convergence, report ownership, and persistence semantics.
148
+ - `prompts/lead/adapters/claude-code.md`, `prompts/lead/adapters/codex.md`, and `prompts/lead/adapters/external.md` map the same semantic operations to one selected host runtime. The generated launch prompt exposes the core path plus exactly one adapter path.
149
+ - Runtime selection and worker-provider assignment remain independent. Milestone 1 keeps `claude-execution-prompt.md`, existing manifest role labels, model defaults, and worker rosters for compatibility; provider registry and front-door separation are later milestones.
148
150
  - [`skills/okstra-setup/SKILL.md`](../skills/okstra-setup/SKILL.md) — **first-run bootstrap**. Runs `okstra install` and creates `project.json`.
149
151
  - [`skills/okstra-run/SKILL.md`](../skills/okstra-run/SKILL.md) — in-session entry point that **starts an okstra task in the current Claude session**. Calls `prepare_task_bundle` directly.
150
152
  - Thirteen skills are user-invocable: `skills/okstra-setup/SKILL.md`, `skills/okstra-brief-gen/SKILL.md`, `skills/okstra-run/SKILL.md`, `skills/okstra-manager/SKILL.md`, `skills/okstra-memory/SKILL.md`, `skills/okstra-inspect/SKILL.md`, `skills/okstra-rollup/SKILL.md`, `skills/okstra-usage/SKILL.md`, `skills/okstra-schedule/SKILL.md`, `skills/okstra-container-build/SKILL.md`, `skills/okstra-graphify/SKILL.md`, `skills/okstra-pr-gen/SKILL.md`, and `skills/okstra-user-response/SKILL.md`. Only these are copied into the agent skill home. They cover brief authoring, phase execution, cross-project manager task coordination, global Memory Book storage/search, read-side status/history/report/time/logs/cost/errors/recap, task-group-level aggregation of run results (rollup), project-wide historical resource usage, schedule support, local container deployment, `.okstra` knowledge graphs, PR description generation, and clarification-response submission. `okstra-manager` uses `okstra manager` CLI JSON/launch packets as the source of truth, and stores manager-owned plans, assignments, directives, snapshots, and events under `~/.okstra/managers/<manager-id>/`. `okstra-rollup` is a read-side layer that fans the single-task aggregators from `okstra-inspect` (time/errors/recap) out to a task group or the whole project catalog. The `okstra rollup` CLI owns deterministic aggregation, while the skill (LLM) writes only the synthesized report summary. `okstra-usage` is a separate read-only resource snapshot grouped by lifecycle task type; it does not replace single-task `okstra-inspect` detail or the status/report digest from `okstra-rollup`. The canonical definition of `okstra-inspect` read-side facets is the subcommand table in `skills/okstra-inspect/SKILL.md`. `okstra-inspect logs` provides a read-only inventory and cleanup guidance for the live-log sidecars that the Codex/Antigravity wrappers write on every dispatch at the resolved `<run-dir>/prompts/<worker>-prompt-<phase>-<seq>.log`; for stage executions, the stage-qualified `run_dir` includes `stage-<N>/`. `okstra-inspect cost` summarizes `okstra context-cost`; `okstra-inspect errors` collects a task's okstra-run error logs into a timestamped Markdown error report and prints a summary; and `okstra-inspect recap` answers free-form questions about `.okstra` artifacts in addition to summarizing phases before and after each task run.
@@ -351,7 +351,7 @@ Optional (v1.0 하위호환) 최상위 키:
351
351
  | `agents/workers/antigravity-worker.params.json` | Antigravity analyzer/verifier/executor wrapper params (build 가 `_cli-wrapper-template.md` 로 `.md` 렌더) |
352
352
  | `agents/workers/report-writer-worker.md` | data.json SSOT author and audit sidecar writer |
353
353
 
354
- The lead operating contract moved out of `agents/` to `prompts/lead/okstra-lead-contract.md` (a runtime resource installed to `~/.okstra/prompts/lead/`, not an agent skill).
354
+ The neutral lead lifecycle contract lives at `prompts/lead/okstra-lead-contract.md`. Host mappings live under `prompts/lead/adapters/`: `claude-code.md`, `codex.md`, and `external.md`. All are runtime resources installed under `~/.okstra/prompts/lead/`, not agent skills.
355
355
 
356
356
  ### 4.12 `tests/` and `tests-e2e/`
357
357
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.121.0",
3
+ "version": "0.122.0",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.121.0",
3
- "builtAt": "2026-07-15T15:37:19.231Z",
2
+ "package": "0.122.0",
3
+ "builtAt": "2026-07-16T04:13:37.510Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -74,7 +74,7 @@ Follow the **Worker output sections** contract in the preamble you Read via the
74
74
 
75
75
  ## Stop Condition (BLOCKING)
76
76
 
77
- When Lead dispatches you with `run_in_background: true`, its `Agent()` call returns `Spawned successfully` **immediately** and does NOT block on your completion — Lead detects your completion by self-scheduled polling of your worker-results file (see `team-contract` "Worker-completion detection (self-scheduled polling)"). Therefore you MUST write your worker-results file at the canonical Result Path before returning: that file's appearance is the ONLY completion signal Lead uses. Lingering after your worker-results file is on disk extends Phase 4 wall-clock time for the entire run and delays convergence. Be deliberate about stopping.
77
+ When Lead dispatches you with `run_in_background: true`, its `Agent()` call returns `Spawned successfully` **immediately** and does NOT block on your completion — Lead detects your completion by self-scheduled polling of your worker-results file (see `team-contract` "Worker-completion detection"). Therefore you MUST write your worker-results file at the canonical Result Path before returning: that file's appearance is the ONLY completion signal Lead uses. Lingering after your worker-results file is on disk extends Phase 4 wall-clock time for the entire run and delays convergence. Be deliberate about stopping.
78
78
 
79
79
  After your `Write` to the assigned worker-results file (path provided by Lead as `**Result Path:**` — the canonical anchor header defined in `team-contract` "Worker Prompt Composition" — or derived under `runs/<task-type>/worker-results/claude-worker-<task-type>-<seq>.md`) succeeds:
80
80
 
@@ -91,7 +91,7 @@ options:
91
91
  --lead-model Model for Claude lead. Default: OKSTRA_DEFAULT_LEAD_MODEL or opus
92
92
  --claude-model Model for Claude worker. Default: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
93
93
  --codex-model Model for Codex worker. Default: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6
94
- --antigravity-model Model for Antigravity worker. Default: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or auto
94
+ --antigravity-model Model for Antigravity worker. Default: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
95
95
  --report-writer-model
96
96
  Model for report writer worker. Default: OKSTRA_DEFAULT_REPORT_WRITER_MODEL or lead model default
97
97
  --lead-runtime Lead runtime adapter. Default: claude-code.
@@ -125,7 +125,7 @@ model defaults:
125
125
  Report writer worker: OKSTRA_DEFAULT_REPORT_WRITER_MODEL or Claude lead default
126
126
  Claude worker: OKSTRA_DEFAULT_CLAUDE_MODEL or opus
127
127
  Codex worker: OKSTRA_DEFAULT_CODEX_MODEL or gpt-5.6
128
- Antigravity worker: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or auto
128
+ Antigravity worker: OKSTRA_DEFAULT_ANTIGRAVITY_MODEL or gemini-3.1-pro
129
129
  Implementation executor: OKSTRA_DEFAULT_EXECUTOR or claude (one of: claude | codex | antigravity)
130
130
 
131
131
  output:
@@ -5,7 +5,7 @@
5
5
 
6
6
  ## Progress reporting (BLOCKING)
7
7
 
8
- Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at every checkpoint enumerated in the okstra lead contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Progress reporting (BLOCKING)") — phase-1-intake start/complete, phase-2-prompts, phase-3-team-create, phase-4-dispatch (per worker), phase-5-collect (per worker), phase-5.5-convergence (per round), phase-6-synthesis, phase-7-persist, and final `complete`. One line per checkpoint, never batched, never replaced with prose. This is the only signal the user has during multi-minute silent windows.
8
+ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at every checkpoint enumerated in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Progress reporting (BLOCKING)") — phase-1-intake start/complete, phase-2-prompts, phase-3-team-create, phase-4-dispatch (per worker), phase-5-collect (per worker), phase-5.5-convergence (per round), phase-6-synthesis, phase-7-persist, and final `complete`. One line per checkpoint, never batched, never replaced with prose. This is the only signal the user has during multi-minute silent windows.
9
9
 
10
10
  ## Current Phase Boundary
11
11
 
@@ -19,7 +19,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
19
19
  {{VERIFICATION_TARGET}}
20
20
  {{STAGE_INTEGRATION}}
21
21
  - Phase advancement requires a new okstra invocation launched with `--task-type {{WORKFLOW_NEXT_RECOMMENDED_PHASE}}` after this run's final report is written and approved. The lead must not write source code, run builds/migrations/deployments, or otherwise produce artifacts of a different phase from inside this run.
22
- - See `Lifecycle Phase Boundaries` in the okstra lead contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}`) for the canonical rules and the phase-transition checklist.
22
+ - See `Lifecycle Phase Boundaries` in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}`) for the canonical rules and the phase-transition checklist.
23
23
 
24
24
  {{TEAM_CREATION_GATE}}
25
25
 
@@ -58,7 +58,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
58
58
  - Codex worker: `{{CODEX_WORKER_ERRORS_SIDECAR_PATH}}`
59
59
  - Antigravity worker: `{{ANTIGRAVITY_WORKER_ERRORS_SIDECAR_PATH}}`
60
60
  - Report writer worker: `{{REPORT_WRITER_WORKER_ERRORS_SIDECAR_PATH}}`
61
- - The paths above are the values; the wiring duties — injecting the `**Errors log path:**` / `**Errors sidecar path:**` header pair into every dispatch prompt, and dumping each terminated worker's sidecar via `okstra error-log append-from-worker` — are defined once in the okstra lead contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Errors log path wiring (BLOCKING)"). Follow that section; do not re-derive the rules from this block.
61
+ - The paths above are the values; the wiring duties — injecting the `**Errors log path:**` / `**Errors sidecar path:**` header pair into every dispatch prompt, and dumping each terminated worker's sidecar via `okstra error-log append-from-worker` — are defined once in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Errors log path wiring (BLOCKING)"). Follow that section; do not re-derive the rules from this block.
62
62
 
63
63
  ## Executor Worktree
64
64
 
@@ -76,7 +76,7 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
76
76
 
77
77
  {{AVAILABLE_MCP_SERVERS}}
78
78
  - The full usage policy and per-phase rules live in the analysis packet's `Available MCP Servers` extract. Inject only the one-line pointer below into each analysis-worker prompt: `**MCP servers:** follow the analysis packet's "Available MCP Servers" section (already in your Required reading).`
79
- - **Invocation rule (forward to every worker prompt)**: MCP tools are addressed by their tool name through the host's tool interface — **never via `Bash`**. Claude-side workers call the tool directly (e.g. `mcp__<server>__<tool>`). Codex/Antigravity workers call through their CLI's own MCP transport (e.g. `codex mcp call ...`). Running the tool name as a shell command is a contract violation and will always fail regardless of permission grants.
79
+ - **Invocation rule (forward to every worker prompt)**: MCP tools are addressed through the executing worker provider's native tool interface — never by running the tool name as a shell command. In-process workers call the tool directly; CLI workers use that CLI's configured MCP transport. A worker without the configured MCP server records `MCP not available in this CLI` instead of guessing.
80
80
  - Codex worker and Antigravity worker run external CLIs; they can only use these MCP servers if their own CLI configs mirror them. If not, instruct the worker to record `MCP not available in this CLI` in its `Missing Information or Assumptions` block rather than guessing or shell-falling-back.
81
81
  - MCP queries are evidence-grade. Cite server, table, and the SELECT used in worker output. MCP must NOT be used as a write path in any phase, including `implementation`.
82
82
 
@@ -0,0 +1,104 @@
1
+ # Claude Code Lead Runtime Adapter
2
+
3
+ ## Scope
4
+
5
+ This adapter maps the neutral Okstra lead operations to Claude Code host primitives. Read it only when the rendered launch prompt selects `leadRuntime=claude-code`.
6
+
7
+ ## Capability declaration
8
+
9
+ | Field | Value |
10
+ |---|---|
11
+ | `runtime` | `claude-code` |
12
+ | `leadRoleLabel` | `Claude lead` |
13
+ | `userPromptMode` | `native-question` |
14
+ | `workerDispatchBackend` | `team` |
15
+ | `sessionAccounting` | `claude-jsonl` |
16
+ | `resumeMode` | `session-id` |
17
+ | `teardownMode` | `teammate-shutdown` |
18
+ | `leadEventSource` | `claude-jsonl+artifact` |
19
+
20
+ ## Semantic operation mapping
21
+
22
+ | Operation | Mapping |
23
+ |---|---|
24
+ | `read_artifacts` | Use the host file-read primitive and preserve the core contract's read order. |
25
+ | `write_artifact` | Use the host file-write primitive only for paths authorized by the active lifecycle phase. |
26
+ | `prompt_user` | Use the native question tool for approvals and clarifications; do not infer an answer from silence. |
27
+ | `dispatch_worker` | Dispatch `Agent(name: "<role>", run_in_background: true)` without `team_name`; apply the assigned model as specified below. |
28
+ | `await_workers` | Arm one background shell poll for the pending Result Paths; the spawn acknowledgement is not completion. |
29
+ | `redispatch_worker` | Dispatch a fresh `Agent(...)` session with the same prompt plus the core reverify/retry reason. |
30
+ | `shutdown_workers` | Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` only to confirmed-complete teammates selected for cleanup. |
31
+ | `record_lead_event` | Emit the required `PROGRESS:` line as assistant text and persist core-required state/artifact updates. |
32
+ | `collect_usage` | Run `okstra token-usage` against the team-state; it reads the run-scoped `~/.claude/projects` session JSONL evidence. |
33
+
34
+ ## Dispatch variants
35
+
36
+ - The session owns one implicit team. `TeamCreate` and `TeamDelete` are absent on current Claude Code builds; never probe for them and never pass `team_name`.
37
+ - Set `name` to the core-assigned functional role label so token attribution can match `agentName`.
38
+ - Map the core assignment key to the native `subagent_type` field: `claude-worker`, `codex-worker`, `antigravity-worker`, or `report-writer-worker`. Never substitute `general-purpose` for a rostered Report writer worker.
39
+ - For in-process Claude and report-writer roles, map `modelExecutionValue` to the supported family token and pass it as the `model` argument. CLI-wrapper roles apply their model in the wrapper and remain `inherit` at the Agent layer.
40
+ - A resumed lead can dispatch a fresh worker; resume is not a valid reason to omit a rostered role.
41
+
42
+ ### Dispatch-time model enforcement
43
+
44
+ - `Claude worker` and `Report writer worker` definitions declare `model: inherit`; the lead MUST override that default by passing the assigned family token (`fable`, `opus`, `sonnet`, or `haiku`) as the `Agent(...)` `model` argument.
45
+ - Codex and Antigravity wrapper agents remain `inherit` at the Agent layer because their exact `modelExecutionValue` is applied by the wrapper CLI's own model argument.
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
+ - 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
+ - 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 auto-loads the in-process `claude-worker` definition, so that worker's prompt body may be shorter than CLI-wrapper prompt bodies; every worker still receives the same Worker Preamble pointer and core inputs.
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
+ - An internally detected contract violation without a specific worker uses `--agent "claude-lead"` in the error-log event.
52
+
53
+ ### Reverify, critic, and report-writer assignments
54
+
55
+ - 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
+ - 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
+ - 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.
58
+ - Each variant persists its prompt path, Result Path, worker-results path, error paths, and `dispatchKind` before dispatch. Completion uses the shared background Result Path poll; an Agent acknowledgement never completes the variant.
59
+
60
+ ## Completion, cleanup, and resume
61
+
62
+ - 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.
63
+ - 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.
64
+ - The Claude 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.
65
+ - 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.
66
+ - On approved cleanup, reconcile the current live session roster before sending shutdown requests. Never target the lead session.
67
+ - Collect usage before teardown. Resume through the recorded Claude session id and keep all run artifacts authoritative.
68
+
69
+ ### CLI-wrapper polling
70
+
71
+ - Start `okstra-codex-exec.sh` / `okstra-antigravity-exec.sh` with `Bash(run_in_background: true)` and poll `BashOutput(bash_id)` back-to-back until terminal completion. Never add a foreground sleep.
72
+ - Return accumulated stdout on success. On a non-zero `exit_code`, record the real code and observed duration.
73
+ - At the 1800-second cap, inspect the live log mtime once. Recent output grants one extension to 2100 seconds; otherwise call `KillShell(shell_id)`, record exit code 124, and return the wrapper timeout sentinel.
74
+ - Keep the wrapper subagent alive throughout polling so its JSONL timestamp window covers the underlying CLI rollout.
75
+
76
+ ### Session accounting
77
+
78
+ - At the start of Phase 7, run `okstra token-usage /abs/path/to/run/state/team-state-<task-type>-<seq>.json --write --summary` with the literal team-state path.
79
+ - Read the lead and Claude-side wrapper evidence from `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`; attribute workers by the dispatch `agentName` recorded above.
80
+ - Resolve `teamName` from `state.teamName` or `state.team.teamName` and use the full manifest-provided value as the team needle. If it is missing, the collector's short-form fallback cannot match worker JSONLs and records those workers as `source: "unavailable"`.
81
+ - Keep underlying Codex and Antigravity CLI usage separate from the Claude wrapper-session usage. Persist `leadUsage`, per-worker usage, and `usageSummary` before report substitution and cleanup.
82
+
83
+ ## Run-scoped resource lifecycle
84
+
85
+ - At run start, record `teamName` as the audit label and `teamCreate: { attempted: false, status: "implicit", splitPane: <bool> }` in team-state. A concurrent run records `status: "skipped", reason: "concurrent-run"`. Populate `lead.sessionId`; the session transcript lives under `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`.
86
+ - Record the lead pane once with `mkdir -p "<RUN_DIR>/state" && { . "$HOME/.okstra/bin/lib/okstra/tmux-pane.sh" 2>/dev/null && okstra_resolve_caller_pane; } > "<RUN_DIR>/state/lead-pane.id" 2>/dev/null || true`. This is silent setup and must not gate cleanup; the cleanup script protects the lead pane itself.
87
+ - Collect and persist token usage before any live-roster cleanup, including cleanup between batches and the run-end shutdown sequence.
88
+ - Before each new worker batch, run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"`, then send `SendMessage(to: <name>, message: { type: "shutdown_request" })` only to confirmed-complete teammates from the prior batch. Never target the lead or an incomplete critic/reverify worker.
89
+ - After batch cleanup, record the current live session generation with `okstra token-usage "<TEAM_STATE_PATH>" --record-observed-session --project-root "<PROJECT_ROOT>"`. This protects usage accounting when Claude Code re-issues the session id after resume or compaction.
90
+ - Claude Code cannot delete the implicit team or surgically remove an idle roster entry. Explain that teammates may remain visible until session end and, when needed, give the manual action `Delete team <teamName> in Teams/FleetView`.
91
+ - The `SessionEnd` hook runs `$HOME/.okstra/bin/okstra-team-reconcile.sh --session-end` as the safety net for the current live session.
92
+
93
+ ### Run-end cleanup sequence (BLOCKING)
94
+
95
+ 1. Call `collect_usage` through this adapter and persist usage before inspecting or changing any residual resource.
96
+ 2. Run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --list --run-dir "<RUN_DIR>"` exactly once and inspect the current live roster without mutating it.
97
+ 3. If no residual pane and no current live roster exists, skip the question and perform no cleanup operation.
98
+ 4. Otherwise call `prompt_user` exactly once with this binary prompt. This one answer controls the complete residual pane and teammate set; never ask a second teammate-only question.
99
+ > This phase is ending. The following Okstra panes and worker teammates remain — close and clean them up?
100
+ > <quoted `--list` output>
101
+ > (Yes) Close everything and clean up teammates / (No) Keep everything
102
+ 5. On `keep`, preserve every residual resource and show `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"` plus the manual Teams/FleetView action.
103
+ 6. On approved `clean`, emit the teardown checkpoint, run `$HOME/.okstra/bin/okstra-trace-cleanup.sh --run-dir "<RUN_DIR>"`, then run `$HOME/.okstra/bin/okstra-team-reconcile.sh --project-root "<PROJECT_ROOT>" --fallback-team "session-<lead.sessionId-prefix>"` exactly once. The resolver reads the current live session's `~/.claude/teams/session-<live>/config.json`, falling back to the snapshot directory only when the live directory is absent, and prints `dismissible-member: <name>` records.
104
+ 7. Send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to each printed, confirmed-complete non-lead member. The `message` MUST be the object literal shown, NEVER a JSON string in a text field. Never target the lead or use `TaskStop`; teammates are not background tasks.
@@ -0,0 +1,45 @@
1
+ # Codex Lead Runtime Adapter
2
+
3
+ ## Scope
4
+
5
+ This adapter maps the neutral Okstra lead operations to the Codex artifact-first CLI path. Read it only when the rendered launch prompt selects `leadRuntime=codex`.
6
+
7
+ ## Capability declaration
8
+
9
+ | Field | Value |
10
+ |---|---|
11
+ | `runtime` | `codex` |
12
+ | `leadRoleLabel` | `Codex lead` |
13
+ | `userPromptMode` | `host-text` |
14
+ | `workerDispatchBackend` | `cli-wrapper` |
15
+ | `sessionAccounting` | `artifact-only` |
16
+ | `resumeMode` | `artifact-checkpoint` |
17
+ | `teardownMode` | `process-cleanup` |
18
+ | `leadEventSource` | `lead-events-jsonl` |
19
+
20
+ ## Semantic operation mapping
21
+
22
+ | Operation | Mapping |
23
+ |---|---|
24
+ | `read_artifacts` | Read the manifest-provided paths through the current host's file interface. |
25
+ | `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
26
+ | `prompt_user` | Ask through the host text/question interface and stop at approval gates until an explicit answer arrives. |
27
+ | `dispatch_worker` | Run `okstra codex-dispatch --project-root <root> --run-manifest <path>`; use `--dry-run` first when the core requires a dispatch preview. |
28
+ | `await_workers` | Treat the synchronous dispatch return plus team-state terminal records and Result Paths as completion evidence. |
29
+ | `redispatch_worker` | Invoke a fresh `okstra codex-dispatch` worker attempt for the selected role and record the retry/reverify dispatch kind. |
30
+ | `shutdown_workers` | Perform process cleanup when a wrapper remains live; otherwise this operation is a no-op recorded in state. |
31
+ | `record_lead_event` | Append the required structured event to the manifest-provided `leadEventsPath`; emit the matching user-facing `PROGRESS:` line. |
32
+ | `collect_usage` | Collect artifact/rollout-backed usage through the existing Okstra token-usage path; never read Claude session JSONL as a substitute. |
33
+
34
+ ## Codex dispatch details
35
+
36
+ - Do not invoke Claude Code team or subagent tools.
37
+ - 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
+ - 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.
39
+ - Reverify and critic retries invoke a fresh worker attempt and persist the core-supplied `dispatchKind` (`reverify-r<N>` or `critic`) in the dispatch record; never reuse a prior rollout as a new vote.
40
+ - Report-writer completion requires both the data.json Result Path and the worker-results audit path, even when the synchronous dispatch command exits successfully.
41
+
42
+ ## Completion, cleanup, and resume
43
+
44
+ - A successful synchronous dispatch return alone is insufficient; verify terminal state, every required completion path, and the corresponding worker-dispatch audit record before counting the worker as complete.
45
+ - Resume from run artifacts and lead-events checkpoints. Do not invent a Claude session id.
@@ -0,0 +1,46 @@
1
+ # External Lead Runtime Adapter
2
+
3
+ ## Scope
4
+
5
+ This adapter maps the neutral Okstra lead operations to a generic host using Okstra-owned tmux panes. Read it only when the rendered launch prompt selects `leadRuntime=external`.
6
+
7
+ ## Capability declaration
8
+
9
+ | Field | Value |
10
+ |---|---|
11
+ | `runtime` | `external` |
12
+ | `leadRoleLabel` | `Okstra lead` |
13
+ | `userPromptMode` | `host-text` |
14
+ | `workerDispatchBackend` | `tmux-pane` |
15
+ | `sessionAccounting` | `artifact-only` |
16
+ | `resumeMode` | `artifact-checkpoint` |
17
+ | `teardownMode` | `pane-teardown` |
18
+ | `leadEventSource` | `lead-events-jsonl` |
19
+
20
+ ## Semantic operation mapping
21
+
22
+ | Operation | Mapping |
23
+ |---|---|
24
+ | `read_artifacts` | Read the manifest-provided paths through the current host's file or shell interface. |
25
+ | `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
26
+ | `prompt_user` | Ask through the host text/question interface and require an explicit approval or clarification response. |
27
+ | `dispatch_worker` | Run `okstra team dispatch --project-root <root> --run-manifest <path>`; use `--dry-run` first when the core requires a dispatch preview. |
28
+ | `await_workers` | Run `okstra team await --project-root <root> --run-manifest <path>` through the host's asynchronous shell facility. |
29
+ | `redispatch_worker` | Create the core-specified fresh jobs file and dispatch it with a new `dispatchKind`; never reuse a live worker conversation. |
30
+ | `shutdown_workers` | Run `okstra team teardown --project-root <root> --run-manifest <path>` only after the user-approved cleanup gate. |
31
+ | `record_lead_event` | Append the required structured event to the manifest-provided `leadEventsPath`; emit the matching user-facing `PROGRESS:` line. |
32
+ | `collect_usage` | Collect artifact/CLI-log-backed usage through the existing Okstra token-usage path; never substitute another runtime's session log. |
33
+
34
+ ## External dispatch details
35
+
36
+ - Do not invoke Claude Code team tools or `okstra codex-dispatch`.
37
+ - Worker completion is valid only from `workerDispatches[]`, terminal status sidecars, and required Result Paths. Pane creation alone is not completion.
38
+ - 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>`.
39
+ - Report-writer uses a fresh one-job jobs file with `dispatchKind: "report-writer"` and the same schema, then dispatches through `okstra team dispatch --project-root <root> --run-manifest <path> --jobs-file <jobs-file>`.
40
+ - Every reverify or report-writer jobs file carries `workerId`, `provider`, `role`, `modelExecutionValue`, `promptPath`, `resultPath`, `workerResultPath`, and `completionPaths`. For reverify, set `role` to `worker-reverify-r<N>` for the pane title. The report-writer completion paths include both data.json and the worker-results audit file.
41
+ - After either dispatch, run `okstra team await --project-root <root> --run-manifest <path>` before evaluating terminal status or completion paths.
42
+
43
+ ## Completion, cleanup, and resume
44
+
45
+ - Await through `okstra team await`; raw Result Path polling is forbidden for this backend.
46
+ - Resume from run artifacts and lead-events checkpoints. After usage collection, persistence, and the core user-approval gate, run `okstra team teardown --project-root <root> --run-manifest <path>` and tear down only Okstra-owned panes recorded for the run.
@@ -81,10 +81,10 @@ After identifying the task root in `task-manifest.json`, derive all paths accord
81
81
  │ └── <task-type>/ (Run scope isolated per task-type, e.g. error-analysis)
82
82
  │ ├── manifests/ (run-manifest-<task-type>-<seq>.json)
83
83
  │ ├── state/ (team-state-<task-type>-<seq>.json, convergence-<task-type>-<seq>.json)
84
- │ ├── prompts/ (claude-execution-prompt-<task-type>-<seq>.md and worker prompt history files)
84
+ │ ├── prompts/ (run prompt path and worker prompt history paths recorded in the manifest)
85
85
  │ ├── reports/ (final-report-<task-type>-<seq>.md)
86
86
  │ ├── status/ (final-<task-type>-<seq>.status)
87
- │ ├── sessions/ (claude-resume-<task-type>-<seq>.sh)
87
+ │ ├── sessions/ (runtime-specific resume artifacts when the selected adapter supports them)
88
88
  │ ├── logs/ (errors-<task-type>-<seq>.jsonl, optional)
89
89
  │ └── worker-results/
90
90
  │ ├── claude-worker-<task-type>-<seq>.md
@@ -147,6 +147,6 @@ Information produced after completing this contract:
147
147
  - Reference list of config files/deployment manifests and task-level expected values
148
148
  - Current run status and presence of existing worker results
149
149
  - Current run prompt history contract for attempted workers
150
- - Candidate `teamName` for Phase 3 hand-off: `okstra-<task-key>` (with task-key slugified per Step 1's slug rule); implementation stage runs append `-s<N>` the launch prompt's Teammate Dispatch Gate block carries the final name verbatim
151
- - Current Claude `lead.sessionId` (the in-flight Claude Code session) — required by `team-contract` when registering the lead in `team-state.json`
152
- - Resume command path: from `task-manifest.json` → `latestResumeCommandPath` (fallback: latest `runs/<task-type>/sessions/claude-resume-*.sh` by mtime). Never reconstruct the filename — the `<seq>` counter is category-local and may diverge from `manifests/`.
150
+ - Candidate `teamName` for the manifest/team-state audit identity: `okstra-<task-key>` (with task-key slugified per Step 1's slug rule); implementation stage runs append `-s<N>`. The selected runtime adapter owns whether an adapter-specific audit label is exposed in the launch prompt's "Runtime Adapter Dispatch Gate (BLOCKING)" setup facts; this common contract does not guarantee that label for every runtime.
151
+ - Current lead session/checkpoint identity, when supplied by the selected adapter
152
+ - Resume artifact path from `task-manifest.json.artifacts.resumeCommandPath`; never reconstruct a runtime-specific filename
@@ -12,7 +12,7 @@
12
12
  - [Convergence Test](#convergence-test)
13
13
  - [Verification Mode](#verification-mode)
14
14
  - [Adversarial Verification Mode](#adversarial-verification-mode)
15
- - [Re-verification Agent Dispatch](#re-verification-agent-dispatch)
15
+ - [Re-verification Dispatch](#re-verification-dispatch)
16
16
  - [Convergence State Artifact](#convergence-state-artifact)
17
17
  - [Coverage critic pass](#coverage-critic-pass)
18
18
  - [Acceptance critic pass (final-verification)](#acceptance-critic-pass-final-verification)
@@ -74,7 +74,7 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
74
74
  - Items with multiple tickets (e.g. `TICKET-123, TICKET-456`) expand to a set of ticket keys.
75
75
  - Items tagged `unknown` keep the literal `unknown` as their ticket key.
76
76
  2. For each finding, record the summary, evidence (file path, line number, basis), the worker who identified it, **the worker-internal item ID assigned by that worker** (e.g. `F-001`, `1.1`, `F-3` — see `prompts/profiles/_common-contract.md` "Cross-worker traceability" SSOT), and the parsed ticket set. The item ID is persisted on the finding record as `findings[].discoveredBy.<worker>.itemId` and on each cross-worker confirmation as `findings[].sourceItems[]` (one entry per contributing `<worker>:<item-id>` pair). The final-report's `## 6.1 Consensus` / `## 6.2 Differences` / `## 2.1 Primary Evidence` tables read this list verbatim into their `Source items` columns — without this, the synthesised `C-NNN` row has no traceable link back to the original worker wording.
77
- 3. Claude Lead groups findings based on semantic similarity AND ticket-set equality:
77
+ 3. The lead groups findings based on semantic similarity AND ticket-set equality:
78
78
  - Same semantics + same ticket set across 2+ workers → immediately reach `full consensus`.
79
79
  - Same semantics but disjoint ticket sets → keep as separate groups (do NOT over-merge across tickets).
80
80
  - Only one worker confirms a finding → `unique`, enter the verification queue.
@@ -165,7 +165,7 @@ A reverify dispatch that returns a **terminal non-result** (`timeout`, `error`,
165
165
  Rules:
166
166
 
167
167
  1. For each affected finding, append a `votes[W].verdict = "verification-error"` entry instead of `disagree`, plus the wrapper's captured exit reason in `votes[W].explanation`.
168
- 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 Codex/Antigravity; for Claude worker timeouts the lead does it).
168
+ 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).
169
169
  3. Add an entry to the round's `skippedWorkers[]` with `{worker: <W>, reason: "dispatch-non-result", terminalStatus: <timeout|error|not-run>}`.
170
170
  4. If at least one dispatch was issued AND all reverify dispatches in a round terminate as non-result (mirroring the pseudocode's `len(dispatches) > 0` guard), the round is treated as gate-closed: write `round2SkippedReason: "all-reverify-non-result"` (even if the round in question is round 1 — i.e. round 2 never runs because round 1 produced no usable votes), record one `contract-violation` event per non-result dispatch, and exit the WHILE loop.
171
171
  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`.
@@ -248,31 +248,16 @@ ELSE:
248
248
 
249
249
  Design intent: one `counter-evidence` refute is enough to deny a claim consensus (it cannot rise above `contested` no matter how many others AGREE), while a single `burden-not-met` doubt does not by itself sink an otherwise-surviving claim — only a majority of burden-not-met doubts does. When every non-discoverer refutes (all_others_disagree), the finding is worker-unique regardless of whether those refutes were counter-evidence or burden-not-met — only the discoverer still holds it. A SUPPLEMENT/caveat with zero disagrees lands partial-consensus rather than full-consensus, because a caveat means the claim does not pass cleanly (this differs from the collaborative classifier, where SUPPLEMENT counts as full agreement).
250
250
 
251
- ## Re-verification Agent Dispatch
251
+ ## Re-verification Dispatch
252
252
 
253
253
  ### Sponsorship Optimization
254
254
 
255
- Processing is performed by spawning each worker once per round. All findings to be verified by that worker are included in a single prompt.
255
+ For each analysis worker with a non-empty current round's `items_for_W` batch, build one reverify prompt and call `redispatch_worker(assignment, prompt, reason)` exactly once per worker through the selected runtime adapter. The batch contains only that worker's eligible findings from the current verification queue; final classification labels never select dispatch targets. 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.
256
256
 
257
- ```text
258
- Agent(
259
- description: "Re-verify findings for <task-key> round <N>",
260
- prompt: "<re-verification prompt with findings batch>",
261
- name: "<role-slug>-reverify-r<N>",
262
- subagent_type: "<same as initial execution>",
263
- run_in_background: true, # no team_name — implicit team; see team-contract Operating Rule 0
264
- model: "<same as initial execution>",
265
- mode: "auto"
266
- )
267
- ```
268
-
269
- - Claude / in-process worker: spawn with `Agent(name: ..., run_in_background: true)` per [team-contract](./team-contract.md) rule 0 (split-pane when `$TMUX` is set)
270
- - CLI (Codex / Antigravity) worker: inject `**Pane role:** worker-reverify-r<N>` (the Agent `name` minus the `<cli>-` prefix) into the reverify prompt body so the tmux trace pane reads `<cli>-worker-reverify-r<N>` per [okstra-lead-contract](./okstra-lead-contract.md) "Agent `name` on dispatch".
257
+ 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.
271
258
 
272
- For `tmux-pane` backend runs, do not use the Agent snippet. For each reverify round, write a jobs file at `runs/<task-type>/state/reverify-jobs-r<N>-<task-type>-<seq>.json` with `dispatchKind: "reverify-r<N>"` and worker entries containing `workerId`, `provider`, `role` (set to `worker-reverify-r<N>` for the pane title), `modelExecutionValue`, `promptPath`, `resultPath`, `workerResultPath`, and `completionPaths`; then run `okstra team dispatch --project-root <dir> --run-manifest <path> --dispatch-kind reverify-r<N> --jobs-file <jobs-file>` followed by `okstra team await --project-root <dir> --run-manifest <path>`.
273
259
 
274
-
275
- **Completion detection per round (BLOCKING).** The spawn acks are NOT completion — detect each round's completion via the SSOT protocol in [team-contract](./team-contract.md) "Worker-completion detection (self-scheduled polling)", with the pending set reconstructed from that round's dispatched workers' Result Paths. Do NOT end the turn with a prose "waiting" statement.
260
+ **Completion detection per round (BLOCKING).** A dispatch acknowledgement is NOT completion — detect each round's completion via the SSOT protocol in [team-contract](./team-contract.md) "Worker-completion detection", with the pending set reconstructed from that round's dispatched workers' Result Paths. Do NOT end the turn with a prose "waiting" statement.
276
261
 
277
262
  ### Required reverify-prompt anchor headers (BLOCKING)
278
263
 
@@ -292,9 +277,7 @@ Assigned worker prompt history path: <Project Root>/<Prompt History Path>
292
277
  2. `team-state-<task-type>-<seq>.json` → `workers[].usage.cliModel` for that role (initial run's actual execution value)
293
278
  3. The `**Model:**` line of the initial Phase 4 prompt for that role (read from its persisted prompt-history file)
294
279
 
295
- If none of the three is available, **abort the reverify dispatch for that role** and record a `contract-violation` event via `okstra error-log append-observed`. Do NOT guess, do NOT fall back to training-data defaults for codex this silently produces `o4-mini` instead of the assigned `gpt-5.6`-class model.
296
-
297
- For Codex/Antigravity wrapper subagents, the `**Model:** <role>, <modelExecutionValue>` line is what their wrapper extracts to pass into the underlying CLI's `--model` flag. Omitting it forces the wrapper to fall back to its own training-data knowledge of the CLI's historical default.
280
+ If none of the three is available, **abort the reverify dispatch for that role** and record a `contract-violation` event via `okstra error-log append-observed`. Do NOT guess or fall back to a runtime default. The selected adapter receives the exact value through the assignment and owns how it reaches the worker runtime. The current Codex catalog default is `gpt-5.6`, but that reference value never replaces the manifest assignment.
298
281
 
299
282
  ### Reverify prompt: required-reading suppression
300
283
 
@@ -524,8 +507,8 @@ The critic input is the Round 0 consolidated finding list. Reverify rounds only
524
507
  - **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.
525
508
  - **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 — surface the gaps as unverified `clarification` items per §"Gap verification" and record that fact.
526
509
 
527
- ### Dispatch (reused worker)
528
- Dispatch ONE pass to the `config.critic.provider`'s existing subagent (`claude-worker` / `codex-worker` / `antigravity-worker`) with `model = config.critic.modelExecutionValue` no new agent type, `name: "<provider>-worker-critic"`. If `config.critic.modelExecutionValue` is null/empty (model could not be resolved), skip the critic pass and record `critic-skipped: model-unresolved` in the convergence state rather than dispatching with no model. For a CLI (Codex / Antigravity) critic dispatch, inject `**Pane role:** worker-critic` into the prompt body so the trace pane reads `<cli>-worker-critic` per [okstra-lead-contract](./okstra-lead-contract.md) "Agent `name` on dispatch". 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:
510
+ ### Dispatch (fresh one-shot)
511
+ 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:
529
512
 
530
513
  ```
531
514
  You are the coverage critic for <task-key>. Below are the consolidated findings
@@ -546,7 +529,7 @@ Each critic gap enters the verification queue as a finding with `originWorker =
546
529
 
547
530
  ## Acceptance critic pass (final-verification)
548
531
 
549
- The `final-verification` phase reuses the SAME reused-worker dispatch AND the same dispatch timing as §"Coverage critic pass" §"When" (provider + `config.critic.modelExecutionValue` from the `convergence.critic` block; default off; same model-unresolved skip rule) — the delivered work the critic inspects is likewise fixed before the reverify round starts. Only the prompt, the verification semantics, and the output sink differ — final-verification's findings are defects/blockers, so the critic acts as an **acceptance devil's advocate** (find reasons NOT to accept), and its candidate blockers are NEVER dropped (that would suppress real defects).
532
+ The `final-verification` phase uses the same fresh one-shot `redispatch_worker` pattern and the same dispatch timing as §"Coverage critic pass" §"When" (provider + `config.critic.modelExecutionValue` from the `convergence.critic` block; default off; same model-unresolved skip rule) — the delivered work the critic inspects is likewise fixed before the reverify round starts. Only the prompt, the verification semantics, and the output sink differ — final-verification's findings are defects/blockers, so the critic acts as an **acceptance devil's advocate** (find reasons NOT to accept), and its candidate blockers are NEVER dropped (that would suppress real defects).
550
533
 
551
534
  ### Prompt
552
535