CDST rework#25
Merged
Merged
Conversation
Food prevention removes food mass and shrinks the total, but the non-food
waste fractions were rescaled by old_nonfood_total / new_nonfood_total instead
of by the actual total-reduction factor. That over-inflated every non-food
share, so the diversion allocator believed more metal/glass/other/textiles
existed than the unchanged masses hold, and the downstream mass check raised a
spurious "Negative mass for <type>" -- erroring the city DST chart (e.g. Algiers
with composting + recycling + food prevention).
Rescale every fraction by (1 - food_waste_prevention * food_fraction), the same
factor waste_mass is reduced by, so the invariant
waste_fractions[w] * waste_mass == waste_masses[w]
holds for all waste types.
Adds tests/test_food_waste_prevention.py: a DB-free regression suite built from
country defaults (dst_baseline_blank) that exercises the real
implement_dst_changes_simple_v1_5 path. The tests fail on the pre-fix code and
pass on the fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| f"{t.capitalize()} can be at most {cond * 100:.1f}% given " | ||
| f"the other diversion selections for this city, but " | ||
| f"{three_targets[t] * 100:.1f}% was requested. Reduce " | ||
| f"{t} or the other diversion sliders.", |
Collaborator
There was a problem hiding this comment.
This is great! They'll know exactly which slider.
| @@ -0,0 +1,582 @@ | |||
| """ | |||
Collaborator
There was a problem hiding this comment.
This feels weird. If this is meant to replace something in the future, should it be in a future ticket and not here?
andre-scheinwald
requested changes
Jun 25, 2026
andre-scheinwald
left a comment
Collaborator
There was a problem hiding this comment.
There's a lot going on here. I do want to hear your thoughts on my comment in the prototype.py file. Even if it's "no".
andre-scheinwald
approved these changes
Jun 25, 2026
andre-scheinwald
left a comment
Collaborator
There was a problem hiding this comment.
Questions addressed!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Jira: WP-344 · Type: Bug fix + refactor · Labels:
bug,refactor,test· Pairs with WasteMAP PR (WP-344)What
The model-side half of WP-344 — the city DST chart's red "Something went wrong…" error. Replaces the hand-rolled diversion allocator in
City.mass_checker_mathwith an exact min-cost max-flow solver (SWEET_python/dst_allocation.py). The frontend half (showing the reason) is the companion WasteMAP PR.Root cause
Splitting the compost / anaerobic / recycling sliders across waste types is a transportation problem — each treatment accepts only some types, and no type can be diverted more than it exists. The old loop solved it with local moves: it redistributed an over-allocated type's excess proportional to each sibling's current share, ignoring remaining capacity, overshot small pools, then permanently banned the overshot type — painting itself into a corner and raising
CustomErroron inputs that are actually feasible. (It could also silently divert 0 tons, or raise a bareAssertionError→ HTTP 500.)The fix
CustomErrornaming the binding slider and its true max — e.g. "Compost can be at most 48.0% of this city's waste … but 95.0% was requested" — which the frontend surfaces (WP-344 companion).city_params.pynet −252 lines.Validation
58 unit tests (solver vs an independent exact-rational oracle) + 18 integration tests (real
mass_checker_math, incl. a 0–100% recycling sweep) + a ~400k-case fuzz harness (dst_allocation_prototype.py) → 0 mismatches, 0 invalid allocations, 0 crashes. Verified live on Korçë: the previously-erroring combo now renders; infeasible inputs return clean 400s.Follow-up fix — food-waste-prevention renormalization
A separate, pre-existing bug surfaced on dev (Algiers, composting + recycling + food prevention): the food-waste-prevention step rescaled non-food fractions by
old_nonfood/new_nonfood, over-inflating metal/glass/other/textiles so a non-food type went negative → spurious "Negative mass for <type>". Now rescaled by the true total-reduction factor(1 - food_waste_prevention × food_fraction), preservingwaste_fractions[w] × waste_mass == waste_masses[w]. Addstests/test_food_waste_prevention.py(DB-free, fails pre-fix / passes post-fix).Acceptance criteria (WP-344)
Definition of Done
tests/