Skip to content

Releases: bejranonda/flood2026

v0.34.0 — the impact tab's plan grid

Choose a tag to compare

@bejranonda bejranonda released this 06 Oct 22:55

v0.34.0 — 2026-10-06

  • The impact tab's release plans in one comparison grid (owner: "massive with text"; D-110). The ★, today's release,
    the engine's best plan per goal (goal icons), up to three of your own plans and a collapsed ladder of constant releases
    every 2 ล้าน ลบ.ม./วัน (0–24): each row a 7-day strip coloured by its worst gauge (over the bank / inside that day's
    tested error / room), storage on day 7, the lowest margin and km near the bank. A day header and a selected row colour
    the river; on a desktop the map follows the case. The plan sheet shows the river as 5 gauges × 7 days of margins. A goal
    names a best plan only where the plans differ on it ("ท่วมรวมน้อยสุด" had been awarded while no plan overtopped), and
    "ไม่มีจุดใดล้นหนัก" is now "ห่างตลิ่งมากสุด" — what it measures.
  • Plans beyond the river data are labelled, not hidden (KI-319; the owner's "label only"). The engine flagged every
    gauge-day whose flow passes its rating's highest (B.18 143, B.10 86, B.16 73 m³/s), but nothing used the flag, and the ★
    (21.5 for 7 days ≈ 249 m³/s) is outside from day 1. Now the day cells are hatched and "⚠ นอกช่วงข้อมูล" stands on the
    row, in the sheet (each gauge's flow against the rating's highest) and in the brief; an AI rewording may not drop it.
    The ★ rule is unchanged — an owner exception to GUIDELINES §6c-6, written into the rule.
  • ONWR's layers clipped to the case and off by default (KI-318). Whole zoom-10 tiles had put cells around Ratchaburi,
    30–56 km from the Phetchaburi River, on the case map (118 of 134 warning cells outside the case box). The collector now
    keeps only the cells in the box, older stored copies are clipped when served, and the layers sit unticked inside the
    app's one layer box as "สทนช. · ไม่ขึ้นกับแผนระบาย".
  • Flood coverage as river km + villages, until ONWR's maps by release level or a LiDAR DEM arrive: km of river near or
    over its bank per plan and day, and the villages + อำเภอ along those stretches (OpenStreetMap, built once into a file:
    97 of 105 river samples named a village; OpenStreetMap has no ตำบล boundaries there). No water is drawn on land.
  • AI on tap for officials (GLM; the rules write every number): an executive brief to copy (≤ 7 bullets; caveat lines
    never go to the AI; a reworded line is used only if it adds no number, no advice or alarm word and drops no caveat), two
    plans compared, and a plan typed in Thai (rules first, GLM only for what they cannot read; the answer is 7 numbers that
    only fill the boxes; values above 200 and per-second units are refused before the AI; the text is never logged).
    New login-only endpoints: GET /api/impact/case/{id}/explain?q=brief|compare and POST /api/impact/case/{id}/parse.
  • Validated live, with three fixes found only against production: the grid was wider than its panel (443 px in 428 on
    a desktop, 407 in 358 on a phone) and › scrolled the plan labels away — it now fits at every stage (7eac4fa); the tab
    check waited with a string predicate that needs the eval the page's CSP forbids (6bb91d8) and read window.map, which
    browsers point at the #map element (a4c9e27). No paragraph over 160 characters in the view, the sheets or the brief; a
    first-time engineer answers "what if we release 15 for 7 days?" in 3 taps and typing (UX_VALIDATION round 15).
  • From the reviews: a crafted plan answers 422, not 500; empty boxes are refused; an expired session clears the map and
    shows the login form; ONWR's and status strings are escaped; a villages file of the wrong shape gives no villages instead
    of breaking the hourly case build; the shared memo keeps at most 256 live entries (a typed plan's key no longer stays
    forever).
  • Docs: D-110; KI-318, KI-319; KNOWLEDGE §28 corrected and §30; GUIDELINES §6c-11 and the §6c-6 exception; APPROACH
    §19.27; MODELS §11e (with the §11 note, §11d's ONWR counts and a §12c row); SOURCES §2p and §2q; ARCHITECTURE;
    UX_VALIDATION round 15; OWNER_ACTIONS DISK; the pilot plan; PLAN; HANDOFF §3x.
  • Tests: 563 (102 new).

Docs between v0.33.1 and v0.34.0:

  • KNOWN_ISSUES IDs are unique again. KI-301…307 had been used twice since v0.29 — for the original modelling issues
    (2026-09-26) and for the impact tab's. The original ones are now KI-311…317 (placeholder tide constants, the draft
    hydraulic engine, managed operations, street-elevation benchmarks, as-issued archive, scale mismatch, point check); each
    heading names its old number, and every reference in the repository points to the right entry. References to KI-301…307
    in release notes from v0.29 on mean the impact tab's issues. KI-225's two write-ups are merged; the index lists every issue.
  • KNOWLEDGE §29 (what the 2026 record says about forecasting), GUIDELINES §6c-10, APPROACH §19.26, ARCHITECTURE's layout,
    README (the 50 % range as issued), the docs index, research/README and the owner tracker's verification line.

v0.33.1 — range calibration fixed; models measured as issued

Choose a tag to compare

@bejranonda bejranonda released this 06 Oct 12:31
  • The daily range calibration no longer undoes itself (KI-287). risks.band90_factors measured coverage on stored
    ranges that were already widened by the factor in force, while the new factor is applied to the raw ranges; once five
    days of widened forecasts filled the window, the ranges would have shrunk back. The factor is now found on the raw
    range. A day-by-day replay on 35,252 stored ranges keeps the served rule (next-day coverage of the 90 % range
    88.9/91.6/93.4 % at 24/48/72 h; a 93 % target overshoots) and leaves the 50 % range uncalibrated (a daily factor
    overshoots). What no width rule fixes: on 5 Oct the misses changed side within days (the water stopped falling while
    the models still expected a fall) — next, a short-term correction of the median (MODELS §5k).
  • The old and the new star on the same days (MODELS §5j): at the gauges every model generation forecast, the inputs
    v0.25.0 added are slightly better than the old ones at every horizon on the same days; the flat as-issued record there
    is the recession, not the inputs.
  • Owner items: Q3 handled by the owner; the /impact password is a test password by the owner's choice (a long
    passphrase before any partner data are loaded).
  • How the models improved, release by release (owner: "In models.MD we expect to see how good the models were developed
    here along many release and history"; MODELS §12).
    The tested gain of every model release, and an as-issued record:
    all 96,287 forecast runs stored since 2026-09-26, scored per model generation against what the water did. Nationwide,
    6–12 h forecasts beat "no change" by 11–21 % in every generation since star, 24 h by 3–7 %, 48–72 h about zero; the
    share of 24 h forecasts served by a real model rose from 38 % to 56 %. The 90 % ranges held 80–89 % and the 50 % ranges
    37–55 % — KI-287 is open again; on the 266 gauges every generation forecast, the latest model is level with "no change"
    in its first day and a half — on the same days the newer inputs are not the cause (MODELS §5j).
  • The rules follow the decisions (owner's review; D-109). The phase gates are quality reviews (D-012), AI is GLM for
    everything the app shows (the ✨ card only on a tap, the ticker in the worker), held-out data means later in time plus a
    disjoint sample plus the newest season (the 2011–2022 events are not in the archive), PLAN shows what is live, and the
    hand-written "Last updated" stamps are gone (git is the record).
  • A test for the 7-day planning models, and "made worse" means beyond chance (D-107). GUIDELINES §4.5; a unit is made
    worse only if its error rises by more than 3 % and a moving-block bootstrap says the rise is real
    (floodwatch.model_gate); research/q52_harness.py prints both counts.
  • Research calls to Open-Meteo are counted in code (D-108, KI-264): floodwatch.research_quota holds research to
    3,000 weighted calls a day, 1,000 an hour, 10 s apart, by the pricing page's weighting, in one ledger shared by every run;
    a test fails when a new research script names Open-Meteo without it. (Earlier today a hand-paced fetch used ≈ 4,800.)
  • Tests: 461 (16 new).

Full details: docs/MODELS.md §5j, §5k, §12 · KNOWN_ISSUES KI-287 · DECISIONS D-107–D-109.

v0.33.0 — a flood view per release plan

Choose a tag to compare

@bejranonda bejranonda released this 06 Oct 07:12
  • A flood view for each release plan (owner: "can we show flood area in the map for each … scenario?"; D-105). Pick
    a day in a plan's sheet and the map colours the Phetchaburi by its nearest gauge — red over the bank, orange inside that
    day's model error, blue with room — and says it is not a flooded area (D-019). ONWR's own layers sit beside it: today's
    area warning, the +1…+3-day forecast and the observed flooded area, dated and credited "ที่มา: สทนช." (refreshed every
    3 h; a dependency-free vector-tile reader).
  • Validated before use, and therefore not shown: satellite flood maps (Copernicus GFM blind on 39–58 % of the
    lowland, inconsistent between passes; GISTDA and GFM agree on 73 % of GISTDA's flood but 13 % of GFM's; no Google Flood
    Hub gauge there) and a 30 m DEM flood area (an experiment that cannot be scored: no gauge went over its bank in three
    years). Needed: ONWR/RID flood maps by release level and a higher-resolution DEM (OWNER_ACTIONS FLOODMAP, DEM).
  • Reservoir inflow, chosen on a whole wet season (D-106): the forecast archive reaches back to 2024, so models are now
    chosen on the 2025 wet season and scored on 2026; damped persistence + ECMWF rain on days 3–7 where persistence was
    served is better at every lead with no dam made worse — 32 dams on tested 7-day models (was 16).
  • The river on three wet seasons: HII's older years (2023-09 on) are kept as daily means; the gain method won both
    samples but lost the latest season at days 5–7, so the served river model is unchanged (MODELS §11c). The 72 h-only
    history idea for the public forecast fails on gauges made worse (MODELS §5i).
  • Fixes found while testing: logout now clears ONWR's layers and the plan legend; the 7-day tip names each day range's
    model and its tested gains.

v0.32.0 — seven days for the release plans

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 22:43
  • Seven days for the impact tab's release plans (owner: "plan reservoir discharge release for 7 days in advance
    together with future rain"; D-104).
    The river below Kaeng Krachan is judged per plan with a tested model — B.18's
    rating anchored on today's level, past the diversion today's level + a non-negative gain — and each point keeps a
    margin of that day's hindcast error (~10 cm on day 1 to ~40 cm on day 7). The old absolute chain was ~1 m off
    (KI-306). The plan's inflow uses the dam's tested 7-day path; the page, the ★ story and the test sheet say which models
    were used and how they tested.
  • The served reservoir inflow model now runs on the mean of four rain forecasts (best_match, ECMWF, GFS, ICON): better
    at every lead 1–7 in both samples and no dam made worse — the one change of 31 candidates and four selection rules that
    passed the two-sample gate (MODELS §9d). 7 days hold.
  • Fixes: the 7-day bands were mirrored (KI-309); overnight the KK case had no "now" (RID posts in batches, KI-307);
    hii_dams_history was recorded as failing although it worked (KI-308).
  • Research: E-7D-IN (35 dams, 31 candidates incl. an HBV-style bucket, analogs, log/direct ridges) and E-7D-DOWN (15 river
    candidates incl. rain, wetness, tide phase) — results in MODELS §9d and §11c, including what did not work.

v0.31.0 — the dams list reads like the station list

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 21:39
  • The dams list reads like the station list (owner: "too much info each card"; D-103). Dams grouped under headers
    with ⓘ (เหนือเส้นควบคุมบน · อยู่ระหว่างเส้นควบคุม · ไม่มีเส้นควบคุม); two-line rows — name and a storage-% badge, then
    "เข้า · ออก · อีก 7 วัน ↘ %"; units and date once in the header. A row or a ◆ on the map opens the dam's sheet (chips,
    a 7-day chart, the daily table folded, the other agency's record, map and case buttons), as a station does. Six visitor
    rounds, measured in a browser: row 112 → 62 px at 360–1366 px (never a third line), 154 → 53 characters, 5 → 12 dams
    on the first phone screen; arrows agree with the numbers beside them.
  • A 7-day trend for 36 of 38 dams: a tested inflow model where one exists (17), else a projection "if today's inflow
    and release hold" with the dam's own band, marked *; the national back-fill now fetches inflow.
  • One % for the whole list (KI-305): storage ÷ the agency's own normal storage — EGAT reports 0 % for 11 of 15 dams
    (and another definition for the rest), which showed as 0 % badges; reporting zeros are now missing or "ไม่มีข้อมูล" and
    never start an outlook (ปากมูล); EGAT's แม่งัด is listed with RID's แม่งัดสมบูรณ์ชล, records apart.
  • Honest "largest since": the claim needs enough complete years and names our records (KI-304). Chart axes follow
    the storage; far reference lines are named, not drawn.
  • Research: two years of training history rejected by the two-sample gate (MODELS §5i).

v0.30.0 — impact tab in the app's grammar; 7-day reservoir outlook

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 20:47
  • The impact tab's case view reads like the rest of the app (owner: "just click and see … not read so long"; D-102).
    Number chips (tap → the dam's sheet), one ★ card with three icon lines and one "why", one-line plan rows with
    "เหมาะกับ…" badges, ➕ กำหนดเอง in a sheet, ✨, a river strip in the app's colours (tap → the station's own sheet),
    and one ℹ️ collapsible whose buttons open the replay, the river table, the full comparison, the method and the data
    request. First screen 768 characters, no long paragraphs. The disabled what-if card is gone.
  • 7-day reservoir outlook on the dams list (Q58, D-102). For 17 dams a rain-driven inflow model (ERA5 catchment rain
    • yesterday's inflow, 2018–2024) is used only at the horizons where it beat persistence by ≥ 10 % in an operational
      test with archived rain forecasts (43 wet-season days, 17 Aug–28 Sep 2026); elsewhere today's inflow is held; storage by water balance
      with each dam's monthly loss term; bands from the tested residuals; recomputed every 6 h; the test result sits in the ⓘ.
  • Research (MODELS §5e–5h): discharge forecasts for RID gauges beat persistence on both samples (a new parameter;
    placement to be decided); upstream flow as an input and a dam's daily release as an input do not help; two years of
    training history under test.

v0.29.0 — 7-day release scenarios for Kaeng Krachan

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 19:03
  • 7-day release scenarios for Kaeng Krachan on the impact tab (owner request; D-101). Plans are found by search (676
    constant, ramped and front-loaded releases), each judged on seven effects (city margin, worst point, overtopping,
    dam safety, return under the rule curve, water kept, warning time); the ★ plan follows a printed rule — the fastest
    return toward the upper curve among plans whose every gauge stays farther from its bank than the downstream model's
    own error, within the maximum storage, and not leaving the reservoir higher; "เหมาะกับ…" marks the best plan per
    effect; a custom day-by-day plan; cards like the station list and the app's bottom sheet with a 7-day table and chart;
    ✨ retells the comparison. The reservoir side is a tested water balance; the river side is labelled 🔴 unvalidated.
  • Inflow held at today's value with a regime band — a rain-driven inflow model lost to persistence at every horizon
    in the honest test (KI-301); the catchment rain forecast is shown as context. Inflow history stored for the dam.
  • Fixed before release: two rule versions that would have recommended flooding (KI-302).

v0.28.1 — /impact map tiles fix

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 18:19
  • Fix: OpenStreetMap tiles on /impact showed "Access blocked" (403). The page's Referrer-Policy: same-origin sent
    no Referer, which OSM's tile policy requires; now strict-origin-when-cross-origin (the origin only, KI-300).

v0.28.0 — /impact: the whole app + a risk & impact tab

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 13:21
  • /impact is now the whole app plus a "💧 ผลกระทบ" tab (owner request; D-100). Engineers get the same map, list,
    แม่น้ำ, จับตา, point check and ✨ as the public page, and one more tab after login:
    • 🏞️ เขื่อนทั่วประเทศ: every large dam (39, from HII's 50 daily records) as a card and a ◆ on the map, coloured by
      its storage against the agencies' own rule curve (5 Oct: 13 above the upper curve — ป่าสักชลสิทธิ์ 109.8 %, หนองปลาไหล
      105 %, แก่งกระจาน 102 %), RID and EGAT side by side, and "the largest release since …" where it applies;
    • cases as chips — Kaeng Krachan (pilot): the board from v0.27.0, and the Phetchaburi River, the dam and the five
      gauges with travel times on the map.
  • The public page is unchanged; app.js gets two hooks (window.FW_TABS, the fw:map event) and ?v=119.
  • Every dam's rule curve and release history from HII, at most 10 requests an hour (hii_dams_history); a dam table
    with coordinates and storage bounds.
  • The impact assets carry a content hash in ?v= (Cloudflare had served a stale file under an unchanged ?v=, KI-298).

v0.27.0 — /impact for partner engineers (pilot Kaeng Krachan)

Choose a tag to compare

@bejranonda bejranonda released this 05 Oct 09:59
  • /impact: flood-impact analysis for partner engineers, pilot Kaeng Krachan (owner request; D-099). A separate page
    behind one shared password (value only in .env): the dam's daily RID record against HII's rule curve (5 Oct: 132 ล้าน
    ลบ.ม. above the upper curve) and its own history since 2018 (the release since 2 Oct is the largest since 2018); EGAT's
    differing record and "storage 102 % with no spill reported" asked as questions; the Phetchaburi River now (margin to each
    agency's own bank, flow, travel time with its correlation, when measured); the replay; the data request to ONWR/RID with
    CSV templates; the method, with a live check that B.18 carries the reported release (a year: r 0.93).
  • The what-if release table is built but gated. Replayed on the last 40 % of the year, no method beats keeping
    today's level at B.10 and B.16 (B.10 12.5 cm vs 12.0–39.4; B.16 13.6 vs 13.7–113.6), so the table stays off (HTTP 409)
    until one does by ≥ 10 %; the replay is rebuilt hourly (KI-297).
  • Security: constant-time password check, a signed HttpOnly/Secure/SameSite=Strict cookie bound to the password,
    a failed-login limit, noindex and robots, a strict CSP and X-Frame-Options: DENY (KI-293, KI-294).
  • Data: dam_daily (HII's national daily dam records, every 6 h) and the pilot dam's history since 2018 and rule
    curves; owner_status.py IMPACT row (length only). pyproject.toml caught up with __version__ (was 0.20.5).