Rebuild the terrain map-tile server: per-state DEM fan-out + tileserver-gl deploy (agent prompt included; follow-up to #484/#556) #921

Closed
opened 2026-08-05 23:57:39 +00:00 by spikerj · 1 comment
Owner

Follow-up to #484 / #556 (and the mobile tracker lane #920): tiles.spikersoft.com 404s on everything because the map-tile server does not exist — no swarm service, no stack file, and the terrain.mbtiles data asset survives in no repo. Only the informal build recipe exists (spikersoft-angular/.../map-tracker/documentation/map-tiles-information.md). The web tracker's 3D terrain has been silently broken the whole time; the new iOS/Android tracker hillshade (android#3 / ios#4) points at the same URL and degrades the same way.

Plan: rebuild the data from the public-domain USGS 3DEP 1/3-arc-second DEM (S3, no API key), fanned out one agent per state, then merge and deploy a proper tileserver-gl stack. Design points already validated:

  • Workers build from full 1°×1° USGS cells (never state-clipped polygons) → border tiles are byte-identical between neighboring states → the merge is seam-free and order-independent.
  • Build zooms 5–10 only: every consumer (web map.service.ts, both mobile tracker styles) declares maxzoom: 10 on the terrain source — the old notes' z13 would be ~50× wasted work for tiles nobody requests.
  • Ship the merged mbtiles to SERVER via MinIO + a one-shot swarm job (no ssh from the 4090), serve with a pinned tileserver-gl stack behind Traefik, re-enable the (now opt-in) TileServerGL API health check, and promote the notes into a real runbook at spikersoft-infrastructure/docs/map-tile-server.md.

Operational cautions: full 50-state CONUS at 10 m ≈ a few hundred GB of cached source cells — ensure disk, or pilot with a small batch (Colorado + wherever people actually run) before the full sweep. Alaska/Hawaii live in different USGS collections; workers are instructed to stop-and-report on them rather than improvise.


Exact agent prompt (coordinator + per-state worker template)

# Rebuild the SpikerSoft terrain tile server (spikersoft-issues #484 / #556)

## Context — read first, all verified 2026-08-05

- `tiles.spikersoft.com` serves 404 for every path INCLUDING `/`. This is NOT an outage:
  per `spikersoft-infrastructure/README.md` § "map-tile-server — does not exist", no such
  swarm service exists and no stack file was ever committed. DNS+TLS work only because the
  wildcard cert covers the host; requests fall through to Traefik's catch-all.
- The terrain `.mbtiles` data asset exists in NO repo. Only the build recipe survives:
  `spikersoft-angular/projects/spikersoft/src/app/_components/map-tracker/documentation/map-tiles-information.md`
  (GDAL warp → rio-rgbify mapbox-RGB webp → tileserver-gl).
- Consumers (all tolerate 404s, so nothing breaks while you work):
  - web `map-tracker` `add3DTerrain()` → `${tileServerUrl}/data/terrain/{z}/{x}/{y}.webp`,
    raster-dem, encoding "mapbox", tileSize 256, **maxzoom 10**
  - iOS/Android tracker styles (`TrackerStyle.json` / `tracker_style.json`) — same URL,
    same `maxzoom: 10`, hillshade layer
- Because every consumer caps the source at **z10, build zooms 5–10 only** (the old notes
  say 7–13; z11–13 would never be requested — do not build them).
- The API health check `TileServerGL` is opt-in and currently disabled
  (`TileServerGL:Enabled=false`, spikersoft-backend #556). Re-enable it at the end.
- This host is the 4090 swarm MANAGER: docker works locally; there is NO ssh to other
  nodes and NO /mnt/fusionio here — SERVER-local work happens via one-shot swarm jobs
  pinned with `--constraint node.hostname==SERVER` (see the repo memory/README patterns).
- Repo rules: issues live in spikerj/spikersoft-issues; infra changes go through a PR to
  spikersoft-infrastructure; never commit secrets; MinIO creds live in the `minio_minio`
  service spec env.

## Architecture

1. FAN OUT one worker per state (template below). Workers only produce artifacts — they
   never touch git or the swarm config.
2. Workers share a download cache and each emit `terrain-<state>.mbtiles`.
3. COORDINATOR merges all mbtiles into one `terrain.mbtiles`, ships it to SERVER,
   commits + deploys the tileserver-gl stack, re-enables the health check, verifies
   end-to-end, writes the runbook, and comments on #484/#556.

Work directory on this host: `/home/joey/map-tiles-build/` with `cache/` (shared 1° cell
GeoTIFFs), `states/<state>/`, and `out/`.

---

## PER-STATE WORKER PROMPT (fan out with {{STATE}} = lowercase state name, e.g. "colorado")

You are building mapbox-RGB terrain tiles for the US state {{STATE}}. Produce
`/home/joey/map-tiles-build/out/terrain-{{STATE}}.mbtiles`. Artifact-only: no git, no
swarm changes, no deletions outside your state dir. Steps:

1. **State bbox**: fetch `https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json`
   once (cache at `/home/joey/map-tiles-build/cache/us-states.json`), extract {{STATE}}'s
   feature, compute its bbox (python3 + json is fine — min/max over all coordinates).
2. **DEM cells**: the USGS 3DEP 1/3-arc-second DEM is public-domain on S3 as 1°×1° cells
   named by their NW corner: cell covering lat∈[N-1,N], lon∈[-W,-W+1] is
   `n{N}w{W}` (zero-padded W to 3 digits). Enumerate every cell intersecting the bbox
   (NO polygon clipping — full cells only; this makes border tiles identical between
   neighboring states so the coordinator's merge is seam-free). For each cell, find the
   real object key by listing
   `https://prd-tnm.s3.amazonaws.com/?list-type=2&prefix=StagedProducts/Elevation/13/TIFF/current/n{N}w{W}/`
   (public bucket, XML response — take the `.tif` key) and download to
   `/home/joey/map-tiles-build/cache/<cellname>.tif` **only if not already cached**
   (cells are shared between states — never re-download, never delete the cache).
   Some coastal/border cells legitimately don't exist — skip 404s, log the skip.
   If ALL cells are missing (e.g. Alaska uses a different collection), stop and report
   rather than improvising.
3. **Warp** (docker, per the surviving recipe): build a VRT of your cells then reproject:
   ```
   docker run --rm -v /home/joey/map-tiles-build:/w ghcr.io/osgeo/gdal:alpine-normal-latest \
     gdalbuildvrt /w/states/{{STATE}}/dem.vrt /w/cache/<cell1>.tif /w/cache/<cell2>.tif ...
   docker run --rm -v /home/joey/map-tiles-build:/w ghcr.io/osgeo/gdal:alpine-normal-latest \
     gdalwarp -r cubicspline -t_srs EPSG:3857 -dstnodata 0 -co COMPRESS=DEFLATE \
     /w/states/{{STATE}}/dem.vrt /w/states/{{STATE}}/dem3857.tif
   ```
4. **Tile** (mapbox RGB encoding, webp, zooms 5–10 — NOT 13, consumers cap at 10):
   ```
   docker run --rm -v /home/joey/map-tiles-build:/w helmi03/rio-rgbify \
     -b -10000 -i 0.1 --min-z 5 --max-z 10 -j 4 --format webp \
     /w/states/{{STATE}}/dem3857.tif /w/out/terrain-{{STATE}}.mbtiles
   ```
   (If `helmi03/rio-rgbify` won't pull, build a small image: `FROM python:3.11-slim` +
   `pip install rio-rgbify` — document what you used.)
5. **Verify before declaring success**: with sqlite3 (or python3 stdlib), assert the
   mbtiles has >0 rows in `tiles`, zoom_levels ⊆ [5,10], and extract one mid-state z10
   tile blob — its first bytes must be RIFF/WEBP. Report: cell count, skipped cells,
   tile count, file size, and the sample tile's tile_column/row for the coordinator's
   spot-check. Then delete `states/{{STATE}}/` intermediates (keep cache/ and out/).

---

## COORDINATOR — after all workers report

1. **Merge**: create `out/terrain.mbtiles` — copy the largest state file, then for each
   other file: `ATTACH` it in sqlite and `INSERT OR REPLACE INTO tiles SELECT * FROM
   src.tiles;`. Overlapping border tiles are identical by construction, so order doesn't
   matter. Rewrite `metadata`: name=terrain, format=webp, minzoom=5, maxzoom=10,
   bounds=union of all state bounds, plus `attribution` = "USGS 3DEP (public domain)".
   Sanity: total tile count ≥ max per-state count; spot-check 3 tiles from different
   states decode as webp.
2. **Ship to SERVER** (no ssh — use MinIO as the bridge): upload `terrain.mbtiles` and a
   `config.json` (copy the shape from the map-tiles-information.md notes: serve mbtiles
   `terrain` from `/data`, cors on) with `mc` to a `map-tiles` bucket, then a one-shot
   swarm service pinned to SERVER (`--restart-condition none`, mount
   `/mnt/fusionio/spikersoft`) that `mc cp`s both into
   `/mnt/fusionio/spikersoft/map-tiles/`. Remove the one-shot service after. (MinIO root
   creds: extract from the `minio_minio` service spec env — never echo them.)
3. **Stack file**: in a `spikersoft-infrastructure` branch, add `map-tile-server/` with a
   docker-stack.yml following the repo's existing stack conventions:
   `maptiler/tileserver-gl` (the maintained image; `klokantech/tileserver-gl` in the old
   notes is deprecated — pin a specific version), constraint `node.hostname==SERVER`,
   bind `/mnt/fusionio/spikersoft/map-tiles:/data:ro`, command
   `--config /data/config.json`, network `traefik-public`, Traefik labels for host
   `tiles.spikersoft.com` (cert resolver `myresolver` — copy a neighboring stack's label
   block), modest memory limit. Also delete/rewrite the README § "map-tile-server — does
   not exist" section to describe the now-real service.
4. **Runbook**: promote the informal notes into
   `spikersoft-infrastructure/docs/map-tile-server.md` — data source (USGS 3DEP S3
   layout), the exact worker pipeline, why zooms are 5–10 (client maxzoom), the merge
   procedure, and how to add a state later (run one worker + re-merge + re-upload).
5. **Deploy** (this host is a manager): `docker stack deploy` per the repo's deploy
   conventions, then verify:
   - `curl -sI https://tiles.spikersoft.com/data/terrain/8/53/98.webp` (or a coordinate
     you computed over Colorado) → 200 `image/webp`; an out-of-coverage tile → 404;
     `/data/terrain.json` → 200 JSON.
6. **Re-enable the health canary**: set `TileServerGL__Enabled=true` on the API service's
   environment in its infra stack file (the check degrades rather than 503s — backend
   #556 made it safe), redeploy the API, confirm `/healthz` shows the check green.
7. **Close the loop**: PR the infra branch (reference #484/#556 and #920), and after
   merge comment on spikersoft-issues #484 and #556 with what was deployed (manual
   comment+close per the close-tracker-issues rule — decide close vs keep-open based on
   what those tickets still track beyond the tile server). Note for the human: web 3D
   terrain and the mobile hillshade (PRs android#3 / ios#4) light up with zero client
   changes; a device/browser check of `/tracker` 3D is the final visual confirmation.

Constraints for everyone: never log or commit MinIO credentials; don't touch
`/mnt/fusionio` except via the documented one-shot-job pattern; the shared cache is
append-only during the run; if a step's tooling fails (image won't pull, S3 layout
changed), stop and report precisely rather than substituting a different data source.
Follow-up to #484 / #556 (and the mobile tracker lane #920): `tiles.spikersoft.com` 404s on everything because **the map-tile server does not exist** — no swarm service, no stack file, and the `terrain.mbtiles` data asset survives in no repo. Only the informal build recipe exists (`spikersoft-angular/.../map-tracker/documentation/map-tiles-information.md`). The web tracker's 3D terrain has been silently broken the whole time; the new iOS/Android tracker hillshade (android#3 / ios#4) points at the same URL and degrades the same way. **Plan**: rebuild the data from the public-domain USGS 3DEP 1/3-arc-second DEM (S3, no API key), fanned out **one agent per state**, then merge and deploy a proper `tileserver-gl` stack. Design points already validated: - Workers build from **full 1°×1° USGS cells** (never state-clipped polygons) → border tiles are byte-identical between neighboring states → the merge is seam-free and order-independent. - Build **zooms 5–10 only**: every consumer (web `map.service.ts`, both mobile tracker styles) declares `maxzoom: 10` on the terrain source — the old notes' z13 would be ~50× wasted work for tiles nobody requests. - Ship the merged mbtiles to SERVER via MinIO + a one-shot swarm job (no ssh from the 4090), serve with a pinned `tileserver-gl` stack behind Traefik, re-enable the (now opt-in) `TileServerGL` API health check, and promote the notes into a real runbook at `spikersoft-infrastructure/docs/map-tile-server.md`. **Operational cautions**: full 50-state CONUS at 10 m ≈ a few hundred GB of cached source cells — ensure disk, or pilot with a small batch (Colorado + wherever people actually run) before the full sweep. Alaska/Hawaii live in different USGS collections; workers are instructed to stop-and-report on them rather than improvise. --- ## Exact agent prompt (coordinator + per-state worker template) `````markdown # Rebuild the SpikerSoft terrain tile server (spikersoft-issues #484 / #556) ## Context — read first, all verified 2026-08-05 - `tiles.spikersoft.com` serves 404 for every path INCLUDING `/`. This is NOT an outage: per `spikersoft-infrastructure/README.md` § "map-tile-server — does not exist", no such swarm service exists and no stack file was ever committed. DNS+TLS work only because the wildcard cert covers the host; requests fall through to Traefik's catch-all. - The terrain `.mbtiles` data asset exists in NO repo. Only the build recipe survives: `spikersoft-angular/projects/spikersoft/src/app/_components/map-tracker/documentation/map-tiles-information.md` (GDAL warp → rio-rgbify mapbox-RGB webp → tileserver-gl). - Consumers (all tolerate 404s, so nothing breaks while you work): - web `map-tracker` `add3DTerrain()` → `${tileServerUrl}/data/terrain/{z}/{x}/{y}.webp`, raster-dem, encoding "mapbox", tileSize 256, **maxzoom 10** - iOS/Android tracker styles (`TrackerStyle.json` / `tracker_style.json`) — same URL, same `maxzoom: 10`, hillshade layer - Because every consumer caps the source at **z10, build zooms 5–10 only** (the old notes say 7–13; z11–13 would never be requested — do not build them). - The API health check `TileServerGL` is opt-in and currently disabled (`TileServerGL:Enabled=false`, spikersoft-backend #556). Re-enable it at the end. - This host is the 4090 swarm MANAGER: docker works locally; there is NO ssh to other nodes and NO /mnt/fusionio here — SERVER-local work happens via one-shot swarm jobs pinned with `--constraint node.hostname==SERVER` (see the repo memory/README patterns). - Repo rules: issues live in spikerj/spikersoft-issues; infra changes go through a PR to spikersoft-infrastructure; never commit secrets; MinIO creds live in the `minio_minio` service spec env. ## Architecture 1. FAN OUT one worker per state (template below). Workers only produce artifacts — they never touch git or the swarm config. 2. Workers share a download cache and each emit `terrain-<state>.mbtiles`. 3. COORDINATOR merges all mbtiles into one `terrain.mbtiles`, ships it to SERVER, commits + deploys the tileserver-gl stack, re-enables the health check, verifies end-to-end, writes the runbook, and comments on #484/#556. Work directory on this host: `/home/joey/map-tiles-build/` with `cache/` (shared 1° cell GeoTIFFs), `states/<state>/`, and `out/`. --- ## PER-STATE WORKER PROMPT (fan out with {{STATE}} = lowercase state name, e.g. "colorado") You are building mapbox-RGB terrain tiles for the US state {{STATE}}. Produce `/home/joey/map-tiles-build/out/terrain-{{STATE}}.mbtiles`. Artifact-only: no git, no swarm changes, no deletions outside your state dir. Steps: 1. **State bbox**: fetch `https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json` once (cache at `/home/joey/map-tiles-build/cache/us-states.json`), extract {{STATE}}'s feature, compute its bbox (python3 + json is fine — min/max over all coordinates). 2. **DEM cells**: the USGS 3DEP 1/3-arc-second DEM is public-domain on S3 as 1°×1° cells named by their NW corner: cell covering lat∈[N-1,N], lon∈[-W,-W+1] is `n{N}w{W}` (zero-padded W to 3 digits). Enumerate every cell intersecting the bbox (NO polygon clipping — full cells only; this makes border tiles identical between neighboring states so the coordinator's merge is seam-free). For each cell, find the real object key by listing `https://prd-tnm.s3.amazonaws.com/?list-type=2&prefix=StagedProducts/Elevation/13/TIFF/current/n{N}w{W}/` (public bucket, XML response — take the `.tif` key) and download to `/home/joey/map-tiles-build/cache/<cellname>.tif` **only if not already cached** (cells are shared between states — never re-download, never delete the cache). Some coastal/border cells legitimately don't exist — skip 404s, log the skip. If ALL cells are missing (e.g. Alaska uses a different collection), stop and report rather than improvising. 3. **Warp** (docker, per the surviving recipe): build a VRT of your cells then reproject: ``` docker run --rm -v /home/joey/map-tiles-build:/w ghcr.io/osgeo/gdal:alpine-normal-latest \ gdalbuildvrt /w/states/{{STATE}}/dem.vrt /w/cache/<cell1>.tif /w/cache/<cell2>.tif ... docker run --rm -v /home/joey/map-tiles-build:/w ghcr.io/osgeo/gdal:alpine-normal-latest \ gdalwarp -r cubicspline -t_srs EPSG:3857 -dstnodata 0 -co COMPRESS=DEFLATE \ /w/states/{{STATE}}/dem.vrt /w/states/{{STATE}}/dem3857.tif ``` 4. **Tile** (mapbox RGB encoding, webp, zooms 5–10 — NOT 13, consumers cap at 10): ``` docker run --rm -v /home/joey/map-tiles-build:/w helmi03/rio-rgbify \ -b -10000 -i 0.1 --min-z 5 --max-z 10 -j 4 --format webp \ /w/states/{{STATE}}/dem3857.tif /w/out/terrain-{{STATE}}.mbtiles ``` (If `helmi03/rio-rgbify` won't pull, build a small image: `FROM python:3.11-slim` + `pip install rio-rgbify` — document what you used.) 5. **Verify before declaring success**: with sqlite3 (or python3 stdlib), assert the mbtiles has >0 rows in `tiles`, zoom_levels ⊆ [5,10], and extract one mid-state z10 tile blob — its first bytes must be RIFF/WEBP. Report: cell count, skipped cells, tile count, file size, and the sample tile's tile_column/row for the coordinator's spot-check. Then delete `states/{{STATE}}/` intermediates (keep cache/ and out/). --- ## COORDINATOR — after all workers report 1. **Merge**: create `out/terrain.mbtiles` — copy the largest state file, then for each other file: `ATTACH` it in sqlite and `INSERT OR REPLACE INTO tiles SELECT * FROM src.tiles;`. Overlapping border tiles are identical by construction, so order doesn't matter. Rewrite `metadata`: name=terrain, format=webp, minzoom=5, maxzoom=10, bounds=union of all state bounds, plus `attribution` = "USGS 3DEP (public domain)". Sanity: total tile count ≥ max per-state count; spot-check 3 tiles from different states decode as webp. 2. **Ship to SERVER** (no ssh — use MinIO as the bridge): upload `terrain.mbtiles` and a `config.json` (copy the shape from the map-tiles-information.md notes: serve mbtiles `terrain` from `/data`, cors on) with `mc` to a `map-tiles` bucket, then a one-shot swarm service pinned to SERVER (`--restart-condition none`, mount `/mnt/fusionio/spikersoft`) that `mc cp`s both into `/mnt/fusionio/spikersoft/map-tiles/`. Remove the one-shot service after. (MinIO root creds: extract from the `minio_minio` service spec env — never echo them.) 3. **Stack file**: in a `spikersoft-infrastructure` branch, add `map-tile-server/` with a docker-stack.yml following the repo's existing stack conventions: `maptiler/tileserver-gl` (the maintained image; `klokantech/tileserver-gl` in the old notes is deprecated — pin a specific version), constraint `node.hostname==SERVER`, bind `/mnt/fusionio/spikersoft/map-tiles:/data:ro`, command `--config /data/config.json`, network `traefik-public`, Traefik labels for host `tiles.spikersoft.com` (cert resolver `myresolver` — copy a neighboring stack's label block), modest memory limit. Also delete/rewrite the README § "map-tile-server — does not exist" section to describe the now-real service. 4. **Runbook**: promote the informal notes into `spikersoft-infrastructure/docs/map-tile-server.md` — data source (USGS 3DEP S3 layout), the exact worker pipeline, why zooms are 5–10 (client maxzoom), the merge procedure, and how to add a state later (run one worker + re-merge + re-upload). 5. **Deploy** (this host is a manager): `docker stack deploy` per the repo's deploy conventions, then verify: - `curl -sI https://tiles.spikersoft.com/data/terrain/8/53/98.webp` (or a coordinate you computed over Colorado) → 200 `image/webp`; an out-of-coverage tile → 404; `/data/terrain.json` → 200 JSON. 6. **Re-enable the health canary**: set `TileServerGL__Enabled=true` on the API service's environment in its infra stack file (the check degrades rather than 503s — backend #556 made it safe), redeploy the API, confirm `/healthz` shows the check green. 7. **Close the loop**: PR the infra branch (reference #484/#556 and #920), and after merge comment on spikersoft-issues #484 and #556 with what was deployed (manual comment+close per the close-tracker-issues rule — decide close vs keep-open based on what those tickets still track beyond the tile server). Note for the human: web 3D terrain and the mobile hillshade (PRs android#3 / ios#4) light up with zero client changes; a device/browser check of `/tracker` 3D is the final visual confirmation. Constraints for everyone: never log or commit MinIO credentials; don't touch `/mnt/fusionio` except via the documented one-shot-job pattern; the shared cache is append-only during the run; if a step's tooling fails (image won't pull, S3 layout changed), stop and report precisely rather than substituting a different data source. `````
Author
Owner

Migrated to spikerj/spikersoft-infrastructure#166 as part of the umbrella-tracker breakup.

Most of this one actually landed — I'm migrating rather than closing because two explicit steps of the plan did not.

Verified 2026-08-07 against spikersoft-infrastructure@86d03ff:

  • map-tile-server/docker-stack.yml (PR #160, maptiler/tileserver-gl:v5.6.0, Traefik tiles.spikersoft.com, SERVER-pinned) and the runbook docs/map-tile-server.md (PR #162, which also promoted PMTiles on MinIO to primary delivery) both exist.
  • Live: docker service ls → map-tile-server_map-tile-server 1/1; https://tiles.spikersoft.com/ → 200; /data/terrain.json → 200 (webp, minzoom 5, maxzoom 10, USGS 3DEP (public domain)); /data/terrain/8/53/98.webp → 200 image/webp; https://minio.spikersoft.com/map-tiles/terrain.pmtiles → 200 with Accept-Ranges: bytes, ranged GET → 206, 3.89 GB. Clients followed through: angular#626, ios#13, android#13.

Status: partially done — two things still missing.

  1. Step 6, the TileServerGL health canary, was never re-enabled. https://api.spikersoft.com/healthz returns 13 checks and TileServerGL is not one of them; no infra stack file sets TileServerGL__Enabled.
  2. README.md:281 is now false — it still claims the stack is "Not deployed until terrain.mbtiles + config.json are shipped to SERVER". They were shipped; it is deployed.
    (Plus step 7's loop-closing comments on #484/#556, if those are still open.)

Closing here. Work now lives in the repo that holds the fix, so fixes #166 in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.

— Opus 5 Agent

Migrated to **spikerj/spikersoft-infrastructure#166** as part of the umbrella-tracker breakup. Most of this one actually **landed** — I'm migrating rather than closing because two explicit steps of the plan did not. Verified 2026-08-07 against `spikersoft-infrastructure@86d03ff`: - `map-tile-server/docker-stack.yml` (PR #160, `maptiler/tileserver-gl:v5.6.0`, Traefik `tiles.spikersoft.com`, SERVER-pinned) and the runbook `docs/map-tile-server.md` (PR #162, which also promoted **PMTiles on MinIO** to primary delivery) both exist. - Live: `docker service ls` → `map-tile-server_map-tile-server 1/1`; `https://tiles.spikersoft.com/` → 200; `/data/terrain.json` → 200 (`webp`, minzoom 5, maxzoom 10, `USGS 3DEP (public domain)`); `/data/terrain/8/53/98.webp` → 200 `image/webp`; `https://minio.spikersoft.com/map-tiles/terrain.pmtiles` → 200 with `Accept-Ranges: bytes`, ranged GET → 206, 3.89 GB. Clients followed through: angular#626, ios#13, android#13. Status: **partially done — two things still missing.** 1. **Step 6, the `TileServerGL` health canary, was never re-enabled.** `https://api.spikersoft.com/healthz` returns 13 checks and `TileServerGL` is not one of them; no infra stack file sets `TileServerGL__Enabled`. 2. **`README.md:281` is now false** — it still claims the stack is "Not deployed until `terrain.mbtiles` + `config.json` are shipped to SERVER". They were shipped; it is deployed. (Plus step 7's loop-closing comments on #484/#556, if those are still open.) Closing here. Work now lives in the repo that holds the fix, so `fixes #166` in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only. — Opus 5 Agent
Sign in to join this conversation.