# Derive GGG_renewable/INVDATASET_renewable/AAA_renewable names from one shared technology identity `GGG_renewable`, `INVDATASET_renewable`, and `AAA_renewable` are three different Balmorel set domains (per-vintage generators, investment-option groups, and region-technology pairs) that legitimately need different string spellings for the same underlying technology — but `build_GGG`, `build_INVDATASET`, and `build_AAA` in `additional_inc.py` each independently hardcoded their own f-string template for that same `(turbine/PV model, resource grade, onshore/offshore, region)` tuple, with no shared source of truth. This already caused one real bug (a `SP316-HHHH155` vs `SP316-HH155` spelling divergence), and is the direct cause of `INVDATA` linking an area computed under one spelling (`IE_VRE-ONS_SP335-HH100_RG1`) to an investment option built under another (`GNR_WT-SP335-HH100_ONS_RG1_Y-2020`) for what is meant to be the same technology. We decided to extract a single per-technology identity helper (`_template_for` plus the `_WIND_TEMPLATES`/`_SOLAR_TEMPLATES` tables) that each of the three builders calls to produce their (deliberately different) name strings, rather than accept the risk of three independently hand-maintained templates drifting apart again. We initially also planned to consolidate `build_INVDATA_renewable`'s `AAA_renewable`-based regex-substring bridge to `INVDATASET_renewable` onto `build_ALLOWEDINV`'s `GGG_renewable`-based matching, on the assumption that it duplicated the same linking task. Reading the actual implementation showed this assumption was wrong: `build_AAA`'s templates always nest the `INVDATASET_renewable` string directly inside the corresponding `AAA_renewable` string by construction (region + "_" + that string for wind, region + "_VRE-" + that string for solar), so `build_INVDATA_renewable`'s plain containment check is already exact and correct — it isn't duplicating `build_ALLOWEDINV`'s logic, it's solving a different problem (linking every real region to an investment option, vs. `build_ALLOWEDINV` finding which literal generator members belong to one representative region). We left this matching mechanism as-is and only removed the dead, always-no-op `.replace("ONSVRE_", "").replace("OFFSVRE_", "")` call and switched `str.contains` from `regex=True` to `regex=False`, since no metacharacter-sensitive matching was ever needed. ## Considered options - **Keep three independent templates, add a cross-consistency test asserting they stay in sync.** Rejected — this treats a structural duplication as a testing problem rather than removing the duplication itself; a test only catches drift after the fact instead of making it impossible. - **Rebuild `build_INVDATA_renewable` on `build_ALLOWEDINV`'s GGG-based matching.** Rejected after reading the actual code — the two functions solve genuinely different linking problems (see above), and forcing them onto one mechanism would only add complexity without fixing anything that was actually broken. ## Consequences - `GGG_renewable`, `INVDATASET_renewable`, and `AAA_renewable` keep their distinct spellings (`GNR_WT-...`, `VRE-ONS_...`, `_VRE-ONS_...`) — this is not a move toward one shared string across all three sets, only toward one shared source of truth for the parts of those strings that should never disagree.