# Requirements Discovery Profile

```yaml
roles:
  - role: analyser
    min: 2
    recommended: 3
    max: 5
    duty: discovery-worker
  - role: critic
    min: 1
    recommended: 1
    max: 1
    duty: scope-critic
  - 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: classify the work request, identify missing requirement evidence, and route the task to the safest next lifecycle phase before implementation starts
- Required workers:
  - claude
  - codex
  - report-writer
- Optional workers (opt-in via `--workers`):
  - antigravity — when added to the roster it joins the analyser set; omitted by default
  - grok — optional adversarial analyser/critic through the Grok CLI wrapper
  - kimi — optional long-context analyser/critic through the Kimi CLI wrapper
{{INCLUDE:_common-contract.md}}
- Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
  - Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows use `Blocks=next-phase`.
  - before classifying (after the precondition passes), scan the brief for every `Open Questions` row prefixed `intent-check:` / `terminology:` / `conversion-block:` and every `Augmentation` entry labelled `intent-inference` / `terminology-mapping`, and resolve OR carry forward each one in this phase.
  - before deciding whether to fan out, read `Related Task Graph`. Use `depends-on`, `blocks` / `blocked-by`, parent/child, follow-up, and split edges as seed ordering constraints. Do not flatten a directed graph into unrelated tasks.
  - `intent-inference` augmentations whose paired `intent-check:` row carries `[CONFIRMED …]` are treated as **confirmed**; trust the confirmation text in `## Reporter Confirmations` over the original inference if they differ. Unconfirmed `intent-inference` rows under `reporter-confirmations: skipped` follow the precondition's `skipped` branch above.
  - `conversion-block:` rows are explicit "translation failed" signals — never attempt to resolve them by inference here; the precondition above already handled them.
- Worker discovery procedure:
  - **Ticket Tagging.** Tag every section 1–5 item with its related ticket. Use `Issue / Ticket`, fall back to Task ID, then `unknown`; comma-separate multiple tickets.
  - classify the request and cite the evidence that supports a recommended work category and safest next phase. The lead's Phase Routing settles the next phase.
  - identify independently startable decomposition candidates without publishing or rendering fan-out artifacts; preserve every directed dependency from `Related Task Graph`
  - resolve codebase-answerable ambiguity by inspection and record file:line evidence; return only human-owned decisions as clarification candidates with the evidence already checked
  - state the reporter's rejection criteria, missing routing inputs, and the evidence boundary behind each recommendation
- Primary focus areas:
  - classify the work as bugfix, feature, improvement, refactor, or ops
  - determine whether `error-analysis` or `implementation-option-selection` is the next safe step. Direct `implementation-planning` or `implementation` handoff is never a valid routing target — implementation requires direction selection followed by an approved `implementation-planning` report
  - capture the reporter's **rejection criteria** — the delivered outcome that would make this work wrong or unacceptable — as a routing input. Consume it from the brief's `Desired Outcome` / `Out of Scope` / `Source Material` when present; when it is absent AND it would change the classification (e.g. bugfix vs feature) or the next-phase choice, raise it as one `decision` clarification row with `Evidence checked: none — reporter intent`. Never infer it — this is a reporter-intent signal, the mirror of improvement-discovery's `Anti-goals`
  - record the rejection criteria in `requirementsDiscovery.rejectionCriteria` with the
    `source` that produced it. When it was absent and would not have changed the
    classification or the routing, say so with `source: absent-not-material` — an empty
    field cannot be told apart from a phase that never looked
  - record the terminology this phase settled in `requirementsDiscovery.domainAlignment`:
    whether the glossary and decision records were read, and for every fuzzy or overloaded
    term, the single canonical form and what decided it
  - identify missing materials that block reliable routing
  - define task continuity expectations for long-running work under the same task key
  - capture approval or confirmation points before the next phase starts
  - **domain alignment check**: read `<PROJECT_ROOT>/.okstra/glossary.md` and `<PROJECT_ROOT>/.okstra/decisions/` titles if present. Absent okstra memory files are normal — do not error. Validate that every `terminology:*` entry under the brief's `Open Questions` has a canonical resolution before routing. Fuzzy or overloaded terms in the brief MUST be resolved to a single canonical term in this phase.
- Fan-out (multi-item / multi-domain requests only):
  - A single-item / single-domain request is not fanned out (preserving the current single-routing behaviour).
  - When a request spans two or more domains, or has two or more independently-startable work items,
    publish each item as a `runs/requirements-discovery/fan-out/unit-<NNN>.md` packet.
    The packet follows the `templates/reports/fan-out-unit.template.md` format, and its frontmatter
    `domain`(work-category 5-enum: bugfix / feature / refactor / ops / improvement),
    `depends-on`(an inline list of unit-ids within the same fan-out `[unit-001]`, or `[]` if none),
    `recommended-next-phase`(error-analysis | implementation-option-selection) are filled in.
    Each packet MUST carry a non-empty `## Requirement Provenance` section whose every bullet is `brief:EB-001` / `brief:PB-001` / `brief:EO-001` — an end-state id the brief declares — or `contract:<rule>`. When the brief pins ids, citing a heading is rejected: every brief carries the same generic headings, so a heading cannot say WHICH reporter line demanded this unit, and a fan-out unit becomes the brief for a whole downstream task. Only a brief authored before the end-state sections existed still takes the older `brief:<heading>` form, and there the heading must literally exist in it. `derived:` is not admissible in a packet — cross-packet derivation cannot be resolved from a single packet, so each unit anchors directly on the brief. A unit you cannot source that way is not a work item: raise it as a clarification row instead of publishing a packet for it. **Enforced:** `validators/validate_fanout.py` `_check_provenance`.
  - in `runs/requirements-discovery/fan-out/index.md`, list the packets in depends-on topological order
    as a numbered list (`1. unit-001`) (a generated view; explicitly do not hand-edit). The depends-on graph
    must be a DAG — `validate_fanout` rejects a cycle as a validation failure, so if a cycle appears,
    break the offending dependency to make it a DAG before finalizing the packet.
  - an ordering edge seeded from the brief's `Related Task Graph` is preserved in each packet's `depends-on`
    and in the final report's routing rationale. A `duplicates` / `related-to` edge is
    not interpreted as fan-out ordering; use it only as a reference for avoiding duplicate work / scope alignment.
    One exception to "only a reference": when such an edge — `related-to` / `duplicates` / `split-from`, or a
    shared `parent-of` parent — names a sibling task that performs the same behaviour on a different resource
    (same action, different noun), record that commonality in the final report's routing rationale as a
    variation-point input: a named candidate for shared-interface extraction that the next
    `implementation-planning` run reads when it fills `variationPointAnalysis`. This does not fan out and adds
    no `depends-on` edge — it stays a routing-rationale note. Without it the planner meets the task alone and
    scores its options against a single implementation.
  - in the final report, do not duplicate the decomposition result; keep only the one-line "fan-out: N packets → fan-out/index.md"
    pointer. Packet execution is separate: the user starts each unit as a new task-key via
    `okstra-run --task-brief <packet path>` (this phase does not directly start any downstream run).
- Decision-tree walk (bounded):
  - When the brief's `Desired Outcome`, classification, or routing target depends on a chain of decisions, walk that chain one branch at a time. Each branch is one `Clarification Items` row, not a free-form interview.
  - For every `Kind=decision` clarification row, author `options[]` as the Clarification recommendation fragment specifies: exactly one `role: recommended`, and every option carrying `scopeImpact` / `addedWork` / `directionChange`. Consequences belong in those fields — appending them to the option text puts them where nothing reads them.
  - **Codebase-first rule**: if a branch can be resolved by `Read` / `Grep` / file inspection, resolve it that way and record `Evidence checked: <path:line>` in the `Statement` cell. Do NOT escalate to the user.
  - Budget: the unified `## 1. Clarification Items` table caps at the smaller of (a) one row per unresolved decision branch, (b) 8 rows total. Beyond the cap, fold remaining ambiguity into the routing recommendation's risk notes.
- Expected output emphasis:
  - evidence-backed routing decision
  - uncertainty boundaries and missing inputs
  - next recommended phase and safe resume guidance
  - canonical-term resolution for every `terminology:*` brief item as `<term> = <definition>`, plus whether `<PROJECT_ROOT>/.okstra/glossary.md` should be updated
  - one `endStateCoverage` row per brief end-state id (`EB-NNN` / `PB-NNN` / `EO-NNN`). `coveredBy` names the routing decision, the fan-out unit id, or the `C-NNN` clarification that accounts for it. This phase does NOT author a goal of its own — the brief already pinned the end state, and restating it here is how four phases end up with four different targets. **Enforced:** `validators/validate-run.py` `_validate_end_state_coverage`.
- Report assembly instructions:
  - write canonical-term resolutions in a new `Domain Alignment` subsection of the final report; actual glossary writes happen via `okstra-brief-gen` Step 4.5 on a subsequent run
- Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
  - if any blocking input is missing at the time of writing the final report, populate `## 1. Clarification Items` in `final-report-template.md` (a single unified table; `Blocks=next-phase` for items the next run cannot start without)
  - prefer concrete questions whose answers map directly to a routing decision (`bugfix` vs `feature`, `error-analysis` vs `implementation-option-selection`, etc.). State each option in plain language with one sentence describing what choosing it would mean for the next phase.
{{INCLUDE:_clarification-recommendation.md}}
  - **Codebase-first ambiguity resolution (defect rule)**: any ambiguity that can be answered by `Read` / `Grep` / file inspection MUST be resolved that way and recorded with file:line evidence. Writing a clarification row for something the codebase already answers is a defect of this phase. **Boundary — facts only, never intent:** this rule governs questions of *fact* ("what does this code do", "where is this called", "does this field exist"). It never governs questions of *intent* ("should we do this at all", "is this in scope", "which outcome does the reporter want"). Scope and intent are not the kind of question a codebase can answer, so inspecting files never discharges them — raise them as clarification rows. Resolving a scope question by inference and building on that inference is the mirror defect, and a more expensive one.
  - **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only a human can answer this" (reporter intent, business priority, external authority). A row with `none` that *could* have been answered by the codebase is a defect.
- Cross-verification mode:
  - Phase 5.5 convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker's finding by directly re-inspecting the cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode". A single evidence-backed refutation prevents a finding from reaching consensus.
{{INCLUDE:_coverage-critic.md}}
- Non-goals:
  - full implementation design unless it is required to decide the next phase
  - **source code edits, plan authoring, builds, or deployments** — this run only classifies the work and routes it; deeper analysis and planning belong to subsequent phases
  - **writes outside `<PROJECT_ROOT>/.okstra/`** — this phase only uses okstra's artifact root. Glossary additions land in `<PROJECT_ROOT>/.okstra/glossary.md` (via `okstra-brief-gen` Step 4.5); decision drafts land in `<PROJECT_ROOT>/.okstra/decisions/` (via `implementation-planning`).
  - work-unit decomposition (fan-out) is in-scope for this phase — but each unit's *solution design*, source edits, and plan authoring remain non-goals and are handled by downstream phases
