Skip to content

fix(build-routing-solution): warning banner separate from build-failed error#116

Merged
sfc-gh-obielov merged 58 commits into
devfrom
feat/obielov-feat
May 19, 2026
Merged

fix(build-routing-solution): warning banner separate from build-failed error#116
sfc-gh-obielov merged 58 commits into
devfrom
feat/obielov-feat

Conversation

@sfc-gh-obielov
Copy link
Copy Markdown
Contributor

Summary

The MatrixBuilder UI was showing 'Build failed: RES7: 65,128 hexagons (4.2B pairs) — recommend XLARGE warehouse' for builds that had actually launched successfully. The server returns this message as a soft preflight warning (data.warning) advising the user to scale the warehouse for >625M-pair builds, but the client was rendering any data.warning in the same red 'Build failed:' banner as a real data.error.

This change:

  • Adds a separate buildWarning React state.
  • Adds a yellow .warning-banner style with a 'Heads up:' label.
  • startBuild now sets buildError only on data.error; data.warning goes to buildWarning.
  • Bumps ors_control_app image to v1.0.185 (image-versions.env + ors_control_app_service.yaml).

Test plan

  • Live diagnosis confirmed against MATRIX_BUILD_JOBS: California RES7 build was actually RUNNING despite the red banner.
  • Image v1.0.185 built (multi-stage Dockerfile.runtime) and pushed.
  • Service redeployed via SUSPEND -> ALTER FROM @stage -> RESUME.
  • SHOW ENDPOINTS confirms ingress URL is up: jlcmjncj-pm-fleet-test.snowflakecomputing.app
  • Trigger a >625M-pair matrix build in the UI and confirm the message renders in the new yellow 'Heads up:' banner instead of red 'Build failed:'.

sfc-gh-obielov and others added 30 commits May 14, 2026 09:59
…rquet

Adds simplified region polygons (~100m tolerance) and ISO 3166-1/-2 codes
to REGION_CATALOG so downstream consumers (function tester, synthetic data
generators, H3 matrix builder, control-app map) can replace bbox sampling
with real-shape ST_WITHIN filtering and stop hitting water / out-of-graph
points.

- New build_boundaries.py bakes all 460 catalog rows in one pass:
  * 222 Geofabrik rows resolve their .poly clip mask (the EXACT polygon
    used to cut each .osm.pbf extract -> 1:1 match with the ORS routing
    graph). ~32s wall-clock, cached locally for re-runs.
  * 238 BBBike rows use bbox-as-polygon (BBBike clips PBFs rectangularly,
    so bbox is the true boundary).
  * Coverage: 460/460 boundaries, mean 97 vertices/region post-simplify.

- New columns on REGION_CATALOG: LOOKUP_NAME, ISO_COUNTRY_A2,
  ISO_COUNTRY_A3, ISO_SUBDIVISION, UN_M49, BOUNDARY (GEOGRAPHY),
  BOUNDARY_SOURCE, BOUNDARY_VERTICES, BOUNDARY_AREA_KM2, BOUNDARY_BAKED_AT.
  All nullable -> server-side dynamic catalog refresh keeps working.

- LOAD_SEED_CATALOG COPY transform extended with TRY_TO_GEOGRAPHY of the
  WKB hex column.

- New REGION_REGISTRY_V view joins REGION_REGISTRY -> REGION_CATALOG via
  ORS_REGION_KEY and exposes BOUNDARY + ISO codes; falls back to bbox when
  no catalog row exists for a manually-added region.

- manual_iso_overrides.json provides an escape hatch for regions whose
  country / subdivision name doesn't auto-resolve via pycountry.

Parquet size: 6 KB -> 1.05 MB. ISO country coverage: 196/460 (covers all
single-country Geofabrik rows; BBBike cities + multi-country Geofabrik
aggregates remain null and can be filled via overrides as needed).
…, and helper UDFs

SQL-only changes that consume the BOUNDARY column shipped in the previous
commit (REGION_CATALOG seed parquet). No service rebuilds needed.

Matrix pipeline (05_matrix_pipeline.sql)
- BUILD_HEXAGONS: enumerate H3 cells inside REGION_CATALOG.BOUNDARY instead
  of the bbox rectangle. Drops water cells before any ORS Matrix call. Falls
  back to bbox polygon when no catalog row is found.
- BUILD_HEXAGONS_ROAD_AWARE: keep the Overture native bbox prefilter (it's a
  partition prune; removing it would scan the global table) but refine via
  ST_INTERSECTS against the actual region polygon, dropping foreign-country
  road segments that bleed across the bbox. Final hex centroid clip uses
  ST_WITHIN(centroid, BOUNDARY) instead of bbox BETWEEN. Multi-country bboxes
  (Israel-Palestine, Germany-Austria-Switzerland, Malaysia-Singapore-Brunei)
  see 25-30% null hex rate drop to <5% with this change.

Routing functions (02_routing_functions.sql)
- New REGION_FOR_POINT(lon, lat) UDF returns OBJECT with the smallest
  containing region (region_name, ISO codes, area). Enables auto-pick from
  user-pasted lat/lon, fact-table region tagging, cross-region drift
  detection, and LLM-coordinate validation.
- New POINT_IN_REGION(lon, lat, region) BOOLEAN UDF for binary checks.
- New ISOCHRONES_CLIPPED(method, lon, lat, range, region) returns isochrone
  polygons clipped to BOUNDARY via ST_INTERSECTION so retail catchment zones
  and address-density estimates don't claim foreign territory or water.
- New SAMPLE_ADDRESSES_FOR_REGION(region) returns MAP_CONFIG.sample_addresses
  filtered to those inside the region's actual boundary (catches curated
  addresses that drifted out of region).

Retail catchment seed (retail-catchment/references/seed-data.sql)
- RETAIL_POIS Overture POI loader: keep bbox prefilter, add polygon refine
  via subquery against REGION_CATALOG.BOUNDARY.
- REGIONAL_ADDRESSES loader: same pattern.

All new functions/queries fall through gracefully when REGION_CATALOG has no
boundary for a region (use bbox or skip the filter).
…er, and fallbacks

Frontend + server-side consumers of the BOUNDARY column shipped earlier.
Code-only - control-app Docker image rebuild is required for the frontend
changes to take effect at runtime, but no SQL/data changes are needed.

Frontend (control app)
- src/hooks/useRegion.ts: extend RegionInfo + RegionContextValue with
  BOUNDARY_GEOJSON, BOUNDARY_SOURCE, BOUNDARY_BAKED_AT, BOUNDARY_CENTROID_*,
  ISO_COUNTRY_*. Default map center now prefers boundary centroid (always
  on land) over CENTER_LAT/LON. Boundary cache-bust uses BOUNDARY_BAKED_AT.
- src/components/function-tester/samplePoints.ts: new randomPointInBoundary()
  rejection sampling using a JS point-in-polygon implementation (handles
  Polygon + MultiPolygon, holes). Threaded through sampleOne, sampleWith
  Separation, sampleDirections/Isochrones/Matrix/MatrixTabular/Optimization,
  and the entry point samplePoints(). Falls back to bbox after 50 attempts.
- src/components/FunctionTester.tsx: pass region.boundaryGeoJson to
  samplePoints().
- src/components/FleetDataStudio.tsx: keep hard-coded SF/Germany bbox as
  last-resort default with a comment pointing at REGION_CATALOG.BOUNDARY.

Server (control app)
- server/index.ts /api/regions: LEFT JOIN REGION_CATALOG via ORS_REGION_KEY
  -> LOOKUP_NAME and project ST_ASGEOJSON(BOUNDARY) + ISO codes + centroid.
- server/studio/engine.ts loadPOIs: keep bbox prefilter (partition prune),
  add ST_INTERSECTS(GEOMETRY, rc.BOUNDARY) refine. Falls through (TRUE) when
  catalog has no boundary for the region.
- server/studio/routes.ts: replace hard-coded SF bbox fallback with COALESCE
  cascade: REGION_REGISTRY -> REGION_CATALOG -> SF default.

Routing agent (deploy-agent.sql + agent-definitions.md)
- TOOL_DIRECTIONS: validate every LLM-extracted coord via REGION_FOR_POINT
  before calling DIRECTIONS. Returns detected_regions + out_of_region_count
  in the failure path so the agent can produce friendly errors like
  "Cambridge geocoded to Cambridge MA, did you mean Cambridge UK?" instead
  of a silent ORS RouteNotFound.
- TOOL_ISOCHRONE: same validation + uses ISOCHRONES_CLIPPED so the
  isochrone polygon is trimmed to the detected region's boundary.
- agent-definitions.md: short summary, point at deploy-agent.sql for canon.

Docs (available-functions.md)
- New "Region Boundary Helpers" section showing the new UDFs/UDTFs
  (REGION_FOR_POINT, POINT_IN_REGION, ISOCHRONES_CLIPPED) plus example
  patterns for filtering Overture POIs and H3 hexagon coverage by polygon.
- build_boundaries.py docstring: when to re-run + commit workflow
- server/index.ts parseBBBikePoly: inline comment pointing at the offline
  bake script for full polygon support; bbbike rows are bbox by design
Re-running 05_matrix_pipeline.sql against an account where the four filter
columns (ROAD_FILTER, HEXAGONS_BEFORE_FILTER, HEXAGONS_AFTER_FILTER,
FILTER_DURATION_SECONDS) already exist aborted with:

  SQL compilation error: ambiguous column name 'ROAD_FILTER'

at the standalone ALTER TABLE ... ADD COLUMN IF NOT EXISTS statement (line
24). This is a Snowflake bug: ADD COLUMN IF NOT EXISTS + DEFAULT clause does
not reliably no-op when the column exists; it raises a compile-time error.

Aborting line 24 also blocked every downstream proc creation (BUILD_HEXAGONS,
BUILD_HEXAGONS_ROAD_AWARE, BUILD_MATRIX_JOB_WRAPPER, etc.) which is why the
boundary-aware matrix changes from the previous PR could not be applied via
snow sql -f and required direct CREATE PROCEDURE calls.

Fix:
- Move the four columns into the canonical CREATE TABLE IF NOT EXISTS block
  so fresh installs never run the buggy ALTER path.
- Replace the four standalone ALTERs with EXCEPTION-wrapped anonymous blocks
  via EXECUTE IMMEDIATE, which swallow the compile error so legacy tables
  (created before the columns were canonical) still get backfilled, and
  re-runs against modern tables proceed silently.

Verified end-to-end: snow sql -f re-runs cleanly twice in a row. Confirmed
21 columns on MATRIX_BUILD_JOBS and both boundary-aware procs intact.
…+ LEFT JOIN

Snowflake error 002031 (Unsupported subquery type) was thrown because
the loadPOIs query used a correlated scalar subquery passing the outer
table's GEOMETRY column into ST_INTERSECTS(). Rewrite as a CTE that
pre-fetches the region boundary once, then LEFT JOIN + plain predicate.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…mpletion

The header region/vehicle-type switcher always showed "San Francisco" even
after Data Studio generated datasets for other regions (Germany, California),
because the generation flow only wrote to SYNTHETIC_DATASETS.UNIFIED.* and
never propagated the new region into REGION_REGISTRY or the per-skill CONFIG
tables.

Changes:
- jobs.ts: After a job COMPLETED, MERGE the new region into REGION_REGISTRY
  using REGION_CATALOG.BOUNDARY (Geofabrik polygon) when available, falling
  back to a telemetry-derived bbox polygon. Center/bbox derived via
  ST_CENTROID / ST_XMIN / ST_YMAX so maps pan to a real on-land centroid
  instead of (0, 0). Then call SET_ACTIVE_REGION and update all 6 CONFIG
  schemas so projection views immediately filter to the freshly generated
  (region, vehicleType).
- index.ts: Replace the synthetic-region 0,0 fallback in /api/regions with a
  catalog-aware query that resolves geometry from REGION_CATALOG (preferred)
  or telemetry bbox (fallback). Add BOUNDARY_GEOJSON to the synthetic path
  for parity with the main query.
- index.ts: On server boot, hydrate activeRegionOverride from
  REGION_REGISTRY.IS_DEFAULT so the user's last selection survives container
  restarts (previously it reset to null and fell back to the seeded default).
- index.ts: Wire setRegionActivatedHandler so Data Studio completion can
  refresh the in-memory override without waiting for the next /api/regions
  call.
- ors_control_app_service.yaml: Bump image to v1.0.181.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Move build_boundaries.py and manual_iso_overrides.json from
datasets/region_catalog/ to scripts/region_catalog/. Datasets folder
now only holds installer-consumed seed artifacts; helper/maintainer
scripts live under scripts/.

- Add scripts/README.md documenting the convention
- Update docstring path reference inside build_boundaries.py
- Update comment in ors_control_app/server/index.ts

PARQUET_PATH still resolves correctly (parents[2] = repo root).
No installer or runtime path is affected.
…tion

The header region/vehicle-type dropdowns each filtered options by the OTHER
axis using datasetPairs. When the only valid pair for both axes was the
current selection (e.g. CONFIG=(ebike, SanFrancisco) but FACT_TRIPS also has
(hgv, California) and (hgv, Germany)), the user was deadlocked: the region
dropdown showed only SanFrancisco, the vehicle dropdown showed only ebike,
and there was no path to the other 2 datasets.

Changes:
- RegionSwitcher.tsx: stop hard-filtering. Render every region in
  data.regions; compute validRegions only for visual styling. On click,
  auto-switch vehicleType to a valid one for the picked region first.
- VehicleTypeSwitcher.tsx: same pattern. Render every type in
  availableTypes; compute validTypes only for visual styling. On click,
  auto-switch region to a valid one for the picked type first.
- index.html: add CSS for .region-option--no-data (dimmed) and
  .region-tag.autoswitch (warm-color tag showing the auto-switch target).
- ors_control_app_service.yaml: bump image to v1.0.182.

UX: hovering a "no-data" option shows a tooltip "Switches vehicle type to
HGV" so the auto-switch is signaled before the click. Clicking still works
and lands on a valid (region, vehicleType) pair.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…erage

Closes the silent bbox-fallback gap that affected California (and any
other region missing from REGION_CATALOG). The catalog now contains:

- 555 Geofabrik regions (full tree: continents, countries, sub-regions,
  sub-sub-regions) - up from 222
- 4,401 Natural Earth admin-1 polygons (every US state, BR/IN/MX state,
  every admin-1 globally) - new SOURCE='natural-earth'
- 238 BBBike cities (unchanged)

Total: 5,194 rows, all with non-null BOUNDARY (was 460).

Critical insight: Geofabrik does NOT split US/Brazil/India into states,
so California, Texas, SaoPaulo, etc. previously fell through the
COALESCE in BUILD_HEXAGONS to bbox - leaking hexes across NV/OR/Pacific.
Natural Earth admin-1 supplement closes that gap.

BUILD_HEXAGONS and BUILD_HEXAGONS_ROAD_AWARE now log to
TRAVEL_MATRIX.MATRIX_BBOX_FALLBACK_WARNINGS whenever no catalog row
matches P_REGION, replacing the silent fallback.

REGION_CATALOG.PBF_URL relaxed to nullable (NE rows have no PBF).

New scripts in scripts/region_catalog/:
- expand_geofabrik_subregions.py - crawls live index-v1.json
- supplement_natural_earth.py - admin-1 from NE GeoJSON
- build_boundaries.py - now also derives bbox from polygon

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
When switching from Germany to California (or other regions), demo pages
sometimes appeared not to refresh. Investigation showed the API call did
reach the server (CONFIG was correctly updated), so the issue is either
React state propagation or a visual data-quality illusion (California's
synthetic dataset has SF coordinates).

Changes:
- App.tsx: Add `?debug=1` status pill in header showing live regionName,
  vehicleType, and center. Lets users (and us) see in real-time whether
  context state is actually changing.
- App.tsx: Add `key={regionName|vehicleType}` to demo components
  (FleetTaxis, FleetDelivery, DwellAnalysis, RouteDeviation, RouteOptimization,
  RetailCatchment). React fully remounts the component on region/vehicleType
  change - sidesteps any subtle context-update edge cases (stale closures,
  throttled re-renders, ref-equality memos).
- RegionSwitcher.tsx / VehicleTypeSwitcher.tsx: Add pulsing animation +
  "..." suffix while a switch is in flight, so users get immediate visual
  confirmation that the click was received.
- index.html: Add @Keyframes pulse-glow for the trigger button.
- FleetOverview.tsx / DeliveryDashboard.tsx: Stop auto-panning the map to
  the data centroid after a fetch. The boundary-based center from useRegion
  is authoritative; auto-panning to data masked region mismatches (e.g.
  California-tagged points landing in SF).
- ors_control_app_service.yaml: Bump image to v1.0.183.

Note: The boundary-based ST_WITHIN filter on projection views is held back
to a future iteration. The debug pill will tell us in 30s whether the
remount fix is sufficient (state propagation issue) or whether we also
need the boundary filter (data quality illusion).

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…mator

Polygon-aware cost estimator changes (server cost-estimate endpoint,
/api/matrix/regions, MatrixBuilder.tsx, types.ts) landed in 8769605.
This commit aligns the deployed image tag with the redeployed service
in Snowflake (built + pushed + suspend/alter/resume completed).

Estimator now reads REGION_CATALOG.BOUNDARY_AREA_KM2 and uses the
actual polygon (not the bbox rectangle) for hex/pair/credit estimates,
so previews match what BUILD_HEXAGONS will produce. California
estimate drops from ~580k km^2 (bbox) to ~410k km^2 (polygon).

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
… dropdowns

The two separate region and vehicle-type header dropdowns were confusing:
cross-filter deadlock locked users into the current combo, and region
names didn't map to what the user generated in Data Studio (e.g.
"California" showed SF-area data because the synthetic dataset was
generated with SF bounding box).

Replace both dropdowns with a single DatasetPicker that shows completed
Data Studio generation jobs (presets) directly. Each entry displays:
  - Preset name (e.g. "DE - HGV Logistics")
  - Region + ORS profile as secondary labels
  - Trip count
  - Active indicator

Clicking an entry atomically sets both region and vehicle type in all 6
CONFIG schemas + REGION_REGISTRY, then the key={dataKey} remount fires
to refresh all demo pages.

Changes:
- server/index.ts: New GET /api/datasets endpoint returning completed
  GENERATION_JOBS joined with REGION_REGISTRY for display names, with
  ORS profile -> vehicle type resolution and active flag.
- src/shared/DatasetPicker.tsx: New unified dropdown component.
- src/App.tsx: Replace <VehicleTypeSwitcher /> + <RegionSwitcher /> with
  <DatasetPicker /> in header.
- ors_control_app_service.yaml: Bump to v1.0.184.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…m errors in MatrixBuilder

Server returns {status:'launched', warning:'...'} when implied pairs exceed
625M (recommends LARGE/XLARGE warehouse). Previously the client treated
data.warning identically to data.error and showed it under a red
'Build failed:' banner, even though the build had successfully launched.

Add a separate buildWarning state and a yellow .warning-banner component
labeled 'Heads up:'. Only data.error now sets buildError.
Ships the warning vs error separation in MatrixBuilder. Image built and
pushed to OPENROUTESERVICE_APP image registry; service redeployed via
suspend -> spec update -> resume.
Data Studio's checkOrsReadiness() called ORS_STATUS() with no argument,
which always queries the default ors-service. When the user picks a region
whose dedicated ORS service is running (e.g. ors-service-california) but
the default service is suspended, generation aborted with "ORS service is
not running" before even attempting to start.

Fix: pass the region from GenerationConfig and use the 1-arg
ORS_STATUS('<region>') overload so the gateway routes the status check to
the correct per-region service. Mirrors the same fix already applied in
engine.ts and jobs.ts:waitForOrsReady (data-studio-region-arg-fix-2026-05-13).

Bump image to v1.0.185.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…_PROFILE

GET /api/datasets was deriving vehicleType from ORS_PROFILE_TO_VEHICLE_TYPE
map (driving-car -> car), ignoring the job's stored CONFIG:vehicleType.
This caused the DatasetPicker to write VEHICLE_TYPE='car' to CONFIG tables
when the actual FACT_TRIPS data had VEHICLE_TYPE='hgv', resulting in 0 trips
shown in Fleet Taxis for California.

Now reads CONFIG:vehicleType::STRING from GENERATION_JOBS first, falling
back to ORS_PROFILE derivation for legacy jobs without the field.

Deployed as ors_control_app:v1.0.186.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…STRY

Centralizes bbox resolution in routes.ts:resolveRegionBbox so any registered
region (California, France, Spain, ...) gets the correct full boundary,
regardless of preset_id vs rawConfig path or what the client sends. Removes
hardcoded Germany/SF fallbacks in FleetDataStudio.tsx and the SF default in
routes.ts. Throws a clear error if region isn't in REGION_REGISTRY/CATALOG.

Previously, picking a built-in template (HGV Logistics, City Taxis, etc.)
with a non-Germany region sent rawConfig with a hardcoded SF bbox, causing
data to be generated within SF only. California is the most visible victim
but every region except Germany was affected.

Deployed as ors_control_app:v1.0.187.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Route Deviation pages were stuck showing the original SF e-bike data
because the 3 ETL output tables (TRIP_DEVIATION_ANALYSIS,
DRIVER_DEVIATION_SUMMARY, DAILY_DEVIATION_TRENDS) were created as
static base tables. Switching CONFIG region/vehicle_type had no effect
because the static tables never refreshed.

Convert all 3 to Dynamic Tables (lag=5min, refresh_mode=AUTO,
warehouse=ROUTING_ANALYTICS) matching the dwell-analysis pattern, so
they auto-refresh whenever CONFIG or upstream FACT_TRIPS change.
Update SKILL.md, references/seed-data.sql, and references/sql-pipeline.md.

In-place migration on the live system: dropped the 3 stale tables
and recreated as DTs. Verified showing 665 California rows under the
active CONFIG (hgv/California).

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Add three thin views (VW_IDLE_TRAILERS, VW_LANE_DEMAND,
VW_TRAILER_COST_OF_IDLENESS) reusing dwell-analysis DTs to
detect non-moving trailers, score cost of idleness, and surface
demand terminals for repositioning. Brand-neutral framing applies
to long-haul carriers, container lines, leasing operators,
cold-chain 3PLs, and rail intermodal.
…e and VROOM repositioning

New /asset-velocity page renders idle-trailer KPIs, deck.gl map,
sortable Action Alerts table, and modal AI rationale via
SNOWFLAKE.CORTEX.COMPLETE (claude-sonnet-4-5). Optimize Repositioning
button calls OPENROUTESERVICE_APP.CORE.OPTIMIZATION (driving-hgv
profile) to compute reposition routes from idle trailers to top
demand terminals. Page guards on missing dwell-analysis DT and
renders an empty-state pointer if not deployed.
…a engine

Adds an optional ghost_trailer config block (default 10% of HGV
fleet, 5-7 day window starting in the first 2 days of generation).
Tagged vehicles skip trip + per-day idle emission inside the window
and emit a single multi-day IDLE dwell at their home POI with
sparse 5-15 min ping cadence. The dwell sessionizer rolls these
into one continuous session, populating VW_IDLE_TRAILERS with
realistic >7d idle entries so the Asset Velocity demo can run at
the production 168h threshold.
sfc-gh-obielov and others added 28 commits May 16, 2026 15:34
New demo skill that solves trailer-to-load assignment as a fleet-wide
VRP via OPENROUTESERVICE_APP.CORE.OPTIMIZATION. Internal-first priority
encoded as VROOM priority, ADR via skills, direction-to-home via vehicle
end. Includes deterministic Python codegen for demo data, AISQL notebook,
schema contract, productisation notes, and Cortex Agent YAML.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Adds the Backload Matching React component (live data from
FLEET_INTELLIGENCE.BACKLOAD_MATCHING.* views, OPTIMIZATION call,
DIRECTIONS for empty legs with cache, Cortex rationale card,
PROPOSAL_DECISIONS write-back, inline Decisions Audit panel).
Sidebar entry under Solution Accelerators next to Asset Velocity.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…ter matrix build

The auto-resize block in BUILD_MATRIX_JOB_WRAPPER bumped ROUTING_ANALYTICS to
LARGE/X-LARGE for hex_count > 5000/25000 and was supposed to restore the
captured original size after BUILD_WORK_QUEUE. The captured-size block silently
swallowed errors by setting original_wh_size := NULL, and both restore paths
were guarded by IF (original_wh_size IS NOT NULL), so any failure inside the
capture block (or a stale captured size from a previous un-restored run)
guaranteed the restore would be skipped and the warehouse stranded at the
bumped size. Confirmed in account wgb26798 on 2026-05-15: warehouse stuck at
X-Large for ~24h after a matrix build.

Changes:
- Default original_wh_size to 'SMALL' (steady-state) instead of NULL so the
  restore is always a no-op-or-shrink, never a no-op leaving the warehouse bumped.
- Reject LARGE/X-LARGE/2X-LARGE/etc. as a captured "original" (treat as drift
  from a prior un-restored run and replace with the steady-state default).
- Replace null-guard restore with an explicit did_bump BOOLEAN flag so we only
  restore when we actually changed the size, but original_wh_size always has
  a sensible value.
…onciler

Idempotent safety net for ROUTING_ANALYTICS size drift. Mirrors the existing
RECONCILE_AUTO_SUSPEND pattern: if no matrix job is currently PENDING/RUNNING,
shrinks ROUTING_ANALYTICS back to the SMALL steady-state. Wired into
SUSPEND_ALL_SERVICES so it self-heals on every suspend cycle.

Catches the case where a matrix build bumped the warehouse to LARGE/X-LARGE
and the in-procedure restore was skipped (e.g. session killed, unhandled
exception, parallel matrix jobs racing).

Tested in account wgb26798: returns 'already at steady-state: Small' when at
SMALL, and 'reconciled: Large -> SMALL' when at LARGE with no active jobs.
Documents the resize of ROUTING_ANALYTICS from X-Large to SMALL, the
hardening of the auto-resize block in 05_matrix_pipeline.sql, and the new
RECONCILE_WAREHOUSE_SIZE safety reconciler in 04_service_lifecycle.sql.
…ATION call

OPTIMIZATION returns 0 rows for Germany coords (server-side VROOM routing
issue). Pivoted seed to California cities (OPERATING_COUNTRY='US') where
OPTIMIZATION is verified working.

Changes:
- gen_demo_data.py: US cities (LA, SF, San Diego, etc.) + West-Coast home depots
- BackloadMatching.tsx: import useRegion(); sync viewState to preset center;
  pass regionName as 2nd arg to OPTIMIZATION + 4th to DIRECTIONS;
  country filter on VW_TRAILERS; drop time_windows; add Solver Log
- productisation.md: document Germany OPTIMIZATION known issue

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
The view filtered STATUS LIKE 'DWELL%', silently dropping the multi-day
ghost-trailer IDLE sessions emitted by the data engine. As a result the
Asset Velocity page showed zero ghost trailers for California (and any
region with realistic 5-7d idle synthetic data); only sub-1h DWELL_*
sessions made it through, all below the page's default 1h threshold.

- VW_IDLE_TRAILERS: WHERE (STATUS LIKE 'DWELL%' OR STATUS = 'IDLE')
- AssetVelocity.tsx: default idle threshold 1h -> 72h (matches WATCH band)
- Helper subtitle: explain severity bands instead of generic note
- Image bumped to v1.0.199, deployed
Replaces the static seed file with a CONFIG-driven projection view pattern
matching food-delivery / dwell-analysis / route-deviation. Backload data
follows whichever preset the user selects in DatasetPicker.

Data Studio changes:
- New SYNTHETIC_DATASETS.UNIFIED.FACT_FREIGHT_OFFERS table
- engine.ts generateFreightOffers + sourceLabelsForRegion (DAT/Truckstop in
  US, Timocom/WTransnet in EU)
- jobs.ts insertFactFreightOffers, ensureTables DDL, truncate list
- jobs.ts FLEET_CONFIG_SCHEMAS includes BACKLOAD_MATCHING
- server/index.ts runtime CONFIG_SCHEMAS includes BACKLOAD_MATCHING

Backload-matching skill:
- references/bootstrap.sql: CONFIG + 3 views (VW_TRAILERS, VW_INTERNAL_VOLUMES,
  VW_EXTERNAL_OFFERS) filtered by CONFIG row
- references/backfill-freight-offers.sql: one-time backfill for existing presets
- BackloadMatching.tsx: drop hardcoded OPERATING_COUNTRY filter (CONFIG handles it)
- Archived load-demo-data.sql and gen_demo_data.py

Verified: California-HGV preset = 27 trailers / 120 internal / 300 external;
switching to SanFrancisco-ebike yields 50 trailers (per-preset views work).
Deployed v1.0.199.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Removed orphaned objects that no longer match the live (CONFIG-driven
projection-view) architecture:
- EXTERNAL_OFFERS_ENRICHED Dynamic Table (source table no longer exists)
- SP_SOLVE_REGION_BACKLOAD stored procedure (React builds VRP inline)
- TASK_BACKLOAD_RESCAN scheduled task (called the dropped SP)
- BACKLOAD_PLAN_HISTORY table (write target of the dead task)

Doc updates:
- SKILL.md Cleanup section: drop TRAILERS/INTERNAL_VOLUMES/EXTERNAL_OFFERS
  refs, list only the live views + CONFIG + PROPOSAL_DECISIONS
- productisation.md section 3: reposition TASK_BACKLOAD_RESCAN as a future
  enhancement instead of a shipped fact
- agent YAML: replace dropped solve_backload tool with view-reading tools
  (list_idle_trailers, list_internal_volumes, list_offers, savings_report,
  explain_decision)

No service redeploy required.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…matching

The build-routing-solution seed loader populates DIM_POIS / DIM_FLEET /
FACT_TRIPS but did not produce FACT_FREIGHT_OFFERS. New customers running
load-seed-data.sql got an empty VW_EXTERNAL_OFFERS in backload-matching.

Splice a deterministic 300-offers-per-region INSERT after the timestamp
offset section (which runs after DIM_POIS is fully loaded) and before
LOAD_SEED_MATRIX. Same pattern as the standalone backfill-freight-offers.sql
already verified working. Idempotent via WHERE region NOT IN (existing) so
re-running the loader is safe.

Smoke-tested on fleet_test_evals: 0 rows inserted (both regions already
populated). New regions added by Data Studio jobs after v1.0.199 populate
this table natively.

SKILL.md verification block now lists FREIGHT_OFFERS=300 in the expected
counts.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
The full-width container has overflow:hidden, which clipped the Action
Alerts table below the 420px map. Asset Velocity uses a normal flow
layout (like Route Optimizer, which is not full-width and works fine),
so it should use the standard scrollable .app-main container.

Image bumped to v1.0.200, deployed.
- Add selectedVehicleId state, reset on region change
- focusTrailer callback: setViewState (zoom 14) + scrollIntoView on map
- Row onClick wired with cursor:pointer + light blue highlight
- AI Rationale button uses stopPropagation
- Selected trailer pops on map via wider line stroke + accent color

Image v1.0.201, deployed.
VRP hardcoded profile=driving-hgv, but California region only provisioned
the driving-car graph. ORS returned rows with empty GEOJSON, so the page
silently rendered no routes.

- Read ORS_PROFILE from GENERATION_JOBS for the active region
- Use that profile in vrpVehicles
- Surface "profile: ..." label next to Optimize Repositioning button
- Show a warning info-box when solver returns no routable paths

Image v1.0.202 deployed.
The Backload Matching page was returning empty optimization results when
the underlying ORS routing services were auto-suspended after 4h of inactivity.

Adds:
- Required-services status pill (N/M ready/warming/suspended) polling
  SHOW SERVICES every 30s with a green/amber/red dot.
- "Wake up ORS" button that resumes any suspended service in parallel
  and polls until all are RUNNING with target instances (90s budget).
- Auto-warm in solve(): if any required service is not RUNNING when the
  user clicks Solve, the wake-up routine runs first so a user never gets
  a silent-empty result.

Required services tracked: VROOM_SERVICE, ROUTING_GATEWAY_SERVICE,
ORS_SERVICE, and ORS_SERVICE_<active region>. The denominator uses the
actual number of services found, so presets that use the default
ORS_SERVICE (e.g. SanFrancisco) display correctly as 3/3 rather than
showing a missing region-specific service as red.

Service yaml bumped to v1.0.203 and redeployed.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…ofile, cap dot pixel size

- Sync FLEET_INTELLIGENCE.BACKLOAD_MATCHING.CONFIG.REGION from useRegion() on
  mount/region change so VW_TRAILERS/VW_INTERNAL_VOLUMES/VW_EXTERNAL_OFFERS
  return data for the active preset (was stuck on SanFrancisco even when app
  showed California).
- Read VEHICLE_TYPE from CONFIG and map ebike->cycling-electric, hgv->driving-hgv,
  car->driving-car for both VRP profile and empty-leg DIRECTIONS calls (was
  hardcoded 'driving-hgv').
- Add radiusMaxPixels caps to all three ScatterplotLayer calls so dots no
  longer become huge meter-radii circles when zoomed in.
- Surface red banner when OPTIMIZATION returns 0 rows with diagnostic hints
  (services suspended, region/profile mismatch).
- Bump ors_control_app to v1.0.203.
…, dashes, data quality

- Query REGION_PROVISION_JOBS.PROFILES at refetch time to use the actually
  provisioned ORS profile (e.g. driving-car for California) instead of
  naively mapping from VEHICLE_TYPE (which would send driving-hgv to a
  region that only has driving-car graphs).
- Fix audit query: CONFIG has flat columns (VEHICLE_TYPE, REGION), not
  KEY/VALUE rows. Replace broken subquery with EUR_PER_EMPTY_KM constant.
- Remove dead CONFIG reads (INTERNAL_PRIORITY, EXTERNAL_PRIORITY, etc.)
  that silently failed since those columns don't exist.
- Add PathStyleExtension import for dashed empty-leg lines (getDashArray
  was silently ignored without it).
- Use r.DURATION instead of r.COST (OPTIMIZATION returns DURATION, not COST).
- Remove ORS_SERVICE from requiredServices (only region-specific service needed).
- Remove 130 lines of dead German mock data (MOCK_TRAILERS, DE_CITIES, etc).
- Recreate VW_INTERNAL_VOLUMES with diversified PRODUCT (5 categories) and
  some HAZMAT=true rows.
- Recreate VW_TRAILERS: strip POI quote chars, vary CURRENT_LOAD (6 cargo
  types), HAZMAT_CERT (20% true), MAX_PAYLOAD_KG (18-24k range).
- Bump ors_control_app to v1.0.204.
…IMIZATION

Generic per-region VROOM architecture so OPTIMIZATION works for any provisioned
region (California, Germany, USA, future) without hardcoding or per-region code.

VROOM image (vroom-docker:v1.0.3):
- config.yml templated with __ORS_HOST__ placeholder for all 8 ORS profiles
- New docker-entrypoint-region.sh runs sed substitution from $ORS_HOST env var
  at container startup (defaults to 'ors-service' if unset for backward compat)
- Same image serves any region; ORS_HOST env per-service points it at
  ors-service-<region>.

SQL (03_region_management.sql):
- BUILD_VROOM_SERVICE_SPEC(P_REGION) function generates the per-region spec.
- create_region_vroom_service(P_REGION) procedure mirrors create_region_ors_service:
  CREATE SERVICE VROOM_SERVICE_<REGION> in ORS_POOL_<REGION> with ORS_HOST env.
- drop_region_vroom(P_REGION) for symmetric teardown; called by drop_region_ors.
- Wired into PROVISION_REGION_WRAPPER (post-service-ready), REBUILD_REGION_GRAPHS,
  and the rescue-task path so any region provisioning auto-deploys VROOM.

Gateway (routing_reverse_proxy:v1.0.5):
- resolve_vroom_host(region) -> vroom-service-<normalized-region>.
- get_vroom_response(payload, vroom_host=None) routes per-region; falls back to
  global VROOM_HOST on connection error.
- _handle_optimization_tabular and post_optimization pass vroom_host through.
- _remap_indices keeps location/start/end alongside *_index keys so VROOM's
  internal ORS geometry call has coords (the per-region ORS supports them).

App (ors_control_app:v1.0.205):
- BackloadMatching.tsx requiredServices now depends on VROOM_SERVICE_<REGION>
  + ORS_SERVICE_<REGION> + ROUTING_GATEWAY_SERVICE. The base global services
  are no longer required for solving.

Bootstrap: VROOM_SERVICE_CALIFORNIA created and verified end-to-end with
statewide OPTIMIZATION (San Diego -> LA -> SF, 4341-point GEOJSON, 32481s).

AGENTS.md: documented per-region VROOM lifecycle alongside ORS.
…puted matrices

VROOM's vroom-express config had limit:'1mb' which rejected pre-computed
distance matrices >1MB. At app scale (27 vehicles + 420 jobs in California
Backload Matching) the matrix JSON is ~2.4MB, causing Python requests to
surface a ConnectionError, gateway returning connection_failed, and the
OPTIMIZATION SQL function flattening 0 rows.

Bumping the limit to 50mb safely covers any realistic VRP (VROOM hard
caps at 1000 locations -> ~12MB matrix). No memory or runtime impact.

Bumped to vroom-docker:v1.0.4 and updated BUILD_VROOM_SERVICE_SPEC.
VROOM_SERVICE_CALIFORNIA recreated; verified 27 rows for the full
app-scale payload.
…i-region path)

After the per-region VROOM architecture, every OPTIMIZATION caller must pass
the region as the second argument so the gateway routes to VROOM_SERVICE_<REGION>
+ ORS_SERVICE_<REGION>. Without it, requests fall through to the legacy global
VROOM with the SF-only base ORS graph and fail for any non-SF data.

Updated callers:
- RouteOptimization.tsx: pass regionName from useRegion()
- AssetVelocity.tsx: pass regionName from useRegion()
- routing-agent TOOL_ROUTE_OPTIMIZATION: add REGION VARCHAR DEFAULT 'California'
  parameter, switch to OBJECT_CONSTRUCT(jobs,vehicles)::VARIANT form, expose
  region in the agent tool descriptor (input_schema). Re-deployed in account.
- backload-matching-aisql.ipynb: append 'Germany' arg, fix COST -> DURATION.
- route-optimization routing_functions_aisql.ipynb: replace NULL region with
  'California' in both _OPTIMIZATION_TABULAR_RAW cells.

Updated docs:
- AGENTS.md: explicit warning that region is required + body-limit note.
- backload-matching SKILL.md, optimization-vrp-mapping.md: 2-arg signature.
- build-routing-solution available-functions.md: IMPORTANT note on region arg.

ors_control_app bumped to v1.0.206 and redeployed.
TOOL_ROUTE_OPTIMIZATION verified end-to-end with California test
(SF + Oakland + San Jose, depot Berkeley) -> SUCCESS with 2 routes.
Add a hover tooltip and a yellow info-box that explain the precondition for
enabling the green Optimize Routes button:
- if no centerCoords: 'Search a location first (enter address and click Go)'
- if places=0 after geocode: 'No places found for region <region>...'

Root cause for the user's report: PLACES, LOOKUP, and JOB_TEMPLATE tables
are only seeded for REGION='SanFrancisco'. When the app region picker is
California (or anywhere else), loadPlaces() returns 0 rows and the button
stays disabled with no hint why.

Bumped ors_control_app to v1.0.207 and redeployed.
…n-aware suspended warning

Move "Wake up ORS" out of Backload Matching into a shared OrsWakeButton component
mounted in the app header next to DatasetPicker. Shows green dot when all services
are running, red pill + Resume button when region's ORS is suspended, amber spinner
while warming. DatasetPicker dispatches ors-region-switched event for immediate re-check.
Auto-warm logic inside BackloadMatching.solve() preserved for race-condition safety.

Deployed as v1.0.208.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…y active region

The Route Optimization page already used useRegion() dynamically, but its
underlying tables only had data for SanFrancisco. This adds a stored procedure
SEED_ROUTE_OPTIMIZATION_REGION that pulls POI data from Overture Maps for any
region's bbox, and wires it into the server's region-switch endpoint so data is
seeded automatically when the user picks a new preset.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
Two latent bugs were preventing the universal ORS status indicator from working:

1. RESULT_SCAN(LAST_QUERY_ID()) doesn't work across /api/query calls — the server
   uses Snowflake's stateless REST /api/v2/statements API, so each call gets a new
   session. The two-call SHOW SERVICES + RESULT_SCAN pattern returned 0 rows,
   leaving svcStatus.length === 0 forever (grey "ORS checking..." stuck).
   Fix: single SHOW SERVICES IN DATABASE + JS-side filter.

2. /api/query rejects ALTER (allow-list is SELECT/SHOW/DESC/CALL/WITH), so the
   Resume button would 403. Fix: use existing POST /api/services/:name/resume
   endpoint which calls the RESUME_SERVICE proc.

Same two fixes applied to BackloadMatching's inline auto-warm probe.
Added "ORS not provisioned for <region>" empty-state for regions where the
ORS_SERVICE_<REGION> doesn't exist yet.

Deployed as v1.0.209.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
… auto-seed

Deploys the auto-seed server hook (POST /api/regions/active calls
SEED_ROUTE_OPTIMIZATION_REGION) and the updated RouteOptimization.tsx
warning message.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…nt works for non-SF regions

Preview Catchment was failing silently for any region other than SanFrancisco
because the ISOCHRONES call passed NULL for the region arg, routing through
the legacy global ORS service (SF-only graph) which is suspended on most
deployments. The function returned an error and a NULL GEOJSON, but the
React handler had no error path so the user saw nothing.

Fix passes the active region from useRegion() and adds try/catch + alert so
future failures surface to the user.

Bumps image to v1.0.211.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
…k Solving state

Optimize Routes was failing silently for two reasons:
1. No try/catch around sfQuery — if the call threw (e.g., transient VROOM
   connection failure during cold-start), setSolving(false) was never reached
   and the button stuck on "Solving..." forever.
2. No user-visible error message when OPTIMIZATION returned zero rows.

Fix wraps the call in try/catch/finally, probes _OPTIMIZATION_RAW on empty
results to extract the underlying error, and shows an alert so users see
exactly why the solve failed (region not provisioned, VROOM warming up, etc.)
Also adds regionName to the dependency array.

Bumps image to v1.0.212.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <noreply@snowflake.com>
@sfc-gh-obielov sfc-gh-obielov merged commit 2b5cba3 into dev May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant