# Improvement Discovery Profile

```yaml
roles:
  - role: analyser
    min: 3
    recommended: 3
    max: 5
    duty: discovery-worker
  - role: report-writer
    min: 1
    recommended: 1
    max: 1
    duty: report-writer
  - role: verifier
    min: 0
    recommended: 0
    max: 0
    duty: reverification-worker
    dynamic: true
```

- Purpose: scan a codebase scope through a fixed lens whitelist and surface ranked improvement candidates with multi-worker consensus classification
- Required workers:
  - claude
  - codex
  - antigravity
  - report-writer
- Optional workers (opt-in via `--workers`):
  - grok — optional adversarial analyser/critic through the Grok CLI wrapper
  - kimi — optional long-context analyser/critic through the Kimi CLI wrapper
- Roster guidance: the required block plus these opt-in providers form the full allowlist. As everywhere, `--workers` may narrow within it (`okstra_ctl.workers.validate_workers_against_profile` enforces the allowlist only, minimum 1), but narrowing this phase is strongly discouraged: cross-worker lens diversity is its load-bearing value, and a reduced roster produces candidates no second worker ever challenged.
{{INCLUDE:_common-contract.md}}
- Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
  - this phase REQUIRES a codebase-scan brief whose frontmatter contains `scope: codebase`. A brief without that marker is rejected before worker dispatch.
  - the brief's `priority-lenses` MUST be a non-empty subset (size 1..4) of the lens whitelist defined in `scripts/okstra_ctl/improvement_lenses.py`. Lenses outside the whitelist are rejected.
  - the brief's `scan-scope` defines the only paths workers may read for candidate evidence. `out-of-scope` paths MUST be ignored even when the codebase is otherwise reachable.
  - the brief's `candidate-cap` (default 8 if absent, absolute cap 12) bounds the number of rows in `## 5.9 Improvement Candidates`.
  - Apply the shared reporter-confirmation precondition as written. For this phase any unresolved `intent-check:` / `conversion-block:` row uses `Blocks=next-phase`.
  - read `Related Task Graph` before candidate discovery. If a candidate overlaps an existing linked task, preserve the edge in the candidate notes and prefer `related-to` / `follow-up-of` routing over emitting a duplicate standalone task.
- Primary focus areas:
  - candidate discovery within the lens whitelist
  - per-candidate evidence (path:line) and scope mapping
  - per-candidate severity / effort / recommended-next-phase
  - convergence classification (full / partial / contested / worker-unique) across workers
- Worker candidate procedure:
  - inspect every resolved priority lens inside the resolved scan scope; the assigned primary lens changes only the first pass, never total coverage
  - for the primary pass, return an evidence-backed candidate or a no-candidate rationale citing the highest-signal path:line inspected
  - for every candidate, record lens, scope, severity, effort, recommended next phase, evidence, and a worker-local source item ID
  - identify overlap with other findings or linked tasks as duplicate, broader/narrower, conflicting, blocked-by, or follow-up instead of silently merging it
- Worker diversity rule:
  - every analyser inspects every resolved priority lens. The Phase 1.5 grilling log assigns only the first pass: enumerate selected analyser worker instances in `requiredWorkerRoles` order and rotate them over resolved priority lenses in log order. Provider/model names never determine the position.
  - each worker, before broadening to the remaining lenses, must do one of: (a) produce at least one candidate from its primary pass, or (b) record a no-candidate rationale citing the highest-signal path:line evidence it inspected.
  - two workers' candidates are the same candidate only when they cite the same underlying design/code problem and the same remediation direction. Shared evidence paths alone are not enough to merge; keep distinct failure modes distinct.
  - when a candidate from one worker overlaps another worker's evidence, convergence must classify the relationship as one of: duplicate, broader/narrower, or conflicting. Do not collapse contested candidates just to meet the candidate cap.
  - when a candidate overlaps a brief `Related Task Graph` edge, convergence must classify whether the candidate is a duplicate of, blocked by, or follow-up to the linked task. Do not assign a new task-key without carrying the linked task reference into Recommended Next Steps.
- Phase 1.5 — Lead reflect-back grilling (runs after Phase 1 context loading and before Phase 4 worker dispatch):
  - Lead inspects scan-scope paths via `ls` / `Grep` / `Read` to map modules, entry points, dependencies, and approximate LOC, and reviews recent git history to note which scan-scope files change most.
  - Lead emits a single reflect-back message covering: (a) understood scope per path (one-line summary), (b) understood meaning of each priority lens in this scope, (c) understood out-of-scope rationale, (d) ordered list of N open questions.
  - For each open question Lead asks ONE `AskUserQuestion` with a `(Recommended)` answer drawn from a codebase-first inspection. Budget: at most 12 questions in this phase.
  - Stop conditions (OR): all questions resolved / budget exhausted / user signals proceed.
  - Lead persists the round at `<RUN_DIR>/state/phase-1.5-grilling.md` with one section per question (question / recommended / user answer) and a closing `Resolved scope` / `Resolved lenses` block. Worker prompts use this resolved block as the authoritative scope and lens definition.
  - The same log includes `## Primary Pass Assignments` with a `Worker ID | Primary lens` table. It contains every selected analyser exactly once in `requiredWorkerRoles` order; the lead derives it from the resolved roster and lenses rather than provider catalog order.
  - After writing the log and before Phase 4 dispatch, the lead injects its **absolute path** into every analyser prompt as the `**Phase 1.5 Grilling Log:** <absolute-path>` anchor header (see `okstra_ctl.worker_prompt_headers.worker_prompt_headers()`). This is the improvement-discovery counterpart to the `**Worktree:**` / `**Verification …:**` anchors that implementation / final-verification inject: workers read the log from this explicit path rather than re-deriving `<RUN_DIR>`. The path is byte-identical across all analysers, so it does not break the dispatch-prompt invariant.
- Decision-tree walk (bounded):
  - When candidates branch on a structural question (e.g. "is module X meant to own this responsibility?"), resolve via `Read` / `Grep` first. Only escalate to the user inside the Phase 1.5 budget.
- Expected output emphasis:
  - evidence-backed candidate or explicit no-candidate result for every resolved lens
  - worker-local candidate IDs that convergence can trace back to their source worker
  - uncertainty and overlap relationships kept explicit for downstream consensus classification
  - every candidate's `Expected behavior after` is checked against the brief's `## Preserved Behavior` items before the row is written. A candidate whose observable change contradicts a `PB-NNN` item is dropped, or raised as a `## 1. Clarification Items` row — never softened into a vaguer cell. The scan brief's PB set is the upper bound on what this phase may propose changing.
- Report assembly instructions:
  - current branch — `schemaVersion: 2.0`: author the structured data contract below and let the independent renderers produce the full reading copy and task-specific human HTML.
  - v1 legacy branch: when validating or rerendering an existing schema-v1 report, preserve its `## 5.9 Improvement Candidates` table and legacy Markdown contract; do not rewrite that historical data into v2 implicitly.
  - the `## 5.9 Improvement Candidates` table populated with rows that obey the 11-column schema from `validators/validate_improvement_report.py` (Cand ID `I-NNN`, Lens from whitelist, Title, Scope ⊆ scan-scope, Severity, Effort, Consensus, Source workers `<worker>:<id>` from {claude, codex, antigravity}, Recommended next-phase ∈ {requirements-discovery, implementation-option-selection, error-analysis}, Expected behavior after, Evidence as path:line list). `Expected behavior after` states, in one observable sentence, what becomes different once the candidate is applied — it is the seed of the downstream brief's `EB-NNN` / `EO-NNN`. A candidate you cannot write this cell for is a preference, not a finding: drop it rather than filling the cell with a restatement of the title.
  - `Consensus` cells in `## 5.9 Improvement Candidates` use the table enum exactly: `full`, `partial`, `contested`, `worker-unique`. Map convergence's `full-consensus` / `partial-consensus` labels to `full` / `partial` before writing the table.
  - Verdict Token — **branch-specific, and the two branches do not share a vocabulary.** On the current v2 branch use the shared analysis enum: `analysis-complete` when every resolved lens was examined, `analysis-partial` when one could not be, `blocked` when the scan itself could not run. `schemas/final-report-v2.0.schema.json` admits only those three for `finalVerdict.verdictToken` — the report's single verdict-token home — so a v2 report carrying `candidates-ready` fails Phase 7. **Finding no candidates is not a verdict**: it is an empty `candidates[]` plus a `lensCoverage[]` row per lens with `status: no-candidate` and its evidence-backed rationale — the verdict stays `analysis-complete`. `candidates-ready` / `no-candidates` belong to the v1 legacy `## 7. Final Verdict` Markdown alone, where `validators/validate_improvement_report.py` enforces them. Both branches: Direction `routing`; Next Step "ask the user to select K candidates (see the ## 5.9 table)".
  - `## 3. Recommended Next Steps` first entry summarises per-candidate routing and proposes new task-key names of the form `<task-group>/imp-<Cand-ID>`
  - author the shared narrative fields plus `improvementDiscovery.candidates[]`, `improvementDiscovery.lensCoverage[]`, `improvementDiscovery.selectionLimit`, and `improvementDiscovery.userNarrative` in the report narrative. `candidates[]` carries the same 11 logical fields described above; `lensCoverage[]` records either candidate IDs or an evidence-backed no-candidate rationale for every resolved lens. `schemas/final-report-v3.0.schema.json`, `schemas/report-narrative-v3.0.schema.json`, and `validators/validate_improvement_report.py` enforce this contract. Phase 7 assembles the final record and derives the reading copy and human HTML.
- Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
  - if scan-scope or priority-lenses cannot be made concrete during Phase 1.5, end the run with Verdict Token `blocked`, populate `## 1. Clarification Items` with `Blocks=next-phase` rows, and do not run worker dispatch
{{INCLUDE:_clarification-recommendation.md}}
- Non-goals:
  - concrete implementation plans, cost estimates, or code edits for any candidate
  - inventing lenses outside the whitelist
  - acting as a final-verification quality gate — this phase is discovery, not acceptance
  - silently merging out-of-scope findings into in-scope candidates
