# okstra-run Performance Improvement Plan v2

## Index

- [1. Purpose](#1-purpose)
- [2. Summary of the Current Architecture](#2-summary-of-the-current-architecture)
  - [2.1 Entry Points](#21-entry-points)
  - [2.2 Distinguish the Two Kinds of Phase](#22-distinguish-the-two-kinds-of-phase)
  - [2.3 Cost Characteristics of the Prepare Step](#23-cost-characteristics-of-the-prepare-step)
  - [2.4 Worker Structure](#24-worker-structure)
- [3. Performance Bottleneck Hypotheses](#3-performance-bottleneck-hypotheses)
- [4. Measurement Criteria](#4-measurement-criteria)
  - [4.1 Measured Results (2026-06-11)](#41-measured-results-2026-06-11-fontradar-v2-api-dev-9186)
- [5. Improvement Priorities](#5-improvement-priorities)
  - [P0. Baseline Measurement and Terminology](#p0-baseline-measurement-and-terminology)
  - [P1. Reduce the Scope of Convergence Reverification](#p1-reduce-the-scope-of-convergence-reverification)
  - [P2. Prompt Diet: Reduce Analysis Worker Input](#p2-prompt-diet-reduce-analysis-worker-input)
  - [P3. Fast-track Routing](#p3-fast-track-routing)
  - [P4. Evaluate Prompt Caching Feasibility](#p4-evaluate-prompt-caching-feasibility)
  - [P5. Parallelize Prepare Rendering](#p5-parallelize-prepare-rendering)
  - [P6. Incremental Token Usage Collection](#p6-incremental-token-usage-collection)
- [6. Parallel Work Plan](#6-parallel-work-plan)
- [7. P1 Implementation Checklist](#7-p1-implementation-checklist)
- [8. Risks and Guardrails](#8-risks-and-guardrails)
- [9. Conclusion](#9-conclusion)

## 1. Purpose

Reduce the perceived cost of cross-verification runs started through the `okstra-run` skill or `scripts/okstra.sh`. This document separates the current architecture into its correct layers and defines improvement priorities, measurement criteria, opportunities for parallel work, and the initial implementation scope.

Key conclusions:

- The largest costs occur after worker dispatch, in repeated verification and long prompt consumption, rather than in the prepare step.
- First reduce the scope of convergence reverification to lower the number of worker calls and wall-clock time.
- Fast-track routing, prompt caching, and reductions to templates or worker definitions affect different layers and should be handled as separate work.

## 2. Summary of the Current Architecture

### 2.1 Entry Points

Both `scripts/okstra.sh` and `skills/okstra-run/SKILL.md` call `prepare_task_bundle()` in `scripts/okstra_ctl/run.py`. This single reference point must be preserved.

- `scripts/okstra.sh`: parses CLI arguments, calls `prepare_task_bundle()`, and runs `claude` for non-render-only executions.
- `okstra-run` skill: collects input in the current Claude session, calls the same Python entry point, and takes over the lead role.
- Shared prepare logic: `scripts/okstra_ctl/run.py`.

### 2.2 Distinguish the Two Kinds of Phase

The current documentation and code contain two layers with similarly named phases. Performance work must not conflate them.

#### Task-type lifecycle

`PHASE_SEQUENCE` in `scripts/okstra_ctl/workflow.py` contains the following task types in order.

| Order | task-type | Responsibility |
|---|---|---|
| 1 | `requirements-discovery` | Classify the work category, route safely to the next phase, and identify missing inputs |
| 2 | `error-analysis` | Analyze symptoms, root-cause hypotheses, reproduction gaps, and verification paths |
| 3 | `implementation-option-selection` | Compare implementation directions, validate exact coverage, and record the user's selected direction |
| 4 | `implementation-planning` | Expand the `selected-direction` contract into execution order, validation, rollback, and a separate plan approval request |
| 5 | `implementation` | Execute the approved plan, commit, run verifier checks, and capture rollback evidence |
| 6 | `final-verification` | Verify acceptability and residual risk, and decide whether to enter release handoff |
| 7 | `release-handoff` | Perform the commit/push/PR handoff action selected by the user |

Each okstra invocation performs exactly one task type. Moving to the next task type requires a new invocation.

#### Okstra lead operating phases

Phases 1–7 in `prompts/lead/okstra-lead-contract.md` are operating steps that the lead performs within one task-type run.

| Operating phase | Name | Responsibility |
|---|---|---|
| 1 | Intake | Read the task bundle |
| 2~5 | Prompt / Team / Execution / Fallback | Prepare worker prompts, establish the team context, and dispatch workers |
| 5.5 | Convergence | Reverify worker findings and classify consensus |
| 6 | Synthesis | Dispatch the report writer or use the lead fallback |
| 7 | Persist | Collect token usage, substitute final-report placeholders, and finalize manifests/status |

Therefore, "P1 convergence improvement" in this document does not change the task-type lifecycle. It reduces the cost of the lead operating phase defined by `prompts/lead/okstra-lead-contract.md` and `prompts/lead/convergence.md`.

### 2.3 Cost Characteristics of the Prepare Step

`prepare_task_bundle()` writes the instruction set and manifest-related files sequentially.

- Instruction set: `analysis-profile.md`, `analysis-material.md`, `task-brief.md`, optional carry-in/directive, `reference-expectations.md`, `final-report-template.md`, canonical `lead-execution-prompt.md`, and the prompt snapshot.
- Manifest/discovery: `team-state`, `task-manifest`, `task-index`, `run-manifest`, `timeline`, task catalog, and latest task.

This serial rendering has room for improvement, but it is generally cheaper than external worker dispatch. Render parallelization is therefore not the first priority.

### 2.4 Worker Structure

The four default worker definitions are under `agents/workers/`.

- `claude-worker.md`: Claude subagent.
- `codex-worker.md`: invokes the Codex CLI through the `okstra-codex-exec.sh` wrapper.
- `antigravity-worker.md`: invokes the Antigravity CLI through the `okstra-antigravity-exec.sh` wrapper.
- `report-writer-worker.md`: final-report author. It is not an analysis worker and does not vote in convergence.

## 3. Performance Bottleneck Hypotheses

| ID | Bottleneck | Impact | Evidence / location | Assessment |
|---|---|---:|---|---|
| B1 | Each convergence reverify round creates another dispatch per worker | High | `prompts/lead/convergence.md` Round 1-N | **Resolved** — P1 queue pruning implemented and critic serialization parallelized (§4.1 item 2) |
| B2 | Analysis worker prompts and required reading are long | High | `prompts/lead/okstra-lead-contract.md`, `team-contract`, worker definitions | **Mostly resolved** — analysis-packet-primary measured at 22 KB/worker (§4.1) |
| B3 | The report writer rereads worker results, convergence, and the final-report template | ~~Medium~~ Low | `prompts/lead/report-writer.md` | **Input compression rejected** — measured reading time is 1–2 minutes and generation dominates (§4.1 item 3) |
| B4 | Multiple renders/writes run serially during prepare | Low–medium | `scripts/okstra_ctl/run.py` render block | Lower priority |
| B5 | The token usage collector scans session JSONL linearly | Low–medium | `scripts/okstra_token_usage/` | **Resolved** — P6 incremental cache implemented |
| B6 | Simple work uses the same full workflow | Medium | task-type lifecycle / requirements routing | Fast-track design needed — largest remaining lever |
| B7 | The report writer's final-report/data.json **output volume itself** is large (90–140 KB) | High | Measurements in §4.1 item 3 — 8–19 minutes of generation per run | **Resolved** — default report-writer model lowered to `sonnet` (catalog `ROLE_DEFAULTS`) and a prose-budget dedup contract landed on the narrative blocks (`tests/contract/test_report_prose_budget.py`); fix runs additionally author reports incrementally (see the fix-run incremental reverification section in `docs/architecture.md`) |

Established assumptions:

- `contested` is not a classification that exists before entry into Round 2. In the current algorithm, `contested` is the final classification assigned to unresolved findings after the maximum round is reached.
- Therefore, the correct rule is not "Round 2 for contested items only," but "Round 2 only for the verification queue that remains mixed/unresolved after Round 1."

## 4. Measurement Criteria

At minimum, improvement work compares the following metrics before and after the change.

| Metric | Collection method | Target |
|---|---|---|
| Worker dispatch count | team-state `workers[]`, convergence state round history, number of prompt files | Fewer reverify dispatches in runs with P1 applied |
| Wall-clock | team-state worker usage `durationMs`, run start/end timestamps | 20–40% reduction in convergence-heavy runs |
| Raw tokens | Lead/worker totals from the token usage collector | Fewer worker tokens associated with reverify prompts |
| Billable equivalent | `usageSummary.*BillableEquivalentTokens` | Confirm a cost reduction |
| Quality regression | Missing contested/worker-unique items in the final report and validator results | Preserve the existing contract |

Minimum fixtures before implementing P1:

1. Early convergence: a run whose verification queue becomes empty in Round 0 or Round 1.
2. Mixed/unresolved: a run in which some findings remain after Round 1 and require selective Round 2 processing.
3. Worker failure: a run in which some reverify dispatches end in `timeout`/`error`.

### 4.1 Measured Results (2026-06-11, fontradar-v2-api dev-9186)

Measurements came from artifact mtimes, team-state `phaseTimeline`, and report-writer session JSONL tool-call timelines for three real runs (requirements discovery, implementation planning, and implementation stage 1).

1. **Wall-clock breakdown by run phase** — In analysis runs, "core analysis" accounts for only 17–24% of wall time: setup 4–6 minutes, analysis 16–24 minutes, convergence plus critic 23 minutes, and report writer 12–24 minutes.

2. **Critic serialization** — The critic was dispatched only after reverification finished, wasting 6–12 serial minutes per run. Because the critic input is fixed to the integrated Round 0 results, dispatch now runs in parallel with the first reverify round (`prompts/lead/convergence.md` §When).

3. **Report-writer generation dominates** — Session tool-call measurements show that reading all input (~404 KB, 16 files) takes **1–2 minutes**, generating data.json (skeleton Write followed by incremental Edit operations per section) takes **8–19 minutes**, and self-verification/audit takes about 3 minutes. B3 input compression would therefore save only about one wall-clock minute and was **rejected**. The remaining output-side lever is B7: slim the report contract (a quality trade-off requiring a user decision) or lower `--report-writer-model` using the existing knob.

4. **Automated measurement** — The Phase 7 collector extracts the lead's `PROGRESS: phase-*` markers and persists them as team-state `phaseTimeline` (`scripts/okstra_token_usage/collect.py :: phase_timeline`). Subsequent runs can measure item 1 through `/okstra-inspect time` instead of manual mtime analysis. The reportWriter surface of `okstra context-cost` was also aligned with the actual dispatch contract (current sequence plus analysis packet).

## 5. Improvement Priorities

### P0. Baseline Measurement and Terminology

Goals:

- Prevent documentation and code from conflating the task-type lifecycle with lead operating phases.
- Define the P1 baseline by requiring convergence state to expose `effectiveMaxRounds`, `roundsExecuted`, `dispatchCount`, `queueSizeByRound`, and `finalClassificationCounts`.

Primary change candidates:

- `prompts/lead/convergence.md`
- `prompts/lead/okstra-lead-contract.md`
- Convergence state schema documentation, if needed

Completion criteria:

- Documentation does not use `contested` as the name of an intermediate queue.
- The metrics required for before/after comparison are available in the final report or state artifact.

### P1. Reduce the Scope of Convergence Reverification

Goals:

- Immediately finalize findings that can be resolved in Round 1 under the default behavior.
- Run Round 2 only for the verification queue that remains `mixed` or `unresolved` after Round 1.
- Do not send findings already finalized as `full-consensus`, `partial-consensus`, or `worker-unique` back to workers.

Current problem:

- For task types with `maxRounds=2`, the documentation does not draw a sufficiently strong boundary between items remaining after Round 1 and already finalized items.
- If operators interpret the process as "reverify every item," unnecessary redispatches grow in proportion to the worker count.

Improved algorithm:

```text
Round 0:
  Parse and group worker results.
  If two or more workers agree on the same semantics and ticket set, classify it as full-consensus.
  Put only single-worker findings into the verification queue.

Round 1:
  Reverify only queued items, batched by worker.
  all agree/supplement -> classify as full-consensus and remove from the queue.
  majority agree/supplement -> classify as partial-consensus and remove from the queue.
  all disagree -> classify as worker-unique and remove from the queue.
  mixed/error/insufficient evidence -> leave in the unresolved queue.

Optional Round 2:
  Skip when the unresolved queue is empty.
  If the unresolved queue is non-empty, reverify only those items.
  Finally classify items that remain after Round 2:
    majority agreement -> partial-consensus
    otherwise -> contested
```

Round 2 entry conditions:

- `effectiveMaxRounds >= 2`
- The unresolved queue is non-empty after Round 1.
- The unresolved cause is not solely worker failure. If every reverify worker returns a terminal non-result, record `verification-error`/blocked evidence instead of dispatching again.

Change targets:

- `prompts/lead/convergence.md`: specify queue pruning after Round 1, the Round 2 gate, and state artifact fields.
- `prompts/lead/okstra-lead-contract.md`: align the description of `convergence.maxRounds` with queue-pruned behavior.
- `prompts/lead/report-writer.md`: confirm that the final report records round history and why Round 2 was skipped.
- Validator or tests only if new convergence state fields become required.

Completion criteria:

- Findings finalized in Round 1 do not appear again in the Round 2 prompt.
- State contains `skippedReason` when Round 2 does not run.
- The final report continues to represent all four classifications: `Full Consensus`, `Partial Consensus`, `Contested`, and `Worker-Unique`.

### P2. Prompt Diet: Reduce Analysis Worker Input

Goals:

- Preserve the current rule that analysis workers do not read the final-report template, and keep report-writer-only material out of actual dispatch prompts.
- Reduce repeated wording in worker definitions while preserving blocking contracts such as path extraction, the model line, and the error sidecar.

Cautions:

- Before extracting shared worker text into `agents/workers/_cli-wrapper-template.md`, confirm that install/packaging paths and skill/agent loaders support includes.
- Merely moving text into a separate file can increase cost if the runtime does not inline it and the worker must read another file.

Change targets:

- `agents/workers/codex-worker.params.json`
- `agents/workers/antigravity-worker.params.json`
- `prompts/lead/team-contract.md`
- Install/build packaging

### P3. Fast-track Routing

Goal:

- Route work for which the full lifecycle is excessive—such as docs-only changes, typos, and clear one-file fixes—through a shorter path.

Recommended design:

- Rather than arbitrarily skipping the task-type lifecycle, have `requirements-discovery` record an explicit routing token such as `route=lite-implementation-planning` or `route=direct-implementation-planning`.
- Source edits still occur only in the `implementation` task type.
- Retain minimum verification through `final-verification` or an equivalent read-only check.

Change targets:

- `prompts/profiles/requirements-discovery.md`
- `scripts/okstra_ctl/workflow.py`
- Next-phase selection UI in `skills/okstra-run/SKILL.md`
- `skills/okstra-inspect/SKILL.md` (the former `okstra-status` skill folded into `okstra-inspect`)
- Validator expectations

Caution:

- If "fast-track" bypasses the implementation-planning approval gate, it breaks the single reference point and approval contract. Whether to reduce or remove the approval gate requires a separate user decision.

### P4. Evaluate Prompt Caching Feasibility

Goal:

- Use prompt caching only on transports that support it.

Current uncertainty:

- `render.py` renders Markdown files.
- Codex/Antigravity wrappers pass prompt files to CLI stdin.
- It is unclear whether API-level metadata such as `cache_control: ephemeral` is actually carried through this path.

Therefore, begin P4 with a spike rather than immediate implementation.

Validation items:

- Whether cache hints can be expressed in Claude Agent dispatch prompts.
- Whether cache hints have meaning in Codex CLI stdin prompts.
- Whether Antigravity CLI has a corresponding feature.
- Whether the token usage collector can observe changes in cache reads/creation.

### P5. Parallelize Prepare Rendering

Goal:

- Parallelize independent file renders/writes in the prepare step.

Cautions:

- `prepare_task_bundle()` remains the single authority, so callers stay unchanged even if work is parallelized.
- Manifest/discovery rendering shares context and file-order dependencies, so do not combine those operations aggressively.
- First examine only independent instruction-set writes.

Expected effect:

- Small relative to worker dispatch cost.
- Potentially noticeable in environments with many render-only smoke tests.

### P6. Incremental Token Usage Collection

Goal:

- Reuse a previous offset or session-summary cache instead of scanning the entire session JSONL every time.

Cautions:

- Accuracy is more important than speed because this connects to final-report placeholder substitution in Phase 7.
- Do not break aggregation across reruns, retries, or multiple subagent sessions.

## 6. Parallel Work Plan

| Track | Work | Primary files | Parallelism | Prerequisite |
|---|---|---|---|---|
| A | P1 convergence queue pruning | `prompts/lead/convergence.md`, `prompts/lead/okstra-lead-contract.md`, report-writer contract | High | P0 terminology cleanup |
| B | P3 fast-track routing | Requirements profile, workflow/status/run UI | Medium | P0 complete; approval-gate policy decided |
| C | P5 prepare render parallelization | `scripts/okstra_ctl/run.py`, render tests | High | None |
| D | P2 prompt diet | Worker definitions, team contract, packaging | Medium | Recommended after P1 |
| E | P4 prompt-cache spike | Experiments for each wrapper/dispatch path | High | None |
| F | P6 incremental token usage | `scripts/okstra_token_usage/` | High | Collector fixtures required |

Recommended order:

1. Start with Track A (P1). It directly reduces the largest cost and confines contract changes to documentation and lead operating phases.
2. Track C (P5) or E (P4 spike) can proceed in parallel.
3. Track B (P3) changes approval gates and lifecycle semantics, so it requires a separate design review first.
4. Start Track D (P2) after the prompt contract stabilizes following P1.

## 7. P1 Implementation Checklist

1. Update the Round 1-N pseudocode in `prompts/lead/convergence.md` to use queue pruning.
2. Do not use `contested` as an intermediate state; use `unresolved` or `mixed-after-round-1` for Round 2 candidates.
3. Specify the following fields in the convergence state artifact:
   - `config.effectiveMaxRounds`
   - `rounds[].inputQueueSize`
   - `rounds[].resolvedCount`
   - `rounds[].carriedForwardCount`
   - `rounds[].dispatches[]`
   - `rounds[].skippedWorkers[]`
   - `finalClassificationCounts`
   - `round2SkippedReason`
4. Verify that the report-writer contract includes round history and final classification counts in the final report.
5. Create simple early-convergence and mixed/unresolved fixtures and run a dry run or contract-level test.
6. Use the token usage collector to record before/after dispatch, token, and wall-clock measurements.

## 8. Risks and Guardrails

- **Correlated hallucination risk**: if a majority of workers reach the same incorrect conclusion in Round 1, less additional verification occurs. The guardrails are opt-in `verificationMode=full-reanalysis` and an evidence quality check.
- **Worker-failure misclassification risk**: treating a worker timeout/error as disagreement distorts `contested`. Separate terminal non-results into `verification-error` evidence rather than votes.
- **Fast-track misclassification risk**: incorrectly classifying work as simple can leave approval or verification insufficient. P3 requires a separate policy decision about bypassing the approval gate.
- **False caching benefit risk**: API-level cache hints may be ignored on CLI stdin paths. P4 requires a spike before implementation.
- **Validator failure from template reduction**: removing final-report headings or token placeholders can break `validate-run.py` and Phase 7 substitution. P2/P4 must inventory validator contracts first.

## 9. Conclusion

The current plan correctly makes P1 the top priority, but the earlier phrases "7-phase lifecycle" and "contested-only Round 2" did not match the code. The revised plan is ordered as follows.

1. Use P0 to establish terminology and measurement criteria.
2. Implement convergence queue pruning in P1.
3. Keep P3 fast-track and P4 prompt caching as follow-up work requiring separate design and verification.
4. Treat prepare-render parallelization and incremental token usage collection as smaller or end-of-run costs that can proceed as parallel supporting work after P1.

**2026-06-11 update** — Measurements in §4.1 confirm that P0/P1/P6, critic parallelization, and phaseTimeline instrumentation are complete, while B3 (report-writer input compression) was rejected. Only two priorities remain, and both require a user decision first:

1. **B7 — reduce report-writer output-side cost**: **done** — the default report-writer model is now `sonnet`, and the prose-budget contract deduplicates the narrative blocks. Remaining follow-up if further reduction is needed: evidence pointer-ization (option B of the slimming decision).
2. **B6/P3 — fast-track routing**: shorten the lifecycle for simple work. Requires an approval-gate policy decision.

### Implementation Plan Links

- P0 + P1: implemented in convergence state v1.2
- P6: implemented in incremental token-usage scanning
- Critic parallelization + phaseTimeline instrumentation: implemented directly without a plan (2026-06-11; see the corresponding `CHANGES.md` entry)
- P3 / P4 / P5 / B7: not written; each track requires a separate plan
