# REmodel Codebase Investigation Report **Date:** 2026-05-07 **Investigator:** Claude (Agentic exploration) --- ## 1. Executive Summary REmodel is a **full-stack hybrid renewable energy (Solar + Wind + BESS) project finance modeling platform** built in Python with a FastAPI backend and Next.js frontend. The project is designed to replace an Excel-macro workflow used for bid preparation at ReNew Power in India, targeting computation of optimal flat tariff and full 25-year project financials in under 30 seconds per scenario. ### Key Architecture ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ packages/engine │ │ Python calculation engine (pip-installable) │ │ • Generation (solar, wind, BESS) │ │ • Capex + IDC calculation │ │ • Financial model (P&L, CFS, BS) │ │ • Debt sizing + scheduling │ │ • Tariff solver (brentq) │ │ • CLI driver (Typer) │ └─────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ packages/api │ │ FastAPI + Arq async workers (Redis-backed) │ │ • REST endpoints (scenarios, templates) │ │ • Background task processing │ │ • SQLite + Parquet storage │ │ • SSE for real-time progress │ │ • Excel export │ └─────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ packages/web │ │ Next.js 14 App Router + shadcn/ui + Tailwind │ │ • Scenario list + wizard │ │ • Results dashboard │ │ • KPI visualizations (Recharts) │ │ • Compare scenarios view │ │ • DataGrid (AG Grid) │ └─────────────────────────────────────────────┘ ``` --- ## 2. Codebase Structure ### 2.1 Root Directory ``` /Users/manohar_air/MyProjects/REModel/ ├── PROJECT.md # Master specification document ├── README.md # Quick reference ├── docker-compose.yml # Redis service ├── Makefile # Common commands ├── .pre-commit-config.yaml ├── .github/workflows/ # CI/CD ├── packages/ # Monorepo structure │ ├── engine/ # Python calculation engine │ ├── api/ # FastAPI backend │ └── web/ # Next.js frontend └── sprints/ # Sprint documentation (SPRINT_00-08) ``` --- ## 3. Packages/Engine Analysis ### 3.1 Module Structure (42 Python files) ``` packages/engine/src/remodel_engine/ ├── __init__.py ├── cli.py # Typer CLI (simulate-gen, compute-idc, solve-tariff) │ ├── schemas/ # Pydantic models (single source of truth) │ ├── __init__.py │ ├── scenario.py # ScenarioInput, ScenarioResult, KpiSummary │ ├── capex.py # CostItem, CapexConfig, PhasingCurve, DrawdownCurve │ ├── debt.py # DebtConfig, DebtYearRow, IRRMetrics │ ├── financial.py # CommercialConfig, OpexConfig, TaxConfig, Financials │ └── generation.py # SolarConfig, WindConfig, BessConfig │ ├── catalog/ # Defaults and profile loaders │ ├── __init__.py │ ├── defaults.py # Constants: PROJECT_LIFE=25, HOURS=8760 │ ├── loader.py # Solar/wind profile CSV loader (RJ, KA, GJ) │ └── profiles/ # Bundled 8760-hour CSV files │ ├── generation/ # 25-year generation simulation │ ├── __init__.py │ ├── solar.py # DC→AC→clipping→availability→soiling→degradation │ ├── wind.py # Power curve lookup→shear→wake→availability │ └── bess_state.py # Degradation + augmentation capacity model │ ├── dispatch/ # Hybrid RTC dispatch │ ├── __init__.py │ ├── hybrid_rtc.py # Per-hour charge/discharge logic │ └── mcp_settlement.py # Merchant sale at MCP │ ├── capex/ # Capital expenditure │ ├── __init__.py │ ├── cost_items.py # CostItem catalog → total capex │ ├── phasing.py # Construction phasing matrix │ └── idc.py # Interest During Construction (fixed-point) │ ├── commercial/ # Revenue and DSM │ ├── __init__.py │ └── ppa.py # Generation aggregation, receivables/payables │ ├── financial/ # 3-statement model │ ├── __init__.py │ ├── pnl.py # Revenue → OpEx → EBITDA → Depr → EBIT → Tax → PAT │ ├── cfs.py # Cash Flow Statement (CFO/CFI/CFF) │ ├── bs.py # Balance Sheet (reconciliation) │ ├── depreciation.py # Book SLM + tax WDV schedules │ ├── tax.py # 115BAA (India) tax computation │ └── working_capital.py # Receivables, payables, inventory │ ├── debt/ # Debt financing │ ├── __init__.py │ ├── sizing.py # Fixed-point debt sizing (D:E, DSCR constraints) │ └── schedule.py # Repayment shapes (equal principal, EMI, sculpted, balloon) │ ├── irr/ # Financial metrics │ └── metrics.py # IRR, NPV, LCOE, DSCR, LLCR, PLCR, payback │ ├── solver/ # Solver logic │ └── tariff.py # Brentq solver for tariff→IRR target │ ├── scenarios/ # Scenario orchestration │ ├── __init__.py │ ├── runner.py # Full pipeline (generation→financial→debt→IRR) │ └── sweep.py # Sensitivity analysis │ └── io/ # Data export └── excel_export.py # .xlsx workbook generation ``` ### 3.2 Key Schema Definitions #### ScenarioInput (Top-level input) ```python class ScenarioInput(BaseModel): project: ProjectInfo # name, state, capacities, COD solar: SolarConfig | None # location, DC/AC, losses, degradation wind: WindConfig | None # location, MW, hub-height bess: BessConfig | None # MWh, power, RTE, DoD rtc: RtcConfig | None # contracted RTC MW, MCP toggle commercial: CommercialConfig # tariff, losses, working capital capex: CapexConfig # cost items, phasing curves, drawdowns opex: OpexConfig # O&M, insurance, land lease debt: DebtConfig # rate, tenor, DSCR constraints tax: TaxConfig # 115BAA rates solver: SolverConfig # solve_tariff or fixed_tariff mode ``` #### ScenarioResult (Full output) ```python class ScenarioResult(BaseModel): inputs: ScenarioInput status: Literal["queued","running","success","failed"] solved_tariff: float | None kpis: KpiSummary # equity_irr, project_irr, DSCR, capex, LCOE, etc. financials: Financials # pnl_25y, cfs_25y, bs_25y debt_schedule: list[DebtYearRow] irr_metrics: IRRMetrics warnings: list[str] runtime_s: float generation_by_year: list[dict] idc_phasing: dict ``` ### 3.3 Financial Model Flow The 3-statement model computes: 1. **P&L (Profit & Loss)** - Revenue: generation_MWh × tariff × (1 - losses) / 10^7 → Cr - OpEx: O&M + insurance + land_lease + AM_fee + misc - EBITDA = Revenue - OpEx - Depreciation: Book SLM by asset class - EBIT = EBITDA - Depreciation - Interest: From debt schedule - PBT = EBIT - Interest - Tax: 115BAA (25.17%) current + deferred - PAT = PBT - Tax 2. **CFS (Cash Flow Statement)** - CFO = PAT + Depreciation - ΔWC - CFI = 0 (capex in year 0) - CFF = Debt drawdown - Debt repayment + Equity injection - Net = CFO + CFI + CFF 3. **BS (Balance Sheet)** - Assets = Net block + Cash + Receivables - Liabilities = Equity + Reserves + LT Debt + Payables + DTL - Reconciliation enforced (≤₹0.05 Cr difference) ### 3.4 Debt Sizing Algorithm The debt sizing module (`debt/sizing.py`) implements a fixed-point iteration that satisfies three constraints: 1. **D:E Ratio Cap:** `debt ≤ total_capex × de_ratio / (1 + de_ratio)` 2. **Min DSCR Constraint:** `debt ≤ max satisfying min(DSCR) ≥ min_dscr` 3. **Avg DSCR Constraint:** `debt ≤ max satisfying avg(DSCR) ≥ avg_dscr` The binding constraint determines the final debt amount. ### 3.5 Repayment Schedule Shapes Five debt schedule shapes are supported (in `debt/schedule.py`): 1. **equal_principal:** Fixed principal each year in repayment period 2. **equal_installment:** EMI (level annuity) 3. **dscr_sculpted:** Principal sculpted so DSCR = avg_dscr each year 4. **balloon:** Interest-only then principal at end 5. **custom_pct_vector:** Caller supplies repayment % per year ### 3.6 Tariff Solver The solver (`solver/tariff.py`) uses Brent's method (scipy.optimize.brentq) to find the tariff that achieves target equity IRR: - Bracket: [2.0, 8.0] INR/kWh - Convergence tolerance: 1e-4 - Max iterations: 50 ### 3.7 Generation Models **Solar (`generation/solar.py`):** - Input: irradiance × capacity_dc → DC power → DC losses - Inverter efficiency → AC pre-clip - Clipping at MW_AC (DC/AC ratio > 1) - Availability × soiling × degradation - Output: 25 years × 8760 hours = 219,000 rows Model chain: ``` irradiance → DC power → DC losses → inverter → AC losses → clipping at MW_AC → availability → soiling → degradation ``` **Wind (`generation/wind.py`):** - Wind speed at reference → hub-height correction (power law shear) - Power curve lookup → normalized power (0-1) - Wake losses × electrical losses × availability × degradation **BESS (`generation/bess_state.py`):** - Degradation: `SOH = max(eol_soh, 1 - cum_cycles/design_cycles × (1 - eol_soh))` - Usable MWh = (nameplate + augmentation) × SOH - Augmentation steps add capacity at specified years ### 3.8 Hybrid RTC Dispatch The dispatch module (`dispatch/hybrid_rtc.py`) implements hourly charge/discharge: ``` For each hour h: gen = solar[h] + wind[h] surplus = gen - target (positive = excess, negative = deficit) If surplus ≥ 0: - Charge BESS with min(surplus, bess_mw, headroom) - Curtail excess Else: - Discharge BESS with min(deficit, available) - Shortfall = deficit - discharge ``` ### 3.9 CLI Commands ```bash # Simulate 25-year solar + wind generation remodel simulate-gen --input scenario.json --output gen.parquet # Compute IDC (Interest During Construction) remodel compute-idc --input capex.json --output idc.json # Run full scenario pipeline remodel solve-tariff --input scenario.json --output result.json ``` --- ## 4. Packages/API Analysis ### 4.1 Module Structure ``` packages/api/src/remodel_api/ ├── __init__.py ├── main.py # FastAPI app, CORS, lifespan ├── config.py # Settings (environment config) ├── db/ │ ├── __init__.py │ ├── session.py # SQLAlchemy async session │ └── models.py # Scenario ORM model ├── routers/ │ ├── __init__.py │ ├── scenarios.py # CRUD + run + results + SSE + Excel export │ └── templates.py # Scenario templates └── workers/ ├── __init__.py ├── main.py # Arq worker setup └── tasks.py # Background scenario execution ``` ### 4.2 API Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/scenarios` | Create scenario, queue for execution | | GET | `/api/scenarios` | List scenarios | | GET | `/api/scenarios/{id}` | Get scenario details | | PATCH | `/api/scenarios/{id}/inputs` | Update inputs, re-queue | | DELETE | `/api/scenarios/{id}` | Archive scenario | | GET | `/api/scenarios/{id}/kpis` | Get KPI results | | GET | `/api/scenarios/{id}/statements` | Get P&L, CFS, BS | | GET | `/api/scenarios/{id}/export/excel` | Export .xlsx | | GET | `/api/scenarios/{id}/events` | SSE progress events | ### 4.3 Database Schema ```python class Scenario(Base): id: str (UUID, primary key) name: str status: str ("queued", "running", "success", "failed") inputs_json: Text (JSON string of ScenarioInput) kpis_json: Text (JSON string of KpiSummary) statements_json: Text (JSON string of pnl/cfs/bs) debt_schedule_json: Text timeseries_path: str error_message: str runtime_s: float created_at: datetime archived_at: datetime | None ``` ### 4.4 Background Processing - Uses **Arq** (async Redis-backed task queue) - **ThreadPoolExecutor** runs CPU-bound engine in separate thread - Progress published via Redis pub/sub - SSE endpoint polls progress --- ## 5. Packages/WEB Analysis ### 5.1 Module Structure ``` packages/web/ ├── app/ │ ├── page.tsx # Scenario list + wizard │ ├── layout.tsx # Root layout │ ├── providers.tsx # React Query, etc. │ ├── globals.css # Tailwind │ ├── scenarios/ │ │ └── [id]/ │ │ └── page.tsx # Scenario detail view │ ├── compare/ │ │ └── page.tsx # Scenario comparison │ └── api-types/ # Auto-generated OpenAPI types ├── components/ │ ├── ui/ # shadcn/ui components │ ├── DataGrid/ # AG Grid wrapper │ ├── ScenarioWizard/ # Input wizard form │ ├── Charts/ # Recharts visualizations │ └── KpiCard/ # KPI display card └── lib/ └── api.ts # TypeScript API client ``` ### 5.2 Frontend Tech Stack - **Next.js 14** App Router - **TypeScript** (strict mode) - **shadcn/ui** + Tailwind CSS - **TanStack Query** (React Query) - **AG Grid Community** (DataGrid) - **Recharts** (KPIs) - **Zustand** (lightweight state) --- ## 6. Domain Context (Indian RE Bidding) ### 6.1 Key Concepts - **PPA:** Power Purchase Agreement at tariff (₹/kWh) - **RTC CUF:** Round-the-clock capacity factor developer commits to - **DSM:** Deviation Settlement Mechanism penalties - **IDC:** Interest During Construction - **115BAA:** Indian tax regime (22% + cess = 25.17%) - **DSCR:** Debt Service Coverage Ratio - **D:E:** Debt-to-Equity ratio (typically 75:25) ### 6.2 Currency - **Crore (Cr)** = 10 million INR (1 Cr = 1,00,00,000) - **Lakh** = 100 thousand INR - Capex quoted in Cr/MW or INR/Wp --- ## 7. Sprint Status | Sprint | Goal | Status | |--------|------|--------| | S0 | Repo setup, CI, API/Web skeleton | Complete | | S1 | Solar + Wind + BESS generation | Complete | | S2 | Capex + IDC calculation | In Progress | | S3 | 3-statement financial model | Pending | | S4 | Debt sizing + scheduling | Pending | | S5 | IRR/tariff solver | Pending | | S6 | Full scenario runner | Pending | | S7 | Excel parity gate | Pending | | S8 | Sensitivity sweeps | Pending | --- ## 8. Technical Constraints & Decisions ### 8.1 Working Agreements (from PROJECT.md) 1. Engine is UI-agnostic (pip-installable package) 2. CostItem table model (not flat fields) 3. Three nested iterations: tariff → debt → IDC 4. IDC has independent equity/debt drawdowns 5. Two DSCR compliance knobs 6. Sync-async hybrid: all runs through Arq queue 7. SQLite v0, Parquet for timeseries 8. **Excel parity is sacred** — must match user Excel within 0.1% 9. Coverage ≥85% 10. mypy strict mode 11. One DataGrid component (shared across 5+ places) ### 8.2 Testing - Unit tests for every public function - Integration tests for modules - **Parity gate** — tests against user's Excel gold scenarios - Location: `packages/engine/tests/` - Fixtures: `packages/engine/tests/fixtures/` --- ## 9. Observations & Potential Issues ### 9.1 Strong Points 1. **Clean architecture** — engine/API/web separation well-enforced 2. **Pydantic schemas** — single source of truth for types 3. **Comprehensive financial model** — 3-statement + depreciation + tax 4. **Multiple debt schedule shapes** — flexible repayment 5. **Production-ready** — Ruff, mypy, pytest, coverage 6. **Async backend** — Redis queue for scaling 7. **TypeScript types** — auto-generated from OpenAPI ### 9.2 Potential Concerns 1. **IDC fixed-point** — may need more robust convergence handling 2. **Parity gate** — not yet validated against user Excel 3. **Multi-user** — SQLite v0, needs Postgres for v2 4. **Test coverage gaps** — some modules newly added 5. **Wind power curve** — generic, may need calibration 6. **Solar profiles** — only 3 locations (RJ, KA, GJ) ### 9.3 Missing/Incomplete (from git status) The git status shows many new untracked files: - `packages/engine/src/remodel_engine/capex/` (existing, modified) - New modules for dispatch, commercial, debt, financial, irr, solver, scenarios, io - `packages/web/app/compare/` (new page) - Various test updates --- ## 10. Recommendations for Discussion 1. **Validation Priority:** Run the Excel parity gate with user-supplied gold scenario to verify model accuracy before proceeding to next sprints 2. **Test Coverage:** Some newly-added modules (dispatch, commercial, irr) have limited test coverage — prioritize before shipping 3. **DataGrid Usage:** Single AG Grid component exists but needs verification across all 5+ use cases 4. **Database Migration:** SQLite works for v0, but PostgreSQL planning would help architecture decisions 5. **Wind Profile Calibration:** Generic wind power curve may need location-specific calibration for Indian sites 6. **Performance:** 30-second target may be achievable, but needs benchmarking with realistic scenarios --- ## 11. File Locations Reference ### Key Source Files | Component | Path | |-----------|------| | Scenario input schema | `packages/engine/src/remodel_engine/schemas/scenario.py` | | Generation simulation | `packages/engine/src/remodel_engine/generation/solar.py` | | Wind simulation | `packages/engine/src/remodel_engine/generation/wind.py` | | BESS model | `packages/engine/src/remodel_engine/generation/bess_state.py` | | RTC dispatch | `packages/engine/src/remodel_engine/dispatch/hybrid_rtc.py` | | Capex calculation | `packages/engine/src/remodel_engine/capex/cost_items.py` | | IDC calculation | `packages/engine/src/remodel_engine/capex/idc.py` | | P&L | `packages/engine/src/remodel_engine/financial/pnl.py` | | CFS | `packages/engine/src/remodel_engine/financial/cfs.py` | | Balance Sheet | `packages/engine/src/remodel_engine/financial/bs.py` | | Depreciation | `packages/engine/src/remodel_engine/financial/depreciation.py` | | Tax | `packages/engine/src/remodel_engine/financial/tax.py` | | Debt sizing | `packages/engine/src/remodel_engine/debt/sizing.py` | | Debt schedule | `packages/engine/src/remodel_engine/debt/schedule.py` | | IRR metrics | `packages/engine/src/remodel_engine/irr/metrics.py` | | Tariff solver | `packages/engine/src/remodel_engine/solver/tariff.py` | | Scenario runner | `packages/engine/src/remodel_engine/scenarios/runner.py` | | CLI | `packages/engine/src/remodel_engine/cli.py` | | API main | `packages/api/src/remodel_api/main.py` | | Scenario endpoints | `packages/api/src/remodel_api/routers/scenarios.py` | | Background tasks | `packages/api/src/remodel_api/workers/tasks.py` | | Web API client | `packages/web/lib/api.ts` | | Main page | `packages/web/app/page.tsx` | --- *End of investigation report.*