tandem-server 0.6.9

HTTP server for Tandem engine APIs
use anyhow::Context;
use axum::http::StatusCode;
use tandem_types::TenantContext;

use crate::governance_store::{self, GovernanceStoreFile};
use crate::AppState;

pub(crate) async fn append_memory_audit(
    state: &AppState,
    tenant_context: &TenantContext,
    mut event: crate::MemoryAuditEvent,
) -> Result<(), StatusCode> {
    event.tenant_context = tenant_context.clone();
    let line = serde_json::to_string(&event).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    governance_store::for_state(state)
        .append_jsonl_line(
            GovernanceStoreFile::MemoryAudit,
            &line,
            tenant_context,
            None,
            &event.audit_id,
            true,
        )
        .await
        .map_err(|error| {
            tracing::error!(
                tenant_org_id = %tenant_context.org_id,
                tenant_workspace_id = %tenant_context.workspace_id,
                audit_id = %event.audit_id,
                error = ?error,
                "memory audit persistence failed"
            );
            StatusCode::INTERNAL_SERVER_ERROR
        })?;
    let mut audit = state.memory_audit_log.write().await;
    audit.push(event);
    Ok(())
}

pub(crate) async fn load_memory_audit_events_strict(
    state: &AppState,
) -> anyhow::Result<Vec<crate::MemoryAuditEvent>> {
    let lines = match governance_store::for_state(state)
        .read_jsonl_lines(GovernanceStoreFile::MemoryAudit)
        .await?
    {
        Some(lines) => lines,
        None => return Ok(Vec::new()),
    };

    let mut events = Vec::with_capacity(lines.len());
    for line in lines {
        let event = serde_json::from_str::<crate::MemoryAuditEvent>(line.trim())
            .context("protected memory audit store contains a malformed record")?;
        events.push(event);
    }
    Ok(events)
}

pub(crate) async fn load_memory_audit_events(state: &AppState) -> Vec<crate::MemoryAuditEvent> {
    match load_memory_audit_events_strict(state).await {
        Ok(events) => events,
        Err(error) => {
            tracing::error!(error = ?error, "failed to load protected memory audit store");
            Vec::new()
        }
    }
}