open-standards/map/SPEC.md
Transaction Science ba1212361f Add aac, map, sandbox standards; catalog the standards family
Commit the previously-untracked standard directories and catalog them in the
root README alongside proof:

- aac/    — communication cargo class: portable boards + a ten-level
            offline-first cascade (Apache-2.0 code / CC-BY-4.0 spec).
- map/    — geospatial cargo class: range-requestable signed tilesets +
            an F0–F4 fidelity cascade (Apache-2.0 code / CC-BY-4.0 spec).
- sandbox/— isolated, metered, attested execution across the heterogeneous
            compute fabric (Apache-2.0 code / CC-BY-4.0 spec).
- jouleclaw-otel-authz, jouleclaw-trust — new jouleclaw reference crates.

Root README now lists aac, map, sandbox, and proof in the catalog, the tree,
and the contribution guide.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-07 17:04:36 -04:00

130 lines
12 KiB
Markdown

# Map v0.1 — A Carrier for Place
Status: **Draft Standard**. Reference implementation: [`map-rs/`](map-rs/) (Rust workspace, Apache-2.0). Specification text: CC-BY-4.0.
The keywords **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as described in RFC 2119.
---
## 1. Scope and doctrine
Map specifies how a region of the world — at a place, an altitude, an instant, and a fidelity — is identified, addressed, resolved through an energy-tiered fidelity cascade, and reported with its energy cost. It is the **geospatial cargo class** of the Transaction Science substrate. Where [Smart Byte](../smart-byte/) carries value, [Joule Code](../joule-code/) carries coding work, and [EOC](../eoc/) carries compute, Map carries **place**.
The **doctrine** is one sentence: *the map is a file, not a service.* Three normative consequences follow.
### 1.1 The tile is the cargo (REQUIRED)
The unit of place is a **tile**: a content-addressed, signed unit of the world at a single 4D cell, with its energy cost intrinsic. A tile is not an image and not an API response. It is a vesicle carrying exactly five things — identity (the BLAKE3 content address of its canonical serialization), a cell key (where/when/how-detailed it is), provenance (the prior tileset root it was published under, and the author key that signed it), cargo (the payload — terrain, a field, vector features, or splats), and a two-part joule cost (`measured + estimated`, honestly tagged).
### 1.2 The cascade (REQUIRED)
A conforming resolver **MUST** resolve every render request through an explicit energy-tiered **fidelity cascade**, **MUST** return the highest tier that is at or below the requested fidelity *and* holds data for the cell, and **MUST** fall back toward the base floor — which always closes the request. The tiers are energy-ordered:
| Tier | Wire tag | Named tag | Joule class | Payload for a render request |
|------|----------|------------|-----------------|-------------------------------------------------------------------------|
| F0 | `F0` | Cache | picojoules | content-addressed tile already resolved in the local store (OPFS) |
| F1 | `F1` | Base | microjoules | terrain DEM + coastlines + borders — the universal floor, always present |
| F2 | `F2` | Field | sub-millijoules | raster + scalar/vector field tiles (imagery, weather grids, wind) |
| F3 | `F3` | Feature | millijoules | vector feature tiles (roads, POIs, labels, airspace) + live entities |
| F4 | `F4` | Photoreal | joules | 3D Gaussian splats — dense, sparse-coverage; the escape hatch |
A resolver **MUST NOT** return a tier above the requested fidelity. A resolver **MUST NOT** fail a render request for a covered region: F1 **SHALL** be defined everywhere on the datum, so graceful fallback is a property of the standard, not of an implementation. A resolver **MUST** record in the receipt the tier that actually closed the request. F0 is the cache short-circuit and **MAY** close any request whose cell key was previously resolved.
> The cascade is inverted relative to compute cascades (JouleClaw, Joule Code) only in *intent*: there the cheapest sufficient tier wins; here the highest *available* tier at or below the request wins, with the cheap floor as the guaranteed fallback. The shared invariant is identical — **stop at the first tier that closes the request, and record it.**
### 1.3 The receipt (REQUIRED)
Every resolve/decode operation **MUST** report a two-part energy cost in integer microjoules — `measured + estimated` — with a `Provenance` tag (`HwShunt | ModelBased | Estimator`) on every reading, sealed as a **JCR-1** envelope (canonical det-CBOR + COSE_Sign1/EdDSA — the family's shared signed-receipt format). A `measured` figure **MUST** originate from a hardware energy interface; the spec never claims an accuracy the platform cannot deliver.
---
## 2. The cell key
A tile is addressed by a 4D **cell key** with four orthogonal axes (`map-schema::CellKey`):
```
CellKey {
s2: S2CellId, // horizontal position + extent (hierarchical, levels 0..30)
alt: AltBand, // altitude band index (signed; band 0 = datum surface)
time: TimeBucket, // half-open [start, start+width) interval; bucket 0 = atemporal
lod: Lod, // 0..=MAX detail level within the tier
}
```
- **Horizontal (REQUIRED).** The `s2` axis **MUST** be an S2 cell identifier. S2 is a hierarchical, space-filling (Hilbert-ordered) decomposition of the sphere: adjacent cells are adjacent in the integer key space, which is what makes a tileset range-requestable (§4). An implementation **MUST** treat the S2 level as the horizontal LOD.
- **Vertical (REQUIRED).** The `alt` axis **MUST** be a signed band index against a declared band schedule (`map-schema::AltSchedule`). Band 0 is the datum surface; negative bands are sub-surface; positive bands are altitude. Atmospheric and orbital payloads occupy positive bands; bathymetry occupies negative bands.
- **Temporal (REQUIRED).** The `time` axis **MUST** be a `TimeBucket`: a half-open interval anchored to TAI. Bucket 0 is reserved for **atemporal** tiles (a coastline, a border). A weather forecast cycle, an AIRAC navigation cycle, and an ADS-B snapshot are distinct, non-zero buckets. The temporal axis is first-class: a "map of Tuesday at 14:00Z" is a different, equally addressable region from "the same place on Wednesday."
- **Detail (REQUIRED).** The `lod` axis is the within-tier detail level, independent of the S2 level (which is the horizontal extent). A splat tile at S2 level 20 **MAY** carry LODs 0..N of progressively denser Gaussians.
Two cell keys are equal iff all four axes are equal. The canonical serialization of a `CellKey` (§3) is deterministic, so its BLAKE3 hash is a stable join key across implementations.
---
## 3. Canonical serialization and content addressing
Every Map structure that is hashed or signed **MUST** be serialized with the family's deterministic CBOR profile (det-CBOR: definite-length, canonically-ordered keys, no floats where an integer suffices). The **content id** of a tile is `blake3(canonical_serialization)` (`map-schema::ContentId`, 32 bytes). Content ids are the only cross-reference Map uses internally: a tileset directory maps cell keys to content ids; a manifest commits to content ids; a receipt references the content ids it resolved.
A tile is **immutable**: changing any byte changes its content id and therefore its identity. There is no in-place edit. Revision happens at the tileset level (§5).
---
## 4. The tileset (REQUIRED)
A **tileset** is the on-disk, range-requestable archive — the "it's just a file" deliverable. A conforming tileset is a single addressable blob on dumb storage (object store, static host, OPFS) with three parts:
1. A **header** with a magic tag, the standard version, the datum, the alt schedule, and the byte offset of the directory.
2. A **directory** mapping `CellKey → (byte_offset, byte_len, content_id)` for every tile in the set, **MUST** be ordered by the S2 (Hilbert) key so that the tiles of one viewport occupy a near-contiguous byte range. A reader **MUST** be able to fetch the directory, compute the cell keys a viewport needs, and issue HTTP range requests for only those byte ranges — no server-side logic, no per-request billing.
3. The **tile payloads**, content-addressable and independently decodable.
A reader **MUST NOT** be required to download the whole tileset to render a viewport. A reader **MUST** verify that each fetched payload hashes to the `content_id` the directory claims.
---
## 5. The manifest and signed transitions (REQUIRED)
A tileset's authenticity rests on a signed **manifest** (`map-schema::Manifest`): a commitment to the directory root (a BLAKE3 Merkle root over the sorted `CellKey → content_id` pairs), the publisher's Ed25519 public key, the standard version, and the cell-key bounds of the set. The manifest **MUST** be signed (Ed25519 over the det-CBOR of the manifest body).
A **revision** is a signed transition `prev_root → new_root` (`map-schema::Revision`): a new manifest that names the root it supersedes and is signed by the same publisher key (or a successor key it endorses). Revisions are **append-only and dated** (each carries a TAI timestamp). A new weather forecast hour, a new 28-day AIRAC cycle, and a re-flight of a corridor are revisions — never in-place mutations. A reader **MAY** pin any historical root and **MUST** be able to verify a revision chain back to a trusted root without contacting the publisher.
This is the "works forever" guarantee made normative: a newsroom's election map, an archived flight plan, or a forecast cycle is a signed, dated file whose validity does not depend on any service remaining online.
---
## 6. Energy and the receipt (REQUIRED)
The receipt is the family's JCR-1 envelope (`map-receipt`). A receipt **MUST** carry:
- the `CellKey` and `content_id` of the tile(s) it covers;
- the cascade `Tier` that closed the request;
- an `Energy` record: `measured_uj: Option<u64>`, `estimated_uj: u64`, `provenance: Provenance`;
- the publisher/resolver identity and an Ed25519 signature (COSE_Sign1/EdDSA over canonical det-CBOR).
The provenance coupling is normative: `HwShunt` **REQUIRES** a present `measured_uj`; `Estimator` **MUST** leave it absent; `ModelBased` **MAY** include it. A session's total cost is the sum of its tile receipts. A resolver **MUST NOT** report a `measured` figure it did not measure.
A reference (non-normative) estimator orders the tiers by joule class: a cache hit is picojoules; a base/terrain tile is microjoules; a field tile is sub-millijoules; a feature/entity tile is millijoules; a splat tile is joules. The standard is that the figure is reported and honestly tagged — not the constant.
---
## 7. No capture (REQUIRED)
Map carries no protocol-level token. Reading a tileset **MUST** require nothing but the bytes and the publisher's public key. A conforming reader performs its core function — resolve a cell, verify it, render it, meter it — against static storage, with no contact with any single company's servers as a condition of operation. Transaction Science is one steward: it publishes the spec, ships the reference implementation, and operates optional commercial services (capture pipelines, hosted tilesets, a registry) around the substrate — not its proprietor.
---
## 8. Conformance
An implementation is **conformant** if it round-trips the vectors in [`conformance/v1/`](conformance/v1/):
- **C1 — cell key.** Canonical serialization and `ContentId` of the cell-key vectors match byte-for-byte.
- **C2 — tileset directory.** A reader resolves the correct byte range for a viewport over the sample tileset and verifies every payload hash.
- **C3 — manifest & revision.** Signature verification and revision-chain validation against the sample roots; a tampered directory root **MUST** fail.
- **C4 — cascade.** For each render-request vector, the resolver closes at the specified tier and falls back to F1 where higher tiers are absent.
- **C5 — receipt.** JCR-1 receipts seal, verify, and enforce the provenance ↔ measured coupling; vectors are interoperable with the family's existing JCR-1 verifiers.
A negative pack (`C-neg`) covers tampered payloads, an out-of-order directory, a revision signed by an unendorsed key, and a receipt claiming `HwShunt` with no `measured_uj`.
---
## 9. Non-goals
Map is a **substrate for read-heavy, published geospatial data**. It is explicitly **not** a live geocoding/routing *service* (the reference ships `map-route` as a local capability over a tileset, not a hosted API), and it is **not** a certified primary navigation source. Air-navigation payloads are for **situational awareness, planning, and simulation only** — never a DO-178C/TSO-certified source of primary flight guidance. A conforming flight-nav tileset **MUST** carry this disclaimer in its manifest metadata.