DEV Community

Cover image for Your Code Knows What Changed. But Does It Know Why?
Bobby Hall Jr
Bobby Hall Jr

Posted on

Your Code Knows What Changed. But Does It Know Why?

AI can write a pull request in seconds.

But when that pull request touches a piece of code written three years ago, there is a much harder question:

Why does this code exist?

That answer might be buried across 47 commits, 12 pull requests, an old incident, a Slack conversation nobody remembers, and one engineer who left the company six months ago.

This is becoming one of the biggest problems in AI-assisted software engineering.

Because writing code is getting cheaper. Understanding code is not.


The Codebase Is Not the Whole System

Consider this:

if (user.isLegacy && !featureEnabled) {
  return fallback();
}
Enter fullscreen mode Exit fullscreen mode

Looks suspicious.

Maybe it's dead code.

Maybe someone forgot to clean it up.

So an AI coding agent suggests:

- if (user.isLegacy && !featureEnabled) {
-   return fallback();
- }
Enter fullscreen mode Exit fullscreen mode

The tests pass.

The PR looks clean.

You merge it.

Three hours later, production breaks for a subset of customers.

Now you're asking a very different question:

Who knew why that code was there?

The answer might have been hiding in the engineering history.


Git Knows What Changed

Git is incredible.

It can tell you:

What changed?
Who changed it?
When did they change it?
Enter fullscreen mode Exit fullscreen mode

But those aren't always the questions engineers need answered.

We need:

Why did it change?

What problem was it solving?

What depends on it?

What happens if I change it?

Has this failed before?

Who understands this part of the system?

Was this introduced because of an incident?

What happened the last time someone touched it?
Enter fullscreen mode Exit fullscreen mode

The problem isn't that this information doesn't exist.

It does.

It's just fragmented.


The Hidden Knowledge Graph Inside Every Codebase

Every engineering organization already has a graph.

They just don't usually call it one.

A pull request is connected to commits.

Commits are connected to files.

Files are connected to services.

Services are connected to deployments.

Deployments are connected to incidents.

Incidents are connected to fixes.

Fixes are connected to engineers.

Engineers are connected to decisions.

Decisions are connected to outcomes.

Like this:

                    ┌────────────┐
                    │   Issue    │
                    └─────┬──────┘
                          │
                       solved by
                          │
                          ▼
                    ┌────────────┐
                    │     PR     │
                    └─────┬──────┘
                          │
                       modified
                          │
                          ▼
                    ┌────────────┐
                    │    Code    │
                    └─────┬──────┘
                          │
                      depends on
                          │
                          ▼
                    ┌────────────┐
                    │  Service   │
                    └─────┬──────┘
                          │
                      affected
                          │
                          ▼
                    ┌────────────┐
                    │  Incident  │
                    └─────┬──────┘
                          │
                       caused
                          │
                          ▼
                    ┌────────────┐
                    │    Fix     │
                    └────────────┘
Enter fullscreen mode Exit fullscreen mode

The valuable information isn't just the nodes.

It's the edges.


Why Relationships Matter

Suppose you're looking at:

checkout.ts
Enter fullscreen mode Exit fullscreen mode

A traditional code search might tell you:

checkout.ts
├── imported by payment.ts
├── imported by cart.ts
└── imported by order.ts
Enter fullscreen mode Exit fullscreen mode

Useful.

But an Engineering Graph could tell you:

checkout.ts
│
├── modified by PR #842
│     ├── solved issue #421
│     ├── reviewed by Maya
│     └── followed incident #91
│
├── depends on retry.ts
│     └── introduced after checkout timeout
│
├── affects payment-service
│
└── changed 7 times during payment incidents
Enter fullscreen mode Exit fullscreen mode

Now you aren't just looking at code.

You're looking at the story of the code.

And that story can change the decision you make.


Give AI the Story, Not Just the Source File

This is where things get interesting.

Imagine asking an AI agent:

"Can I remove this retry?"

With only the source code, it might respond:

"The retry appears redundant and could potentially be removed."

That's not useful.

Now give it the engineering context:

retry.ts
   ↓
used by checkout.ts
   ↓
introduced in PR #842
   ↓
PR linked to checkout timeout #421
   ↓
incident #91 involved the same request path
   ↓
three subsequent PRs modified retry behavior
Enter fullscreen mode Exit fullscreen mode

Now the answer could be:

"I would not remove it yet. This retry mechanism was introduced to address a checkout timeout and has been modified several times after production issues. I'd inspect incident #91 and the related PRs before changing it."

Same model.

Different context.

Better context → better reasoning.

That's the fundamental idea.


Let's Build One

You don't need a giant infrastructure project to understand the architecture.

Start with a tiny graph.

type NodeType =
  | "file"
  | "commit"
  | "pull_request"
  | "issue"
  | "service"
  | "incident"
  | "person";

type Relationship =
  | "MODIFIED"
  | "SOLVED"
  | "DEPENDS_ON"
  | "AUTHORED_BY"
  | "REVIEWED_BY"
  | "AFFECTED"
  | "CAUSED";
Enter fullscreen mode Exit fullscreen mode

Our nodes:

type Node = {
  id: string;
  type: NodeType;
  name: string;
  metadata?: Record<string, unknown>;
};
Enter fullscreen mode Exit fullscreen mode

And edges:

type Edge = {
  from: string;
  to: string;
  relationship: Relationship;
  metadata?: Record<string, unknown>;
};
Enter fullscreen mode Exit fullscreen mode

Now we can represent:

const edges: Edge[] = [
  {
    from: "pr:842",
    to: "file:checkout.ts",
    relationship: "MODIFIED",
  },
  {
    from: "pr:842",
    to: "issue:421",
    relationship: "SOLVED",
  },
  {
    from: "file:checkout.ts",
    to: "file:retry.ts",
    relationship: "DEPENDS_ON",
  },
  {
    from: "incident:91",
    to: "service:checkout",
    relationship: "AFFECTED",
  },
];
Enter fullscreen mode Exit fullscreen mode

That's already enough to start answering questions that plain text search struggles with.


The Agent Should Query the Graph Before It Acts

Now put an AI agent on top.

A traditional agent looks something like:

Goal
 ↓
Observe
 ↓
Decide
 ↓
Act
 ↓
Check
 ↓
Repeat
Enter fullscreen mode Exit fullscreen mode

Useful.

But it starts every task with roughly the same level of ignorance.

Give it the graph:

                    ┌──────────────────────┐
                    │        Goal          │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │    Query Graph       │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │      Observe         │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │       Decide         │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │       Execute        │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │       Verify         │
                    └──────────┬───────────┘
                               ↓
                    ┌──────────────────────┐
                    │    Update Graph      │
                    └──────────┬───────────┘
                               │
                               └──────→ Next task
Enter fullscreen mode Exit fullscreen mode

Now the agent doesn't just observe the repository.

It observes what happened before.


The Agent Can Learn Without Retraining

This distinction is easy to miss.

We normally think an AI system improves like this:

Better model
     ↓
More training
     ↓
Better weights
     ↓
Better performance
Enter fullscreen mode Exit fullscreen mode

But agents have another path:

Better experience
       ↓
Better graph
       ↓
Better context
       ↓
Better decisions
       ↓
Better experience
Enter fullscreen mode Exit fullscreen mode

The underlying model doesn't have to change.

The environment around the model improves.

That's powerful.


But There's a Catch

We shouldn't blindly turn agent activity into permanent knowledge.

Imagine an agent tries:

Increase retry count: 2 → 10
Enter fullscreen mode Exit fullscreen mode

The test passes.

The agent records:

"10 retries fixes checkout."
Enter fullscreen mode Exit fullscreen mode

Next week another agent sees that "knowledge" and does the same thing.

Now you've created a feedback loop that makes the system confidently worse.

That's why learning systems need evidence.


Knowledge Needs Evidence

Instead of:

Agent says it worked.
Enter fullscreen mode Exit fullscreen mode

Store:

Code changed
    ↓
Unit tests passed
    ↓
Integration tests passed
    ↓
PR merged
    ↓
Deployment succeeded
    ↓
No incident followed
Enter fullscreen mode Exit fullscreen mode

Now your graph can represent:

type Outcome = {
  status: "success" | "failure";
  confidence: number;
  evidence: string[];
};
Enter fullscreen mode Exit fullscreen mode

For example:

const outcome: Outcome = {
  status: "success",
  confidence: 0.92,
  evidence: [
    "unit tests passed",
    "integration tests passed",
    "pull request merged",
    "deployment succeeded",
  ],
};
Enter fullscreen mode Exit fullscreen mode

The system isn't just remembering.

It's remembering why it believes something.

That difference becomes enormous at scale.


Not Everything Is Knowledge

An agent might make 50 observations while solving one problem.

We shouldn't permanently promote all 50 into "truth."

There are levels:

Observation
     ↓
Evidence
     ↓
Repeated pattern
     ↓
Validated relationship
     ↓
Reusable knowledge
     ↓
Heuristic
Enter fullscreen mode Exit fullscreen mode

For example:

Observation

checkout.ts imports retry.ts
Enter fullscreen mode Exit fullscreen mode

Event

PR #842 modified checkout.ts
Enter fullscreen mode Exit fullscreen mode

Outcome

Tests passed after the change.
Enter fullscreen mode Exit fullscreen mode

Knowledge

checkout.ts frequently changes with retry.ts.
Enter fullscreen mode Exit fullscreen mode

Heuristic

When checkout timeout tests fail,
inspect retry behavior first.
Enter fullscreen mode Exit fullscreen mode

That's a much safer learning architecture than dumping every agent thought into a vector database.


And Failure Is Data Too

This might be the most underrated part.

Suppose an agent tries two approaches:

Task: Fix checkout timeout

Approach A
    ↓
FAILED

Approach B
    ↓
SUCCEEDED
Enter fullscreen mode Exit fullscreen mode

A normal system might only remember B.

A learning system should remember both.

Task
│
├── attempted → Approach A
│                 └── FAILED
│
└── attempted → Approach B
                  └── SUCCEEDED
Enter fullscreen mode Exit fullscreen mode

That's negative knowledge.

The next agent doesn't have to walk into the same wall.

It can know:

"This approach was already tried. It failed."

The graph remembers the dead ends.


This Isn't RAG

RAG is incredibly useful.

But RAG and an Engineering Graph solve different problems.

RAG asks:

What information is relevant to this question?

A graph can ask:

How are these things related?

Imagine asking:

Why is checkout.ts high risk?
Enter fullscreen mode Exit fullscreen mode

A document retriever might find:

PR #842
PR #811
PR #743
Enter fullscreen mode Exit fullscreen mode

A graph can reconstruct:

checkout.ts
│
├── modified by PR #842
│      ├── authored by Maya
│      └── reviewed by Bobby
│
├── related to retry.ts
│
├── affected checkout-service
│
└── connected to incident #91
       └── caused by previous checkout change
Enter fullscreen mode Exit fullscreen mode

That's not just retrieval.

That's contextual reasoning over relationships.

And the two technologies work beautifully together:

                 User Question
                       ↓
              ┌────────────────┐
              │  Semantic Search│
              └───────┬────────┘
                      ↓
              Relevant entities
                      ↓
              ┌────────────────┐
              │ Graph Traversal│
              └───────┬────────┘
                      ↓
               Relationships
                      ↓
              ┌────────────────┐
              │      LLM       │
              └───────┬────────┘
                      ↓
             Evidence-backed answer
Enter fullscreen mode Exit fullscreen mode

Now Scale It Beyond One Repository

This is where the idea gets really interesting.

Imagine your engineering graph continuously absorbs:

GitHub
   ↓
Commits
   ↓
Pull Requests
   ↓
Code
   ↓
Services
   ↓
Deployments
   ↓
Incidents
   ↓
Fixes
   ↓
Agent Experiences
Enter fullscreen mode Exit fullscreen mode

Then add:

Jira
Slack
Confluence
Datadog
Architecture decisions
Human feedback
Enter fullscreen mode Exit fullscreen mode

Eventually you're not building another code search engine.

You're building a living model of how the engineering organization works.

You can ask:

Why was this architecture chosen?

Who understands this service?

What usually breaks when we change it?

Which files are high risk?

What has already been tried?

Which engineers solved similar problems?

What happened after the last deployment?

What should an AI agent inspect before touching this service?
Enter fullscreen mode Exit fullscreen mode

Those answers don't exist in any single system.

They emerge from the connections between systems.


The Real Opportunity

Here's the part I think matters most.

AI is making software creation dramatically faster.

That's great.

But it creates a new bottleneck:

understanding.

If AI can generate 10x more code, we need tools that help engineers understand 10x more software.

Otherwise we're just accelerating the production of systems nobody fully understands.

The next generation of engineering tools won't just answer:

"What does this code do?"

They'll answer:

"Why is it here, what does it connect to, what happened before, and what happens if I change it?"

That's a much harder problem.

And a much more valuable one.


The Four-Layer Architecture

I think the architecture eventually becomes surprisingly simple:

┌─────────────────────────────────────┐
│               AGENTS                │
│        Reason • Plan • Act          │
└──────────────────┬──────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│              CONTEXT                │
│       Search • Retrieval • RAG       │
└──────────────────┬──────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│        ENGINEERING GRAPH             │
│ Code • PRs • People • Incidents     │
│ Decisions • Dependencies • Outcomes │
└──────────────────┬──────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│              EVIDENCE               │
│     GitHub • CI • Deployments       │
│      Observability • Humans         │
└─────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The model provides reasoning.

The tools provide action.

The graph provides memory.

Evidence provides trust.

Put those together and you get something much more interesting than an AI coding assistant.

You get an engineering system that can learn from the work it performs.


Software Should Explain Itself

The future of AI-assisted engineering isn't just about generating code faster.

It's about building systems that understand the software they're changing.

Every commit tells a story.

Every pull request adds context.

Every incident teaches something.

Every fix creates new knowledge.

Every engineer leaves behind experience.

The opportunity is to connect all of it.

Because your code already knows what changed.

Your Git history knows when.

Your team knows why.

The problem is that nobody has connected the three.

That's what Engineering Intelligence should do.

And that's what we're building with Helix: a living engineering graph that connects software, engineering activity, decisions, and evidence so humans and AI can understand what happened before deciding what happens next.

The goal isn't AI that confidently guesses.

The goal is AI that can show its work.


Your code has a history. Helix makes it understandable.

Connect your GitHub and see what your code knows.

Explore Helix →

Top comments (0)