use anyhow::Result;
use chrono::Utc;
use serde_json::json;
use sqlitegraph::GraphEntity;
use super::super::json_to_string;
use super::super::{
AtheneumGraph, CommitParams, EdgeType, EntityType, FileAccessParams, FileWriteParams,
FixChainParams, PromptParams, ProvenanceData, RelationEndpoint, TestRunParams, ToolCallParams,
};
impl AtheneumGraph {
fn ensure_commit_sql_row(
&self,
session_id: &str,
commit_sha: &str,
commit_type: &str,
) -> Result<String> {
if let Some(existing) = self.with_raw_connection(|conn| {
Ok(conn
.query_row(
"SELECT commit_id FROM commits WHERE commit_sha = ?1 LIMIT 1",
rusqlite::params![commit_sha],
|row| row.get(0),
)
.ok())
})? {
return Ok(existing);
}
let commit_id = uuid::Uuid::now_v7().to_string();
let now = Utc::now().to_rfc3339();
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO commits
(commit_id, session_id, commit_sha, parent_sha, message, author,
timestamp, files_changed, lines_inserted, lines_deleted, commit_type, feature_tag)
VALUES (?1, ?2, ?3, NULL, ?4, ?5, ?6, 0, 0, 0, ?7, NULL)",
rusqlite::params![
commit_id,
session_id,
commit_sha,
format!("synthetic {} commit for fix chain", commit_type),
"atheneum",
now,
commit_type,
],
)?;
Ok::<(), anyhow::Error>(())
})?;
Ok(commit_id)
}
pub fn record_evidence_prompt(&self, params: PromptParams) -> Result<()> {
let now = Utc::now().to_rfc3339();
let metadata = json!({
"session_id": params.session_id,
"role": params.role,
"sequence": params.sequence,
"source": params.source,
"input_hash": params.input_hash,
});
let metadata_str = json_to_string(&metadata)?;
let session_id = params.session_id.clone();
let session_agent_id = self.session_agent_sql_id(&session_id)?.ok_or_else(|| {
anyhow::anyhow!("Session {} not found for prompt evidence", session_id)
})?;
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO reasoning_logs (agent_id, content, project_id, metadata, created_at, session_id)
VALUES (?1, ?2, NULL, ?3, ?4, ?5)",
rusqlite::params![
session_agent_id,
params.role,
metadata_str,
now,
params.session_id
],
)?;
Ok::<(), anyhow::Error>(())
})?;
let prompt_entity = GraphEntity {
id: 0,
kind: "ReasoningLog".to_string(),
name: format!("{}:{}", session_id, params.sequence),
file_path: None,
data: json!({
"session_id": params.session_id,
"role": params.role,
"sequence": params.sequence,
"content_summary": params.content_summary,
"source": params.source,
"input_hash": params.input_hash,
"output_hash": params.output_hash,
"model": params.model,
}),
};
let prompt_entity_id = self
.inner
.insert_entity(&prompt_entity)
.map_err(|e| anyhow::anyhow!("Failed to insert prompt entity: {}", e))?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
self.insert_edge(
prompt_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": ProvenanceData::new("record_evidence_prompt").to_value()}),
)?;
}
self.link_entity_to_project(
prompt_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"role": params.role,
"sequence": params.sequence,
"content_summary": params.content_summary,
"source": params.source,
"input_hash": params.input_hash,
"input_tokens": params.input_tokens,
"output_hash": params.output_hash,
"output_tokens": params.output_tokens,
"latency_ms": params.latency_ms,
"model": params.model,
"cost_usd": params.cost_usd,
});
self.append_event_log(
"prompt",
&format!("{}:{}", session_id, params.sequence),
&session_id,
&payload,
)?;
Ok(())
}
pub fn record_evidence_tool_call(&self, params: ToolCallParams) -> Result<()> {
let now = Utc::now().to_rfc3339();
let metadata = json!({
"session_id": params.session_id,
"sequence": params.sequence,
"source": params.source,
"tool_name": params.tool_name,
"tool_category": params.tool_category,
"tool_version": params.tool_version,
"input_hash": params.input_hash,
"input_summary": params.input_summary,
"output_hash": params.output_hash,
"output_summary": params.output_summary,
"input_tokens_est": params.input_tokens_est,
});
let metadata_str = json_to_string(&metadata)?;
let session_id = params.session_id.clone();
let tool_name = params.tool_name.clone();
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO tool_calls (reasoning_log_id, tool_name, args, project_id, created_at, session_id)
VALUES (NULL, ?1, ?2, NULL, ?3, ?4)",
rusqlite::params![params.tool_name, metadata_str, now, params.session_id],
)?;
Ok::<(), anyhow::Error>(())
})?;
let tool_entity = GraphEntity {
id: 0,
kind: EntityType::ToolCall.as_str().to_string(),
name: tool_name.clone(),
file_path: None,
data: json!({
"session_id": params.session_id,
"sequence": params.sequence,
"source": params.source,
"tool_name": params.tool_name,
"tool_version": params.tool_version,
"tool_category": params.tool_category,
"input_hash": params.input_hash,
"output_hash": params.output_hash,
"exit_status": params.exit_status,
}),
};
let tool_entity_id = self
.inner
.insert_entity(&tool_entity)
.map_err(|e| anyhow::anyhow!("Failed to insert tool call entity: {}", e))?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
let tool_prov = ProvenanceData::new("record_evidence_tool_call").to_value();
self.insert_edge(
tool_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": tool_prov}),
)?;
self.insert_edge(
session_entity_id,
tool_entity_id,
EdgeType::HandledByTool,
json!({"provenance": tool_prov}),
)?;
}
self.link_entity_to_project(
tool_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"sequence": params.sequence,
"source": params.source,
"tool_name": params.tool_name,
"tool_version": params.tool_version,
"input_hash": params.input_hash,
"input_summary": params.input_summary,
"output_hash": params.output_hash,
"output_summary": params.output_summary,
"exit_status": params.exit_status,
"latency_ms": params.latency_ms,
"input_tokens_est": params.input_tokens_est,
"tool_category": params.tool_category,
});
self.append_event_log(
"tool_call",
&match params.sequence {
Some(sequence) => format!("{}:{}:{}", session_id, tool_name, sequence),
None => format!("{}:{}", session_id, tool_name),
},
&session_id,
&payload,
)?;
Ok(())
}
pub fn record_evidence_file_write(&self, params: FileWriteParams) -> Result<()> {
let session_id = params.session_id.clone();
let file_path = params.file_path.clone();
let file_entity_id = self.ensure_relation_endpoint(&RelationEndpoint {
kind: "File".to_string(),
name: params.file_path.clone(),
file_path: Some(params.file_path.clone()),
data: json!({
"sequence": params.sequence,
"file_id": params.file_id,
"before_hash": params.before_hash,
"after_hash": params.after_hash,
"write_type": params.write_type,
}),
})?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
self.insert_edge(
file_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": ProvenanceData::new("record_evidence_file_write").to_value()}),
)?;
}
self.link_entity_to_project(
file_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"sequence": params.sequence,
"file_path": params.file_path,
"file_id": params.file_id,
"before_hash": params.before_hash,
"after_hash": params.after_hash,
"lines_added": params.lines_added,
"lines_deleted": params.lines_deleted,
"lines_changed": params.lines_changed,
"write_type": params.write_type,
});
self.append_event_log(
"file_write",
&match params.sequence {
Some(sequence) => format!("{}:{}:{}", session_id, file_path, sequence),
None => format!("{}:{}", session_id, file_path),
},
¶ms.session_id,
&payload,
)?;
Ok(())
}
pub fn record_evidence_file_access(&self, params: FileAccessParams) -> Result<()> {
let session_id = params.session_id.clone();
let file_path = params.file_path.clone();
let file_entity_id = self.ensure_relation_endpoint(&RelationEndpoint {
kind: "File".to_string(),
name: params.file_path.clone(),
file_path: Some(params.file_path.clone()),
data: json!({
"path": params.file_path,
}),
})?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
let file_access_prov = ProvenanceData::new("record_evidence_file_access").to_value();
self.insert_edge(
session_entity_id,
file_entity_id,
EdgeType::Accessed,
json!({
"sequence": params.sequence,
"access_type": params.access_type,
"tool_name": params.tool_name,
"source": params.source,
"provenance": file_access_prov,
}),
)?;
self.insert_edge(
file_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({
"source": params.source,
"provenance": file_access_prov,
}),
)?;
}
self.link_entity_to_project(
file_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"sequence": params.sequence,
"file_path": params.file_path,
"access_type": params.access_type,
"tool_name": params.tool_name,
"source": params.source,
});
self.append_event_log(
"file_access",
&format!("{}:{}:{}", session_id, file_path, params.sequence),
&session_id,
&payload,
)?;
Ok(())
}
pub fn record_evidence_commit(&self, params: CommitParams) -> Result<()> {
let commit_id = uuid::Uuid::now_v7().to_string();
let now = Utc::now().to_rfc3339();
let session_id = params.session_id.clone();
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO commits
(commit_id, session_id, commit_sha, parent_sha, message, author,
timestamp, files_changed, lines_inserted, lines_deleted, commit_type, feature_tag)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)",
rusqlite::params![
commit_id,
params.session_id,
params.commit_sha,
params.parent_sha,
params.message,
params.author,
now,
params.files_changed,
params.lines_inserted,
params.lines_deleted,
params.commit_type,
params.feature_tag
],
)?;
Ok::<(), anyhow::Error>(())
})?;
let data = json!({
"commit_id": commit_id,
"commit_sha": params.commit_sha,
"commit_type": params.commit_type,
"feature_tag": params.feature_tag,
});
let entity = GraphEntity {
id: 0,
kind: EntityType::Commit.as_str().to_string(),
name: format!(
"{}:{}",
params.commit_sha.chars().take(8).collect::<String>(),
params.commit_type
),
file_path: None,
data,
};
let commit_entity_id = self
.inner
.insert_entity(&entity)
.map_err(|e| anyhow::anyhow!("Failed to insert Commit entity: {}", e))?;
if let Some(session_entity_id) =
self.find_entity_id_by_data("Session", "session_id", &session_id)?
{
let commit_prov = ProvenanceData::new("record_evidence_commit").to_value();
self.insert_edge(
session_entity_id,
commit_entity_id,
EdgeType::Created,
json!({"provenance": commit_prov}),
)?;
self.insert_edge(
commit_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": commit_prov}),
)?;
}
self.link_entity_to_project(
commit_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"commit_sha": params.commit_sha,
"commit_type": params.commit_type,
"files_changed": params.files_changed,
"feature_tag": params.feature_tag,
});
self.append_event_log("commit", &commit_id, &session_id, &payload)?;
Ok(())
}
pub fn record_evidence_test_run(&self, params: TestRunParams) -> Result<()> {
let test_run_id = uuid::Uuid::now_v7().to_string();
let now = Utc::now().to_rfc3339();
let session_id = params.session_id.clone();
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO test_runs
(test_run_id, session_id, commit_sha, test_command, test_suite,
test_name, result, duration_ms, logs_summary, timestamp)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
rusqlite::params![
test_run_id,
params.session_id,
params.commit_sha,
params.test_command,
params.test_suite,
params.test_name,
params.result,
params.duration_ms,
params.logs_summary,
now
],
)?;
Ok::<(), anyhow::Error>(())
})?;
let data = json!({
"test_run_id": test_run_id,
"test_name": params.test_name,
"result": params.result,
"duration_ms": params.duration_ms,
});
let entity = GraphEntity {
id: 0,
kind: EntityType::TestRun.as_str().to_string(),
name: format!("{}:{}", params.test_name, params.result),
file_path: None,
data,
};
let test_entity_id = self
.inner
.insert_entity(&entity)
.map_err(|e| anyhow::anyhow!("Failed to insert TestRun entity: {}", e))?;
if let Some(session_entity_id) =
self.find_entity_id_by_data("Session", "session_id", &session_id)?
{
let test_prov = ProvenanceData::new("record_evidence_test_run").to_value();
self.insert_edge(
session_entity_id,
test_entity_id,
EdgeType::VerifiedBy,
json!({"provenance": test_prov}),
)?;
self.insert_edge(
test_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": test_prov}),
)?;
}
if let Some(commit_sha) = params.commit_sha.as_deref() {
if let Some(commit_entity_id) =
self.find_entity_id_by_data(EntityType::Commit.as_str(), "commit_sha", commit_sha)?
{
self.insert_edge(
commit_entity_id,
test_entity_id,
EdgeType::TestedBy,
json!({"provenance": ProvenanceData::new("record_evidence_test_run").to_value()}),
)?;
}
}
self.link_entity_to_project(
test_entity_id,
self.session_project(&session_id)?.as_deref(),
)?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"test_name": params.test_name,
"result": params.result,
"duration_ms": params.duration_ms,
});
self.append_event_log("test", &test_run_id, &session_id, &payload)?;
Ok(())
}
pub fn record_evidence_fix_chain(&self, params: FixChainParams) -> Result<()> {
let fix_chain_id = uuid::Uuid::now_v7().to_string();
let now = Utc::now().to_rfc3339();
let session_id = params.session_id.clone();
let bug_commit_id =
self.ensure_commit_sql_row(&session_id, ¶ms.bug_commit_sha, "bug")?;
let fix_commit_id =
self.ensure_commit_sql_row(&session_id, ¶ms.fix_commit_sha, "fix")?;
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO fix_chains
(fix_chain_id, bug_commit_id, fix_commit_id, fix_session_id,
fix_type, severity, cycles_to_fix, bug_timestamp, fix_timestamp, time_to_fix_ms)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
rusqlite::params![
fix_chain_id,
bug_commit_id,
fix_commit_id,
params.session_id,
params.fix_type,
params.severity,
params.cycles_to_fix,
now,
now,
params.time_to_fix_ms
],
)?;
Ok::<(), anyhow::Error>(())
})?;
let bug_entity_id = self.ensure_relation_endpoint(&RelationEndpoint {
kind: EntityType::Commit.as_str().to_string(),
name: format!(
"{}:{}",
params.bug_commit_sha.chars().take(8).collect::<String>(),
"bug"
),
file_path: None,
data: json!({"commit_sha": params.bug_commit_sha}),
})?;
let fix_entity_id = self.ensure_relation_endpoint(&RelationEndpoint {
kind: EntityType::Commit.as_str().to_string(),
name: format!(
"{}:{}",
params.fix_commit_sha.chars().take(8).collect::<String>(),
"fix"
),
file_path: None,
data: json!({"commit_sha": params.fix_commit_sha}),
})?;
self.insert_edge(
bug_entity_id,
fix_entity_id,
EdgeType::FixedBy,
json!({
"fix_type": params.fix_type,
"severity": params.severity,
"cycles_to_fix": params.cycles_to_fix,
"time_to_fix_ms": params.time_to_fix_ms,
}),
)?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
self.insert_edge(
fix_entity_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": ProvenanceData::new("record_evidence_fix_chain").to_value()}),
)?;
}
self.link_entity_to_project(fix_entity_id, self.session_project(&session_id)?.as_deref())?;
self.ingest_relation_hints(¶ms.relations)?;
let payload = json!({
"bug_commit_sha": params.bug_commit_sha,
"fix_commit_sha": params.fix_commit_sha,
"fix_type": params.fix_type,
"severity": params.severity,
"cycles_to_fix": params.cycles_to_fix,
});
self.append_event_log("fix_linked", &fix_chain_id, &session_id, &payload)?;
Ok(())
}
pub fn record_evidence_bench_run(
&self,
session_id: String,
bench_name: String,
mean_ns: Option<i64>,
median_ns: Option<i64>,
p95_ns: Option<i64>,
is_regression: bool,
) -> Result<()> {
let bench_run_id = uuid::Uuid::now_v7().to_string();
let now = Utc::now().to_rfc3339();
self.with_raw_connection(|conn| {
conn.execute(
"INSERT INTO bench_runs
(bench_run_id, session_id, bench_name, mean_ns, median_ns, p95_ns, is_regression, timestamp)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
rusqlite::params![
bench_run_id, session_id, bench_name, mean_ns, median_ns, p95_ns,
is_regression as i64, now
],
)?;
Ok::<(), anyhow::Error>(())
})?;
if is_regression {
let regression_id = self.ensure_relation_endpoint(&RelationEndpoint {
kind: "Failure".to_string(),
name: format!("bench:{}", bench_name),
file_path: None,
data: json!({
"bench_name": bench_name,
"mean_ns": mean_ns,
"median_ns": median_ns,
"p95_ns": p95_ns,
}),
})?;
if let Some(session_entity_id) = self.maybe_session_entity_id(&session_id)? {
let bench_prov = ProvenanceData::new("record_evidence_bench_run").to_value();
self.insert_edge(
regression_id,
session_entity_id,
EdgeType::RegressedBy,
json!({"provenance": bench_prov}),
)?;
self.insert_edge(
regression_id,
session_entity_id,
EdgeType::ObservedIn,
json!({"provenance": bench_prov}),
)?;
}
self.link_entity_to_project(
regression_id,
self.session_project(&session_id)?.as_deref(),
)?;
}
let payload = json!({
"bench_name": bench_name,
"mean_ns": mean_ns,
"is_regression": is_regression,
});
self.append_event_log("bench", &bench_run_id, &session_id, &payload)?;
Ok(())
}
}