# How to Use Graphify Reflection for Stale Data Detection and Recovery

> Master stale data detection with Graphify reflection. Learn how Graphify generates sidecars to identify outdated knowledge using source code fingerprinting. Recover your data efficiently.

- Repository: [Graphify Labs/graphify](https://github.com/Graphify-Labs/graphify)
- Tags: how-to-guide
- Published: 2026-07-16

---

**Graphify reflection generates a [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json) side-car that marks lessons as stale when source code fingerprints (SHA-256 hashes) no longer match current files, enabling automated detection of outdated knowledge.**

Graphify (Graphify-Labs/graphify) is an open-source knowledge management tool that converts Q&A memory into deterministic lessons. Its reflection engine tracks code changes to identify when cached knowledge becomes stale, allowing agents to ignore outdated advice or trigger regeneration.

## How Graphify Reflection Detects Stale Data

The reflection process in [`graphify/reflect.py`](https://github.com/Graphify-Labs/graphify/blob/main/graphify/reflect.py) transforms memory documents into a structured learning overlay. It fingerprints source files to detect when lesson content no longer reflects the current implementation.

### The Reflection Pipeline

The reflection pipeline executes six distinct steps to generate lessons and detect staleness:

1. **Collect memory docs** – `load_memory_docs` parses every `*.md` file containing front-matter written by `graphify save-result` (lines 33-57) in [`graphify/reflect.py`](https://github.com/Graphify-Labs/graphify/blob/main/graphify/reflect.py).
2. **Aggregate lessons** – `aggregate_lessons` scores each source node with time-decayed weights, grouping them into *preferred*, *tentative*, and *contested* buckets while recording provenance events (lines 64-78).
3. **Render the lessons file** – `render_lessons_md` produces a stable markdown document at [`graphify-out/reflections/LESSONS.md`](https://github.com/Graphify-Labs/graphify/blob/main/graphify-out/reflections/LESSONS.md) (lines 90-110).
4. **Build the learning side-car** – `build_learning_overlay` resolves each node to a canonical ID and adds a `code_fingerprint` (SHA-256 hash of the node's source file) via `_content_hash` (lines 672-679).
5. **Write the side-car** – `write_learning_sidecar` writes [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json) beside the graph in a deterministic, sorted format (lines 331-338).
6. **Detect staleness** – The `_is_stale` function (lines 687-699) compares stored fingerprints against current file hashes.

### The Learning Side-Car Structure

The [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json) file contains metadata for each node referenced in the lessons:

- `code_fingerprint`: SHA-256 hash of the source file content at the time of reflection
- `stale`: Boolean flag indicating whether the implementation has changed
- `source_file`: Path to the source file (resolved via `_resolve_source_path`)
- `generated_at`: Timestamp of lesson creation

This side-car is generated by `build_learning_overlay` and written atomically to prevent corruption during concurrent access.

### The Staleness Check Algorithm

When `load_learning_overlay` loads the side-car, it invokes `_is_stale` to validate each entry:

- `_resolve_source_path` (lines 668-682) handles absolute paths, layout-specific roots, and the optional `.graphify_root` marker to locate the current source file.
- The function recomputes the SHA-256 hash of the current file and compares it with the stored `code_fingerprint`.
- If the file is missing, the hash differs, or no fingerprint was recorded, the entry is marked **stale** (lines 687-699).

## Detecting Stale Data Programmatically

You can consume the reflection artifacts in Python to build staleness-aware workflows.

### Loading the Side-Car with load_learning_overlay

Import `load_learning_overlay` from `graphify.reflect` to access the staleness metadata:

```python
from pathlib import Path
from graphify.reflect import load_learning_overlay

graph_path = Path("graphify-out/graph.json")
learning = load_learning_overlay(graph_path)

# Returns a dict: node_id → entry dict

print(f"Loaded {len(learning)} lesson entries")

```

Each entry contains the `stale` boolean, `code_fingerprint`, and `source_file` path.

### Filtering Stale Entries

Filter the overlay to identify outdated lessons that require attention:

```python

# Filter for stale entries only

stale_nodes = {
    nid: entry for nid, entry in learning.items() 
    if entry.get("stale")
}

print(f"Found {len(stale_nodes)} stale lessons:")
for nid, entry in stale_nodes.items():
    print(f"- {entry['label']} (id={nid}) – last updated {entry['generated_at']}")

```

This pattern allows agents to exclude stale guidance from prompt context or flag them for review.

## Refreshing Stale Lessons

When stale data is detected, you can regenerate the lessons using either the CLI or the Python API.

### CLI Workflow

Run reflection from the command line to regenerate the lessons file and side-car:

```bash
graphify reflect --memory graphify-out/memory \
               --out graphify-out/reflections/LESSONS.md \
               --graph graphify-out/graph.json \
               --if-stale   # skips work if output is already fresh

```

The `--if-stale` flag optimizes performance by checking modification times before recomputing. The command reads memory docs, aggregates lessons, writes [`LESSONS.md`](https://github.com/Graphify-Labs/graphify/blob/main/LESSONS.md), and produces [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json) beside the graph.

### Programmatic Refresh with lessons_fresh

Use the Python API to conditionally refresh only when necessary:

```python
from pathlib import Path
from graphify.reflect import reflect, lessons_fresh

memory_dir = Path("graphify-out/memory")
out_path = Path("graphify-out/reflections/LESSONS.md")
graph_path = Path("graphify-out/graph.json")

# Re-run only if source files changed

if not lessons_fresh(out_path, memory_dir, graph_path=graph_path):
    reflect(memory_dir, out_path, graph_path=graph_path)
    print("Lessons refreshed – stale data updated.")
else:
    print("Lessons are up-to-date.")

```

The `lessons_fresh` function checks file modification times, while the side-car provides content-hash verification for cryptographic certainty.

## Summary

- **Graphify reflection** produces a deterministic [`LESSONS.md`](https://github.com/Graphify-Labs/graphify/blob/main/LESSONS.md) artifact and a [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json) side-car containing SHA-256 fingerprints for every source node.
- **Stale detection** occurs in `_is_stale` (lines 687-699 of [`graphify/reflect.py`](https://github.com/Graphify-Labs/graphify/blob/main/graphify/reflect.py)), which compares stored fingerprints against current file hashes using `_resolve_source_path`.
- **Programmatic access** via `load_learning_overlay` returns a dictionary where the `stale` boolean flag indicates outdated entries.
- **Conditional regeneration** uses `lessons_fresh` to avoid unnecessary computation, while the `--if-stale` CLI flag provides similar optimization for shell workflows.

## Frequently Asked Questions

### What does "stale data" mean in Graphify?

In Graphify, **stale data** refers to a lesson whose associated source code has been modified or deleted after the lesson was generated. The reflection engine stores a SHA-256 fingerprint of each source file; when `load_learning_overlay` detects a hash mismatch or missing file via `_is_stale`, it marks the entry as stale to prevent agents from relying on outdated guidance.

### How does Graphify track code changes for staleness?

Graphify tracks changes through **content hashing** rather than timestamps. During reflection, `build_learning_overlay` computes a `code_fingerprint` (SHA-256 hash) for each node's source file (lines 672-679 in [`graphify/reflect.py`](https://github.com/Graphify-Labs/graphify/blob/main/graphify/reflect.py)). When loading the overlay, `_is_stale` recomputes the hash and compares it to the stored fingerprint, marking the entry stale if they differ or if the file is missing.

### Can I skip reflection if lessons are already fresh?

Yes. Use the `--if-stale` flag in the CLI to skip processing when outputs are current, or call `lessons_fresh(out_path, memory_dir, graph_path=graph_path)` in Python to check modification times before invoking `reflect`. This prevents unnecessary I/O when source files and memory documents haven't changed since the last run.

### Where is the stale data metadata stored?

The staleness metadata is stored in [`.graphify_learning.json`](https://github.com/Graphify-Labs/graphify/blob/main/.graphify_learning.json), a JSON side-car file written beside your graph file (e.g., [`graphify-out/graph.json`](https://github.com/Graphify-Labs/graphify/blob/main/graphify-out/graph.json)). This file is generated by `write_learning_sidecar` (lines 331-338) and contains the `code_fingerprint`, `stale` boolean, and `source_file` path for each lesson entry.