diff --git a/crates/tracedecay-automation-runtime/src/automation/artifact_payloads.rs b/crates/tracedecay-automation-runtime/src/automation/artifact_payloads.rs index 3c88c1960a..88427c31df 100644 --- a/crates/tracedecay-automation-runtime/src/automation/artifact_payloads.rs +++ b/crates/tracedecay-automation-runtime/src/automation/artifact_payloads.rs @@ -63,6 +63,7 @@ pub(super) struct ArtifactRefs { pub(super) optimizer_diagnosis: Value, } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_traces")] pub(super) fn traces_payload(ctx: &ArtifactPayloadContext<'_>) -> Value { let curation_result = (ctx.task == AgentTaskKind::MemoryCurator) .then(|| curation::memory_curation_trace_summary(ctx.record)); @@ -118,6 +119,7 @@ fn session_reflection_summary(record: &AutomationRunLedgerRecord) -> Value { }) } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_feedback")] pub(super) fn feedback_payload(ctx: &ArtifactPayloadContext<'_>, trace_ref: &Value) -> Value { json!({ "schema_version": 1, @@ -140,6 +142,7 @@ pub(super) fn feedback_payload(ctx: &ArtifactPayloadContext<'_>, trace_ref: &Val }) } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.derive_generated_evals")] pub(super) fn generated_eval_payloads(ctx: &ArtifactPayloadContext<'_>) -> GeneratedEvalPayloads { let definitions = generated_eval_definitions(ctx.record, ctx.task, ctx.policy); let count = definitions.len(); @@ -155,6 +158,7 @@ pub(super) fn generated_eval_payloads(ctx: &ArtifactPayloadContext<'_>) -> Gener } } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_generated_evals")] pub(super) fn generated_evals_payload( ctx: &ArtifactPayloadContext<'_>, refs: (&Value, &Value), @@ -224,6 +228,7 @@ pub(super) fn improvement_gate_payload( } } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_validation_gate")] pub(super) fn validation_gate_payload( ctx: &ArtifactPayloadContext<'_>, refs: (&Value, &Value, &Value), @@ -288,6 +293,7 @@ pub(super) fn validation_gate_payload( }) } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_optimizer_diagnosis")] pub(super) fn optimizer_diagnosis_payload( ctx: &ArtifactPayloadContext<'_>, refs: (&Value, &Value, &Value, &Value), @@ -334,6 +340,7 @@ pub(super) fn optimizer_diagnosis_payload( }) } +#[hotpath::measure(label = "automation_runtime.artifact_payloads.build_codex_handoff")] pub(super) fn codex_handoff_payload( ctx: &ArtifactPayloadContext<'_>, refs: &ArtifactRefs, diff --git a/crates/tracedecay-automation-runtime/src/automation/artifacts.rs b/crates/tracedecay-automation-runtime/src/automation/artifacts.rs index 56a4bbb1e7..2c1fd53b12 100644 --- a/crates/tracedecay-automation-runtime/src/automation/artifacts.rs +++ b/crates/tracedecay-automation-runtime/src/automation/artifacts.rs @@ -40,6 +40,7 @@ impl<'a> ImprovementArtifactWriter<'a> { } } + #[hotpath::measure(label = "automation_runtime.artifacts.prepare_artifact", future = true)] async fn write( &mut self, kind: AutomationRunArtifactKind, @@ -61,6 +62,10 @@ impl<'a> ImprovementArtifactWriter<'a> { } } +#[hotpath::measure( + label = "automation_runtime.artifacts.write_improvement_chain", + future = true +)] pub(crate) async fn write_improvement_artifacts( dashboard_root: &Path, run_id: &str, diff --git a/crates/tracedecay-automation-runtime/src/automation/backend_identity.rs b/crates/tracedecay-automation-runtime/src/automation/backend_identity.rs index ac372caaac..5e1e05437e 100644 --- a/crates/tracedecay-automation-runtime/src/automation/backend_identity.rs +++ b/crates/tracedecay-automation-runtime/src/automation/backend_identity.rs @@ -94,6 +94,7 @@ fn executable_digest_cache() -> &'static Mutex Result { // `canonical_sha256` is the crate's one identity primitive: key-ordered, // whitespace-free, and already used to derive the configuration identity @@ -129,6 +130,7 @@ fn backend_executable_identity(config: &AutomationConfig) -> Option { } } +#[hotpath::measure(label = "automation_runtime.backend_identity.resolve_executable")] fn codex_executable_identity(spec: &str) -> Value { match locate_backend_executable(spec) { Ok(Some(path)) => opened_executable_identity(spec, &path) @@ -246,6 +248,7 @@ fn opened_file_revision(_file: &File, _metadata: &Metadata) -> Option bool { .is_some() } +#[hotpath::measure(label = "automation_runtime.effect_journal.read_source_bindings")] pub fn retained_source_bindings( path: &Path, ) -> Result<(Option, Option)> { @@ -504,10 +505,12 @@ fn reserve_or_replay_with_index_and_writer( } } +#[hotpath::measure(label = "automation_runtime.effect_journal.read_record")] pub fn read_indexed_record_blocking(path: &Path) -> Result> { with_journal_lock(path, || read_stabilized_record(path)) } +#[hotpath::measure(label = "automation_runtime.effect_journal.read_terminal")] pub fn read_indexed_terminal_blocking(path: &Path) -> Result> { with_journal_lock(path, || { let Some(record) = read_stabilized_record(path)? else { @@ -544,6 +547,7 @@ impl DurableSettlementClassification { } /// Revalidates the exact intended settlement without changing journal state. +#[hotpath::measure(label = "automation_runtime.effect_journal.classify_settlement")] pub fn classify_durable_settlement_blocking( path: &Path, requested: &DurableAutomationAdmission, @@ -620,6 +624,7 @@ fn classify_durable_settlement_with_stabilizer( /// order used by binding and makes the state check atomic with subsequent /// cleanup: a writer cannot stage and bind `Prepared` between this check and /// deletion. +#[hotpath::measure(label = "automation_runtime.effect_journal.check_unbound_cleanup")] pub fn unbound_reserved_cleanup_is_safe_blocking( path: &Path, expected: &DurableAutomationAdmission, @@ -774,6 +779,7 @@ pub fn persist_prepared_terminal_blocking( /// matching `Prepared` (or already promoted `Terminal`) proves the binding was /// durable despite the surfaced I/O/readback error; `Reserved` proves no /// journal binding and leaves the spool for recovery cleanup. +#[hotpath::measure(label = "automation_runtime.effect_journal.replay_exact_binding")] pub fn replay_exact_binding_after_error_blocking( path: &Path, requested: &DurableAutomationAdmission, diff --git a/crates/tracedecay-automation-runtime/src/automation/run_ledger.rs b/crates/tracedecay-automation-runtime/src/automation/run_ledger.rs index 0eb3e04678..844e82f974 100644 --- a/crates/tracedecay-automation-runtime/src/automation/run_ledger.rs +++ b/crates/tracedecay-automation-runtime/src/automation/run_ledger.rs @@ -355,6 +355,7 @@ pub async fn append_run_record( Ok(()) } +#[hotpath::measure(label = "automation_runtime.run_ledger.append_locked")] fn append_jsonl_line_locked(path: &Path, line: &str) -> std::io::Result<()> { use std::io::Write; @@ -895,6 +896,7 @@ impl AutomationRunLedgerTaskSummary { } } +#[hotpath::measure(label = "automation_runtime.run_ledger.load_page", future = true)] pub async fn load_run_records_page( dashboard_root: &Path, limit: usize, @@ -908,6 +910,7 @@ pub async fn load_run_records_page( .map_err(|e| config_error(format!("failed to join automation run ledger read: {e}")))? } +#[hotpath::measure(label = "automation_runtime.run_ledger.load_for_task_key", future = true)] pub async fn load_run_records_for_task_key( dashboard_root: &Path, requested_task_key: &str, @@ -1261,6 +1264,7 @@ fn is_session_evidence_budget_exhausted_skip( status == AutomationRunStatus::Skipped && session_evidence_budget_exhausted_error } +#[hotpath::measure(label = "automation_runtime.run_ledger.scan_task_summary")] fn read_run_ledger_task_summary( path: &Path, task: AgentTaskKind, @@ -1479,6 +1483,7 @@ fn decode_task_summary( Ok(summary) } +#[hotpath::measure(label = "automation_runtime.run_ledger.scan_page")] fn read_any_run_records_page( file: &std::fs::File, path: &Path, @@ -1531,6 +1536,7 @@ struct FilteredRunSelection { effective_task_key: String, } +#[hotpath::measure(label = "automation_runtime.run_ledger.scan_filtered")] fn read_filtered_run_records_two_pass( file: &std::fs::File, path: &Path, diff --git a/crates/tracedecay-automation-runtime/src/automation/run_ledger/exact_lookup.rs b/crates/tracedecay-automation-runtime/src/automation/run_ledger/exact_lookup.rs index 6aca9bf4a3..597c4dcdad 100644 --- a/crates/tracedecay-automation-runtime/src/automation/run_ledger/exact_lookup.rs +++ b/crates/tracedecay-automation-runtime/src/automation/run_ledger/exact_lookup.rs @@ -354,6 +354,7 @@ pub(super) fn read_exact_run_digest(path: &Path, run_id: &str) -> Result( dashboard_root: &Path, record: &AutomationRunLedgerRecord, @@ -410,6 +411,7 @@ pub async fn discard_staged_run_record_exact( /// The validator runs under the spool lock. It may acquire the journal lock, /// establishing the same `spool -> journal` order as exact binding. Returning /// `false` retains every candidate and lets the caller resnapshot newer state. +#[hotpath::measure(label = "automation_runtime.run_ledger.discard_unbound", future = true)] pub async fn discard_unbound_staged_run_records_if( dashboard_root: &Path, run_id: &str, @@ -438,6 +440,7 @@ where })? } +#[hotpath::measure(label = "automation_runtime.run_ledger.publish_exact_blocking")] pub fn publish_staged_run_record_exact_blocking( dashboard_root: &Path, run_id: &str, @@ -483,6 +486,7 @@ fn publish_staged_run_record_exact_blocking_with_publisher( /// Repairs only a corrupt exact-append intent whose ledger state has one /// independently provable outcome. Valid intents remain owned by their exact /// publication and are not resolved without that journal binding. +#[hotpath::measure(label = "automation_runtime.run_ledger.repair_append_intent")] pub fn repair_corrupt_run_ledger_append_intent_blocking(dashboard_root: &Path) -> Result<()> { repair_corrupt_run_ledger_append_intent_impl( dashboard_root, @@ -539,6 +543,7 @@ fn repair_corrupt_run_ledger_append_intent_impl( /// Blocking form of [`discard_staged_run_record_exact`] for owners that must /// retain a claim across process-blocking durability work. +#[hotpath::measure(label = "automation_runtime.run_ledger.discard_exact")] pub fn discard_staged_run_record_exact_blocking( dashboard_root: &Path, run_id: &str, @@ -593,6 +598,7 @@ where })? } +#[hotpath::measure(label = "automation_runtime.run_ledger.discard_stale_exact")] fn discard_stale_staged_run_record_exact_after_terminal_blocking( dashboard_root: &Path, run_id: &str, diff --git a/crates/tracedecay-automation-runtime/src/automation/runner/retrieval.rs b/crates/tracedecay-automation-runtime/src/automation/runner/retrieval.rs index 952c4ceb37..bbae64e923 100644 --- a/crates/tracedecay-automation-runtime/src/automation/runner/retrieval.rs +++ b/crates/tracedecay-automation-runtime/src/automation/runner/retrieval.rs @@ -189,6 +189,7 @@ impl SessionScopeAuthorizer for ProductionAutomationSessionAuthorizer { } impl ProductionAutomationSessionRetrieval { + #[hotpath::measure(label = "automation_runtime.retrieval.mint_request_context")] fn request_context( &self, provider: Option<&str>, @@ -341,6 +342,10 @@ fn automation_session_policy_digest() -> Option { PolicyDigest::from_access_policy_digest(&digest).ok() } +#[hotpath::measure( + label = "automation_runtime.retrieval.retrieve_session_evidence", + future = true +)] pub(super) async fn retrieve_automation_session_evidence( retrieval: &dyn AutomationSessionRetrieval, query_text: &str, @@ -398,6 +403,7 @@ pub(super) async fn retrieve_automation_session_evidence( Ok(retrieval.retrieve(temporal_query).await) } +#[hotpath::measure(label = "automation_runtime.retrieval.accept_outcome")] pub(super) fn accept_automation_temporal_outcome( outcome: SessionRetrievalOutcome, ) -> AutomationTemporalRetrieval { @@ -586,6 +592,7 @@ fn registered_scope_matches( } } +#[hotpath::measure(label = "automation_runtime.retrieval.resolve_anchor", future = true)] async fn active_registered_automation_anchor(database: &RegisteredGlobalDb) -> Option { let snapshot = database.read_snapshot().await.ok()?; let mut rows = snapshot @@ -661,6 +668,10 @@ fn profile_automation_identity( )) } +#[hotpath::measure( + label = "automation_runtime.retrieval.bind_project_authority", + future = true +)] pub async fn registered_project_automation_retrieval( database: RegisteredGlobalDbLeaseV1, profile_identity: &dyn ProfileIdentityReadPort, diff --git a/crates/tracedecay-automation-runtime/src/automation/scheduler.rs b/crates/tracedecay-automation-runtime/src/automation/scheduler.rs index d4ec72b0ab..8768a646c1 100644 --- a/crates/tracedecay-automation-runtime/src/automation/scheduler.rs +++ b/crates/tracedecay-automation-runtime/src/automation/scheduler.rs @@ -344,6 +344,7 @@ pub fn schedule_decision( schedule_decision_or_history_denial(config, task, records, activity, now_secs, true) } +#[hotpath::measure(label = "automation_runtime.scheduler.decide_host_receipt")] pub fn host_receipt_decision( config: &AutomationConfig, task: AgentTaskKind, @@ -814,6 +815,7 @@ fn new_automation_task_lock_token() -> Result { Ok(hex::encode(random)) } +#[hotpath::measure(label = "automation_runtime.scheduler.acquire_task_lock")] fn try_acquire_task_lock_blocking( path: &Path, ownership_token: &str, @@ -1157,6 +1159,7 @@ impl AutomationTaskLock { } } +#[hotpath::measure(label = "automation_runtime.scheduler.release_task_lock")] fn remove_owned_task_lock_blocking(path: &Path, ownership_token: &str) -> std::io::Result<()> { let _coordination = acquire_task_lock_coordination(path)?; let Some(snapshot) = read_task_lock_snapshot(path)? else { diff --git a/crates/tracedecay-automation-runtime/src/automation/skill_materialization.rs b/crates/tracedecay-automation-runtime/src/automation/skill_materialization.rs index eb97b0f96a..3bd8b1c40c 100644 --- a/crates/tracedecay-automation-runtime/src/automation/skill_materialization.rs +++ b/crates/tracedecay-automation-runtime/src/automation/skill_materialization.rs @@ -305,6 +305,7 @@ fn is_reserved_support_path(relative: &Path) -> bool { /// file under `dir` except `SKILL.md`, the manifest/pending sidecars, and /// `*.new` staging), returned sorted by relative path to mirror the ordering /// [`ManagedSkill::materialized_package_hash`] hashes support files in. +#[hotpath::measure(label = "automation_runtime.skill_materialization.scan_support_files")] fn collect_on_disk_support_files(dir: &Path) -> Result)>> { fn walk(base: &Path, dir: &Path, out: &mut Vec<(PathBuf, Vec)>) -> Result<()> { let entries = match fs::read_dir(dir) { @@ -347,6 +348,7 @@ fn collect_on_disk_support_files(dir: &Path) -> Result)>> /// does, and — when the result matches the recorded hash — returns a re-derived /// manifest proving the package is pristine (safe to treat as owned). Returns /// `Ok(None)` when the file is missing, has no content-hash, or has drifted. +#[hotpath::measure(label = "automation_runtime.skill_materialization.recompute_package")] fn recompute_on_disk_package( dir: &Path, provenance: &FileProvenance, @@ -1468,6 +1470,7 @@ fn skills_for_scope(skills: &[ManagedSkill], scope: &MaterializationScope) -> Ve /// and `project_root` (project): a scope is eligible when its host config /// directory (`.claude` / `.codex`) is present, so we never create a host /// integration the user has not opted into. +#[hotpath::measure(label = "automation_runtime.skill_materialization.detect_scopes")] pub fn detect_scopes(home: &Path, project_root: &Path) -> Vec { let mut scopes = Vec::new(); for host in MaterializationHost::all() {