Build a bottom-up QC frame from per-zone interim CSVs.
Reads each interim/zone_<col>.csv written by download_zone_loads, outer-joins the actual-load columns, and appends two aggregate columns:
"Actual Load": sum of the per-zone actual columns with min_count=len(zones). A row where any zone’s value is missing yields NaN in the total — partial sums are never silently reported.
"Forecasted Load": sum of the per-zone <col>_forecast columns with the same min_count, only if every zone has a forecast column present in its CSV; otherwise the column is all-NaN. This mirrors the operational behaviour in the chapter-14 four-zone pipeline.
Fail-safe contract: a missing interim file raises FileNotFoundError naming the path rather than silently skipping the zone. No fallback, no substitution.
Files written by successful zones in a partial collect run are not rolled back. Call build_zone_qc_frame with the subset of succeeded zones to avoid triggering the FileNotFoundError guard for zones whose download failed.