# Weighted Best-Path Score in Impact Analysis: How code-review-graph Ranks Affected Nodes

> Discover the weighted best-path score in impact analysis. Learn how code-review-graph ranks affected nodes using multiplicative metrics and edge-specific weights for precise change propagation.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: deep-dive
- Published: 2026-08-11

---

**The weighted best-path score is a multiplicative ranking metric that propagates impact from changed code through relationship edges, applying edge-specific weights and depth decay while keeping only the highest score when multiple paths reach the same node.**

In the `code-review-graph` open-source project, this score drives the impact analysis engine that identifies which parts of a codebase are most likely affected by a code change. Understanding how this score works is essential for interpreting results and tuning the analysis for your repository's structure.

---

## How the Weighted Best-Path Score Works

The scoring algorithm follows a five-stage pipeline that combines graph traversal with probabilistic decay. Each stage is implemented in specific source files with configurable parameters.

### 1. Seed Node Initialization

All **qualified names** appearing in changed files enter the frontier with a fixed score of **1.0**. These seeds represent the starting points of impact propagation—in [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py), the initialization populates the `_impact_frontier` temporary table before traversal begins.

```python
from code_review_graph.graph import GraphStore

store = GraphStore("my_repo/graph.db")

# Start impact analysis from specific changed files

result = store.get_impact_radius_sql(
    changed_files=["/project/src/auth.py"],
    max_depth=2,
    max_nodes=10,
)

```

### 2. Edge Traversal with Direction Policies

For every node in the frontier, the engine examines incident edges filtered by **impact direction** rules. These rules are defined in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py) at lines 57-88:

- **CALLS** edges are traversed *incoming* (who calls this function?)
- **TESTED_BY** edges are traversed *outgoing* (what tests cover this?)

Each edge kind also carries a **weight** reflecting semantic strength—stronger relationships propagate more impact. The default weight map lives in the same file at lines 54-68.

### 3. Score Calculation with Decay

When reaching a neighbor node, the candidate score computes as:

```

new_score = current_score × edge_weight × IMPACT_DEPTH_DECAY

```

The `IMPACT_DEPTH_DECAY` constant defaults to **0.6** and is defined in [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) at lines 94-99. This decay factor ensures that impact weakens with distance from the original change—nodes "closer" to modified code score higher, all else equal.

```sql
-- Core score computation from graph.py (simplified)
SELECT
    e.target_qualified AS node_qn,
    f.score * COALESCE(p.weight, ?) * ? AS score
FROM _impact_frontier f
JOIN edges e ON e.source_qualified = f.node_qn
LEFT JOIN _impact_policies p ON p.kind = e.kind

```

### 4. Best-Path Selection via MAX Aggregation

A node may be reachable through multiple paths. The engine enforces **single best-path retention** using `MAX(score)` aggregation in the `_impact_next` temporary table—see [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) lines 46-66. This guarantees each qualified name keeps only its highest discovered score, regardless of path multiplicity.

The SQL implementation explicitly uses:

```sql
INSERT OR REPLACE INTO _impact_next (node_qn, score)
SELECT node_qn, MAX(score) FROM (/* ... UNION of incoming/outgoing traversals ... */)
GROUP BY node_qn

```

### 5. Floor Filtering and Result Truncation

Scores falling below `IMPACT_SCORE_FLOOR` (default **0.05**) are discarded—preventing infinite expansion in cyclical graphs. After BFS termination or `MAX_IMPACT_DEPTH` reached, results are truncated to `max_nodes` entries with an optional truncation flag.

---

## Weighted Best-Path Score Formula

Combining all components, the complete scoring logic:

| Component | Default Value | Location |
|-----------|-------------|----------|
| Initial seed score | 1.0 | [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) frontier init |
| Edge weights | 0.3–1.0 per kind | [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py#L54-L68) |
| Direction policy | varies by edge kind | [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py#L57-L88) |
| `IMPACT_DEPTH_DECAY` | 0.6 | [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py#L94-L99) |
| `IMPACT_SCORE_FLOOR` | 0.05 | [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py#L96-L99) |
| `MAX_IMPACT_DEPTH` | 5 | [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) |

Final score for node *n* via path *p*:

```

score(n, p) = Π(edge_weight_i) × (IMPACT_DEPTH_DECAY)^depth

```

With best-path selection: `final_score(n) = max_p score(n, p)`

---

## Code Example: Working with Impact Scores

```python
from code_review_graph.graph import GraphStore

store = GraphStore("my_repo/graph.db")
result = store.get_impact_radius_sql(
    changed_files=["/project/src/auth.py"],
    max_depth=2,
    max_nodes=10,
)

print("Impacted nodes by weighted best-path score:")
for node in result["impacted_nodes"]:
    qn = node.qualified_name
    score = result["impact_scores"][qn]
    print(f"{qn:<40} → {score:.4f}")

# Typical output showing decay cascade:

# /project/src/service.py::login          → 0.6000  (direct caller, weight 1.0)

# /project/src/util.py::hash_password    → 0.3600  (2 hops: 1.0 × 0.6 × 0.6)

# /project/src/config.py::load_settings   → 0.3000  (indirect, lower edge weight)

```

The **best-path weighting is engine-independent**—both SQL and NetworkX implementations produce identical scores:

```python
result_sql = store.get_impact_radius_sql(["/project/src/auth.py"])
result_nx  = store._get_impact_radius_networkx(["/project/src/auth.py"])

assert result_sql["impact_scores"] == result_nx["impact_scores"]

```

---

## Tuning the Weighted Best-Path Score

Modify constants in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py) to adjust analysis behavior:

```python

# Sharper decay for more localized results

IMPACT_DEPTH_DECAY = 0.4  # default 0.6

# Higher floor for stricter relevance

IMPACT_SCORE_FLOOR = 0.1  # default 0.05

# Custom edge weights for your domain

EDGE_IMPACT_WEIGHTS = {
    "CALLS": 1.0,        # strong propagation

    "IMPORTS": 0.5,      # moderate

    "MENTIONS": 0.2,     # weak signal

}

```

Changes affect both SQL and NetworkX engines since both reference the same `constants` module.

---

## Summary

- **Weighted best-path score** combines edge semantics, multiplicative decay, and maximum-path selection to rank code affected by changes
- **Seed nodes** start at 1.0; each hop multiplies by `edge_weight × IMPACT_DEPTH_DECAY` (default 0.6)
- **Best-path rule** keeps only `MAX(score)` per node, handling multiple reachability paths
- **Floor truncation** (default 0.05) prevents noise from distant or cyclical relationships
- Implementation spans [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) (parameters), [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) (SQL/NetworkX engines), and [`tests/test_graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_graph.py) (verification)

---

## Frequently Asked Questions

### How is the weighted best-path score different from simple shortest-path distance?

Simple shortest-path counts hops regardless of relationship strength. The weighted best-path score in `code-review-graph` incorporates **edge-specific weights** (defined in [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) lines 54-68) and **exponential depth decay**, so a longer path through strong relationships can outrank a shorter path through weak ones. The `MAX(score)` aggregation in [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) lines 48-66 selects the optimal trade-off per node.

### Why does impact score decrease with depth even if edge weights are 1.0?

The `IMPACT_DEPTH_DECAY` factor (default 0.6, [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) lines 94-99) applies unconditionally to every hop. This reflects the intuition that indirect relationships are inherently less reliable indicators of impact. A three-hop path with weight-1.0 edges scores `0.6³ = 0.216`, while a one-hop path with weight 0.5 scores `0.5 × 0.6 = 0.30`—demonstrating how decay penalizes distance.

### Can two different paths produce the same final score for a node?

Yes, if their combined edge-weight-and-decay products are equal. For example: path A with two hops of weight 1.0 scores `1.0 × 0.6 × 1.0 × 0.6 = 0.36`; path B with one hop of weight 0.6 scores `0.6 × 0.6 = 0.36`. The `MAX(score)` aggregation in [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) handles ties transparently—both paths validate the same score, and the node retains 0.36.

### Where are the unit tests for weighted best-path scoring?

The [`tests/test_graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_graph.py) file contains class `TestWeightedImpactScoring` verifying correct scoring, ranking order, edge-weight handling, and parity between SQL and NetworkX engines. These tests ensure that modifications to [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py) parameters or [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py) algorithms preserve expected mathematical properties of the weighted best-path score.