# How Staleness Detection Determines When the Egonex-AI Knowledge Graph Needs Rebuilding

> Learn how staleness detection in Egonex-AI determines knowledge graph rebuilds by comparing Git HEAD to stored commit hashes, triggering updates when files change.

- Repository: [Egonex/Understand-Anything](https://github.com/Egonex-AI/Understand-Anything)
- Tags: internals
- Published: 2026-06-14

---

**Staleness detection in Egonex-AI compares the current Git HEAD against the commit hash stored in the knowledge graph, triggering a rebuild only when `git diff` identifies changed files between these two points.**

The Egonex-AI Understand-Anything engine maintains an incremental knowledge graph that tracks codebases over time. To avoid expensive full rebuilds, the system implements **staleness detection** that determines exactly when the underlying source has drifted from the stored analysis. This mechanism lives in the core package and leverages Git history to make precise, file-level decisions about graph validity.

## How Staleness Detection Identifies Changed Files

### Git Diff Execution

The detection starts in [`understand-anything-plugin/packages/core/src/staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/staleness.ts) with the `getChangedFiles` function (lines 13‑26). This utility executes a synchronous Git command via `child_process.execFileSync` to compare the stored commit hash against the current repository state.

```typescript
const output = execFileSync('git',
  ['diff', `${lastCommitHash}..HEAD`, '--name-only'],
  { cwd: projectDir, encoding: "utf-8" });

```

The function parses the newline‑delimited output into an array of file paths. If Git fails—for instance, when the stored commit hash is unknown or the repository is corrupted—the function returns an empty array, conservatively treating the graph as up‑to‑date to prevent unnecessary rebuilds.

### Staleness Evaluation Logic

The `isStale` function (lines 34‑42) consumes the changed file list to make a boolean determination. It calls `getChangedFiles` and evaluates whether the returned array contains any entries. When the array is non‑empty, the function returns `stale: true` alongside the list of changed files for downstream processing.

This design separates the **detection** concern from the **action** concern, allowing the pipeline to inspect exactly which files triggered the staleness flag before committing to a rebuild.

## Rebuilding the Knowledge Graph After Stale Detection

When staleness is confirmed, the pipeline invokes `mergeGraphUpdate` (lines 54‑90) to surgically update the graph rather than regenerating it from scratch.

### Selective Node and Edge Removal

The merge strategy operates on the principle of **file-level invalidation**:

- **Node removal**: All nodes whose `filePath` property appears in the changed file set are discarded from the graph
- **Edge cleanup**: Any edges connected to removed nodes—whether as source or target—are automatically stripped to maintain graph integrity
- **Fresh data append**: New nodes and edges from the current analysis are appended to the cleaned graph structure

This approach preserves analysis results for unchanged files while eliminating stale references to modified code.

### Metadata Synchronization

After structural updates, `mergeGraphUpdate` updates the project metadata stored within the `KnowledgeGraph` object. It writes the new `gitCommitHash` (current HEAD) and refreshes the `analyzedAt` timestamp to reflect the analysis time, ensuring future staleness checks compare against the correct baseline.

## Practical Implementation Examples

### Checking Graph Freshness

The following pattern demonstrates how the main analysis pipeline uses `isStale` to gate rebuild operations:

```typescript
import { isStale } from "@understand-anything/core";

async function maybeRebuild(projectDir: string, storedGraph: KnowledgeGraph) {
  const { stale, changedFiles } = isStale(projectDir, storedGraph.project.gitCommitHash);
  if (!stale) {
    console.log("Graph is fresh – no rebuild needed.");
    return storedGraph;
  }

  console.log("Detected changes:", changedFiles);
  // Run a fresh analysis (omitted) → newNodes, newEdges, newCommitHash
  // const { newNodes, newEdges, newCommitHash } = await runAnalysis(projectDir);
  // return mergeGraphUpdate(storedGraph, changedFiles, newNodes, newEdges, newCommitHash);
}

```

### Applying Incremental Updates

When changes are detected, the `mergeGraphUpdate` function reconciles the old graph with fresh analysis data:

```typescript
import { mergeGraphUpdate } from "@understand-anything/core";

function updateGraph(
  oldGraph: KnowledgeGraph,
  changedFiles: string[],
  freshNodes: GraphNode[],
  freshEdges: GraphEdge[],
  newCommitHash: string,
) {
  return mergeGraphUpdate(
    oldGraph,
    changedFiles,
    freshNodes,
    freshEdges,
    newCommitHash,
  );
}

```

### Unit Test Verification

The test suite in [`understand-anything-plugin/packages/core/src/__tests__/staleness.test.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/__tests__/staleness.test.ts) validates each branch of the logic, including Git output parsing and error handling:

```typescript
import { isStale, getChangedFiles } from "../staleness.js";

test("isStale returns true when files changed", () => {
  vi.mocked(execFileSync).mockReturnValue("src/index.ts\n");
  expect(isStale("/project", "abc123")).toEqual({
    stale: true,
    changedFiles: ["src/index.ts"],
  });
});

```

## Summary

- **Staleness detection** relies on `git diff ${lastCommitHash}..HEAD --name-only` to identify changed files between the stored analysis commit and the current repository state.
- The `isStale` function in [`staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/staleness.ts) (lines 34‑42) returns a boolean flag and the specific file list, enabling precise invalidation decisions.
- When rebuilding is required, `mergeGraphUpdate` (lines 54‑90) removes nodes and edges associated with changed files while preserving the rest of the graph structure.
- The system updates `gitCommitHash` and `analyzedAt` metadata after each successful rebuild to establish a new baseline for future comparisons.
- Error handling in `getChangedFiles` defaults to "fresh" status if Git commands fail, preventing unnecessary rebuilds on repository errors.

## Frequently Asked Questions

### What triggers a knowledge graph rebuild in Egonex-AI?

A rebuild triggers when the `isStale` function detects that the Git commit hash stored in the knowledge graph differs from the current HEAD and `git diff` returns a non‑empty list of changed files. The system then removes nodes associated with those specific files and merges fresh analysis results.

### How does the system handle Git command failures during staleness checks?

If `execFileSync` throws an error—for example, when the stored commit hash no longer exists in the repository—the `getChangedFiles` function catches the exception and returns an empty array. This conservative approach treats the graph as fresh, preventing unnecessary rebuilds when Git metadata is unavailable or corrupted.

### What happens to graph edges when a file is marked as stale?

The `mergeGraphUpdate` function removes any edges where either the source or target node references a file path in the changed file set. This ensures the graph maintains referential integrity after nodes are removed, eliminating dangling connections to obsolete code entities.

### Where is the staleness detection logic located in the codebase?

The core implementation resides in [`understand-anything-plugin/packages/core/src/staleness.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/staleness.ts), which exports `getChangedFiles`, `isStale`, and `mergeGraphUpdate`. Type definitions for `KnowledgeGraph`, `GraphNode`, and `GraphEdge` are imported from [`types.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/types.ts) in the same directory, while comprehensive unit tests are located in [`__tests__/staleness.test.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/__tests__/staleness.test.ts).