open-standards/map/SPEC.md
Transaction Science fca3f76e51 specs: a vendor counter is a hardware reading only while it is demonstrably live
The monorepo's IOReport energy backends now decline unless the CPU energy
rail keeps advancing: on macOS 27 an unprivileged reader sees the CPU rails
frozen or republished only in rare lumps, so a meter that trusted a present
counter reported CPU work as GPU-only energy, or as zero, while tagging it a
reading. The owner's decision is that a vendor energy counter is a real
reading (the trust gap is provenance, not accuracy), so a LIVE reading is
graded as a hardware reading, and every spec that grades vendor counters now
carries the same rule:

  A reading from a vendor energy counter (RAPL, NVML, Apple IOReport, ...)
  MAY be graded as a hardware reading only while the counter is demonstrably
  live for the domain the figure claims: the implementation MUST have
  observed the counter covering that domain advance under load (for Apple
  IOReport: the CPU energy rail itself advancing in at least 5 sample
  intervals, in at least 4 of every 5, over at least 300 ms while the probing
  thread burns CPU). A counter that is present but not live - frozen, or
  republished in lumps - MUST NOT produce a hardware-graded figure; the
  implementation falls back to its estimator or reports the work unmetered,
  and SHOULD record why. A figure MUST NOT claim coverage of a domain its
  counter does not read; where the format has a coverage field, such a
  figure is Partial.

Joule Code
- spec/receipt.md §2 (REQUIRED): HwShunt now reads "an external shunt, or a
  vendor energy counter (RAPL, NVML, Apple SMC/IOReport) while that counter
  is live"; the rule above is added verbatim, and in this receipt the
  hardware grade is a present measured_uj and the HwShunt tag, so a counter
  that is not live supplies neither. The §1 comment and §5 say "live".
- SPEC.md §6: the provenance definition now names IOReport and NVML beside
  RAPL/SMC, measured_uj comes only from an interface live for the domain it
  claims, and a paragraph states the MAY/MUST NOT, pointing to receipt.md §2
  for the test. The §9 readiness row says "live" and "not live".
- ROADMAP.md v0.2 "Measured energy": a vendor counter feeds the HwShunt path
  only while live; where it is present but not live (IOReport's CPU rails to
  an unprivileged reader on macOS 27) the receipt stays on the estimator.
- examples/l3-jouleclaw/README.md: the claim that the receipt is "a real
  local measurement ... (HwShunt on RAPL/NVML hosts; Estimator on Apple
  Silicon until IOReport is wired)" was wrong both ways: run.rs wires only
  Apple Silicon's counter, and other hosts fall to the token Estimator. It
  now says so, that the counter's own tag is carried, and that HwShunt needs
  a live counter.
- joule-code-receipt: the Provenance::HwShunt doc comment says the same.
- CHANGELOG.md [Unreleased] ### Changed: the rule; no wire or vector change.

Sense
- SPEC.md §7 (REQUIRED): measured_uj comes only from a live interface; the
  rule is added verbatim. The Sandbox PowerMeter was described as "(real
  RAPL/IOReport)"; it is now described as grading a reading HwShunt only
  while its counter is live and falling back to its estimator otherwise,
  which is what origin/sandbox-meter/cpu-rail-liveness implements. §10's
  Sandbox edge says the same in brief.
- sense-schema: the HwShunt, Energy and Energy::measured doc comments say a
  vendor counter is a hardware reading only while live.
- Sense keeps no CHANGELOG, so none is added.

Other specs that grade vendor counters
- map/spec/receipt.md §2: the HwShunt row read "RAPL/SMC/shunt"; it now
  names a counter "while it is live", and the rule is added verbatim, noting
  that Receipt::seal cannot check liveness (the meter's duty, upstream).
  map/SPEC.md §6 states the MUST NOT and points there. CHANGELOG.md gains an
  [Unreleased] ### Changed entry; no wire or vector change.
- arl/ARL-S.md, Telemetry: physical telemetry is what gates tiers above 0,
  and it said energy is "measured directly via RAPL ... NVML". The rule is
  added in ARL-S's own terms and lower-case keywords (ARL uses no RFC 2119
  capitals): a counter that is not live does not produce physical telemetry,
  the energy it would have covered is reported unmetered, and the Supervisor
  must have observed the counter advance. No version bump.
- smart-byte treatise §8.6: "Where RAPL or equivalent hardware energy
  counters are available, the measurement is read from the hardware" now
  requires the counter to be demonstrably live, and a frozen or lump-
  republished counter yields the same honest zero as an absent one.

Text and doc comments only: no code path, wire format, or conformance
vector changes. joule-code-rs (joule-code-receipt, joule-code-conformance)
and sense-rs (sense-schema, sense-conformance) build and test clean, their
rustdoc builds under -D warnings, map-rs (map-receipt, map-conformance)
tests pass, `joule-code-conformance verify ../conformance/v1` passes
24/0/0, the no-vanity-metrics check passes, and every relative link in the
changed Markdown resolves.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 01:10:36 -04:00

12 KiB

Map v0.1 — A Carrier for Place

Status: Draft Standard. Reference implementation: 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 carries value, Joule Code carries coding work, and 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. A schedule's width_m MAY be +∞ — a single unbounded surface band, the 2.5D case; JSON has no infinity, so its JSON form is null, which MUST be read back as +∞, while the canonical CBOR (§3) carries the float itself.
  • 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 vendor energy counter (RAPL, NVML, Apple IOReport, ...) grades a figure HwShunt only while it is demonstrably live for the domain the figure claims; a counter that is present but not live — frozen, or republished in lumps — MUST NOT produce one (spec/receipt.md §2).

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/:

  • 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.