# v3.19.2 — stale codebase-graph gate

Follow-up to the 3.19.1 ingest deadlock fix. The deadlock guard stopped the
hang; this stops the *stale graph* it could leave behind.

## What it fixes

`/cortex-visualize` (and `ingest_codebase`) could serve an **out-of-date AST**:
the cached code-graph was reused as long as the graph directory merely *existed*,
with no check that the codebase hadn't changed since it was built. A graph built
before your last edits was reused indefinitely — the "graph shows an old version
of the analysis" report.

## The change

New `graph_is_fresh(project_path, graph_path)`: compares the graph artefact's own
build mtime against the newest source file under the project, via a bounded,
ignore-pruned walk that early-exits on the first newer file (vendored/build dirs
— `.git`, `node_modules`, `target`, `.venv`, `search_index`, … — are skipped so
they can't trip false staleness). `find_cached_graph` now skips a stale (or
non-materialised) graph, so ingestion falls through to a fresh `analyze_codebase`.
It errs fresh on uncertainty (absent project root / unreadable graph) to avoid
needless re-analysis. Scope: ingestion only — the visualizer's roster resolver is
untouched.

## Recovering an already-bad cache

If a prior run left a *half-built* graph (recent, so the freshness gate treats it
as current), force one clean rebuild:

```
ingest_codebase(project_path="<repo>", force_reindex=true)
# or: rm -rf ~/.cache/cortex/code-graphs/<project>-*/
```

With the 3.19.1 deadlock guard, that re-ingest completes instead of hanging.

## Still in progress

The deadlock guard is a safety net; the architectural root (the pooled MCP reader
bound to a throwaway per-call event loop) and symbol-read producer/consumer
overlap are tracked in `docs/provenance/ingest-ecosystem-fix-plan.md`.
