Skip to content

Commit e4fc151

Browse files
jgravelleclaude
andcommitted
Document the 13 template-less config keys (empty the 'Other' group)
These keys lived in DEFAULTS/CONFIG_TYPES but were never added to the JSONC config template that config_report parses for group+description, so config --json emitted them under the 'Other' catch-all with an empty description (surfaced by the jMunch Console's grouped config screen showing blank rows). Added all 13 to generate_template() under proper === Section === headers with inline comments: watch_paths/watch_extra_ignore/watch_follow_symlinks/ watch_idle_timeout/watch_log (Watcher); runtime_ingest_enabled/org_ingest_ enabled/runtime_ingest_max_body_bytes (new Runtime & Org HTTP Ingest); license_key (new Licensing); cross_repo_default/discovery_hint (Identity & Indexing Behavior); agent_selector (new Agent Selector); enrichment (new Enrichment). The 'Other' group is now empty. Metadata is parsed from the template, not the user's on-disk config, so descriptions appear immediately on upgrade -- no config --upgrade needed. New regression test test_no_key_falls_into_other_or_missing_description fails if a future DEFAULTS key ships template-less. No config value behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3103ffa commit e4fc151

5 files changed

Lines changed: 109 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@ All notable changes to jcodemunch-mcp are documented here.
44

55
## [Unreleased]
66

7+
## [1.108.61] - 2026-06-18 - Every config key is now documented (no more "Other")
8+
9+
### Fixed
10+
11+
- **13 config keys shipped without a template section or description**, so
12+
`config --json` (and any consumer of it, including the jMunch Console's grouped
13+
config screen) emitted them under the `Other` catch-all group with an empty
14+
`description`. The keys existed in `DEFAULTS`/`CONFIG_TYPES` but were never
15+
added to the JSONC config template that `config_report` parses for group +
16+
description metadata. Added all of them to `generate_template()` under proper
17+
`=== Section ===` headers with inline comments:
18+
- `watch_paths`, `watch_extra_ignore`, `watch_follow_symlinks`,
19+
`watch_idle_timeout`, `watch_log` -> **Watcher**
20+
- `runtime_ingest_enabled`, `org_ingest_enabled`,
21+
`runtime_ingest_max_body_bytes` -> **Runtime & Org HTTP Ingest** (new section)
22+
- `license_key` -> **Licensing** (new section)
23+
- `cross_repo_default`, `discovery_hint` -> **Identity & Indexing Behavior**
24+
- `agent_selector` -> **Agent Selector (model routing)** (new section)
25+
- `enrichment` -> **Enrichment (LSP)** (new section)
26+
27+
The `Other` group is now empty. Because metadata is parsed from the template
28+
(not the user's on-disk config), descriptions appear immediately on upgrade --
29+
no `config --upgrade` required. New regression test
30+
`TestConfigReportGrouping::test_no_key_falls_into_other_or_missing_description`
31+
fails loudly if a future key is added to `DEFAULTS` without a template entry.
32+
No config *value* behavior change. Surfaced via the jMunch Console.
33+
734
## [1.108.60] - 2026-06-18 - `config --check` distinguishes sandbox-limited storage probes
835

936
### Fixed

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# jcodemunch-mcp — Project Brief
22

33
## Current State
4+
- **Version:** 1.108.61 — Config-template completeness. 13 keys lived in `DEFAULTS`/`CONFIG_TYPES` but were never added to the JSONC template that `config_report` parses for `group`+`description`, so `config --json` emitted them under the `Other` catch-all with an empty description (surfaced via the jMunch Console's grouped config screen showing blank rows). Added all 13 to `generate_template()` under proper `=== Section ===` headers + inline comments: `watch_paths`/`watch_extra_ignore`/`watch_follow_symlinks`/`watch_idle_timeout`/`watch_log` → **Watcher**; `runtime_ingest_enabled`/`org_ingest_enabled`/`runtime_ingest_max_body_bytes` → new **Runtime & Org HTTP Ingest**; `license_key` → new **Licensing**; `cross_repo_default`/`discovery_hint` → **Identity & Indexing Behavior**; `agent_selector` → new **Agent Selector (model routing)**; `enrichment` → new **Enrichment (LSP)**. `Other` is now empty. Metadata is parsed from the template (not the user's on-disk config) so descriptions appear immediately on upgrade — no `config --upgrade` needed. New regression test `TestConfigReportGrouping::test_no_key_falls_into_other_or_missing_description` fails if any future `DEFAULTS` key ships template-less. No config *value* behavior change. See [[project_jmunch_console]].
45
- **Version:** 1.108.60 — #335 (reported by @mmashwani). `config --check` treated *every* index-storage probe exception as a confirmed `storage` failure (exit 1), so a sandboxed agent shell that can read the index but can't write the index root (`PermissionError` EPERM/EACCES on the `.jcm_probe` write) reported a healthy install as broken — exactly the false-failure an agent might "repair." Fix (his suggested shape): split the probe's `except` — a `PermissionError` with `errno` ∈ {EPERM, EACCES} is **host-confirmation-needed** (`⚠ index storage writability needs host confirmation` + a "rerun outside a sandbox/restricted shell" hint, recorded in a new `host_confirmation` list), NOT a confirmed failure; any other exception (e.g. `EROFS` read-only FS) stays a confirmed `✗ index storage not writable` issue. Exit contract: confirmed `issues` → exit 1 (unchanged); host-confirmation-only (no confirmed issues) → **exit 0** so an agent client doesn't mistake a healthy install for a broken one (a new nonzero exit code would risk the same false-failure, so deliberately not introduced). `import errno` added to server.py. 4 tests `tests/test_config.py::TestServerConfigCheckStorageProbe` (writable→pass/exit0; EROFS→confirmed/exit1; EPERM→host-confirmation/no-exit; output names sandbox + rerun).
56
- **Version:** 1.108.59 — Decision-context surfacing in impact analysis (clean-room F-15 #2 from the trace-mcp review; see memory `project_trace_mcp_f15s`). New `tools/decision_context.py::resolve_decision_context` mines the git commit record of the focal symbol's file + impacted files for **decision-bearing commits** (revert/perf/refactor/rename/bugfix), reusing `get_symbol_provenance`'s `_run_git`/`_classify_commit`/`_extract_intent`; dedupes by SHA, ranks by category weight × recency, returns a digest + `by_category` + a `volatility` read + one-line `summary`. `get_blast_radius` and `get_impact_preview` attach it as an additive `decisions` block behind new opt-in `include_decisions` (default false; server schema + dispatch wired). **Clean-room contrast to trace-mcp:** source is the durable git record (not ephemeral agent JSONL), and it is **surface-only — nothing persisted, no decision graph written, no user file touched** (read-only charter [[feedback_jcm_read_only_charter]]); theirs writes a decision graph, ours surfaces and forgets. Bounded cost (≤8 files × ≤20 commits) → opt-in. Honest `{available:false, reason, hint}` for GitHub-indexed/non-git roots. `get_blast_radius` result-cache key now includes `include_decisions`. Flag off → byte-identical. 8 tests `tests/test_v1_108_59.py`. Tool count stays 82. **Both trace-mcp F-15s now shipped** (#1 v1.108.58 flow edges, #2 this release).
67
- **Version:** 1.108.58 — Framework flow-edge resolver (clean-room F-15 #1 from the trace-mcp review; see memory `project_trace_mcp_f15s`). New `tools/flow_edges.py::resolve_flow_edges` emits **typed** request-flow edges the AST call graph can't see, over the existing index (symbols + import graph + file content), and `get_signal_chains` consumes them. **route→handler**: a string-dispatched handler (Django `path()`/`re_path()`/`url()`, Express/Fastify/Koa `router.get(p, h)`, Flask `add_url_rule(view_func=)`, Rails `to: "ctrl#action"`) is referenced not called/decorated, so it left no call edge and never surfaced — the resolver detects the registration *shape*, resolves the handler ref to a symbol through the import graph, and `get_signal_chains` promotes it to an `http` gateway (repos that dispatch by string now produce chains where they returned none). Decorator-bound handlers already surface as gateways and are NOT re-emitted (no double-count). **render→view**: a handler rendering a string-named template (`render`/`render_template`/`res.render`/`view`) gets an additive per-chain `views` list, resolved to the template file when that file is indexed. **One shape-keyed resolver, not a plugin per framework** — resolution reuses the same symbol-table + import-graph machinery `find_direct_callees` uses. Pure read path: no reindex, no INDEX_VERSION bump, nothing persisted. New `get_signal_chains(include_flow_edges=True)` param (server schema + dispatch wired); `_meta.flow_edges = {route_gateways, unresolved_routes, render_views}`. Flag off OR no route/render shapes → byte-identical to prior output (the MUNCH `sc2` encoder already drops per-chain list detail like `symbols`/`files_touched`, so `views`/`flow_edges` follow the same lossy-compact contract; route-dispatch gateways still move the declared `gateway_count`/`chain_count` scalars). 10 tests `tests/test_v1_108_58.py`. **Gates the versus.php trace-mcp row** (ship ≥1 F-15 first).

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "jcodemunch-mcp"
3-
version = "1.108.60"
3+
version = "1.108.61"
44
description = "Token-efficient MCP server for source code exploration via tree-sitter AST parsing"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/jcodemunch_mcp/config.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,13 +2076,51 @@ def generate_template() -> str:
20762076
// "rate_limit": 0,
20772077
// Max requests per minute per client IP. 0 = disabled (default).
20782078
2079+
// === Runtime & Org HTTP Ingest ===
2080+
// Off-by-default write endpoints on the HTTP transports. Each is a
2081+
// two-key turn: the flag below PLUS a JCODEMUNCH_HTTP_TOKEN bearer.
2082+
// "runtime_ingest_enabled": false,
2083+
// Accept POST /runtime/otel, /runtime/sql, /runtime/stack (live trace
2084+
// ingest). Off by default — these are write endpoints.
2085+
// "org_ingest_enabled": false,
2086+
// Accept POST /org/report so seats can report savings to this org host
2087+
// (team-SKU rollup). Off by default.
2088+
// "runtime_ingest_max_body_bytes": 5242880,
2089+
// Per-request body cap for the ingest endpoints, in bytes (default
2090+
// 5 MB). Checked on both the on-wire and decompressed size (gzip-bomb
2091+
// guard). Minimum 1024.
2092+
2093+
// === Licensing ===
2094+
// "license_key": "",
2095+
// jCodeMunch license key. Gates the org-rollup team feature ONLY —
2096+
// every individual tool, indexing, and search stays free. Validated
2097+
// online against the licensing backend (sticky-offline; 14-day grace
2098+
// for a new org). Also settable via JCODEMUNCH_LICENSE_KEY. Check
2099+
// status with the `license` CLI.
2100+
20792101
// === Watcher ===
20802102
// "watch": false,
20812103
// Enable automatic reindexing when files change.
20822104
// Use "jcodemunch-mcp watch <paths>" CLI command to activate.
20832105
// "watch_debounce_ms": 2000,
20842106
// Milliseconds to wait after a file change before reindexing.
20852107
// Higher values reduce CPU usage but slower detection.
2108+
// "watch_paths": [],
2109+
// Folders the `watch` CLI monitors when no paths are passed on the
2110+
// command line. Empty = watch the indexed repo's own source root.
2111+
// "watch_extra_ignore": [],
2112+
// Extra gitignore-style patterns the watcher ignores on top of the
2113+
// index's own ignore rules (e.g. ["*.log", "build/"]). Changes to
2114+
// matching files never trigger a reindex.
2115+
// "watch_follow_symlinks": false,
2116+
// Follow symlinked directories while watching. Default false avoids
2117+
// reindex loops and watching files outside the repo.
2118+
// "watch_idle_timeout": null,
2119+
// Seconds of no file activity after which the watcher exits. null =
2120+
// run until stopped. Handy for one-shot "watch until quiet" CI runs.
2121+
// "watch_log": null,
2122+
// Path to a file the watcher appends reindex activity to.
2123+
// null = log to stderr only.
20862124
// "freshness_mode": "relaxed",
20872125
// relaxed - Default. Index remains queryable during reindex.
20882126
// Best for interactive use (IDE, chat).
@@ -2126,6 +2164,14 @@ def generate_template() -> str:
21262164
// history those bounds may still not be enough — set false to
21272165
// skip the probe entirely. Index still builds; only the blame
21282166
// metadata is omitted.
2167+
// "cross_repo_default": false,
2168+
// When true, find_importers / get_blast_radius / get_dependency_graph
2169+
// traverse OTHER indexed repos by default, not just the focal one. A
2170+
// per-call `cross_repo` argument still overrides this. Default false
2171+
// keeps results scoped to the repo you asked about.
2172+
// "discovery_hint": true,
2173+
// Append a short "next tools to try" hint to certain results so an
2174+
// agent can chain follow-up queries. Set false to suppress the hint.
21292175
21302176
// === Summarization input policy ===
21312177
// "summarize_from_docstrings": true,
@@ -2258,6 +2304,19 @@ def generate_template() -> str:
22582304
// Cross-platform path remapping. Format: "orig1=new1,orig2=new2".
22592305
// Allows indexes built on Linux to work on Windows and vice versa.
22602306
2307+
// === Agent Selector (model routing) ===
2308+
// "agent_selector": {{}},
2309+
// Config for the optional model-advisory layer (complexity scoring →
2310+
// model routing, modes off/manual/auto). Empty {{}} uses the built-in
2311+
// defaults; populate to override the per-complexity model batting order.
2312+
2313+
// === Enrichment (LSP) ===
2314+
// "enrichment": {{}},
2315+
// Opt-in compiler-grade call-graph resolution via Language Servers
2316+
// (pyright / gopls / ts-language-server / rust-analyzer). Empty {{}} =
2317+
// disabled (AST-only call graph). Populate to configure per-language
2318+
// server commands.
2319+
22612320
// === Mermaid Viewer Integration ===
22622321
// "render_diagram_viewer_enabled": false,
22632322
// When true, render_diagram exposes an extra boolean parameter

tests/test_config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,27 @@ def test_every_entry_has_group_and_description(self):
14011401
assert "group" in entry and isinstance(entry["group"], str) and entry["group"]
14021402
assert "description" in entry and isinstance(entry["description"], str)
14031403

1404+
def test_no_key_falls_into_other_or_missing_description(self):
1405+
"""Every config key must be documented in the template — a real section
1406+
(not the 'Other' catch-all) AND a non-empty description. Regression for
1407+
the 13 keys (watch_paths/watch_extra_ignore/watch_follow_symlinks/
1408+
watch_idle_timeout/watch_log, runtime_ingest_enabled/org_ingest_enabled/
1409+
runtime_ingest_max_body_bytes, license_key, cross_repo_default,
1410+
discovery_hint, agent_selector, enrichment) that shipped template-less,
1411+
so jcm emitted them as Other/no-description and the Console showed blank
1412+
rows. Fails loudly if a future key is added to DEFAULTS without a
1413+
matching template entry."""
1414+
from src.jcodemunch_mcp.config import config_report
1415+
offenders = [
1416+
e["key"] for e in config_report()
1417+
if e["group"] == "Other" or not e["description"]
1418+
]
1419+
assert not offenders, (
1420+
f"config keys missing a template section/description: {offenders}. "
1421+
"Add each to the JSONC template in generate_template() under a "
1422+
"=== Section === header with an inline comment."
1423+
)
1424+
14041425
def test_known_keys_map_to_expected_sections(self):
14051426
from src.jcodemunch_mcp.config import config_report, _config_meta, generate_template
14061427
groups = {e["key"]: e["group"] for e in config_report()}

0 commit comments

Comments
 (0)