fix(detect): respect cache root for converted sidecars (#2787)

Converted Office/Google-Workspace sidecars were written to `root/GRAPHIFY_OUT/converted`,
always anchored to the scanned source tree, so `graphify extract --out <dir>` against a
read-only or pinned checkout polluted the source tree. Route sidecar writes through the
cache root while keeping the content hash anchored to the scan root, so sidecar filenames
stay stable across checkouts.
This commit is contained in:
hopstreax
2026-08-19 14:05:58 +01:00
committed by safishamsi
parent 000c71a4a5
commit c443ee7b3a
2 changed files with 45 additions and 1 deletions
+2 -1
View File
@@ -1699,7 +1699,8 @@ def detect(root: Path, *, follow_symlinks: bool | None = None, google_workspace:
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
+43
View File
@@ -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."""