Skip to content

v1.108.285 — Five answers that were asserted, not established

Choose a tag to compare

@jgravelle jgravelle released this 18 Aug 14:37
· 26 commits to main since this release

Five fixes, each one a place that reported a result it had not checked: a cache that said ready, an index that said fresh, a resolver that said this repository, an opt-out that said applied, and an embedding store that said one model.

Three of the five were a comment or docstring describing behaviour the code did not implement. Prose in the tree is not evidence about the code beside it.

#490 — a cache that announced it was ready one key before it was

search_symbols could raise KeyError: 'centrality' when a second search arrived while the first was still building the lexical corpus. The cache publishes four keys behind a check-then-build guarded on idf alone, and the statement that looked atomic is four separate __setitem__ calls.

The window is the entire runtime of _compute_centrality, so it widens with corpus size — the installs most likely to hit it are the ones where the rebuild is most expensive. The lock was real and correctly held; what leaked was the readiness signal, which is read outside it by design. The same block lived in three modules.

#493 — a single-file refresh certified a corpus it never re-read

index_file wrote live HEAD as the repository's stored SHA, so refreshing one file out of a two-file commit cleared repo_is_stale for the file that was never refreshed. get_file_content then served the old commit's content reporting channels.index: fresh against a clean working tree.

index_folder's _refresh_git_head_if_advanced makes the identical write on a no-change run and is correct, because that run walked the corpus. The write is not the defect; what has been proven before it is.

#492 — a repository question answered with a filesystem fact

resolve_repo matched source_root containment alone, so a path inside an independent git repository nested in an indexed parent came back as the parent index with indexed: true. Gitignored, the read fails and reads absent; absorbed into the parent walk, it succeeds and reads ok. Two symptoms, one mis-resolution.

The guard is a .git stat, never a subprocess — that fast path exists to avoid a walk that can hang. Submodules still resolve to the parent.

#491 — an opt-out that never read the config documenting it

exclude_skip_directories and exclude_secret_patterns were read without repo=, skipping the project overlay, so a project declaring either key in its own .jcodemunch.jsonc got no effect, no warning and a successful index. Both keys' own comments describe the per-project behaviour one line above the global-only read.

#500 — a model change left the embedding store holding two vector widths

embed_repo carried the comment "Detect dimension mismatch — if the stored model differs, force a rebuild" and implemented no such detection. A model change wrote new-width vectors beside the old ones behind a meta row naming the first, and the matrix — which infers width from the first row — silently excluded every symbol embedded afterwards, cumulatively.

Installing or removing [local-embed], deleting the ONNX model, changing embed_model, or rotating a cloud key all reach it. The read path was left alone: fixing the consumer would have hidden the producer.


Upgrade: uv tool install --upgrade jcodemunch-mcp or pip install -U jcodemunch-mcp

No migration required. If you changed embedding models on an existing index, the next embed_repo now detects it, rebuilds, and says so; search_symbols reports _meta.semantic_partial for a store that is already mixed.

Reported by @rknighton (#490, #491, #492, #493), each with a shipped-path reproduction and a control.

Suite: 7945 passed, 17 skipped, 0 failed on 3.10 and 3.13 alike — same total and same skip split. ruff check src/ clean. CI green on fb8bfec.