Define the envelope, topic namespace and OBD-II signal registry

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013kj58Jugkic783b8ZrtTVZ
This commit is contained in:
2026-09-05 12:54:14 +09:00
commit 8f490aba8e
8 changed files with 317 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
---
type: guidelines
---
# Contract guidelines
## 1. `signals.json` is the single source for a signal's identity
- Topic name and the envelope's `unit` are both **derived** from a registry entry.
Neither is authored by hand anywhere else.
- ⚠ **The unit appears in both the topic name and the payload, so they can
contradict each other.** Generating both from one entry is what stops that; a
hand-written `"unit"` reintroduces the failure it was meant to prevent.
- Signal names carry their unit (`vehicle_speed_kph`, `coolant_temp_c`), so a unit
mismatch is visible at the call site rather than one registry lookup away.
## 2. Two clocks, and they answer different questions
- `monotonic` is authoritative for **ordering and intervals**. It cannot step.
- `timestamp` is the **absolute reference** and can step: the car boots with no
network, LTE connects several minutes in, and NTP corrects the clock mid-drive.
- ⚠ **Never derive a duration from `timestamp`.** A step lands inside the interval
and the result is silently wrong, most likely during exactly the drive worth
keeping. Durations come from `monotonic`.
## 3. Raw CAN is not the envelope
- `yukart/can/raw` is binary. A four-key JSON object at 1000–3000 frames/sec is
not a reasonable encoding.
- The envelope is for decoded signals, which are low-rate by comparison.
## 4. Absent means default
- `quality` is omitted when `ok`; `mock` is omitted when false. A consumer treats
absence as the default, never as an error.
## 5. This repo is versioned by git tag
- There is no version in any topic or payload. A recorded session names the
contracts tag it was captured under, which is what keeps old captures readable.
## 6. To be added
+39
View File
@@ -0,0 +1,39 @@
---
type: plan
status: active
updated: 2026-09-05
---
# Initial plan
## What is defined
The envelope, the topic namespace, and the standard OBD-II signals — the ones
whose names, units and ranges are fixed by the standard rather than by the car.
## What is not
**Z27AG-specific signals.** They do not exist until Phase 2 identifies them from
observed traffic. They arrive as DBC entries plus registry rows with
`source: "z27ag"`, one at a time as each is confirmed.
**Composite payload shapes.** `gnss/fix`, `nav/guidance`, `nav/route` and
`system/<service>` have their fields named in `topics.json` but no JSON Schema
yet. They get one when a publisher exists to constrain.
## Order
1. Schema validation available to all three languages — the Rust services, the
Python fixtures and the Dart client must reject a malformed message
identically, or the contract is decorative.
2. `gnss/fix` schema, driven by what `tool-mock` replays.
3. Z27AG signals, as Phase 2 confirms them.
## Consumers
| Repo | Reads |
|---|---|
| `svc-core` | signals, envelope, DBC |
| `svc-gw` | topics, envelope |
| `svc-nav` | topics, envelope |
| `app-flutter` | topics, envelope, signals (for display units) |
| `tool-mock` | all of it — fixtures publish the real schema |
View File