Repository Dependency Graphs for Change Planning: Compute the Impact Closure Before Writing Code
Directory proximity does not imply a dependency. This article organizes build, symbol, configuration, and runtime edges into a versioned repository graph so coding Agents can compute the impact closure, rollout order, and rollback boundaries before making changes.
Key Points
- Topic Focus: AI Agent、TypeScript、DevOps
- Suitable for: indie hackers, full-stack engineers, AI application developers
- Core value: quickly understand background, practical paths, common pitfalls, and engineering advice
When a coding Agent receives a request to "add a field to a shared type," searching by directory usually finds only explicit imports. The actual impact may also include code-generation targets, runtime registries, configuration consumers, database migrations, test fixtures, and a client written in another language. Writing code first and expanding the scope only as compiler errors appear turns planning into trial and error, while silent compatibility issues produce no compiler errors at all.
The goal of dependency-graph-driven planning is not to draw yet another repository map. Repository Maps for Coding Agents answers "What modules and entry points exist?" This article goes further by answering, "Starting from this contract change, which nodes must be inspected, in what order should they be modified, and which unknown edges should block automatic execution?"
The commands in this article are intended to run in a Linux/GNU CI container with Bash, GNU coreutils, and Git; macOS and Windows runners must use the same container.
Graph Edges Must Carry Types and Evidence
Treat packages, build targets, public symbols, schemas, generators, configuration keys, and deployment units as distinct node types. Edges must distinguish at least imports, implements, generates, reads-config, publishes-event, migrates-data, and loads-dynamically. Every edge must store its source file, extractor version, source commit, and confidence level; A -> B alone is not enough.
The build system provides package-level ground truth, the compiler or LSP provides symbol-level references, and runtime logs and registration configurations supplement the graph with dynamic edges. None can replace the others: a static graph cannot see plugins loaded through strings, while dynamic coverage cannot prove that branches never executed have no dependencies. Unresolvable globs, reflection, templates, and environment variables belong in unknownEdges instead of being silently dropped from the graph.
{
"sourceCommit": "8f61c2a",
"seed": "//libs/contracts:user-v2",
"required": ["//apps/api", "//sdk/typescript"],
"inspect": ["//jobs/export"],
"unknownEdges": ["plugins/*:runtime-load"],
"graphDigest": "sha256:4a12..."
}
Compute a Bidirectional Impact Closure from Change Seeds
The planner first maps the requirement to explicit seeds, such as a symbol, schema field, or build target. It then traverses upward to find consumers and downward to find generation sources and runtime dependencies. A public interface change cannot stop at reverse imports: it must also include implementers, serialization boundaries, compatibility adapters, and release units. When deleting a file, the baseline graph must be queried because the old node no longer exists in the HEAD graph.
In a repository using Bazel, reverse dependencies can be verified from a frozen baseline; in an Nx project, affected results can serve as package-level input:
BASE_SHA=$(git merge-base origin/main HEAD)
git diff --name-status --find-renames "$BASE_SHA...HEAD"
bazel query 'rdeps(//..., set(//libs/contracts:user_v2))' --output=label
pnpm exec nx show projects --affected --base="$BASE_SHA" --head=HEAD
The commands, tool versions, graph digest, and both Git SHAs all become part of the plan artifact. A project should use only the commands that match its own build system; it must not combine outputs from example tools into a falsely precise result. If HEAD, the lockfile, or workspace configuration changes afterward, the old plan becomes invalid immediately.
Closure nodes are classified as required, inspect, or unknown. Direct consumers, generation targets, and published contracts are required; low-confidence dynamic edges are inspect; parse failures and cross-repository edges are unknown. Any high-risk unknown prevents the Agent from rewriting code automatically until an owner adds the missing edge or confirms that the scope should be expanded.
Use Strongly Connected Components to Determine Rollout Order
The graph determines not only which files to read, but also the migration sequence. Execute the acyclic portion in topological order; first collapse cyclic dependencies into strongly connected components and treat each as a single review unit. Breaking contract changes use expand-migrate-contract: first release a provider that accepts both the old and new formats, then migrate consumers, confirm that usage of the old path has fallen to zero, and finally remove the compatibility layer.
The plan should list the inputs, observable completion criteria, and rollback point for each phase. For example, the schema phase only adds an optional field, the client phase continues to read the old field, and the cleanup phase requires zero calls using the old field for seven consecutive days. This prevents the Agent from changing the provider and every consumer while also deleting the old format in a single PR, which would make independent validation impossible.
Constrain the Actual Patch with a Plan Diff
After completing the changes, regenerate the graph and impact closure, then compare the nodes actually touched with the approved plan. If files outside the plan, changes to public edges, or new strongly connected components appear, stop execution and request approval again. Planned nodes that were not modified also require an explanation, preventing omissions from being concealed by passing tests.
Validation must include build-graph queries, builds and tests for every required target, public contract checks, and the selective regression testing described in Test Impact Analysis for Coding Agents. Final merge evidence still follows Change Validation Gates for Coding Agents, but the verification set must be traceable to specific edges in the graph.
pnpm exec nx affected -t lint test build --base="$BASE_SHA" --head=HEAD
cmp -s .artifacts/approved-impact-plan.json \
.artifacts/computed-impact-plan.json
The second command requires CI to restore the approved plan from a trusted artifact and independently compute the actual plan from the current HEAD; the Agent has no authority to rewrite the former after a failure. If a tool query fails, the graph version is outdated, or unknown has not been reduced to zero, the safe fallback is to expand verification to the relevant workspace or the entire repository, not return an empty impact set.
Rollback is performed one phase at a time. For a patch that has not been released, simply discard the isolated branch; for a merged phase, use git revert <sha> to create an inverse commit and rerun validation over the same dependency closure. Once data or messages have been expanded, do not roll back the provider first and leave new consumers without compatibility. Executors for large repositories can be built on Monorepo Tooling, but reliability comes from evidence-backed edges, freezeable plans, and phases that can be reversed independently.
Related
Related Content
Article
What Is Vibe Coding? Will It Change How Programmers Work?
Technical trends, engineering practices, and an indie developer perspective on Vibe Coding, AI, and independent development.
Article
From Copilot to Codex: AI Coding Tools Enter the Agent Era
Technical trends, engineering practices, and indie-developer perspectives around AI, AI Agents, and Vibe Coding.
Article
Why Does MCP Matter? Understanding the AI Tool Protocol
Technical trends, engineering practices, and an independent developer perspective on MCP and AI Agents.
Article
Core Architecture of AI Agents: Planning, Memory, Tools, and Execution
Technical trends, engineering practices, and independent developer perspectives around AI Agents and large language models.