> ## Documentation Index
> Fetch the complete documentation index at: https://village-docs.villagelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Simulation Core

> The annual processing pipeline that powers ESOP forecasts

## The Heart of the Engine

The Simulation Core is a **discrete, step-by-step annual processing pipeline**. For each year of a projection, the engine executes a sequence of modules, each responsible for a specific aspect of ESOP administration.

<Info>
  This strict order of operations ensures that legal obligations are met before discretionary actions are taken.
</Info>

## Annual Processing Cycle

```mermaid theme={null}
graph TD
    START[Start Year N] --> S0[Step 0: Turnover Projection]
    S0 --> S1[Step 1: Initialization]
    S1 --> S2[Step 2: Determine Share Pool]
    S2 --> S3[Step 3: Allocate Shares]
    S3 --> S4[Step 4: Calculate Contribution]
    S4 --> S5[Step 5: Update Vesting]
    S5 --> S6[Step 6: Process Diversification]
    S6 --> S7[Step 7: Process Repurchases]
    S7 --> S8[Step 8: Year-End Closing]
    S8 --> SNAPSHOT[Capture Year-End State]
    SNAPSHOT --> END[End Year N]
    
    style START fill:#29371F,color:#fff
    style END fill:#29371F,color:#fff
    style S2 fill:#3D5030,color:#fff
    style S7 fill:#3D5030,color:#fff
```

## Processing Steps Overview

<AccordionGroup>
  <Accordion title="Step 0: Turnover Projection" icon="chart-line">
    **Optional predictive module**

    Uses statistical models to forecast which employees will terminate in the current year.

    **Inputs:**

    * Participant age, tenure, compensation
    * Historical turnover rates
    * Industry benchmarks

    **Output:**

    * List of projected termination events with probabilities
  </Accordion>

  <Accordion title="Step 1: Initialization" icon="play">
    **Calculate share price and prepare for annual processing**

    Initialize the annual processing cycle by calculating current share price and preparing state variables.

    **Actions:**

    * Calculate per-share value from company equity and outstanding shares
    * Apply annual growth rate to company equity value
    * Initialize security-specific prices in multi-class mode
    * Set up year-specific state variables
  </Accordion>

  <Accordion title="Step 2: Determine Share Pool" icon="shapes">
    **Calculate shares available for allocation**

    Critical step that implements loan-by-loan share release mechanics.

    **Sources:**

    * New company contributions (stock)
    * Released suspense shares from ESOP loans
    * Reallocated forfeitures

    **See:** [Loan-by-Loan Mechanics](#loan-by-loan-share-release)
  </Accordion>

  <Accordion title="Step 3: Allocate Shares" icon="divide">
    **Distribute shares to participant accounts**

    Apply allocation formula to credit shares to individual accounts.

    **Formula Options:**

    * Pro-rata by compensation
    * Pro-rata by hours
    * Integrated (Social Security-adjusted)
  </Accordion>

  <Accordion title="Step 4: Calculate Contribution" icon="hand-holding-dollar">
    **Determine annual company contribution**

    Based on `contribution_policy` in OperatingAssumptions.

    **Policy Types:**

    * Fixed amount
    * Percentage of payroll
    * Discretionary formula
    * Loan payment-based
  </Accordion>

  <Accordion title="Step 5: Update Vesting" icon="check-double">
    **Calculate vested balances and potential forfeitures**

    Apply the plan's vesting schedule to determine vested vs unvested portions of participant accounts.

    **Actions:**

    * Apply vesting schedule based on years of service
    * Calculate vested percentages for each participant
    * Identify non-vested amounts subject to forfeiture
    * Track vesting per security in multi-class mode
    * Apply vesting to both shares and cash balances
  </Accordion>

  <Accordion title="Step 6: Process Diversification" icon="chart-pie">
    **Handle statutory diversification**

    Process elections from eligible participants (age 55+ with 10+ years).

    **Actions:**

    * Identify eligible participants
    * Process diversification elections
    * Calculate amounts (25% or 50% of account)
    * Move funds to diversified investments
  </Accordion>

  <Accordion title="Step 7: Process Repurchases" icon="money-bill-transfer">
    **Execute share repurchases**

    Repurchase shares from terminated participants using the Funding Waterfall.

    **See:** [Funding Waterfall](#funding-waterfall)
  </Accordion>

  <Accordion title="Step 8: Year-End Closing" icon="flag-checkered">
    **Finalize annual results and prepare for next year**

    Roll account balances forward, evolve employee data, and capture year-end snapshots.

    **Actions:**

    * Move allocated/diversified amounts to opening balances
    * Age employees by 1 year and increment service years
    * Apply compensation growth rates
    * Remove fully distributed participants
    * Capture year-end state snapshots and KPIs
  </Accordion>
</AccordionGroup>

## Key Logic Modules

### Loan-by-Loan Share Release

For leveraged ESOPs with multiple debt tranches, the engine implements precise loan-by-loan accounting.

<Warning>
  **Critical:** Each `ESOPLoan` object directly owns the shares that collateralize it. This prevents cross-contamination of suspense accounts.
</Warning>

#### How It Works

<Steps>
  <Step title="Iterate Through Loans">
    ```python theme={null}
    for loan in esop_loans:
        if loan.principal_balance > 0:
            process_loan_payment(loan)
    ```
  </Step>

  <Step title="Calculate Payment">
    Determine principal and interest for current year based on loan terms
  </Step>

  <Step title="Release Shares">
    ```python theme={null}
    # Release shares proportional to principal paid
    shares_to_release = (
        loan.suspense_shares * 
        (principal_payment / original_loan_amount)
    )

    loan.suspense_shares -= shares_to_release
    share_pool += shares_to_release
    ```
  </Step>

  <Step title="Update Loan Balance">
    ```python theme={null}
    loan.principal_balance -= principal_payment
    ```
  </Step>
</Steps>

#### Example: Multi-Loan Scenario

```python theme={null}
# Year 2025 Processing

# Loan 1: Original $3M loan from 2020
loan_1 = ESOPLoan(
    loan_id="LOAN_2020",
    principal_balance=2_000_000,
    suspense_shares=20_000,
    annual_payment=400_000  # $300K principal + $100K interest
)

# Loan 2: New $2M loan from 2023
loan_2 = ESOPLoan(
    loan_id="LOAN_2023",
    principal_balance=1_800_000,
    suspense_shares=15_000,
    annual_payment=300_000  # $200K principal + $100K interest
)

# Process Loan 1
shares_released_loan_1 = 20_000 * (300_000 / 3_000_000) = 2_000 shares
loan_1.suspense_shares = 20_000 - 2_000 = 18_000

# Process Loan 2
shares_released_loan_2 = 15_000 * (200_000 / 2_000_000) = 1_500 shares
loan_2.suspense_shares = 15_000 - 1_500 = 13_500

# Total shares available for allocation
share_pool = 2_000 + 1_500 = 3_500 shares
```

<Note>
  **Why This Matters:** Without loan-by-loan tracking, shares from one loan could incorrectly be released when paying down another loan, violating ERISA requirements and creating audit risk.
</Note>

### Funding Waterfall

The repurchase processing module implements a **strict, rules-based sequence** for drawing funds from the trust's cash accounts.

#### The Waterfall Sequence

The engine follows `PlanRules.cash_usage_policy` to draw funds in the specified order:

```python theme={null}
cash_usage_policy = [
    "unallocated_company_contributions",  # 1st priority
    "unallocated_forfeiture_cash",        # 2nd priority
    "participant_cash_accounts"           # 3rd priority
]
```

#### Processing Algorithm

<Steps>
  <Step title="Calculate Total Repurchase Need">
    ```python theme={null}
    total_repurchase_obligation = sum(
        participant.vested_shares * current_share_price
        for participant in terminated_participants
    )
    ```
  </Step>

  <Step title="Apply Waterfall">
    ```python theme={null}
    remaining_need = total_repurchase_obligation

    for cash_source in cash_usage_policy:
        if remaining_need <= 0:
            break
            
        available = trust_cash_ledger[cash_source]
        amount_to_use = min(available, remaining_need)
        
        trust_cash_ledger[cash_source] -= amount_to_use
        remaining_need -= amount_to_use
        
        log_transaction(cash_source, amount_to_use)
    ```
  </Step>

  <Step title="Handle Shortfall">
    ```python theme={null}
    if remaining_need > 0:
        # Unfunded repurchase obligation
        defer_to_next_year(remaining_need)
        # OR trigger company loan/contribution
    ```
  </Step>
</Steps>

#### Example: Waterfall in Action

```
Repurchase Need: $500,000

Trust Cash Ledger:
├─ unallocated_company_contributions: $200,000
├─ unallocated_forfeiture_cash: $150,000
└─ participant_cash_accounts: $300,000

Waterfall Execution:
1. Draw $200,000 from unallocated_contributions → $300,000 remaining
2. Draw $150,000 from unallocated_forfeitures → $150,000 remaining
3. Draw $150,000 from participant_cash → $0 remaining

Result: ✅ Fully funded
```

<Warning>
  **Legal Compliance:** The order matters! For example, forfeiture cash often has restrictions on use. The waterfall ensures compliance with plan document rules and ERISA regulations.
</Warning>

## State Capture

At the end of each annual cycle, the engine captures complete snapshots:

<Tabs>
  <Tab title="Company State">
    ```json theme={null}
    {
      "simulation_run_id": "run_123",
      "year": 2025,
      "revenue": 10_000_000,
      "ebitda": 2_200_000,
      "total_payroll": 3_500_000,
      "esop_contribution": 500_000,
      "source_type": "simulated"
    }
    ```
  </Tab>

  <Tab title="Trust State">
    ```json theme={null}
    {
      "simulation_run_id": "run_123",
      "year": 2025,
      "total_shares_outstanding": 100_000,
      "allocated_shares": 68_000,
      "suspense_shares": 32_000,
      "unallocated_shares": 0,
      "cash_ledger": {
        "unallocated_contributions": 50_000,
        "unallocated_forfeitures": 25_000,
        "participant_cash": 125_000
      },
      "loans": [...]
    }
    ```
  </Tab>

  <Tab title="Participant Snapshot">
    ```json theme={null}
    {
      "simulation_run_id": "run_123",
      "year": 2025,
      "participant_id": "EMP001",
      "allocated_shares": 1_200,
      "vested_percentage": 0.80,
      "vested_shares": 960,
      "account_value": 132_000,
      "cash_balance": 2_500,
      "status": "active"
    }
    ```
  </Tab>
</Tabs>

## Error Handling & Validation

The engine performs extensive validation at each step:

<CardGroup cols={2}>
  <Card title="Input Validation" icon="shield-check">
    * Schema compliance
    * Business rule checks
    * Data completeness
    * Referential integrity
  </Card>

  <Card title="Processing Checks" icon="clipboard-check">
    * Share count reconciliation
    * Cash balance validation
    * Loan payment calculations
    * Legal compliance flags
  </Card>

  <Card title="Output Verification" icon="circle-check">
    * Total shares consistency
    * Cash flow balance
    * Participant account totals
    * Year-over-year deltas
  </Card>

  <Card title="Audit Logging" icon="file-lines">
    * Every transaction logged
    * Decision points captured
    * Assumption tracking
    * Error breadcrumbs
  </Card>
</CardGroup>

## Performance Optimizations

<AccordionGroup>
  <Accordion title="Vectorized Calculations" icon="gauge-high">
    Participant-level calculations use NumPy for efficient batch processing.
  </Accordion>

  <Accordion title="Lazy Loading" icon="hourglass">
    Historical snapshots loaded on-demand, not preloaded into memory.
  </Accordion>

  <Accordion title="Caching" icon="database">
    Frequently accessed reference data (e.g., plan rules) cached per simulation run.
  </Accordion>

  <Accordion title="Parallel Execution" icon="diagram-project">
    Independent scenario runs can execute in parallel for sensitivity analysis.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Processing Steps" icon="list-ol" href="/simulation/overview">
    Detailed breakdown of each simulation step
  </Card>

  <Card title="Data Layer" icon="database" href="/architecture/data-layer">
    How state is persisted and retrieved
  </Card>

  <Card title="Data Models" icon="shapes" href="/models/overview">
    Core objects used in processing
  </Card>

  <Card title="Examples" icon="code" href="/examples/basic-simulation">
    See the engine in action
  </Card>
</CardGroup>
