Traffic Growth ============== **Implementation status:** Partial (coverage matrix row *Traffic Growth*). Production: global CAGR (single, two-period or multi-segment) + COVID factors, two-track headline model per DL-022 — no route/regional differentiation in the wedge path. The rest of the page — the cubic Hermite linking family (eq. 2–9), the flight-count projection (eq. 10), the region-pair CAGR form (eq. 13) and the per-route fuel-mass series (eq. 15) — is implemented standalone in ``src/engine/traffic-growth-full.ts`` (DL-137, Stage-1 shadow; import guards keep it unreachable from production entry points). Every result declares its traffic basis per DL-139/DL-165 (root year, root value, growth rate, COVID treatment, recovery assumption). **Source:** ``src/engine/cascade.ts:computeLCA`` (``growthMultAt``, ``grossAt``); ``src/engine/traffic-growth-full.ts`` (full page, shadow) **Test evidence:** ``tests/traffic-model.spec.ts``, ``tests/end-year.spec.ts``, ``tests/horizon-2100.spec.ts``, ``tests/suite-l-traffic-growth-full.spec.ts``, ``tests/traffic-dataset-provenance.spec.ts`` Compound growth --------------- Growth is applied to the 2019 baseline (cf. CASCADE *Traffic Growth*, eqs. 11–14). For a single compound annual growth rate: .. math:: M(y) = \left(1 + \frac{g}{100}\right)^{y - 2019} with :math:`g` the scenario CAGR (default 3.5 %/yr). Two refinements are implemented. A two-period form switches CAGR at a break year: .. math:: M(y) = (1+g_1/100)^{y_b - 2019}\,(1+g_2/100)^{y - y_b}, \qquad y > y_b and a multi-segment form (``cagrPeriods``, up to 12 periods, overriding the simpler forms when present) compounds segment by segment: .. math:: M(y) = \prod_{s \in S} (1 + g_s/100)^{\,\min(e_s, y) - \max(s_s, 2019)} \quad\text{for segments with } \min(e_s,y) > \max(s_s,2019) COVID demand shock ------------------ Calendar years 2020–2023 are scaled by demand-recovery factors (``constants.ts:COVID_FACTORS``), calibrated to the global traffic collapse and recovery: .. list-table:: :header-rows: 1 * - Year - Factor * - 2019 - 1.0 * - 2020 - 0.3941 * - 2021 - 0.4631 * - 2022 - 0.7168 * - 2023 - 0.9424 Gross BAU emissions at year :math:`y` are then: .. math:: G_{gross}(y) = 0.92\ \mathrm{Gt} \times M(y) \times f_{covid}(y), \qquad f_{covid}(y) = 1\ \text{outside 2020–2023} so the 2021 gross value falls **below** the 2019 baseline (pinned by test). At defaults the 2050 value is :math:`0.92 \times 1.035^{31} \approx 2.67` GtCO₂. Two-track headline model (DL-022) --------------------------------- Historically the headline scalar and the time-series sweep used different BAU models (2.82 Gt anchor vs 2.67 Gt compounded — DEFECT-NEW-1). DL-022 unified both behind the shared growth machinery and introduced ``traffic_model``: * ``'cascade_series'`` (default): headline ≡ time-series, as above. * ``'legacy_anchor'``: the frozen v3.3 scalar :math:`G = 2.82 \cdot (g/3.5) \cdot y_f \cdot f_{covid} + 0.92(1-y_f)`, retained only so the frozen parity baseline stays reproducible. Test evidence (8 tests) pins the headline≡series identity, the :math:`0.92 \times 1.035^{31}` value, the legacy anchor, monotonicity in both modes, the COVID shock below baseline, and conservation :math:`0 \le G_{net} \le G_{gross}`. Extended horizon: ``end_year`` 2050 / 2075 / 2100 (DL-044) ---------------------------------------------------------- The scenario horizon is selectable via ``end_year`` (``2050 | 2075 | 2100``, default 2050; URL-state v2 accepts only these three values as ``enum_end_year``, and the engine defensively clamps any out-of-set value into [2050, 2100]). Extending the horizon must never reshape the legacy window, so the rule is **hold-not-stretch**: a ``Y_SAT = 2050`` constant anchors every curve normalisation (adoption S-curves saturate at 2050, the SBTi pathway — defined to 2050 only — holds its 2050 floor), while ``end_year`` only extends the sweep loop. Traffic growth keeps compounding beyond 2050 at the last-period CAGR (the two-period machinery defaults :math:`g_2 = g_1`, so the extension is continuous): .. math:: G_{gross}(2100) = G_{gross}(2050)\,(1 + g/100)^{50} \qquad \text{(single-CAGR default)} Acceptance properties, all pinned by test: * **Frozen-baseline bit-identity** — ``end_year: 2050`` (or omitted) reproduces the legacy engine exactly (physics-signature equality); both frozen two-track baselines are untouched by construction. * **Prefix invariance** — the first 32 slices (2019–2050) of a 2100 run are exactly the 2050 run. * **Hold-flat** — adoption/saturation curves, SAF and methane blends, removal cost/capacity and SBTi hold their 2050 values beyond 2050 (no silent stretch); the aircraft-wedge/gross ratio is flat once fleet renewal completes. * **KPI stability** — the 2050-anchored KPIs (``net2050``, ``grossBau2050``, ``sbti2050``, ``gapToSbti``) never move with ``end_year``; ``endYear`` / ``netEnd`` / ``grossEnd`` expose the horizon end. A 2100 run has 82 slices (2019–2100), conservation :math:`G_{gross} = G_{net} + \sum \text{reductions}` holds every year, and cumulative net emissions are monotone non-decreasing. DL-044 also wires the RST **Custom Global Initiative (CGI)** offsets mode (``cgi_enabled``, ``cgi_gamma_end`` clamped to [0, 0.85]): offsets are auto-set to hold eligible emissions at the CORSIA baseline :math:`0.85\,G_{2019}` for 2024–2035, then follow a linear CGI baseline to :math:`\gamma_{end}\,G_{2019}` at ``end_year`` (continuity at 2036 exact by construction). Constrained offset mode only — the frozen ``'percent'`` track ignores CGI, and the user offsets ambition is inert while CGI is active (per the RST). See :doc:`scenarios` for the URL-state surface. Known deviations / limitations ------------------------------ * CASCADE's cubic-Hermite shock-recovery blend is implemented standalone (``traffic-growth-full.ts``, DL-137) but **cannot reproduce CASCADE's curve**: the spline-width parameter α is never given a value anywhere in the 27-file corpus, so it is a required caller argument with no default (``HERMITE_ALPHA_UNVALUED_NOTE``), and the printed eq. 8/9 use an absolute-year exponent that overflows as printed (reproduced under ``CASCADE_PARITY`` as a diagnostic, corrected under ``CURRENT_EVIDENCE``). The production path applies the flat factor table; the 2019-rooted vs 2023-rebased readings differ by 21.77 % from 2032 onward, which is why every result names its basis (DL-139/165). * No route-, region- or market-segment-differentiated growth in production. The region-pair CAGR form (eq. 13) exists in the shadow module, and since DL-166 it has a **sourced value**: Boeing's own published CMO 2026 forecast-data workbook (all 39 region-pair RPK flow rows, transcribed programmatically with attribution) plus Airbus GMF 2026 world figures ship in ``src/data/market-outlooks.ts`` (``tests/market-outlooks.spec.ts``), and the ``boeing_cmo_2026`` library scenario applies the published world CAGR. CASCADE's own internal CMO/WACF configuration remains unheld beyond its two public endpoint anchors (see the Boeing-CMO root, :doc:`scenarios`). * The ambition table's traffic levels (``AMBITION.traffic`` = 2.4/2.9/3.4/3.7/4.0 %/yr) are available but the headline CAGR remains a direct user input in most flows.