# `Choreo.Requirement.Analysis`
[🔗](https://github.com/code-shoily/choreo/blob/v0.14.1/lib/choreo/requirement/analysis.ex#L1)

Analysis algorithms for `Choreo.Requirement` diagrams.

Provides traceability coverage, risk propagation, impact analysis, and
structural validation.

# `circular_dependencies`

```elixir
@spec circular_dependencies(Choreo.Requirement.t()) :: [[Yog.node_id()]]
```

Detects cycles among requirement-to-requirement relationships.

Only considers `depends`, `refines`, `contains`, and `derives` edges.

Returns a list of cycles, where each cycle is a list of node IDs.

# `components_for`

```elixir
@spec components_for(Choreo.Requirement.t(), Yog.node_id()) :: [Yog.node_id()]
```

Returns components, tests, and stakeholders related to a requirement.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1, id: "R1", text: "One")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    iex> Analysis.components_for(req, :r1)
    [:c]

# `coverage`

```elixir
@spec coverage(Choreo.Requirement.t()) :: map()
```

Returns coverage statistics for the requirements diagram.

Returns a map with satisfied, verified, and orphan requirement IDs plus
ratios.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1, id: "R1", text: "One")
    ...>   |> Choreo.Requirement.add_requirement(:r2, id: "R2", text: "Two")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.add_test(:t)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    ...>   |> Choreo.Requirement.verifies(:t, :r2)
    iex> %{satisfied: [:r1], verified: [:r2], orphan: []} = Analysis.coverage(req)

# `high_risk_gaps`

```elixir
@spec high_risk_gaps(Choreo.Requirement.t()) :: [Yog.node_id()]
```

Returns high or critical risk requirements that are neither satisfied nor
verified.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1,
    ...>     id: "R1",
    ...>     text: "Critical",
    ...>     risk: :critical
    ...>   )
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    iex> Analysis.high_risk_gaps(req)
    [] # satisfied, so not a gap

# `impact_of`

```elixir
@spec impact_of(Choreo.Requirement.t(), Yog.node_id()) :: [Yog.node_id()]
```

Returns all nodes upstream and downstream of a given node.

Useful for impact analysis: "if I change this component, what else is
affected?"

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1, id: "R1", text: "One")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    iex> Analysis.impact_of(req, :c)
    [:r1]

# `orphan_requirements`

```elixir
@spec orphan_requirements(Choreo.Requirement.t()) :: [Yog.node_id()]
```

Returns requirements that have no relationships.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:orphan, id: "R1", text: "Orphan")
    ...>   |> Choreo.Requirement.add_requirement(:sat, id: "R2", text: "Satisfied")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :sat)
    iex> Analysis.orphan_requirements(req)
    [:orphan]

# `requirements_for`

```elixir
@spec requirements_for(Choreo.Requirement.t(), Yog.node_id()) :: [Yog.node_id()]
```

Returns requirements related to a given component, test, or stakeholder.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1, id: "R1", text: "One")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    iex> Analysis.requirements_for(req, :c)
    [:r1]

# `risk_propagation`

```elixir
@spec risk_propagation(Choreo.Requirement.t()) :: %{required(Yog.node_id()) =&gt; atom()}
```

Propagates risk from parent requirements down to their children.

A child requirement inherits the maximum risk of any ancestor through
`refines`, `contains`, or `derives` relationships.

Returns a map of requirement ID to propagated risk.

# `traceability_matrix`

```elixir
@spec traceability_matrix(Choreo.Requirement.t()) :: %{
  required(Yog.node_id()) =&gt; map()
}
```

Returns a traceability matrix: requirements mapped to their related
components, tests, and stakeholders.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:r1, id: "R1", text: "One")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :r1)
    iex> matrix = Analysis.traceability_matrix(req)
    iex> matrix[:r1].components
    [:c]

# `unmitigated_risks`

```elixir
@spec unmitigated_risks(Choreo.Requirement.t()) :: [Yog.node_id()]
```

Returns high or critical risk requirements that do not have a lower-risk
child refinement.

These are risks that have not been decomposed into more manageable pieces.

# `unsatisfied`

```elixir
@spec unsatisfied(Choreo.Requirement.t()) :: [Yog.node_id()]
```

Returns requirements with no `satisfies` edge from a component.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:unsat, id: "R1", text: "Unsatisfied")
    ...>   |> Choreo.Requirement.add_requirement(:sat, id: "R2", text: "Satisfied")
    ...>   |> Choreo.Requirement.add_component(:c)
    ...>   |> Choreo.Requirement.satisfies(:c, :sat)
    iex> Analysis.unsatisfied(req)
    [:unsat]

# `unverified`

```elixir
@spec unverified(Choreo.Requirement.t()) :: [Yog.node_id()]
```

Returns requirements with no `verifies` edge from a test.

## Examples

    iex> req = Choreo.Requirement.new()
    ...>   |> Choreo.Requirement.add_requirement(:unver, id: "R1", text: "Unverified")
    ...>   |> Choreo.Requirement.add_requirement(:ver, id: "R2", text: "Verified")
    ...>   |> Choreo.Requirement.add_test(:t)
    ...>   |> Choreo.Requirement.verifies(:t, :ver)
    iex> Analysis.unverified(req)
    [:unver]

# `validate`

```elixir
@spec validate(Choreo.Requirement.t()) :: [{:error | :warning, String.t()}]
```

Evaluates structural integrity and returns a list of human-readable warnings and errors.

# `validate_messages`

```elixir
@spec validate_messages(Choreo.Requirement.t()) :: [{:error | :warning, String.t()}]
```

Returns human-readable validation messages.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
