# Understanding Edge Types and Weight Conventions in Lum1104/Understand-Anything's Knowledge Graph

> Explore Lum1104 Understand Anything's knowledge graph edge types and weight conventions. Learn how relationship strength is represented and managed for accurate analysis.

- Repository: [Yuxiang Lin/Understand-Anything](https://github.com/Lum1104/Understand-Anything)
- Tags: deep-dive
- Published: 2026-05-22

---

**Lum1104/Understand-Anything defines 35 edge types across eight semantic categories, with weights constrained to [0, 1] to represent relationship strength, where missing values default to 0.5 and out-of-range values are clamped to the nearest bound.**

The knowledge graph at the heart of the Understand-Anything project transforms codebases into navigable networks of semantic relationships. To interpret these connections accurately, developers must grasp how **edge types** categorize relationships and how **weights** quantify their significance. This guide examines the edge taxonomy, weight semantics, and validation rules implemented in the Lum1104/Understand-Anything repository.

## Edge Type Taxonomy in Understand-Anything's Knowledge Graph

The complete list of edge types lives in [`packages/core/src/types.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/types.ts), implemented as a TypeScript union type called `EdgeType`. These 35 distinct types are grouped into eight semantic categories that capture everything from code structure to domain knowledge.

The definition groups edges as follows:

```ts
// Edge types (35 total in 8 categories)
export type EdgeType =
  // Structural
  | "imports" | "exports" | "contains" | "inherits" | "implements"
  // Behavioral
  | "calls" | "subscribes" | "publishes" | "middleware"
  // Data flow
  | "reads_from" | "writes_to" | "transforms" | "validates"
  // Dependencies
  | "depends_on" | "tested_by" | "configures"
  // Semantic
  | "related" | "similar_to"
  // Infrastructure / Schema
  | "deploys" | "serves" | "provisions" | "triggers"
  // Schema / Data
  | "migrates" | "documents" | "routes" | "defines_schema"
  // Domain
  | "contains_flow" | "flow_step" | "cross_domain"
  // Knowledge
  | "cites" | "contradicts" | "builds_on" | "exemplifies"
  | "categorized_under" | "authored_by";

```

All edge type strings are validated by **zod** in [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts) within the `EdgeTypeSchema`. If an edge is missing a type, the validator auto-corrects it to `"depends_on"` and records an issue.

### Structural and Behavioral Relationships

Structural edges model containment and inheritance hierarchies. The `contains` type indicates that a file or module encapsulates a function or class, while `inherits` and `implements` capture object-oriented relationships. Behavioral edges such as `calls`, `subscribes`, and `publishes` map runtime interactions like function invocations and event-driven communication patterns.

### Data Flow and Dependencies

Data flow edges track how information moves through the system. The `reads_from` and `writes_to` types link functions to data sources, while `transforms` and `validates` indicate processing stages. Dependency edges like `depends_on` and `tested_by` express service relationships and testing coverage, often assigned higher weights to reflect critical path connections.

### Semantic and Domain-Specific Connections

Higher-level relationships include `related` and `similar_to` for semantic similarity, `cross_domain` for boundary crossings in domain-driven design, and knowledge-graph primitives like `cites` and `builds_on` for documentation and research contexts. These edges typically carry lower weights (0.2–0.4) to indicate loose coupling compared to structural containment.

## Edge Weight Conventions and Validation Rules

Every edge in the knowledge graph carries a `weight: number` field constrained to the closed interval **[0, 1]** as defined in `GraphEdgeSchema` within [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts). The weight quantifies the **strength or confidence** of the relationship:

- **0.0–0.2**: Weak or optional relations (e.g., loose references or semantic similarity)
- **0.3–0.6**: Moderate confidence (common imports, typical function calls)
- **0.7–1.0**: Strong or deterministic relations (containment, direct calls, explicit dependencies)

### Auto-Correction and Normalization

When deserializing a graph, the validation pipeline in [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts) enforces strict normalization rules:

- **Missing weight**: Defaulted to `0.5` (mid-range) and recorded as an auto-corrected issue
- **String weight**: Coerced to a number; invalid strings fall back to `0.5`
- **Out-of-range values** (e.g., `-0.1` or `1.5`): Clamped to the nearest bound (`0` or `1`) with an issue logged

These conventions guarantee that downstream consumers—such as the dashboard layout algorithms and LLM-driven explanations—always receive a numeric weight they can safely use for ranking or filtering.

## Edge Directionality Semantics

Edges carry a `direction` field with three allowed values:

```ts
direction: "forward" | "backward" | "bidirectional"

```

During deserialization, the validator normalizes aliases such as `"TO"` to `"forward"`. Forward edges point from source to target, backward edges represent the inverse relationship, and bidirectional edges render as two-way links in the UI. Directionality is critical for pathfinding algorithms and for correctly interpreting relationships like `imports` versus `exports`.

## Practical Applications of Edge Weights

Edge weights influence multiple subsystems throughout the Understand-Anything codebase:

- **Layout algorithms**: The dashboard's [`utils/layout.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/utils/layout.ts) and [`utils/louvain.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/utils/louvain.ts) compute community detection and force-directed placement using weights to influence edge length—stronger edges draw nodes closer together
- **Explanation generation**: [`src/explain-builder.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/src/explain-builder.ts) filters and ranks edges by weight when assembling human-readable narratives, prioritizing high-confidence relationships (≥ 0.7)
- **Diff analysis**: [`src/diff-analyzer.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/src/diff-analyzer.ts) propagates changes through high-weight edges first, treating them as more impactful to the system's behavior

## Working with GraphEdge in Code

The following examples demonstrate how to construct edges, handle validation, and utilize weights in custom algorithms.

### Constructing a Type-Safe Edge

```ts
import { GraphEdge } from "@understand-anything/core";

const edge: GraphEdge = {
  source: "file:src/auth.ts",
  target: "function:src/auth.ts:login",
  type: "contains",          // structural containment
  direction: "forward",
  description: "auth file contains login function",
  weight: 1.0,               // strongest possible link
};

```

### Validating Raw Input with Auto-Correction

```ts
import { validateKnowledgeGraph } from "@understand-anything/core";

const raw = {
  source: "file:src/service.ts",
  target: "file:src/db.ts",
  type: "reads_from",
  // direction omitted → defaults to "forward"
  // weight omitted → defaults to 0.5 (auto-corrected)
};

const { data, issues } = validateKnowledgeGraph({ 
  version: "1.0", 
  project: {/*…*/}, 
  nodes: [], 
  edges: [raw], 
  layers: [], 
  tour: [] 
});

console.log(data.edges[0].direction); // "forward"
console.log(data.edges[0].weight);    // 0.5
console.log(issues[0].message);       // edges[0]: missing "direction" — defaulted to "forward"

```

### Using Weights in Layout Algorithms

```ts
import { GraphEdge } from "@understand-anything/core";

function computeEdgeLength(edge: GraphEdge): number {
  // Stronger edges are drawn shorter (more tightly) – inverse mapping
  const minLen = 30, maxLen = 200;
  return maxLen - edge.weight * (maxLen - minLen);
}

// Example usage:
const short = computeEdgeLength({ 
  weight: 1, 
  source: "", 
  target: "", 
  type: "contains", 
  direction: "forward" 
});
const long  = computeEdgeLength({ 
  weight: 0.2, 
  source: "", 
  target: "", 
  type: "related", 
  direction: "forward" 
});

console.log(short, long); // 30 170

```

### Filtering by Confidence Threshold

```ts
import { GraphEdge } from "@understand-anything/core";

function topEdges(edges: GraphEdge[], threshold = 0.7) {
  return edges.filter(e => e.weight >= threshold);
}

const important = topEdges(sampleGraph.edges);
console.log(important.map(e => `${e.source} → ${e.target} (${e.weight})`));

```

## Summary

- **35 edge types** in eight categories (structural, behavioral, data-flow, dependencies, semantic, infrastructure, schema, and knowledge) are defined in [`packages/core/src/types.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/types.ts)
- **Weight values** must fall within [0, 1], where higher values indicate stronger relationships; the system defaults missing weights to `0.5` and clamps out-of-range values
- **Validation** occurs in [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts) using zod schemas that auto-correct missing types to `"depends_on"` and normalize direction strings
- **Directionality** supports forward, backward, and bidirectional relationships, with normalization for legacy aliases
- **Downstream systems** leverage weights for force-directed layout in [`utils/layout.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/utils/layout.ts), explanation ranking in [`explain-builder.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/explain-builder.ts), and impact analysis in [`diff-analyzer.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/diff-analyzer.ts)

## Frequently Asked Questions

### What are the 35 edge types in Understand-Anything?

The 35 edge types span eight semantic categories defined in [`packages/core/src/types.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/types.ts). Structural types include `imports`, `exports`, `contains`, `inherits`, and `implements`. Behavioral types cover `calls`, `subscribes`, `publishes`, and `middleware`. Data flow is captured by `reads_from`, `writes_to`, `transforms`, and `validates`. Additional categories handle dependencies (`depends_on`, `tested_by`), infrastructure (`deploys`, `serves`), schema (`defines_schema`, `migrates`), domain logic (`cross_domain`, `flow_step`), and knowledge relationships (`cites`, `builds_on`).

### How does Understand-Anything handle missing edge weights?

When an edge lacks a weight field, the validator in [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts) assigns a default value of `0.5` and logs an auto-correction issue. If the weight is provided as a string, the system attempts to coerce it to a number; invalid strings also fall back to `0.5`. Values outside the [0, 1] range are clamped to the nearest valid bound (0 or 1) rather than rejected.

### What is the difference between forward and bidirectional edges?

Forward edges represent relationships that flow from source to target, such as a file importing another module or a function calling another function. Bidirectional edges indicate mutual relationships where both nodes influence each other equally, such as two services in a circular dependency or semantically similar concepts. The UI renders forward edges as single arrows and bidirectional edges as double-headed links.

### How are edge weights used in the dashboard layout?

The dashboard's layout engine in [`packages/dashboard/src/utils/layout.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/dashboard/src/utils/layout.ts) uses edge weights to compute force-directed graph distances. Higher weights (closer to 1.0) result in shorter edge lengths, pulling connected nodes tightly together. Lower weights allow greater separation. This visual encoding helps users immediately distinguish strong structural dependencies from weak semantic associations.