Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion graphify/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1644,7 +1644,8 @@ def _on_walk_error(err: OSError) -> None:

all_files.sort(key=lambda p: str(p))

converted_dir = root / GRAPHIFY_OUT / "converted"
out_base = Path(cache_root).resolve() if cache_root is not None else root
converted_dir = out_base / GRAPHIFY_OUT / "converted"

for p in all_files:
# For memory dir files, skip hidden/noise filtering
Expand Down
43 changes: 43 additions & 0 deletions tests/test_detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2557,6 +2557,49 @@ def test_convert_office_file_outside_root_falls_back(tmp_path, monkeypatch):
assert out1 is not None and out1.name == out2.name


def test_detect_office_conversion_respects_cache_root(tmp_path, monkeypatch):
"""#2787: detect() with cache_root must write converted sidecars under
cache_root/GRAPHIFY_OUT/converted, leaving the scanned corpus untouched, while
keeping the sidecar filename hash anchored to the scan root."""
monkeypatch.setattr(detect_mod, "docx_to_markdown", lambda p: "# Spec\nConverted specification text.")

corpus = tmp_path / "corpus"
corpus.mkdir(parents=True)
cache_out = tmp_path / "cache_out"
cache_out.mkdir(parents=True)

doc_path = corpus / "spec.docx"
doc_path.write_bytes(b"placeholder")

result = detect(corpus, cache_root=cache_out)

# 1. Scanned corpus tree must not be mutated
assert not (corpus / detect_mod.GRAPHIFY_OUT).exists(), (
"detect() must not write graphify-out into the scanned corpus tree when cache_root is provided (#2787)"
)

# 2. Converted sidecar must exist under cache_root
converted_dir = cache_out / detect_mod.GRAPHIFY_OUT / "converted"
assert converted_dir.is_dir(), "converted directory must be created under cache_root"

# 3. Detection result must point to the redirected sidecar
doc_files = result["files"]["document"]
assert len(doc_files) == 1
sidecar_path = Path(doc_files[0])
assert sidecar_path.is_file()
assert sidecar_path.parent.resolve() == converted_dir.resolve()

# 4. Content must match expected conversion
content = sidecar_path.read_text(encoding="utf-8")
assert "<!-- converted from spec.docx -->" in content
assert "# Spec" in content

# 5. Sidecar filename must remain anchored to the corpus scan root
import hashlib
expected_hash = hashlib.sha256(unicodedata.normalize("NFC", "spec.docx").encode()).hexdigest()[:8]
assert sidecar_path.name == f"spec_{expected_hash}.md"


def test_detect_keeps_env_source_dirs(tmp_path):
"""#2058: a real source directory named env/ or *_env/ with no virtualenv
markers must be indexed, not silently pruned as a false-positive venv."""
Expand Down
Loading