# Changelog — Map All notable changes to the Map standard and its reference implementation. Format follows Keep a Changelog; the standard versions independently of the reference crates (which share the `map-rs` workspace version). ## [0.1.0] — 2026-06-04 Initial draft standard — the protocol spine. ### Added - **Specification.** `SPEC.md` (RFC 2119) defining the tile cargo, the 4D cell key, canonical serialization + content addressing, the range-requestable tileset + signed manifest/revision chain, the F0–F4 fidelity cascade, and the JCR-1 receipt. Sub-specs under `spec/`. - **`map-schema`** — `CellKey` (S2 + altitude band + time bucket + LOD), `ContentId`, `Tile`, `Directory` (Hilbert-sorted + range planner), `Manifest`, `Revision`, `verify_chain`, and the `Tier` enum. - **`map-cascade`** — `resolve` over a `TileSource`, returning the highest tier ≤ the request with a guaranteed F1 fallback. - **`map-receipt`** — `Receipt`, `Energy`, `Provenance`, JCR-1 sealing/verifying (vendored, byte-compatible with the family verifiers). - **`map-conformance`** — C1–C5 + C-neg harness (all checks real) and the `gen-vectors` generator; published vectors in `conformance/v1/`. - **Vocabulary.** `vocab/v1.ttl`, `v1.jsonld`, `v1.shapes.ttl`, `LEXICON.md`. - **`map-index`** — pure-Rust S2 cell geometry (cell ids, projection, lat/lng, points, edges, polygons, regions/caps/rects, the region coverer, metrics) ported from `joule-s2`, plus a `bridge` to `map-schema`: `cell_key` from coordinates, and `cover_region`/`cover_viewport` from a cap, rectangle, or **polygon** to sorted `CellKey`s feeding the directory range planner. 75 tests, zero clippy warnings. - **Fixed (vs. upstream `joule-s2`)** the `polygon` module, which failed its own tests upstream: spherical point-in-polygon now uses an orientation-robust winding-angle test (was a degenerate ray); area uses the van Oosterom–Strackee signed-area fan (was Girard's-formula complement, ≈4π−A); and `S2Polygon` now implements `S2Region`, so the coverer accepts arbitrary boundaries / footprints / geofences. - **`map-index::volume`** — the recommended 4D discretization scheme ported from `joule-spatial3d`: logarithmic `AltBand`s (Mariana Trench → cislunar), logarithmic `TimeTier`/`TimeBucket`s (1 s → 100 yr), `SpaceTimePoint`, `SpatialKey`, and the `Spatial3DIndex`/`PositionRingBuffer` runtime utilities. New bridge functions `alt_band`, `time_bucket`, and `cover_volume` map the scheme into `map-schema` `CellKey`s and cover a horizontal region × altitude range × time range. (The `chrono` convenience constructors were dropped to keep the reference dependency-light.) - **`map-tiles`** — tile payload codecs ported from `joule-tiles`: MVT vector, raster (PNG/WebP), terrain quantized-mesh, and 3D Tiles, with no S2/geo or routing dependency. A `tile` bridge wraps each as a content-addressed `map-schema` `Tile` at its cascade tier — terrain → `F1`, raster → `F2`, MVT + b3dm → `F3`, splat → `F4` — with stable `codec` tags. - **`map-tiles` splat codec** (`map_tiles::splat`) — the `F4:Photoreal` cargo codec the tier was missing: a compact SPZ-style container for 3D Gaussian splats (positions fixed-point, scales log-quantized, rotation quaternion + colour as bytes, gzip-compressed), with `encode_splats`/`decode_splats`. **Spherical harmonics**: encodes degree-`n` view-dependent colour as `(n+1)²−1` quantized RGB coefficients above the DC term (`sh_degree` in the header). Round-trip (incl. degree-1 SH) + compression tests. - **`map-tiles` PLY ingest** (`map_tiles::splat::read_ply`) — reads the de-facto **INRIA `.ply`** 3DGS interchange format (ASCII + binary-little-endian), inverting the trainer's storage conventions (log-scales → `exp`, logit-opacity → `sigmoid`, `(w,x,y,z)` → `(x,y,z,w)` normalized, DC `= 0.5 + C₀·f_dc`, channel-major `f_rest` → per-coefficient SH) into `Splat`s that `encode_splats` re-encodes into a conforming F4 tile. ASCII + binary + rejection tests. - **`map-tiles` b3dm / glTF decode** (`map_tiles::tiles3d::read_b3dm`, `read_glb`) — the reader half of the 3D Tiles codec: strips the b3dm header + feature/batch tables and decodes the embedded binary glTF (GLB) into a triangle mesh, general over accessors/bufferViews (f32 VEC3 positions; u8/u16/u32 indices; accessor + bufferView byte offsets and strides; multi-primitive merge). Round-trips `B3dmBuilder::encode`; encode/decode + u16-index + rejection tests. - **`map-serve` crate** — a transport-agnostic tile-serving core (no HTTP-framework dependency): `serve(store, steward, req)` parses a tile request, resolves it through the F0–F4 cascade, and returns a content-addressed `Response` with a strong `ETag`, `Cache-Control: immutable`, `If-None-Match` → `304`, `X-Map-Tier` / fell-back, and a JCR-1 energy-receipt header. Includes a `MemoryStore` reference `TileServer`, plus a filesystem `DirStore` (content-addressed blobs on disk + a reloadable JSON index; `std`-only). Pure + unit-tested with a runnable doctest. - **`map-serve-axum` crate** — an axum/tokio HTTP binding for the serving core: `router(store, steward)` exposes `serve` as an axum `Router`, `run(addr, …)` is a one-call server. The async stack is isolated here so `map-serve` stays framework-free. Verified by `oneshot` tests and a live-socket demo over real HTTP. - **`map-route` turn-by-turn + isochrones** — `directions::turn_by_turn` derives human maneuvers (depart with cardinal heading, slight/normal/sharp turns, U-turn, arrive) from route-segment bearing deltas, merging straight runs into one step; `isochrone::isochrone` computes the budget-bounded reachable set from a source by travel time or distance (Dijkstra expansion with pruning). Both unit-tested. - **`map-route` multi-modal + traffic-aware costs** — a `CostModel` trait and a built-in `ModeProfile` (car/bicycle/foot) with per-mode road-class access matrices, free-flow speeds, and a congestion multiplier; `cost::find_route_with` is a generalized A* (admissible time heuristic) that skips inaccessible edges and reports mode-specific durations. `RoadType` is now `Copy`. Unit-tested (mode access, highway avoidance on foot, traffic slowdown). - **`map-route` public-transit routing** (`transit`) — the Connection Scan Algorithm over a GTFS-like `Timetable`: earliest arrival from timetabled `Connection`s with walking-footpath transfers (manual or auto-generated within a radius), reconstructing ride/walk `Leg`s. Times are integer seconds. Unit-tested (line with wait, missed connection, faster-of-two, footpath transfer, auto-transfers). - **`map-tiles` MVT decoder** — added the reader half (`mvt::decode_tile`, `decode_geometry`, `unzigzag`): a minimal protobuf reader inverse to the encoder, plus the geometry-command decoder back to absolute tile-local rings / line-strings. A conforming reader must decode to render; the encoder shipped without it. Encode→decode roundtrip tests cover geometry + properties + closed polygons. (Not in upstream `joule-tiles`.) - **Real-world robustness fix:** `decode_value` now handles MVT `sint_value` (field 6, zigzag), decodes `int_value` (field 4) as a plain varint per spec (was wrongly zigzag), and tolerates an empty/unknown value instead of aborting the whole tile. Verified by decoding live OpenMapTiles tiles (OpenFreeMap) — previously failed with `ProtobufError("empty value")`. - **Fixed (vs. upstream `joule-tiles`)** `mvt::encode_polygon`, which clobbered the `CMD_MOVE_TO` command word with a coordinate and reset the geometry cursor per ring (malformed multi-ring polygons); added the missing regression test. Backported to `joule-tiles`. - **`map-orbital`** — TLE parsing, SGP4/SDP4 propagation, and ECI/ECEF/geodetic transforms ported from `joule-orbital` (no `tracing` dependency; only the doctest referenced it). A `bridge` maps a propagated satellite sub-point to a `map-schema` `CellKey` — S2 cell at the sub-point, the altitude band for its altitude (the ISS lands in the LEO band), and the time bucket for the instant — so a live satellite is an `F3` address on the same 4D grid as every tile. Lint cleanups only; the 38 SGP4/SDP4 known-answer tests confirm the numerics are unchanged. - **`map-route`** — local geospatial capabilities over a tileset, ported from `joule-maps` (energy metering, tile cache, and the in-memory store dropped — redundant with `map-receipt`/`map-tiles`/`map-schema`): WGS84 geometry, haversine/bearing/midpoint, point-in-polygon, POI geocoding, Dijkstra + A* routing on a weighted graph, and polygon geofencing. Added a **feed-agnostic adapter** (`feed::{Entity, Feed}`): any source — flights, vessels, satellites, CVEs, incidents, supply-chain nodes, enterprise signals — resolves to a `CellKey`, so "swap the feeds and it visualizes anything with a location or a time" is a property of the standard, not a per-feed rewrite. Tests cover the ported geocode/route/geofence/geometry paths (the upstream tests did not come with the extracted subset). - **`map-schema`** — `TimeBucket.width_ms` widened `u32 → u64` so the temporal axis can express coarse archival buckets (a year, a century); `u32` capped it at ~49 days. CBOR encodes integers by magnitude, so existing content ids and conformance vectors are byte-identical. ### Notes - The remaining substrate crates (`map-index` 4D layer from `joule-spatial3d`, `map-tiles`, `map-orbital`, `map-route`) and the demonstrator's `wgpu` renderer are not yet in this release — see [`ROADMAP.md`](ROADMAP.md).