[Bug]: changed-files rebuild (hook/watch) evicts placeholder nodes for files that were never scanned
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
- #4161 de @rohit-jsfreaky — cerrado sin fusionar
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 85/100
Línea de trabajo
El bug se encuentra en la lógica de barrido del corpus de la función _reconcile_existing_graph; comienza ahí para modificar la comprobación de expulsión de rutas de origen faltantes. Usa el manifest.json del escaneo anterior (solo se sobrescribe después de que finalice la reconciliación) como evidencia de eliminación: solo expulsa una ruta faltante si estaba presente en el último manifest, de lo contrario conserva los nodos marcador de posición para archivos que nunca se han escaneado. Ejecuta el script repro.py proporcionado para confirmar que los nodos marcador de posición y sus bordes se conservan en las reconstrucciones de archivos modificados, coincidiendo con la salida de la reconstrucción completa.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Pre-flight checks
- I have checked the Troubleshooting section in the README
What happened?
An extractor can mint a node for a file that is not in the checkout: the target of an unresolved dynamic import (import('./queue.js')), or a project a .sln / .slnx / <ProjectReference> names. The node carries the missing path as its source_file, but it is the referring file's output (label ./queue.js, edges only from the referrer).
On a changed-files rebuild (_rebuild_code(changed_paths=...), used by the post-commit hook and graphify watch), the corpus sweep in _reconcile_existing_graph reads that missing path as a deleted source and evicts the node. The unchanged referrer's preserved edges to it then dangle and are dropped. A full rebuild of the same tree keeps both, so after every hook or watch rebuild the graph silently differs from a full rebuild, and it flips back on the next graphify update.
This goes against CONTRIBUTING ("Cross-file edges: must be preserved during incremental updates") and against the intent of #1795 ("require deletion evidence before evicting a missing source"): a path that was never scanned has no deletion evidence.
On graphify's own repo (975 files, v8 5c7b847), editing one unrelated file and running the changed-files rebuild loses 8 nodes and 15 edges compared with a full rebuild of the same tree: the placeholders for tests/fixtures/dynamic_import.ts's missing ./queue.js, ./mayaEngine.js, ./staticHelper, and the .csproj projects sample.sln, sample.slnx and sample.csproj reference.
Related to #3570 (same symptom class); the commenters there found that cause fixed by 32b209a, and this is a different mechanism that still reproduces on 0.9.77.
Steps to reproduce
cat > repro.py <<'EOF'
import json, tempfile
from pathlib import Path
from graphify.watch import _rebuild_code
def placeholder(c):
g = json.loads((c / "graphify-out/graph.json").read_text(encoding="utf-8"))
nodes = [n["id"] for n in g["nodes"] if n.get("source_file", "").endswith("queue.js")]
edges = [(e["source"], e["relation"]) for e in g["links"] if e["target"] in nodes]
return nodes, edges
if __name__ == "__main__":
c = Path(tempfile.mkdtemp()) / "corpus"; c.mkdir()
(c / "app.ts").write_text("export async function load() {\n return import('./queue.js');\n}\n")
(c / "other.ts").write_text("export function other() {\n return 1;\n}\n")
_rebuild_code(c, no_cluster=True, acquire_lock=False, force=True)
print("full rebuild: ", placeholder(c))
(c / "other.ts").write_text("export function other() {\n return 2;\n}\n")
_rebuild_code(c, changed_paths=[Path("other.ts")], no_cluster=True, acquire_lock=False, force=True)
print("changed-files (other.ts): ", placeholder(c))
_rebuild_code(c, no_cluster=True, acquire_lock=False, force=True)
print("full rebuild, same tree: ", placeholder(c))
EOF
PYTHONHASHSEED=0 python repro.py
Error output or graph output
full rebuild: (['queue'], [('app_load', 'imports_from'), ('app', 'dynamic_import')])
changed-files (other.ts): ([], [])
full rebuild, same tree: (['queue'], [('app_load', 'imports_from'), ('app', 'dynamic_import')])
On graphify's own repo, after a one-file edit: changed-files rebuild 18,617 nodes / 37,920 edges vs full rebuild of the same tree 18,625 / 37,935.
Graphify version
0.9.77 (5c7b847)
Operating System
Windows
Python Version
3.12
Installation Method
built from source (git clone)
Additional Environment Details
AST-only, no provider environment variables, PYTHONHASHSEED=0. A clean checkout of v8 at 5c7b847 reproduces it. Found while comparing changed-files and full rebuilds of graphify's own repo.
Additional context
Fix ready: use the previous scan (manifest.json, rewritten only after reconcile) as the deletion evidence. A missing path that was in the last scan is evicted as before; one that was never scanned is kept while a referrer that is not re-extracted this run still points at it. No manifest: old behaviour. PR right after this.
- Lenguaje dominante
- Python
- Estrellas
- 124k
- Forks
- 11.9k
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Graphify-Labs/graphify
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Graphify-Labs/graphify#4831 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 75/100
Graphify-Labs/graphify#4829 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
hooks: last-resort `python3` probe launches the Microsoft Store redirector on Windows (visible console flash, exit 9009)Posiblemente ocupada @Deepjyoti-Sarmah la tomó hace 8 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Graphify-Labs/graphify#4563 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
GRAPHIFY_DISABLE_THINKING is ignored by the claude backend, so thinking eats max_tokens and extraction truncatesPosiblemente ocupada @bercedev la tomó hace 8 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 69/100
Graphify-Labs/graphify#4546 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
--update runbook: graph.json backup instruction comes after the diff that needs it, so the graph diff never runsPosiblemente ocupada @sunildivakar96-cpu la tomó hace 9 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Graphify-Labs/graphify#4539 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de Graphify-Labs/graphify
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
pydot/pydot#601 · 4 comentarios ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
letsencrypt/cp-cps#361 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
-
CI: startup_failure because callers grant fewer permissions than ledger-app-workflows@v1 declaresPosiblemente ocupada @maykonmichel la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
LedgerHQ/app-boilerplate-rust#227 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
linuxmint/mintupdate#1107 ·