fix(extract): initialize detection for pathless Postgres

This commit is contained in:
oleksii-tumanov
2026-07-20 11:31:36 +01:00
committed by safishamsi
parent 220a675265
commit b35898aafc
2 changed files with 129 additions and 3 deletions
+19 -3
View File
@@ -2557,6 +2557,7 @@ def dispatch_command(cmd: str) -> None:
)
if not has_path:
detection = {}
code_files = []
doc_files = []
paper_files = []
@@ -2976,7 +2977,9 @@ def dispatch_command(cmd: str) -> None:
_live_hashes.add(_file_hash(_abs, target, cache_root=out_root))
except OSError:
pass
_prune_semantic_cache(out_root, _live_hashes)
# A pathless database extraction has no filesystem corpus to sweep.
if has_path:
_prune_semantic_cache(out_root, _live_hashes)
except Exception as exc:
print(f"[graphify extract] warning: could not prune semantic cache: {exc}", file=sys.stderr)
stages.mark("semantic extract")
@@ -3056,6 +3059,15 @@ def dispatch_command(cmd: str) -> None:
if has_path else None
)
def _invalidate_file_manifest_for_db_graph() -> None:
if has_path:
return
try:
manifest_path.unlink(missing_ok=True)
except OSError as exc:
print(f"error: could not invalidate file manifest: {exc}", file=sys.stderr)
sys.exit(1)
if no_cluster:
# --no-cluster: dump the raw merged extraction as graph.json.
# No NetworkX, no community detection, no analysis sidecar.
@@ -3140,6 +3152,7 @@ def dispatch_command(cmd: str) -> None:
)
sys.exit(1)
_backup(graphify_out)
_invalidate_file_manifest_for_db_graph()
from graphify.paths import write_json_atomic as _write_json_atomic
_write_json_atomic(graph_json_path, merged, indent=2)
stages.mark("write")
@@ -3159,7 +3172,8 @@ def dispatch_command(cmd: str) -> None:
f"est. cost: ${cost:.4f}"
)
try:
_save_manifest(_manifest_files, manifest_path=str(manifest_path), kind="both", root=target, scan_corpus=_scan_corpus, clear_semantic=_cleared_semantic)
if has_path:
_save_manifest(_manifest_files, manifest_path=str(manifest_path), kind="both", root=target, scan_corpus=_scan_corpus, clear_semantic=_cleared_semantic)
except Exception as exc:
print(f"[graphify extract] warning: could not write manifest: {exc}", file=sys.stderr)
if global_merge:
@@ -3231,6 +3245,7 @@ def dispatch_command(cmd: str) -> None:
from graphify.export import backup_if_protected as _backup
_backup(graphify_out)
_invalidate_file_manifest_for_db_graph()
# force=True bypasses the #479 shrink guard entirely. A full build
# legitimately shrinks (fuzzy dedup collapse, deleted code) so it keeps
# force=True — EXCEPT when this run's extraction was incomplete (an
@@ -3296,7 +3311,8 @@ def dispatch_command(cmd: str) -> None:
from graphify.paths import write_json_atomic as _wja
_wja(analysis_path, analysis, indent=2)
try:
_save_manifest(_manifest_files, manifest_path=str(manifest_path), kind="both", root=target, scan_corpus=_scan_corpus, clear_semantic=_cleared_semantic)
if has_path:
_save_manifest(_manifest_files, manifest_path=str(manifest_path), kind="both", root=target, scan_corpus=_scan_corpus, clear_semantic=_cleared_semantic)
except Exception as exc:
print(f"[graphify extract] warning: could not write manifest: {exc}", file=sys.stderr)
+110
View File
@@ -789,6 +789,116 @@ def test_extract_timing_flag_emits_stage_timings(monkeypatch, tmp_path, capsys):
assert "graphify timing" not in capsys.readouterr().err
@pytest.mark.parametrize(
"postgres_args",
[["--postgres", "test-dsn"], ["--postgres=test-dsn"]],
)
@pytest.mark.parametrize("cluster_args", [[], ["--no-cluster"]])
def test_pathless_postgres_extract_initializes_empty_detection(
monkeypatch, tmp_path, postgres_args, cluster_args
):
calls = []
def _introspect(dsn):
calls.append(dsn)
return {
"nodes": [
{
"id": "postgresql_users",
"label": "users",
"type": "table",
"file_type": "code",
"source_file": "postgresql:/localhost/test",
}
],
"edges": [],
}
corpus = tmp_path / "corpus"
corpus.mkdir()
(corpus / "app.py").write_text("def app():\n return 1\n")
launcher = tmp_path / "launcher"
launcher.mkdir()
monkeypatch.chdir(launcher)
out_root = tmp_path / "output"
graph_path = out_root / "graphify-out" / "graph.json"
manifest = out_root / "graphify-out" / "manifest.json"
monkeypatch.setattr(mainmod, "_check_skill_version", lambda _: None)
monkeypatch.setattr("graphify.pg_introspect.introspect_postgres", _introspect)
def _run(argv):
monkeypatch.setattr(mainmod.sys, "argv", argv)
try:
mainmod.main()
except SystemExit as exc:
assert exc.code in (None, 0)
_run(
[
"graphify",
"extract",
str(corpus),
"--code-only",
"--no-cluster",
"--out",
str(out_root),
]
)
assert manifest.exists()
assert "app.py" in _node_sources(graph_path)
manifest_content = manifest.read_text()
(out_root / "graphify-out" / ".graphify_semantic_marker").write_text(
'{"output_tokens": 1}'
)
cache_entry = (
out_root
/ "graphify-out"
/ "cache"
/ "semantic"
/ "deadbeef.json"
)
cache_entry.parent.mkdir(parents=True)
cache_entry.write_text('{"nodes": [], "edges": []}')
_run(
[
"graphify",
"extract",
*postgres_args,
*cluster_args,
"--out",
str(out_root),
]
)
assert calls == ["test-dsn"]
assert cache_entry.exists()
assert not manifest.exists()
assert "postgresql:/localhost/test" in _node_sources(graph_path)
backups = [
path
for path in (out_root / "graphify-out").iterdir()
if path.is_dir() and (path / "manifest.json").exists()
]
assert backups
assert backups[0].joinpath("manifest.json").read_text() == manifest_content
_run(
[
"graphify",
"extract",
str(corpus),
"--code-only",
"--no-cluster",
"--out",
str(out_root),
]
)
final_sources = _node_sources(graph_path)
assert "app.py" in final_sources
assert "postgresql:/localhost/test" not in final_sources
assert manifest.exists()
# ---------------------------------------------------------------------------
# #1909: a newly-excluded file's nodes must be pruned from graph.json on the
# next incremental extract even when the manifest never listed the file (the