@@ -12805,6 +12805,105 @@ TEST(mcp_auto_watch_false_skips_watcher_on_connect) {
1280512805 PASS();
1280612806}
1280712807
12808+ /* ══════════════════════════════════════════════════════════════════
12809+ * #1466 — autoindex.skip must report the effective numeric limit
12810+ * ══════════════════════════════════════════════════════════════════ */
12811+
12812+ static char autoindex_skip_log[1024];
12813+
12814+ /* Keeps only the too_many_files skip line, so later lines cannot displace it. */
12815+ static void autoindex_skip_capture_log(const char *line) {
12816+ if (line && strstr(line, "msg=autoindex.skip") && strstr(line, "reason=too_many_files")) {
12817+ snprintf(autoindex_skip_log, sizeof(autoindex_skip_log), "%s", line);
12818+ }
12819+ }
12820+
12821+ /* Drive initialize → maybe_auto_index over a fresh project holding more tracked
12822+ * files than auto_index_limit, and capture the resulting skip warning.
12823+ * Returns false on fixture setup failure. */
12824+ static bool autoindex_skip_warning(char *out, size_t out_size) {
12825+ char cache[256];
12826+ snprintf(cache, sizeof(cache), "%s/cbm-autoindex-limit-XXXXXX", cbm_tmpdir());
12827+ if (!cbm_mkdtemp(cache)) {
12828+ return false;
12829+ }
12830+
12831+ char repodir[512];
12832+ snprintf(repodir, sizeof(repodir), "%s/repo", cache);
12833+ char file_a[640];
12834+ char file_b[640];
12835+ snprintf(file_a, sizeof(file_a), "%s/a.py", repodir);
12836+ snprintf(file_b, sizeof(file_b), "%s/b.py", repodir);
12837+ if (th_mkdir_p(repodir) != 0 || th_write_file(file_a, "def a():\n return 1\n") != 0 ||
12838+ th_write_file(file_b, "def b():\n return 2\n") != 0) {
12839+ th_rmtree(cache);
12840+ return false;
12841+ }
12842+
12843+ const char *saved = getenv("CBM_CACHE_DIR");
12844+ char *saved_copy = saved ? strdup(saved) : NULL;
12845+ cbm_setenv("CBM_CACHE_DIR", cache, 1);
12846+
12847+ char old_cwd[1024];
12848+ if (!cbm_getcwd(old_cwd, sizeof(old_cwd)) || cbm_chdir(repodir) != 0) {
12849+ restore_cache_dir(saved_copy);
12850+ free(saved_copy);
12851+ th_rmtree(cache);
12852+ return false;
12853+ }
12854+
12855+ bool ok = false;
12856+ cbm_config_t *cfg = cbm_config_open(cache);
12857+ if (cfg) {
12858+ cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX, "true");
12859+ cbm_config_set(cfg, CBM_CONFIG_AUTO_INDEX_LIMIT, "1");
12860+
12861+ cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
12862+ if (srv) {
12863+ autoindex_skip_log[0] = '\0';
12864+ CBMLogLevel prev_level = cbm_log_get_level();
12865+ cbm_log_set_level(CBM_LOG_WARN);
12866+ cbm_log_set_format(CBM_LOG_FORMAT_TEXT);
12867+ cbm_log_set_sink_ex(autoindex_skip_capture_log, CBM_LOG_SINK_REPLACE);
12868+
12869+ cbm_mcp_server_set_config(srv, cfg);
12870+ char *resp = cbm_mcp_server_handle(
12871+ srv, "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}");
12872+ free(resp);
12873+ cbm_mcp_server_free(srv);
12874+
12875+ cbm_log_set_sink(NULL);
12876+ cbm_log_set_level(prev_level);
12877+
12878+ snprintf(out, out_size, "%s", autoindex_skip_log);
12879+ ok = true;
12880+ }
12881+ cbm_config_close(cfg);
12882+ }
12883+
12884+ (void)cbm_chdir(old_cwd);
12885+ restore_cache_dir(saved_copy);
12886+ free(saved_copy);
12887+ th_rmtree(cache);
12888+ return ok;
12889+ }
12890+
12891+ /* RED before the fix: the warning carries `limit=auto_index_limit`, the config
12892+ * key constant, instead of the configured value. */
12893+ TEST(autoindex_skip_reports_numeric_limit_issue1466) {
12894+ char warning[1024];
12895+ if (!autoindex_skip_warning(warning, sizeof(warning))) {
12896+ PASS(); /* fixture setup failed (tmpdir/cwd unavailable) — skip */
12897+ }
12898+ /* Not vacuous: the skip path must actually have been taken. */
12899+ ASSERT_NOT_NULL(strstr(warning, "msg=autoindex.skip"));
12900+ ASSERT_NOT_NULL(strstr(warning, "reason=too_many_files"));
12901+ ASSERT_NOT_NULL(strstr(warning, "files=2"));
12902+ ASSERT_NOT_NULL(strstr(warning, "limit=1"));
12903+ ASSERT_NULL(strstr(warning, "limit=auto_index_limit"));
12904+ PASS();
12905+ }
12906+
1280812907/* ══════════════════════════════════════════════════════════════════
1280912908 * #853 — auto_watch=false must ALSO gate the SUPERVISED fresh-index
1281012909 * watcher registration (keystone × #849 merge interaction)
@@ -14019,6 +14118,7 @@ SUITE(mcp) {
1401914118 RUN_TEST(mcp_auto_watch_default_registers_watcher_on_connect);
1402014119 RUN_TEST(mcp_auto_watch_false_skips_watcher_on_connect);
1402114120 RUN_TEST(mcp_auto_watch_false_skips_supervised_autoindex_issue853);
14121+ RUN_TEST(autoindex_skip_reports_numeric_limit_issue1466);
1402214122}
1402314123
1402414124/* Kept separate so daemon-coordination regressions can be iterated without
0 commit comments