Port a0ec4bc Extract the shared graded-window tail in views.py from monorepo (drift reconciliation)

Claude-Session: https://claude.ai/code/session_01RdARHDJaYC1wSQRTYM6t3Z
This commit is contained in:
Emi Griffith 2026-07-22 12:08:13 -07:00
parent 8cec935b06
commit cc0b1e298f

View file

@ -143,6 +143,19 @@ def _attach_dry_streaks(graded: list[dict], *precip_frames) -> None:
g["dsr"] = dsr_map.get(g["date"])
def _graded_window(history, rows, precip_frames, doy) -> tuple[list[dict], dict]:
"""The shared tail of the /grade and /forecast payloads: grade `rows` against
history, attach dry streaks over `precip_frames`, order newest-first, and pair
the result with the target day-of-year's climatology summary. The window
*assembly* (recent+archive merge vs future-only filter) differs per builder and
stays there; only this post-processing is shared."""
graded = _grade_rows(history, rows)
_attach_dry_streaks(graded, *precip_frames)
graded.reverse() # newest-first for display (the chart reverses to L→R chronological)
climo = grading.climatology(history, doy)
return graded, climo
def build_grade(cell, target, days, history, recent, cache_meta, place, run=None, after=14) -> dict:
"""/grade payload: a window of days centered on the target — `days` of history
before it, the target itself, then up to `after` days after it plus the
@ -167,10 +180,8 @@ def build_grade(cell, target, days, history, recent, cache_meta, place, run=None
# old pandas concat when the two sources' columns differ (e.g. a reduced
# recent bundle); grading treats an absent column's value as None.
window = pl.concat([rwin, hwin], how="diagonal_relaxed").sort("date")
graded = _grade_rows(history, window)
_attach_dry_streaks(graded, history, recent)
graded.reverse() # newest first for display
climo = grading.climatology(history, target.timetuple().tm_yday)
graded, climo = _graded_window(history, window, (history, recent),
target.timetuple().tm_yday)
# Summarize what this run actually covered. A fresh history fetch pulls the
# full ~45-year archive (run_type "full"); a cache hit only fetched the
@ -274,10 +285,8 @@ def build_forecast(cell, days, history, fc, today, place, run=None) -> dict:
# Strictly future days (tomorrow onward), earliest→latest, capped at `days`.
future = fc.filter(pl.col("date") > today).sort("date").head(days)
with run.phase("grading"):
graded = _grade_rows(history, future)
_attach_dry_streaks(graded, history, fc)
graded.reverse() # furthest-out first, so the chart reverses to L→R chronological
climo = grading.climatology(history, today.timetuple().tm_yday)
graded, climo = _graded_window(history, future, (history, fc),
today.timetuple().tm_yday)
run.set(graded_days=len(graded), place_found=place is not None)
return {
"api_version": "v2",