Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This repository is documentation-only. It contains no runtime implementation cod
| Gateway API | [gateway-api/v1.md](gateway-api/v1.md) | Implemented baseline |
| CLI commands | [cli-commands/v1.md](cli-commands/v1.md) | Contract target; runtime entrypoint implemented |
| Runtime health socket RPC | [runtime-health/v1.md](runtime-health/v1.md) | Implemented |
| Runtime telemetry HTTP export | [runtime-telemetry/v1.md](runtime-telemetry/v1.md) | Implemented baseline |
| Device policy | [device-policy/v1.md](device-policy/v1.md) | Implemented baseline |
| Offline Tier C tokens | [offline-tokens/v1.md](offline-tokens/v1.md) | Implemented baseline |
| Runtime config surface | [runtime-config/v1.md](runtime-config/v1.md) | Implemented baseline |
Expand Down
16 changes: 16 additions & 0 deletions runtime-config/v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ attested by `state.encryption`.
| `max_clock_skew_s` | `int` | Must be `>=1` |
| `refresh_interval_s` | `int` | Must be `>=60` |

## `telemetry_export`

| Key | Type | Notes |
|---|---|---|
| `enabled` | `bool` | Disabled by default. Enables direct HTTP export to a product backend. |
| `endpoint` | `string` | Absolute HTTP(S) URL. Must use `https://` unless targeting loopback. |
| `api_key_env` | `string` | Environment variable name holding the device API key. |
| `flush_interval_s` | `float` | `1..300` seconds. |
| `batch_size` | `int` | `1..500` events per POST. |
| `timeout_ms` | `int` | `100..30000` request timeout. |
| `max_queue_size` | `int` | Must be greater than or equal to `batch_size`. |

This config surface implements `runtime-telemetry/v1.md`. It mirrors
`sensor.reading` events only and must not be used for runtime mutation or
actuator authority.

## `health_socket`

| Key | Type | Notes |
Expand Down
144 changes: 144 additions & 0 deletions runtime-telemetry/v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Runtime Telemetry v1

> Status: Implemented baseline in `ori-runtime`
> Primary consumer: `ori-energy apps/api` during Phone Starter/XPRIZE path.

This contract defines the direct HTTP telemetry boundary from `ori-runtime` to a
product backend. It exists for phone and lightweight deployments where running a
LAN `ori-gateway` is unnecessary or unavailable.

This is not the runtime/gateway MQTT boundary. Gateway exports remain defined in
`gateway-api/v1.md`.

## Authority Boundary

Runtime telemetry export is observational only.

- It mirrors real runtime `sensor.reading` events to a product backend.
- Backend availability must never affect Tier B, Tier C, or Tier D action
authority.
- The backend must not use this endpoint to mutate runtime configuration,
thresholds, relay state, DevicePolicy, update intent, or actuator settings.
- Tier D remains deterministic and local.

## Transport

| Field | Value |
|---|---|
| Protocol | HTTPS POST |
| Content type | `application/json` |
| Runtime config | `telemetry_export` |
| Default state | Disabled |
| Loopback exception | `http://localhost` or `http://127.0.0.1` allowed for local development |

Production and public endpoints must use HTTPS.

## Request Headers

| Header | Required | Notes |
|---|---:|---|
| `Authorization` | Yes | `Bearer <device_api_key>` |
| `Content-Type` | Yes | `application/json` |
| `X-Ori-Device-Id` | Yes | Must match payload `device_id`. |
| `X-Ori-Timestamp-Ms` | Yes | Unix milliseconds UTC when the request was signed. |
| `X-Ori-Signature` | Yes | `v1=<hex hmac sha256>` |

The device API key is read from the runtime environment variable named by
`telemetry_export.api_key_env`. The secret must not be committed to `ori.yaml`.

## Signature

The runtime signs:

```text
timestamp_ms + "." + canonical_json_body
```

Using HMAC-SHA256 with the device API key as the secret.

The JSON body must be canonicalized with sorted keys and compact separators
before signing.

The backend must:

- verify the bearer token/device API key;
- verify `X-Ori-Device-Id` matches payload `device_id`;
- verify timestamp skew within backend policy;
- verify HMAC signature before accepting the batch;
- reject replayed or duplicate batches using `device_id`, `sequence`, and/or
event IDs.

## Request Body

```json
{
"schema_version": "runtime.telemetry.v1",
"device_id": "phone-gateway-ikeja-01",
"sequence": 1,
"sent_at_ms": 1719000000000,
"events": [
{
"event_id": "uuid4-string",
"event_type": "sensor.reading",
"device_id": "phone-gateway-ikeja-01",
"sensor_id": "phone-main-power",
"timestamp": 1719000000000,
"source": "usb_serial",
"fingerprint": "sha256-hex-or-empty",
"context": {},
"reading": {
"sensor_id": "phone-main-power",
"sensor_type": "usb_power",
"value": 1240.5,
"unit": "watt",
"timestamp": 1719000000000,
"quality": 1.0,
"metadata": {
"source": "usb_serial"
}
}
}
]
}
```

`reading.raw` is intentionally omitted from the HTTP payload.

## Runtime Config

```yaml
telemetry_export:
enabled: false
endpoint: "https://api.ori.energy/runtime/telemetry"
api_key_env: ORI_ENERGY_DEVICE_API_KEY
flush_interval_s: 30
batch_size: 50
timeout_ms: 3000
max_queue_size: 1000
```

## Retry And Backpressure

Runtime behavior:

- queue writes are non-blocking;
- queue size is bounded by `max_queue_size`;
- overflow drops new telemetry and increments a runtime drop counter;
- failed POST batches are retained in memory when queue capacity permits;
- durable historical backfill is outside the v1 runtime contract.

The backend should treat event IDs as idempotency keys.

## Relationship To ori-gateway

`runtime.telemetry.v1` is for direct product ingestion. `gateway-api/v1.md`
remains the Edge Node and site-gateway contract for MQTT reasoning, runtime
health, and bounded historical exports.

An Ori deployment may use both:

- direct telemetry export for phone/product dashboards;
- gateway MQTT exports for certified Edge Node reporting and local gateway
services.

The two contracts must not share mutation semantics.
Loading