# Fair Lending Compliance Audit

Causal fairness analysis for ECOA/CFPB compliance. Decomposes the
effect of protected characteristics into direct (concerning) and
indirect (legitimate) causal pathways.

## Overview

The fair lending pipeline:

1. Loads the credit ontology
2. Decomposes the causal effect of protected attributes on lending outcomes
3. Classifies paths as legitimate (through business factors) or concerning
4. Audits individual borrower decisions with counterfactual analysis
5. Aggregates portfolio-level fairness metrics

## Run It

```bash
python examples/fair_lending_audit.py
```

## Key Concepts

### Causal Fairness Framework

Orxaq implements the Pearl/Kilbertus causal fairness framework. The total
effect of a protected attribute (e.g., age) is decomposed into:

- **Direct effect**: `age → default_flag` (no mediator — potentially discriminatory)
- **Indirect through legitimate mediators**: `age → income → PD` (acceptable, as income is a legitimate business factor)
- **Indirect through non-legitimate mediators**: concerning if present

### Legitimate Mediators

Variables considered legitimate business factors under ECOA:

- `employment_length`, `income`, `credit_score`, `dti`
- `loan_amount`, `interest_rate`, `ltv`, `term`, `current_balance`

### Decision Audit

For each borrower, the analyzer computes:

1. **Actual decision** based on PD threshold
2. **Counterfactual decision** — what would happen if the protected attribute differed
3. **Recommendation**: `clear`, `review`, or `flag`

| Condition | Recommendation |
|-----------|---------------|
| Direct effect > 0.3 | Flag |
| Direct effect > 0.1 or decision changed | Review |
| Otherwise | Clear |

## Python API

### Effect Decomposition

```python
from orxaq.credit.fair_lending import FairLendingAnalyzer
from orxaq.credit.ontology import build_credit_ontology

dag = build_credit_ontology()
analyzer = FairLendingAnalyzer(dag)

# Decompose effect of age on default
decomp = analyzer.decompose_effect("age", "default_flag")

print(f"Direct effect:    {decomp.direct_effect:.4f}")
print(f"Legitimate paths: {len(decomp.legitimate_paths)}")
print(f"Concerning paths: {len(decomp.concerning_paths)}")

for mediator, effect in decomp.indirect_effects.items():
    print(f"  via {mediator}: {effect:.4f}")
```

### Individual Borrower Audit

```python
from orxaq.credit.synthetic import CreditDataGenerator

gen = CreditDataGenerator(dag, seed=42)
data = gen.generate(500)

# Audit a single borrower
report = analyzer.audit_decision(data[0])
print(f"Decision:     {report.decision}")
print(f"Counterfactual: {report.counterfactual_decision}")
print(f"Changed:      {report.decision_changed}")
print(f"Recommendation: {report.recommendation}")
```

### Portfolio Audit

```python
flagged = sum(1 for b in data if analyzer.audit_decision(b).recommendation == "flag")
print(f"Flagged: {flagged}/{len(data)} ({flagged/len(data):.1%})")
```

## CLI

```bash
# Fair lending decomposition
orxaq credit fairness --protected age

# JSON output
orxaq --json credit fairness --protected age
```

## Regulatory Context

- **ECOA** (Equal Credit Opportunity Act): Prohibits discrimination based on protected characteristics
- **CFPB** (Consumer Financial Protection Bureau): Enforces fair lending through disparate impact analysis
- **Causal advantage**: Traditional disparate impact analysis uses statistical correlation; causal analysis distinguishes legitimate business necessity from discriminatory effect

## Source

- Example script: [`examples/fair_lending_audit.py`](https://github.com/Orxaq/orxaq/blob/main/examples/fair_lending_audit.py)
- Fair lending analyzer: `src/orxaq/credit/fair_lending.py`
- Credit ontology: `src/orxaq/credit/ontology.py`
