Skip to content

Commit dd60906

Browse files
HumanBean17claude
andauthored
fix(jrag): honor JAVA_CODEBASE_RAG_SOURCE_ROOT over a stray ancestor marker (#387)
jrag._resolve_cfg passed source_root=discover_project_root(cwd) into resolve_operator_config, which only honors JAVA_CODEBASE_RAG_SOURCE_ROOT when source_root is None. So any ancestor .java-codebase-rag marker silently overrode the env var that pipeline.subprocess_env sets for the cocoindex child (and that operators/tests rely on), making `jrag imports/outline <rel-file>` resolve against the wrong root → "file not found", exit 2. Pass source_root=None instead, mirroring cli._resolved_from_ns: resolution is now env var → YAML source_root → discover_project_root(cwd). Interactive use (discovery fallback) is unchanged; the #383 config_source pointer is preserved. Regression test creates a non-empty ancestor marker + sets the env var and asserts the env var wins (fails on pre-fix code, passes with the fix). Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9061da0 commit dd60906

2 files changed

Lines changed: 57 additions & 7 deletions

File tree

java_codebase_rag/jrag.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,20 +1096,26 @@ def _core_parser() -> argparse.ArgumentParser:
10961096
def _resolve_cfg(args: argparse.Namespace): # type: ignore[no-untyped-def]
10971097
"""Resolve operator config (reuses the operator's cocoindex-free resolver).
10981098
1099-
Same pattern as ``java_codebase_rag.cli._resolved_from_ns``: walks up from
1100-
cwd to find a project root (config file or ``.java-codebase-rag/`` index),
1101-
applies CLI ``--index-dir`` if given, and calls ``apply_to_os_environ`` so
1102-
downstream modules see a consistent env (critically: SBERT_MODEL for
1103-
``jrag search`` in PR-JRAG-4).
1099+
Mirrors ``java_codebase_rag.cli._resolved_from_ns``: pass ``source_root=None``
1100+
so ``resolve_operator_config`` honors ``JAVA_CODEBASE_RAG_SOURCE_ROOT`` first,
1101+
then a YAML ``source_root`` field, then walks up from cwd to find a project
1102+
root. Passing a discovered root explicitly here would OVERRIDE a set env var
1103+
whenever any ancestor dir has a ``.java-codebase-rag`` marker — silently
1104+
ignoring the documented subprocess source-root mechanism that
1105+
``pipeline.subprocess_env`` sets for the cocoindex child (and that operators
1106+
set directly).
11041107
11051108
When the anchor is an index dir with no YAML beside it, resolution follows
11061109
that index's ``config_source`` pointer (see ``config._effective_config_dir``)
11071110
so a config living in a sibling dir is still found from inside a microservice.
1111+
Applies CLI ``--index-dir`` if given and calls ``apply_to_os_environ`` so
1112+
downstream modules see a consistent env (critically SBERT_MODEL for ``jrag
1113+
search``).
11081114
"""
1109-
from java_codebase_rag.config import discover_project_root, resolve_operator_config
1115+
from java_codebase_rag.config import resolve_operator_config
11101116

11111117
cfg = resolve_operator_config(
1112-
source_root=discover_project_root(Path.cwd()),
1118+
source_root=None,
11131119
cli_index_dir=getattr(args, "index_dir", None),
11141120
)
11151121
cfg.apply_to_os_environ()

tests/test_jrag_status.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import sys
2222
from pathlib import Path
2323

24+
import pytest
25+
2426

2527
def _jrag_exe() -> str:
2628
"""Locate the installed ``jrag`` entry point next to the venv interpreter."""
@@ -172,3 +174,45 @@ def test_jrag_help_lists_status_subcommand() -> None:
172174
assert "status" in proc.stdout
173175
# The --offset flag must NOT appear in the top-level help.
174176
assert "--offset" not in proc.stdout
177+
178+
179+
# ----- Config resolution: env var beats a stray ancestor marker -----
180+
181+
182+
def test_resolve_cfg_honors_source_root_env_over_stray_marker(
183+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
184+
) -> None:
185+
"""JAVA_CODEBASE_RAG_SOURCE_ROOT must win over a stray ``.java-codebase-rag``
186+
marker in an ancestor of cwd.
187+
188+
Regression: ``jrag._resolve_cfg`` used to pass ``discover_project_root(cwd)``
189+
as the explicit ``source_root``, which silently overrode the env var whenever
190+
any ancestor dir had a non-empty ``.java-codebase-rag/`` index — the
191+
documented subprocess source-root mechanism ``pipeline.subprocess_env`` sets
192+
for the cocoindex child (and that the traversal tests rely on). It now passes
193+
``source_root=None`` so ``resolve_operator_config`` honors the env var first
194+
(mirroring ``cli._resolved_from_ns``).
195+
"""
196+
from java_codebase_rag.jrag import _resolve_cfg
197+
198+
real_root = tmp_path / "real-source"
199+
real_root.mkdir()
200+
# cwd sits inside a dir whose PARENT has a stray non-empty .java-codebase-rag/
201+
# index dir — the hijack condition that used to override the env var.
202+
# (_has_index_dir requires the marker dir to be non-empty: any(iterdir()).)
203+
workdir = tmp_path / "has-marker" / "sub"
204+
workdir.mkdir(parents=True)
205+
stray_idx = tmp_path / "has-marker" / ".java-codebase-rag"
206+
stray_idx.mkdir()
207+
(stray_idx / "cocoindex.db").write_bytes(b"") # non-empty → recognized as marker
208+
monkeypatch.chdir(workdir)
209+
monkeypatch.setenv("JAVA_CODEBASE_RAG_SOURCE_ROOT", str(real_root))
210+
monkeypatch.delenv("JAVA_CODEBASE_RAG_INDEX_DIR", raising=False)
211+
212+
class _Args:
213+
index_dir = None
214+
215+
cfg = _resolve_cfg(_Args()) # type: ignore[arg-type]
216+
assert cfg.source_root == real_root.resolve(), (
217+
"JAVA_CODEBASE_RAG_SOURCE_ROOT must win over a stray ancestor marker"
218+
)

0 commit comments

Comments
 (0)