Repository navigation
Releases: bejranonda/flood2026
Releases · bejranonda/flood2026
Release list
v0.34.0 — the impact tab's plan grid
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|compareandPOST /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 theevalthe page's CSP forbids (6bb91d8) and readwindow.map, which
browsers point at the#mapelement (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
- The daily range calibration no longer undoes itself (KI-287).
risks.band90_factorsmeasured 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
staron 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
/impactpassword 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 sincestar, 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.pyprints both counts. - Research calls to Open-Meteo are counted in code (D-108, KI-264):
floodwatch.research_quotaholds 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
- 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
- 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
- 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
- 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 ⓘ.
- yesterday's inflow, 2018–2024) is used only at the horizons where it beat persistence by ≥ 10 % in an operational
- 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
- 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
- Fix: OpenStreetMap tiles on
/impactshowed "Access blocked" (403). The page'sReferrer-Policy: same-originsent
no Referer, which OSM's tile policy requires; nowstrict-origin-when-cross-origin(the origin only, KI-300).
v0.28.0 — /impact: the whole app + a risk & impact tab
/impactis 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.
- 🏞️ เขื่อนทั่วประเทศ: every large dam (39, from HII's 50 daily records) as a card and a ◆ on the map, coloured by
- The public page is unchanged;
app.jsgets two hooks (window.FW_TABS, thefw:mapevent) and?v=119. - Every dam's rule curve and release history from HII, at most 10 requests an hour (
hii_dams_history); adamtable
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)
/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 andX-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.pyIMPACT row (length only).pyproject.tomlcaught up with__version__(was 0.20.5).