Skip to content

extract() writes AST cache into the analyzed source tree, bypassing CWD (pollutes read-only corpora) #1774

Description

@happypotato0227-star

Summary

graphify.extract.extract() writes its per-file AST cache into a
graphify-out/cache/ directory placed inside the analyzed source tree,
not under the current working directory. When graphify is run to analyze a
corpus you don't want to mutate (a read-only knowledge base, a git working
tree, someone else's repo), this silently creates files inside that corpus,
defeating any attempt to isolate outputs via CWD.

Version

  • graphifyy==0.1.14 (installed), source @ 91f4d120b630ee35c79bf3c75ccd186870a808f9
  • Python 3.12

Reproduction

from pathlib import Path
from graphify.extract import extract

# CWD is /tmp/work  (where I want all outputs)
extract([Path("/data/corpus/a.py"), Path("/data/corpus/b.py")])

# Observed: /data/corpus/graphify-out/cache/<hash>.json   <-- pollutes source
# Expected: cache under CWD (/tmp/work/graphify-out/cache/) or a caller-provided dir

Root cause

extract() takes only paths and has no cache-location parameter, so it
derives a root from the common parent of the input files and passes
that to the cache layer:

  • extract.py:2256 def extract(paths: list[Path]) -> dict: (no cache-root arg)
  • extract.py:2266-2279 root = common parent of paths (falls back to .)
  • extract.py:2285 / 2291 load_cached(path, root) / save_cached(path, result, root)
  • cache.py:14-18 cache_dir(root) -> root / "graphify-out" / "cache" (mkdir + write)

Note cache_dir's own default is Path(".") (CWD), which is the sane
behavior - but extract() overrides it with the source-tree root, so the
cache follows the input location instead of the output location.

Impact

  • Read-only / analyze-only runs mutate the target corpus.
  • In a git working tree this leaves untracked files (dirty status, risk of
    accidental commit).
  • Recurs on every re-run; output-isolation via CWD does not prevent it.

Suggested fix (backward-compatible)

Give extract() an optional cache location and default it to CWD rather
than the input tree:

def extract(paths: list[Path], cache_root: Path | None = None) -> dict:
    root = cache_root if cache_root is not None else Path(".")
    ...

This keeps caching (the perf win of skipping unchanged files) while letting
callers keep all writes under CWD. The same root coupling exists in the
semantic-cache helpers (cache.check_semantic_cache / save_semantic_cache),
which would benefit from the same treatment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions