# Source Registry — C6: Tile cache + spatial index

> Mode A Phase 2 — engine Step 2 (Source Tiering & Exhaustive Web Investigation). Sources backing the C6 component candidates ([`../06_component_fit_matrix/C6_tile_cache_spatial_index.md`](../06_component_fit_matrix/C6_tile_cache_spatial_index.md)) and C6 fact cards ([`../02_fact_cards/C6_tile_cache_spatial_index.md`](../02_fact_cards/C6_tile_cache_spatial_index.md)).
>
> Index: [`00_summary.md`](00_summary.md). Sibling component sources: [C1 VIO](C1_vio.md), [C2 VPR](C2_vpr.md), [C3 Matchers](C3_matchers.md), [C4 Pose](C4_pose_estimation.md), [C5 State estimator](C5_state_estimator.md). Sub-question sources: [SQ6 external positioning](SQ6_external_positioning.md), [SQ1 existing systems](SQ1_existing_systems.md), [SQ2 canonical pipeline](SQ2_canonical_pipeline.md).

---

## Scope summary

C6 candidates evaluated documentary level: **Cand 1 (mandatory simple-baseline)** mirrors the parent-suite `satellite-provider` pattern (PostgreSQL + pure btree composite on slippy-map `(tile_zoom, tile_x, tile_y, version)` + filesystem tile storage at `./tiles/{zoom}/{x}/{y}.jpg`); **Cand 2 (modern-competitive-lead-spatial-extension)** = PostGIS GiST on `geography(POINT,4326)` for geographic side + pgvector HNSW for descriptor ANN side + same filesystem tile storage. Both candidates share the same Postgres-as-runtime-DB substrate per user-pinned scope (Postgres on Jetson at runtime, c6_postgres_locus = A). The user explicitly stated the satellite-provider pattern is NOT carved in stone — Cand 2 may cascade changes back to the satellite-provider IF research reveals a MATERIAL improvement (small improvements stay with Cand 1).

---

## Sources

### Source #92 — Parent-suite `satellite-provider` existing pattern (verified directly via filesystem read at /Users/obezdienie001/dev/azaion/suite/satellite-provider/)

**Title**: `azaion/suite/satellite-provider` .NET 8.0 microservice (PostgreSQL + Dapper + filesystem tile storage)
**Tier**: L1 — primary code in the same multi-repo project workspace
**URL**: file:///Users/obezdienie001/dev/azaion/suite/satellite-provider/
**Access date**: 2026-05-08
**Direct verification**:
- README at `satellite-provider/README.md` — confirms PostgreSQL backend, .NET 8.0 microservice, Dapper-based DataAccess layer, filesystem tile storage at `./tiles/{zoomLevel}/{x}/{y}.jpg`, NO PostGIS extension declared.
- Migration `001_CreateTilesTable.sql` — `tiles` table with `(id UUID PK, zoom_level INT, latitude DOUBLE PRECISION, longitude DOUBLE PRECISION, tile_size_meters DOUBLE PRECISION, tile_size_pixels INT, image_type VARCHAR(10), maps_version VARCHAR(50), file_path VARCHAR(500), created_at, updated_at)`.
- Migration `003_CreateIndexes.sql` — `CREATE INDEX idx_tiles_composite ON tiles(latitude, longitude, tile_size_meters)` + `CREATE INDEX idx_tiles_zoom ON tiles(zoom_level)` + `CREATE INDEX idx_regions_status ON regions(status)`. **Pure btree composite indexes; NO GiST, NO PostGIS, NO spatial extension.**
- Migration `011_AddTileCoordinates.sql` — RENAME `zoom_level` → `tile_zoom`; ADD `tile_x INT NOT NULL` + `tile_y INT NOT NULL` derived via slippy-map Web Mercator math (`tile_x = FLOOR((longitude + 180.0) / 360.0 * POWER(2, tile_zoom))::INT` + `tile_y = FLOOR((1.0 - LN(TAN(RADIANS(latitude)) + 1.0 / COS(RADIANS(latitude))) / PI()) / 2.0 * POWER(2, tile_zoom))::INT`); CREATE UNIQUE INDEX `idx_tiles_unique_location ON tiles(latitude, longitude, tile_zoom, tile_size_meters, version)` + `CREATE INDEX idx_tiles_coordinates ON tiles(tile_zoom, tile_x, tile_y, version)`. **Confirms: existing pattern uses btree on slippy-map (zoom, x, y) integer-coordinate columns for spatial-grid range queries.**

**Key facts extracted**:
- DB engine: PostgreSQL (vanilla, no extensions).
- Spatial index strategy: pure btree composite on slippy-map integer coordinates `(tile_zoom, tile_x, tile_y, version)` for spatial-grid range queries; secondary btree on lat/lon for inverse-geocode lookups.
- Tile bytes: filesystem at canonical slippy-map path `./tiles/{zoom}/{x}/{y}.jpg`.
- DB ↔ filesystem coupling: `file_path VARCHAR(500)` pointer in DB.
- Migration mechanism: numbered SQL files as `EmbeddedResource`, run automatically on startup via `DatabaseMigrator.cs`.
- App layer: .NET 8.0 + Dapper + raw SQL repos.

**Implication**: For the on-Jetson C6 (which is Python/C++, not .NET), the equivalent stack is `psycopg[binary]` or `asyncpg` Python driver + raw SQL queries against the same schema pattern.

---

### Source #93 — PostgreSQL official documentation: btree multi-column index ordering and range query optimization

**Title**: PostgreSQL 16 documentation — "Multicolumn Indexes" + "Indexes and ORDER BY" + "EXPLAIN" + "btree access method"
**Tier**: L1 — official authoritative docs
**URL**: <https://www.postgresql.org/docs/current/indexes-multicolumn.html> + <https://www.postgresql.org/docs/current/btree.html>
**Access date**: 2026-05-08
**Direct verification**: pending WebFetch
**Key facts to extract**:
- Btree multicolumn index supports range queries on the leading prefix (i.e., `WHERE tile_zoom = ? AND tile_x BETWEEN ? AND ?` uses the index optimally).
- Btree composite index access time: O(log N) where N = total rows.
- Storage overhead: typically ~50-100 bytes per index entry depending on column types.

**Use**: backs Fact #92 sub-matrix entries on AC-4.1 (latency) and AC-4.2 (memory) for Cand 1.

---

### Source #94 — PostGIS official documentation: GiST spatial index on geography type + KNN distance ordering

**Title**: PostGIS 3.4 documentation — "GiST Indexes" + "geography Type" + "PostGIS Special Functions Index" + "ST_DWithin" + "<-> KNN operator"
**Tier**: L1 — official authoritative docs (OGC SFS-compliant canonical extension)
**URL**: <https://postgis.net/docs/using_postgis_dbmanagement.html#idx-spgist> + <https://postgis.net/docs/geography.html> + <https://postgis.net/workshops/postgis-intro/knn.html>
**Access date**: 2026-05-08
**Direct verification**: pending WebFetch
**Key facts to extract**:
- GiST index access time on `geography(POINT,4326)`: O(log N) for bounding-box pre-filter; full geographic distance check is exact (not approximate).
- KNN ordering via `ORDER BY position <-> ST_MakePoint(?, ?)::geography LIMIT K` is index-optimized in PostGIS 2.0+.
- `ST_DWithin(position::geography, ST_MakePoint(?, ?)::geography, radius_m)` supports radius queries with native great-circle distance.
- PostGIS extension installed footprint: typically ~30-50 MB shared libraries + ~10-20 MB SRID/projection metadata catalog.

**Use**: backs Fact #93 sub-matrix entries on AC-4.1 (latency) and AC-4.2 (memory) for Cand 2 + comparative-improvement-vs-Cand-1 analysis.

---

### Source #95 — pgvector official documentation: HNSW index for vector similarity search

**Title**: pgvector — "Open-source vector similarity search for Postgres" (`pgvector/pgvector`)
**Tier**: L1 — canonical implementation by Andrew Kane
**URL**: <https://github.com/pgvector/pgvector> + context7 indexed via `/pgvector/pgvector`
**Access date**: 2026-05-08
**Direct verification**: pending context7 + WebFetch
**Key facts to extract**:
- HNSW index API: `CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)` + `CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops)` + `CREATE INDEX ON items USING hnsw (embedding vector_ip_ops)`.
- Default tunable parameters: `m=16` (max connections per layer) + `ef_construction=64` (build-time candidate list size); query-time `ef_search` (default 40).
- Vector dimension limits: pgvector 0.7+ supports up to 16,000 dimensions for HNSW; 2,000 dimensions for IVFFlat.
- Memory footprint: extension itself ~5-10 MB shared library; per-vector storage = 4 bytes × dimensions (so 2048-D = 8 KB/vec, 1024-D = 4 KB/vec, 512-D = 2 KB/vec, 256-D = 1 KB/vec).

**Use**: backs Fact #93 sub-matrix on descriptor ANN side for Cand 2 + comparative cache footprint analysis.

---

### Source #96 — FAISS official documentation: in-memory ANN library + Python bindings

**Title**: FAISS — "A library for efficient similarity search and clustering of dense vectors" (`facebookresearch/faiss`)
**Tier**: L1 — canonical implementation by Meta AI Research
**URL**: <https://github.com/facebookresearch/faiss> + <https://faiss.ai/>
**Access date**: 2026-05-08
**Direct verification**: pending WebFetch + context7
**Key facts to extract**:
- Index types relevant to C6 descriptor ANN: `IndexFlatL2` (brute-force, exact), `IndexHNSWFlat` (HNSW graph, approximate), `IndexIVFFlat` (Inverted File, approximate w/ training).
- Memory: in-memory only at query time; loaded from disk via `faiss.read_index(path)` at startup.
- License: MIT.
- Python API: `faiss.IndexFlatL2(d)` / `faiss.IndexHNSWFlat(d, m)` / `index.add(xb)` / `D, I = index.search(xq, k)`.

**Use**: backs Fact #92 sub-matrix on descriptor ANN side for Cand 1 (app-side FAISS in-memory loaded at takeoff from Postgres bytea blobs).

---

### Source #97 — Postgres on NVIDIA Jetson Orin Nano memory footprint and JetPack 6 deployment

**Title**: PostgreSQL on ARM64 / Ubuntu 22.04 (JetPack 6 base) — official packaging + Docker images
**Tier**: L1 — official Postgres ARM64 packages + Docker `postgres:16-alpine` image documentation
**URL**: <https://hub.docker.com/_/postgres> + <https://www.postgresql.org/download/linux/ubuntu/>
**Access date**: 2026-05-08
**Direct verification**: pending WebFetch
**Key facts to extract**:
- ARM64 packages available for Postgres 16 on Ubuntu 22.04 (JetPack 6 base).
- Default `shared_buffers=128MB` + `work_mem=4MB` resident footprint ~80-150 MB on idle; ~200-400 MB under modest load.
- Docker `postgres:16-alpine` image size: ~250 MB compressed.
- PostGIS Docker image `postgis/postgis:16-3.4-alpine` adds ~50-80 MB to base postgres image.

**Use**: backs both Fact #92 + Fact #93 sub-matrix entries on AC-4.2 (8 GB shared memory budget) for the Postgres-on-Jetson deployment.

---

### Source #98 — Slippy Map Tilenames specification (OpenStreetMap canonical reference)

**Title**: Slippy Map Tilenames — XYZ tile coordinate system + Web Mercator projection
**Tier**: L1 — canonical convention documented by OpenStreetMap Foundation
**URL**: <https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames>
**Access date**: 2026-05-08
**Direct verification**: pending WebFetch
**Key facts to extract**:
- Tile X/Y math: `xtile = floor((lon + 180) / 360 * 2^zoom)` + `ytile = floor((1 - asinh(tan(lat * π/180)) / π) / 2 * 2^zoom)` — matches satellite-provider migration 011 exactly.
- Tile coverage: at zoom Z, world divided into 2^Z × 2^Z tiles; each tile covers `360/2^Z` longitude × variable-latitude.
- Project zoom: ZoomLevel 18 (per satellite-provider README default) covers ~38m × 38m at equator (cited as "tileSizeMeters: 38.2" in README sample response).
- Cache budget per AC-8.3 (10 GB): at typical JPEG ~30 KB/tile, fits ~330,000 tiles = roughly an area of 50 km × 50 km × 9 zoom levels OR a single mission corridor at zoom 18 of ~1000 km × 12 m.

**Use**: backs both Fact #92 + Fact #93 sub-matrix entries on AC-8.3 (10 GB cache budget) + AC-3.x (mission corridor coverage).

---

(Subsequent sources #99+ added during fact extraction below as candidate-specific evidence is gathered.)
