Problem
topology.py decides sea crossings from a hardcoded dict LOCATION_CONTINENT (6 countries). derive_sea_edges calls a stage "sea" when its endpoints sit on different continents.
Four flaws:
- Silent skip. Guard
if c_src and c_dst: — an unknown location yields no
crossing, no error, no lane. A PDL with location: China loses its sea leg silently.
- Joins on free text, not entity id.
location: Brasilien instead of Brazil
misses — silently, per (1).
- Sidecar entities are invisible to the classifier (they carry no
location:).
- Continent-difference is a leaky proxy. UK→Netherlands (sea, same continent)
reads as land; Panama→Colombia (land, two continents) reads as sea.
Geography is also split across three places: this dict, inline lat/lng on sidecar
entities, and the frontend gazetteer.
Solution
A top-level geo: block in the roster sidecar, keyed by entity id — the single home
for geography:
geo:
brazil_farms: { continent: South America, lat: -15.8, lng: -47.9, illustrative: true }
rotterdam_port: { continent: Europe, lat: 51.9, lng: 4.1, illustrative: true }
Plus a per-stage override for the cases the proxy gets wrong — a dedicated top-level
crossings: block, normalized (undirected) pair key, binary mode:
crossings:
- stage: [uk_port, rotterdam_port] # [a,b] == [b,a]
mode: sea
- stage: [panama_hub, colombia_hub]
mode: land
Resolution order: explicit stage mode → both endpoints' geo.continent → raise.
Scope
Acceptance
- No geographic literal in
topology.py; geography declared in exactly one place.
- An unresolvable crossing raises (entity + stage named); never yields a missing lane.
- Shipped and alternate PDLs: unchanged topology, unchanged values.
Notes
- Sidecar is an additive bridge; fields must survive going upstream to the partner
schema. continent: South America and mode: sea can; is_sea_side: true cannot.
Rejected
- Overloading sidecar
edges: with a mode field — a PDL stage isn't an edge.
- A node flag on
geo: (is_sea_side:) — repeats the node→edge inference mistake.
- Deriving continent from coordinates via a geo library — the coords are
illustrative.
Out of scope
Frontend gazetteer migration (settled in #33) · #37 cardinality work.
Problem
topology.pydecides sea crossings from a hardcoded dictLOCATION_CONTINENT(6 countries).derive_sea_edgescalls a stage "sea" when its endpoints sit on different continents.Four flaws:
if c_src and c_dst:— an unknown location yields nocrossing, no error, no lane. A PDL with
location: Chinaloses its sea leg silently.location: Brasilieninstead ofBrazilmisses — silently, per (1).
location:).reads as land; Panama→Colombia (land, two continents) reads as sea.
Geography is also split across three places: this dict, inline
lat/lngon sidecarentities, and the frontend gazetteer.
Solution
A top-level
geo:block in the roster sidecar, keyed by entity id — the single homefor geography:
Plus a per-stage override for the cases the proxy gets wrong — a dedicated top-level
crossings:block, normalized (undirected) pair key, binary mode:Resolution order: explicit stage
mode→ both endpoints'geo.continent→ raise.Scope
geo:toload_roster_sidecar, validated like_entity_placement(type / range / finiteness / boolean flag).
geo:the single home for geography: move inlinelat/lng/illustrativeoff the sidecar entities into it, delete the inline path;
_entity_placementreads from
geo:.derive_sea_edgesto resolve continents fromgeo:over the mergedentity list, by id.
crossings:override (shape decided above).Never a silent skip.
LOCATION_CONTINENT.replacement_crossingsinbuild_flow_adjacencycan be simplifiedonce classification reads the merged list. Don't remove on assumption.
Acceptance
topology.py; geography declared in exactly one place.Notes
schema.
continent: South Americaandmode: seacan;is_sea_side: truecannot.Rejected
edges:with a mode field — a PDL stage isn't an edge.geo:(is_sea_side:) — repeats the node→edge inference mistake.illustrative.Out of scope
Frontend gazetteer migration (settled in #33) · #37 cardinality work.