Skip to content

Commit c51a8d6

Browse files
authored
Add fiscal-year uprating planning docs page (#1437 #1436) (#1716)
#1437 is filed as a low-priority enhancement to align uprating indices with the UK fiscal year (April 6) rather than the current January 1 dates plus convert_to_fiscal_year_parameters post-process workaround. #1436 proposes the inverse — keep January 1 dates but resolve the conversion lazily at query time. This page captures both, the relationship between them, and the recommended sequencing (#1437 first, then re-evaluate #1436). It also identifies the four pipeline changes the April-date move needs: 1. yoy_growth.yaml dates from YYYY-01-01 to YYYY-04-06, 2. create_economic_assumption_indices.py emitting at April 6, 3. confirm policyengine-core's uprate_parameters doesn't hardcode January 1, 4. remove convert_to_fiscal_year_parameters and its call site in tax_benefit_system.py. The headline correctness gain is that mid-year queries (e.g. param("2026-05-15")) currently return the wrong fiscal-year value, and the planned change fixes that.
1 parent 634b9ce commit c51a8d6

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

changelog.d/1437.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add a planning docs page at `docs/book/assumptions/fiscal-year-uprating-plan.md` describing the proposed move from January-1 to April-6 dates for OBR growth indices (#1437) and how it relates to the on-the-fly conversion alternative (#1436); identifies the four pipeline changes needed (yoy_growth.yaml dates, create_economic_assumption_indices.py, policyengine-core's `uprate_parameters` assumptions, and removing `convert_to_fiscal_year_parameters`) and notes the user-visible correctness gain at mid-year queries.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Fiscal-year uprating: April-date alignment plan
2+
3+
```{note}
4+
**Planning page.** PolicyEngine UK currently stores OBR growth indices
5+
at **January 1** dates and post-processes parameters to the fiscal year
6+
via `convert_to_fiscal_year_parameters`. This page captures the proposed
7+
move to **April 6** dates throughout, tracked under
8+
[#1437](https://github.com/PolicyEngine/policyengine-uk/issues/1437),
9+
and the on-the-fly alternative tracked under
10+
[#1436](https://github.com/PolicyEngine/policyengine-uk/issues/1436).
11+
This is a low-priority enhancement — the current approach is correct
12+
for annual analysis after PR #1435 extended the fiscal-year-conversion
13+
range out to 2040.
14+
```
15+
16+
## Current pipeline
17+
18+
The model currently does three things in sequence:
19+
20+
1. **OBR indices** live at January 1 dates in
21+
[`parameters/gov/economic_assumptions/yoy_growth.yaml`](../../../policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml)
22+
(annual calendar-year growth rates) and the cumulative indices are
23+
generated by
24+
[`create_economic_assumption_indices.py`](../../../policyengine_uk/parameters/gov/economic_assumptions/create_economic_assumption_indices.py)
25+
at January 1 dates (`f"{year}-01-01"`).
26+
2. **`uprate_parameters`** in `policyengine-core` writes uprated
27+
parameter values at the same dates as the uprating index, so all
28+
uprated parameters land at January 1.
29+
3. **`convert_to_fiscal_year_parameters`** in
30+
[`utils/parameters.py`](../../../policyengine_uk/utils/parameters.py)
31+
post-processes the parameter tree by sampling each parameter at
32+
April 30 and overwriting the whole calendar year with that value.
33+
This is what produces the fiscal-year-correct outputs PolicyEngine
34+
ships today.
35+
36+
This works for annual simulations but has three downsides:
37+
38+
- **Intra-year queries are wrong.** `param("2026-03-15")` returns the
39+
fiscal-year-2026 value when April 6 2026 hasn't happened yet; the
40+
intended pre-April-6 value is the fiscal-year-2025 value.
41+
- The fiscal-year conversion is a **post-process workaround**, not a
42+
correct upstream model.
43+
- Parameter `values_list` entries appear at January 1 dates even
44+
though the legislative change usually takes effect on April 6.
45+
46+
## Proposed change (#1437): store at April 6 throughout
47+
48+
Update each step of the pipeline so it speaks fiscal years natively:
49+
50+
1. Move the dates in `yoy_growth.yaml` from `YYYY-01-01` to
51+
`YYYY-04-06` for every entry, ensuring the growth rate that applies
52+
between fiscal year T and fiscal year T+1 sits at the start of T+1.
53+
2. Update `create_economic_assumption_indices.py` to emit cumulative
54+
indices at April 6 dates.
55+
3. Confirm that `policyengine-core`'s `uprate_parameters` does not bake
56+
any January-1 assumption — if it does, parametrise the date.
57+
4. **Remove** `convert_to_fiscal_year_parameters` and its call site in
58+
[`tax_benefit_system.py`](../../../policyengine_uk/tax_benefit_system.py).
59+
Once steps 1-3 land, the natural answer at every date is already the
60+
fiscal-year-correct value.
61+
62+
### What changes for users
63+
64+
| Query | Today | After April-date move |
65+
|-------|-------|------------------------|
66+
| `param("2026")` (year-string) | Fiscal year 2026/27 value (post-process) | Fiscal year 2026/27 value (direct) |
67+
| `param("2026-03-15")` (pre-April 6) | Fiscal year 2025/26 value (correct) | Fiscal year 2025/26 value (correct) |
68+
| `param("2026-05-15")` (post-April 6) | Fiscal year 2025/26 value (**wrong**) | Fiscal year 2026/27 value (correct) |
69+
| `values_list` dates | January 1 | April 6 |
70+
71+
The third row is the headline correctness gain.
72+
73+
### Scope
74+
75+
- Pure documentation/wiring change — **no household-impact values
76+
should move** for any annual query.
77+
- Regression tests must include both an annual-query and an
78+
April-30-style mid-year-query case so the next refactor can't
79+
reintroduce the off-by-three-months bug.
80+
- Reform-side parameters (legislated rate changes) should already be
81+
dated April 6 in their YAML files (most are); spot-check the
82+
exceptions during the migration.
83+
84+
## On-the-fly alternative (#1436)
85+
86+
The complementary issue [#1436](https://github.com/PolicyEngine/policyengine-uk/issues/1436)
87+
proposes the inverse: instead of moving every date to April 6, keep
88+
indices at January 1 and resolve the fiscal-year conversion lazily at
89+
query time.
90+
91+
That would let the conversion stop being a 26-year pre-computation step
92+
at startup (the `range(2015, 2041)` loop in
93+
`convert_to_fiscal_year_parameters`) and remove the year-range
94+
upper-bound altogether.
95+
96+
The two approaches are mutually exclusive: either we change the data to
97+
match the queries (#1437) or we change the resolver to translate
98+
queries to the data (#1436). Recommendation:
99+
100+
- Prefer **#1437 (April dates)** for correctness and ergonomics — the
101+
underlying policy change happens on April 6, so the YAML should say
102+
April 6.
103+
- Consider **#1436 (on-the-fly)** if a refactor of
104+
`convert_to_fiscal_year_parameters` becomes hot-path for any specific
105+
user — it's primarily a startup-cost optimisation.
106+
107+
## Sequencing
108+
109+
1. Land #1437 first: it removes the post-process workaround and makes
110+
the YAML files self-explanatory.
111+
2. Once #1437 is live, evaluate whether the lazy approach in #1436 is
112+
still worth doing — most of its benefit is already captured by step 4
113+
above ("remove `convert_to_fiscal_year_parameters`").
114+
115+
## References
116+
117+
- Issue [#1437](https://github.com/PolicyEngine/policyengine-uk/issues/1437) — April-date alignment.
118+
- Issue [#1436](https://github.com/PolicyEngine/policyengine-uk/issues/1436) — on-the-fly conversion exploration.
119+
- PR [#1435](https://github.com/PolicyEngine/policyengine-uk/pull/1435) — extended the fiscal-year-conversion range to 2040.
120+
- [`growthfactors.md`](./growthfactors.md) — the underlying OBR growth rates.

0 commit comments

Comments
 (0)