# GaugeH₂ LCOH / TEA Calculator — Frozen Methodology v7.1.0

**model_version:** `7.1.0` · **methodology_version:** `3.31`
**Status:** FROZEN. This file is content-addressed: its sha256 is published in
`docs/methodology/calculator-methodology-v7.1.0.sha256.txt`, published beside it in
`public/methodology/`, and embedded in the shipped reference-case artifacts. Editing one byte of this file without
regenerating both invalidates the anchor, and the test suite fails.

The previous frozen document is `docs/methodology/calculator-methodology-v7.0.0.md`
(`7.0.0` / `3.30`) and remains the specification for every report issued under that
model. Reports are never retroactively recalculated. What the reports asserted under that
engine is published in its own methodology changes document, and the series continues for
`7.1.0`: `calculator-methodology-v7.1.0-m3.31-changes.md`.

**This is a MINOR bump, and §10 says why.** Four project-finance options are added to the TEA,
every one of them an optional input (§7.7): the loan and project life cover ratios (LLCR,
PLCR), a debt repayment sculpted to a target DSCR, a debt service reserve account (DSRA), and
the carry-forward of tax losses, which reaches the project (unlevered) flow too. An optional
external-heat cost enters the LCOH (§3), and the platform defaults the contract writes into new
calculations change (§4.1). With none of the options and none of the heat inputs, every output
of every input is the output of 7.0.0, bit for bit, and the output object carries no new key; a
stored input re-run gives what it always gave. §11 states what moves and what does not.

**A note on the runtime, new in 2.5.** The figures below are reproducible to the
precision stated in §9. The 17-digit artifacts shipped with this engine are not:
the annual arithmetic and the IRR solver both move in their last bits with the
major version of the Node.js runtime — measured, not assumed. The runtime this
engine is built and served under is declared in `.nvmrc`, and the build refuses to
proceed under any other. A figure reproduces **given that runtime**; claiming more
than that would be claiming more than the method delivers.

---

## 1. Identity and scope

This document is the executable specification of the engine that produces every
LCOH and TEA figure GaugeH₂ publishes. It describes **what the code does**, not
what a source recommends. Where the implementation departs from its source, the
departure is stated here and in the code.

In scope: the levelised cost of hydrogen (LCOH), the capital charge, and the
techno-economic assessment (TEA) built on the same cash flow — the deterministic
paths and their two Monte Carlo fast paths, which are held in lockstep by test.

Out of scope, and deliberately so: plant engineering (equipment sizing, process
design, utilities), hydrogen demand evaluation, and the Iberian Green Hydrogen
Cost Index, which has its own frozen methodology
(`docs/methodology/index-methodology-v1.md`, version `index-v1.0`) and consumes
this engine as a black box.

## 2. Conventions

| convention | value | note |
|---|---|---|
| currency | EUR, nominal | no FX inside the engine |
| price basis | the first operating year's money — `infl(1) = 1` — escalated by `inflation_rate_pct` from year 2 | see §3 |
| discounting | end-of-year, `(1 + wacc)^t`, t = 1..N; the WACC is a nominal rate, because every flow it discounts is escalated | capital sits at t = 0 |
| production year | `operating_hours × availability_pct` | no fixed calendar-day convention |
| subsidy treatment | LCOH is GROSS of subsidy | §5 |
| rounding | published LCOH rounded to 2 decimals; all internals full double precision | |
| levelised price | nominal; the same LCOH in constant money is published beside it — new in 6.1.0 | §3.2 |

The engine takes no position on the number of operating days in a year: hours
are an input (`operating_hours`), not a derived constant.

## 3. The LCOH definition

Let `P₀` be annual production at nameplate, `E` the electricity the plant buys in a
year, `d` the annual stack degradation, `f` the inflation rate, `i` the WACC and `N`
the project lifetime in years.

```
P₀     = capacity_MW × 1000 × operating_hours × (availability_pct / 100)
         ÷ electricity_consumption_kwh_kg
E      = P₀ × electricity_consumption_kwh_kg                (kWh, the same every year)

a(t)   = the stack's age at the start of year t: years since the last replacement
         (t − 1 before the first; 0 in the year after each one)
P(t)   = P₀ × (1 − d)^a(t)
infl(t)= (1 + f)^(t−1)
df(t)  = (1 + i)^t

electricity(t) = E × (price_eur_mwh / 1000) × infl(t)
opex(t)        = CAPEX_physical × (om_pct / 100) × infl(t)
water(t)       = P(t) × water_l_kg × (water_cost_eur_m3 / 1000) × infl(t)
heat(t)        = P(t) × heat_demand_kwh_kg × (heat_cost_eur_mwh_th / 1000) × infl(t)
                 — new in 7.1.0, optional: 0 unless both inputs are given and positive
stack(t)       = CAPEX_electrolyser × (stack_cost_pct / 100) × infl(t)
                 when t mod stack_replacement_interval = 0 and t < N, else 0

                 CAPEX_capitalised + Σ_{t=1..N} [ cost(t) / df(t) ]
LCOH  =  ─────────────────────────────────────────────────────────────
                        Σ_{t=1..N} [ P(t) / df(t) ]
```

Four properties of this expression are load-bearing and each is pinned by test:

1. **The capital in the numerator is the CAPITALISED figure** (§4), while the
   O&M base and the stack-replacement base are the **PHYSICAL** figure. The two
   are different quantities and the engine never conflates them.
2. **Degradation is lost efficiency, and a replacement restores it — new in 5.3.0.**
   The stack draws the same power every year, so the plant buys the same energy `E`
   and produces less as the stack ages; each kilogram therefore takes more
   electricity. The age counts from the last replacement, the same rule that decides
   the replacement below. **A replacement is charged in the year it falls and the
   output returns the year AFTER it**: year `r` runs on the stack it is replacing, so
   its output is that of a stack of age `r − 1`, and year `r + 1` produces what year 1
   produced. A reader who restores the output in year `r` gets a different lifetime
   production: the T-HYNET sample, whose stack is replaced at year 13 of
   20, gives 393 156 t this way and 394 332 t the other.

   The model a calculation used is one of its inputs, `stack_degradation_model`, and
   so it travels inside the hashed payload of §8. The contract writes
   `efficiency_loss` into every new calculation. **Absent, the engine evaluates the
   model of 5.2.0 and before**, character for character: `P(t) = P₀ × (1 − d)^(t−1)`
   with no reset, and `electricity(t) = P(t) × consumption × (price / 1000) × infl(t)`,
   the electricity falling with the production. Every calculation stored before 5.3.0,
   the Iberian index (`index-v1.0`, §4) and the catalogue benchmark
   (`catalogue-benchmark-v1.1`) declare no model and keep that one: none of their
   published figures moves. With `d = 0` the two models give the same bits.

   **The 5.2.0 document called its model conservative, and measured it was not.** On
   the T-HYNET sample — 150 MW alkaline, 0.5 %/year, a replacement every 13 years —
   it gives 9.89 EUR/kg where this one gives 10.09: holding the electricity per
   kilogram flat understates what an ageing stack costs by more than the missing reset
   overstates it. Said plainly, because it is what a user sees: the same figures typed
   under 5.2.0 and under this engine do not give the same result — 10.09 EUR/kg on the
   T-HYNET sample instead of 9.89, and 4.7425 on the reference case instead of 4.7117.
3. **The last-year replacement is suppressed** (`t < N`): buying a stack the
   plant will never use would be a modelling artefact, not a cost.
4. **External heat is costed only when declared — new in 7.1.0.** An SOEC's
   electricity consumption assumes an external supply of high-temperature heat. With
   `heat_demand_kwh_kg` (thermal kWh per kg) and `heat_cost_eur_mwh_th` both given, `heat(t)`
   above is a cost of the year, inside the numerator and the TEA's `opex`; it follows the
   output `P(t)` and the inflation like water. Absent, `heat(t)` is 0 and adding 0 moves no bit:
   the LCOH of 7.0.0. No technology has a default: a suggested demand for SOEC, 8 kWh_th/kg, is
   shown beside the field — the US DOE 2026 system targets for high-temperature electrolysis,
   44 kWh/kg of total energy minus 36 kWh/kg of electricity
   (https://www.energy.gov/eere/fuelcells/technical-targets-high-temperature-electrolysis) —
   and is not filled in, because the price of heat is site-specific and has no sourced default.
   Without the inputs an SOEC report says that heat is not costed; with them it states the
   figures used. The LCOH output gains `heat_pct` and `heat_cost` only when heat is costed.

### 3.1 The sensitivity sweep — new in 5.3.0

Each row moves **one** input, holds every other at its base value, recomputes the LCOH
of §3, and records how far it moved its input:

| input | how it moves |
|---|---|
| `electricity_cost_eur_mwh` | × (1 ± 0.20) |
| `electrolyzer_cost_eur_kw` | × (1 ± b / 100), where `b` is the **wide end** of the accuracy band of the declared estimate class: concept 40, feasibility 15, bankable feasibility 15, FEED 5; 20 when no class is declared |
| `operating_hours` | × (1 ± 0.20) |
| `wacc_pct` | × (1 ± 0.20) |
| `electricity_consumption_kwh_kg` | × (1 ± 0.20) |
| `inflation_rate_pct` | ± 1 percentage point, kept within the 0–10 % the input contract accepts |

**No row asks for an input the contract would reject.** Each end is kept within what the
input contract accepts for that input in that calculation: the bounds of the field, read
from the contract itself — 1 000 to 8 760 operating hours, a WACC of 1 to 25 %, an
electricity price of 0 to 500 EUR/MWh, an electrolyser cost of at most 5 000 EUR/kW, a
specific consumption of at most 80 kWh/kg — and, for the specific consumption, the floor of
its technology route plus the one a declared delivery leg adds, the same sum the contract
rejects below. An end that would cross stops at that edge, and the row publishes the value
it used. The inflation row already stopped at 0 and 10 %; since 5.3.0 every row does. On
the T-HYNET sample, at 7 463 hours, the operating-hours row stops at 8 760 on the high side,
+17.4 %, instead of asking for 8 955.6 hours in a year. The TEA's sweep (§7) follows the same
rule — a debt share stops at 100 %, a hydrogen price at 30 EUR/kg, an interest rate at 30 %,
an O&M rate at 10 % — and, since 6.1.0, moves its electrolyser cost across the same class
band as the row above; its other seven inputs move ±20 %, and every TEA row publishes its
`sweep`. Until 6.0.0 the TEA moved the capital cost ±20 % while the first page of the same
report declared ±25–40 % for a concept estimate.

Every row publishes `sweep` (`unit`, `amount`), the three values of its input
(`input_low`, `input_base`, `input_high`), the three LCOHs rounded to two decimals
(`lcoh_low`, `lcoh_base`, `lcoh_high`), and `impact_range`, the exact
`|lcoh_high − lcoh_low|` before rounding, which orders the rows. A report prints, for a row
that stopped, how far each side moved and the value it stopped at.

**Why the capital cost moves by its class and not by 20 %.** The report's first page
declares the estimate class and its band — a concept estimate is ±25–40 % on the
capital cost. A sweep of ±20 % sat inside the uncertainty the same report declares.
The wide end is used because the band is the source's statement of how far the figure
can be off (Seddon, appendix A9), and the point of the row is to show that.

**Why the inflation rate is a row.** Every cost is escalated at it (§2) and the WACC
that discounts them is nominal: on the T-HYNET sample one point either way moves the
LCOH from 9.43 to 10.82 EUR/kg, eleven times what the WACC row moves it.

**What the sweep does not move**, stated on every report: the stack replacement
years, which are a calendar interval, do not move with the operating hours; and an
anchored electricity price is not re-derived. One anchored at the project's own hours is
not re-anchored at the new load factor; one that averages every hour of its window does not
depend on the hours at all, and the report says so for it. Until 6.0.0 the report printed the
first sentence in both cases, and the T-HYNET sample, anchored to the average of its window,
is the second.

Up to 5.2.0 there were five rows, all ±20 %, published as `lcoh_minus20` and
`lcoh_plus20`. Stored calculations keep that shape and the reports read both.

### 3.2 The LCOH in constant money — new in 6.1.0

The LCOH of §3 is a **nominal** levelised price: every cost after the first year is
escalated at the declared inflation rate and every flow is discounted at the nominal WACC,
so it is the one price per kilogram which, charged unchanged every year, recovers those
costs. Sector references usually publish the levelised cost in constant money, and a reader
comparing against them had to redo the calculation. Since 6.1.0 the engine publishes, beside
the nominal figure, the same project evaluated with **nothing escalated** and discounted at
the **real** WACC:

```
i_real        = (1 + i) / (1 + f) − 1          (exactly i when f = 0)
LCOH_constant = the LCOH of §3 evaluated with f = 0 and i = i_real
```

It is the same calculation with two inputs changed: production, degradation, the capital
and the stack replacements are identical by construction, and the construction period is
capitalised at the real WACC, the cost of capital in that same money. It is in the money of
the inputs — of one year only if every input is of that year. With a zero inflation rate the
two figures are the same bits.

It is published as `lcoh_constant_eur_kg`, rounded to two decimals like the LCOH, with
`wacc_real_pct`, on every LCOH output, and as `lcoh_constant` on every TEA output. The nominal
figure remains the headline; the Monte Carlo runs remain nominal. On the reference case (§9)
the constant LCOH is 4.0226 EUR/kg at a real WACC of 4.902 %; on the T-HYNET sample, 8.63
EUR/kg beside a nominal 10.09.

## 4. Capital: physical, capitalised, net

Three distinct quantities. Confusing them is the single most common error in
published hydrogen economics, so the engine names all three and publishes all
three.

```
CAPEX_electrolyser  = capacity_MW × 1000 × cost_eur_kw
                      (or, when a reference capacity is declared,
                       scaled by (capacity / reference)^exponent)

CAPEX_physical      = CAPEX_electrolyser × M
                      M = (1 + bop_pct/100)                       [default]
                      M = surcharge factor from the four itemised
                          surcharges                                [opt-in]

CAPEX_capitalised   = CAPEX_physical × CF(T, i)                   §5

CAPEX_net           = CAPEX_physical    − subsidy   → the TEA's capex_total
CAPEX_net_funded    = CAPEX_capitalised − subsidy   → the TEA's capex_funded
```

**One output name, two quantities.** The LCOH's `capex_total` is `CAPEX_physical`,
before subsidy — the LCOH is gross of subsidy (§6). The TEA's `capex_total` is
`CAPEX_net`. The 5.2.0 document gave only the second.

`bop_pct` and the itemised surcharges are **alternatives, never summed**. They
express the same quantity at different levels of detail and they sit on
different boundaries: `bop_pct` is a percentage on the installed electrolyser,
the four surcharges (general facilities, engineering and start-up, contingency,
land) sit on delivered equipment. Adding them double-counts the balance of
plant.

Exponent scaling is opt-in. Without a declared reference capacity the cost per
kW is applied flat and capital is linear in capacity.

### 4.1 Platform defaults — changed in 7.1.0

The engine takes capital cost as an input; the platform writes defaults into the form of a new
calculation, and those defaults belong to a model version (`src/lib/constants/defaults-registry.ts`).
**From 7.1.0** the electrolyser cost default is an INSTALLED figure: PEM 2 365 EUR/kW and
alkaline 1 819 EUR/kW (IEA *Global Hydrogen Review 2025*, 2024 data, installation included), and
therefore the Balance of Plant default is set per technology — 0 % for PEM and alkaline, whose
cost is already installed, and 30 % for SOEC and AEM. **Up to and including
7.0.0** the defaults were those of the previous era (an uninstalled cost with a flat 30 % BoP).
A stored calculation keeps the inputs it was computed with; a re-downloaded report of a 7.0.0
calculation resolves "platform default" against the 7.0.0 values. The reference case of §9
declares its own inputs (900 EUR/kW, BoP 30 %) and does not move.

## 5. The construction-capitalisation factor CF(T, i)

Capital spent during a build earns nothing until the plant starts. The interest
accrued over that period is real and it belongs in the capital charge.

```
CF(T, i) = Σ_{s=0}^{T−1}  a_s · (1 + i)^(T − s)
```

where `T` is the build duration in years (`construction_months / 12`) and `a_s`
is the fraction of capital disbursed in year `s`, taken from Seddon Table A7-1:

| T (years) | disbursement profile a_s |
|---|---|
| 1 | 1.00 |
| 2 | 0.50, 0.50 |
| 3 | 0.30, 0.45, 0.25 |
| 4 | 0.17, 0.32, 0.26, 0.25 |
| 5 | 0.04, 0.14, 0.32, 0.36, 0.14 |

Each column sums to exactly 1. The profile is **not** uniform, and that matters:
a flat split across the build years overstates capitalised interest, because it
front-loads spend that the real profile defers.

Behaviour outside the table:

- `T ≤ 0`, absent or non-finite ⇒ **CF is exactly 1**. This is the documented
  escape hatch: an input written before 5.0.0 produces its pre-5.0.0 capital
  charge, so any change in a result is attributable to a field the caller set.
- Fractional `T` ⇒ linear interpolation of the RESULT between the two adjacent
  tabulated durations, anchored at CF(0) = 1. The table is discrete; an 18-month
  build has no published profile. Interpolating the result rather than inventing
  a profile keeps CF monotonic in T and inside the bracketing published values.
- `T > 5` ⇒ clamped to the 5-year profile, the longest the source tabulates.

**Deliberate departure from the source.** The book prints
`K_o = K(1+i)·C_o·Σ a_s(1+i)^(p−s)`, which applies `(1+i)` twice and does not
reproduce its own Tables A7-3 and A7-4 — it overstates the return on capital by
5–15 %. The form above was derived by reproducing the published tables instead
of the prose, and matches them exactly. At i = 10 % it returns
1.100 / 1.155 / 1.2188 / 1.264417 / 1.2849144 for T = 1..5, and those figures
times the capital-recovery factor K(20, 10 %) reproduce the entire 10 % row of
Table A7-3. All 25 cells of that block are pinned in the test suite.

## 6. What the LCOH does NOT contain

Stated explicitly, because silence about an omission reads as a claim:

- **No subsidy.** The cost of producing hydrogen is a physical property of the
  asset and does not depend on who paid for the equipment. This follows IRENA's cost
  analyses, which exclude "the impact of government incentives or subsidies", and the
  US DOE Hydrogen Program Record 24005, which reports "untaxed and unsubsidized"
  hydrogen production cost; NREL's ATB applies it to tax credits in its R&D-only case.
  The EU Hydrogen Observatory's calculator carries subsidies inside its formula, so
  compare against its default figure. A capital grant does not lower the reported
  LCOH; it is retained where it economically belongs, in the investor cash flow.
- **No working capital.** The source charges a working-capital allowance at the
  plain rate. It is not implemented, so it is not claimed.
- **No royalty on a licensed process.** The source charges 2 % for licensed
  process plant, 0 % for infrastructure. Not implemented.
- **No location factor, no cost-index escalation** of any published capital
  figure. The platform takes capital cost as a user input and does not carry the
  source's own cost figures as platform values.
- **No delivery, storage, compression or conversion** downstream of the plant
  gate.
- **No hydrogen price.** The LCOH is a cost, never a price. Price enters only in
  the TEA (§7).

## 7. The TEA — investor cash flow

The TEA consumes the same discounted cash flow as the LCOH and adds the capital
structure. Capital is sized on **CAPEX_net_funded** — the capitalised figure net
of subsidy — because that is the cash the promoter must actually raise (decision
D2, 2026-08-10).

```
debt      = CAPEX_net_funded × (debt_share_pct / 100)
equity    = CAPEX_net_funded − debt
t = 0     : equity outflow, no revenue
t = 1..N  : revenue   = P(t) × (offtake_volume_pct/100) × price × escalation(t)
                        + o2_revenue_eur_year
            — or, when an offtake contract is declared, the contract form in §7.1
            debt service = level annuity over debt_tenor_years at interest_rate_pct
                           — or the sculpted repayment of §7.7
            depreciation = CAPEX_net_funded / depreciation_years, straight line,
                           for t ≤ depreciation_years
            tax       = tax_rate_pct on (revenue − opex − stack − depreciation
                                         − interest), floored at zero
                        — or, with the carry-forward of §7.7, net of losses carried
            reserve   = the maintenance-reserve contribution of year t       (§7.4)
            drawdown  = the stack replacement the reserve pays in year t     (§7.4)
            equity CF = revenue − opex − stack − reserve + drawdown
                        − debt service − tax
            DSCR      = (revenue − opex − reserve − tax) / debt service,  t ≤ debt_tenor_years
                        (CFADS after the year's cash tax; no debt service → no DSCR)

project (unlevered) flow:
t = 0     : − CAPEX_net_funded
t = 1..N  : revenue − opex − stack − unlevered tax, where the unlevered tax is
            tax_rate_pct on (revenue − opex − stack − depreciation), floored at zero
            — or, with the carry-forward of §7.7, net of unlevered losses carried
```

`opex` is the recurring cost — electricity, O&M, water and, when declared, external heat (§3) — and `stack` the replacement of
§3 in its year. The project flow pays the replacement in its year whatever the financing;
the equity flow pays it through the reserve when one is funded (§7.4).

### 7.1 The declared offtake contract — new in 5.1.0, given a term in 5.2.0, its take-or-pay capped at production in 6.2.0

Before 5.1.0 the offtake was two loose numbers: `offtake_volume_pct`, a flat
haircut on production, and `price_escalation_pct`, a flat escalation. Neither can
express what makes a project bankable — a take-or-pay, a price floor and its cap,
or a real indexation. `offtake_contract` is an **optional** input; when it is
absent the engine evaluates the expression above, character for character, and a
pre-5.1.0 input therefore produces the identical figure.

When it is present:

```
price(t)     = clamp( price × (1 + index_rate_pct/100)^(t-1),
                      price_floor_eur_kg, price_cap_eur_kg )
delivered(t) = P(t) × (offtake_volume_pct/100)
shortfall(t) = max(0, min(minimum_volume_kg_year, P(t)) − delivered(t))   from 6.2.0
             = max(0, minimum_volume_kg_year − delivered(t))              until 6.1.0
revenue(t)   = delivered(t) × price(t)
               + shortfall(t) × price(t) × (take_or_pay_pct/100)
               + o2_revenue_eur_year
```

**The buyer pays for what the plant made available, not for what it could not make — new in
6.2.0.** A take-or-pay obliges the buyer to pay for committed volume it does not take; it does
not oblige it to pay for volume the seller never produced. A shortfall on the seller's side is
the seller's default, and under a real contract it can cost the seller damages. Until 6.1.0 the
shortfall here was measured against the commitment alone, so a plant producing less than its
minimum was paid the difference: revenue stayed at `minimum × price` whatever the plant made,
and cutting the operating hours — buying less electricity for the same revenue — raised the
NPV. From 6.2.0 the volume the buyer pays for is capped at what the plant produced that year,
so at a take-or-pay of 100 % the hydrogen revenue of a year never exceeds `P(t) × price(t)`.
The engine does not compute the seller's damages, and the report says so (§7.2).

The rule travels inside the inputs, `take_or_pay_basis: produced`, which the input contract
writes into every new calculation and refuses with any other value: no author chooses it. A
calculation stored before 6.2.0 does not carry it and keeps the 6.1.0 rule, so its report,
re-issued, is the one its engine made.

**The contract has a term, and outside it the contract does not apply.**
`term_years` states how many operating years the contract covers. Absent, it covers
the whole modelled life — which is what 5.1.0 did without being able to say so, and
that silence was an *optimistic* assumption: a ten-year take-or-pay declared on a
twenty-year project was charged for twenty. Measured on a 100 % take-or-pay over a
2 Mkg commitment at half delivery, twenty-year revenue falls from **200.0 M€** to
**125.0 M€** once the real ten-year term is declared — a **60 %** overstatement,
carried straight into the cover ratio.

A year beyond the term returns **exactly** the expression a project with no contract
at all would return: the price, offtake share and escalation stated on the form. Not
a projected merchant curve — this platform does not forecast one — and not zero. The
report says which years those are and what they were computed from (§7.2).

**The order indexes then clamps, and it is not a stylistic choice.** A contract
indexes and then bounds; clamping first would let the escalation push the price
above the cap the contract just set. Measured: 5 EUR/kg at 10 % in year 10 is
11.79 EUR/kg, and 6.00 exactly under a cap of 6 — where the reverse order would
give 14.15, above the cap.

**`index_rate_pct` REPLACES `price_escalation_pct` when a contract is declared;
the two are never summed.** They express the same quantity at different levels of
detail, and adding them would count one escalation twice. Same rule as
`capex_surcharges` against `bop_pct` in §4.

**The index is declared, not forecast.** `index_kind` states what the contract
says (`fixed`, `cpi`, `gas_price`, `power_price`); `index_rate_pct` is the
**author's** assumption about what that index will do. Indexation to a gas or
power price requires a forward curve this platform does not hold and could not
re-derive, so a report on such a contract prints a fixed sentence saying the rate
is the author's assumption and that no forward curve was consulted. Publishing a
projection without being able to show the work would contradict everything the
verifiability chain in §8 exists for.

**Two declarations are refused, not resolved.** A price floor above its own cap is
not a contract anyone signs, and applied literally the cap wins and the floor
disappears — the platform would return a plausible figure computed from half of
what was declared. A take-or-pay above 100 % charges more than the price for volume
never received; a penalty on top of the price is a separate clause. Both are
rejected at the input contract with the reason stated in the contract's own terms.

### 7.2 What a declared contract does to the published figures, and what the report must say

A floor and a take-or-pay **raise** revenue; a cap lowers it. Measured on a
1 Mkg/year plant at 5 EUR/kg with 80 % contracted and 2 % escalation, a floor of
6 EUR/kg together with a 100 % take-or-pay on a 1 Mkg commitment takes year-1
revenue to **1.48×** the same project with no contract declared. Because
`min_dscr` is `(revenue − recurring opex) / debt service` with both denominators
fixed, the effect on the coverage ratio is **larger** than that 1.48. Since 6.1.0 the numerator
also deducts the maintenance-reserve contribution (§7.4), which a contract does not move.

That is legitimate — a real take-or-pay does support the coverage ratio — and it
is exactly why the disclosure is part of the method rather than a courtesy:

1. a contract indexed to a market price the platform does not forecast prints the
   author's-assumption sentence above;
2. a price cap prints that the high percentiles of a Monte Carlo run are the
   capped price, not the market price the simulation drew;
3. a minimum volume with a take-or-pay of 0 prints that it is a volume target and
   not a take-or-pay, and puts no floor under the coverage ratio;
4. **the years outside the contract term**, when one is declared: how many there
   are and that they carry the author's stated price rather than contracted revenue;
5. **the merchant tail of the financing** — when the debt tenor runs past the
   contract term, how many years of debt service, and what share of the repayment
   schedule, are covered by revenue with no contract behind them. A lender
   underwrites the contract, not the projection, and this is the year the cover ratio
   stops being contractual;
6. **a commitment above what the plant delivers** prints what fraction of the
   commitment the plant covers and the volume the buyer is charged for — what the
   plant produces and the buyer does not take — and, at a take-or-pay of 100 % with
   the commitment within what the plant produces, that revenue then equals the
   committed volume times the price and does not move with production while the
   plant still produces it, so the coverage ratio shown measures the buyer's
   obligation to pay rather than this plant's output;
7. **a commitment above what the plant produces** — new in 6.2.0 — prints that the
   excess earns nothing, because a take-or-pay charges the buyer only for volume the
   plant made available, and that under the contract it is the seller's shortfall,
   which can cost the seller damages that this model does not compute.

A calculation stored before 6.2.0 prints the sixth as it did: under its rule the
commitment above production was charged, and revenue did not move with production at
all. The parameter table of a calculation that carries the rule and declares a
take-or-pay prints it in its own row, "Take-or-Pay Rule — Charged only on volume the
plant produced and the buyer did not take", with its origin, as it prints the
maintenance reserve.

The sixth and seventh are disclosures and not refusals: over-commitment is a contract
that gets signed, and it is precisely the risk a lender wants to see. The comparison
basis is year-1 **nameplate** production, before degradation — the conservative
choice, since no later year produces more, so a commitment that already exceeds
nameplate exceeds every later year by at least as much.

Published metrics and their definitions:

| metric | definition |
|---|---|
| `npv`, `project_irr` | on the **unlevered** project free cash flow, discounted at the WACC. Financing cost lives in the WACC, not in the flows (methodology v2.2). |
| `equity_irr` | on the levered equity flow. `null` when it does not resolve. |
| `min_dscr`, per-year `dscr` | **after tax**: (revenue − recurring opex − maintenance-reserve contribution − the cash tax of the year) ÷ debt service, the reserve since 6.1.0 (§7.4) and the tax since 7.0.0. A change in revenue moves the DSCR by `(Δrevenue − Δtax) / debt_service`. **`null` when the calculation has no debt** — there is no debt service to cover — and so is `avg_dscr`; until 6.2.0 both were 0. |
| `reserve_contribution`, `reserve_drawdown` | per year: what is set aside for the next stack replacement inside the debt tenor, and what the reserve pays that year — new in 6.1.0 (§7.4). |
| `lcoh_constant` | the LCOH in constant money (§3.2) — new in 6.1.0. |
| `breakeven_price` | bisection to NPV = 0, ceiling 100 EUR/kg. `null` when the project never reaches profitability in range — an explicit sentinel, never a saturated figure. |
| `simple_payback` | first year cumulative equity cash flow turns non-negative. `null` when it never does. |
| `capex_total` | CAPEX_net. **Meaning unchanged across the 4.1.1 → 5.0.0 boundary**, deliberately: it is consumed by every issued report. |
| `capex_funded` | CAPEX_net_funded — new in 5.0.0. |
| `capex_physical_gross` | CAPEX_physical, before subsidy and before capitalisation. |

This cash flow is evaluated at several call sites in the codebase — the
deterministic TEA and its sensitivity sweep, the two Monte Carlo fast paths, and
the subsidy-premium adapter and its own sweep. Two of its terms are now **single
definitions** that every site imports rather than repeats: the unlevered project
cash flow, and — since the cut that preceded 5.1.0 — the annual revenue line
itself, which had been written five times in four files. That consolidation was
verified byte-identical over 200,000 cases before the contract was added to it,
which is why it shipped as a re-pin and not as a version bump.

The remaining per-year terms are still implemented independently and are held
byte-equal in behaviour by lockstep tests, not by convention: the premium adapter
at premium = 0 must equal the deterministic TEA field by field, and the Monte
Carlo TEA with zero variables must equal the closed-form NPV. Both are pinned. The
maintenance-reserve rule of §7.4 is, like the project flow and the revenue line, a single
definition that the three TEA paths import.

### 7.3 Aggregating a Monte Carlo TEA run — new in 6.0.0

A Monte Carlo TEA run evaluates the cash flow above once per simulation and then
aggregates. What counts, and for what, is method and not an implementation detail,
because the published probabilities are quotients and a quotient is as much its
denominator as its numerator.

**A simulation is DISCARDED only when it produces no finite number.** It is then
counted in `invalid_runs` and enters nothing. When every simulation of a run is
discarded, the run fails rather than returning zeros — the same behaviour the LCOH
Monte Carlo has had since 23 Aug 2026.

**A simulation with no project IRR is not a discarded simulation.** The project IRR
does not exist when the unlevered cash flows never turn positive; that is what a loss
looks like, not a failure to compute. Such a simulation carries a finite NPV, a DSCR
and a payback answer, and it counts in all of them, in `simulations`, and in the
sensitivity regression. It is excluded from one thing only — the IRR **distribution**,
which cannot contain a number that does not exist — and how many there were is
published as `runs_without_irr`.

It follows that, for `prob_irr_above_wacc` and for `prob_all_bankable`, a missing IRR
is a **failure of the condition and not a removal from the sample**: it sits in the
denominator and fails the test. Since 7.0.0 a missing IRR means that the NPV does not change
sign between −99 % and 1 000 %, and nothing else: the solver falls back to bisection (§7.6).

**A simulation without debt has no DSCR — new in 7.0.0.** Its minimum DSCR is `null` and it
does not enter the DSCR distribution; `prob_dscr_above_1_3` is taken over the simulations that
carry debt, and is `null` when none does, in which case `min_dscr` is `null` too. For
`prob_all_bankable` the DSCR condition **does not apply** to a simulation without debt: it
is bankable on NPV > 0 and IRR > WACC alone. Until 6.2.0 the 0 stored for "no debt" failed
"DSCR > 1.30" and therefore every "all bankable" test of an all-equity project.

`prob_no_payback` is the share of the counted simulations whose cumulative equity cash
flow never turns non-negative.

Until 5.3.0 a simulation without an IRR was discarded whole, which removed from the
sample exactly the cases where the project loses money. §11 states the measurement.

### 7.4 The maintenance reserve and the DSCR — new in 6.1.0

Until 6.0.0 the DSCR left the stack replacement out of its numerator. On the reference case
(§9) it read 1.64 in year 10, the year the equity holders paid a 4.30 M€ replacement out of
their own cash. A lender does not measure cover that way: major maintenance comes out of the
cash before debt service, and a reserve is funded in the years before it so that the year of
the replacement does not sink the cover. Decided by the owner on 29 Sep 2026, with the
figures below in front of him.

The rule is one definition, imported by the deterministic TEA, its Monte Carlo fast path and
the premium adapter:

1. **Every stack replacement inside the debt tenor is reserved** (`t ≤ debt_tenor_years`).
   One after the tenor is paid from that year's equity cash flow, as before: there is no
   lender left to require it.
2. **It is funded in equal contributions over the years of that stack**: from the year after
   the previous replacement — or from year 1 — to the year of the replacement itself, both
   included. A ten-year stack is funded in ten contributions.
3. **The reserve pays the replacement**, so that year's equity cash flow does not pay it
   again.
4. **No debt, no reserve.**

```
contribution(t) = stack(r) / (r − r_prev)   for r_prev < t ≤ r, r a reserved replacement
drawdown(t)     = stack(t)                  when t is a reserved replacement, else 0
DSCR(t)         = (revenue(t) − opex(t) − contribution(t) − tax(t)) / debt_service(t)
```

The `− tax(t)` term is 7.0.0's (§11); under 6.1.0 and 6.2.0 the numerator stopped at the
contribution.

**What does not move**, and a test holds each: the tax — the replacement is deducted in its
year, and a contribution to a reserve is not an expense —, the unlevered project flow, which
still pays the replacement in its year, and therefore the NPV and the project IRR; and the
sum of the equity cash flows over the life. What moves is when the equity holders pay:
sooner. On the reference case, under 6.1.0, the minimum DSCR fell from 1.638 to 1.054, still
in year 10, the average from 1.819 to 1.429, and the equity IRR from 5.17 % to 4.12 %; the NPV
stayed at −2.32 M€ and the project IRR at 4.50 %. The after-tax figures of 7.0.0 are in §9.

**It travels inside the inputs.** The input contract writes
`maintenance_reserve: funded_over_stack_years` into every new TEA and Monte Carlo TEA
calculation and rejects any other value, so the rule is inside the content hash of §8.
**Absent, the engine evaluates the rule of 6.0.0 and before**: no reserve, and the
replacement out of the DSCR numerator. Every calculation stored before 6.1.0 declares none
and keeps its figures, and a report re-issued from one recomputes its sensitivity, its stress
test and its premium analysis under its own rule instead of mixing two DSCRs in one document.

The report prints the rule of the calculation it describes: the parameter table names it,
the DSCR definition in the glossary and the legend of the coverage page say how the reserve
is funded and who pays, and the annual table carries a `Reserve` column and marks the
replacement the reserve pays.

### 7.5 The stress test against the declared structure — specified in 6.1.0

Methodology `2.7` added a stress table to the TEA report and said its specification would
land in the next frozen document at the next model bump; the documents of `5.3.0` and `6.0.0`
did not carry it. This is it. The primary sources remain `src/lib/calculations/stress.ts`,
`stress-disclosure.ts` and `sensitivity-sweep.ts`, and a test ties every magnitude below to
the constant the code uses.

Four shocks, each applied to the declared inputs and evaluated with the full engine of §7 —
so a declared offtake contract (§7.1) applies its floor, its cap and its take-or-pay as it
would in any year:

| shock | input it moves | how |
|---|---|---|
| Price down | `hydrogen_selling_price` | × (1 − m) |
| Price up | `hydrogen_selling_price` | × (1 + m) |
| Volume down | `offtake_volume_pct` | × (1 − m) |
| Price and volume down | both | × (1 − m) each, at once |

`m` is 20 % — the magnitude the sensitivity sweep uses for the selling price, so the two
tables are read on the same scale. The shocked price is kept within the 0 to 30 EUR/kg the
input contract accepts, and a shock that stops at that edge prints the price it used. The
four are independent evaluations; the combined one moves both inputs at once, so there is no
order of application to state.

For each shock the table publishes:

- **the minimum DSCR over the whole life**, beside the base case's;
- **what the structure absorbed, on year 1**: `1 − |ΔR_structure| / |ΔR_bare|`, kept within
  0 to 100 %, where `ΔR_structure` is the change the shock makes to year-1 revenue with the
  declared contract and `ΔR_bare` the change it makes with none. Year 1 is the only year that
  exists under any declared term, so the measure does not depend on the term. A shock that
  moves no bare revenue gives 0, not a percentage;
- **which clause absorbed it**, asked of the contract and not deduced from the figure: the
  price floor when the shocked price falls below it, the cap when it rises above it, and the
  take-or-pay when a volume shock leaves a shortfall and the take-or-pay is above 0 — and only
  when the contract covers year 1. A combined shock can name two; none is named when nothing
  was absorbed.

**What it is not**, printed with the table: it is not a full lender acid test — OIES ET21
lists seven downside factors and this platform models two — and no threshold is applied: the
DSCR is reported, not judged.

### 7.6 Two numerical rules — new in 7.0.0

**The Beta-PERT is the standard one.** A PERT(min, mode, max) input is a Beta(α, β) on
[min, max] with λ = 4:

```
α = 1 + 4 · (mode − min) / (max − min)
β = 1 + 4 · (max − mode) / (max − min)
mean = (min + 4 · mode + max) / 6
```

Until 6.2.0 the engine took α and β from the mean, `α = 1 + 4 · (mean − min)/(max − min)`,
which equals the standard form only when the mode is at the centre of the range. With the
mode off-centre it pulled the distribution towards the centre: PERT(0, 0.2, 1) had a mean of
0.367 instead of 0.300. The sampler, the copula's inverse CDF and the reference CDF of the
goodness-of-fit test now share the standard form. The copula's inverse Beta CDF is a Newton
iteration held inside a bracket that always contains the root, with bisection when a step
leaves it; before, a skewed Beta could send it to the upper bound.

**An IRR exists when the NPV changes sign.** Every IRR the engine publishes — project and
equity IRR in the deterministic TEA, the project IRR of each Monte Carlo simulation and the
premium adapter — comes from one solver: Newton's method from 10 %, as before, and when it
does not converge, bisection on the first sign change of the NPV over a grid from −99 % to
1 000 %, the one nearest to 0 % first. Where Newton converged the figure is unchanged. Until
6.2.0 Newton had no fallback, and cash flows with an IRR near −40 % were reported as having
none: [−100, 10, 5, 5, 5] has an IRR of −41.6 %.

### 7.7 Project-finance options — new in 7.1.0

Every option below is an optional input of the TEA. With none of them present the engine runs
the expressions of 7.0.0 unchanged and the output carries no `financing` object and no
`dsra_flow` column. With any of them present the output carries a `financing` object with the
figures below.

**Cover ratios** (`loan_life_cover_ratios`; also published whenever any other option is set).
Following Yescombe, *Principles of Project Finance* (2nd ed., 2014), §12.4.2, and the cover
ratios of Moody's *Generic Project Finance Methodology*:

```
CFADS(t) = revenue − opex − reserve − tax                (the DSCR numerator of §7)
LLCR(t)  = Σ_{k=t..tenor} CFADS(k) / (1 + i)^(k−t+1)  ÷  debt outstanding at the start of t
min LLCR = min over the years t ≤ tenor with debt outstanding
PLCR     = Σ_{k=1..N} CFADS(k) / (1 + i)^k  ÷  the debt drawn         (at the start of operation)
```

`i` is `interest_rate_pct`. The DSRA balance is not added to the numerator. Without debt both
are `null`.

**Sculpted repayment** (`debt_repayment: 'sculpted'`, `target_dscr`, default 1.30). Following
Yescombe §12.5.4 and Gatti, *Project Finance in Theory and Practice* (3rd ed., 2018), ch. 5, the
principal of each year is the one that sets the DSCR at the target:

```
interest(t)  = debt outstanding at the start of t × i
principal(t) = min( max(0, CFADS(t) / target − interest(t)), debt outstanding )
debt service = interest(t) + principal(t)
```

The debt amount is still `debt_share_pct` of the funded capital: sculpting shapes the
repayment, it does not size the debt. Because the tax deducts the interest, the year's tax and
CFADS are computed before its debt service. If the target cannot be met — CFADS/target below
the interest in some year, or debt still outstanding in the last year of the tenor — the last
year of the tenor repays the balance (a balloon), `sculpting_target_unmet` is `true` and
`sculpting_balloon_eur` states the amount; that year's DSCR falls below the target and the
minimum DSCR shows it. Debt repaid before the tenor ends has no further debt service.

**Debt service reserve account** (`dsra_months`). Following Yescombe §12.6.2: the balance held
during year t is `dsra_months / 12` of that year's debt service. It is funded at the start of
operation (year 0) **from equity**, adjusted each year to the next year's requirement and
released in full when the debt is repaid. Each year's movement is published as `dsra_flow` and
is inside the equity cash flow; `dsra_initial_funding` is the year-0 amount. The DSRA earns no
interest in the model and does not touch the tax, the DSCR or the project (unlevered) flow; it
moves the equity flow, the equity IRR and the payback.

**Carry-forward of tax losses** (`tax_loss_carry_forward`, `tax_loss_cap_pct`,
`tax_loss_cap_floor_eur`). A negative taxable base is carried forward without time limit; a
positive one is offset by the losses carried, up to `max(base × cap %, floor)` and never more
than the base. Without a cap the whole base can be offset. The Spanish corporate income tax,
Ley 27/2014, art. 26.1, sets a cap of 70 % of the prior taxable base, always allowing 1 M€, with
no time limit: `tax_loss_cap_pct` 70 and `tax_loss_cap_floor_eur` 1 000 000. The lower caps for
large companies of its additional provision 15 are not modelled. Losses not offset by the end
of the life are published as `tax_losses_unused_eur`. The carry-forward applies to the tax the
company pays — the equity flow, CFADS, DSCR, LLCR and PLCR — **and to the project (unlevered)
flow, its NPV, its IRR and the breakeven**: the same rule, with its own pool of losses, on the
unlevered base (revenue − opex − stack − depreciation, no interest). `tax_losses_unused_eur`
reports the company's pool. The TEA report's annual table and the screen table apply it too.

The Monte Carlo TEA and the premium adapter apply the same rules through the same code
(`calculations/financiacion.ts`): without dispersion the Monte Carlo gives the deterministic
NPV and minimum DSCR, and a zero premium gives the deterministic TEA field by field.

## 8. Verifiability

Two independent anchors travel with every figure.

**`content_sha256` — the calculation.** sha256 over the canonical JSON of
`{ type, inputs, outputs, model_version }` (plus `seed` and
`correlation_matrix` for Monte Carlo runs). It excludes any timestamp, so it is
reproducible without knowing when the calculation ran, and it excludes
`methodology_version`, because a methodology change changes the formulae, which
changes the outputs, which changes the hash — recording the version inside would
be redundant metadata. The canonical-JSON recipe is published on the public
methodology page, with a worked example and snippets, so a third party can
recompute it without this platform.

**This document's own sha256 — the method.** Published in
`calculator-methodology-v7.1.0.sha256.txt` and embedded as
`methodology_sha256` in the shipped reference-case artifacts
(`src/data/lcoh-reference-case.json`, `src/data/tea-reference-case.json`). It is
NOT part of the content payload: adding it would change the published hash
recipe and break the symmetry above. It sits beside the payload as metadata, so
a reader can tie a reference case to the exact method text that produced it, and
a test refuses any drift between the three.

## 9. Reproduction invariants

A reader who implements §3–§5 independently must obtain these figures. They are
pinned in the test suite; if the engine ever stops producing them, the suite goes
red before anything ships.

Reference case — PEM, 10 MW, 900 EUR/kW, BoP 30 %, 4 000 h, availability 95 %,
consumption 50 kWh/kg, electricity 40 EUR/MWh, water 10 L/kg at 2 EUR/m³, O&M 2 %,
life 20 y, WACC 7 %, degradation 1 %/y as lost efficiency, stack every 10 y at 40 %,
inflation 2 %, subsidy 0:

| construction period | LCOH | CF | CAPEX physical | CAPEX capitalised |
|---|---|---|---|---|
| absent or 0 months | 4.6084 EUR/kg | 1 (exactly) | 11 700 000 EUR | 11 700 000 EUR |
| 18 months (the default) | 4.7425 EUR/kg | 1.088725 | 11 700 000 EUR | 12 738 083 EUR |

These are under the degradation model the contract writes, `efficiency_loss`. Without
it — the 5.2.0 model — the same case gives 4.5731 and 4.7117, the figures of the 5.2.0
document.

The TEA of the same case — the default form: hydrogen at 5 EUR/kg with 80 % offtaken and 2 %
escalation, no oxygen revenue, 60 % debt at 5 % over 15 years, tax 25 %, depreciation over
15 years, the 18-month build and the maintenance reserve of §7.4 — gives a minimum DSCR of
**1.0141** in year 9 and an average of **1.3436** over the fifteen years of debt; under the
6.0.0 rule, without the reserve, **1.5984**. Year 10 is no longer the minimum because it deducts
the stack replacement from its taxable base and pays no tax. Before 7.0.0, pre-tax, the same
case gave 1.0537 in year 10, 1.4290 and 1.6380. With `debt_share_pct` 0 the minimum and the
average DSCR are `null`. Its LCOH in constant money (§3.2) is
**4.0226 EUR/kg**, at a real WACC of 4.902 %.

The take-or-pay rule of §7.1 on the same case: the default form with a 100 % take-or-pay on
760 000 kg/year — what the plant produces in its first year at 4 000 h — indexed at a fixed
2 %. At 4 000 h the NPV is **4.5237 M€**; at 2 000 h it is **−5.3867 M€**, with a first-year
revenue of 1 900 000 EUR, the 380 000 kg produced at 5 EUR/kg. Under the 6.1.0 rule the same
case gives **5.9795 M€** and **13.1858 M€**, and 3 800 000 EUR in year 1 at both hours: the
buyer paid for the 760 000 kg whether the plant made them or not. The two rules already
differ at 4 000 h because the stack loses output as it ages, so from year 2 the plant makes
less than the commitment until its replacement restores it.

Book-table invariants: Table A7-2 (20 cells), the 10 % block of Table A7-3
(25 cells), four comparable cells of Table A7-4, and both Table 8.8 totals
(667.00 → 1047.19 and 976.60 → 1533.26 at the ×1.57 surcharge factor).

## 10. Versioning

`model_version` is the engine (semantic versioning: MAJOR when the same inputs
legitimately produce materially different outputs; MINOR when what moves is what the input
contract writes into NEW calculations, or an output is added beside the others, and a stored
input re-run gives what it always gave — 5.3.0, 6.1.0, 6.2.0 and 7.1.0; 6.0.0 and 7.0.0 are MAJOR).
`methodology_version` is
this document. They move independently — 4.1.1 corrected the LCOH capital base
without changing the financial method, so the methodology stayed at 2.2.

Issued reports are never retroactively recalculated. A report carries the
version pair that produced it.

## 11. Change log — 7.0.0 / 3.30 → 7.1.0 / 3.31

**Why MINOR on the model.** §10: an input re-run gives what it always gave. The four options
of §7.7 travel inside the inputs, none has a default the contract writes, and without them the
engine runs the expressions of 7.0.0; the output gains a key only when the input asked for it.

1. **LLCR and PLCR** (§7.7), published with any of the options.
2. **Sculpted repayment** to a target DSCR, with a flag and a balloon when the target cannot
   repay the debt within the tenor.
3. **DSRA** in months of debt service, funded from equity at the start of operation and
   released at maturity.
4. **Carry-forward of tax losses**, without time limit, with an optional cap and floor (the
   Spanish rule is 70 % and 1 M€), on the company's tax and on the project (unlevered) flow.
5. **External heat** (§3, property 4): two optional inputs, costed in the LCOH, the TEA, both
   Monte Carlo fast paths and the premium adapter; no default for any technology.
6. **Platform defaults** (§4.1): the installed capex defaults of PEM and alkaline and the BoP per
   technology belong to 7.1.0; 7.0.0 keeps the previous ones.

**Re-frozen on 12 Oct 2026, before any client calculation.** This document was first frozen on
11 Oct with items 1–4 (the carry-forward then only on the company's tax). Items 5 and 6 and the
unlevered carry-forward were folded into the same version pair before launch, when no calculation
had been issued to a client under 7.1.0; the two reference cases were regenerated and their
inputs and outputs did not move (§9), only this document's sha256.

**What moves:** the TEA, Monte Carlo TEA and premium figures of a NEW calculation whose input
sets one of the options; the LCOH and TEA figures of a NEW calculation that declares the heat
inputs; the defaults written into a NEW calculation (§4.1); the `content_sha256` of every new calculation, which carries the model
version; and the two shipped reference cases' version stamp, `content_sha256` and this
document's sha256 — not their inputs or outputs. **What does not:** every stored calculation,
its figures and its hash; every output of any input without the options, bit for bit, with no
new key; the LCOH and the LCOH Monte Carlo of any input; the index and the catalogue benchmark.

The methodology change `3.30`, under `7.0.0`, is published in
`calculator-methodology-v7.0.0-m3.30-changes.md` and continues, with this one, in
`calculator-methodology-v7.1.0-m3.31-changes.md`. The change log for `6.2.0` / `3.29` →
`7.0.0` / `3.30` lives in the frozen document for that version pair.

## 12. Provenance of the method

The capital-charge formulation follows the ICI / Stratton concept-estimate
methodology as set out in D. Seddon, *The Hydrogen Economy: Fundamentals,
Technology, Economics* (2022), Appendix A7 (Tables A7-1 to A7-4) and Chapter 8
(Tables 8.8 to 8.10). Every constant taken from that source names its table in
the code, together with the invariant that reproduces the published cells.

The source's cost figures are **not** carried as platform values: capital and
operating costs are user inputs. What is taken from the source is method, and
where the printed method fails to reproduce its own tables, the tables win —
see §5.
