Skip to content
Merged
29 changes: 0 additions & 29 deletions cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,16 @@ pub(crate) trait HasLogger {
fn logger(&self) -> &Self::Logger;
}

#[allow(dead_code)]
pub(crate) trait HasTelemetry {
type Telemetry: TelemetryTrait;

fn telemetry(&self) -> &Self::Telemetry;
}

#[allow(dead_code)]
pub(crate) trait HasFs {
type Fs: services::capabilities::FsOps;

fn fs(&self) -> &Self::Fs;
}

#[allow(dead_code)]
pub(crate) trait HasGit {
type Git: services::capabilities::GitOps;

Expand Down Expand Up @@ -113,23 +108,12 @@ where
HasLogger::logger(self)
}

#[allow(dead_code)]
pub(crate) fn fs(&self) -> &F {
HasFs::fs(self)
}

#[allow(dead_code)]
pub(crate) fn git(&self) -> &G {
HasGit::git(self)
}

fn telemetry(&self) -> &T {
HasTelemetry::telemetry(self)
}

/// Returns a context for a command-scoped repository root while preserving
/// the runtime logger, telemetry, and capability dependencies.
#[allow(dead_code)]
pub(crate) fn with_repo_root(&self, repo_root: impl Into<PathBuf>) -> Self {
Self {
logger: self.logger,
Expand All @@ -139,15 +123,6 @@ where
repo_root: Some(repo_root.into()),
}
}

/// Returns the resolved repository root path when available.
///
/// Lifecycle providers use this during setup to avoid re-resolving
/// the repository root independently.
#[allow(dead_code)]
pub fn repo_root(&self) -> Option<&Path> {
HasRepoRoot::repo_root(self)
}
}

impl<L, T, F, G> HasLogger for AppContext<'_, L, T, F, G>
Expand Down Expand Up @@ -186,10 +161,6 @@ where
G: services::capabilities::GitOps,
{
type Fs = F;

fn fs(&self) -> &Self::Fs {
self.fs
}
}

impl<L, T, F, G> HasGit for AppContext<'_, L, T, F, G>
Expand Down
1 change: 0 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
mod app;
mod cli_schema;
mod command_surface;
#[allow(dead_code)]
mod generated_migrations {
include!(concat!(env!("OUT_DIR"), "/generated_migrations.rs"));
}
Expand Down
100 changes: 0 additions & 100 deletions cli/src/services/agent_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,34 +188,22 @@ fn parse_commit_timestamp(commit_timestamp: &str) -> Result<DateTime<FixedOffset
})
}

#[allow(dead_code)]
const AGENT_TRACE_SCHEMA_PATH: &str = "config/schema/agent-trace.schema.json";
#[allow(dead_code)]
pub(crate) const AGENT_TRACE_SCHEMA_JSON: &str = include_str!(concat!(
env!("OUT_DIR"),
"/static/schema/agent-trace.schema.json"
));

#[allow(dead_code)]
static AGENT_TRACE_SCHEMA_VALIDATOR: OnceLock<Validator> = OnceLock::new();

#[derive(Debug, Eq, PartialEq)]
#[allow(dead_code)]
pub(crate) enum AgentTraceValidationError {
FileRead { path: String, message: String },
InvalidJson { message: String },
SchemaValidation { errors: Vec<String> },
}

impl fmt::Display for AgentTraceValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FileRead { path, message } => {
write!(f, "Agent Trace JSON file could not be read at '{path}': {message}")
}
Self::InvalidJson { message } => {
write!(f, "Agent Trace JSON must be valid JSON: {message}")
}
Self::SchemaValidation { errors } => write!(
f,
"Agent Trace JSON failed schema validation against embedded schema '{AGENT_TRACE_SCHEMA_PATH}': {}",
Expand All @@ -227,7 +215,6 @@ impl fmt::Display for AgentTraceValidationError {

impl Error for AgentTraceValidationError {}

#[allow(dead_code)]
fn agent_trace_schema_validator() -> &'static Validator {
AGENT_TRACE_SCHEMA_VALIDATOR.get_or_init(|| {
let schema: Value = serde_json::from_str(AGENT_TRACE_SCHEMA_JSON)
Expand All @@ -236,7 +223,6 @@ fn agent_trace_schema_validator() -> &'static Validator {
})
}

#[allow(dead_code)]
pub(crate) fn validate_agent_trace_value(value: &Value) -> Result<(), AgentTraceValidationError> {
let mut errors = agent_trace_schema_validator()
.iter_errors(value)
Expand All @@ -252,26 +238,6 @@ pub(crate) fn validate_agent_trace_value(value: &Value) -> Result<(), AgentTrace
Err(AgentTraceValidationError::SchemaValidation { errors })
}

#[allow(dead_code)]
pub(crate) fn validate_agent_trace_json(raw: &str) -> Result<(), AgentTraceValidationError> {
let value: Value =
serde_json::from_str(raw).map_err(|error| AgentTraceValidationError::InvalidJson {
message: error.to_string(),
})?;

validate_agent_trace_value(&value)
}

#[allow(dead_code)]
pub(crate) fn validate_agent_trace_file(path: &Path) -> Result<(), AgentTraceValidationError> {
let raw =
std::fs::read_to_string(path).map_err(|error| AgentTraceValidationError::FileRead {
path: path.display().to_string(),
message: error.to_string(),
})?;

validate_agent_trace_json(&raw)
}
/// Classification of a single hunk's origin relative to the AI candidate patch.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -305,7 +271,6 @@ pub struct Conversation {
/// A related resource for a conversation entry.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
#[allow(dead_code)]
pub struct ConversationRelated {
/// Free-form related resource type.
#[serde(rename = "type")]
Expand Down Expand Up @@ -371,40 +336,6 @@ pub struct AgentTrace {
pub files: Vec<TraceFile>,
}

/// Classify a single `post_commit_patch` hunk against the corresponding
/// `intersection_patch` hunk (if any).
///
/// Two hunks correspond when they share the same `old_start` value within the
/// same file. This is the slot-matching rule that aligns `intersection_patch`
/// hunks to `post_commit_patch` hunks for comparison.
///
/// Returns:
/// - `HunkContributor::Ai` when the `intersection_patch` hunk exists and its
/// touched lines match the `post_commit_patch` hunk's touched lines exactly
/// (same count, same kind, same `line_number`, same content, in the same order).
/// - `HunkContributor::Mixed` when the `intersection_patch` hunk exists but its
/// touched lines differ from the `post_commit_patch` hunk's touched lines.
/// - `HunkContributor::Unknown` when no `intersection_patch` hunk with the same
/// `old_start` exists for this `post_commit_patch` hunk.
#[allow(dead_code)]
pub fn classify_hunk(
post_commit_hunk: &PatchHunk,
intersection_hunks: &[PatchHunk],
) -> HunkContributor {
let Some(intersection_hunk) = intersection_hunks
.iter()
.find(|h| h.old_start == post_commit_hunk.old_start)
else {
return HunkContributor::Unknown;
};

if hunks_match_exactly(post_commit_hunk, intersection_hunk) {
HunkContributor::Ai
} else {
HunkContributor::Mixed
}
}

type CoverageLineKey<'a> = (TouchedLineKind, u64, &'a str);

fn coverage_line_key(line: &TouchedLine) -> CoverageLineKey<'_> {
Expand Down Expand Up @@ -473,7 +404,6 @@ fn combined_model_id(
}
}

#[allow(dead_code)]
pub(crate) fn patches_have_overlap(
candidate_patch: &ParsedPatch,
target_patch: &ParsedPatch,
Expand All @@ -490,17 +420,6 @@ pub(crate) fn patch_has_touched_lines(patch: &ParsedPatch) -> bool {
.any(|file| file.hunks.iter().any(|hunk| !hunk.lines.is_empty()))
}

/// Check whether two hunks have identical touched lines in the same order.
fn hunks_match_exactly(left: &PatchHunk, right: &PatchHunk) -> bool {
if left.lines.len() != right.lines.len() {
return false;
}
left.lines.iter().zip(right.lines.iter()).all(|(ll, rl)| {
ll.kind == rl.kind && ll.line_number == rl.line_number && ll.content == rl.content
})
}

#[allow(dead_code)]
pub(crate) fn range_content_hash(hunk: &PatchHunk) -> String {
let mut input = Vec::new();
input.extend_from_slice(RANGE_CONTENT_HASH_INPUT_VERSION);
Expand Down Expand Up @@ -650,25 +569,6 @@ fn build_trace_file(
})
}

#[allow(dead_code)]
pub fn build_agent_trace(
constructed_patch: &ParsedPatch,
post_commit_patch: &ParsedPatch,
metadata: AgentTraceMetadataInput<'_>,
) -> Result<AgentTrace> {
let empty_mutation_ai_patch = ParsedPatch { files: Vec::new() };

build_agent_trace_from_evidence(
AgentTraceEvidence {
direct_patch: constructed_patch,
mutation_ai_patch: &empty_mutation_ai_patch,
},
post_commit_patch,
metadata,
)
}

#[allow(dead_code)]
pub fn build_agent_trace_from_evidence(
evidence: AgentTraceEvidence<'_>,
post_commit_patch: &ParsedPatch,
Expand Down
18 changes: 11 additions & 7 deletions cli/src/services/agent_trace/tests.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
use super::{
build_agent_trace, build_agent_trace_from_evidence, validate_agent_trace_value,
AgentTraceEvidence, AgentTraceMetadataInput, AgentTraceVcsType, AGENT_TRACE_VERSION,
build_agent_trace_from_evidence, validate_agent_trace_value, AgentTraceEvidence,
AgentTraceMetadataInput, AgentTraceVcsType, AGENT_TRACE_VERSION,
};
use crate::services::{
agent_trace::agent_trace_conversation_url,
patch::{combine_patches, parse_patch, ParsedPatch},
};
use serde_json::Value;

const TEST_COMMIT_TIMESTAMP: &str = "2026-04-23T10:20:30Z";
const TEST_COMMIT_REVISION: &str = "a0b1c2d3e4f5a6b7c8d9e0f11223344556677889";

#[derive(Clone, Copy)]
struct AgentTraceScenario {
incremental: &'static [&'static str],
post_commit: &'static str,
golden: &'static str,
}

const TEST_COMMIT_TIMESTAMP: &str = "2026-04-23T10:20:30Z";
const TEST_COMMIT_REVISION: &str = "a0b1c2d3e4f5a6b7c8d9e0f11223344556677889";

fn parse_fixtures(fixtures: &[&str]) -> Vec<ParsedPatch> {
fixtures
.iter()
Expand Down Expand Up @@ -60,8 +60,12 @@ fn assert_builds_expected_agent_trace(scenario: AgentTraceScenario) {
parse_patch(scenario.post_commit, None).expect("fixture patch should parse");
let golden: Value = serde_json::from_str(scenario.golden).expect("golden json should load");
validate_agent_trace_value(&golden).expect("golden json should validate against schema");
let actual = build_agent_trace(
&constructed_patch,
let empty_mutation_ai_patch = ParsedPatch { files: Vec::new() };
let actual = build_agent_trace_from_evidence(
AgentTraceEvidence {
direct_patch: &constructed_patch,
mutation_ai_patch: &empty_mutation_ai_patch,
},
&post_commit_patch,
AgentTraceMetadataInput {
commit_timestamp: TEST_COMMIT_TIMESTAMP,
Expand Down
6 changes: 1 addition & 5 deletions cli/src/services/agent_trace_db/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::services::db::{bootstrap_db_parent, collect_db_path_health, DbSpec};
use crate::services::default_paths::agent_trace_db_path_for_repository;
use crate::services::lifecycle::{
FixOutcome, FixResultRecord, HealthCategory, HealthFixability, HealthProblem,
HealthProblemKind, HealthSeverity, LifecycleProviderId, ServiceLifecycle, SetupOutcome,
HealthProblemKind, HealthSeverity, ServiceLifecycle, SetupOutcome,
};
use crate::services::repository_identity::resolve::{
resolve_repository_identity, RepositoryIdentitySource,
Expand All @@ -20,10 +20,6 @@ use super::repository::{RepositoryAgentTraceDb, RepositoryAgentTraceDbSpec};
pub struct AgentTraceDbLifecycle;

impl ServiceLifecycle for AgentTraceDbLifecycle {
fn id(&self) -> LifecycleProviderId {
LifecycleProviderId::AgentTraceDb
}

async fn diagnose<C: HasRepoRoot>(&self, ctx: &C) -> Vec<HealthProblem> {
diagnose_agent_trace_db_health(ctx.repo_root()).await
}
Expand Down
32 changes: 0 additions & 32 deletions cli/src/services/agent_trace_db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,23 +408,6 @@ fn claude_model_state_observation_from_turso(
})
}

#[allow(dead_code)]
async fn insert_message_with<M: DbSpec>(
db: &TursoDb<M>,
input: InsertMessageInsert,
) -> Result<u64> {
db.execute(
INSERT_MESSAGE_SQL,
(
input.session_id,
input.message_id,
input.role.to_string(),
input.generated_at_unix_ms,
),
)
.await
}

async fn insert_messages_with<M: DbSpec>(
db: &TursoDb<M>,
inputs: Vec<InsertMessageInsert>,
Expand Down Expand Up @@ -453,21 +436,6 @@ async fn insert_messages_with<M: DbSpec>(
db.execute(&sql, params).await
}

#[allow(dead_code)]
async fn insert_part_with<M: DbSpec>(db: &TursoDb<M>, input: InsertPartInsert) -> Result<u64> {
db.execute(
INSERT_PART_SQL,
(
input.part_type.to_string(),
input.text,
input.message_id,
input.session_id,
input.generated_at_unix_ms,
),
)
.await
}

async fn insert_parts_with<M: DbSpec>(
db: &TursoDb<M>,
inputs: Vec<InsertPartInsert>,
Expand Down
Loading
Loading