diff --git a/docs/adr/ADR-297-perception-substrate-program.md b/docs/adr/ADR-297-perception-substrate-program.md index 7fc7acb4..c8ec0fc7 100644 --- a/docs/adr/ADR-297-perception-substrate-program.md +++ b/docs/adr/ADR-297-perception-substrate-program.md @@ -28,10 +28,69 @@ Several of these primitives already have foundations in the tree and should be - The in-flight ADR-292 (provenance state machine), ADR-293 (authenticated data plane, step one), ADR-295 (model sanity gates) — the first bricks. +## What RuView is optimizing for + +Not inference capability — **epistemic reliability**: + +``` +signal → observation → calibration → inference → uncertainty → evidence + → certificate → policy → governed action +``` + +That pipeline is the product. The defensible category is not "RuView perceives +the physical world" but "RuView determines what machines are justified in +believing about it, proves why, and constrains what they may do with that +belief." + +### Four non-negotiable program rules + +Every child ADR and implementation is bound by these: + +1. **UNKNOWN is a first-class output, never an error condition.** A surface that + cannot answer says UNKNOWN and stays legible; it does not throw, default to a + confident class, or silently hold a stale value. +2. **Capability certificates bind cryptographically.** Hardware, environment, + model, calibration, metrics, expiry, and evidence level are bound under one + signature (ADR-315/ADR-302). An unsigned or partially-bound certificate is + not a certificate. +3. **One canonical semantics downstream.** Every surface (MQTT, REST, WebSocket, + RuField, Matter, agents, UI) consumes the same Observation → Inference → + GovernedEvent types (ADR-303). No transport- or UI-specific reinterpretation. +4. **Benchmarks expose worst-domain performance and confidence intervals.** + Pooled accuracy is never sufficient for promotion (ADR-314). + +### Certificate conditionality (the staleness guard) + +The central architectural risk is **certificate staleness**: a room can remain +syntactically calibrated while its RF distribution has drifted enough to +invalidate the certificate. Therefore a capability certificate is **conditional +on a continuously evaluated domain signature** (ADR-299), not a one-time stamp. +Crossing the OOD threshold automatically degrades state and triggers +recalibration rather than silently continuing: + +``` +VALID → DEGRADED → UNKNOWN (auto-degrade on domain drift; triggers recalibration) +``` + +This binds ADR-298 (calibration), ADR-299 (OOD), ADR-315 (certificate), and +ADR-318 (policy): a degraded/unknown domain must invalidate the affected +capability *before* a false confident inference reaches an actuator. + +### Commercial framing — three primitives, not one product + +- **RuView Runtime** — provides perception. +- **RuView Certify** — establishes what a deployment can legitimately claim + (calibration + evidence + capability certificate + policy). +- **RuView Trust / Fleet** — keeps that claim valid across hardware, firmware, + models, and environmental drift (ADR-313). + +Certify and Trust are the parts that are hard to commoditize; presence +detection alone is not. + ## Decision -Adopt a **20-primitive phased program**. Each primitive gets a child ADR -(ADR-298…ADR-317) that owns its detailed decision, status, and validation. +Adopt a **21-primitive phased program**. Each primitive gets a child ADR +(ADR-298…ADR-318) that owns its detailed decision, status, and validation. This ADR owns the framing, the dependency order, and the phase assignment. ### Primitive → ADR map @@ -58,23 +117,29 @@ This ADR owns the framing, the dependency order, and the phase assignment. | 18 | Capability certificates | ADR-315 | 1 | | 19 | Witness chain | ADR-316 | 1 | | 20 | RuView sensor HAL | ADR-317 | 2 | +| 21 | Decision policy — action authorization | ADR-318 | 1 | ### Dependency order (why phase, not score, drives sequencing) ``` ADR-303 spatial ontology ──┐ ADR-302 auth identity ─────┼──► ADR-298 calibration cert ──► ADR-299 OOD gating - │ │ - └──► ADR-316 witness chain │ - │ ▼ + │ │ │ + └──► ADR-316 witness chain │ (VALID→DEGRADED→UNKNOWN) + │ ▼ ADR-301 evidence engine ──► ADR-315 capability certificate - │ + │ │ (conditional on domain signature) + │ ▼ + │ ADR-318 decision policy ──► governed action └──► ADR-314 benchmark scorecard (per-PR gate) ``` -- **Phase 1 (the certificate spine, built now):** 303, 302, 316, 298, 299, - 301, 315, 314. This set is exactly the acceptance test decomposed and is - buildable without new hardware (types, logic, signatures, tests). +- **Phase 1 (the certificate spine, built now):** foundational roots 303, 302, + 301, 298 (implemented first, in their own crates); then the dependent wave + 316, 299, 315, 314, 318. This set is exactly the acceptance test decomposed + and is buildable without new hardware (types, logic, signatures, tests). The + dependent wave adds the staleness guard (299 auto-degrades 315) and the + action gate (318) that denies at the actuator on a degraded/unknown domain. - **Phase 2 (integration & operations):** 300 ground truth, 304 tracking, 307 802.11bf-native, 308 fusion, 313 fleet, 317 HAL. Depends on the spine. - **Phase 3 (higher-ceiling, research-forward):** 305 placement optimizer, 306 @@ -84,7 +149,7 @@ This ADR owns the framing, the dependency order, and the phase assignment. Phase-2 and phase-3 child ADRs are authored as **Proposed** (design intent, validation plan) and are not implemented by the phase-1 swarm. -### Acceptance test (from the strategic assessment) +### Acceptance test A — onboarding (from the strategic assessment) > Connect a new sensor type in an unseen room. Within 30 minutes RuView should > identify the hardware (HAL, ADR-317), calibrate the environment (ADR-298), @@ -93,7 +158,18 @@ validation plan) and are not implemented by the phase-1 swarm. > events (ADR-303), and return UNKNOWN whenever evidence falls outside that > certificate (ADR-299). -Phase 1 makes every clause except HAL testable in software; HAL (phase 2) +### Acceptance test B — drift invalidation (the staleness guard) + +> Deliberately change the room after certification — move furniture, change the +> AP channel, or substitute hardware. RuView should detect distribution drift +> (ADR-299), invalidate the affected capability (ADR-315) **before** a false +> confident inference reaches an actuator (ADR-318 denies with the specific +> failed condition), emit UNKNOWN, preserve the complete witness chain +> (ADR-316), and explain exactly which certificate condition failed. + +Test B is the load-bearing one: it proves the substrate fails safe, not just +that it perceives well. Phase 1 makes every clause except HAL testable in +software; HAL (phase 2) closes the "identify the hardware" clause. ## Consequences diff --git a/docs/adr/ADR-318-decision-policy-action-authorization.md b/docs/adr/ADR-318-decision-policy-action-authorization.md new file mode 100644 index 00000000..fc3a6dbd --- /dev/null +++ b/docs/adr/ADR-318-decision-policy-action-authorization.md @@ -0,0 +1,101 @@ +# ADR-318: Decision policy — action authorization conditioned on certificate class, freshness, uncertainty, and evidence + +- **Status**: Accepted — initial implementation planned (ADR-297 phase 1) +- **Date**: 2026-08-11 +- **Deciders**: ruv +- **Tags**: policy, authorization, safety, certificates, governed-action, phase-1 + +## Context + +The perception substrate (ADR-297) makes RuView state *what it knows* and +*how well* — the capability certificate (ADR-315) binds hardware, environment, +model, calibration, metrics, expiry, and evidence level. But a certificate is a +statement of knowledge, not a grant of action. The same certificate that is +adequate to dim a light is wholly inadequate to release a door lock or clear an +industrial stop condition. + +Without an explicit authorization layer, every consumer re-implements its own +(inconsistent, usually optimistic) rule for "is this good enough to act on," +and a confident-but-out-of-domain inference can reach an actuator. That is the +exact failure the substrate exists to prevent. Decision policy therefore +belongs in **phase 1**, alongside the certificate it gates, not later. + +This ADR realizes program invariant #1 (UNKNOWN is a first-class output, never +an error) and the action-side of the refined acceptance test: a drift- +invalidated capability must be *denied at the actuator* before a false +confident inference is acted upon. + +## Decision + +Introduce a `ruview-policy` crate providing an **action authorization gate** +that sits between governed spatial state and any actuator. + +### 1. Assurance requirements per action + +An `ActionClass` declares the assurance an action demands: + +- `min_certificate_class` — the required `CapabilityCertificate` class (ADR-315). +- `max_certificate_age` / `min_domain_freshness` — the certificate must be + currently valid **and** the live domain signature (ADR-299) must not be in a + DEGRADED/UNKNOWN state (this is the staleness guard, program invariant on + certificate conditionality — see ADR-297). +- `max_uncertainty` — inference uncertainty ceiling. +- `min_evidence_level` — the L0–L5 floor (ADR-282/ADR-301); e.g. a safety + action may require ≥ L3 (held-out room+subject validation). + +Reference action classes (illustrative, configurable): + +| Class | Example | Typical floor | +|---|---|---| +| `Convenience` | lighting, scenes | tolerant: L1+, higher uncertainty ok | +| `Security` | alerts, arming | stricter: valid cert, L2+, bounded uncertainty | +| `SafetyCritical` | door lock, machine stop | strict: fresh cert, L3+, low uncertainty, KNOWN domain only | + +### 2. The authorization decision + +`authorize(action, capability_certificate, live_state) -> Authorization` where +`live_state` carries the current `SourceState` (ADR-292), OOD/domain state +(ADR-299), and inference uncertainty. Rules: + +- **Fail-closed.** Any unmet condition → `Deny { failed_condition }`. The denial + names the *specific* condition (expired cert, domain DEGRADED, uncertainty + over ceiling, evidence below floor, certificate class too low). +- **UNKNOWN denies high-assurance actions.** A domain in UNKNOWN (ADR-299) + cannot authorize `Security`/`SafetyCritical` actions; it may still authorize + `Convenience` if that class's policy permits, but the authorization records + that it proceeded under UNKNOWN. +- The decision is a **pure function** of (action class, certificate, live + state) — deterministic and unit-testable without a clock or actuator. +- Every authorization (allow or deny) is emitted as the terminal stage of the + witness chain (ADR-316), so "why was this actuator allowed/denied" is + auditable end-to-end. + +### 3. No silent optimism + +A missing certificate, an expired certificate, or an unrecognized action class +all deny by default. Absence of a policy is not permission. + +## Consequences + +- Action authorization becomes uniform and centrally reasoned instead of + per-consumer and optimistic; this is the "RuView Certify → constrains action" + boundary that is hard to commoditize. +- A behavior change for existing automations that acted directly on presence: + they now pass through the gate. Convenience-class defaults keep low-stakes + automations working; high-stakes actions must opt into stricter classes. +- Depends on ADR-315 (certificate), ADR-299 (domain/OOD state), ADR-292 + (source state), ADR-301 (evidence). Built in the phase-1 dependent wave after + those types land. + +## Validation + +- Unit tests: each action class authorizes/denies correctly across the matrix + of (valid/expired/degraded cert × KNOWN/DEGRADED/UNKNOWN domain × uncertainty + above/below ceiling × evidence above/below floor); UNKNOWN denies + safety-critical; every deny names its failed condition; absence-of-policy + denies; determinism. +- Integration: the acceptance-test scenario (ADR-297) — post-certification room + change drives domain to DEGRADED→UNKNOWN, and a `SafetyCritical` authorization + is denied with `failed_condition = domain_not_known` *before* the inference + reaches the actuator, witness chain preserved. +- `cargo test -p ruview-policy`. diff --git a/docs/adr/README.md b/docs/adr/README.md index dca701d4..040d450d 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -154,7 +154,7 @@ Statuses: **Proposed** (under discussion), **Accepted** (approved and/or impleme | [ADR-294](ADR-294-multi-node-semantic-correctness.md) | Multi-node semantic correctness — per-node inference, node-keyed rate limiting, stale state | Accepted (initial implementation) | | [ADR-295](ADR-295-model-release-sanity-gates.md) | Model release sanity gates — block degenerate and mislabeled model artifacts | Accepted (initial implementation) | | [ADR-296](ADR-296-csi-data-incident-repo-controls.md) | Repository CSI data-incident controls — ignore rules and pre-commit/CI policy check | Accepted (controls implemented; tree remediation gated) | -| [ADR-297](ADR-297-perception-substrate-program.md) | RuView perception substrate — phased 20-primitive program (calibration, evidence, trust, deployment) | Accepted (program; children ADR-298..317) | +| [ADR-297](ADR-297-perception-substrate-program.md) | RuView perception substrate — phased 21-primitive program (calibration, evidence, trust, deployment) | Accepted (program; children ADR-298..317) | | [ADR-298](ADR-298-automatic-domain-calibration.md) | Automatic domain calibration — signed, versioned, invalidatable room fingerprint | Accepted (phase 1) | | [ADR-299](ADR-299-out-of-distribution-detection.md) | Out-of-distribution detection — KNOWN / DEGRADED / UNKNOWN gating | Accepted (phase 1) | | [ADR-300](ADR-300-ground-truth-synchronization.md) | Ground-truth synchronization — reference sensors as a formal validation plane | Proposed (phase 2) | @@ -175,6 +175,7 @@ Statuses: **Proposed** (under discussion), **Accepted** (approved and/or impleme | [ADR-315](ADR-315-capability-certificates.md) | Capability certificates — validated-for-this-environment claims | Accepted (phase 1) | | [ADR-316](ADR-316-witness-chain.md) | Witness chain — staged, signed epistemic envelope | Accepted (phase 1) | | [ADR-317](ADR-317-sensor-hal.md) | RuView sensor HAL — abstract all sensing hardware to one Observation type | Proposed (phase 2) | +| [ADR-318](ADR-318-decision-policy-action-authorization.md) | Decision policy — action authorization conditioned on certificate class, freshness, uncertainty, evidence | Accepted (phase 1) | ---