Source Valmiera's Faktiskā temperature from Priekuļi as a temporary substitute
CI / backend (push) Successful in 1m7s
CI / frontend (push) Successful in 42s

LVĢMC's open-data station list has no station in or near Valmiera at all
(confirmed live 2026-08-23 in OpenDataStationService.scala), so that fixed
position has been silently blank. Priekuļi is the closest currently-
reporting station -- measured against the app's own calibrated map
coordinates (~56px away vs. the next-closest candidate, Rūjiena, at ~81px),
not a guess. Same pattern already used for Stende/Talsi and Zīlāni/Jēkabpils.

Implemented client-side in Faktiskā's fetch only: query Priekuļi's reading,
remap it back onto the "Valmiera" key before it reaches the rest of the
component. Valmiera's marker position and on-map label are untouched (both
are tied to Valmiera's real map location, not Priekuļi's) -- only the data
source for that one slot changes. This also fixes a second, previously
unexplained symptom for free: the weather-symbol picker only lists cities
with a value, so Valmiera never appeared there either; it now does.

Provisional pending direct confirmation from LVĢMC -- documented as such in
PRODUCT_WORKFLOWS.md, matching how Stende/Zīlāni are already flagged.

Verified: typecheck clean, production build succeeds, headless-browser
checks confirm Valmiera's field shows Priekuļi's real live value (14.8°C,
fresh timestamp, not flagged manual/stale) and now appears in the
weather-symbol exceptions list (13 cities, was 12).
This commit is contained in:
b0txec
2026-08-25 11:16:12 +03:00
parent e1ce1533bd
commit 07b16accb2
2 changed files with 26 additions and 6 deletions
+3 -4
View File
@@ -62,7 +62,7 @@ Fixed positions:
| 4 | Rīga | | 4 | Rīga |
| 5 | Jelgava | | 5 | Jelgava |
| 6 | Ainaži | | 6 | Ainaži |
| 7 | Valmiera | | 7 | Valmiera, sourced from Priekuļi (temporary substitute, see below) |
| 8 | Madona | | 8 | Madona |
| 9 | Alūksne | | 9 | Alūksne |
| 10 | Zīlāni (temporary substitute for Jēkabpils) | | 10 | Zīlāni (temporary substitute for Jēkabpils) |
@@ -83,7 +83,7 @@ Completed Faktiskā checkpoint:
- automatic badge-relative image placement using consistent 256×256 asset geometry; - automatic badge-relative image placement using consistent 256×256 asset geometry;
- guarded 3840×1440 export using the fixed wind production artwork. - guarded 3840×1440 export using the fixed wind production artwork.
Confirmed Monda Regular/Bold files are now bundled and used. The export dimensions are locked, but final pixel-level placement must still be compared against the production masters after the font change. As of 2026-08-23 the 12 other fixed positions load real station data; Valmiera has no matching real open-data station yet, so it currently still shows the last synthetic row generated before synthetic data generation was stopped (increasingly stale, since nothing refreshes it). Once the old synthetic rows are wiped from `weather` (a still-pending step — see `docs/UPDATE_ROADMAP.md` Phase 7), Valmiera will show no data until a real source is found. Confirmed Monda Regular/Bold files are now bundled and used. The export dimensions are locked, but final pixel-level placement must still be compared against the production masters after the font change. All 13 fixed positions now load real station data. Valmiera itself has no matching LVĢMC open-data station (confirmed live 2026-08-23); as of 2026-08-25 that position queries Priekuļi's reading instead, chosen as the closest currently-reporting station by measuring against the app's own calibrated map coordinates (~56px away vs. the next-closest candidate's ~81px). Valmiera's marker position and on-map label are unaffected — only the underlying data source for that slot changed. This is a provisional stand-in pending direct confirmation from LVĢMC.
## Ūdens ## Ūdens
@@ -151,7 +151,6 @@ Development limitation: representative forecast CSV fixtures are not currently i
## Decisions still required ## Decisions still required
- Whether weather conditions can eventually be populated automatically and which provider field is authoritative. - Whether weather conditions can eventually be populated automatically and which provider field is authoritative.
- Whether Stende and Zīlāni remain the production feeds after users test real provider data. - Whether Stende, Zīlāni, and now Priekuļi (for Valmiera) remain the production feeds after users test real provider data — Priekuļi is a provisional pick pending direct confirmation from LVĢMC.
- Confirm how Valmiera is named and sourced when authorized provider data is available.
- Apply the same native-resolution production comparison to additional broadcast products as they are finalized. - Apply the same native-resolution production comparison to additional broadcast products as they are finalized.
- Required authentication and role separation for analytical, production, and administrative workspaces. - Required authentication and role separation for analytical, production, and administrative workspaces.
+23 -2
View File
@@ -7,10 +7,26 @@ import type { FaktiskaTemplate } from "./faktiskaTemplates";
import "./mapGraphics.css"; import "./mapGraphics.css";
type LatestTemperature = { city: FaktiskaStation; observedAt: string; value: number | null }; type LatestTemperature = { city: FaktiskaStation; observedAt: string; value: number | null };
type RawLatestTemperature = { city: string; observedAt: string; value: number | null };
const emptyValues = (): Record<FaktiskaStation, string> => const emptyValues = (): Record<FaktiskaStation, string> =>
Object.fromEntries(faktiskaStations.map(city => [city, ""])) as Record<FaktiskaStation, string>; Object.fromEntries(faktiskaStations.map(city => [city, ""])) as Record<FaktiskaStation, string>;
// LVĢMC's open-data station list has no station in or near Valmiera at all
// (confirmed live 2026-08-23, see OpenDataStationService.scala). Priekuļi is
// the closest currently-reporting station (verified against the app's own
// calibrated map coordinates: ~56px away vs. the next-closest candidate's
// ~81px). Valmiera's marker position and on-map label stay exactly where
// they are -- only the queried data source for that one slot changes.
// Temporary, same pattern as Stende/Zīlāni substituting for Talsi/Jēkabpils
// (see PRODUCT_WORKFLOWS.md); pending confirmation directly from LVĢMC.
const stationSubstitutes: Partial<Record<FaktiskaStation, string>> = {
"Valmiera": "Priekuļi",
};
const substituteToStation = new Map(
Object.entries(stationSubstitutes).map(([station, substitute]) => [substitute, station as FaktiskaStation])
);
export function Faktiska() { export function Faktiska() {
const [values, setValues] = createSignal(emptyValues()); const [values, setValues] = createSignal(emptyValues());
const [overrides, setOverrides] = createSignal<Set<FaktiskaStation>>(new Set()); const [overrides, setOverrides] = createSignal<Set<FaktiskaStation>>(new Set());
@@ -21,9 +37,14 @@ export function Faktiska() {
: { width: 3840, height: 1440 }; : { width: 3840, height: 1440 };
const fetchLatest = async (): Promise<LatestTemperature[]> => { const fetchLatest = async (): Promise<LatestTemperature[]> => {
const response = await fetch(`${apiHost}/api/query/latest-temperatures/${faktiskaStations.join(",")}`); const queryCities = faktiskaStations.map(city => stationSubstitutes[city] ?? city);
const response = await fetch(`${apiHost}/api/query/latest-temperatures/${queryCities.join(",")}`);
if (!response.ok) throw new Error(`Latest observations failed (${response.status})`); if (!response.ok) throw new Error(`Latest observations failed (${response.status})`);
return response.json(); const observations: RawLatestTemperature[] = await response.json();
return observations.map(observation => ({
...observation,
city: substituteToStation.get(observation.city) ?? observation.city as FaktiskaStation,
}));
}; };
const [latest, { refetch }] = createResource(fetchLatest); const [latest, { refetch }] = createResource(fetchLatest);