use crate::core::context_admission::stores::StoreAdmission;
use crate::core::events::LeanCtxEvent;
use crate::core::ocla_bus::OclaEvent;
use std::fmt;
use std::sync::{Mutex, MutexGuard, OnceLock, TryLockError};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LocalObservationSource {
Ocla,
Legacy,
}
impl LocalObservationSource {
pub fn as_str(self) -> &'static str {
match self {
Self::Ocla => "ocla",
Self::Legacy => "legacy",
}
}
pub fn parse(value: &str) -> Result<Self, ObservationPersistenceError> {
match value {
"ocla" => Ok(Self::Ocla),
"legacy" => Ok(Self::Legacy),
other => Err(ObservationPersistenceError::InvalidRow(format!(
"unknown local observation source {other:?}"
))),
}
}
}
#[derive(Debug)]
pub enum ObservationPersistenceError {
Io(std::io::Error),
LockPoisoned,
LockTimeout,
IdentityConflict,
Serialization(String),
Sqlite(String),
InvalidRow(String),
Withheld,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LocalObservationPayload {
Ocla(OclaEvent),
Legacy(LeanCtxEvent),
}
#[derive(Debug, Clone, PartialEq)]
pub struct LocalObservationV1 {
pub cursor_id: i64,
pub producer_instance: String,
pub source_id: u64,
pub source_timestamp: String,
pub source: LocalObservationSource,
pub payload: LocalObservationPayload,
}
impl fmt::Display for ObservationPersistenceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(error) => write!(f, "context bus storage unavailable: {error}"),
Self::LockPoisoned => f.write_str("context bus observation lock poisoned"),
Self::LockTimeout => f.write_str("context bus observation lock timed out"),
Self::IdentityConflict => {
f.write_str("observation identity reused with different data")
}
Self::Serialization(error) => write!(f, "observation serialization failed: {error}"),
Self::Sqlite(error) => write!(f, "observation sqlite operation failed: {error}"),
Self::InvalidRow(error) => write!(f, "invalid local observation row: {error}"),
Self::Withheld => f.write_str("observation withheld by the context gateway"),
}
}
}
const SOURCE_TOOL: &str = "ctx_read";
fn payload_text(payload: &serde_json::Value) -> String {
fn collect<'a>(value: &'a serde_json::Value, leaves: &mut Vec<&'a str>) {
match value {
serde_json::Value::String(text) => leaves.push(text),
serde_json::Value::Array(items) => {
for item in items {
collect(item, leaves);
}
}
serde_json::Value::Object(fields) => {
fields.values().for_each(|field| collect(field, leaves));
}
_ => {}
}
}
let mut leaves = Vec::new();
collect(payload, &mut leaves);
leaves.join("\n")
}
fn payload_path(payload: &serde_json::Value) -> Option<&str> {
let fields = payload.as_object()?;
fields
.get("path")
.and_then(serde_json::Value::as_str)
.or_else(|| fields.values().find_map(payload_path))
}
pub(crate) fn admit_payload(payload_json: &str) -> Result<(), ObservationPersistenceError> {
let text = payload_text(&serde_json::from_str(payload_json)?);
if kept_verbatim(&admission_snapshot(), &text) {
Ok(())
} else {
Err(ObservationPersistenceError::Withheld)
}
}
fn admission_snapshot() -> StoreAdmission {
StoreAdmission::with_policy(
crate::core::context_admission::AdmissionPolicy::from_config(
&crate::core::config::Config::load_arc(),
),
)
.built_in_floor()
}
fn kept_verbatim(admission: &StoreAdmission, text: &str) -> bool {
text.is_empty() || admission.admit_shell_command(text).as_deref() == Some(text)
}
pub(crate) struct ObservationGate {
files: Option<crate::core::bm25_index::source_gate::SourceGate>,
admission: StoreAdmission,
protected: bool,
withheld: usize,
}
impl ObservationGate {
pub(crate) fn for_project(project: Option<&std::path::Path>) -> Self {
use crate::core::bm25_index::source_gate::SourceGate;
let request = crate::core::admitted_sources::request_root();
let admission = admission_snapshot();
let root = match project {
Some(root) => Some(root),
None if request.is_empty() => None,
None => Some(std::path::Path::new(&request)),
};
let files = root.map(|root| SourceGate::with_admission(root, SOURCE_TOOL, &admission));
Self {
files,
admission,
protected: crate::core::context_admission::stored::source_authority_required(),
withheld: 0,
}
}
pub(crate) fn serves<T: serde::Serialize>(&mut self, observation: &T) -> bool {
let served = serde_json::to_value(observation).is_ok_and(|payload| {
if !kept_verbatim(&self.admission, &payload_text(&payload)) {
return false;
}
match (payload_path(&payload), self.files.as_mut()) {
(Some(path), Some(files)) => files.serves(path, ""),
_ => !self.protected,
}
});
if !served {
self.withheld += 1;
}
served
}
pub(crate) fn gateway_unchanged(&self) -> bool {
self.admission.digest() == admission_snapshot().digest()
}
pub(crate) fn withheld(&self) -> usize {
self.withheld
}
}
impl std::error::Error for ObservationPersistenceError {}
impl From<serde_json::Error> for ObservationPersistenceError {
fn from(error: serde_json::Error) -> Self {
Self::Serialization(error.to_string())
}
}
impl From<rusqlite::Error> for ObservationPersistenceError {
fn from(error: rusqlite::Error) -> Self {
Self::Sqlite(error.to_string())
}
}
impl From<std::io::Error> for ObservationPersistenceError {
fn from(error: std::io::Error) -> Self {
Self::Io(error)
}
}
pub(crate) fn validate_identity(
producer_instance: &str,
source_id: u64,
) -> Result<(), ObservationPersistenceError> {
if source_id == 0
|| !uuid::Uuid::parse_str(producer_instance)
.is_ok_and(|id| id.to_string() == producer_instance && !id.is_nil())
{
return Err(ObservationPersistenceError::InvalidRow(
"invalid producer instance or source ID".into(),
));
}
Ok(())
}
pub(crate) fn decode_row(
row: &rusqlite::Row<'_>,
) -> Result<Option<LocalObservationV1>, ObservationPersistenceError> {
if row.get::<_, i64>(6)? != 1 {
return Err(ObservationPersistenceError::InvalidRow(
"unsupported local observation schema".into(),
));
}
let cursor_id: i64 = row.get(0)?;
let source = LocalObservationSource::parse(row.get::<_, String>(1)?.as_str())?;
let source_id_raw: String = row.get(2)?;
let source_id = source_id_raw.parse::<u64>().map_err(|_| {
ObservationPersistenceError::InvalidRow("invalid source ID encoding".into())
})?;
let producer_instance: String = row.get(5)?;
validate_identity(&producer_instance, source_id)?;
if cursor_id <= 0 || source_id.to_string() != source_id_raw {
return Err(ObservationPersistenceError::InvalidRow(
"noncanonical observation identity".into(),
));
}
let source_timestamp: String = row.get(3)?;
let payload_json: String = row.get(4)?;
let payload = match source {
LocalObservationSource::Ocla => {
if !source_timestamp
.parse::<u64>()
.is_ok_and(|value| value.to_string() == source_timestamp)
{
return Err(ObservationPersistenceError::InvalidRow(
"invalid OCLA timestamp encoding".into(),
));
}
LocalObservationPayload::Ocla(serde_json::from_str(&payload_json)?)
}
LocalObservationSource::Legacy => {
if crate::core::events::is_retired_event_record(&payload_json) {
return Ok(None);
}
let event: LeanCtxEvent = serde_json::from_str(&payload_json)?;
if event.id != source_id || event.timestamp != source_timestamp {
return Err(ObservationPersistenceError::InvalidRow(
"legacy payload contradicts observation identity or timestamp".into(),
));
}
LocalObservationPayload::Legacy(event)
}
};
Ok(Some(LocalObservationV1 {
cursor_id,
producer_instance,
source_id,
source_timestamp,
source,
payload,
}))
}
pub(crate) fn producer_instance() -> &'static str {
static INSTANCE: OnceLock<String> = OnceLock::new();
INSTANCE.get_or_init(|| uuid::Uuid::new_v4().to_string())
}
pub(crate) fn lock_observation<T>(
mutex: &Mutex<T>,
) -> Result<MutexGuard<'_, T>, ObservationPersistenceError> {
let started = Instant::now();
loop {
match mutex.try_lock() {
Ok(guard) => return Ok(guard),
Err(TryLockError::Poisoned(_)) => {
return Err(ObservationPersistenceError::LockPoisoned);
}
Err(TryLockError::WouldBlock) => {
if started.elapsed() >= Duration::from_secs(5) {
return Err(ObservationPersistenceError::LockTimeout);
}
std::thread::sleep(Duration::from_millis(1));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::context_os::context_bus::ContextBus;
use crate::core::events::EventKind;
const AWS_KEY: &str = concat!("AK", "IAIOSFODNN7EXAMPLE");
fn event(id: u64, kind: EventKind) -> LeanCtxEvent {
LeanCtxEvent {
id,
timestamp: "2026-01-01T00:00:00.000".to_owned(),
kind,
}
}
#[test]
fn an_observation_is_shown_only_while_the_file_it_names_is_admitted() {
let _data = crate::core::data_dir::isolated_data_dir();
let community = crate::core::policy::runtime::TestPolicyOverride::set(None);
let project = tempfile::tempdir().expect("project");
let root = project.path().canonicalize().expect("canonical root");
let store = tempfile::tempdir().expect("store");
let bus = ContextBus::open_at(store.path().join("context-bus.db"));
std::fs::write(root.join("billing.rs"), "pub fn settle() {}\n").expect("source");
let hit = event(
1,
EventKind::CacheHit {
path: "billing.rs".to_owned(),
saved_tokens: 10,
},
);
bus.append_legacy_observation(producer_instance(), &hit)
.expect("an admitted payload is stored");
let shown = || -> usize {
let mut gate = ObservationGate::for_project(Some(root.as_path()));
bus.read_legacy_observations(10)
.expect("rows")
.iter()
.filter(|stored| gate.serves(*stored))
.count()
};
assert_eq!(shown(), 1);
std::fs::remove_file(root.join("billing.rs")).expect("withdraw");
assert_eq!(shown(), 0);
let mut gate = ObservationGate::for_project(Some(root.as_path()));
assert!(!gate.serves(&hit));
assert_eq!(gate.withheld(), 1);
let keyed = event(
2,
EventKind::VerificationWarning {
warning_kind: "drift".to_owned(),
detail: format!("deploy token {AWS_KEY}"),
severity: "warn".to_owned(),
},
);
let refused = bus
.append_legacy_observation(producer_instance(), &keyed)
.expect_err("a payload admission would mask is not persisted");
assert!(matches!(refused, ObservationPersistenceError::Withheld));
assert!(!refused.to_string().contains(AWS_KEY));
assert_eq!(bus.read_legacy_observations(10).expect("rows").len(), 1);
std::fs::write(root.join("ledger.rs"), "pub fn post() {}\n").expect("source");
let call = |id: u64, mode: &str| {
event(
id,
EventKind::ToolCall {
tool: "ctx_read".to_owned(),
tokens_original: 10,
tokens_saved: 5,
mode: Some(mode.to_owned()),
duration_ms: 1,
path: Some("ledger.rs".to_owned()),
},
)
};
for stored in [call(3, "map"), call(4, "CONFIDENTIAL")] {
bus.append_legacy_observation(producer_instance(), &stored)
.expect("stored under the looser rule");
}
drop(community);
let policy = crate::core::policy::load(
"name = \"observation-test\"\nversion = \"1.0.0\"\ndescription = \"test\"\n\
[filters]\nclassification = \"block\"\nblocked_labels = [\"CONFIDENTIAL\"]\n",
)
.expect("policy");
let _tightened = crate::core::policy::runtime::TestPolicyOverride::set(Some(policy));
let mut gate = ObservationGate::for_project(Some(root.as_path()));
let shown: Vec<u64> = bus
.read_legacy_observations(10)
.expect("rows")
.iter()
.filter(|stored| gate.serves(*stored))
.map(|stored| stored.id)
.collect();
assert_eq!(shown, [3]);
}
}