//! Documented status and usage probes for supervised coding harnesses. //! //! `lumbridge-core` owns the usage ledger and stays free of IO, clocks, and //! async. This crate is the other side of that boundary: it runs processes, //! reads a clock, parses untrusted wire text, and hands back //! [`lumbridge_core::UsageObservation`] values. Nothing here interprets a //! usage number; it only decides which observation is honest to record. //! //! The rule every probe follows: Lumbridge observes documented surfaces of a //! harness it launched, and never reads that harness's credentials. A probe //! that cannot obtain a reading records //! [`lumbridge_core::UsageObservation::unavailable`] rather than a zero. #![forbid(unsafe_code)] mod child; pub mod claude; mod clock; pub mod codex; mod jsonrpc; mod probe; pub use child::PROBE_ENV_ALLOWLIST; pub use clock::MonotonicWallClock; pub use jsonrpc::ServerRequestClass; pub use probe::{ProbeHealth, ProbeOutcome, UsageProbe}; use thiserror::Error; /// Failures a probe can report. /// /// Every variant is [`Copy`] and carries only a static discriminator, an /// [`std::io::ErrorKind`], or a number. No variant can capture a string from a /// child process or the filesystem, so an error can never smuggle a path, /// a credential, or attacker-chosen text into a log or a UI surface. #[derive(Clone, Copy, Debug, Eq, Error, PartialEq)] pub enum HarnessError { #[error("a probe program name must not be empty")] EmptyProgram, #[error("the environment variable {0} is not on the probe allowlist")] EnvNotAllowlisted(&'static str), #[error("a probe poll interval must be at least one second")] ProbeIntervalTooShort, #[error("the probe program could not be started ({0:?})")] SpawnFailed(std::io::ErrorKind), #[error("the probe program closed its output")] Eof, #[error("the probe program sent a {0} byte line, over the accepted limit")] OversizedLine(usize), #[error("the probe program sent a line that is not a JSON-RPC frame")] Malformed, #[error("the harness rejected the request with JSON-RPC code {0}")] Rejected(i64), #[error("the harness has no subscription account to report a quota for")] NotAuthenticated, } impl HarnessError { /// Whether this failure means "there is no number", as opposed to /// "the probe broke". /// /// Both record an unavailable observation, but only the second is a fault /// worth surfacing as a broken probe. #[must_use] pub const fn is_expected_gap(self) -> bool { matches!(self, Self::NotAuthenticated) } }