From 3b12909648cbe12e2fe3b25c8e719442d1f3fdb8 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 27 Sep 2026 10:51:23 +0000 Subject: [PATCH] fix(mcp-catalog): keep an unsized project count out of context help `tracedecay tool context --help` printed "This project (0 nodes) allows 3 broad context calls": the static tool registry embedded the dynamic call-budget sentence with placeholder figures it cannot compute. The static description now carries only the tool's purpose; live discovery keeps adding the node count and budget (or the warming variant) where a project graph sizes them. --- .../tests/core_cli_suite/cli_boundary.rs | 26 +++++++++++++++++++ .../tracedecay-mcp-catalog/src/definitions.rs | 21 ++++++++------- .../src/definitions/graph.rs | 4 +-- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/crates/tracedecay-cli/tests/core_cli_suite/cli_boundary.rs b/crates/tracedecay-cli/tests/core_cli_suite/cli_boundary.rs index 41a2e6c5d0..b8bcc4a819 100644 --- a/crates/tracedecay-cli/tests/core_cli_suite/cli_boundary.rs +++ b/crates/tracedecay-cli/tests/core_cli_suite/cli_boundary.rs @@ -33,6 +33,32 @@ fn shipped_binary_stops_quietly_when_a_pipeline_reader_exits() { ); } +/// Help runs without a project graph, so it describes the tool without a +/// node count or call budget it cannot compute. +#[test] +fn context_help_describes_the_tool_without_a_project_size() { + let home = tempfile::tempdir().expect("isolated home"); + let output = Command::new(env!("CARGO_BIN_EXE_tracedecay")) + .args(["tool", "context", "--help"]) + .env("HOME", home.path()) + .env("TRACEDECAY_HOME", home.path().join(".tracedecay")) + .env("HOTPATH_METRICS_SERVER_OFF", "true") + .output() + .expect("run tool help"); + + assert!(output.status.success(), "{output:?}"); + let stdout = String::from_utf8_lossy(&output.stdout); + let description = stdout.lines().nth(2).expect("description line"); + assert_eq!( + description, + "Build an AI-ready context for a task description. Returns relevant symbols, \ + relationships, up to three untracked project memory matches when available, and \ + optionally code snippets. Use it for broad questions that need relationship synthesis \ + across the code graph.", + "{stdout}" + ); +} + #[cfg(not(feature = "hotpath"))] #[test] fn production_feature_profile_ignores_hotpath_environment() { diff --git a/crates/tracedecay-mcp-catalog/src/definitions.rs b/crates/tracedecay-mcp-catalog/src/definitions.rs index ce3891bb29..1c48bb36aa 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions.rs @@ -172,14 +172,18 @@ pub fn explore_call_budget(total_nodes: u64) -> u8 { } } +/// The `tracedecay_context` description for surfaces that have no project +/// graph to size, such as `tracedecay tool context --help`. +const CONTEXT_DESCRIPTION: &str = "Build an AI-ready context for a task description. Returns \ + relevant symbols, relationships, up to three untracked project memory matches when \ + available, and optionally code snippets. Use it for broad questions that need \ + relationship synthesis across the code graph."; + /// Generates the `tracedecay_context` description with a dynamic call budget. pub fn context_description(node_count: u64, budget: u8) -> String { format!( - "Build an AI-ready context for a task description. Returns relevant symbols, \ - relationships, up to three untracked project memory matches when available, \ - and optionally code snippets. Use it for broad questions that need \ - relationship synthesis across the code graph. This project ({node_count} nodes) \ - allows {budget} broad context calls." + "{CONTEXT_DESCRIPTION} This project ({node_count} nodes) allows {budget} broad \ + context calls." ) } @@ -248,11 +252,8 @@ pub fn get_tool_definitions_with_warming_budget( /// The `tracedecay_context` description while the project graph is still warming. pub fn context_warming_description(budget: u8) -> String { format!( - "Build an AI-ready context for a task description. Returns relevant symbols, \ - relationships, up to three untracked project memory matches when available, \ - and optionally code snippets. Use it for broad questions that need \ - relationship synthesis across the code graph. The graph is still warming, and \ - {budget} broad context calls are available." + "{CONTEXT_DESCRIPTION} The graph is still warming, and {budget} broad context calls \ + are available." ) } diff --git a/crates/tracedecay-mcp-catalog/src/definitions/graph.rs b/crates/tracedecay-mcp-catalog/src/definitions/graph.rs index 112fc79d84..6b612867ca 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions/graph.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions/graph.rs @@ -2,7 +2,7 @@ use serde_json::Value; -use super::{context_description, def, def_always_load}; +use super::{CONTEXT_DESCRIPTION, def, def_always_load}; use crate::ToolDefinition; // ── alwaysLoad tools (loaded into the model prompt immediately) ───────── @@ -43,7 +43,7 @@ pub(super) fn def_context(input_schema: Value) -> ToolDefinition { def_always_load( "tracedecay_context", "Task Context", - &context_description(0, 3), + CONTEXT_DESCRIPTION, input_schema, ) }