The Wrong District Lit Up on a Better Map.

What shipping detailed vector tiles taught me about separating render geometry from behavioral truth in a map product.

A founder studies a detailed travel map and a mismatched highlighted district beside handwritten notes about rendering and evidence.
A more detailed map does not automatically make a truer product.

After I shipped a more detailed map for Wimemo, the wrong district still lit up.

That sentence is useful precisely because it removes the comforting excuse.

The map was not failing because it was too coarse anymore.

I had already built the deep-zoom boundary pipeline I wanted. South Korea became the first production-shaped proving ground: 17 ADM1 regions, 228 ADM2 regions, 876 immutable vector tiles, and about 696 KB of packaged detail instead of one giant geometry download. At country-level zoom, Wimemo could now keep its bundled coarse world map for instant rendering, then fetch only the visible district detail after the gesture settled.

The Atlas looked better.

But one real contradiction remained: photos from Seoul and Busan could still light an unrelated Korean district before the cards separated.

That was the moment the real lesson appeared.

The problem was no longer map detail.

The problem was that I had let the rendering system and the truth system borrow the same evidence.

Wimemo is an iPhone app that turns travel photos into a private Atlas. Users do not think in terms of tile manifests, bounding boxes, or point-in-polygon tests. They think in a simpler question: did the product correctly understand where I have actually been?

That sounds like a map question.

It is only partly a map question.

The rendering pipeline answers: how should the screen look right now at this zoom level, on this network, on this device?

The behavioral pipeline answers: which country, region, or place did the user's source media actually prove?

Those are related questions. They are not the same question.

I learned that the hard way because a screen can look more accurate while the product meaning is still wrong.

Better Borders Did Not Make Better Truth

The rendering work was real engineering work, not cosmetic polish.

Before this batch, Wimemo's bundled topology was intentionally small: roughly 108 KB for low detail and 756 KB for medium detail. That kept the app fast and offline-friendly, but deep zoom could not recover border detail that did not exist in the source geometry. Downloading a full high-resolution GeoJSON per country after zoom would have solved one problem by creating four others: unpredictable network cost, larger decode cost, more memory pressure, and more frame-time risk.

So the Atlas moved to a versioned vector-tile model.

After a gesture settled at country-level zoom, the client requested only the visible ADM1 and ADM2 tiles plus one surrounding ring. Requests used immutable URLs, ETags, and content validation. Decode and path construction stayed off the main thread. If a request failed, the last valid level of detail stayed on screen. A weak network could make the map less detailed, but not empty.

That was the right rendering decision.

It just did not answer the semantic question.

Because tiles are built for drawing.

They are not built to decide where the user has been.

Mapbox's own vector-tile docs describe vector tiles as a lightweight format for storing geospatial points, lines, and polygons. Its style-optimized tile docs go further: a tile may intentionally omit layers or features that are not needed by the current style in order to reduce size. That is exactly what a good rendering pipeline should do. It is also exactly why a rendering asset is dangerous as a truth source.

The job of a tile is to help the screen render the right picture efficiently.

The job of visit evidence is to survive zoom, clustering, simplification, and presentation tricks without changing meaning.

I had let those two jobs drift too close together.

The Visual Center Was A Lie

The bug was subtle because it looked reasonable when I was thinking like a UI engineer.

Atlas photo cards cluster differently at different zoom levels. When the map is farther out, the app groups nearby photos so the screen remains readable. When the user zooms in, those cards separate and reveal more local structure.

If you use the card's visual center, representative label, or cluster centroid as visit evidence, you are quietly turning a presentation artifact into product truth.

That is what the Korean case exposed.

A trip containing source photos from Seoul and Busan can produce a useful visual summary card before the user zooms all the way in. But the center of that temporary visual grouping is not a place the user visited. It is just a compromise position chosen by the interface.

Once that clicked, the durable rule became obvious:

Presentation data can summarize evidence. It must not replace evidence.

So the subdivision model changed.

An administrative area is now considered visited only when a source photo coordinate falls inside that area's boundary.

Not the card center.

Not the cluster centroid.

Not the trip title.

Not the dominant city label.

Not the prettiest district the current zoom level happens to make visible.

Only source-photo coordinates.

That rule is more boring and more trustworthy than the previous mental model. It also scales better because it is country-agnostic. Korea was only the case that made the mistake visible first.

Truth Needed Its Own Pipeline

Once I stopped treating rendering and evidence as one system, the implementation became much cleaner.

The app now resolves subdivision evidence once, after source coordinates are available, and persists normalized region keys on the trip itself. The stored value is deliberately minimal: ISO3|AREA-CODE, for example KOR|KR-11 or USA|US-CA.

That design mattered for two reasons.

First, it avoids rerunning expensive point-in-polygon work during gestures. The map can consume precomputed visited sets instead of pretending every pan is a semantic event.

Second, it keeps the privacy boundary intact. Wimemo does not upload per-photo coordinates or photo identifiers just to remember that a trip covered Seoul and Busan. The backend only stores additive region evidence keys. The migration and tests explicitly gate deduplication, stale-revision rejection, and malformed payload rejection so this stays part of the same atomic sync contract instead of becoming a side channel.

That separation also made a future problem easier to name.

Administrative regions are not the same thing as travel meaning.

Drawing province and district fills correctly is useful. Counting a province as visited is also useful. But a travel route still needs a semantic place model above both. A same-country 30 km city-merge rule can hide reverse-geocoder noise, yet it can also silently merge distinct nearby cities and fail on coasts, islands, borders, and true A -> B -> A revisits.

So the August 21 follow-up decision did not stop at district evidence. It formalized another rule:

Render geometry is not a safe source of travel meaning.

That sounds obvious after the fact. In practice, teams collapse these layers together all the time because the map is already there, the cluster center is already there, and the visible label is already there. Reusing them feels efficient.

It is efficient in the same way many convenient shortcuts are efficient: until the day the product tells a plausible lie.

The Reusable Lesson

If I were handing this story to another product engineer, I would reduce it to one checklist:

  1. Separate display truth from behavioral truth.
  2. Let render assets optimize for draw cost, not product semantics.
  3. Let visit evidence come from the smallest direct proof you actually trust.
  4. Persist semantic results in a stable form so the UI does not recompute meaning from presentation.
  5. Add one test that proves the same evidence still means the same thing after zoom, clustering, or style changes.

This is bigger than maps.

Any UI-heavy product can fall into the same trap:

  • a feed rank used as a proxy for satisfaction
  • an avatar state used as a proxy for identity linkage
  • a progress bar used as a proxy for durable completion
  • a clustered map label used as a proxy for physical presence

The display layer exists to help humans see.

The truth layer exists to help the product decide.

Those layers can cooperate.

They should not impersonate each other.

Where Human Judgment Still Matters

This is not a complete end state.

Old photo-backed trips only gain subdivision evidence when local photos are available again; the system does not fabricate certainty from missing media. Manual historical trips without photos may still use an outline-only fallback because deliberate user memory deserves a visible place on the Atlas even when it is not photo-backed coverage. And none of this removes the need for versioned place semantics, licenses, label governance, or country-by-country rollout judgment.

But the thesis I am keeping is simple:

A more detailed map can still tell the wrong story if rendering is allowed to decide what is true.

That is the rule this incident gave me.

And it is the one I would reuse before I add another layer of polish.


I write these from building Wimemo, a private travel memory app. If you want the product context behind the engineering decisions, you can read more about Wimemo here.