From 539efa04f89ca356cd20ac65e5b811933c450c66 Mon Sep 17 00:00:00 2001 From: jacobvjk Date: Fri, 9 Oct 2026 10:28:17 +0200 Subject: [PATCH] fix(download): fall back to the full publisher name in the CSV The timeseries CSV read only publication.publisher.short. TransitionZero's four timeseries files carry a full name only, so their downloads had an empty publisher column and a source starting with "undefined" (found by the benchmark prep repo's review workbook, RMI/tpr_benchmark_data_preparation#18). publisherLabel now uses the short name, or the full name where there is none, for both columns, the same rule the review workbook uses, so the two match. Only the four TransitionZero CSVs change; every other file builds byte-identical. Co-Authored-By: Claude Opus 5.5 --- scripts/build-timeseries-files.ts | 10 +++++++--- scripts/timeseries-csv.test.ts | 23 ++++++++++++++++++++++- scripts/timeseries-csv.ts | 14 ++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/scripts/build-timeseries-files.ts b/scripts/build-timeseries-files.ts index 50deb4f8..016aac55 100644 --- a/scripts/build-timeseries-files.ts +++ b/scripts/build-timeseries-files.ts @@ -26,7 +26,11 @@ import { getTechnologyDefinition, UnknownTaxonomyError, } from "../src/utils/timeseriesTaxonomy.ts"; -import { jsonToCsv, sectorSegmentColumns } from "./timeseries-csv.ts"; +import { + jsonToCsv, + publisherLabel, + sectorSegmentColumns, +} from "./timeseries-csv.ts"; const STRICT = process.env.TS_INDEX_STRICT === "1"; const DEBUG = process.env.TS_INDEX_DEBUG === "1"; @@ -363,7 +367,7 @@ async function main() { .join(", "); const optionalBlock = optionalParts ? ` (${optionalParts})` : ""; // Final string - const source = `${pub.publisher.short}, ${pub.year}, ${pub.title.full}${optionalBlock}`; + const source = `${publisherLabel(pub.publisher)}, ${pub.year}, ${pub.title.full}${optionalBlock}`; // Look up definitions from centralized taxonomy. // These WILL throw if unknown, which is what we want in strict mode. @@ -378,7 +382,7 @@ async function main() { : undefined; const outRaw = { - publisher: parsed.publication.publisher.short, + publisher: publisherLabel(pub.publisher), publicationName: parsed.publication.title.full, publicationYear: parsed.publication.year, pathwayName: parsed.pathwayName, diff --git a/scripts/timeseries-csv.test.ts b/scripts/timeseries-csv.test.ts index 4dbc05d3..e50aa305 100644 --- a/scripts/timeseries-csv.test.ts +++ b/scripts/timeseries-csv.test.ts @@ -1,5 +1,10 @@ import { describe, it, expect } from "vitest"; -import { csvCell, jsonToCsv, sectorSegmentColumns } from "./timeseries-csv.ts"; +import { + csvCell, + jsonToCsv, + publisherLabel, + sectorSegmentColumns, +} from "./timeseries-csv.ts"; describe("sectorSegmentColumns", () => { it("lists the row's segments and their definitions in the same order", () => { @@ -47,3 +52,19 @@ describe("CSV writing", () => { expect(row).toBe('"Southeast Asia","A; B",1'); }); }); + +describe("publisherLabel", () => { + it("uses the short name when there is one", () => { + expect( + publisherLabel({ short: "IEA", full: "International Energy Agency" }), + ).toBe("IEA"); + }); + + it("falls back to the full name when there is no short one", () => { + // TransitionZero's files carry a full name only. + expect(publisherLabel({ full: "TransitionZero" })).toBe("TransitionZero"); + expect(publisherLabel({ short: " ", full: "TransitionZero" })).toBe( + "TransitionZero", + ); + }); +}); diff --git a/scripts/timeseries-csv.ts b/scripts/timeseries-csv.ts index fbe89249..b67ae592 100644 --- a/scripts/timeseries-csv.ts +++ b/scripts/timeseries-csv.ts @@ -40,6 +40,20 @@ export function sectorSegmentColumns( }; } +/** + * The publisher as the download names it: the short name, or the full name + * where the publication has none. Some publishers carry only a full name + * (TransitionZero), and reading `short` alone wrote an empty `publisher` and a + * `source` starting with "undefined". The prep repo's review workbook uses + * the same rule, so the two match. + */ +export function publisherLabel(publisher: { + short?: string | null; + full: string; +}): string { + return publisher.short?.trim() || publisher.full; +} + /** * One CSV cell. Strings are always quoted; a list is joined first, so it can * never spill its commas into the next columns.