diff --git a/gaps/open.md b/gaps/open.md index a2d5029..5e3e79c 100644 --- a/gaps/open.md +++ b/gaps/open.md @@ -1,7 +1,22 @@ # Open Gaps -## G-12 — ContextEnricher device snapshot integration (post-v1 scope) +## G-15 — Tier C enrichment MQTT transport wiring -- Domain: `skills-package/v1`, `runtime-config/v1` -- Status: Deferred (post-v1.0.0) -- Summary: Prompt-time cross-sensor device snapshot fusion is approved architecture but intentionally deferred until single-device v1.0.0 stability is confirmed in PoC deployments. +- Domain: `gateway-api/v1` +- Status: Contract defined in `ori-gateway` (`internal/contracts/tier_c_enrichment.go`), DECISIONS.md entry recorded. MQTT topic constants and `app.go` handler are not yet wired. Runtime has no client for sending enrichment requests. +- Summary: The advisory Tier C enrichment flow requires topic constants in `contracts.go` and a subscription handler in `app.go` on the gateway side, and a corresponding MQTT client on the runtime side. Until wired, enriched Tier C operator messages are unavailable. +- Tracking: `ori-platform/ori-gateway` — open issue for MQTT wiring. + +## G-16 — `reasoning_log` export missing from gateway runtimeclient + +- Domain: `gateway-api/v1` +- Status: Export type documented in spec and served by runtime. Gateway `runtimeclient/mqtt.go` implements `Health`, `SensorHistory`, `ActionLog`, `TierCDecisionLog` but has no `ReasoningLog` method. +- Summary: The reasoning audit export surface is unusable from the gateway until the runtimeclient method is added. +- Tracking: `ori-platform/ori-gateway` — open issue for runtimeclient gap. + +## G-17 — Gateway config surface not spec'd + +- Domain: (new) `gateway-config/v1` +- Status: `ori-gateway` has a working `gateway.yaml` config surface (`gateway.broker_url`, `gateway.heartbeat_interval_s`, `provider.*`, `reporting.*`, `sim.*`, `fleet.*`). No corresponding spec document exists. +- Summary: A `gateway-config/v1.md` spec is needed so the CLI, dashboard, and SDK can align with the gateway's configuration surface without reading Go source. +- Tracking: `ori-platform/ori-specs` — create `gateway-config/v1.md`. diff --git a/gaps/resolved.md b/gaps/resolved.md index f84c7a0..c9a2e95 100644 --- a/gaps/resolved.md +++ b/gaps/resolved.md @@ -48,12 +48,26 @@ provider details remain outside the runtime boundary. ## G-05 — Gateway availability check -Resolved: runtime tracks `ori/gateway/health` heartbeat in capability posture and -uses freshness before routing non-explicit deterministic escalation signals to -gateway reasoning. +Resolved: runtime `CapabilityPostureTracker` tracks `ori/gateway/health` heartbeat +freshness and uses it before routing non-explicit deterministic escalation signals to +gateway reasoning. Gateway heartbeat publisher is fully implemented in `ori-gateway` +(`internal/heartbeat/publisher.go`). + +Note: runtime-side MQTT subscription to `ori/gateway/health` is tracked in +`ori-platform/ori-runtime#144` — the posture tracking mechanism is correct but +currently fed only through the in-process EventBus rather than a live MQTT subscribe. ## G-14 — Runtime export surface for gateway/reporting Resolved: runtime exposes bounded MQTT exports for `health`, `sensor_history`, `action_log`, `reasoning_log`, and `tier_c_decision_log`; gateway consumers do not read runtime SQLite directly. + +## G-12 — ContextEnricher device snapshot integration + +Resolved (2026-06-08): `ori/reasoning/context_enricher.py` implements prompt-time +cross-sensor snapshot enrichment. Config lives under `reasoning.context_enricher` +(`enabled`, `staleness_window_ms`, `max_entries`, `include_sources`). Disabled by +default; fail-open. Staleness evaluated at prompt-build time, not event-emit time. +Tier D never reaches the enricher by construction. See `ori-runtime/DECISIONS.md` +2026-06-08 entry and `docs/CAPABILITY_MATRIX.md` for full implementation scope. diff --git a/gateway-api/v1.md b/gateway-api/v1.md index 0db2d84..e1053b9 100644 --- a/gateway-api/v1.md +++ b/gateway-api/v1.md @@ -305,3 +305,100 @@ outcome, proposal ID, and creation timestamp. - Cloud/provider SDKs do not belong in runtime export or runtime reasoning implementations. Gateway/product layers own reporting and cloud reasoning providers. + +--- + +## Tier C Enrichment + +> Status: Contract defined in `ori-gateway` (`internal/contracts/tier_c_enrichment.go`). +> MQTT transport wiring is pending (see gap G-15). + +The gateway may optionally enrich the operator-facing message for an existing Tier C +proposal. Enrichment is advisory: the runtime remains the sole authority for action +tier, proposed action, safe default, approval requirement, and execution. Enrichment +failure or timeout must not block or delay the approval workflow. + +### Topics (pending transport wiring) + +| Message family | Direction | Topic | +|---|---|---| +| Enrichment request | Runtime -> Gateway | `ori/{device_id}/tier_c/enrichment/request` | +| Enrichment response | Gateway -> Runtime | `ori/{device_id}/tier_c/enrichment/response` | + +### Tier C Enrichment Request Payload + +```json +{ + "request_id": "uuid4-string", + "proposal_id": "short-alphanumeric-nonce", + "device_id": "string", + "skill_name": "string", + "trigger_name": "string", + "sensor_id": "string", + "sensor_type": "string", + "reading_value": 0.0, + "unit": "string", + "history_window": [ + { + "sensor_id": "string", + "sensor_type": "string", + "unit": "string", + "timestamp_ms": 0, + "value": 0.0, + "quality": 0.0 + } + ], + "proposed_action": "string", + "safe_default_action": "string", + "operator_message": "string", + "timeout_ms": 5000 +} +``` + +### Tier C Enrichment Response Payload + +```json +{ + "request_id": "uuid4-string", + "proposal_id": "short-alphanumeric-nonce", + "explanation": "string or omitted", + "estimated_impact": "string or omitted", + "recommended_operator_context": "string or omitted", + "provider": "string or omitted", + "model": "string or omitted", + "tokens_used": 0, + "latency_ms": 0, + "error": "string or omitted" +} +``` + +Both `request_id` and `proposal_id` must match the pending runtime proposal. On +enrichment failure, the gateway publishes an error response (non-null `error` field) +so the runtime does not wait. The runtime preserves the original operator message +when enrichment returns an error or times out. + +Enrichment responses must not contain fields that change action tier, action name, +safe default, approval requirement, or any other runtime authority field. + +--- + +## Gateway Weekly Reporting + +> Status: Implemented in `ori-gateway` (`internal/reporting/weekly.go`). No +> dedicated MQTT topic — the gateway generates reports by consuming runtime +> export surfaces and delivers them via configured reporting provider. + +The gateway generates periodic site-level summaries using bounded runtime exports. +Report content includes action log summary, sensor history aggregates, and Tier C +decision context. Report delivery (channel, frequency, format) is configured in +`gateway.yaml` under `reporting.weekly_report`. + +### Invariants + +- Weekly reports are generated from runtime exports only. The gateway must not + read runtime SQLite directly for any reporting path. +- Report generation must not block reasoning request handling. +- Report failure must not affect Tier C approval handling, Tier D safety, or + runtime fallback behaviour. +- Cloud reporting credentials (`reporting.gemini.*`) are gateway-scoped. They + must not appear in runtime config or be passed through reasoning envelopes. diff --git a/runtime-config/v1.md b/runtime-config/v1.md index 12a1018..b59914e 100644 --- a/runtime-config/v1.md +++ b/runtime-config/v1.md @@ -132,16 +132,20 @@ When any `protocol=coap` sensors are configured, host allowlist enforcement rema Cloud provider configuration is intentionally absent from runtime config. Cloud reasoning providers are gateway backends. -## Deferred (post-v1.0.0): `reasoning.context_enricher` (reserved) +## `reasoning.context_enricher` -This block is intentionally **not part of the pre-v1 implemented surface**. -It is reserved for post-v1 cross-sensor prompt context fusion work. +> Status: Implemented — 2026-06-08 -Planned keys: +Prompt-time device snapshot enrichment. Appends fresh readings from all other sensors +on the same device to the prompt before local SLM or gateway inference. Disabled by +default. Fail-open: any store or filter error leaves the prompt unchanged. -| Key | Type | Planned semantics | -|---|---|---| -| `enabled` | `bool` | Enable prompt-time device snapshot enrichment | -| `staleness_window_ms` | `int` | Freshness threshold for snapshot entries | -| `max_entries` | `int` | Hard cap for snapshot lines injected into prompt | -| `include_sources` | `bool` | Include source metadata labels in prompt snapshot | +| Key | Type | Default | Notes | +|---|---|---|---| +| `enabled` | `bool` | `false` | Enable cross-sensor snapshot injection | +| `staleness_window_ms` | `int` | `60000` | Min `100`. Snapshot entries older than this are excluded (evaluated at prompt-build time, not event-emit time) | +| `max_entries` | `int` | `5` | `1..20`. Hard cap on snapshot lines injected | +| `include_sources` | `string[]` | `[]` | Empty means all sources. Filtered in Python after store query — not a SQL predicate | + +Tier D never reaches the enricher by construction (bypass_llm path exits before prompt building). +See `ori-runtime/DECISIONS.md` 2026-06-08 for full invariant set and implementation rationale.