Skip to content

City.sdst_v1_5 scenario matches baseline before the implementation year - #47

Merged
HughRunyan merged 2 commits into
mainfrom
fix-sdst-preimplement-composition
Aug 18, 2026
Merged

City.sdst_v1_5 scenario matches baseline before the implementation year#47
HughRunyan merged 2 commits into
mainfrom
fix-sdst-preimplement-composition

Conversation

@HughRunyan

@HughRunyan HughRunyan commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Purpose

City.sdst_v1_5 (the engine behind WasteMAP's /v1/site_emissions/sdst_v1_5)
models the baseline and the scenario as two independent landfills. Before the
scenario's implementation year nothing has changed, so the scenario landfill must
receive exactly the baseline waste — mass and composition — and emit identically
until then.
For blank/custom sites it did not: a scenario that changed the waste
composition had the new composition wrongly back-dated onto deposits from before
the implementation year, so baseline and scenario diverged before the change was
even implemented.

Bug

  • Component: SWEET_python/city_params.py, City.sdst_v1_5, the blank/custom-site branch (baseline_data=None).
  • Reproduction: run a single custom site (no rmi_id) with baseline waste fractions ≠ scenario waste fractions (e.g. the /sdst "Custom Location" flow, where the UI exposes independent baseline and scenario composition columns).
  • Expected: for every year before implement_year, scenario total emissions == baseline total emissions.
  • Actual: they differed (~6% on the scenario series in a representative dump→landfill case), because the scenario composition was applied to pre-implementation deposits.

Root cause

_generated_waste_masses() splices the scenario total mass at implement_year
but multiplies by the scenario composition for every year. The two
TRACE-reconciled branches (real sites) already correct this:

waste_masses_df_scenario.loc[:implement_year-1, :] = waste_masses_df_baseline.loc[:implement_year-1, :]

(city_params.py:8236 and :8271), and advanced_dst.run_advanced_dst (:161) and
advanced_dst_city.run_advanced_dst_city (:296) both force baseline pre-implement.
Only the else (blank/custom-site) branch omitted the splice.

Fix

Add the same pre-implement splice the sibling branches already use, before the
open/close window is applied. It copies the baseline generated waste (mass +
composition) into the scenario frame for every year < implement_year.

Blast radius

  • No-op whenever baseline and scenario composition match — so it only changes
    output for a composition-changing scenario on the custom-site path. Baseline
    output is never touched.
  • Reachable from the live /sdst UI (custom locations send no rmi_id → the
    custom-site branch; the composition inputs have separate baseline/scenario
    columns).
  • Breaks no existing test (the only active sdst_v1_5 tests use identical
    baseline/scenario composition).

Acceptance criteria

  • For a blank/custom site with differing baseline/scenario composition, scenario emissions == baseline emissions for every year < implement_year.
  • Composition-stable scenarios are byte-for-byte unchanged.
  • Baseline emissions are unchanged.
  • run_advanced_dst and City.sdst_v1_5 now produce identical output for equivalent single-site inputs including composition changes (verified by WasteMAP's compare_sdst_adst_parity.py).

Definition of Done

  • Acceptance criteria met
  • New regression test tests/test_sdst_v1_5_preimplement_composition.py (fails on the pre-fix engine, passes after)
  • Full SWEET_python suite passes (92 passed)
  • Changelog updated (changelog/2026-08.md)
  • Reviewed & merged

model-output-change (not breaking-change): changes output values only for a
composition-changing scenario on the custom-site path; nothing stops running.

Paired with WasteMAP RMI/WasteMAP#747 (same branch name), which adds the
endpoint-level regression test and the sdstadst parity harness. Merge together.

🤖 Generated with Claude Code

…ation year

City.sdst_v1_5 models the baseline and scenario as two independent landfills.
Before the scenario's implementation year nothing has been changed, so the
scenario landfill must receive exactly the baseline waste — mass and
composition — and emit identically until then.

The scenario waste-mass series already splices the total mass at implement_year,
but the scenario composition (fractions) was applied to every year. The two
TRACE-reconciled branches (real sites) correct this with
`waste_masses_df_scenario.loc[:implement_year-1, :] = waste_masses_df_baseline...`,
and the newer advanced_dst / advanced_dst_city engines force baseline
pre-implement too. Only the blank/custom-site branch (baseline_data=None, a
"Custom Location" in the /sdst UI) omitted the splice, so a scenario that changed
the waste composition wrongly back-dated the new composition onto deposits from
before the implementation year — the baseline and scenario diverged before the
change was even implemented (~6% on the scenario series in a representative case).

Add the same pre-implement splice the sibling branches already use. It is a
no-op whenever baseline and scenario composition match, so it only changes output
for a composition-changing scenario on the custom-site path.

model-output-change. Adds tests/test_sdst_v1_5_preimplement_composition.py
(fails on the pre-fix engine).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HughRunyan HughRunyan added bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs labels Aug 18, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a correctness bug in City.sdst_v1_5 for blank/custom sites (baseline_data=None) where scenario waste composition could be applied to pre-implementation-year deposits, causing baseline/scenario emissions to diverge before implement_year.

Changes:

  • Splice baseline generated waste masses (mass + composition) into the scenario series for all years < implement_year on the blank/custom-site branch (matching the existing TRACE-reconciled branches’ behavior).
  • Add a regression test covering composition-changing scenarios on the custom-site path to ensure pre-implement scenario emissions equal baseline emissions.
  • Update August 2026 changelog and changelog index entry to document the model-output change.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
SWEET_python/city_params.py Forces scenario generated waste masses to equal baseline before implement_year for blank/custom sites, preventing back-dated scenario composition.
tests/test_sdst_v1_5_preimplement_composition.py New regression test ensuring scenario == baseline emissions pre-implement when only composition differs on custom-site path.
changelog/README.md Updates the 2026-08 summary line to include this fix.
changelog/2026-08.md Documents the fix under “Fixed” with impact/behavior notes and PR link.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@HughRunyan
HughRunyan merged commit c00189e into main Aug 18, 2026
1 check passed
@HughRunyan
HughRunyan deleted the fix-sdst-preimplement-composition branch August 18, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants