X-GIS
Blog

architecture

The coordinates rot before the symptom does

A package extraction moved the render code to a new package. It changed no behavior, so every open bug report's symptom stayed valid — and every report's file:line pointed at a path that no longer existed. The precise-looking part of a report rots first.

By the X-GIS team 4 min read

The bug report was specific in the way you want a report to be: the line outline jitters at high zoom, and the culprit is runtime/src/engine/shaders/dsl/line.ts:237-244. So I opened it:

$ sed -n '237,244p' runtime/src/engine/shaders/dsl/line.ts
$ # nothing — exit 2, no such file

The file does not exist. Not moved-and-edited; gone from that path entirely. The code it named is alive and well at map/src/shaders/dsl/line.ts — a different package. The symptom in the report was still real and still reproducible. The address had been demolished three weeks earlier by a change that touched no behavior at all: a package extraction.

Four of the open issues I was triaging pointed into runtime/src/…line.ts, vector-tile-renderer.ts:3539, label-pass.ts:600-633, feature-helpers.ts:107-118 — and every one of those files now lives under map/src/… and is gone from runtime. Same code, new home, dead coordinates.

The wrong first move

The wrong move is the natural one: navigate by the report. A file:line is the most precise field in a bug report, so it reads as the most trustworthy — the part someone already did the work to pin down. When I seeded a batch of triage agents, my first instinct was to hand each one the path its issue named. That is handing a fixer a treasure map to a building that has been torn down.

The precision is exactly what makes it dangerous. A vague report (“labels look wrong somewhere in the text pass”) forces you to go find the code, so you always land on the current tree. A precise one (“feature-helpers.ts:107-118”) invites you to jump straight there — and jumps straight into a sed that returns nothing, or worse, into a stale mirror that still exists but no longer does what the report says.

What actually happened

The engine is mid-extraction. A formerly-monolithic @xgis/runtime is being decomposed into focused packages — @xgis/map (render / camera / shaders / text), @xgis/data, @xgis/geo, and the rest — and the render subsystem has already moved out. map now holds 179 source files; runtime is down to 18 and mostly re-exports the others. The move was a git mv at heart: byte-for-byte the same rendering, so no test changed its result and no PR description mentioned a behavior delta. Nothing in the issue tracker got a notification. Every report filed against the old layout kept its symptom and silently lost its location.

This is the property that makes it sneaky. A code change that alters behavior trips a test, and the red test is a loud signal that some assumption elsewhere just aged. A pure relocation trips nothing. There is no merge conflict against an issue body, no CI check that a file:line in a three-week-old report still resolves. The staleness accrues in a system — the tracker — that the compiler never reads.

The way through was to stop navigating by path and navigate by symbol. Instead of trusting runtime/src/engine/shaders/dsl/line.ts, ask the code graph “where is finalize_corner defined today” and let it answer map/src/shaders/dsl/line.ts — “the only copy,” as the trace put it. The symptom told me what was wrong; the current symbol table, not the report, told me where.

What generalizes

A bug report has two halves with wildly different half-lives. The symptom — what the user sees — ages slowly; a jitter reported three weeks ago is very likely still a jitter. The location — the file:line, the named function, the “sibling implementation to copy from” — ages at the speed of your refactors, and a package extraction ages all of them at once, on the day of the move, with no signal.

So treat the coordinates in a report as a lead, not an address, and treat a recent large-scale move as a tracker-wide cache invalidation you were never told about. When the most precise line in the report is the first to have rotted, the fix is to re-derive location from the live symbol graph every time — the report is authoritative about the bug, never about where the bug now lives.

References

  1. When the bug is already fixed, the test still isn’t — the other way a precise report rots: not a relocation, but a concurrent fix that leaves the symptom described and the diagnosis stale.

Read next

architecture

8 min read

The issue said to move the code back

An issue prescribed relocating a context type to kill an adapter-to-adapter dependency edge. By pickup, that mechanism meant reverting a merged refactor. We cut the edge with composition-root injection instead, and locked it with a shrink-only ratchet.

architecture

3 min read

The migration regressed one renderer at a time

A coordinate-space migration carried one assumption — "absolute geometry needs no per-copy shift" — that was true for the globe and false for flat maps. Applied per-renderer, it silently dropped world-copy fan-out path by path. The fix is one ten-line router.

architecture

5 min read

Your render pipeline is just a string

217 GPURenderPipeline references stood between @xgis/map and backend-neutrality. Most of them turned out not to be pipelines at all — they were labels being matched. Collapsing them to a neutral { label } handle, and how prove-or-refute kept us from doing the wrong migration.