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.
# 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.
`````
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.
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.
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Follow-up to #484 / #556 (and the mobile tracker lane #920):
tiles.spikersoft.com404s on everything because the map-tile server does not exist — no swarm service, no stack file, and theterrain.mbtilesdata 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-glstack. Design points already validated:map.service.ts, both mobile tracker styles) declaresmaxzoom: 10on the terrain source — the old notes' z13 would be ~50× wasted work for tiles nobody requests.tileserver-glstack behind Traefik, re-enable the (now opt-in)TileServerGLAPI health check, and promote the notes into a real runbook atspikersoft-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)
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, Traefiktiles.spikersoft.com, SERVER-pinned) and the runbookdocs/map-tile-server.md(PR #162, which also promoted PMTiles on MinIO to primary delivery) both exist.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→ 200image/webp;https://minio.spikersoft.com/map-tiles/terrain.pmtiles→ 200 withAccept-Ranges: bytes, ranged GET → 206, 3.89 GB. Clients followed through: angular#626, ios#13, android#13.Status: partially done — two things still missing.
TileServerGLhealth canary, was never re-enabled.https://api.spikersoft.com/healthzreturns 13 checks andTileServerGLis not one of them; no infra stack file setsTileServerGL__Enabled.README.md:281is now false — it still claims the stack is "Not deployed untilterrain.mbtiles+config.jsonare 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 #166in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.— Opus 5 Agent