Files
ruvnet--RuView/v2/crates/ruview-ood/src/certificate.rs
T
Claude 516331461a feat: implement ADR-297 phase-1 dependent wave — OOD, witness, certify, scorecard, policy
Completes the phase-1 certificate spine; both acceptance tests now pass as code.

ruview-ood (ADR-299): domain-distance vs the certified fingerprint and a pure
DomainState KNOWN/DEGRADED/UNKNOWN classifier implementing the ADR-297
VALID->DEGRADED->UNKNOWN staleness guard; InferenceGate suppresses the class
(UNKNOWN as a first-class value) when domain is not KNOWN; RecalibrationRequest
signalled on DEGRADED/UNKNOWN. 25 tests.

ruview-witness (ADR-316): ordered, append-only, BLAKE3 hash-linked stage chain
(observation->DSP->inference->corroboration->spatial->policy) rooted in an
attest VerifiedMeasurement; verify() catches mutation/reorder/dropped/broken
links; effective level is the minimum across stages. 19 tests.

ruview-certify (ADR-315): signed CapabilityCertificate minted from a single-
context evidence slice (never pooled), evidence level capped at the slice floor,
valid_until bounded by calibration validity; is_valid(now, domain) returns false
when expired OR domain != KNOWN (certificate conditional on the live domain
signature). 17 tests incl. non_known_domain_invalidates.

ruview-scorecard (ADR-314): multi-domain scorecard with per-domain CIs,
worst_domain(), and a promotion gate that fails when only pooled average
improved while a worst-domain slice regressed. 17 tests.

ruview-policy (ADR-318): fail-closed action gate; Convenience/Security/
SafetyCritical assurance classes; authorize() denies with a named failed
condition; UNKNOWN denies high-assurance actions. Includes
acceptance_test_b_post_drift_unknown_denies_safety_critical. 10 tests.

All five verified green independently (88 tests). Registers the five crates as
workspace members. SYNTHETIC/L0 reference crypto; no hardware claims.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015TcKegTS7QqhWPC2L2SzaS
2026-08-11 02:06:31 +00:00

73 lines
3.3 KiB
Rust

//! Cross-ADR adapter: turn an ADR-298 [`CalibrationCertificate`] plus a live
//! fingerprint into the two OOD inputs it governs — the [`FingerprintDistance`]
//! and the [`CalibrationCompat`] (ADR-299 §1 inputs 1 and 3).
//!
//! This is the point where certificate *staleness* becomes a domain signal:
//! an expired, tampered, drifted, or identity-mismatched certificate maps to a
//! non-`Valid` compatibility, which the state machine drives straight to
//! UNKNOWN (ADR-297 staleness guard). Absence of a certificate is handled by
//! [`no_certificate`] and likewise defaults to UNKNOWN — absence of evidence is
//! absence of capability (ADR-299 §3).
use wifi_densepose_calibration::certificate::{
CalibrationCertificate, CertificateStatus, CertificateVerifier, FingerprintDistance, RoomFingerprint,
};
use crate::domain::CalibrationCompat;
/// Identity the live inference expects the certificate to attest: which space
/// (ADR-303) and which signed device (ADR-302). Validated before the
/// certificate's own status, so a certificate for the wrong room/device can
/// never present as compatible.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ExpectedIdentity<'a> {
/// The canonical space id the inference is running in.
pub space_id: &'a str,
/// The signed device id producing the live traffic.
pub device_id: &'a str,
}
/// Assess a present certificate against the live fingerprint and expected
/// identity, returning the domain distance and the calibration compatibility.
///
/// `now_unix_s` is **injected** — never read from the wall clock — so the
/// staleness decision is deterministic and testable. The distance is always the
/// certificate-fingerprint-vs-live distance, computed even for a stale/tampered
/// certificate so the drift is still reported.
///
/// Precedence mirrors ADR-298 `status()` but adds the identity checks first:
/// space mismatch → device mismatch → tampered → expired → drifted → valid.
pub fn assess_certificate<V: CertificateVerifier>(
cert: &CalibrationCertificate,
live: &RoomFingerprint,
expected: ExpectedIdentity<'_>,
now_unix_s: i64,
verifier: &V,
) -> (FingerprintDistance, CalibrationCompat) {
let distance = cert.fingerprint.distance(live);
// Identity binding first (ADR-302/303): a certificate for the wrong
// space/device is incompatible regardless of its own validity.
if cert.space_id != expected.space_id {
return (distance, CalibrationCompat::SpaceMismatch);
}
if cert.sensor_id != expected.device_id {
return (distance, CalibrationCompat::DeviceMismatch);
}
let compat = match cert.status(live, now_unix_s, verifier) {
CertificateStatus::Valid { .. } => CalibrationCompat::Valid,
CertificateStatus::Expired { .. } => CalibrationCompat::Expired,
CertificateStatus::Drifted { .. } => CalibrationCompat::DriftedBeyondEnvelope,
CertificateStatus::TamperedSignature => CalibrationCompat::Tampered,
};
(distance, compat)
}
/// The compatibility for a space/device with **no** certificate present. Always
/// [`CalibrationCompat::Absent`], which the gate treats as UNKNOWN (ADR-299 §3:
/// the default state without a valid certificate is UNKNOWN, not KNOWN).
pub fn no_certificate() -> CalibrationCompat {
CalibrationCompat::Absent
}