From 79ae9437f2277bf71e9b2da148e48ee143950ccb Mon Sep 17 00:00:00 2001 From: Andrew Hundt Date: Wed, 22 Jul 2026 15:17:40 -0400 Subject: [PATCH] config: Set automatic dependency-source indexing disabled by default Define CBM_DEFAULT_AUTO_INDEX_DEPS and use it in depindex, MCP request handling, hook guidance, and the config registry. Replace the two quality presets with four exact streamlined/classic presets that state whether automatic installed dependency-source indexing is enabled. Keep rank and optional-graph benchmark ablations on the dependency-disabled baseline. Document that index_dependencies remains available and disabling automation does not delete stored dependency projects. Verification: CBM_ONLY_SUITE=cli make -f Makefile.cbm test (243 passed); CBM_ONLY_SUITE=depindex make -f Makefile.cbm test (40 passed); CBM_ONLY_SUITE=input_validation make -f Makefile.cbm test (56 passed). Signed-off-by: Andrew Hundt --- README.md | 6 +- docs/CONFIGURATION.md | 26 +++++--- src/cli/cli.c | 107 ++++++++++++++++---------------- src/cli/hook_augment.c | 6 +- src/depindex/depindex.c | 6 +- src/depindex/depindex.h | 2 + src/mcp/mcp.c | 4 +- tests/test_cli.c | 111 +++++++++++++++++++++++++++++++--- tests/test_depindex.c | 4 +- tests/test_input_validation.c | 109 ++++++++++++++++++--------------- 10 files changed, 247 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index 018329442..f4629452c 100644 --- a/README.md +++ b/README.md @@ -508,6 +508,8 @@ codebase-memory-mcp config set tool_mode streamlined # concise surface; reve codebase-memory-mcp config set auto_index_deps true # index installed dependency APIs codebase-memory-mcp config set auto_dep_limit 20 # import-ranked dependency package cap; 0=unlimited codebase-memory-mcp config preset list # list named capability/API configurations +codebase-memory-mcp config preset apply streamlined-automatic-dependency-source-indexing-disabled +codebase-memory-mcp config preset apply streamlined-automatic-dependency-source-indexing-enabled codebase-memory-mcp config set auto_watch false # don't register background git watcher (default: true) codebase-memory-mcp config set default_response_format json # full JSON objects instead of compact TOON tables codebase-memory-mcp config reset auto_index # reset to default @@ -520,7 +522,9 @@ indexing and first-response codebase context are automatic when configured. Use directly and uses `search_graph`, then `trace_path`, then `get_code_snippet` for structural discovery. Automatic repository indexing obeys `auto_index`/`auto_index_limit`; automatic dependency indexing obeys -`auto_index_deps`/`auto_dep_limit`. +`auto_index_deps`/`auto_dep_limit` and is disabled by default. Explicit +`index_dependencies` calls remain available; disabling automation does not delete +dependency projects that are already indexed. ### Environment Variables diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 186e69b3c..a38099b19 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -86,7 +86,7 @@ for any registry key): | `tool_mode` | `streamlined` | MCP discovery surface: `streamlined` or `classic`. | | `context_injection` | `true` | Include codebase schema and stats automatically in the first `search_graph` response. | | `rank_enabled` | `true` | Compute PageRank, LinkRank, and degree views used by relevance ranking. | -| `auto_index_deps` | `true` | Index installed dependency APIs for cross-package search and tracing. | +| `auto_index_deps` | `false` | Automatically index installed dependency source for cross-package search and tracing. | | `auto_dep_limit` | `20` | Import-ranked automatic dependency package cap; `0` is unlimited. | | `similarity_enabled` | `true` | Create MinHash similarity edges in applicable index modes. | | `semantic_edges_enabled` | `true` | Create semantic-related edges in applicable index modes. | @@ -107,17 +107,23 @@ silently leak into a comparison: ```bash codebase-memory-mcp config preset list -codebase-memory-mcp config preset apply streamlined-quality -codebase-memory-mcp config preset apply classic-quality +codebase-memory-mcp config preset apply streamlined-automatic-dependency-source-indexing-disabled +codebase-memory-mcp config preset apply streamlined-automatic-dependency-source-indexing-enabled +codebase-memory-mcp config preset apply classic-automatic-dependency-source-indexing-disabled +codebase-memory-mcp config preset apply classic-automatic-dependency-source-indexing-enabled ``` -`streamlined-quality` is the recommended default surface with all measured quality -capabilities enabled. `classic-quality` changes only the API discovery surface while -retaining those capabilities. The `rank-disabled`, `dependency-disabled`, -`optional-graph-disabled`, and `minimal-indexing` presets are explicit ablations; -the CLI labels them as quality tradeoffs when applied. Environment variables remain -higher priority than stored preset values, and the command returns nonzero with a -warning when an active override prevents the requested effective configuration. +The four product presets pair the `streamlined` or `classic` tool surface with an +explicit automatic dependency-source indexing state. All four enable the same rank, +similarity, semantic-edge, Git-history, and HTTP-link capabilities. The disabled +variants bound default indexing latency, CPU, memory, and stored graph size; the +enabled variants add installed dependency-source coverage up to `auto_dep_limit`. +`index_dependencies` remains available for explicit packages. Disabling automation +stops future automatic dependency indexing but does not delete dependency projects +already indexed. `rank-disabled`, `optional-graph-disabled`, and `minimal-indexing` +are benchmark ablations, and the CLI labels them accordingly. Environment variables +remain higher priority than stored preset values, and preset application returns +nonzero when an active override prevents the requested effective configuration. ## 3. UI Settings diff --git a/src/cli/cli.c b/src/cli/cli.c index 4c4e2f280..c20b9b584 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -9978,80 +9978,75 @@ typedef struct { const char *description; const cbm_config_preset_value_t *values; size_t value_count; - bool quality_tradeoff; + bool benchmark_ablation; } cbm_config_preset_t; #define PRESET_VALUE(key_, value_) {key_, value_} #define PRESET_COUNT(values_) (sizeof(values_) / sizeof((values_)[0])) +#define PRESET_QUALITY_VALUES(auto_index_deps_, rank_, similarity_, semantic_, git_, http_) \ + PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, rank_), \ + PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, auto_index_deps_), \ + PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, similarity_), \ + PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, semantic_), \ + PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, git_), \ + PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, http_) -static const cbm_config_preset_value_t PRESET_STREAMLINED_QUALITY[] = { +static const cbm_config_preset_value_t PRESET_STREAMLINED_DEPS_DISABLED[] = { PRESET_VALUE(CBM_CONFIG_TOOL_MODE, CBM_CONFIG_TOOL_MODE_STREAMLINED), - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "true"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "true"), + PRESET_QUALITY_VALUES(CBM_DEFAULT_AUTO_INDEX_DEPS_STR, "true", "true", "true", + "true", "true"), }; -static const cbm_config_preset_value_t PRESET_CLASSIC_QUALITY[] = { +static const cbm_config_preset_value_t PRESET_STREAMLINED_DEPS_ENABLED[] = { + PRESET_VALUE(CBM_CONFIG_TOOL_MODE, CBM_CONFIG_TOOL_MODE_STREAMLINED), + PRESET_QUALITY_VALUES("true", "true", "true", "true", "true", "true"), +}; + +static const cbm_config_preset_value_t PRESET_CLASSIC_DEPS_DISABLED[] = { PRESET_VALUE(CBM_CONFIG_TOOL_MODE, CBM_CONFIG_TOOL_MODE_CLASSIC), - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "true"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "true"), + PRESET_QUALITY_VALUES(CBM_DEFAULT_AUTO_INDEX_DEPS_STR, "true", "true", "true", + "true", "true"), +}; + +static const cbm_config_preset_value_t PRESET_CLASSIC_DEPS_ENABLED[] = { + PRESET_VALUE(CBM_CONFIG_TOOL_MODE, CBM_CONFIG_TOOL_MODE_CLASSIC), + PRESET_QUALITY_VALUES("true", "true", "true", "true", "true", "true"), }; static const cbm_config_preset_value_t PRESET_RANK_DISABLED[] = { - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "true"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "true"), -}; - -static const cbm_config_preset_value_t PRESET_DEPENDENCY_DISABLED[] = { - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "false"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "true"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "true"), + PRESET_QUALITY_VALUES(CBM_DEFAULT_AUTO_INDEX_DEPS_STR, "false", "true", "true", "true", + "true"), }; static const cbm_config_preset_value_t PRESET_OPTIONAL_GRAPH_DISABLED[] = { - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "true"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "false"), + PRESET_QUALITY_VALUES(CBM_DEFAULT_AUTO_INDEX_DEPS_STR, "false", "false", "false", "false", + "false"), }; static const cbm_config_preset_value_t PRESET_MINIMAL_INDEXING[] = { - PRESET_VALUE(CBM_CONFIG_RANK_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_AUTO_INDEX_DEPS, "false"), - PRESET_VALUE(CBM_CONFIG_SIMILARITY_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_GITHISTORY_ENABLED, "false"), - PRESET_VALUE(CBM_CONFIG_HTTPLINKS_ENABLED, "false"), + PRESET_QUALITY_VALUES(CBM_DEFAULT_AUTO_INDEX_DEPS_STR, "false", "false", "false", "false", + "false"), }; static const cbm_config_preset_t CBM_CONFIG_PRESETS[] = { - {"streamlined-quality", "recommended streamlined API with all measured quality capabilities", - PRESET_STREAMLINED_QUALITY, PRESET_COUNT(PRESET_STREAMLINED_QUALITY), false}, - {"classic-quality", "classic API with the same full-quality graph capabilities", - PRESET_CLASSIC_QUALITY, PRESET_COUNT(PRESET_CLASSIC_QUALITY), false}, + {"streamlined-automatic-dependency-source-indexing-disabled", + "streamlined API; automatic installed dependency-source indexing disabled", + PRESET_STREAMLINED_DEPS_DISABLED, PRESET_COUNT(PRESET_STREAMLINED_DEPS_DISABLED), false}, + {"streamlined-automatic-dependency-source-indexing-enabled", + "streamlined API; automatic installed dependency-source indexing enabled", + PRESET_STREAMLINED_DEPS_ENABLED, PRESET_COUNT(PRESET_STREAMLINED_DEPS_ENABLED), false}, + {"classic-automatic-dependency-source-indexing-disabled", + "classic API; automatic installed dependency-source indexing disabled", + PRESET_CLASSIC_DEPS_DISABLED, PRESET_COUNT(PRESET_CLASSIC_DEPS_DISABLED), false}, + {"classic-automatic-dependency-source-indexing-enabled", + "classic API; automatic installed dependency-source indexing enabled", + PRESET_CLASSIC_DEPS_ENABLED, PRESET_COUNT(PRESET_CLASSIC_DEPS_ENABLED), false}, {"rank-disabled", "exact PageRank/LinkRank ablation; lowers measured ranking quality", PRESET_RANK_DISABLED, PRESET_COUNT(PRESET_RANK_DISABLED), true}, - {"dependency-disabled", "exact dependency-indexing ablation; removes dependency API results", - PRESET_DEPENDENCY_DISABLED, PRESET_COUNT(PRESET_DEPENDENCY_DISABLED), true}, - {"optional-graph-disabled", "disable optional graph passes but retain dependency indexing", + {"optional-graph-disabled", + "disable optional graph passes; dependency-source automation stays disabled", PRESET_OPTIONAL_GRAPH_DISABLED, PRESET_COUNT(PRESET_OPTIONAL_GRAPH_DISABLED), true}, - {"minimal-indexing", "lowest measured indexing cost; disables rank and dependency results", + {"minimal-indexing", "disable optional graph passes and dependency-source automation", PRESET_MINIMAL_INDEXING, PRESET_COUNT(PRESET_MINIMAL_INDEXING), true}, {NULL, NULL, NULL, 0, false}, }; @@ -10090,7 +10085,7 @@ static void cbm_config_print_presets(void) { printf("Named presets (applied atomically):\n"); for (size_t i = 0; CBM_CONFIG_PRESETS[i].name; i++) { printf(" %-24s %s%s\n", CBM_CONFIG_PRESETS[i].name, CBM_CONFIG_PRESETS[i].description, - CBM_CONFIG_PRESETS[i].quality_tradeoff ? " [quality tradeoff]" : ""); + CBM_CONFIG_PRESETS[i].benchmark_ablation ? " [benchmark ablation]" : ""); } } @@ -10534,11 +10529,13 @@ const cbm_config_entry_t CBM_CONFIG_REGISTRY[] = { "'unweighted' = raw connection count regardless of type. " "'calls_only' = only count direct function call connections — best for finding the most-called functions."}, /* ── Dependencies ── */ - {"auto_index_deps", "true", NULL, "Dependencies", - "Auto-index installed packages from package.json, Cargo.toml, go.mod, etc.", + {CBM_CONFIG_AUTO_INDEX_DEPS, CBM_DEFAULT_AUTO_INDEX_DEPS_STR, NULL, "Dependencies", + "Automatically index installed dependency source for cross-package search and tracing", "true|false", - "Enable to trace calls into dependencies (e.g. find all callers of a library function). " - "Disable for faster indexing when cross-package search is not needed."}, + "Disabled by default to bound indexing latency, CPU, memory, and stored graph size. Enable when " + "automatic dependency-source coverage is worth that cost; auto_dep_limit bounds each discovery " + "pass. index_dependencies remains available for explicit packages. Disabling this setting stops " + "future automatic dependency indexing; it does not delete dependency projects already indexed."}, {CBM_CONFIG_AUTO_DEP_LIMIT, CBM_STRINGIFY(CBM_DEFAULT_AUTO_DEP_LIMIT), NULL, "Dependencies", "Max number of packages to auto-index", "0-10000", diff --git a/src/cli/hook_augment.c b/src/cli/hook_augment.c index e64824de0..a1d140193 100644 --- a/src/cli/hook_augment.c +++ b/src/cli/hook_augment.c @@ -1158,7 +1158,7 @@ static ha_guidance_config_t ha_load_guidance_config(void) { .auto_index = true, .context_injection = true, .auto_watch = true, - .auto_index_deps = true, + .auto_index_deps = CBM_DEFAULT_AUTO_INDEX_DEPS, .auto_index_limit = CBM_DEFAULT_AUTO_INDEX_LIMIT, .auto_dep_limit = CBM_DEFAULT_AUTO_DEP_LIMIT, }; @@ -1171,8 +1171,8 @@ static ha_guidance_config_t ha_load_guidance_config(void) { result.context_injection = cbm_config_get_effective_bool(cfg, CBM_CONFIG_CONTEXT_INJECTION, true); result.auto_watch = cbm_config_get_effective_bool(cfg, CBM_CONFIG_AUTO_WATCH, true); - result.auto_index_deps = - cbm_config_get_effective_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, true); + result.auto_index_deps = cbm_config_get_effective_bool( + cfg, CBM_CONFIG_AUTO_INDEX_DEPS, CBM_DEFAULT_AUTO_INDEX_DEPS); result.auto_index_limit = cbm_config_get_effective_int(cfg, CBM_CONFIG_AUTO_INDEX_LIMIT, CBM_DEFAULT_AUTO_INDEX_LIMIT); diff --git a/src/depindex/depindex.c b/src/depindex/depindex.c index 63cc2b043..d73e09a8f 100644 --- a/src/depindex/depindex.c +++ b/src/depindex/depindex.c @@ -740,10 +740,8 @@ int cbm_discover_installed_deps(cbm_pkg_manager_t mgr, const char *project_root, /* ── Auto-Index ────────────────────────────────────────────────── */ int cbm_dep_auto_index_effective_limit(cbm_config_t *cfg, int default_limit) { - if (!cfg) { - return default_limit; - } - if (!cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, true)) { + if (!cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, + CBM_DEFAULT_AUTO_INDEX_DEPS)) { return 0; } diff --git a/src/depindex/depindex.h b/src/depindex/depindex.h index 96148ce45..f37e4975c 100644 --- a/src/depindex/depindex.h +++ b/src/depindex/depindex.h @@ -45,6 +45,8 @@ static const char *CBM_MANIFEST_FILES[] = { }; /* Default limits (convention: -1=unlimited, 0=disabled, >0=limit) */ +#define CBM_DEFAULT_AUTO_INDEX_DEPS false +#define CBM_DEFAULT_AUTO_INDEX_DEPS_STR "false" #define CBM_DEFAULT_AUTO_DEP_LIMIT 20 #define CBM_DEFAULT_DEP_MAX_FILES 1000 diff --git a/src/mcp/mcp.c b/src/mcp/mcp.c index 097686547..b794103b4 100644 --- a/src/mcp/mcp.c +++ b/src/mcp/mcp.c @@ -2557,7 +2557,9 @@ static int cbm_mcp_overlay_compaction_max_generations(cbm_mcp_server_t *srv) { } static int cbm_mcp_effective_auto_dep_limit(cbm_mcp_server_t *srv, const char *args_json) { - bool enabled = cbm_config_get_bool(srv ? srv->config : NULL, CBM_CONFIG_AUTO_INDEX_DEPS, true); + bool enabled = cbm_config_get_bool(srv ? srv->config : NULL, + CBM_CONFIG_AUTO_INDEX_DEPS, + CBM_DEFAULT_AUTO_INDEX_DEPS); if (cbm_mcp_has_arg(args_json, CBM_CONFIG_AUTO_INDEX_DEPS)) { enabled = cbm_mcp_get_bool_arg_default(args_json, CBM_CONFIG_AUTO_INDEX_DEPS, enabled); } diff --git a/tests/test_cli.c b/tests/test_cli.c index 641ebe2e0..b98ab83b5 100644 --- a/tests/test_cli.c +++ b/tests/test_cli.c @@ -4171,6 +4171,39 @@ TEST(cli_hook_augment_subagent_no_project_guidance_is_read_only) { PASS(); } +TEST(cli_hook_augment_guidance_uses_dependency_default) { + char tmpdir[256]; + snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-default-XXXXXX"); + if (!cbm_mkdtemp(tmpdir)) + FAIL("cbm_mkdtemp failed"); + + cli_env_snapshot_t cache = {0}; + cli_env_snapshot_t auto_index_deps = {0}; + cli_env_snapshot_t auto_dep_limit = {0}; + ASSERT_TRUE(cli_env_snapshot(&cache, "CBM_CACHE_DIR")); + ASSERT_TRUE(cli_env_snapshot(&auto_index_deps, "CBM_AUTO_INDEX_DEPS")); + ASSERT_TRUE(cli_env_snapshot(&auto_dep_limit, "CBM_AUTO_DEP_LIMIT")); + cbm_setenv("CBM_CACHE_DIR", tmpdir, 1); + cbm_unsetenv("CBM_AUTO_INDEX_DEPS"); + cbm_unsetenv("CBM_AUTO_DEP_LIMIT"); + + const char *input = + "{\"hook_event_name\":\"SessionStart\"," + "\"cwd\":\"/definitely-not-indexed/default-dependency-guidance\"}"; + char *output = cbm_hook_augment_lifecycle_json(input); + ASSERT_NOT_NULL(output); + ASSERT_NOT_NULL(strstr(output, "auto_index_deps=false")); + ASSERT_NOT_NULL(strstr(output, "index_dependencies")); + ASSERT_NULL(strstr(output, "Dependencies: automatic")); + free(output); + + cli_env_restore(&auto_dep_limit); + cli_env_restore(&auto_index_deps); + cli_env_restore(&cache); + test_rmdir_r(tmpdir); + PASS(); +} + TEST(cli_hook_augment_guidance_tracks_tool_and_dependency_config) { char tmpdir[256]; snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-hook-config-XXXXXX"); @@ -6932,6 +6965,24 @@ TEST(cli_config_registry_auto_dep_limit_uses_shared_default) { PASS(); } +TEST(cli_config_registry_auto_index_deps_defaults_disabled) { + const cbm_config_entry_t *found = NULL; + for (int i = 0; CBM_CONFIG_REGISTRY[i].key; i++) { + if (strcmp(CBM_CONFIG_REGISTRY[i].key, CBM_CONFIG_AUTO_INDEX_DEPS) == 0) { + found = &CBM_CONFIG_REGISTRY[i]; + break; + } + } + + ASSERT_NOT_NULL(found); + ASSERT_STR_EQ(found->default_val, "false"); + ASSERT_STR_EQ(found->range, "true|false"); + ASSERT_NOT_NULL(strstr(found->description, "installed dependency source")); + ASSERT_NOT_NULL(strstr(found->guidance, "index_dependencies")); + ASSERT_NOT_NULL(strstr(found->guidance, "does not delete")); + PASS(); +} + TEST(cli_config_registry_reindex_startup_guidance_is_precise) { const cbm_config_entry_t *found = NULL; for (int i = 0; CBM_CONFIG_REGISTRY[i].key; i++) { @@ -7017,14 +7068,55 @@ TEST(cli_config_presets_apply_exact_capability_sets) { cbm_config_t *cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); - ASSERT_EQ(cbm_config_apply_preset(cfg, "streamlined-quality"), 0); - ASSERT_STR_EQ(cbm_config_get(cfg, CBM_CONFIG_TOOL_MODE, ""), "streamlined"); - ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_RANK_ENABLED, false)); - ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, false)); + static const struct { + const char *name; + const char *tool_mode; + bool auto_index_deps; + } cases[] = { + {"streamlined-automatic-dependency-source-indexing-disabled", "streamlined", false}, + {"streamlined-automatic-dependency-source-indexing-enabled", "streamlined", true}, + {"classic-automatic-dependency-source-indexing-disabled", "classic", false}, + {"classic-automatic-dependency-source-indexing-enabled", "classic", true}, + }; + + for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_RANK_ENABLED, "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, + cases[i].auto_index_deps ? "false" : "true"), + 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_SIMILARITY_ENABLED, "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_SEMANTIC_EDGES_ENABLED, "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_GITHISTORY_ENABLED, "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_HTTPLINKS_ENABLED, "false"), 0); + + ASSERT_EQ(cbm_config_apply_preset(cfg, cases[i].name), 0); + ASSERT_STR_EQ(cbm_config_get(cfg, CBM_CONFIG_TOOL_MODE, ""), cases[i].tool_mode); + ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_RANK_ENABLED, false)); + ASSERT_EQ(cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, + !cases[i].auto_index_deps), + cases[i].auto_index_deps); + ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_SIMILARITY_ENABLED, false)); + ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_SEMANTIC_EDGES_ENABLED, false)); + ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_GITHISTORY_ENABLED, false)); + ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_HTTPLINKS_ENABLED, false)); + } + + ASSERT_NEQ(cbm_config_apply_preset(cfg, "streamlined-quality"), 0); + ASSERT_NEQ(cbm_config_apply_preset(cfg, "classic-quality"), 0); + ASSERT_NEQ(cbm_config_apply_preset(cfg, "dependency-disabled"), 0); + + ASSERT_EQ(cbm_config_apply_preset(cfg, "rank-disabled"), 0); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_RANK_ENABLED, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, true)); ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_SIMILARITY_ENABLED, false)); - ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_SEMANTIC_EDGES_ENABLED, false)); - ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_GITHISTORY_ENABLED, false)); - ASSERT_TRUE(cbm_config_get_bool(cfg, CBM_CONFIG_HTTPLINKS_ENABLED, false)); + + ASSERT_EQ(cbm_config_apply_preset(cfg, "optional-graph-disabled"), 0); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_RANK_ENABLED, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_SIMILARITY_ENABLED, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_SEMANTIC_EDGES_ENABLED, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_GITHISTORY_ENABLED, true)); + ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_HTTPLINKS_ENABLED, true)); ASSERT_EQ(cbm_config_apply_preset(cfg, "minimal-indexing"), 0); ASSERT_FALSE(cbm_config_get_bool(cfg, CBM_CONFIG_RANK_ENABLED, true)); @@ -7070,7 +7162,8 @@ TEST(cli_config_command_dispatches_presets) { /* Stored preset values remain deterministic, but an active environment * override must be reported through a nonzero command status. */ cbm_setenv("CBM_TOOL_MODE", CBM_CONFIG_TOOL_MODE_CLASSIC, 1); - char *overridden_args[] = {"preset", "apply", "streamlined-quality"}; + char *overridden_args[] = { + "preset", "apply", "streamlined-automatic-dependency-source-indexing-disabled"}; ASSERT_NEQ(cbm_cmd_config(3, overridden_args), 0); cfg = cbm_config_open(tmpdir); ASSERT_NOT_NULL(cfg); @@ -7643,6 +7736,7 @@ SUITE(cli) { RUN_TEST(cli_hook_augment_lifecycle_output_contract); RUN_TEST(cli_hook_augment_subagent_tier_router_contract); RUN_TEST(cli_hook_augment_subagent_no_project_guidance_is_read_only); + RUN_TEST(cli_hook_augment_guidance_uses_dependency_default); RUN_TEST(cli_hook_augment_guidance_tracks_tool_and_dependency_config); RUN_TEST(cli_hook_augment_post_read_event_and_path_contract); RUN_TEST(cli_hook_augment_hermes_dialect_contract); @@ -7755,6 +7849,7 @@ SUITE(cli) { RUN_TEST(cli_config_registry_includes_dep_ranking_toggle); RUN_TEST(cli_config_registry_includes_query_max_rows); RUN_TEST(cli_config_registry_auto_dep_limit_uses_shared_default); + RUN_TEST(cli_config_registry_auto_index_deps_defaults_disabled); RUN_TEST(cli_config_registry_reindex_startup_guidance_is_precise); RUN_TEST(cli_configuration_doc_auto_index_default_matches_registry); RUN_TEST(cli_config_delete); diff --git a/tests/test_depindex.c b/tests/test_depindex.c index 8b8b46127..8c44e1f9a 100644 --- a/tests/test_depindex.c +++ b/tests/test_depindex.c @@ -1081,8 +1081,8 @@ TEST(test_auto_index_deps_config_limit_policy) { cbm_config_t *cfg = cbm_config_open(cache_tmp); ASSERT_NOT_NULL(cfg); - ASSERT_EQ(cbm_dep_auto_index_effective_limit(cfg, CBM_DEFAULT_AUTO_DEP_LIMIT), - CBM_DEFAULT_AUTO_DEP_LIMIT); + ASSERT_EQ(cbm_dep_auto_index_effective_limit(NULL, CBM_DEFAULT_AUTO_DEP_LIMIT), 0); + ASSERT_EQ(cbm_dep_auto_index_effective_limit(cfg, CBM_DEFAULT_AUTO_DEP_LIMIT), 0); ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, "false"), 0); ASSERT_EQ(cbm_dep_auto_index_effective_limit(cfg, CBM_DEFAULT_AUTO_DEP_LIMIT), 0); ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, "true"), 0); diff --git a/tests/test_input_validation.c b/tests/test_input_validation.c index 1a1c97f83..909e6d900 100644 --- a/tests/test_input_validation.c +++ b/tests/test_input_validation.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1459,7 +1460,7 @@ TEST(path_project_autoindex_respects_file_limit) { /* ══════════════════════════════════════════════════════════════════ * Path-based auto-index must run dependency auto-indexing exactly like - * the session-root branch: auto_index_deps (default true) triggers + * the session-root branch: explicit auto_index_deps=true triggers * cbm_mcp_auto_index_deps after the project index; config can disable * it or cap it via auto_dep_limit. Analysis: * notes/2026-07-21-2332-path-autoindex-dependency-asymmetry-analysis.md @@ -1531,55 +1532,12 @@ TEST(path_project_autoindex_indexes_dependencies) { ASSERT_NOT_NULL(cbm_mkdtemp(target_tmp)); ASSERT_EQ(setup_path_dep_target(target_tmp), 0); - cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL); - ASSERT_NOT_NULL(srv); - const char *old_auto_index = getenv("CBM_AUTO_INDEX"); - char *old_auto_index_copy = old_auto_index ? strdup(old_auto_index) : NULL; - cbm_setenv("CBM_AUTO_INDEX", "true", 1); - - bool project_indexed = false; - char *dep_resp = NULL; - run_path_dep_queries(srv, session_tmp, target_tmp, "path_dep_sentinel", - &project_indexed, &dep_resp); - bool dep_indexed = dep_resp && strstr(dep_resp, "path_dep_sentinel") != NULL; - free(dep_resp); - - cbm_mcp_server_free(srv); - if (old_auto_index_copy) { - cbm_setenv("CBM_AUTO_INDEX", old_auto_index_copy, 1); - free(old_auto_index_copy); - } else { - cbm_unsetenv("CBM_AUTO_INDEX"); - } - th_cleanup(target_tmp); - th_cleanup(session_tmp); - - ASSERT_TRUE(project_indexed); - /* RED before the fix: the path branch never called - * cbm_mcp_auto_index_deps, so the vendored dep was silently absent - * even though auto_index_deps defaults to true. */ - ASSERT_TRUE(dep_indexed); - PASS(); -} - -TEST(path_project_autoindex_deps_disabled_by_config) { - char session_tmp[256]; - snprintf(session_tmp, sizeof(session_tmp), "/tmp/cbm_path_depoff_sess_XXXXXX"); - ASSERT_NOT_NULL(cbm_mkdtemp(session_tmp)); - ASSERT_EQ(th_write_file(TH_PATH(session_tmp, "main.c"), "void session_dep_fn(void) {}\n"), - 0); - - char target_tmp[256]; - snprintf(target_tmp, sizeof(target_tmp), "/tmp/cbm_path_depoff_tgt_XXXXXX"); - ASSERT_NOT_NULL(cbm_mkdtemp(target_tmp)); - ASSERT_EQ(setup_path_dep_target(target_tmp), 0); - char cfg_tmp[256]; - snprintf(cfg_tmp, sizeof(cfg_tmp), "/tmp/cbm_path_depoff_cfg_XXXXXX"); + snprintf(cfg_tmp, sizeof(cfg_tmp), "/tmp/cbm_path_depon_cfg_XXXXXX"); ASSERT_NOT_NULL(cbm_mkdtemp(cfg_tmp)); cbm_config_t *cfg = cbm_config_open(cfg_tmp); ASSERT_NOT_NULL(cfg); - ASSERT_EQ(cbm_config_set(cfg, "auto_index_deps", "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, "true"), 0); cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL); ASSERT_NOT_NULL(srv); @@ -1608,7 +1566,58 @@ TEST(path_project_autoindex_deps_disabled_by_config) { th_cleanup(session_tmp); ASSERT_TRUE(project_indexed); - /* auto_index_deps=false must keep the path branch dep-free. */ + /* The enabled preset path must run the same dependency indexing helper as + * session-root indexing. */ + ASSERT_TRUE(dep_indexed); + PASS(); +} + +TEST(path_project_autoindex_deps_disabled_by_default) { + char session_tmp[256]; + snprintf(session_tmp, sizeof(session_tmp), "/tmp/cbm_path_depoff_sess_XXXXXX"); + ASSERT_NOT_NULL(cbm_mkdtemp(session_tmp)); + ASSERT_EQ(th_write_file(TH_PATH(session_tmp, "main.c"), "void session_dep_fn(void) {}\n"), + 0); + + char target_tmp[256]; + snprintf(target_tmp, sizeof(target_tmp), "/tmp/cbm_path_depoff_tgt_XXXXXX"); + ASSERT_NOT_NULL(cbm_mkdtemp(target_tmp)); + ASSERT_EQ(setup_path_dep_target(target_tmp), 0); + + char cfg_tmp[256]; + snprintf(cfg_tmp, sizeof(cfg_tmp), "/tmp/cbm_path_depoff_cfg_XXXXXX"); + ASSERT_NOT_NULL(cbm_mkdtemp(cfg_tmp)); + cbm_config_t *cfg = cbm_config_open(cfg_tmp); + ASSERT_NOT_NULL(cfg); + + cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL); + ASSERT_NOT_NULL(srv); + cbm_mcp_server_set_config(srv, cfg); + const char *old_auto_index = getenv("CBM_AUTO_INDEX"); + char *old_auto_index_copy = old_auto_index ? strdup(old_auto_index) : NULL; + cbm_setenv("CBM_AUTO_INDEX", "true", 1); + + bool project_indexed = false; + char *dep_resp = NULL; + run_path_dep_queries(srv, session_tmp, target_tmp, "path_dep_sentinel", + &project_indexed, &dep_resp); + bool dep_indexed = dep_resp && strstr(dep_resp, "path_dep_sentinel") != NULL; + free(dep_resp); + + cbm_mcp_server_free(srv); + cbm_config_close(cfg); + if (old_auto_index_copy) { + cbm_setenv("CBM_AUTO_INDEX", old_auto_index_copy, 1); + free(old_auto_index_copy); + } else { + cbm_unsetenv("CBM_AUTO_INDEX"); + } + th_cleanup(cfg_tmp); + th_cleanup(target_tmp); + th_cleanup(session_tmp); + + ASSERT_TRUE(project_indexed); + /* The product default must keep automatic path indexing dep-free. */ ASSERT_FALSE(dep_indexed); PASS(); } @@ -1645,7 +1654,7 @@ TEST(path_project_autoindex_honors_auto_dep_limit) { ASSERT_NOT_NULL(cbm_mkdtemp(cfg_tmp)); cbm_config_t *cfg = cbm_config_open(cfg_tmp); ASSERT_NOT_NULL(cfg); - ASSERT_EQ(cbm_config_set(cfg, "auto_index_deps", "true"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, "true"), 0); ASSERT_EQ(cbm_config_set(cfg, "auto_dep_limit", "1"), 0); cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL); @@ -1697,7 +1706,7 @@ TEST(dep_search_hint_names_index_dependencies_when_deps_disabled) { cbm_config_t *cfg = cbm_config_open(tmp); ASSERT_NOT_NULL(cfg); - ASSERT_EQ(cbm_config_set(cfg, "auto_index_deps", "false"), 0); + ASSERT_EQ(cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_DEPS, "false"), 0); cbm_mcp_server_set_config(srv, cfg); /* "deps" expands to "validation-test.dep" (prefix match, zero rows). @@ -1856,7 +1865,7 @@ void suite_input_validation(void) { RUN_TEST(path_project_auto_indexes_separate_directory); RUN_TEST(path_project_autoindex_respects_file_limit); RUN_TEST(path_project_autoindex_indexes_dependencies); - RUN_TEST(path_project_autoindex_deps_disabled_by_config); + RUN_TEST(path_project_autoindex_deps_disabled_by_default); RUN_TEST(path_project_autoindex_honors_auto_dep_limit); RUN_TEST(dep_search_hint_names_index_dependencies_when_deps_disabled); RUN_TEST(regression_trace_path_tool_name_still_works);