Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions crates/tracedecay-agent-hosts/src/agents/context_scout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,10 +1460,6 @@ impl<M> ContextScoutDurableRuntimeV1<M> {
}
}

pub fn is_current(&self, work: ContextScoutWorkV1) -> bool {
self.coalescer.is_current(work)
}

pub(crate) fn restore_startup(
&mut self,
startup: &ContextScoutDurableStartupOutcomeV1,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeSet;

use sha2::{Digest, Sha256};
use tracedecay_domain::canonical_text::sha256_hex;
use tracedecay_runtime_core::db::engine::{QueryExecutor, params};

use crate::configuration::FreshConfigurationStoreEvidence;
Expand Down Expand Up @@ -378,7 +378,7 @@ async fn validate_temporal_table_definition_digest(
let sql = row
.get::<String>(0)
.map_err(|error| global_db_operation_error(OPERATION, error))?;
let digest = hex::encode(Sha256::digest(normalize_schema_sql(&sql).as_bytes()));
let digest = sha256_hex(normalize_schema_sql(&sql).as_bytes());
if digest != expected_digest {
return Err(session_temporal_reset_required(format!(
"temporal table '{table}' has an incompatible CREATE TABLE contract"
Expand Down
9 changes: 4 additions & 5 deletions crates/tracedecay-graph-db/src/generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use std::sync::{Arc, Condvar, Mutex, OnceLock};
use grafeo_engine::GrafeoDB;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tracedecay_domain::canonical_text::{encode_lowercase_hex, encode_tagged_lowercase_hex};
use tracedecay_domain::canonical_text::{
encode_lowercase_hex, encode_tagged_lowercase_hex, sha256_hex,
};
use tracedecay_store::runtime::{
GraphDependencyGenerationClosureDigestV1, GraphDependencyGenerationIdentityV1,
GraphGenerationIdV1, GraphNamespaceV1, GraphProjectionIdV1, GraphProjectionIdentityV1,
Expand Down Expand Up @@ -885,10 +887,7 @@ pub(crate) fn physical_namespace(
"failed to encode physical graph generation identity: {error}"
))
})?;
GraphNamespace::new(format!(
"generation:{}",
hex::encode(Sha256::digest(encoded))
))
GraphNamespace::new(format!("generation:{}", sha256_hex(&encoded)))
}

pub(crate) fn is_physical_generation_namespace(namespace: &GraphNamespace) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions crates/tracedecay-graph-db/src/store_quarantine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use std::time::{SystemTime, UNIX_EPOCH};

use fs2::FileExt;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tracedecay_domain::canonical_text::sha256_hex;
use tracedecay_private_fs::framed_log::{DirectorySyncPolicy, atomic_write, sync_directory};

use crate::{GraphDb, GraphDbError};
Expand Down Expand Up @@ -347,7 +347,7 @@ fn quarantine_durability_failure(
}

fn fault_fingerprint(fault: &str) -> String {
format!("sha256:{}", hex::encode(Sha256::digest(fault.as_bytes())))
format!("sha256:{}", sha256_hex(fault.as_bytes()))
}

/// `graph.grafeo` -> `graph.grafeo.wal`, matching Grafeo's sidecar layout.
Expand Down
20 changes: 14 additions & 6 deletions crates/tracedecay-graph-query/src/context/read_modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,22 @@ pub fn estimate_tokens(s: &str) -> u32 {
s.chars().count().div_ceil(4).min(u32::MAX as usize) as u32
}
pub fn render_lines(source: &str, range: LineRange) -> String {
let lines = source.lines().collect::<Vec<_>>();
let start = range.start.saturating_sub(1) as usize;
let end = (range.end as usize).min(lines.len());
if start >= end {
String::new()
} else {
lines[start..end].join("\n")
let end_inclusive = range.end as usize;
if start >= end_inclusive {
return String::new();
}
let mut selected = source.lines().skip(start).take(end_inclusive - start);
let Some(first) = selected.next() else {
return String::new();
};
let mut body = String::with_capacity(first.len());
body.push_str(first);
for line in selected {
body.push('\n');
body.push_str(line);
}
body
}

#[hotpath::measure(label = "usecases.context.render_map")]
Expand Down
9 changes: 4 additions & 5 deletions crates/tracedecay-mcp/src/handlers/analysis/field_sites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,14 @@ pub async fn handle_field_sites(
// nodes anyway cost one daemon round trip per file in the project —
// O(store) work to answer a question whose result is a handful of
// sites.
let masked = if path_is_rust(file) {
let masked = path_is_rust(file).then(|| {
tracedecay_code_extraction::source_mask::masked_rust_source_with(
&source,
tracedecay_code_extraction::source_mask::MaskOptions::CODE_SCAN,
)
} else {
source.clone()
};
let sites = find_field_references(&masked, &field_name);
});
let sites =
find_field_references(masked.as_deref().unwrap_or(&source), &field_name);
if sites.is_empty() {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,13 @@ pub async fn handle_unsafe_patterns(
// masked copy; the original line is kept for the emitted snippet.
// Non-Rust files are scanned raw (the Rust grammar would
// mis-tokenise them).
let masked = if path_is_rust(file) {
let masked_owned = path_is_rust(file).then(|| {
tracedecay_code_extraction::source_mask::masked_rust_source_with(
&source,
tracedecay_code_extraction::source_mask::MaskOptions::CODE_SCAN,
)
} else {
source.clone()
};
});
let masked = masked_owned.as_deref().unwrap_or(&source);
let test_lines = if path_is_rust(file) {
tracedecay_code_extraction::source_mask::rust_test_lines(&source).map_err(
|error| {
Expand Down
10 changes: 8 additions & 2 deletions crates/tracedecay-mcp/src/handlers/graph/navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,11 +799,17 @@ fn collect_method_bodies(
});

let mut out: Vec<Value> = Vec::new();
let mut cached_path: Option<String> = None;
let mut cached_source = String::new();
for (file_path, _, child) in methods {
let metadata = required_graph_metadata(&child)?;
let source = graph.read_indexed_source_file(&file_path)?;
if cached_path.as_deref() != Some(file_path.as_str()) {
cached_source = graph.read_indexed_source_file(&file_path)?;
cached_path = Some(file_path);
}
let end_line = graph_symbol_end_line(metadata)?;
let body = crate::handlers::info::extract_lines(&source, metadata.start_line, end_line);
let body =
crate::handlers::info::extract_lines(&cached_source, metadata.start_line, end_line);
out.push(json!({
"name": metadata.simple_name,
"kind": metadata.kind,
Expand Down
17 changes: 13 additions & 4 deletions crates/tracedecay-mcp/src/handlers/info/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,22 @@ use super::verified::{
/// raw tree-sitter row index, so the caller passes them through unchanged.
/// Returns the empty string if the range is out of bounds.
pub fn extract_lines(source: &str, start_line: u32, end_line: u32) -> String {
let lines: Vec<&str> = source.lines().collect();
let start = start_line as usize;
let end = (end_line as usize).saturating_add(1).min(lines.len());
if start >= lines.len() || start >= end {
let end_exclusive = (end_line as usize).saturating_add(1);
if start >= end_exclusive {
return String::new();
}
lines[start..end].join("\n")
let mut selected = source.lines().skip(start).take(end_exclusive - start);
let Some(first) = selected.next() else {
return String::new();
};
let mut body = String::with_capacity(first.len());
body.push_str(first);
for line in selected {
body.push('\n');
body.push_str(line);
}
body
}

#[hotpath::measure(label = "mcp.info.body.total")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::{BTreeMap, BTreeSet};

use sha2::{Digest, Sha256};
use tracedecay_domain::FactOwnerV1;
use tracedecay_domain::canonical_text::sha256_hex;
use tracedecay_graph_db::{
GraphEntity, GraphEntityId, GraphEntityRef, GraphGenerationId, GraphGenerationManifest,
GraphGenerationRelation, GraphLabel, GraphProjectionIdentity, GraphRelationId,
Expand Down Expand Up @@ -53,13 +54,13 @@ pub(super) fn build_manifest(
.map_err(|error| graph_error(owner, error))?;
insert_projection_entity(&mut entity_ids, from.clone())?;
insert_projection_entity(&mut entity_ids, to.clone())?;
let relation_digest = hex::encode(Sha256::digest(
let relation_digest = sha256_hex(
format!(
"{}\0{}\0{}",
relation.source, relation.target, relation.kind
)
.as_bytes(),
));
);
relations.push(
GraphGenerationRelation::new(
GraphRelationId::new(format!("memory-relation:{relation_digest}"))
Expand Down
9 changes: 3 additions & 6 deletions crates/tracedecay-session-temporal-store/src/relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::sync::Arc;

use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use thiserror::Error;
use tracedecay_domain::canonical_text::sha256_hex;
use tracedecay_domain::{
AgentInstanceId, CopyProofV1, MessageOccurrenceIdV1, ProjectId, RetrievalAnchorId, SessionId,
TemporalValidityV1, ThreadId, UserProfileId, UtcMicros,
Expand Down Expand Up @@ -405,11 +405,8 @@ pub(crate) fn projection_watermark(
.then_with(|| left.agent_label.cmp(&right.agent_label))
});
let encoded = serde_json::to_vec(&canonical).map_err(|_| SessionRelationError::Invalid)?;
GraphWatermark::new(format!(
"session-relations:{}",
hex::encode(Sha256::digest(encoded))
))
.map_err(map_graph_error)
GraphWatermark::new(format!("session-relations:{}", sha256_hex(&encoded)))
.map_err(map_graph_error)
}

fn build_graph(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};

use sha2::{Digest as _, Sha256};
use tracedecay_graph_db::{GraphIdempotencyKey, GraphNamespace, GraphProjectorRevision};
use tracedecay_runtime_core::shard_runtime::VerifiedGraphRuntimePortV1;

use super::{
CommitEvidence, CommitRelation, CommitSessionRecord, GIT_EVIDENCE_PROJECTOR_REVISION,
GitCorrelationError, GitCorrelationSessionStore, GitEvidenceProjectionStore,
GitEvidenceProjectionV1, SessionGitSpan, SpanObservation, SpanOverlapKind,
GitEvidenceProjectionV1, SessionGitSpan, SpanObservation, SpanOverlapKind, digest_bytes,
git_evidence_projection_identity, normalize_worktree, observation_extends_span,
providers_compatible, publish_git_evidence_projection, recover_git_evidence_projection,
};
Expand Down Expand Up @@ -185,10 +184,7 @@ pub fn stable_backfill_span(
branch.unwrap_or("\0")
);
SessionGitSpan {
span_id: format!(
"backfill:{}",
hex::encode(Sha256::digest(identity.as_bytes()))
),
span_id: format!("backfill:{}", digest_bytes(identity.as_bytes())),
provider: provider.to_owned(),
session_id: session_id.to_owned(),
thread_id: None,
Expand Down Expand Up @@ -483,10 +479,7 @@ fn transcript_span_id(observation: &SpanObservation, worktree: &str) -> String {
"{}\0{}\0{thread_id}\0{branch}\0{}\0{}\0{:?}",
observation.provider, observation.session_id, worktree, observation.ts, observation.source,
);
format!(
"transcript:{}",
hex::encode(Sha256::digest(material.as_bytes()))
)
format!("transcript:{}", digest_bytes(material.as_bytes()))
}

pub fn graph_evidence_publication_key(
Expand All @@ -495,7 +488,7 @@ pub fn graph_evidence_publication_key(
commits: &[CommitSessionRecord],
) -> Result<String, GitCorrelationError> {
let bytes = serde_json::to_vec(&(prefix, spans, commits))?;
Ok(format!("{prefix}:{}", hex::encode(Sha256::digest(bytes))))
Ok(format!("{prefix}:{}", digest_bytes(&bytes)))
}

fn merge_span(spans: &mut Vec<SessionGitSpan>, incoming: &SessionGitSpan) -> bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use sha2::{Digest as _, Sha256};
use tracedecay_runtime_core::db::engine::{Executor, QueryExecutor, params};

use super::{
CommitSessionRecord, GitCorrelationError, GitCorrelationSessionStore, GitCorrelationWriteTxn,
SpanObservation,
SpanObservation, digest_bytes,
};

/// Maximum exact receipts replayed by one startup or host-admission pass.
Expand Down Expand Up @@ -62,7 +61,7 @@ pub async fn enqueue_git_evidence_publication(
let receipt_material = serde_json::to_vec(&(publication_prefix, &payload))?;
let receipt_id = format!(
"git-evidence-publication:{}",
hex::encode(Sha256::digest(receipt_material))
digest_bytes(&receipt_material)
);
conn.execute(
"INSERT OR IGNORE INTO git_evidence_publication_outbox (
Expand Down
14 changes: 5 additions & 9 deletions crates/tracedecay-sessions/src/runtime/git_correlation/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::future::Future;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};

use sha2::{Digest as _, Sha256};
use tracedecay_graph_db::{
GraphCancellation, GraphDbError, GraphEntity, GraphEntityId, GraphEntityRef, GraphGenerationId,
GraphGenerationManifest, GraphGenerationRelation, GraphIdempotencyKey, GraphLabel,
Expand All @@ -25,8 +24,8 @@ use super::{
GitCorrelationError, GitEvidenceProjectionV1, GitRefFilter, GitScopeFilter,
SessionGitCorrelationHit, SessionGitSpan, SessionsForQuery, SpanObservation,
canonical_provider_map, commit_hits, commit_identities_with_producer_fallback,
commit_record_matches_query, commit_record_order, scope_session_ids, sessions_for_limit,
span_hits, span_matches_query,
commit_record_matches_query, commit_record_order, digest_bytes, scope_session_ids,
sessions_for_limit, span_hits, span_matches_query,
};

const GRAPH_READ_PAGE_ITEMS: usize = 10_000;
Expand Down Expand Up @@ -102,11 +101,8 @@ pub fn git_evidence_generation_id(
projection,
projector_revision,
))?;
GraphGenerationId::new(format!(
"session-git-evidence:{}",
hex::encode(Sha256::digest(bytes))
))
.map_err(Into::into)
GraphGenerationId::new(format!("session-git-evidence:{}", digest_bytes(&bytes)))
.map_err(Into::into)
}

/// Projects the complete evidence into one generation manifest.
Expand Down Expand Up @@ -1452,7 +1448,7 @@ fn stable_identity(kind: &str, material: &str) -> String {
}

fn stable_digest(material: &str) -> String {
hex::encode(Sha256::digest(material.as_bytes()))
digest_bytes(material.as_bytes())
}

struct AtomicGraphCancellation(Arc<AtomicBool>);
Expand Down
14 changes: 9 additions & 5 deletions crates/tracedecay-store-runtime/src/remote_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use tracedecay_contracts::{
EvidenceDomain, EvidencePacket, OperationBudgetUsage, OperationReceipt, PageState,
RetrievalEvidence, TemporalState,
};
use tracedecay_domain::canonical_text::sha256_hex;
use tracedecay_domain::{CurrentRemoteAuthorityStateV1, UtcMicros};
use tracedecay_rusqlite_runtime::remote::{RemoteQueryAuthoritySnapshotV1, RemoteSqliteStorageV1};
use tracedecay_store::{
Expand Down Expand Up @@ -355,11 +356,14 @@ fn current_frontier(
fn runtime_control(
command: &RemoteExactObservationQueryCommandV1,
) -> Result<RuntimeRequestControlV1, RemoteExactObservationQueryErrorV1> {
let suffix = hex::encode(Sha256::digest(format!(
"{}:{}",
command.request_id.as_str(),
command.observation_id.as_str()
)));
let suffix = sha256_hex(
format!(
"{}:{}",
command.request_id.as_str(),
command.observation_id.as_str()
)
.as_bytes(),
);
Ok(RuntimeRequestControlV1 {
requested_at: command.observed_at,
deadline: RuntimeDeadlineV1 {
Expand Down
Loading
Loading